/// <summary> /// A puller method that will continuously loop and ask for the next block in the chain from peers. /// The block will then be passed to the consensus validation. /// </summary> /// <remarks> /// If the <see cref="Block"/> returned from the puller is <c>null</c> that means the puller is signaling a reorg was detected. /// In this case a rewind of the <see cref="CoinView"/> db will be triggered to roll back consensus until a block is found that is in the best chain. /// </remarks> private async Task PullerLoopAsync() { this.logger.LogTrace("()"); while (!this.nodeLifetime.ApplicationStopping.IsCancellationRequested) { BlockValidationContext blockValidationContext = new BlockValidationContext(); using (new StopwatchDisposable(o => this.Validator.PerformanceCounter.AddBlockFetchingTime(o))) { // Save the current consensus tip to later check if it changed. ChainedBlock consensusTip = this.Tip; this.logger.LogTrace("Asking block puller to deliver next block."); // This method will block until the next block is downloaded. LookaheadResult lookaheadResult = this.Puller.NextBlock(this.nodeLifetime.ApplicationStopping); if (lookaheadResult.Block == null) { using (await this.consensusLock.LockAsync(this.nodeLifetime.ApplicationStopping).ConfigureAwait(false)) { this.logger.LogTrace("No block received from puller due to reorganization."); if (!consensusTip.Equals(this.Tip)) { this.logger.LogTrace("Consensus tip changed from '{0}' to '{1}', no rewinding.", consensusTip, this.Tip); continue; } this.logger.LogTrace("Rewinding."); await this.RewindCoinViewLockedAsync().ConfigureAwait(false); continue; } } blockValidationContext.Block = lookaheadResult.Block; blockValidationContext.Peer = lookaheadResult.Peer; } this.logger.LogTrace("Block received from puller."); await this.AcceptBlockAsync(blockValidationContext).ConfigureAwait(false); } this.logger.LogTrace("(-)"); }
/// <summary> /// A puller method that will continuously loop and ask for the next block in the chain from peers. /// The block will then be passed to the consensus validation. /// </summary> /// <remarks> /// If the <see cref="Block"/> returned from the puller is null that means the puller is signalling a reorg was detected. /// In this case a rewind of the <see cref="CoinView"/> db will be triggered to roll back consensus until a block is found that is in the best chain. /// </remarks> /// <param name="cancellationToken">A cancellation token that will stop the loop.</param> private async Task PullerLoopAsync(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { BlockValidationContext blockValidationContext = new BlockValidationContext(); using (new StopwatchDisposable(o => this.Validator.PerformanceCounter.AddBlockFetchingTime(o))) { // Save the current consensus tip to later check if it changed. ChainedBlock consensusTip = this.Tip; // This method will block until the next block is downloaded. blockValidationContext.Block = this.Puller.NextBlock(cancellationToken); if (blockValidationContext.Block == null) { using (await this.consensusLock.LockAsync().ConfigureAwait(false)) { this.logger.LogTrace("No block received from puller due to reorganization."); if (!consensusTip.Equals(this.Tip)) { this.logger.LogTrace("Consensus tip changed from '{0}' to '{1}', no rewinding.", consensusTip, this.Tip); continue; } this.logger.LogTrace("Rewinding."); await this.RewindCoinViewLockedAsync().ConfigureAwait(false); continue; } } } this.logger.LogTrace("Block received from puller."); await this.AcceptBlockAsync(blockValidationContext).ConfigureAwait(false); } }