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); }
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)); }
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)); }
public AddBlockResult SuggestHeader(BlockHeader header) { return(_blockTree.SuggestHeader(header)); }
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); }