コード例 #1
0
        public Keccak GetBlockhash(BlockHeader currentBlock, UInt256 number)
        {
            UInt256 current = currentBlock.Number;

            if (number >= current || number < current - UInt256.Min(current, (UInt256)_maxDepth))
            {
                return(null);
            }

            BlockHeader header = _chain.FindHeader(currentBlock.ParentHash);

            for (var i = 0; i < _maxDepth; i++)
            {
                if (number == header.Number)
                {
                    return(header.Hash);
                }

                header = _chain.FindHeader(header.ParentHash);
                if (_chain.IsMainChain(header.Hash))
                {
                    header = _chain.FindHeader(number);
                }
            }

            return(null);
        }
コード例 #2
0
        private GethLikeTxTrace[] TraceBlock(Block?block, GethTraceOptions options, CancellationToken cancellationToken, Keccak?txHash = null)
        {
            if (block == null)
            {
                throw new InvalidOperationException("Only canonical, historical blocks supported");
            }

            if (!block.IsGenesis)
            {
                BlockHeader?parent = _blockTree.FindParentHeader(block.Header, BlockTreeLookupOptions.None);
                if (parent?.Hash is null)
                {
                    throw new InvalidOperationException("Cannot trace blocks with invalid parents");
                }

                if (!_blockTree.IsMainChain(parent.Hash))
                {
                    throw new InvalidOperationException("Cannot trace orphaned blocks");
                }
            }

            GethLikeBlockTracer listener = txHash == null ? new GethLikeBlockTracer(options) : new GethLikeBlockTracer(txHash, options);

            _processor.Process(block, ProcessingOptions.Trace, listener.WithCancellation(cancellationToken));
            return(listener.BuildResult().ToArray());
        }
コード例 #3
0
            public override async Task <BlockVisitOutcome> VisitBlock(Block block, CancellationToken cancellationToken)
            {
                BlockVisitOutcome outcome = await base.VisitBlock(block, cancellationToken);

                if (_blockTree.IsMainChain(block.Header))
                {
                    _receiptStorage.EnsureCanonical(block);
                }

                return(outcome);
            }
コード例 #4
0
        private GethLikeTxTrace[] TraceBlock(Block block)
        {
            if (block == null)
            {
                throw new InvalidOperationException("Only canonical, historical blocks supported");
            }

            if (block.Number != 0)
            {
                Block parent = _blockTree.FindParent(block);
                if (!_blockTree.IsMainChain(parent.Hash))
                {
                    throw new InvalidOperationException("Cannot trace orphaned blocks");
                }
            }

            GethLikeBlockTracer listener = new GethLikeBlockTracer();

            _processor.Process(block, ProcessingOptions.ForceProcessing | ProcessingOptions.WithRollback | ProcessingOptions.ReadOnlyChain | ProcessingOptions.NoValidation, listener);
            return(listener.BuildResult().ToArray());
        }
コード例 #5
0
        public async Task Happy_path(long headNumber, int options)
        {
            BlockDownloader.DownloadOptions downloadOptions = (BlockDownloader.DownloadOptions)options;
            bool withReceipts = downloadOptions == BlockDownloader.DownloadOptions.DownloadWithReceipts;
            InMemoryReceiptStorage inMemoryReceiptStorage = new InMemoryReceiptStorage();
            BlockDownloader        blockDownloader        = new BlockDownloader(_blockTree, TestBlockValidator.AlwaysValid, TestSealValidator.AlwaysValid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance);

            ISyncPeer            syncPeer             = Substitute.For <ISyncPeer>();
            Task <BlockHeader[]> buildHeadersResponse = null;

            syncPeer.GetBlockHeaders(Arg.Any <long>(), Arg.Any <int>(), Arg.Any <int>(), Arg.Any <CancellationToken>())
            .Returns(ci => buildHeadersResponse = _responseBuilder.BuildHeaderResponse(ci.ArgAt <long>(0), ci.ArgAt <int>(1), Response.AllCorrect));

            Response blockResponseOptions = Response.AllCorrect;

            if (withReceipts)
            {
                blockResponseOptions |= Response.WithTransactions;
            }

            Task <BlockBody[]> buildBlocksResponse = null;

            syncPeer.GetBlocks(Arg.Any <IList <Keccak> >(), Arg.Any <CancellationToken>())
            .Returns(ci => buildBlocksResponse = _responseBuilder.BuildBlocksResponse(ci.ArgAt <IList <Keccak> >(0), blockResponseOptions));

            syncPeer.GetReceipts(Arg.Any <IList <Keccak> >(), Arg.Any <CancellationToken>())
            .Returns(ci => _responseBuilder.BuildReceiptsResponse(buildHeadersResponse.Result, buildBlocksResponse.Result));

            PeerInfo peerInfo = new PeerInfo(syncPeer);

            peerInfo.TotalDifficulty = UInt256.MaxValue;
            peerInfo.HeadNumber      = headNumber;

            await blockDownloader.DownloadHeaders(peerInfo, SyncModeSelector.FullSyncThreshold, CancellationToken.None);

            Assert.AreEqual(Math.Max(0, headNumber - SyncModeSelector.FullSyncThreshold), _blockTree.BestSuggestedHeader.Number, "headers");

            peerInfo.HeadNumber *= 2;
            await blockDownloader.DownloadBlocks(peerInfo, 0, CancellationToken.None, downloadOptions);

            _blockTree.BestSuggestedHeader.Number.Should().Be(Math.Max(0, headNumber * 2));
            _blockTree.IsMainChain(_blockTree.BestSuggestedHeader.Hash).Should().Be(downloadOptions != BlockDownloader.DownloadOptions.DownloadAndProcess);
            inMemoryReceiptStorage.Count.Should().Be(withReceipts ? buildBlocksResponse.Result.Sum(b => b.Transactions?.Length ?? 0) : 0);
        }
コード例 #6
0
        private GethLikeTxTrace[] TraceBlock(Block block, GethTraceOptions options, Keccak txHash = null)
        {
            if (block == null)
            {
                throw new InvalidOperationException("Only canonical, historical blocks supported");
            }

            if (block.Number != 0)
            {
                BlockHeader parent = _blockTree.FindParentHeader(block.Header, BlockTreeLookupOptions.None);
                if (!_blockTree.IsMainChain(parent.Hash))
                {
                    throw new InvalidOperationException("Cannot trace orphaned blocks");
                }
            }

            GethLikeBlockTracer listener = txHash == null ? new GethLikeBlockTracer(options) : new GethLikeBlockTracer(txHash, options);

            _processor.Process(block, ProcessingOptions.Trace, listener);
            return(listener.BuildResult().ToArray());
        }
コード例 #7
0
        public FullTransaction MapFullTransaction(Kafka.Models.FullTransaction fullTransaction)
        {
            var index       = fullTransaction.Index;
            var transaction = fullTransaction.Transaction;
            var receipt     = fullTransaction.Receipt;
            var removed     = !_blockTree.IsMainChain(receipt.BlockHash);

            return(new FullTransaction
            {
                minedAt = (long)_blockTree.FindBlock(receipt.BlockHash, BlockTreeLookupOptions.None).Timestamp,
                blockNumber = (long)receipt.BlockNumber,
                receipt = new Receipt
                {
                    transactionIndex = index,
                    blockNumber = (long)receipt.BlockNumber,
                    toAddr = receipt.Recipient?.ToString() ?? string.Empty,
                    blockHash = receipt.BlockHash.ToString(),
                    fromAddr = receipt.Sender?.ToString() ?? string.Empty,
                    logsBloom = receipt.Bloom.ToString(),
                    gasUsed = receipt.GasUsed,
                    contractAddress = receipt.ContractAddress?.ToString() ?? string.Empty,
                    transactionHash = receipt.TxHash.ToString(),
                    cumulativeGasUsed = receipt.GasUsedTotal,
                    status = receipt.StatusCode,
                    logs = receipt.Logs?.Select((l, i) => new Log
                    {
                        logIndex = i,
                        blockNumber = (long)receipt.BlockNumber,
                        transactionIndex = receipt.Index,
                        blockHash = receipt.BlockHash.ToString(),
                        data = l.Data.ToString(),
                        transactionHash = receipt.TxHash.ToString(),
                        address = l.LoggersAddress.ToString(),
                        logTopics = l.Topics?.Select(t => t.ToString()).ToList() ?? new List <string>(),
                        removed = removed
                    }).ToList() ?? new List <Log>()
                },
                tx = MapTransaction(index, receipt.BlockNumber, receipt.BlockHash, transaction)
            });
        }
コード例 #8
0
 public bool IsMainChain(BlockHeader blockHeader) => _blockTree.IsMainChain(blockHeader);
コード例 #9
0
ファイル: Program.cs プロジェクト: AlexSSD7/nethermind
 public bool IsMainChain(BlockHeader blockHeader)
 {
     return(_blockTree.IsMainChain(blockHeader));
 }
コード例 #10
0
 public bool IsMainChain(BlockHeader blockHeader) => _wrapped.IsMainChain(blockHeader);
コード例 #11
0
ファイル: Program.cs プロジェクト: fosfuan/nethermind
 public bool IsMainChain(Keccak blockHash)
 {
     return(_blockTree.IsMainChain(blockHash));
 }
コード例 #12
0
 public bool IsMainChain(Keccak blockHash)
 {
     return(_wrapped.IsMainChain(blockHash));
 }
コード例 #13
0
 public static bool IsOnMainChainBehindHead(this IBlockTree blockTree, Block block) =>
 block.Number < (blockTree.Head?.Number ?? 0) && blockTree.IsMainChain(block.Header);
コード例 #14
0
        public Block Process(Block suggestedBlock, ProcessingOptions options, IBlockTracer blockTracer)
        {
            if (!RunSimpleChecksAheadOfProcessing(suggestedBlock, options))
            {
                return(null);
            }

            UInt256 totalDifficulty = suggestedBlock.TotalDifficulty ?? 0;

            if (_logger.IsTrace)
            {
                _logger.Trace($"Total difficulty of block {suggestedBlock.ToString(Block.Format.Short)} is {totalDifficulty}");
            }

            BlockHeader branchingPoint = null;

            Block[] processedBlocks = null;
            if (_blockTree.Head == null || totalDifficulty > _blockTree.Head.TotalDifficulty || (options & ProcessingOptions.ForceProcessing) != 0)
            {
                List <Block> blocksToBeAddedToMain = new List <Block>();
                Block        toBeProcessed         = suggestedBlock;
                do
                {
                    blocksToBeAddedToMain.Add(toBeProcessed);
                    if (_logger.IsTrace)
                    {
                        _logger.Trace($"To be processed (of {suggestedBlock.ToString(Block.Format.Short)}) is {toBeProcessed?.ToString(Block.Format.Short)}");
                    }
                    if (toBeProcessed.IsGenesis)
                    {
                        break;
                    }

                    branchingPoint = _blockTree.FindParentHeader(toBeProcessed.Header, BlockTreeLookupOptions.TotalDifficultyNotNeeded);
                    if (branchingPoint == null)
                    {
                        break; //failure here
                    }

                    bool isFastSyncTransition = _blockTree.Head == _blockTree.Genesis && toBeProcessed.Number > 1;
                    if (!isFastSyncTransition)
                    {
                        if (_logger.IsTrace)
                        {
                            _logger.Trace($"Finding parent of {toBeProcessed.ToString(Block.Format.Short)}");
                        }
                        toBeProcessed = _blockTree.FindParent(toBeProcessed.Header, BlockTreeLookupOptions.None);
                        if (_logger.IsTrace)
                        {
                            _logger.Trace($"Found parent {toBeProcessed?.ToString(Block.Format.Short)}");
                        }

                        if (toBeProcessed == null)
                        {
                            if (_logger.IsTrace)
                            {
                                _logger.Trace($"Treating this as fast sync transition for {suggestedBlock.ToString(Block.Format.Short)}");
                            }
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }
                } while (!_blockTree.IsMainChain(branchingPoint.Hash));

                if (branchingPoint != null && branchingPoint.Hash != _blockTree.Head?.Hash)
                {
                    if (_logger.IsTrace)
                    {
                        _logger.Trace($"Head block was: {_blockTree.Head?.ToString(BlockHeader.Format.Short)}");
                    }
                    if (_logger.IsTrace)
                    {
                        _logger.Trace($"Branching from: {branchingPoint.ToString(BlockHeader.Format.Short)}");
                    }
                }
                else
                {
                    if (_logger.IsTrace)
                    {
                        _logger.Trace(branchingPoint == null ? "Setting as genesis block" : $"Adding on top of {branchingPoint.ToString(BlockHeader.Format.Short)}");
                    }
                }

                Keccak stateRoot = branchingPoint?.StateRoot;
                if (_logger.IsTrace)
                {
                    _logger.Trace($"State root lookup: {stateRoot}");
                }

                List <Block> blocksToProcess = new List <Block>();
                Block[]      blocks;
                if ((options & ProcessingOptions.ForceProcessing) != 0)
                {
                    blocksToBeAddedToMain.Clear();
                    blocks    = new Block[1];
                    blocks[0] = suggestedBlock;
                }
                else
                {
                    foreach (Block block in blocksToBeAddedToMain)
                    {
                        if (block.Hash != null && _blockTree.WasProcessed(block.Number, block.Hash))
                        {
                            if (_logger.IsInfo)
                            {
                                _logger.Info($"Rerunning block after reorg: {block.ToString(Block.Format.FullHashAndNumber)}");
                            }
                        }

                        blocksToProcess.Add(block);
                    }

                    blocks = new Block[blocksToProcess.Count];
                    for (int i = 0; i < blocksToProcess.Count; i++)
                    {
                        blocks[blocks.Length - i - 1] = blocksToProcess[i];
                    }
                }

                if (_logger.IsTrace)
                {
                    _logger.Trace($"Processing {blocks.Length} blocks from state root {stateRoot}");
                }

                for (int i = 0; i < blocks.Length; i++)
                {
                    /* this can happen if the block was loaded as an ancestor and did not go through the recovery queue */
                    _recoveryStep.RecoverData(blocks[i]);
                }

                try
                {
                    processedBlocks = _blockProcessor.Process(stateRoot, blocks, options, blockTracer);
                }
                catch (InvalidBlockException ex)
                {
                    for (int i = 0; i < blocks.Length; i++)
                    {
                        if (blocks[i].Hash == ex.InvalidBlockHash)
                        {
                            _blockTree.DeleteInvalidBlock(blocks[i]);
                            if (_logger.IsDebug)
                            {
                                _logger.Debug($"Skipped processing of {suggestedBlock.ToString(Block.Format.FullHashAndNumber)} because of {blocks[i].ToString(Block.Format.FullHashAndNumber)} is invalid");
                            }
                            return(null);
                        }
                    }
                }

                if ((options & ProcessingOptions.ReadOnlyChain) == 0)
                {
                    _blockTree.UpdateMainChain(blocksToBeAddedToMain.ToArray());
                }
            }
            else
            {
                if (_logger.IsDebug)
                {
                    _logger.Debug($"Skipped processing of {suggestedBlock.ToString(Block.Format.FullHashAndNumber)}, Head = {_blockTree.Head?.ToString(BlockHeader.Format.Short)}, total diff = {totalDifficulty}, head total diff = {_blockTree.Head?.TotalDifficulty}");
                }
            }

            Block lastProcessed = null;

            if (processedBlocks != null && processedBlocks.Length > 0)
            {
                lastProcessed = processedBlocks[^ 1];
コード例 #15
0
 private bool IsInconsistent(Keccak blockHash) => blockHash != Keccak.Zero && !_blockTree.IsMainChain(blockHash);
コード例 #16
0
        private void Process(Block suggestedBlock, bool forMining)
        {
            if (suggestedBlock.Number != 0 && _blockTree.FindParent(suggestedBlock) == null)
            {
                throw new InvalidOperationException("Got an orphaned block for porcessing.");
            }

            if (suggestedBlock.Header.TotalDifficulty == null)
            {
                throw new InvalidOperationException("block without total difficulty calculated was suggested for processing");
            }

            if (!forMining && suggestedBlock.Hash == null)
            {
                throw new InvalidOperationException("block hash should be known at this stage if the block is not mining");
            }

            foreach (BlockHeader ommerHeader in suggestedBlock.Ommers)
            {
                if (ommerHeader.Hash == null)
                {
                    throw new InvalidOperationException("ommer's hash is null when processing block");
                }
            }

            BigInteger totalDifficulty   = suggestedBlock.TotalDifficulty ?? 0;
            BigInteger totalTransactions = suggestedBlock.TotalTransactions ?? 0;

            if (_logger.IsDebugEnabled)
            {
                _logger.Debug($"Total difficulty of block {suggestedBlock.ToString(Block.Format.Short)} is {totalDifficulty}");
                _logger.Debug($"Total transactions of block {suggestedBlock.ToString(Block.Format.Short)} is {totalTransactions}");
            }

            if (totalDifficulty > (_blockTree.Head?.TotalDifficulty ?? 0))
            {
                List <Block> blocksToBeAddedToMain = new List <Block>();
                Block        toBeProcessed         = suggestedBlock;
                do
                {
                    blocksToBeAddedToMain.Add(toBeProcessed);
                    toBeProcessed = toBeProcessed.Number == 0 ? null : _blockTree.FindParent(toBeProcessed);
                    // TODO: need to remove the hardcoded head block store at keccak zero as it would be referenced by the genesis...

                    if (toBeProcessed == null)
                    {
                        break;
                    }
                } while (!_blockTree.IsMainChain(toBeProcessed.Hash));

                BlockHeader branchingPoint = toBeProcessed?.Header;
                if (branchingPoint != null && branchingPoint.Hash != _blockTree.Head?.Hash)
                {
                    if (_logger.IsDebugEnabled)
                    {
                        _logger.Debug($"Head block was: {_blockTree.Head?.ToString(BlockHeader.Format.Short)}");
                        _logger.Debug($"Branching from: {branchingPoint.ToString(BlockHeader.Format.Short)}");
                    }
                }
                else
                {
                    if (_logger.IsDebugEnabled)
                    {
                        _logger.Debug(branchingPoint == null ? "Setting as genesis block" : $"Adding on top of {branchingPoint.ToString(BlockHeader.Format.Short)}");
                    }
                }

                Keccak stateRoot = branchingPoint?.StateRoot;
                if (_logger.IsTraceEnabled)
                {
                    _logger.Trace($"State root lookup: {stateRoot}");
                }

                List <Block> unprocessedBlocksToBeAddedToMain = new List <Block>();

                foreach (Block block in blocksToBeAddedToMain)
                {
                    if (!forMining && _blockTree.WasProcessed(block.Hash))
                    {
                        stateRoot = block.Header.StateRoot;
                        if (_logger.IsTraceEnabled)
                        {
                            _logger.Trace($"State root lookup: {stateRoot}");
                        }

                        break;
                    }

                    unprocessedBlocksToBeAddedToMain.Add(block);
                }

                Block[] blocks = new Block[unprocessedBlocksToBeAddedToMain.Count];
                for (int i = 0; i < unprocessedBlocksToBeAddedToMain.Count; i++)
                {
                    blocks[blocks.Length - i - 1] = unprocessedBlocksToBeAddedToMain[i];
                }

                if (_logger.IsDebugEnabled)
                {
                    _logger.Debug($"Processing {blocks.Length} blocks from state root {stateRoot}");
                }

                //TODO: process blocks one by one here, refactor this, test
                for (int i = 0; i < blocks.Length; i++)
                {
                    if (blocks[i].Transactions.Length > 0 && blocks[i].Transactions[0].SenderAddress == null)
                    {
                        _signer.RecoverAddresses(blocks[i]);
                    }
                }
                Block[] processedBlocks = _blockProcessor.Process(stateRoot, blocks, forMining);

                // TODO: lots of unnecessary loading and decoding here, review after adding support for loading headers only
                List <BlockHeader> blocksToBeRemovedFromMain = new List <BlockHeader>();
                if (_blockTree.Head?.Hash != branchingPoint?.Hash && _blockTree.Head != null)
                {
                    blocksToBeRemovedFromMain.Add(_blockTree.Head);
                    BlockHeader teBeRemovedFromMain = _blockTree.FindHeader(_blockTree.Head.ParentHash);
                    while (teBeRemovedFromMain != null && teBeRemovedFromMain.Hash != branchingPoint?.Hash)
                    {
                        blocksToBeRemovedFromMain.Add(teBeRemovedFromMain);
                        teBeRemovedFromMain = _blockTree.FindHeader(teBeRemovedFromMain.ParentHash);
                    }
                }

                if (!forMining)
                {
                    foreach (Block processedBlock in processedBlocks)
                    {
                        if (_logger.IsDebugEnabled)
                        {
                            _logger.Debug($"Marking {processedBlock.ToString(Block.Format.Short)} as processed");
                        }

                        // TODO: review storage and retrieval of receipts since we removed them from the block class
                        _blockTree.MarkAsProcessed(processedBlock.Hash);
                    }

                    Block newHeadBlock = processedBlocks[processedBlocks.Length - 1];
                    newHeadBlock.Header.TotalDifficulty = suggestedBlock.TotalDifficulty; // TODO: cleanup total difficulty
                    if (_logger.IsDebugEnabled)
                    {
                        _logger.Debug($"Setting head block to {newHeadBlock.ToString(Block.Format.Short)}");
                    }

                    foreach (BlockHeader blockHeader in blocksToBeRemovedFromMain)
                    {
                        if (_logger.IsDebugEnabled)
                        {
                            _logger.Debug($"Moving {blockHeader.ToString(BlockHeader.Format.Short)} to branch");
                        }

                        _blockTree.MoveToBranch(blockHeader.Hash);
                        // TODO: only for miners
                        //foreach (Transaction transaction in block.Transactions)
                        //{
                        //    _transactionStore.AddPending(transaction);
                        //}

                        if (_logger.IsDebugEnabled)
                        {
                            _logger.Debug($"Block {blockHeader.ToString(BlockHeader.Format.Short)} moved to branch");
                        }
                    }

                    foreach (Block block in blocksToBeAddedToMain)
                    {
                        if (_logger.IsDebugEnabled)
                        {
                            _logger.Debug($"Moving {block.ToString(Block.Format.Short)} to main");
                        }

                        _blockTree.MoveToMain(block);
                        // TODO: only for miners
                        foreach (Transaction transaction in block.Transactions)
                        {
                            _transactionStore.RemovePending(transaction);
                        }

                        if (_logger.IsDebugEnabled)
                        {
                            _logger.Debug($"Block {block.ToString(Block.Format.Short)} added to main chain");
                        }
                    }

                    if (_logger.IsDebugEnabled)
                    {
                        _logger.Debug($"Updating total difficulty of the main chain to {totalDifficulty}");
                    }
                    if (_logger.IsDebugEnabled)
                    {
                        _logger.Debug($"Updating total transactions of the main chain to {totalTransactions}");
                    }
                }
                else
                {
                    Block blockToBeMined = processedBlocks[processedBlocks.Length - 1];
                    _miningCancellation = new CancellationTokenSource();
                    CancellationTokenSource anyCancellation =
                        CancellationTokenSource.CreateLinkedTokenSource(_miningCancellation.Token, _loopCancellationSource.Token);
                    _sealEngine.MineAsync(blockToBeMined, anyCancellation.Token).ContinueWith(t =>
                    {
                        anyCancellation.Dispose();

                        if (_logger.IsInfoEnabled)
                        {
                            _logger.Info($"Mined a block {t.Result.ToString(Block.Format.Short)} with parent {t.Result.Header.ParentHash}");
                        }

                        Block minedBlock = t.Result;

                        if (minedBlock.Hash == null)
                        {
                            throw new InvalidOperationException("Mined a block with null hash");
                        }

                        _blockTree.SuggestBlock(minedBlock);
                    }, _miningCancellation.Token);
                }
            }
        }