private async Task SyncPreviousBlocksAsync( BlockChain <T> blockChain, BoundPeer peer, BlockHash?stop, IProgress <BlockDownloadState> progress, TimeSpan timeout, long totalBlockCount, int logSessionId, CancellationToken cancellationToken ) { long previousTipIndex = blockChain.Tip?.Index ?? -1; BlockChain <T> synced = null; try { long currentTipIndex = blockChain.Tip?.Index ?? -1; long receivedBlockCount = currentTipIndex - previousTipIndex; const string startMsg = "{SessionId}: Starts " + nameof(FillBlocksAsync) + "()..."; _logger.Debug(startMsg, logSessionId); FillBlocksAsyncStarted.Set(); synced = await FillBlocksAsync( peer, blockChain, stop, progress, totalBlockCount, receivedBlockCount, true, timeout, logSessionId, cancellationToken ); const string finishMsg = "{SessionId}: Finished " + nameof(FillBlocksAsync) + "()."; _logger.Debug(finishMsg, logSessionId); } catch (Exception) { FillBlocksAsyncFailed.Set(); throw; } finally { var canonComparer = BlockChain.Policy.CanonicalChainComparer; if (synced is { } syncedB && !syncedB.Id.Equals(blockChain?.Id) && (!(blockChain.Tip is { } tip&& syncedB.Tip is { } syncedTip) || canonComparer.Compare( blockChain.PerceiveBlock(tip), blockChain.PerceiveBlock( syncedTip, syncedB.PerceiveBlock(syncedTip).PerceivedTime ) ) < 0 ) ) { _logger.Debug( "{SessionId}: Swap the chain {ChainIdA} for the chain {ChainIdB}...", logSessionId, blockChain.Id, synced.Id ); blockChain.Swap( synced, render: true, stateCompleters: null ); _logger.Debug( "{SessionId}: The chain {ChainIdB} replaced {ChainIdA}", logSessionId, synced.Id, blockChain.Id ); } } }
private bool BlockCandidateProcess( SortedList <long, Block <T> > candidate, TimeSpan timeout, CancellationToken cancellationToken) { BlockChain <T> synced = null; System.Action renderSwap = () => { }; const string methodName = nameof(Swarm <T>) + "<T>." + nameof(BlockCandidateProcess) + "()"; try { FillBlocksAsyncStarted.Set(); _logger.Debug( methodName + " starts to append. Current tip: #{BlockIndex}.", BlockChain.Tip.Index ); synced = AppendPreviousBlocks( blockChain: BlockChain, candidate: candidate, timeout: timeout, evaluateActions: true); ProcessFillBlocksFinished.Set(); _logger.Debug( methodName + " finished appending blocks. Synced tip: #{BlockIndex}.", synced.Tip.Index ); } catch (Exception e) { _logger.Error(e, methodName + " failed to append blocks."); FillBlocksAsyncFailed.Set(); return(false); } var canonComparer = BlockChain.Policy.CanonicalChainComparer; if (synced is { } syncedB && !syncedB.Id.Equals(BlockChain?.Id) && (canonComparer.Compare( BlockChain.PerceiveBlock(BlockChain.Tip), BlockChain.PerceiveBlock(syncedB.Tip)) < 0 ) ) { _logger.Debug( "Swapping chain {ChainIdA} with chain {ChainIdB}...", BlockChain.Id, synced.Id ); renderSwap = BlockChain.Swap( synced, render: true, stateCompleters: null); _logger.Debug( "Swapped chain {ChainIdA} with chain {ChainIdB}.", BlockChain.Id, synced.Id ); } renderSwap(); BroadcastBlock(BlockChain.Tip); return(true); }