예제 #1
0
 public override void ValidateTransaction(ChainedHeader chainedHeader, LoadedTx loadedTx)
 {
     if (ValidateTransactionAction == null)
         base.ValidateTransaction(chainedHeader, loadedTx);
     else
         ValidateTransactionAction(chainedHeader, loadedTx);
 }
        public void BeginTransaction(out ChainedHeader chainTip, out int? unspentTxCount, out int? unspentOutputCount, out int? totalTxCount, out int? totalInputCount, out int? totalOutputCount, out ImmutableSortedDictionary<UInt256, ChainedHeader>.Builder headers, out ImmutableSortedDictionary<UInt256, UnspentTx>.Builder unspentTransactions, out ImmutableDictionary<int, BlockSpentTxes>.Builder blockSpentTxes, out ImmutableDictionary<UInt256, IImmutableList<UnmintedTx>>.Builder blockUnmintedTxes, out long chainTipVersion, out long unspentTxCountVersion, out long unspentOutputCountVersion, out long totalTxCountVersion, out long totalInputCountVersion, out long totalOutputCountVersion, out long headersVersion, out long unspentTxesVersion, out long blockSpentTxesVersion, out long blockUnmintedTxesVersion)
        {
            lock (this.lockObject)
            {
                chainTip = this.chainTip;
                unspentTxCount = this.unspentTxCount;
                unspentOutputCount = this.unspentOutputCount;
                totalTxCount = this.totalTxCount;
                totalInputCount = this.totalInputCount;
                totalOutputCount = this.totalOutputCount;
                headers = this.headers.ToImmutable().ToBuilder();
                unspentTransactions = this.unspentTransactions.ToImmutable().ToBuilder();
                blockSpentTxes = this.blockSpentTxes.ToImmutable().ToBuilder();
                blockUnmintedTxes = this.blockUnmintedTxes.ToImmutable().ToBuilder();

                chainTipVersion = this.chainTipVersion;
                unspentTxCountVersion = this.unspentTxCountVersion;
                unspentOutputCountVersion = this.unspentOutputCountVersion;
                totalTxCountVersion = this.totalTxCountVersion;
                totalInputCountVersion = this.totalInputCountVersion;
                totalOutputCountVersion = this.totalOutputCountVersion;
                headersVersion = this.headersVersion;
                unspentTxesVersion = this.unspentTxesVersion;
                blockSpentTxesVersion = this.blockSpentTxesVersion;
                blockUnmintedTxesVersion = this.blockUnmintedTxesVersion;
            }
        }
예제 #3
0
        internal MemoryStorageManager(ChainedHeader chainTip = null, int? unspentTxCount = null, int? unspentOutputCount = null, int? totalTxCount = null, int? totalInputCount = null, int? totalOutputCount = null, ImmutableSortedDictionary<UInt256, ChainedHeader> headers = null, ImmutableSortedDictionary<UInt256, UnspentTx> unspentTransactions = null, ImmutableDictionary<int, BlockSpentTxes> spentTransactions = null)
        {
            blockStorage = new MemoryBlockStorage();
            blockTxesStorage = new MemoryBlockTxesStorage();
            chainStateStorage = new MemoryChainStateStorage(chainTip, unspentTxCount, unspentOutputCount, totalTxCount, totalInputCount, totalOutputCount, headers, unspentTransactions, spentTransactions);
            unconfirmedTxesStorage = new MemoryUnconfirmedTxesStorage();

            chainStateCursorCache = new DisposableCache<IChainStateCursor>(1024,
                createFunc: () => new MemoryChainStateCursor(chainStateStorage),
                prepareAction: cursor =>
                {
                    // rollback any open transaction before returning the cursor to the cache
                    if (cursor.InTransaction)
                        cursor.RollbackTransaction();
                });

            unconfirmedTxesCursorCache = new DisposableCache<IUnconfirmedTxesCursor>(1024,
                createFunc: () => new MemoryUnconfirmedTxesCursor(unconfirmedTxesStorage),
                prepareAction: cursor =>
                {
                    // rollback any open transaction before returning the cursor to the cache
                    if (cursor.InTransaction)
                        cursor.RollbackTransaction();
                });
        }
예제 #4
0
        public void Init()
        {
            var fakeHeaders = new FakeHeaders();
            this.chainedHeader0 = fakeHeaders.GenesisChained();
            this.chainedHeader1 = fakeHeaders.NextChained();

            var fakeHeadersA = new FakeHeaders(fakeHeaders);
            this.chainedHeaderA2 = fakeHeadersA.NextChained();
            this.chainedHeaderA3 = fakeHeadersA.NextChained();
            this.chainedHeaderA4 = fakeHeadersA.NextChained();

            var fakeHeadersB = new FakeHeaders(fakeHeaders);
            this.chainedHeaderB2 = fakeHeadersB.NextChained();
            this.chainedHeaderB3 = fakeHeadersB.NextChained();
            this.chainedHeaderB4 = fakeHeadersB.NextChained();

            var fakeHeadersX = new FakeHeaders();
            this.chainedHeaderX0 = fakeHeadersX.GenesisChained();
            this.chainedHeaderX1 = fakeHeadersX.NextChained();

            this.chain = ImmutableDictionary.CreateRange(
                new[] { chainedHeader0, chainedHeader1, chainedHeaderA2, chainedHeaderA3, chainedHeaderA4, chainedHeaderB2, chainedHeaderB3, chainedHeaderB4, chainedHeaderX0, chainedHeaderX1 }
                .Select(x => new KeyValuePair<UInt256, ChainedHeader>(x.Hash, x)));

            this.getChainedHeader = blockHash => this.chain[blockHash];
        }
예제 #5
0
        public BlockchainPath GetBlockchainPath(ChainedHeader fromBlock, ChainedHeader toBlock, Func<UInt256, ChainedHeader> getChainedHeader, CancellationToken? cancelToken = null)
        {
            var rewindBlocks = ImmutableList.CreateBuilder<ChainedHeader>();
            var advanceBlocks = ImmutableList.CreateBuilder<ChainedHeader>();

            foreach (var pathElement in DiscoverPath(fromBlock, toBlock, getChainedHeader, cancelToken))
            {
                switch (pathElement.Chain)
                {
                    case PathChain.From:
                        rewindBlocks.Add(pathElement.ChainedHeader);
                        break;

                    case PathChain.To:
                        advanceBlocks.Add(pathElement.ChainedHeader);
                        break;

                    case PathChain.LastCommon:
                        advanceBlocks.Reverse();
                        return new BlockchainPath(fromBlock, toBlock, pathElement.ChainedHeader, rewindBlocks.ToImmutable(), advanceBlocks.ToImmutable());

                    default:
                        throw new InvalidEnumArgumentException();
                }
            }

            throw new InvalidOperationException();
        }
예제 #6
0
        public bool TryAddChainedHeader(ChainedHeader chainedHeader)
        {
            try
            {
                using (var handle = this.cursorCache.TakeItem())
                {
                    var cursor = handle.Item;

                    using (var jetTx = cursor.jetSession.BeginTransaction())
                    {
                        using (var jetUpdate = cursor.jetSession.BeginUpdate(cursor.blockHeadersTableId, JET_prep.Insert))
                        {
                            Api.SetColumns(cursor.jetSession, cursor.blockHeadersTableId,
                                new BytesColumnValue { Columnid = cursor.blockHeaderHashColumnId, Value = DbEncoder.EncodeUInt256(chainedHeader.Hash) },
                                new BytesColumnValue { Columnid = cursor.blockHeaderPreviousHashColumnId, Value = DbEncoder.EncodeUInt256(chainedHeader.PreviousBlockHash) },
                                new Int32ColumnValue { Columnid = cursor.blockHeaderHeightColumnId, Value = chainedHeader.Height },
                                new BytesColumnValue { Columnid = cursor.blockHeaderTotalWorkColumnId, Value = DataEncoder.EncodeTotalWork(chainedHeader.TotalWork) },
                                new BytesColumnValue { Columnid = cursor.blockHeaderBytesColumnId, Value = DataEncoder.EncodeChainedHeader(chainedHeader) });

                            jetUpdate.Save();
                        }

                        jetTx.CommitLazy();
                        return true;
                    }
                }
            }
            catch (EsentKeyDuplicateException)
            {
                return false;
            }
        }
예제 #7
0
 public override void ValidationTransactionScript(ChainedHeader chainedHeader, Transaction tx, int txIndex, TxInput txInput, int txInputIndex, TxOutput prevTxOutput)
 {
     if (ValidationTransactionScriptAction == null)
         base.ValidationTransactionScript(chainedHeader, tx, txIndex, txInput, txInputIndex, prevTxOutput);
     else
         ValidationTransactionScriptAction(chainedHeader, tx, txIndex, txInput, txInputIndex, prevTxOutput);
 }
예제 #8
0
 public BlockchainPath(ChainedHeader fromBlock, ChainedHeader toBlock, ChainedHeader lastCommonBlock, ImmutableList<ChainedHeader> rewindBlocks, ImmutableList<ChainedHeader> advanceBlocks)
 {
     FromBlock = fromBlock;
     ToBlock = toBlock;
     LastCommonBlock = lastCommonBlock;
     RewindBlocks = rewindBlocks;
     AdvanceBlocks = advanceBlocks;
 }
예제 #9
0
 public LoadingTx(int txIndex, Transaction transaction, ChainedHeader chainedHeader, ImmutableArray<TxLookupKey> prevOutputTxKeys)
 {
     Transaction = transaction;
     TxIndex = txIndex;
     ChainedHeader = chainedHeader;
     PrevOutputTxKeys = prevOutputTxKeys;
     InputTxes = new CompletionArray<DecodedTx>(txIndex != 0 ? transaction.Inputs.Length : 0);
 }
예제 #10
0
        public static ChainedHeader CreateFromPrev(ChainedHeader prevChainedHeader, BlockHeader blockHeader, DateTimeOffset dateSeen)
        {
            var headerWork = blockHeader.CalculateWork();

            return new ChainedHeader(blockHeader,
                prevChainedHeader.Height + 1,
                prevChainedHeader.TotalWork + headerWork.ToBigInteger(),
                dateSeen);
        }
예제 #11
0
        public ValidatableTx(DecodedBlockTx blockTx, ChainedHeader chainedHeader, ImmutableArray<PrevTxOutput> prevTxOutputs)
        {
            if (blockTx == null)
                throw new ArgumentNullException(nameof(blockTx));

            BlockTx = blockTx;
            ChainedHeader = chainedHeader;
            PrevTxOutputs = prevTxOutputs;
        }
예제 #12
0
        public static ISourceBlock<ValidatableTx> ReplayRollbackUtxo(ICoreStorage coreStorage, IChainState chainState, ChainedHeader replayBlock, CancellationToken cancelToken = default(CancellationToken))
        {
            // replaying rollback of an on-chain block, use the chainstate tx index for replay, same as replaying forward
            if (chainState.Chain.BlocksByHash.ContainsKey(replayBlock.Hash))
            {
                return ReplayFromTxIndex(coreStorage, chainState, replayBlock, replayForward: false, cancelToken: cancelToken);
            }
            // replaying rollback of an off-chain (re-org) block, use the unminted information for replay
            else
            {
                IImmutableList<UnmintedTx> unmintedTxesList;
                if (!chainState.TryGetBlockUnmintedTxes(replayBlock.Hash, out unmintedTxesList))
                {
                    //TODO if a wallet/monitor were to see a chainstate block that wasn't flushed to disk yet,
                    //TODO and if bitsharp crashed, and if the block was orphaned: then the orphaned block would
                    //TODO not be present in the chainstate, and it would not get rolled back to generate unminted information.
                    //TODO DeferredChainStateCursor should be used in order to re-org the chainstate in memory and calculate the unminted information
                    throw new MissingDataException(replayBlock.Hash);
                }

                var unmintedTxes = ImmutableDictionary.CreateRange(
                    unmintedTxesList.Select(x => new KeyValuePair<UInt256, UnmintedTx>(x.TxHash, x)));

                var lookupLoadingTx = new TransformBlock<DecodedBlockTx, ValidatableTx>(
                    blockTx =>
                    {
                        var tx = blockTx.Transaction;
                        var txIndex = blockTx.Index;
                        var prevTxOutputs = ImmutableArray.CreateBuilder<PrevTxOutput>(!blockTx.IsCoinbase ? tx.Inputs.Length : 0);

                        if (!blockTx.IsCoinbase)
                        {
                            UnmintedTx unmintedTx;
                            if (!unmintedTxes.TryGetValue(tx.Hash, out unmintedTx))
                                throw new MissingDataException(replayBlock.Hash);

                            prevTxOutputs.AddRange(unmintedTx.PrevTxOutputs);
                        }

                        return new ValidatableTx(blockTx, replayBlock, prevTxOutputs.MoveToImmutable());
                    });

                IEnumerator<BlockTx> blockTxes;
                if (!coreStorage.TryReadBlockTransactions(replayBlock.Hash, out blockTxes))
                {
                    throw new MissingDataException(replayBlock.Hash);
                }

                var blockTxesBuffer = new BufferBlock<DecodedBlockTx>();
                blockTxesBuffer.LinkTo(lookupLoadingTx, new DataflowLinkOptions { PropagateCompletion = true });

                blockTxesBuffer.SendAndCompleteAsync(blockTxes.UsingAsEnumerable().Select(x => x.Decode()).Reverse(), cancelToken).Forget();

                return lookupLoadingTx;
            }
        }
예제 #13
0
        public static ChainedHeader CreateFromPrev(ChainedHeader prevChainedHeader, BlockHeader blockHeader)
        {
            var headerWork = blockHeader.CalculateWork();
            if (headerWork < 0)
                return null;

            return new ChainedHeader(blockHeader,
                prevChainedHeader.Height + 1,
                prevChainedHeader.TotalWork + headerWork);
        }
예제 #14
0
        public void AddGenesisBlock(ChainedHeader genesisHeader)
        {
            if (genesisHeader.Height != 0)
                throw new ArgumentException("genesisHeader");

            if (this.blockStorage.Value.TryAddChainedHeader(genesisHeader))
            {
                this.cachedHeaders.Value[genesisHeader.Hash] = genesisHeader;
                RaiseChainedHeaderAdded(genesisHeader);
            }
        }
예제 #15
0
        public ChainedHeader GenesisChained()
        {
            if (this.blockHeaders.Count > 0)
                throw new InvalidOperationException();

            var blockHeader = BlockHeader.Create(0, UInt256.Zero, UInt256.Zero, DateTimeOffset.FromUnixTimeSeconds(0), this.bits, this.nonce);
            this.totalWork = blockHeader.CalculateWork().ToBigInteger();

            var chainedHeader = new ChainedHeader(blockHeader, 0, this.totalWork, DateTimeOffset.MinValue);
            this.blockHeaders.Add(chainedHeader);

            return chainedHeader;
        }
 public MemoryChainStateStorage(ChainedHeader chainTip = null, int? unspentTxCount = null, int? totalTxCount = null, int? totalInputCount = null, int? totalOutputCount = null, int? unspentOutputCount = null, ImmutableSortedDictionary<UInt256, ChainedHeader> headers = null, ImmutableSortedDictionary<UInt256, UnspentTx> unspentTransactions = null, ImmutableDictionary<int, BlockSpentTxes> blockSpentTxes = null, ImmutableDictionary<UInt256, IImmutableList<UnmintedTx>> blockUnmintedTxes = null)
 {
     this.chainTip = chainTip;
     this.unspentTxCount = unspentTxCount ?? 0;
     this.unspentOutputCount = unspentOutputCount ?? 0;
     this.totalTxCount = totalTxCount ?? 0;
     this.totalInputCount = totalInputCount ?? 0;
     this.totalOutputCount = totalOutputCount ?? 0;
     this.headers = headers?.ToBuilder() ?? ImmutableSortedDictionary.CreateBuilder<UInt256, ChainedHeader>();
     this.unspentTransactions = unspentTransactions?.ToBuilder() ?? ImmutableSortedDictionary.CreateBuilder<UInt256, UnspentTx>();
     this.blockSpentTxes = blockSpentTxes?.ToBuilder() ?? ImmutableDictionary.CreateBuilder<int, BlockSpentTxes>();
     this.blockUnmintedTxes = blockUnmintedTxes?.ToBuilder() ?? ImmutableDictionary.CreateBuilder<UInt256, IImmutableList<UnmintedTx>>();
 }
예제 #17
0
        public ChainedHeader GenesisChained()
        {
            if (this.blockHeaders.Count > 0)
                throw new InvalidOperationException();

            var blockHeader = new BlockHeader(0, UInt256.Zero, UInt256.Zero, 0, this.bits, this.nonce);
            this.totalWork = blockHeader.CalculateWork();

            var chainedHeader = new ChainedHeader(blockHeader, 0, this.totalWork);
            this.blockHeaders.Add(chainedHeader);

            return chainedHeader;
        }
예제 #18
0
        private IEnumerable<PathElement> DiscoverPath(ChainedHeader fromBlock, ChainedHeader toBlock, Func<UInt256, ChainedHeader> getChainedHeader, CancellationToken? cancelToken)
        {
            // find height difference between chains
            var heightDelta = toBlock.Height - fromBlock.Height;

            var currentFromBlock = fromBlock;
            var currentToBlock = toBlock;

            while (currentFromBlock.Hash != currentToBlock.Hash)
            {
                // cooperative loop
                cancelToken.GetValueOrDefault(CancellationToken.None).ThrowIfCancellationRequested();

                // from chain is longer, rewind it
                if (currentFromBlock.Height > currentToBlock.Height)
                {
                    // if no further rollback is possible, chain mismatch
                    if (currentFromBlock.Height == 0)
                        throw new InvalidOperationException();

                    yield return new PathElement(PathChain.From, currentFromBlock);
                    currentFromBlock = getChainedHeader(currentFromBlock.PreviousBlockHash);
                }
                // to chain is longer, rewind it
                else if (currentToBlock.Height > currentFromBlock.Height)
                {
                    // if no further rollback is possible, chain mismatch
                    if (currentToBlock.Height == 0)
                        throw new InvalidOperationException();

                    yield return new PathElement(PathChain.To, currentToBlock);
                    currentToBlock = getChainedHeader(currentToBlock.PreviousBlockHash);
                }
                // chains are same height, rewind both
                else
                {
                    // if no further rollback is possible, chain mismatch
                    if (currentFromBlock.Height == 0 || currentToBlock.Height == 0)
                        throw new InvalidOperationException();

                    yield return new PathElement(PathChain.From, currentFromBlock);
                    yield return new PathElement(PathChain.To, currentToBlock);

                    currentFromBlock = getChainedHeader(currentFromBlock.PreviousBlockHash);
                    currentToBlock = getChainedHeader(currentToBlock.PreviousBlockHash);
                }
            }

            // return last common block
            yield return new PathElement(PathChain.LastCommon, currentFromBlock);
        }
예제 #19
0
        public void TestChainedHeaderEquality()
        {
            var randomChainedHeader = RandomData.RandomChainedHeader();
            var randomHeader = RandomData.RandomBlockHeader();

            var sameChainedHeader = new ChainedHeader
            (
                blockHeader: randomChainedHeader.BlockHeader,
                height: randomChainedHeader.Height,
                totalWork: randomChainedHeader.TotalWork
            );

            var differentChainedHeaderBlockHeader = new ChainedHeader
            (
                blockHeader: randomHeader,
                height: randomChainedHeader.Height,
                totalWork: randomChainedHeader.TotalWork
            );

            var differentChainedHeaderHeight = new ChainedHeader
            (
                blockHeader: randomChainedHeader.BlockHeader,
                height: ~randomChainedHeader.Height,
                totalWork: randomChainedHeader.TotalWork
            );

            var differentChainedHeaderTotalWork = new ChainedHeader
            (
                blockHeader: randomChainedHeader.BlockHeader,
                height: randomChainedHeader.Height,
                totalWork: ~randomChainedHeader.TotalWork
            );

            Assert.IsTrue(randomChainedHeader.Equals(sameChainedHeader));
            Assert.IsTrue(randomChainedHeader == sameChainedHeader);
            Assert.IsFalse(randomChainedHeader != sameChainedHeader);

            Assert.IsFalse(randomChainedHeader.Equals(differentChainedHeaderBlockHeader));
            Assert.IsFalse(randomChainedHeader == differentChainedHeaderBlockHeader);
            Assert.IsTrue(randomChainedHeader != differentChainedHeaderBlockHeader);

            Assert.IsFalse(randomChainedHeader.Equals(differentChainedHeaderHeight));
            Assert.IsFalse(randomChainedHeader == differentChainedHeaderHeight);
            Assert.IsTrue(randomChainedHeader != differentChainedHeaderHeight);

            Assert.IsFalse(randomChainedHeader.Equals(differentChainedHeaderTotalWork));
            Assert.IsFalse(randomChainedHeader == differentChainedHeaderTotalWork);
            Assert.IsTrue(randomChainedHeader != differentChainedHeaderTotalWork);
        }
예제 #20
0
        public ChainedHeader NextChained(UInt32? bits = null)
        {
            if (this.blockHeaders.Count == 0)
                throw new InvalidOperationException();

            var prevBlockHeader = this.blockHeaders.Last();

            var blockHeader = BlockHeader.Create(0, prevBlockHeader.Hash, UInt256.Zero, DateTimeOffset.FromUnixTimeSeconds(0), bits ?? this.bits, this.nonce);
            this.totalWork += blockHeader.CalculateWork().ToBigInteger();

            var chainedHeader = new ChainedHeader(blockHeader, this.blockHeaders.Count, this.totalWork, DateTimeOffset.Now);
            this.blockHeaders.Add(chainedHeader);

            return chainedHeader;
        }
예제 #21
0
        public bool TryGetChainedHeader(UInt256 blockHash, out ChainedHeader chainedHeader)
        {
            var key = MakeHeaderKey(blockHash);

            Slice value;
            if (db.TryGet(new ReadOptions(), key, out value))
            {
                chainedHeader = DataDecoder.DecodeChainedHeader(value.ToArray());
                return true;
            }
            else
            {
                chainedHeader = default(ChainedHeader);
                return false;
            }
        }
예제 #22
0
 private static TransformBlock<LoadedTx, LoadedTx> InitMerkleValidator(ChainedHeader chainedHeader, MerkleStream merkleStream, CancellationToken cancelToken)
 {
     return new TransformBlock<LoadedTx, LoadedTx>(
         loadedTx =>
         {
             try
             {
                 merkleStream.AddNode(new MerkleTreeNode(loadedTx.TxIndex, 0, loadedTx.Transaction.Hash, false));
             }
             //TODO
             catch (InvalidOperationException)
             {
                 throw CreateMerkleRootException(chainedHeader);
             }
             return loadedTx;
         },
         new ExecutionDataflowBlockOptions { CancellationToken = cancelToken });
 }
예제 #23
0
 public MemoryChainStateStorage(ChainedHeader chainTip = null, int? unspentTxCount = null, int? totalTxCount = null, int? totalInputCount = null, int? totalOutputCount = null, int? unspentOutputCount = null, ImmutableSortedDictionary<UInt256, ChainedHeader> headers = null, ImmutableSortedDictionary<UInt256, UnspentTx> unspentTransactions = null, ImmutableDictionary<int, BlockSpentTxes> blockSpentTxes = null, ImmutableDictionary<UInt256, IImmutableList<UnmintedTx>> blockUnmintedTxes = null)
 {
     this.chainTip = CommittedRecord<ChainedHeader>.Initial(chainTip);
     this.unspentTxCount = CommittedRecord<int>.Initial(unspentTxCount ?? 0);
     this.unspentOutputCount = CommittedRecord<int>.Initial(unspentOutputCount ?? 0);
     this.totalTxCount = CommittedRecord<int>.Initial(totalTxCount ?? 0);
     this.totalInputCount = CommittedRecord<int>.Initial(totalInputCount ?? 0);
     this.totalOutputCount = CommittedRecord<int>.Initial(totalOutputCount ?? 0);
     this.headers = CommittedRecord<ImmutableSortedDictionary<UInt256, ChainedHeader>.Builder>.Initial(
         headers?.ToBuilder() ?? ImmutableSortedDictionary.CreateBuilder<UInt256, ChainedHeader>());
     this.unspentTransactions = CommittedRecord<ImmutableSortedDictionary<UInt256, UnspentTx>.Builder>.Initial(
         unspentTransactions?.ToBuilder() ?? ImmutableSortedDictionary.CreateBuilder<UInt256, UnspentTx>());
     this.unspentTxOutputs = CommittedRecord<ImmutableSortedDictionary<TxOutputKey, TxOutput>.Builder>.Initial(
         ImmutableSortedDictionary.CreateBuilder<TxOutputKey, TxOutput>());
     this.blockSpentTxes = CommittedRecord<ImmutableDictionary<int, BlockSpentTxes>.Builder>.Initial(
         blockSpentTxes?.ToBuilder() ?? ImmutableDictionary.CreateBuilder<int, BlockSpentTxes>());
     this.blockUnmintedTxes = CommittedRecord<ImmutableDictionary<UInt256, IImmutableList<UnmintedTx>>.Builder>.Initial(
         blockUnmintedTxes?.ToBuilder() ?? ImmutableDictionary.CreateBuilder<UInt256, IImmutableList<UnmintedTx>>());
 }
예제 #24
0
        private void Mint(IChainStateCursor chainStateCursor, Transaction tx, int txIndex, ChainedHeader chainedHeader)
        {
            // add transaction to the utxo
            var unspentTx = new UnspentTx(tx.Hash, chainedHeader.Height, txIndex, tx.Version, tx.IsCoinbase, tx.Outputs.Length, OutputState.Unspent);
            if (!chainStateCursor.TryAddUnspentTx(unspentTx))
            {
                // duplicate transaction
                logger.Warn($"Duplicate transaction at block {chainedHeader.Height:N0}, {chainedHeader.Hash}, coinbase");
                throw new ValidationException(chainedHeader.Hash);
            }

            // add transaction outputs to the utxo
            for (var outputIndex = 0; outputIndex < tx.Outputs.Length; outputIndex++)
            {
                var output = tx.Outputs[outputIndex];
                if (!chainStateCursor.TryAddUnspentTxOutput(new TxOutputKey(tx.Hash, (uint)outputIndex), output))
                    throw new ValidationException(chainedHeader.Hash);
            }
        }
예제 #25
0
        private static TransformManyBlock<LoadedTx, Tuple<LoadedTx, int>> InitTxValidator(IBlockchainRules rules, ChainedHeader chainedHeader, CancellationToken cancelToken)
        {
            return new TransformManyBlock<LoadedTx, Tuple<LoadedTx, int>>(
                loadedTx =>
                {
                    rules.ValidateTransaction(chainedHeader, loadedTx);

                    if (!rules.IgnoreScripts && !loadedTx.IsCoinbase)
                    {
                        var scripts = new Tuple<LoadedTx, int>[loadedTx.Transaction.Inputs.Length];
                        for (var i = 0; i < loadedTx.Transaction.Inputs.Length; i++)
                            scripts[i] = Tuple.Create(loadedTx, i);

                        return scripts;
                    }
                    else
                        return new Tuple<LoadedTx, int>[0];
                },
                new ExecutionDataflowBlockOptions { CancellationToken = cancelToken, MaxDegreeOfParallelism = Environment.ProcessorCount });
        }
예제 #26
0
        public static async Task ValidateBlockAsync(ICoreStorage coreStorage, IBlockchainRules rules, ChainedHeader chainedHeader, ISourceBlock<LoadedTx> loadedTxes, CancellationToken cancelToken = default(CancellationToken))
        {
            // validate merkle root
            var merkleStream = new MerkleStream();
            var merkleValidator = InitMerkleValidator(chainedHeader, merkleStream, cancelToken);

            // begin feeding the merkle validator
            loadedTxes.LinkTo(merkleValidator, new DataflowLinkOptions { PropagateCompletion = true });

            // validate transactions
            var txValidator = InitTxValidator(rules, chainedHeader, cancelToken);

            // begin feeding the tx validator
            merkleValidator.LinkTo(txValidator, new DataflowLinkOptions { PropagateCompletion = true });

            // validate scripts
            var scriptValidator = InitScriptValidator(rules, chainedHeader, cancelToken);

            // begin feeding the script validator
            txValidator.LinkTo(scriptValidator, new DataflowLinkOptions { PropagateCompletion = true });

            await merkleValidator.Completion;
            await txValidator.Completion;
            await scriptValidator.Completion;

            if (!rules.BypassPrevTxLoading)
            {
                try
                {
                    merkleStream.FinishPairing();
                }
                //TODO
                catch (InvalidOperationException)
                {
                    throw CreateMerkleRootException(chainedHeader);
                }
                if (merkleStream.RootNode.Hash != chainedHeader.MerkleRoot)
                    throw CreateMerkleRootException(chainedHeader);
            }
        }
예제 #27
0
        public bool TryAddChainedHeader(ChainedHeader chainedHeader)
        {
            var key = MakeHeaderKey(chainedHeader.Hash);

            Slice existingValue;
            if (db.TryGet(ReadOptions.Default, key, out existingValue))
                return false;

            var writeBatch = new WriteBatch();
            try
            {
                writeBatch.Put(key, DataEncoder.EncodeChainedHeader(chainedHeader));
                writeBatch.Put(MakeTotalWorkKey(chainedHeader.Hash, chainedHeader.TotalWork), new byte[1]);

                db.Write(WriteOptions.Default, writeBatch);
            }
            finally
            {
                writeBatch.Dispose();
            }

            return true;
        }
예제 #28
0
        private static ISourceBlock<ValidatableTx> ReplayFromTxIndex(ICoreStorage coreStorage, IChainState chainState, ChainedHeader replayBlock, bool replayForward, CancellationToken cancelToken = default(CancellationToken))
        {
            //TODO use replayForward to retrieve blocks in reverse order
            //TODO also check that the block hasn't been pruned (that information isn't stored yet)

            IEnumerator<BlockTx> blockTxes;
            if (!coreStorage.TryReadBlockTransactions(replayBlock.Hash, out blockTxes))
            {
                throw new MissingDataException(replayBlock.Hash);
            }

            var blockTxesBuffer = new BufferBlock<DecodedBlockTx>();
            if (replayForward)
                blockTxesBuffer.SendAndCompleteAsync(blockTxes.UsingAsEnumerable().Select(x => x.Decode()), cancelToken).Forget();
            else
                blockTxesBuffer.SendAndCompleteAsync(blockTxes.UsingAsEnumerable().Select(x => x.Decode()).Reverse(), cancelToken).Forget();

            // begin looking up txes
            var lookupValidatableTx = InitLookupValidatableTx(chainState, replayBlock, cancelToken);
            blockTxesBuffer.LinkTo(lookupValidatableTx, new DataflowLinkOptions { PropagateCompletion = true });

            return lookupValidatableTx;
        }
예제 #29
0
        /// <summary>
        /// Remove a chained header to the end of this builder.
        /// </summary>
        /// <param name="chainedHeader">The chained header to remove.</param>
        /// <exception cref="InvalidOperationException">Thrown if the chained header is not the last block in the chain.</exception>
        public ChainBuilder RemoveBlock(ChainedHeader chainedHeader)
        {
            var lastBlock = this.LastBlock;
            if (lastBlock == null
                || chainedHeader != lastBlock)
                throw new InvalidOperationException();

            this.blocks.RemoveAt(this.blocks.Count - 1);
            this.blocksByHash.Remove(chainedHeader.Hash);

            return this;
        }
예제 #30
0
        /// <summary>
        /// Add a chained header to the end of this builder.
        /// </summary>
        /// <param name="chainedHeader">The chained header to add.</param>
        /// <exception cref="InvalidOperationException">Thrown if the chained header does not chain off of the last block in the chain, based on height and previous block hash.</exception>
        public ChainBuilder AddBlock(ChainedHeader chainedHeader)
        {
            var lastBlock = this.LastBlock;
            var expectedHash = lastBlock?.Hash ?? chainedHeader.PreviousBlockHash;
            var expectedHeight = (lastBlock?.Height ?? -1) + 1;

            if (chainedHeader.PreviousBlockHash != expectedHash
                || chainedHeader.Height != expectedHeight)
                throw new InvalidOperationException();

            this.blocks.Add(chainedHeader);
            this.blocksByHash.Add(chainedHeader.Hash, chainedHeader);

            return this;
        }
예제 #31
0
 public static BlockchainPath CreateSingleBlockPath(ChainedHeader chainedHeader)
 {
     return(new BlockchainPath(chainedHeader, chainedHeader, chainedHeader, ImmutableList.Create <ChainedHeader>(), ImmutableList.Create <ChainedHeader>()));
 }
예제 #32
0
파일: Chain.cs 프로젝트: sph001/BitSharp
 public static Chain CreateForGenesisBlock(ChainedHeader genesisBlock)
 {
     return(new Chain(ImmutableList.Create <ChainedHeader>(genesisBlock)));
 }