Beispiel #1
0
        public OmmersValidatorTests()
        {
            _blockTree        = Build.A.BlockTree().OfChainLength(1).TestObject;
            _grandgrandparent = _blockTree.FindBlock(0, BlockTreeLookupOptions.None);
            _grandparent      = Build.A.Block.WithParent(_grandgrandparent).TestObject;
            _duplicateOmmer   = Build.A.Block.WithParent(_grandgrandparent).TestObject;
            _parent           = Build.A.Block.WithParent(_grandparent).WithOmmers(_duplicateOmmer).TestObject;
            _block            = Build.A.Block.WithParent(_parent).TestObject;

            _blockTree.SuggestHeader(_grandparent.Header);
            _blockTree.SuggestHeader(_parent.Header);
            _blockTree.SuggestHeader(_block.Header);
        }
Beispiel #2
0
            public async Task <BlockHeader[]> BuildHeaderResponse(long startNumber, int number, Response flags)
            {
                bool consistent         = flags.HasFlag(Response.Consistent);
                bool validSeals         = flags.HasFlag(Response.ValidSeals);
                bool noEmptySpaces      = flags.HasFlag(Response.NoEmptySpace);
                bool justFirst          = flags.HasFlag(Response.JustFirst);
                bool allKnown           = flags.HasFlag(Response.AllKnown);
                bool timeoutOnFullBatch = flags.HasFlag(Response.TimeoutOnFullBatch);
                bool noBody             = flags.HasFlag(Response.NoBody);

                if (timeoutOnFullBatch && number == SyncBatchSize.Max)
                {
                    throw new TimeoutException();
                }

                BlockHeader startBlock = _blockTree.FindHeader(_testHeaderMapping[startNumber], BlockTreeLookupOptions.None);

                BlockHeader[] headers = new BlockHeader[number];
                headers[0] = startBlock;
                if (!justFirst)
                {
                    for (int i = 1; i < number; i++)
                    {
                        headers[i] = consistent
                            ? Build.A.BlockHeader.WithParent(headers[i - 1]).WithOmmersHash(noBody ? Keccak.OfAnEmptySequenceRlp : Keccak.Zero).TestObject
                            : Build.A.BlockHeader.WithNumber(headers[i - 1].Number + 1).TestObject;

                        if (allKnown)
                        {
                            _blockTree.SuggestHeader(headers[i]);
                        }

                        _testHeaderMapping[startNumber + i] = headers[i].Hash;
                    }
                }

                BlockHeadersMessage message = new BlockHeadersMessage(headers);

                byte[] messageSerialized = _headersSerializer.Serialize(message);
                return(await Task.FromResult(_headersSerializer.Deserialize(messageSerialized).BlockHeaders));
            }
Beispiel #3
0
            public async Task <BlockHeader[]> BuildHeaderResponse(long startNumber, int number, Response flags)
            {
                bool consistent         = flags.HasFlag(Response.Consistent);
                bool validSeals         = flags.HasFlag(Response.ValidSeals);
                bool noEmptySpaces      = flags.HasFlag(Response.NoEmptySpace);
                bool justFirst          = flags.HasFlag(Response.JustFirstHeader);
                bool allKnown           = flags.HasFlag(Response.AllKnown);
                bool timeoutOnFullBatch = flags.HasFlag(Response.TimeoutOnFullBatch);

                if (timeoutOnFullBatch && number == SyncBatchSize.Max)
                {
                    throw new TimeoutException();
                }

                BlockHeader startBlock = _blockTree.FindHeader(_testHeaderMapping[startNumber], false);

                BlockHeader[] headers = new BlockHeader[number];
                headers[0] = startBlock;
                if (!justFirst)
                {
                    for (int i = 1; i < number; i++)
                    {
                        headers[i] = consistent
                            ? Build.A.BlockHeader.WithParent(headers[i - 1]).TestObject
                            : Build.A.BlockHeader.WithNumber(headers[i - 1].Number + 1).TestObject;

                        if (allKnown)
                        {
                            _blockTree.SuggestHeader(headers[i]);
                        }

                        _testHeaderMapping[startNumber + i] = headers[i].Hash;
                    }
                }

                return(await Task.FromResult(headers));
            }
Beispiel #4
0
 public AddBlockResult SuggestHeader(BlockHeader header)
 {
     return(_blockTree.SuggestHeader(header));
 }
Beispiel #5
0
        public async Task <long> DownloadHeaders(PeerInfo bestPeer, int newBlocksToSkip, CancellationToken cancellation)
        {
            if (bestPeer == null)
            {
                string message = $"Not expecting best peer to be null inside the {nameof(BlockDownloader)}";
                _logger.Error(message);
                throw new ArgumentNullException(message);
            }

            int headersSynced       = 0;
            int ancestorLookupLevel = 0;

            long currentNumber = Math.Max(0, Math.Min(_blockTree.BestKnownNumber, bestPeer.HeadNumber - 1));

            while (bestPeer.TotalDifficulty > (_blockTree.BestSuggestedHeader?.TotalDifficulty ?? 0) && currentNumber <= bestPeer.HeadNumber)
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Continue headers sync with {bestPeer} (our best {_blockTree.BestKnownNumber})");
                }

                if (ancestorLookupLevel > MaxReorganizationLength)
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn($"Could not find common ancestor with {bestPeer}");
                    }
                    throw new EthSynchronizationException("Peer with inconsistent chain in sync");
                }

                long blocksLeft       = bestPeer.HeadNumber - currentNumber - newBlocksToSkip;
                int  headersToRequest = (int)BigInteger.Min(blocksLeft + 1, _syncBatchSize.Current);
                if (headersToRequest <= 1)
                {
                    break;
                }

                if (_logger.IsTrace)
                {
                    _logger.Trace($"Headers request {currentNumber}+{headersToRequest} to peer {bestPeer} with {bestPeer.HeadNumber} blocks. Got {currentNumber} and asking for {headersToRequest} more.");
                }
                var headers = await RequestHeaders(bestPeer, cancellation, currentNumber, headersToRequest);

                BlockHeader startingPoint = headers[0] == null ? null : _blockTree.FindHeader(headers[0].Hash, BlockTreeLookupOptions.TotalDifficultyNotNeeded);
                if (startingPoint == null)
                {
                    ancestorLookupLevel += _syncBatchSize.Current;
                    currentNumber        = currentNumber >= _syncBatchSize.Current ? (currentNumber - _syncBatchSize.Current) : 0L;
                    continue;
                }

                _sinceLastTimeout++;
                if (_sinceLastTimeout >= 2)
                {
                    _syncBatchSize.Expand();
                }

                for (int i = 1; i < headers.Length; i++)
                {
                    if (cancellation.IsCancellationRequested)
                    {
                        break;
                    }

                    BlockHeader currentHeader = headers[i];
                    if (currentHeader == null)
                    {
                        if (headersSynced > 0)
                        {
                            break;
                        }

                        return(0);
                    }

                    if (_logger.IsTrace)
                    {
                        _logger.Trace($"Received {currentHeader} from {bestPeer:s}");
                    }
                    bool isValid = i > 1 ? _blockValidator.ValidateHeader(currentHeader, headers[i - 1], false) : _blockValidator.ValidateHeader(currentHeader, false);
                    if (!isValid)
                    {
                        throw new EthSynchronizationException($"{bestPeer} sent a block {currentHeader.ToString(BlockHeader.Format.Short)} with an invalid header");
                    }

                    if (HandleAddResult(currentHeader, i == 0, _blockTree.SuggestHeader(currentHeader)))
                    {
                        headersSynced++;
                    }

                    currentNumber = currentNumber + 1;
                }

                if (headersSynced > 0)
                {
                    _syncStats.Update(_blockTree.BestSuggestedHeader?.Number ?? 0, bestPeer.HeadNumber, 1);
                }
            }

            return(headersSynced);
        }