Ejemplo n.º 1
0
        internal Task Notify(CancellationToken token)
        {
            // Not syncing until the StartHash has been set.
            if (this.StartHash == null)
            {
                return(Task.CompletedTask);
            }

            // Not syncing until the chain is downloaded at least up to this block.
            ChainedHeader startBlock = this.Chain.GetBlock(this.StartHash);

            if (startBlock == null)
            {
                return(Task.CompletedTask);
            }

            // Sets the location of the puller to the block preceding the one we want to receive.
            ChainedHeader previousBlock = this.Chain.GetBlock(startBlock.Height > 0 ? startBlock.Height - 1 : 0);

            this.Puller.SetLocation(previousBlock);
            this.tip = previousBlock;

            this.logger.LogTrace("Puller location set to block: {0}.", previousBlock);

            // Send notifications for all the following blocks.
            while (!this.ReSync)
            {
                token.ThrowIfCancellationRequested();

                LookaheadResult lookaheadResult = this.Puller.NextBlock(token);
                if (lookaheadResult.Block != null)
                {
                    // Broadcast the block to the registered observers.
                    this.signals.SignalBlockConnected(lookaheadResult.Block);
                    this.tip = this.Chain.GetBlock(lookaheadResult.Block.GetHash());

                    continue;
                }

                // In reorg we reset the puller to the fork.
                // When a reorg happens the puller is pushed back and continues from the current fork.
                // Find the location of the fork.
                while (this.Chain.GetBlock(this.tip.HashBlock) == null)
                {
                    this.tip = this.tip.Previous;
                }

                // Set the puller to the fork location.
                this.Puller.SetLocation(this.tip);
            }

            this.ReSync = false;

            return(Task.CompletedTask);
        }
Ejemplo n.º 2
0
        /// <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("(-)");
        }