public void Should_allocate_by_speed_post_merge()
    {
        ulong[]           totalDifficulties = { 1, 3, 2 };
        int[]             averageSpeed      = { 5, 8, 10 };
        PublicKey[]       publicKeys        = { TestItem.PublicKeyA, TestItem.PublicKeyB, TestItem.PublicKeyC };
        PeerInfo[]        peers             = new PeerInfo[3];
        INodeStatsManager _nodeStatsManager = Substitute.For <INodeStatsManager>();

        for (int i = 0; i < 3; i++)
        {
            ISyncPeer syncPeer = Substitute.For <ISyncPeer>();
            syncPeer.IsInitialized.Returns(true);
            Node node = new Node(publicKeys[i], "192.168.1.18", i);
            syncPeer.Node.Returns(node);
            syncPeer.TotalDifficulty.Returns(new UInt256(totalDifficulties[i]));
            peers[i] = new PeerInfo(syncPeer);
            peers[i].HeadNumber.Returns(1);
            INodeStats nodeStats = Substitute.For <INodeStats>();
            nodeStats.GetAverageTransferSpeed(Arg.Any <TransferSpeedType>()).Returns(averageSpeed[i]);
            _nodeStatsManager.GetOrAdd(peers[i].SyncPeer.Node).Returns(nodeStats);
        }
        IPoSSwitcher poSSwitcher = Substitute.For <IPoSSwitcher>();

        poSSwitcher.TerminalTotalDifficulty.Returns(new UInt256(1));
        poSSwitcher.HasEverReachedTerminalBlock().Returns(true);

        IBeaconPivot beaconPivot = Substitute.For <IBeaconPivot>();

        IPeerAllocationStrategy mergePeerAllocationStrategy =
            (new MergeBlocksSyncPeerAllocationStrategyFactory(poSSwitcher, beaconPivot, Substitute.For <ILogManager>())).Create(new BlocksRequest());
        IBlockTree _blockTree = Substitute.For <IBlockTree>();
        PeerInfo?  info       = mergePeerAllocationStrategy.Allocate(null, peers, _nodeStatsManager, _blockTree);

        Assert.AreEqual(info, peers[2]);    // peer with highest highest speed
    }
Beispiel #2
0
    private async void BuildHeadersSyncBatches(
        Context ctx,
        BlockTree blockTree,
        BlockTree syncedBlockTree,
        IBeaconPivot pivot,
        long endLowestBeaconHeader)
    {
        ctx.Feed.InitializeFeed();
        long lowestHeaderNumber = pivot.PivotNumber;

        while (lowestHeaderNumber > endLowestBeaconHeader)
        {
            HeadersSyncBatch batch = await ctx.Feed.PrepareRequest();

            batch.Should().NotBeNull();
            BuildHeadersSyncBatchResponse(batch, syncedBlockTree);
            ctx.Feed.HandleResponse(batch);
            lowestHeaderNumber = lowestHeaderNumber - batch.RequestSize < endLowestBeaconHeader
                ? endLowestBeaconHeader
                : lowestHeaderNumber - batch.RequestSize;

            BlockHeader?lowestHeader = syncedBlockTree.FindHeader(lowestHeaderNumber, BlockTreeLookupOptions.None);
            blockTree.LowestInsertedBeaconHeader?.Hash.Should().BeEquivalentTo(lowestHeader?.Hash);
        }
    }
Beispiel #3
0
    public async Task Feed_able_to_sync_when_new_pivot_is_set()
    {
        BlockTree syncedBlockTree = Build.A.BlockTree().OfChainLength(1000).TestObject;
        Block     genesisBlock    = syncedBlockTree.FindBlock(syncedBlockTree.GenesisHash, BlockTreeLookupOptions.None) !;
        BlockTree blockTree       = Build.A.BlockTree().TestObject;

        blockTree.SuggestBlock(genesisBlock);
        ISyncConfig syncConfig = new SyncConfig
        {
            FastSync             = true,
            FastBlocks           = true,
            PivotNumber          = "500",
            PivotHash            = Keccak.Zero.ToString(),
            PivotTotalDifficulty = "1000000" // default difficulty in block tree builder
        };
        BlockHeader? pivotHeader = syncedBlockTree.FindHeader(700, BlockTreeLookupOptions.None);
        IBeaconPivot pivot       = PreparePivot(700, syncConfig, blockTree, pivotHeader);
        Context      ctx         = new (blockTree, syncConfig, pivot);

        BuildAndProcessHeaderSyncBatches(ctx, blockTree, syncedBlockTree, pivot, 0, 501);

        // move best pointers forward as proxy for chain merge
        Block highestBlock = syncedBlockTree.FindBlock(700, BlockTreeLookupOptions.None) !;

        blockTree.Insert(highestBlock, BlockTreeInsertBlockOptions.SaveHeader);

        pivot.EnsurePivot(syncedBlockTree.FindHeader(900, BlockTreeLookupOptions.None));
        BuildAndProcessHeaderSyncBatches(ctx, blockTree, syncedBlockTree, pivot, 700, 701);

        highestBlock = syncedBlockTree.FindBlock(900, BlockTreeLookupOptions.None) !;
        blockTree.Insert(highestBlock, BlockTreeInsertBlockOptions.SaveHeader);
        pivot.EnsurePivot(syncedBlockTree.FindHeader(999, BlockTreeLookupOptions.None));
        BuildAndProcessHeaderSyncBatches(ctx, blockTree, syncedBlockTree, pivot, 900, 901);
    }
 public MergeBlockDownloaderFactory(IPoSSwitcher poSSwitcher,
                                    IBeaconPivot beaconPivot,
                                    ISpecProvider specProvider,
                                    IBlockTree blockTree,
                                    IBlockCacheService blockCacheService,
                                    IReceiptStorage receiptStorage,
                                    IBlockValidator blockValidator,
                                    ISealValidator sealValidator,
                                    ISyncPeerPool peerPool,
                                    ISyncConfig syncConfig,
                                    IBetterPeerStrategy betterPeerStrategy,
                                    ISyncReport syncReport,
                                    ISyncProgressResolver syncProgressResolver,
                                    ILogManager logManager)
 {
     _poSSwitcher          = poSSwitcher ?? throw new ArgumentNullException(nameof(poSSwitcher));
     _beaconPivot          = beaconPivot ?? throw new ArgumentNullException(nameof(beaconPivot));
     _specProvider         = specProvider ?? throw new ArgumentNullException(nameof(specProvider));
     _blockTree            = blockTree ?? throw new ArgumentNullException(nameof(blockTree));
     _receiptStorage       = receiptStorage ?? throw new ArgumentNullException(nameof(receiptStorage));
     _blockValidator       = blockValidator ?? throw new ArgumentNullException(nameof(blockValidator));
     _sealValidator        = sealValidator ?? throw new ArgumentNullException(nameof(sealValidator));
     _syncPeerPool         = peerPool ?? throw new ArgumentNullException(nameof(peerPool));
     _betterPeerStrategy   = betterPeerStrategy ?? throw new ArgumentNullException(nameof(betterPeerStrategy));
     _logManager           = logManager ?? throw new ArgumentNullException(nameof(logManager));
     _syncReport           = syncReport ?? throw new ArgumentNullException(nameof(syncReport));
     _chainLevelHelper     = new ChainLevelHelper(_blockTree, _beaconPivot, syncConfig, _logManager);
     _syncProgressResolver = syncProgressResolver ?? throw new ArgumentNullException(nameof(syncProgressResolver));;
 }
Beispiel #5
0
    public async Task Can_keep_returning_nulls_after_all_batches_were_prepared()
    {
        IDbProvider memDbProvider = await TestMemDbProvider.InitAsync();

        BlockTree blockTree = new(memDbProvider, new ChainLevelInfoRepository(memDbProvider.BlockInfosDb),
                                  MainnetSpecProvider.Instance, NullBloomStorage.Instance, LimboLogs.Instance);
        ISyncConfig syncConfig = new SyncConfig
        {
            FastSync             = true,
            FastBlocks           = true,
            PivotNumber          = "1000",
            PivotHash            = Keccak.Zero.ToString(),
            PivotTotalDifficulty = "1000"
        };
        PoSSwitcher poSSwitcher = new(new MergeConfig(), syncConfig, memDbProvider.MetadataDb, blockTree !,
                                      MainnetSpecProvider.Instance, LimboLogs.Instance);
        IBeaconPivot          pivot = PreparePivot(2000, syncConfig, blockTree);
        BeaconHeadersSyncFeed feed  = new(poSSwitcher, Substitute.For <ISyncModeSelector>(), blockTree,
                                          Substitute.For <ISyncPeerPool>(), syncConfig, Substitute.For <ISyncReport>(),
                                          pivot, new MergeConfig()
        {
            Enabled = true
        }, new NoopInvalidChainTracker(), LimboLogs.Instance);

        feed.InitializeFeed();
        for (int i = 0; i < 6; i++)
        {
            await feed.PrepareRequest();
        }

        HeadersSyncBatch?result = await feed.PrepareRequest();

        result.Should().BeNull();
    }
Beispiel #6
0
 public ForkchoiceUpdatedV1Handler(
     IBlockTree blockTree,
     IManualBlockFinalizationManager manualBlockFinalizationManager,
     IPoSSwitcher poSSwitcher,
     IPayloadPreparationService payloadPreparationService,
     IBlockProcessingQueue processingQueue,
     IBlockCacheService blockCacheService,
     IInvalidChainTracker invalidChainTracker,
     IMergeSyncController mergeSyncController,
     IBeaconPivot beaconPivot,
     IPeerRefresher peerRefresher,
     ILogManager logManager)
 {
     _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree));
     _manualBlockFinalizationManager = manualBlockFinalizationManager ?? throw new ArgumentNullException(nameof(manualBlockFinalizationManager));
     _poSSwitcher = poSSwitcher ?? throw new ArgumentNullException(nameof(poSSwitcher));
     _payloadPreparationService = payloadPreparationService;
     _processingQueue           = processingQueue;
     _blockCacheService         = blockCacheService;
     _invalidChainTracker       = invalidChainTracker;
     _mergeSyncController       = mergeSyncController;
     _beaconPivot   = beaconPivot;
     _peerRefresher = peerRefresher;
     _logger        = logManager.GetClassLogger();
 }
 public MergeBlockDownloader(
     IPoSSwitcher posSwitcher,
     IBeaconPivot beaconPivot,
     ISyncFeed <BlocksRequest?>?feed,
     ISyncPeerPool?syncPeerPool,
     IBlockTree?blockTree,
     IBlockValidator?blockValidator,
     ISealValidator?sealValidator,
     ISyncReport?syncReport,
     IReceiptStorage?receiptStorage,
     ISpecProvider specProvider,
     IBetterPeerStrategy betterPeerStrategy,
     IChainLevelHelper chainLevelHelper,
     ISyncProgressResolver syncProgressResolver,
     ILogManager logManager)
     : base(feed, syncPeerPool, blockTree, blockValidator, sealValidator, syncReport, receiptStorage,
            specProvider, new MergeBlocksSyncPeerAllocationStrategyFactory(posSwitcher, beaconPivot, logManager),
            betterPeerStrategy, logManager)
 {
     _blockTree            = blockTree ?? throw new ArgumentNullException(nameof(blockTree));
     _specProvider         = specProvider ?? throw new ArgumentNullException(nameof(specProvider));
     _chainLevelHelper     = chainLevelHelper ?? throw new ArgumentNullException(nameof(chainLevelHelper));
     _poSSwitcher          = posSwitcher ?? throw new ArgumentNullException(nameof(posSwitcher));
     _blockValidator       = blockValidator ?? throw new ArgumentNullException(nameof(blockValidator));
     _syncReport           = syncReport ?? throw new ArgumentNullException(nameof(syncReport));
     _receiptStorage       = receiptStorage ?? throw new ArgumentNullException(nameof(receiptStorage));
     _beaconPivot          = beaconPivot;
     _receiptsRecovery     = new ReceiptsRecovery(new EthereumEcdsa(specProvider.ChainId, logManager), specProvider);
     _syncProgressResolver = syncProgressResolver ?? throw new ArgumentNullException(nameof(syncProgressResolver));
     _logger = logManager.GetClassLogger();
 }
Beispiel #8
0
    private async void BuildAndProcessHeaderSyncBatches(
        Context ctx,
        BlockTree blockTree,
        BlockTree syncedBlockTree,
        IBeaconPivot pivot,
        long bestPointer,
        long endLowestBeaconHeader)
    {
        ctx.BeaconSync.ShouldBeInBeaconHeaders().Should().BeTrue();
        blockTree.BestKnownNumber.Should().Be(bestPointer);
        BlockHeader?startBestHeader = syncedBlockTree.FindHeader(bestPointer, BlockTreeLookupOptions.None);

        blockTree.BestSuggestedHeader.Should().BeEquivalentTo(startBestHeader);
        blockTree.LowestInsertedBeaconHeader.Should().BeEquivalentTo(syncedBlockTree.FindHeader(pivot.PivotNumber, BlockTreeLookupOptions.None));

        BuildHeadersSyncBatches(ctx, blockTree, syncedBlockTree, pivot, endLowestBeaconHeader);

        HeadersSyncBatch result = await ctx.Feed.PrepareRequest();

        result.Should().BeNull();
        // check headers are inserted into block tree during sync
        blockTree.FindHeader(pivot.PivotNumber - 1, BlockTreeLookupOptions.TotalDifficultyNotNeeded).Should().NotBeNull();
        blockTree.LowestInsertedBeaconHeader?.Hash.Should().BeEquivalentTo(syncedBlockTree.FindHeader(endLowestBeaconHeader, BlockTreeLookupOptions.None)?.Hash);
        blockTree.BestKnownNumber.Should().Be(bestPointer);
        blockTree.BestSuggestedHeader.Should().BeEquivalentTo(startBestHeader);
        ctx.Feed.CurrentState.Should().Be(SyncFeedState.Dormant);
        ctx.BeaconSync.ShouldBeInBeaconHeaders().Should().BeFalse();
    }
Beispiel #9
0
    public async Task Feed_able_to_connect_to_existing_chain_through_block_hash()
    {
        BlockTree syncedBlockTree = Build.A.BlockTree().OfChainLength(600).TestObject;
        Block     genesisBlock    = syncedBlockTree.FindBlock(syncedBlockTree.GenesisHash, BlockTreeLookupOptions.None) !;
        BlockTree blockTree       = Build.A.BlockTree().TestObject;

        blockTree.SuggestBlock(genesisBlock);
        Block?firstBlock = syncedBlockTree.FindBlock(1, BlockTreeLookupOptions.None);

        blockTree.SuggestBlock(firstBlock);
        BlockHeader? pivotHeader = syncedBlockTree.FindHeader(500, BlockTreeLookupOptions.None);
        IBeaconPivot pivot       = PreparePivot(500, new SyncConfig(), blockTree, pivotHeader);
        Context      ctx         = new (blockTree, new SyncConfig(), pivot);
        // fork in chain
        Block parent = firstBlock;

        for (int i = 0; i < 5; i++)
        {
            Block block = Build.A.Block.WithParent(parent).WithNonce(1).TestObject;
            blockTree.SuggestBlock(block);
            parent = block;
        }

        ctx.BeaconSync.ShouldBeInBeaconHeaders().Should().BeTrue();
        blockTree.BestKnownNumber.Should().Be(6);
        BuildHeadersSyncBatches(ctx, blockTree, syncedBlockTree, pivot, 2);
        HeadersSyncBatch result = await ctx.Feed.PrepareRequest();

        result.Should().BeNull();
        blockTree.BestKnownNumber.Should().Be(6);
        ctx.Feed.CurrentState.Should().Be(SyncFeedState.Dormant);
        ctx.BeaconSync.ShouldBeInBeaconHeaders().Should().BeFalse();
    }
 public MergeBlocksSyncPeerAllocationStrategyFactory(
     IPoSSwitcher poSSwitcher,
     IBeaconPivot beaconPivot,
     ILogManager logManager)
 {
     _poSSwitcher = poSSwitcher;
     _beaconPivot = beaconPivot;
     _logManager  = logManager;
 }
 public MergeBetterPeerStrategy(
     IBetterPeerStrategy preMergeBetterPeerStrategy,
     IPoSSwitcher poSSwitcher,
     IBeaconPivot beaconPivot,
     ILogManager logManager)
 {
     _preMergeBetterPeerStrategy = preMergeBetterPeerStrategy;
     _poSSwitcher = poSSwitcher;
     _beaconPivot = beaconPivot;
     _logger      = logManager.GetClassLogger();
 }
 public ChainLevelHelper(
     IBlockTree blockTree,
     IBeaconPivot beaconPivot,
     ISyncConfig syncConfig,
     ILogManager logManager)
 {
     _blockTree   = blockTree;
     _beaconPivot = beaconPivot;
     _syncConfig  = syncConfig;
     _logger      = logManager.GetClassLogger();
 }
Beispiel #13
0
        public Context(
            IBlockTree?blockTree     = null,
            ISyncConfig?syncConfig   = null,
            IBeaconPivot?beaconPivot = null,
            IDb?metadataDb           = null,
            IMergeConfig?mergeConfig = null)
        {
            if (blockTree == null)
            {
                IDb   blockInfoDb = new MemDb();
                Block genesis     = Build.A.Block.Genesis.TestObject;
                BlockTree = new BlockTree(new MemDb(), new MemDb(), blockInfoDb, new ChainLevelInfoRepository(blockInfoDb), MainnetSpecProvider.Instance, NullBloomStorage.Instance, LimboLogs.Instance);
                BlockTree.SuggestBlock(genesis);
            }
            else
            {
                BlockTree = blockTree;
            }

            ISyncPeerPool    peerPool         = Substitute.For <ISyncPeerPool>();
            ISyncReport      report           = Substitute.For <ISyncReport>();
            MeasuredProgress measuredProgress = new MeasuredProgress();

            report.BeaconHeaders.Returns(measuredProgress);
            report.HeadersInQueue.Returns(measuredProgress);

            MemDb stateDb = new();

            _syncConfig  = syncConfig ?? new SyncConfig();
            _mergeConfig = mergeConfig ?? new MergeConfig();
            _metadataDb  = metadataDb ?? new MemDb();
            PoSSwitcher poSSwitcher = new(_mergeConfig, _syncConfig, _metadataDb, blockTree !,
                                          MainnetSpecProvider.Instance, LimboLogs.Instance);

            ProgressTracker progressTracker = new(BlockTree, stateDb, LimboLogs.Instance);

            SyncProgressResolver syncProgressResolver = new(
                BlockTree,
                NullReceiptStorage.Instance,
                stateDb,
                new TrieStore(stateDb, LimboLogs.Instance),
                progressTracker,
                _syncConfig,
                LimboLogs.Instance);
            TotalDifficultyBetterPeerStrategy bestPeerStrategy = new (LimboLogs.Instance);

            BeaconPivot = beaconPivot ?? new BeaconPivot(_syncConfig, _metadataDb, BlockTree, LimboLogs.Instance);
            BeaconSync  = new(BeaconPivot, BlockTree, _syncConfig, new BlockCacheService(), LimboLogs.Instance);
            ISyncModeSelector selector = new MultiSyncModeSelector(syncProgressResolver, peerPool, _syncConfig, BeaconSync, bestPeerStrategy, LimboLogs.Instance);

            Feed = new BeaconHeadersSyncFeed(poSSwitcher, selector, blockTree, peerPool, _syncConfig, report, BeaconPivot, _mergeConfig,
                                             new NoopInvalidChainTracker(), LimboLogs.Instance);
        }
Beispiel #14
0
 public BeaconSync(
     IBeaconPivot beaconPivot,
     IBlockTree blockTree,
     ISyncConfig syncConfig,
     IBlockCacheService blockCacheService,
     ILogManager logManager)
 {
     _beaconPivot       = beaconPivot;
     _blockTree         = blockTree;
     _syncConfig        = syncConfig;
     _blockCacheService = blockCacheService;
     _logger            = logManager.GetClassLogger();
 }
Beispiel #15
0
            public ScenarioBuilder WithBlockTrees(int notSyncedTreeSize, int syncedTreeSize = -1, bool moveBlocksToMainChain = true, UInt256?ttd = null)
            {
                TestSpecProvider testSpecProvider = new TestSpecProvider(London.Instance);

                if (ttd != null)
                {
                    testSpecProvider.TerminalTotalDifficulty = ttd;
                }
                NotSyncedTreeBuilder = Build.A.BlockTree().OfChainLength(notSyncedTreeSize);
                NotSyncedTree        = new(
                    NotSyncedTreeBuilder.BlocksDb,
                    NotSyncedTreeBuilder.HeadersDb,
                    NotSyncedTreeBuilder.BlockInfoDb,
                    NotSyncedTreeBuilder.MetadataDb,
                    NotSyncedTreeBuilder.ChainLevelInfoRepository,
                    testSpecProvider,
                    NullBloomStorage.Instance,
                    new SyncConfig(),
                    LimboLogs.Instance);

                if (syncedTreeSize > 0)
                {
                    _syncedTreeBuilder = Build.A.BlockTree().OfChainLength(syncedTreeSize);
                    SyncedTree         = new(
                        _syncedTreeBuilder.BlocksDb,
                        _syncedTreeBuilder.HeadersDb,
                        _syncedTreeBuilder.BlockInfoDb,
                        _syncedTreeBuilder.MetadataDb,
                        _syncedTreeBuilder.ChainLevelInfoRepository,
                        testSpecProvider,
                        NullBloomStorage.Instance,
                        new SyncConfig(),
                        LimboLogs.Instance);
                }

                _beaconPivot = new BeaconPivot(new SyncConfig(), new MemDb(), SyncedTree, LimboLogs.Instance);

                _chainLevelHelper = new ChainLevelHelper(NotSyncedTree, _beaconPivot, new SyncConfig(), LimboLogs.Instance);
                if (moveBlocksToMainChain)
                {
                    NotSyncedTree.NewBestSuggestedBlock += OnNewBestSuggestedBlock;
                }
                return(this);
            }
    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);
    }
Beispiel #17
0
    public async Task Finishes_when_all_downloaded()
    {
        IBlockTree blockTree = Substitute.For <IBlockTree>();

        blockTree.LowestInsertedBeaconHeader.Returns(Build.A.BlockHeader.WithNumber(2000).TestObject);
        ISyncReport report = Substitute.For <ISyncReport>();

        report.HeadersInQueue.Returns(new MeasuredProgress());
        MeasuredProgress measuredProgress = new ();

        report.BeaconHeaders.Returns(measuredProgress);
        ISyncConfig syncConfig = new SyncConfig
        {
            FastSync             = true,
            FastBlocks           = true,
            PivotNumber          = "1000",
            PivotHash            = Keccak.Zero.ToString(),
            PivotTotalDifficulty = "1000"
        };
        PoSSwitcher poSSwitcher = new(new MergeConfig(), syncConfig, new MemDb(), blockTree !,
                                      MainnetSpecProvider.Instance, LimboLogs.Instance);
        IBeaconPivot          pivot = PreparePivot(2000, syncConfig, blockTree);
        BeaconHeadersSyncFeed feed  = new (poSSwitcher, Substitute.For <ISyncModeSelector>(), blockTree,
                                           Substitute.For <ISyncPeerPool>(), syncConfig, report, pivot, new MergeConfig()
        {
            Enabled = true
        },
                                           new NoopInvalidChainTracker(), LimboLogs.Instance);

        feed.InitializeFeed();
        for (int i = 0; i < 6; i++)
        {
            await feed.PrepareRequest();
        }
        blockTree.LowestInsertedBeaconHeader.Returns(Build.A.BlockHeader.WithNumber(1001).TestObject);
        HeadersSyncBatch?result = await feed.PrepareRequest();

        result.Should().BeNull();
        feed.CurrentState.Should().Be(SyncFeedState.Dormant);
        measuredProgress.CurrentValue.Should().Be(999);
    }
Beispiel #18
0
    private IBetterPeerStrategy CreateMergePeerChoiceStrategy(IPoSSwitcher poSSwitcher, IBeaconPivot beaconPivot)
    {
        TotalDifficultyBetterPeerStrategy preMergePeerStrategy = new(LimboLogs.Instance);

        return(new MergeBetterPeerStrategy(preMergePeerStrategy, poSSwitcher, beaconPivot, LimboLogs.Instance));
    }
 public PostMergeBlocksSyncPeerAllocationStrategy(long?minBlocksAhead, IBeaconPivot beaconPivot)
 {
     _minBlocksAhead = minBlocksAhead;
     _beaconPivot    = beaconPivot;
 }