Exemplo n.º 1
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);
            }
        }
Exemplo n.º 2
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);
        }
Exemplo n.º 3
0
        public static async Task ValidateBlockAsync(ICoreStorage coreStorage, ICoreRules rules, Chain newChain, ISourceBlock<ValidatableTx> validatableTxes, CancellationToken cancelToken = default(CancellationToken))
        {
            // tally transactions
            object finalTally = null;
            var txTallier = new TransformBlock<ValidatableTx, ValidatableTx>(
                validatableTx =>
                {
                    var runningTally = finalTally;
                    rules.TallyTransaction(newChain, validatableTx, ref runningTally);
                    finalTally = runningTally;

                    return validatableTx;
                });
            validatableTxes.LinkTo(txTallier, new DataflowLinkOptions { PropagateCompletion = true });

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

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

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

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

            //TODO
            await PipelineCompletion.Create(
                new Task[] { },
                new IDataflowBlock[] { validatableTxes, txTallier, txValidator, scriptValidator });

            // validate overall block
            rules.PostValidateBlock(newChain, finalTally);
        }
Exemplo n.º 4
0
        public UnconfirmedTxesBuilder(ICoreDaemon coreDaemon, ICoreStorage coreStorage, IStorageManager storageManager)
        {
            this.coreDaemon = coreDaemon;
            this.coreStorage = coreStorage;
            this.storageManager = storageManager;

            this.chain = new Lazy<Chain>(() => LoadChain());
        }
Exemplo n.º 5
0
        public UnconfirmedTxesBuilder(ICoreDaemon coreDaemon, ICoreStorage coreStorage, IStorageManager storageManager)
        {
            this.coreDaemon     = coreDaemon;
            this.coreStorage    = coreStorage;
            this.storageManager = storageManager;

            this.chain = new Lazy <Chain>(() => LoadChain());
        }
Exemplo n.º 6
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;
            }
        }
Exemplo n.º 7
0
        public ChainStateBuilder(ICoreRules rules, ICoreStorage coreStorage, IStorageManager storageManager)
        {
            this.rules          = rules;
            this.coreStorage    = coreStorage;
            this.storageManager = storageManager;

            this.chain = new Lazy <Chain>(() => LoadChain());

            this.stats       = new ChainStateBuilderStats();
            this.utxoBuilder = new UtxoBuilder();
        }
Exemplo n.º 8
0
        public static ISourceBlock<ValidatableTx> ReplayBlock(ICoreStorage coreStorage, IChainState chainState, UInt256 blockHash, bool replayForward, CancellationToken cancelToken = default(CancellationToken))
        {
            ChainedHeader replayBlock;
            if (!coreStorage.TryGetChainedHeader(blockHash, out replayBlock))
                throw new MissingDataException(blockHash);

            // replay the validatable txes for this block, in reverse order for a rollback
            ISourceBlock<ValidatableTx> validatableTxes;
            if (replayForward)
                validatableTxes = UtxoReplayer.ReplayCalculateUtxo(coreStorage, chainState, replayBlock, cancelToken);
            else
                validatableTxes = UtxoReplayer.ReplayRollbackUtxo(coreStorage, chainState, replayBlock, cancelToken);

            return validatableTxes;
        }
Exemplo n.º 9
0
        public static ISourceBlock<LoadedTx> LoadTxes(ICoreStorage coreStorage, ISourceBlock<LoadingTx> loadingTxes, CancellationToken cancelToken = default(CancellationToken))
        {
            // split incoming LoadingTx by its number of inputs
            var createTxInputList = InitCreateTxInputList(cancelToken);

            // link the loading txes to the input splitter
            loadingTxes.LinkTo(createTxInputList, new DataflowLinkOptions { PropagateCompletion = true });

            // load each input, and return and fully loaded txes
            var loadTxInputAndReturnLoadedTx = InitLoadTxInputAndReturnLoadedTx(coreStorage, cancelToken);

            // link the input splitter to the input loader
            createTxInputList.LinkTo(loadTxInputAndReturnLoadedTx, new DataflowLinkOptions { PropagateCompletion = true });

            return loadTxInputAndReturnLoadedTx;
        }
Exemplo n.º 10
0
        private static LoadedTx LoadTxInput(ICoreStorage coreStorage, ConcurrentDictionary <TxLookupKey, Lazy <BlockTx> > txCache, LoadingTx loadingTx, int inputIndex)
        {
            var txIndex       = loadingTx.TxIndex;
            var transaction   = loadingTx.Transaction;
            var chainedHeader = loadingTx.ChainedHeader;

            // load previous transaction for this input, unless this is a coinbase transaction
            if (!loadingTx.IsCoinbase)
            {
                var prevOutputTxKey = loadingTx.PrevOutputTxKeys[inputIndex];

                var input           = transaction.Inputs[inputIndex];
                var inputPrevTxHash = input.PrevTxOutputKey.TxHash;

                var inputPrevTx = txCache.GetOrAdd(prevOutputTxKey, new Lazy <BlockTx>(() =>
                {
                    BlockTx tx;
                    if (coreStorage.TryGetTransaction(prevOutputTxKey.BlockHash, prevOutputTxKey.TxIndex, out tx))
                    {
                        return(tx);
                    }
                    else
                    {
                        throw new MissingDataException(prevOutputTxKey.BlockHash);
                    }
                })).Value;

                if (input.PrevTxOutputKey.TxHash != inputPrevTx.Hash)
                {
                    throw new Exception("TODO");
                }

                if (loadingTx.InputTxes.TryComplete(inputIndex, inputPrevTx.Decode().DecodedTx))
                {
                    return(loadingTx.ToLoadedTx());
                }
                else
                {
                    return(null);
                }
            }
            else
            {
                Debug.Assert(inputIndex == -1);
                return(new LoadedTx(transaction, txIndex, ImmutableArray.Create <DecodedTx>()));
            }
        }
Exemplo n.º 11
0
        private static TransformManyBlock<Tuple<LoadingTx, int>, LoadedTx> InitLoadTxInputAndReturnLoadedTx(ICoreStorage coreStorage, CancellationToken cancelToken)
        {
            var txCache = new ConcurrentDictionary<TxLookupKey, Lazy<BlockTx>>();
            return new TransformManyBlock<Tuple<LoadingTx, int>, LoadedTx>(
                tuple =>
                {
                    var loadingTx = tuple.Item1;
                    var inputIndex = tuple.Item2;

                    var loadedTx = LoadTxInput(coreStorage, txCache, loadingTx, inputIndex);
                    if (loadedTx != null)
                        return new[] { loadedTx };
                    else
                        return new LoadedTx[0];
                },
                new ExecutionDataflowBlockOptions { CancellationToken = cancelToken, MaxDegreeOfParallelism = Environment.ProcessorCount });
        }
Exemplo n.º 12
0
        private async Task ScanBlock(ICoreStorage coreStorage, IChainState chainState, ChainedHeader scanBlock, bool forward, CancellationToken cancelToken = default(CancellationToken))
        {
            var replayTxes = BlockReplayer.ReplayBlock(coreStorage, chainState, scanBlock.Hash, forward, cancelToken);

            var txScanner = new ActionBlock <ValidatableTx>(
                validatableTx =>
            {
                var tx      = validatableTx.Transaction;
                var txIndex = validatableTx.Index;

                if (!validatableTx.IsCoinbase)
                {
                    for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++)
                    {
                        var input                = tx.Inputs[inputIndex];
                        var prevOutput           = validatableTx.PrevTxOutputs[inputIndex];
                        var prevOutputScriptHash = new UInt256(SHA256Static.ComputeHash(prevOutput.ScriptPublicKey));

                        var chainPosition = ChainPosition.Fake();
                        var entryType     = forward ? EnumWalletEntryType.Spend : EnumWalletEntryType.UnSpend;

                        ScanForEntry(chainPosition, entryType, (TxOutput)prevOutput, prevOutputScriptHash);
                    }
                }

                for (var outputIndex = 0; outputIndex < tx.Outputs.Length; outputIndex++)
                {
                    var output           = tx.Outputs[outputIndex];
                    var outputScriptHash = new UInt256(SHA256Static.ComputeHash(output.ScriptPublicKey));

                    var chainPosition = ChainPosition.Fake();
                    var entryType     =
                        validatableTx.IsCoinbase ?
                        (forward ? EnumWalletEntryType.Mine : EnumWalletEntryType.UnMine)
                                : (forward ? EnumWalletEntryType.Receive : EnumWalletEntryType.UnReceieve);

                    ScanForEntry(chainPosition, entryType, output, outputScriptHash);
                }
            });

            replayTxes.LinkTo(txScanner, new DataflowLinkOptions {
                PropagateCompletion = true
            });
            await txScanner.Completion;
        }
Exemplo n.º 13
0
        public static async Task ValidateBlockAsync(ICoreStorage coreStorage, ICoreRules rules, Chain newChain, ISourceBlock <ValidatableTx> validatableTxes, CancellationToken cancelToken = default(CancellationToken))
        {
            // tally transactions
            object finalTally = null;
            var    txTallier  = new TransformBlock <ValidatableTx, ValidatableTx>(
                validatableTx =>
            {
                var runningTally = finalTally;
                rules.TallyTransaction(newChain, validatableTx, ref runningTally);
                finalTally = runningTally;

                return(validatableTx);
            });

            validatableTxes.LinkTo(txTallier, new DataflowLinkOptions {
                PropagateCompletion = true
            });

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

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

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

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

            //TODO
            await PipelineCompletion.Create(
                new Task[] { },
                new IDataflowBlock[] { validatableTxes, txTallier, txValidator, scriptValidator });

            // validate overall block
            rules.PostValidateBlock(newChain, finalTally);
        }
Exemplo n.º 14
0
        public static ISourceBlock <LoadedTx> LoadTxes(ICoreStorage coreStorage, ISourceBlock <LoadingTx> loadingTxes, CancellationToken cancelToken = default(CancellationToken))
        {
            // split incoming LoadingTx by its number of inputs
            var createTxInputList = InitCreateTxInputList(cancelToken);

            // link the loading txes to the input splitter
            loadingTxes.LinkTo(createTxInputList, new DataflowLinkOptions {
                PropagateCompletion = true
            });

            // load each input, and return and fully loaded txes
            var loadTxInputAndReturnLoadedTx = InitLoadTxInputAndReturnLoadedTx(coreStorage, cancelToken);

            // link the input splitter to the input loader
            createTxInputList.LinkTo(loadTxInputAndReturnLoadedTx, new DataflowLinkOptions {
                PropagateCompletion = true
            });

            return(loadTxInputAndReturnLoadedTx);
        }
Exemplo n.º 15
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);
            }
        }
Exemplo n.º 16
0
        public static ISourceBlock <ValidatableTx> ReplayBlock(ICoreStorage coreStorage, IChainState chainState, UInt256 blockHash, bool replayForward, CancellationToken cancelToken = default(CancellationToken))
        {
            ChainedHeader replayBlock;

            if (!coreStorage.TryGetChainedHeader(blockHash, out replayBlock))
            {
                throw new MissingDataException(blockHash);
            }

            // replay the validatable txes for this block, in reverse order for a rollback
            ISourceBlock <ValidatableTx> validatableTxes;

            if (replayForward)
            {
                validatableTxes = UtxoReplayer.ReplayCalculateUtxo(coreStorage, chainState, replayBlock, cancelToken);
            }
            else
            {
                validatableTxes = UtxoReplayer.ReplayRollbackUtxo(coreStorage, chainState, replayBlock, cancelToken);
            }

            return(validatableTxes);
        }
Exemplo n.º 17
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;
        }
Exemplo n.º 18
0
        public static ISourceBlock<LoadedTx> ReplayBlock(ICoreStorage coreStorage, IChainState chainState, UInt256 blockHash, bool replayForward, CancellationToken cancelToken = default(CancellationToken))
        {
            ChainedHeader replayBlock;
            if (!coreStorage.TryGetChainedHeader(blockHash, out replayBlock))
                throw new MissingDataException(blockHash);

            // replay the loading txes for this block, in reverse order for a rollback
            ISourceBlock<LoadingTx> loadingTxes;
            if (replayForward)
                loadingTxes = UtxoReplayer.ReplayCalculateUtxo(coreStorage, chainState, replayBlock, cancelToken);
            else
                loadingTxes = UtxoReplayer.ReplayRollbackUtxo(coreStorage, chainState, replayBlock, cancelToken);

            // capture the original loading txes order
            var orderedLoadingTxes = OrderingBlock.CaptureOrder<LoadingTx, LoadedTx, UInt256>(
                loadingTxes, loadingTx => loadingTx.Transaction.Hash, cancelToken);

            // begin loading txes
            var loadedTxes = TxLoader.LoadTxes(coreStorage, orderedLoadingTxes, cancelToken);

            // return the loaded txes in original order
            return orderedLoadingTxes.ApplyOrder(loadedTxes, loadedTx => loadedTx.Transaction.Hash, cancelToken);
        }
Exemplo n.º 19
0
        private static LoadedTx LoadTxInput(ICoreStorage coreStorage, ConcurrentDictionary<TxLookupKey, Lazy<BlockTx>> txCache, LoadingTx loadingTx, int inputIndex)
        {
            var txIndex = loadingTx.TxIndex;
            var transaction = loadingTx.Transaction;
            var chainedHeader = loadingTx.ChainedHeader;

            // load previous transaction for this input, unless this is a coinbase transaction
            if (!loadingTx.IsCoinbase)
            {
                var prevOutputTxKey = loadingTx.PrevOutputTxKeys[inputIndex];

                var input = transaction.Inputs[inputIndex];
                var inputPrevTxHash = input.PrevTxOutputKey.TxHash;

                var inputPrevTx = txCache.GetOrAdd(prevOutputTxKey, new Lazy<BlockTx>(() =>
                    {
                        BlockTx tx;
                        if (coreStorage.TryGetTransaction(prevOutputTxKey.BlockHash, prevOutputTxKey.TxIndex, out tx))
                            return tx;
                        else
                            throw new MissingDataException(prevOutputTxKey.BlockHash);
                    })).Value;

                if (input.PrevTxOutputKey.TxHash != inputPrevTx.Hash)
                    throw new Exception("TODO");

                if (loadingTx.InputTxes.TryComplete(inputIndex, inputPrevTx.Decode().DecodedTx))
                    return loadingTx.ToLoadedTx();
                else
                    return null;
            }
            else
            {
                Debug.Assert(inputIndex == -1);
                return new LoadedTx(transaction, txIndex, ImmutableArray.Create<DecodedTx>());
            }
        }
Exemplo n.º 20
0
 public static ISourceBlock <ValidatableTx> ReplayCalculateUtxo(ICoreStorage coreStorage, IChainState chainState, ChainedHeader replayBlock, CancellationToken cancelToken = default(CancellationToken))
 {
     return(ReplayFromTxIndex(coreStorage, chainState, replayBlock, replayForward: true, cancelToken: cancelToken));
 }
Exemplo n.º 21
0
 public static ISourceBlock<ValidatableTx> ReplayCalculateUtxo(ICoreStorage coreStorage, IChainState chainState, ChainedHeader replayBlock, CancellationToken cancelToken = default(CancellationToken))
 {
     return ReplayFromTxIndex(coreStorage, chainState, replayBlock, replayForward: true, cancelToken: cancelToken);
 }
Exemplo n.º 22
0
        private static TransformManyBlock <Tuple <LoadingTx, int>, LoadedTx> InitLoadTxInputAndReturnLoadedTx(ICoreStorage coreStorage, CancellationToken cancelToken)
        {
            var txCache = new ConcurrentDictionary <TxLookupKey, Lazy <BlockTx> >();

            return(new TransformManyBlock <Tuple <LoadingTx, int>, LoadedTx>(
                       tuple =>
            {
                var loadingTx = tuple.Item1;
                var inputIndex = tuple.Item2;

                var loadedTx = LoadTxInput(coreStorage, txCache, loadingTx, inputIndex);
                if (loadedTx != null)
                {
                    return new[] { loadedTx }
                }
                ;
                else
                {
                    return new LoadedTx[0];
                }
            },
                       new ExecutionDataflowBlockOptions {
                CancellationToken = cancelToken, MaxDegreeOfParallelism = Environment.ProcessorCount
            }));
        }
Exemplo n.º 23
0
        private static ISourceBlock<LoadingTx> 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, /*requireTransaction:*/true, out blockTxes))
            {
                throw new MissingDataException(replayBlock.Hash);
            }

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

            // capture the original block txes order
            var orderedBlockTxes = OrderingBlock.CaptureOrder<BlockTx, LoadingTx, UInt256>(
                blockTxesBuffer, blockTx => blockTx.Transaction.Hash, cancelToken);

            // begin looking up txes
            var lookupLoadingTx = InitLookupLoadingTx(chainState, replayBlock, cancelToken);
            orderedBlockTxes.LinkTo(lookupLoadingTx, new DataflowLinkOptions { PropagateCompletion = true });

            // return the loading txes in original order
            return orderedBlockTxes.ApplyOrder(lookupLoadingTx, loadingTx => loadingTx.Transaction.Hash, cancelToken); ;
        }
Exemplo n.º 24
0
        private async Task ScanBlock(ICoreStorage coreStorage, IChainState chainState, ChainedHeader scanBlock, bool forward, CancellationToken cancelToken = default(CancellationToken))
        {
            var replayTxes = BlockReplayer.ReplayBlock(coreStorage, chainState, scanBlock.Hash, forward, cancelToken);

            var txScanner = new ActionBlock<ValidatableTx>(
                validatableTx =>
                {
                    var tx = validatableTx.Transaction;
                    var txIndex = validatableTx.Index;

                    if (!validatableTx.IsCoinbase)
                    {
                        for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++)
                        {
                            var input = tx.Inputs[inputIndex];
                            var prevOutput = validatableTx.PrevTxOutputs[inputIndex];
                            var prevOutputScriptHash = new UInt256(SHA256Static.ComputeHash(prevOutput.ScriptPublicKey));

                            var chainPosition = ChainPosition.Fake();
                            var entryType = forward ? EnumWalletEntryType.Spend : EnumWalletEntryType.UnSpend;

                            ScanForEntry(chainPosition, entryType, (TxOutput)prevOutput, prevOutputScriptHash);
                        }
                    }

                    for (var outputIndex = 0; outputIndex < tx.Outputs.Length; outputIndex++)
                    {
                        var output = tx.Outputs[outputIndex];
                        var outputScriptHash = new UInt256(SHA256Static.ComputeHash(output.ScriptPublicKey));

                        var chainPosition = ChainPosition.Fake();
                        var entryType =
                            validatableTx.IsCoinbase ?
                                (forward ? EnumWalletEntryType.Mine : EnumWalletEntryType.UnMine)
                                : (forward ? EnumWalletEntryType.Receive : EnumWalletEntryType.UnReceieve);

                        ScanForEntry(chainPosition, entryType, output, outputScriptHash);
                    }
                });

            replayTxes.LinkTo(txScanner, new DataflowLinkOptions { PropagateCompletion = true });
            await txScanner.Completion;
        }