Beispiel #1
0
        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)}.");
                        }
                    }