public bool ShouldBeInBeaconHeaders() { bool beaconPivotExists = _beaconPivot.BeaconPivotExists(); bool notInBeaconModeControl = !_isInBeaconModeControl; bool notFinishedBeaconHeaderSync = !IsBeaconSyncHeadersFinished(); if (_logger.IsTrace) { _logger.Trace($"ShouldBeInBeaconHeaders: NotInBeaconModeControl: {notInBeaconModeControl}, BeaconPivotExists: {beaconPivotExists}, NotFinishedBeaconHeaderSync: {notFinishedBeaconHeaderSync} LowestInsertedBeaconHeaderNumber: {_blockTree.LowestInsertedBeaconHeader?.Number}, BeaconPivot: {_beaconPivot.PivotNumber}, BeaconPivotDestinationNumber: {_beaconPivot.PivotDestinationNumber}"); } return(beaconPivotExists && notInBeaconModeControl && notFinishedBeaconHeaderSync); }
public PeerInfo?Allocate(PeerInfo?currentPeer, IEnumerable <PeerInfo> peers, INodeStatsManager nodeStatsManager, IBlockTree blockTree) { int nullSpeed = -1; int peersCount = 0; bool wasNull = currentPeer == null; long currentSpeed = wasNull ? nullSpeed : GetSpeed(nodeStatsManager, currentPeer !) ?? nullSpeed; (PeerInfo? Info, long TransferSpeed)fastestPeer = (currentPeer, currentSpeed); foreach (PeerInfo info in peers) { (this as IPeerAllocationStrategy).CheckAsyncState(info); peersCount++; if (_beaconPivot.BeaconPivotExists()) { if (info.HeadNumber < _beaconPivot.PivotNumber - 1) { // we need to guarantee the peer can have all the block prior to beacon pivot continue; } } else if (info.HeadNumber < (blockTree.BestSuggestedBody?.Number ?? 0) + (_minBlocksAhead ?? 1)) { continue; } long averageTransferSpeed = GetSpeed(nodeStatsManager, info) ?? 0; if (averageTransferSpeed > fastestPeer.TransferSpeed) { fastestPeer = (info, averageTransferSpeed); } } if (peersCount == 0) { return(currentPeer); } decimal speedRatio = fastestPeer.TransferSpeed / (decimal)Math.Max(1L, currentSpeed); if (speedRatio > 1m + MinDiffPercentageForSpeedSwitch && fastestPeer.TransferSpeed - currentSpeed > MinDiffForSpeedSwitch) { return(fastestPeer.Info); } return(currentPeer ?? fastestPeer.Info); }
private MergeBetterPeerStrategy CreateStrategy(long?beaconPivotNum = null) { const long ttd = 5; IPoSSwitcher poSSwitcher = Substitute.For <IPoSSwitcher>(); poSSwitcher.TerminalTotalDifficulty.Returns((UInt256)ttd); IBeaconPivot beaconPivot = Substitute.For <IBeaconPivot>(); if (beaconPivotNum != null) { beaconPivot.BeaconPivotExists().Returns(true); beaconPivot.PivotNumber.Returns((long)beaconPivotNum); } TotalDifficultyBetterPeerStrategy preMergeBetterPeerStrategy = new(LimboLogs.Instance); MergeBetterPeerStrategy betterPeerStrategy = new(preMergeBetterPeerStrategy, poSSwitcher, beaconPivot, LimboLogs.Instance); return(betterPeerStrategy); }
public override async Task <long> DownloadBlocks(PeerInfo?bestPeer, BlocksRequest blocksRequest, CancellationToken cancellation) { if (_beaconPivot.BeaconPivotExists() == false && _poSSwitcher.HasEverReachedTerminalBlock() == false) { return(await base.DownloadBlocks(bestPeer, blocksRequest, cancellation)); } if (bestPeer == null) { string message = $"Not expecting best peer to be null inside the {nameof(BlockDownloader)}"; if (_logger.IsError) { _logger.Error(message); } throw new ArgumentNullException(message); } DownloaderOptions options = blocksRequest.Options; bool downloadReceipts = (options & DownloaderOptions.WithReceipts) == DownloaderOptions.WithReceipts; bool shouldProcess = (options & DownloaderOptions.Process) == DownloaderOptions.Process; bool shouldMoveToMain = (options & DownloaderOptions.MoveToMain) == DownloaderOptions.MoveToMain; int blocksSynced = 0; long currentNumber = _blockTree.BestKnownNumber; if (_logger.IsTrace) { _logger.Trace( $"MergeBlockDownloader GetCurrentNumber: currentNumber {currentNumber}, beaconPivotExists: {_beaconPivot.BeaconPivotExists()}, BestSuggestedBody: {_blockTree.BestSuggestedBody?.Number}, BestKnownNumber: {_blockTree.BestKnownNumber}, BestPeer: {bestPeer}, BestKnownBeaconNumber {_blockTree.BestKnownBeaconNumber}"); } bool HasMoreToSync(out BlockHeader[]?headers, out int headersToRequest) { if (_logger.IsDebug) { _logger.Debug($"Continue full sync with {bestPeer} (our best {_blockTree.BestKnownNumber})"); } headersToRequest = Math.Min(_syncBatchSize.Current, bestPeer.MaxHeadersPerRequest()); if (_logger.IsTrace) { _logger.Trace( $"Full sync request {currentNumber}+{headersToRequest} to peer {bestPeer} with {bestPeer.HeadNumber} blocks. Got {currentNumber} and asking for {headersToRequest} more."); } // Note: blocksRequest.NumberOfLatestBlocksToBeIgnored not accounted for headers = _chainLevelHelper.GetNextHeaders(headersToRequest, bestPeer.HeadNumber); if (headers == null || headers.Length <= 1) { if (_logger.IsTrace) { _logger.Trace("Chain level helper got no headers suggestion"); } return(false); } return(true); } while (HasMoreToSync(out BlockHeader[]? headers, out int headersToRequest)) { if (cancellation.IsCancellationRequested) { return(blocksSynced); // check before every heavy operation } Block[]? blocks = null; TxReceipt[]?[]? receipts = null; if (_logger.IsTrace) { _logger.Trace( $"Downloading blocks from peer. CurrentNumber: {currentNumber}, BeaconPivot: {_beaconPivot.PivotNumber}, BestPeer: {bestPeer}, HeaderToRequest: {headersToRequest}"); } BlockDownloadContext context = new(_specProvider, bestPeer, headers !, downloadReceipts, _receiptsRecovery); if (cancellation.IsCancellationRequested) { return(blocksSynced); // check before every heavy operation } await RequestBodies(bestPeer, cancellation, context); if (downloadReceipts) { if (cancellation.IsCancellationRequested) { return(blocksSynced); // check before every heavy operation } await RequestReceipts(bestPeer, cancellation, context); } _sinceLastTimeout++; if (_sinceLastTimeout > 2) { _syncBatchSize.Expand(); } blocks = context.Blocks; receipts = context.ReceiptsForBlocks; if (!(blocks?.Length > 0)) { if (_logger.IsTrace) { _logger.Trace("Break early due to no blocks."); } break; } for (int blockIndex = 0; blockIndex < blocks.Length; blockIndex++) { if (cancellation.IsCancellationRequested) { if (_logger.IsTrace) { _logger.Trace("Peer sync cancelled"); } break; } Block currentBlock = blocks[blockIndex]; if (_logger.IsTrace) { _logger.Trace($"Received {currentBlock} from {bestPeer}"); } if (currentBlock.IsBodyMissing) { throw new EthSyncException($"{bestPeer} didn't send body for block {currentBlock.ToString(Block.Format.Short)}."); } // can move this to block tree now? if (!_blockValidator.ValidateSuggestedBlock(currentBlock)) { throw new EthSyncException($"{bestPeer} sent an invalid block {currentBlock.ToString(Block.Format.Short)}."); } if (shouldProcess) { // covering edge case during fastSyncTransition when we're trying to SuggestBlock without the state bool headIsGenesis = _blockTree.Head?.IsGenesis ?? false; bool toBeProcessedIsNotBlockOne = currentBlock.Number > 1; bool isFastSyncTransition = headIsGenesis && toBeProcessedIsNotBlockOne; if (isFastSyncTransition) { long bestFullState = _syncProgressResolver.FindBestFullState(); shouldProcess = currentBlock.Number > bestFullState && bestFullState != 0; if (!shouldProcess) { if (_logger.IsInfo) { _logger.Info($"Skipping processing during fastSyncTransition, currentBlock: {currentBlock}, bestFullState: {bestFullState}"); } downloadReceipts = true; } } } if (downloadReceipts) { TxReceipt[]? contextReceiptsForBlock = receipts ![blockIndex]; if (currentBlock.Header.HasBody && contextReceiptsForBlock == null) { throw new EthSyncException($"{bestPeer} didn't send receipts for block {currentBlock.ToString(Block.Format.Short)}."); } }