Пример #1
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 });
 }
Пример #2
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);
            }
        }
Пример #3
0
        private ISourceBlock <T> InitMerkleValidator <T>(ChainedHeader chainedHeader, ISourceBlock <T> blockTxes, CancellationToken cancelToken)
            where T : BlockTx
        {
            var merkleStream = new MerkleStream <BlockTxNode>();

            var txHashes      = new HashSet <UInt256>();
            var cve_2012_2459 = false;

            var merkleValidator = new TransformManyBlock <T, T>(
                blockTx =>
            {
                if (cve_2012_2459)
                {
                    return(new T[0]);
                }

                if (txHashes.Add(blockTx.Hash))
                {
                    try
                    {
                        merkleStream.AddNode(blockTx);
                        return(new[] { blockTx });
                    }
                    //TODO
                    catch (InvalidOperationException)
                    {
                        throw CreateMerkleRootException(chainedHeader);
                    }
                }
                else
                {
                    // TODO this needs proper testing, and needs to be made sure this is a safe way to handle the attack
                    // TODO the block should be unmutated before being shared onto the network

                    // CVE-2012-2459
                    // - if a tx has been repeated, this may be a merkle tree malleability attack against the block
                    // - finish the merkle stream early and verify if the root still matches the block header
                    //
                    // - if the root matches, this is a CVE-2012-2459 attack
                    //   - proceed to validate the block normally by ignoring the remaining duplicate transactions
                    //
                    // - if the root does not match
                    //   - the block truly did contain duplicate transactions and is invalid

                    merkleStream.FinishPairing();
                    if (merkleStream.RootNode.Hash == chainedHeader.MerkleRoot)
                    {
                        cve_2012_2459 = true;
                    }
                    else
                    {
                        throw CreateMerkleRootException(chainedHeader);
                    }

                    //TODO throw exception anyway for the sake of the pull tester
                    //return new DecodedBlockTx[0];

                    //TODO remove the attacked version of the block
                    coreStorage.TryRemoveChainedHeader(chainedHeader.Hash);
                    coreStorage.TryRemoveBlockTransactions(chainedHeader.Hash);

                    //TODO fail the block as missing, not invalid
                    throw new MissingDataException(chainedHeader.Hash);
                }
            },
                new ExecutionDataflowBlockOptions {
                CancellationToken = cancelToken
            });

            blockTxes.LinkTo(merkleValidator, new DataflowLinkOptions {
                PropagateCompletion = true
            });

            return(OnCompleteBlock.Create(merkleValidator,
                                          () =>
            {
                try
                {
                    merkleStream.FinishPairing();
                }
                //TODO
                catch (InvalidOperationException)
                {
                    throw CreateMerkleRootException(chainedHeader);
                }

                if (merkleStream.RootNode.Hash != chainedHeader.MerkleRoot)
                {
                    throw CreateMerkleRootException(chainedHeader);
                }
            }, cancelToken));
        }