public void Switch_correctly_from_full_sync_to_state_nodes_catch_up() { ISyncProgressResolver syncProgressResolver = Substitute.For <ISyncProgressResolver>(); syncProgressResolver.FindBestHeader().Returns(Scenario.ChainHead.Number); syncProgressResolver.FindBestFullBlock().Returns(Scenario.ChainHead.Number); syncProgressResolver.FindBestFullState().Returns(Scenario.ChainHead.Number - MultiSyncModeSelector.FastSyncLag); syncProgressResolver.FindBestProcessedBlock().Returns(0); syncProgressResolver.IsFastBlocksFinished().Returns(FastBlocksState.FinishedReceipts); syncProgressResolver.ChainDifficulty.Returns(UInt256.Zero); List <ISyncPeer> syncPeers = new(); BlockHeader header = Scenario.ChainHead; ISyncPeer syncPeer = Substitute.For <ISyncPeer>(); syncPeer.HeadHash.Returns(header.Hash); syncPeer.HeadNumber.Returns(header.Number); syncPeer.TotalDifficulty.Returns(header.TotalDifficulty ?? 0); syncPeer.IsInitialized.Returns(true); syncPeer.ClientId.Returns("nethermind"); syncPeers.Add(syncPeer); ISyncPeerPool syncPeerPool = Substitute.For <ISyncPeerPool>(); IEnumerable <PeerInfo> peerInfos = syncPeers.Select(p => new PeerInfo(p)); syncPeerPool.InitializedPeers.Returns(peerInfos); syncPeerPool.AllPeers.Returns(peerInfos); ISyncConfig syncConfig = new SyncConfig() { FastSyncCatchUpHeightDelta = 2 }; syncConfig.FastSync = true; TotalDifficultyBetterPeerStrategy bestPeerStrategy = new(LimboLogs.Instance); MultiSyncModeSelector selector = new(syncProgressResolver, syncPeerPool, syncConfig, No.BeaconSync, bestPeerStrategy, LimboLogs.Instance); selector.Stop(); syncProgressResolver.FindBestProcessedBlock().Returns(Scenario.ChainHead.Number); selector.Update(); selector.Current.Should().Be(SyncMode.Full); for (uint i = 0; i < syncConfig.FastSyncCatchUpHeightDelta + 1; i++) { long number = header.Number + i; syncPeer.HeadNumber.Returns(number); syncPeer.TotalDifficulty.Returns(header.TotalDifficulty.Value + i); syncProgressResolver.FindBestHeader().Returns(number); syncProgressResolver.FindBestFullBlock().Returns(number); selector.Update(); } selector.Current.Should().Be(SyncMode.StateNodes); }
public void Update() { if (_syncPeerPool.PeerCount == 0) { return; } if (!_syncConfig.FastSync) { if (Current == SyncMode.NotStarted) { Current = SyncMode.Full; Changed?.Invoke(this, EventArgs.Empty); } } else { long bestHeader = _syncProgressResolver.FindBestHeader(); long bestFullBlock = _syncProgressResolver.FindBestFullBlock(); long bestFullState = _syncProgressResolver.FindBestFullState(); long maxBlockNumberAmongPeers = 0; if (bestFullBlock < 0 || bestHeader < 0 || bestFullState < 0 || bestFullBlock > bestHeader) { string errorMessage = $"Invalid best state calculation: {BuildStateString(bestHeader, bestFullBlock, bestFullBlock, maxBlockNumberAmongPeers)}"; if (_logger.IsError) { _logger.Error(errorMessage); } throw new InvalidOperationException(errorMessage); } foreach (PeerInfo peerInfo in _syncPeerPool.UsefulPeers) { maxBlockNumberAmongPeers = Math.Max(maxBlockNumberAmongPeers, peerInfo.HeadNumber); } SyncMode newSyncMode; if (!_syncProgressResolver.IsFastBlocksFinished()) { newSyncMode = SyncMode.FastBlocks; } else if (maxBlockNumberAmongPeers - Math.Max(bestFullState, bestFullBlock) <= FullSyncThreshold) { newSyncMode = Math.Max(bestFullState, bestFullBlock) >= bestHeader ? SyncMode.Full : SyncMode.StateNodes; } else if (maxBlockNumberAmongPeers - bestHeader <= FullSyncThreshold) { // TODO: we need to check here if there are any blocks in processing queue... any other checks are wrong newSyncMode = bestFullBlock > bestFullState ? SyncMode.WaitForProcessor : SyncMode.StateNodes; } else { newSyncMode = bestFullBlock > bestFullState ? SyncMode.WaitForProcessor : SyncMode.Headers; } if (newSyncMode != Current) { if (_logger.IsInfo) { _logger.Info($"Switching sync mode from {Current} to {newSyncMode} {BuildStateString(bestHeader, bestFullBlock, bestFullState, maxBlockNumberAmongPeers)}"); } Current = newSyncMode; Changed?.Invoke(this, EventArgs.Empty); } else { if (_logger.IsInfo) { _logger.Info($"Staying on sync mode {Current} {BuildStateString(bestHeader, bestFullBlock, bestFullState, maxBlockNumberAmongPeers)}"); } } } }
public void Update() { if (!_fastSyncEnabled) { return; } if (_syncPeerPool.PeerCount == 0) { return; } long bestFullBlock = _syncProgressResolver.FindBestFullBlock(); long bestHeader = _syncProgressResolver.FindBestHeader(); long bestFullState = _syncProgressResolver.FindBestFullState(); if (bestFullBlock < 0 || bestHeader < 0 || bestFullState < 0 || bestFullBlock > bestHeader) { string errorMessage = $"Invalid best state calculation: F:{bestFullBlock}|H:{bestHeader}|S:{bestFullState}"; if (_logger.IsError) { _logger.Error(errorMessage); } throw new InvalidOperationException(errorMessage); } long maxBlockNumberAmongPeers = 0; foreach (PeerInfo peerInfo in _syncPeerPool.UsefulPeers) { maxBlockNumberAmongPeers = Math.Max(maxBlockNumberAmongPeers, peerInfo.HeadNumber); } SyncMode newSyncMode; if (maxBlockNumberAmongPeers - Math.Max(bestFullState, bestFullBlock) <= FullSyncThreshold) { newSyncMode = Math.Max(bestFullState, bestFullBlock) >= bestHeader ? SyncMode.Full : SyncMode.StateNodes; } else if (maxBlockNumberAmongPeers - bestHeader <= FullSyncThreshold) { // TODO: we need to check here if there are any blocks in processing queue... any other checks are wrong newSyncMode = bestFullBlock > bestFullState ? SyncMode.WaitForProcessor : SyncMode.StateNodes; } else { newSyncMode = bestFullBlock > bestFullState ? SyncMode.WaitForProcessor : SyncMode.Headers; } if (newSyncMode != Current) { if (_logger.IsInfo) { _logger.Info($"Switching sync mode from {Current} to {newSyncMode} H:{bestHeader}|F:{bestFullBlock}|S:{bestFullState}|R:{maxBlockNumberAmongPeers}."); } Current = newSyncMode; Changed?.Invoke(this, EventArgs.Empty); } else { if (_logger.IsInfo) { _logger.Info($"Staying on sync mode {Current} |best header:{bestHeader}|best full block:{bestFullBlock}|best state:{bestFullState}|best peer block:{maxBlockNumberAmongPeers}"); } } }