public async Task Does_not_do_full_sync_when_not_needed_with_split() { BlockTree minerTree = Build.A.BlockTree(_genesisBlock).OfChainLength(6).TestObject; ISyncPeer miner1 = new SyncPeerMock(minerTree); AutoResetEvent resetEvent = new AutoResetEvent(false); _synchronizer.SyncEvent += (sender, args) => { if (args.SyncEvent == SyncEvent.Completed || args.SyncEvent == SyncEvent.Failed) { resetEvent.Set(); } }; _pool.Start(); _synchronizer.Start(); _pool.AddPeer(miner1); resetEvent.WaitOne(_standardTimeoutUnit); Assert.AreEqual(minerTree.BestSuggestedHeader.Hash, _blockTree.BestSuggestedHeader.Hash, "client agrees with miner before split"); Block newBlock = Build.A.Block.WithParent(minerTree.Head).TestObject; minerTree.SuggestBlock(newBlock); minerTree.UpdateMainChain(newBlock); ISyncPeer miner2 = Substitute.For <ISyncPeer>(); miner2.GetHeadBlockHeader(Arg.Any <Keccak>(), Arg.Any <CancellationToken>()).Returns(miner1.GetHeadBlockHeader(null, CancellationToken.None)); miner2.Node.Id.Returns(TestItem.PublicKeyB); Assert.AreEqual(newBlock.Number, await miner2.GetHeadBlockHeader(null, Arg.Any <CancellationToken>()), "number as expected"); _pool.Start(); _synchronizer.Start(); _pool.AddPeer(miner2); resetEvent.WaitOne(_standardTimeoutUnit); await miner2.Received().GetBlockHeaders(6, 1, 0, default(CancellationToken)); }
private async Task ExecuteRefreshTask(RefreshTotalDiffTask refreshTotalDiffTask, CancellationToken token) { ISyncPeer syncPeer = refreshTotalDiffTask.SyncPeer; if (_logger.IsTrace) { _logger.Trace($"Requesting head block info from {syncPeer.Node:s}"); } var getHeadHeaderTask = syncPeer.GetHeadBlockHeader(refreshTotalDiffTask.BlockHash ?? syncPeer.HeadHash, token); CancellationTokenSource delaySource = new CancellationTokenSource(); CancellationTokenSource linkedSource = CancellationTokenSource.CreateLinkedTokenSource(delaySource.Token, token); Task delayTask = Task.Delay(InitTimeout, linkedSource.Token); Task firstToComplete = await Task.WhenAny(getHeadHeaderTask, delayTask); await firstToComplete.ContinueWith( t => { try { if (firstToComplete == delayTask) { if (_logger.IsDebug) { _logger.Debug($"InitPeerInfo timed out for node: {syncPeer.Node:c}"); } _stats.ReportSyncEvent(syncPeer.Node, syncPeer.IsInitialized ? NodeStatsEventType.SyncFailed : NodeStatsEventType.SyncInitFailed); syncPeer.Disconnect(DisconnectReason.DisconnectRequested, "refresh peer info fault - timeout"); } else if (firstToComplete.IsFaulted) { if (_logger.IsDebug) { _logger.Debug($"InitPeerInfo failed for node: {syncPeer.Node:c}{Environment.NewLine}{t.Exception}"); } _stats.ReportSyncEvent(syncPeer.Node, syncPeer.IsInitialized ? NodeStatsEventType.SyncFailed : NodeStatsEventType.SyncInitFailed); syncPeer.Disconnect(DisconnectReason.DisconnectRequested, "refresh peer info fault - timeout"); } else if (firstToComplete.IsCanceled) { if (_logger.IsTrace) { _logger.Trace($"InitPeerInfo canceled for node: {syncPeer.Node:c}{Environment.NewLine}{t.Exception}"); } _stats.ReportSyncEvent(syncPeer.Node, syncPeer.IsInitialized ? NodeStatsEventType.SyncCancelled : NodeStatsEventType.SyncInitCancelled); token.ThrowIfCancellationRequested(); } else { delaySource.Cancel(); BlockHeader header = getHeadHeaderTask.Result; if (header == null) { if (_logger.IsDebug) { _logger.Debug($"InitPeerInfo failed for node: {syncPeer.Node:c}{Environment.NewLine}{t.Exception}"); } _stats.ReportSyncEvent(syncPeer.Node, syncPeer.IsInitialized ? NodeStatsEventType.SyncFailed : NodeStatsEventType.SyncInitFailed); syncPeer.Disconnect(DisconnectReason.DisconnectRequested, "refresh peer info fault - null response"); return; } if (_logger.IsTrace) { _logger.Trace($"Received head block info from {syncPeer.Node:c} with head block numer {header.Number}"); } if (!syncPeer.IsInitialized) { _stats.ReportSyncEvent(syncPeer.Node, NodeStatsEventType.SyncInitCompleted); } if (_logger.IsTrace) { _logger.Trace($"REFRESH Updating header of {syncPeer} from {syncPeer.HeadNumber} to {header.Number}"); } BlockHeader parent = _blockTree.FindParentHeader(header, BlockTreeLookupOptions.None); if (parent != null) { UInt256 newTotalDifficulty = (parent.TotalDifficulty ?? UInt256.Zero) + header.Difficulty; if (newTotalDifficulty >= syncPeer.TotalDifficulty) { syncPeer.TotalDifficulty = newTotalDifficulty; syncPeer.HeadNumber = header.Number; syncPeer.HeadHash = header.Hash; } } else if (header.Number > syncPeer.HeadNumber) { syncPeer.HeadNumber = header.Number; syncPeer.HeadHash = header.Hash; } syncPeer.IsInitialized = true; SignalPeersChanged(); } } finally { linkedSource.Dispose(); delaySource.Dispose(); } }, token); }