Пример #1
0
        public void DownloadBlocks_EnsureNextChainedBlockIsAskedForOnStartUp()
        {
            var blocks = CreateBlocks(3);

            using (var blockRepository = new BlockRepository(Network.Main, TestBase.AssureEmptyDirAsDataFolder(@"BlockStore\DownloadBlocks_EnsureNextChainedBlockIsAskedForOnStartUp")))
            {
                // The chain has 3 blocks appended
                var chain = new ConcurrentChain(blocks[0].Header);
                AppendBlocks(chain, blocks.Skip(1).Take(2));

                var blockStoreLoop   = CreateBlockStoreLoop(chain, blockRepository, @"BlockStore\DownloadBlocks_EnsureNextChainedBlockIsAskedForOnStartUp");
                var nextChainedBlock = blockStoreLoop.Chain.GetBlock(blocks[1].GetHash());

                var context = new BlockStoreInnerStepContext(new CancellationToken(), blockStoreLoop).Initialize(nextChainedBlock);
                Assert.Equal(1, context.DownloadStack.Count());
                Assert.True(context.DownloadStack.Any(cb => cb.HashBlock == nextChainedBlock.HashBlock));

                // Push blocks[1] to the downloaded blocks collection
                blockStoreLoop.BlockPuller.InjectBlock(blocks[1].GetHash(), new DownloadedBlock()
                {
                    Length = blocks[1].GetSerializedSize(), Block = blocks[1]
                }, new CancellationToken());
                Assert.Equal(1, context.BlockStoreLoop.BlockPuller.DownloadedBlocksCount);

                // TryGetBlock should return NextChainedBlock
                DownloadedBlock downloadedBlock = null;
                context.BlockStoreLoop.BlockPuller.TryGetBlock(context.DownloadStack.Peek(), out downloadedBlock);

                Assert.NotNull(downloadedBlock);
                Assert.Equal(downloadedBlock.Block.GetHash(), nextChainedBlock.HashBlock);
            }
        }
Пример #2
0
 /// <summary>
 /// Adds the specified downloaded block.
 /// </summary>
 /// <param name="downloadedBlock">The downloaded block.</param>
 internal void Add(DownloadedBlock downloadedBlock)
 {
     lock (this.downloadedBlocksList)
     {
         this.downloadedBlocksList.Add(downloadedBlock.StartOffset, downloadedBlock);
     }
 }
        public bool TryGetBlock(ChainedBlock chainedBlock, out DownloadedBlock block)
        {
            if (this.DownloadedBlocks.TryRemove(chainedBlock.HashBlock, out block))
            {
                return(true);
            }

            this.OnStalling(chainedBlock);
            return(false);
        }
Пример #4
0
        /// <inheritdoc />
        public void InjectBlock(uint256 blockHash, DownloadedBlock downloadedBlock, CancellationToken cancellationToken)
        {
            this.logger.LogTrace("({0}:'{1}',{2}.{3}:{4})", nameof(blockHash), blockHash, nameof(downloadedBlock), nameof(downloadedBlock.Length), downloadedBlock.Length);

            if (this.AddDownloadedBlock(blockHash, downloadedBlock))
            {
                this.BlockPushed(blockHash, downloadedBlock, cancellationToken);
            }

            this.logger.LogTrace("(-)");
        }
Пример #5
0
        /// <inheritdoc />
        public void InjectBlock(uint256 blockHash, DownloadedBlock downloadedBlock, CancellationToken cancellationToken)
        {
            this.logger.LogTrace($"({nameof(blockHash)}:'{blockHash}',{nameof(downloadedBlock)}.{nameof(downloadedBlock.Length)}:{downloadedBlock.Length})");

            if (this.AddDownloadedBlock(blockHash, downloadedBlock))
            {
                this.BlockPushed(blockHash, downloadedBlock, cancellationToken);
            }

            this.logger.LogTrace("(-)");
        }
Пример #6
0
        /// <summary>
        /// Adds a downloaded block to the list of downloaded blocks.
        /// <para>
        /// If a block with the same hash already existed in the list,
        /// it is not replaced with the new one, but the function does not fail.
        /// </para>
        /// </summary>
        /// <param name="blockHash">Hash of the block to add.</param>
        /// <param name="downloadedBlock">Downloaded block to add.</param>
        /// <returns><c>true</c> if the block was added to the list of downloaded blocks, <c>false</c> if the block was already present.</returns>
        private bool AddDownloadedBlock(uint256 blockHash, DownloadedBlock downloadedBlock)
        {
            bool res = false;

            lock (this.lockObject)
            {
                res = this.downloadedBlocks.TryAdd(blockHash, downloadedBlock);
            }

            return(res);
        }
Пример #7
0
        /// <inheritdoc />
        public override void BlockPushed(uint256 blockHash, DownloadedBlock downloadedBlock, CancellationToken cancellationToken)
        {
            this.logger.LogTrace("({0}:'{1}',{2}.{3}:{4})", nameof(blockHash), blockHash, nameof(downloadedBlock), nameof(downloadedBlock.Length), downloadedBlock.Length);

            lock (this.bufferLock)
            {
                this.currentBufferedSize += downloadedBlock.Length;
                this.currentBufferedCount++;
            }
            this.pushed.Set();

            this.logger.LogTrace("(-)");
        }
Пример #8
0
        /// <summary>
        /// Tries to retrieve a specific downloaded block from the list of downloaded blocks.
        /// </summary>
        /// <param name="chainedBlock">Header of the block to retrieve.</param>
        /// <param name="block">If the function succeeds, the downloaded block is returned in this parameter.</param>
        /// <returns>true if the function succeeds, false otherwise.</returns>
        public bool TryGetBlock(ChainedBlock chainedBlock, out DownloadedBlock block)
        {
            this.logger.LogTrace("({0}:'{1}')", nameof(chainedBlock), chainedBlock);

            if (this.TryRemoveDownloadedBlock(chainedBlock.HashBlock, out block))
            {
                this.logger.LogTrace("(-):true");
                return(true);
            }

            this.OnStalling(chainedBlock);
            this.logger.LogTrace("(-):false");
            return(false);
        }
Пример #9
0
        /// <summary>
        /// Retrieves a downloaded block from list of downloaded blocks, but does not remove the block from the list.
        /// </summary>
        /// <param name="blockHash">Hash of the block to obtain.</param>
        /// <returns>Downloaded block or null if block with the given hash is not on the list.</returns>
        protected DownloadedBlock GetDownloadedBlock(uint256 blockHash)
        {
            this.logger.LogTrace("({0}:'{1}')", nameof(blockHash), blockHash);

            DownloadedBlock res = null;

            lock (this.lockObject)
            {
                res = this.downloadedBlocks.TryGet(blockHash);
            }

            this.logger.LogTrace("(-):'{0}'", res);
            return(res);
        }
Пример #10
0
        /// <summary>
        /// Retrieves a downloaded block from list of downloaded blocks, but does not remove the block from the list.
        /// </summary>
        /// <param name="blockHash">Hash of the block to obtain.</param>
        /// <returns>Downloaded block or null if block with the given hash is not on the list.</returns>
        protected DownloadedBlock GetDownloadedBlock(uint256 blockHash)
        {
            this.logger.LogTrace($"({nameof(blockHash)}:'{blockHash}')");

            DownloadedBlock res = null;

            lock (this.lockObject)
            {
                res = this.downloadedBlocks.TryGet(blockHash);
            }

            this.logger.LogTrace($"(-):'{res}'");
            return(res);
        }
Пример #11
0
            /// <summary>
            /// Calculates the length of the gap relative to <paramref name="position"/>.
            /// </summary>
            /// <param name="position">The position from which to find the gap.</param>
            /// <param name="desiredLength">Size of the desired.</param>
            /// <param name="gapStart">The gap start.</param>
            /// <param name="gapEnd">The gap end.</param>
            internal void CalculateGapLength(long position, long desiredLength, out long gapStart, out long gapEnd)
            {
                var readAheadStartPosition = position;

                if (this.Any())
                {
                    gapStart = gapEnd = -1;
                    DownloadedBlock block = null;
                    lock (this.downloadedBlocksList)
                    {
                        // Walk all blocks and find the next gap starting
                        foreach (var kvp in this.downloadedBlocksList)
                        {
                            // If we aren't beyond a block, we need to read from there.
                            block = kvp.Value;
                            if (gapStart == -1 && readAheadStartPosition < block.StartOffset)
                            {
                                gapStart = readAheadStartPosition;
                                gapEnd   = block.StartOffset - 1;
                                break;
                            }

                            readAheadStartPosition = block.StartOffset + block.BlockContent.Length;
                        }
                    }

                    // If we walked the whole list and didn't find a gap, we are close to the end.
                    if (gapStart == -1)
                    {
                        gapStart = block.StartOffset + block.BlockContent.Length;
                        gapEnd   = gapStart + desiredLength;
                    }
                }
                else
                {
                    gapStart = position;
                    gapEnd   = position + desiredLength;
                }

                System.Diagnostics.Debug.Assert(gapStart != -1, "Ensure that the gap bounds are not negative.");
                System.Diagnostics.Debug.Assert(gapEnd != -1, "Ensure that the gap bounds are not negative.");
            }
        /// <summary>
        /// Event handler that is called when the attached node receives a network message.
        /// <para>
        /// This handler modifies internal state when an information about a block is received.
        /// </para>
        /// </summary>
        /// <param name="node">Node that received the message.</param>
        /// <param name="message">Received message.</param>
        private void Node_MessageReceived(Node node, IncomingMessage message)
        {
            // TODO: https://github.com/stratisproject/StratisBitcoinFullNode/issues/292
            this.logger.LogTrace($"[{this.GetHashCode():x}] ({nameof(node.Peer.Endpoint)}:'{node.Peer.Endpoint}')");

            message.Message.IfPayloadIs <BlockPayload>((block) =>
            {
                // There are two pullers for each peer connection and each is having its own puller behavior.
                // Both these behaviors get notification from the node when it receives a message,
                // even if the origin of the message was from the other puller behavior.
                // Therefore we first make a quick check whether this puller behavior was the one
                // who should deal with this block.
                uint256 blockHash = block.Object.Header.GetHash();
                if (this.puller.CheckBlockTaskAssignment(this, blockHash))
                {
                    this.logger.LogTrace($"[{this.GetHashCode():x}] Received block '{blockHash}', length {message.Length} bytes.");

                    block.Object.Header.CacheHashes();
                    foreach (Transaction tx in block.Object.Transactions)
                    {
                        tx.CacheHashes();
                    }

                    DownloadedBlock downloadedBlock = new DownloadedBlock()
                    {
                        Block  = block.Object,
                        Length = (int)message.Length,
                    };

                    if (this.puller.DownloadTaskFinished(this, blockHash, downloadedBlock))
                    {
                        this.puller.BlockPushed(blockHash, downloadedBlock, this.cancellationToken.Token);
                    }

                    // This peer is now available for more work.
                    this.AssignPendingVector();
                }
            });

            this.logger.LogTrace($"[{this.GetHashCode():x}] (-)");
        }
Пример #13
0
        /// <summary>
        /// Event handler that is called when a message is received from the attached peer.
        /// <para>
        /// This handler modifies internal state when an information about a block is received.
        /// </para>
        /// </summary>
        /// <param name="peer">Peer that sent us the message.</param>
        /// <param name="message">Received message.</param>
        private async Task OnMessageReceivedAsync(NetworkPeer peer, IncomingMessage message)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:'{3}')", nameof(peer), peer.RemoteSocketEndpoint, nameof(message), message.Message.Command);

            if (message.Message.Payload is BlockPayload block)
            {
                // There are two pullers for each peer connection and each is having its own puller behavior.
                // Both these behaviors get notification from the node when it receives a message,
                // even if the origin of the message was from the other puller behavior.
                // Therefore we first make a quick check whether this puller behavior was the one
                // who should deal with this block.
                uint256 blockHash = block.Obj.Header.GetHash(peer.Network.NetworkOptions);
                if (this.puller.CheckBlockTaskAssignment(this, blockHash))
                {
                    this.logger.LogTrace("Received block '{0}', length {1} bytes.", blockHash, message.Length);

                    block.Obj.Header.CacheHashes();
                    foreach (Transaction tx in block.Obj.Transactions)
                    {
                        tx.CacheHashes();
                    }

                    DownloadedBlock downloadedBlock = new DownloadedBlock
                    {
                        Block  = block.Obj,
                        Length = (int)message.Length,
                        Peer   = peer.RemoteSocketEndpoint
                    };

                    if (this.puller.DownloadTaskFinished(this, blockHash, downloadedBlock))
                    {
                        this.puller.BlockPushed(blockHash, downloadedBlock, this.cancellationToken.Token);
                    }

                    // This peer is now available for more work.
                    await this.AssignPendingVectorAsync().ConfigureAwait(false);
                }
            }

            this.logger.LogTrace("(-)");
        }
Пример #14
0
        /// <inheritdoc />
        /// <remarks>
        /// This method waits for the block puller to have empty space (see <see cref="MaxBufferedSize"/>)) for a new block.
        /// This happens if the consumer is not consuming the downloaded blocks quickly enough - relative to how quickly the blocks are downloaded.
        /// TODO: https://github.com/stratisproject/StratisBitcoinFullNode/issues/277
        /// </remarks>
        public override void BlockPushed(uint256 blockHash, DownloadedBlock downloadedBlock, CancellationToken cancellationToken)
        {
            this.logger.LogTrace($"({nameof(blockHash)}:'{blockHash}')");

            ChainedBlock header = this.Chain.GetBlock(blockHash);

            // TODO: Race condition here (and also below) on this.currentSize. How about this.location.Height?
            // https://github.com/stratisproject/StratisBitcoinFullNode/issues/277
            while ((this.currentSize + downloadedBlock.Length >= this.MaxBufferedSize) && (header.Height != this.location.Height + 1))
            {
                this.logger.LogTrace($"Waiting for free space in the puller. {nameof(this.currentSize)}={this.currentSize} + {nameof(downloadedBlock)}.{nameof(downloadedBlock.Length)}={downloadedBlock.Length} = {this.currentSize + downloadedBlock.Length} >= {this.MaxBufferedSize}.");
                this.IsFull = true;
                this.consumed.WaitOne(1000);
                cancellationToken.ThrowIfCancellationRequested();
            }
            this.IsFull       = false;
            this.currentSize += downloadedBlock.Length;
            this.pushed.Set();

            this.logger.LogTrace("(-)");
        }
Пример #15
0
        /// <summary>
        /// Event handler that is called when the attached node receives a network message.
        /// <para>
        /// This handler modifies internal state when an information about a block is received.
        /// </para>
        /// </summary>
        /// <param name="node">Node that received the message.</param>
        /// <param name="message">Received message.</param>
        private void Node_MessageReceived(Node node, IncomingMessage message)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:'{3}')", nameof(node), node.RemoteSocketEndpoint, nameof(message), message.Message.Command);

            message.Message.IfPayloadIs <BlockPayload>((block) =>
            {
                // There are two pullers for each peer connection and each is having its own puller behavior.
                // Both these behaviors get notification from the node when it receives a message,
                // even if the origin of the message was from the other puller behavior.
                // Therefore we first make a quick check whether this puller behavior was the one
                // who should deal with this block.
                uint256 blockHash = block.Object.Header.GetHash();
                if (this.puller.CheckBlockTaskAssignment(this, blockHash))
                {
                    this.logger.LogTrace("Received block '{0}', length {1} bytes.", blockHash, message.Length);

                    block.Object.Header.CacheHashes();
                    foreach (Transaction tx in block.Object.Transactions)
                    {
                        tx.CacheHashes();
                    }

                    DownloadedBlock downloadedBlock = new DownloadedBlock
                    {
                        Block  = block.Object,
                        Length = (int)message.Length,
                    };

                    if (this.puller.DownloadTaskFinished(this, blockHash, downloadedBlock))
                    {
                        this.puller.BlockPushed(blockHash, downloadedBlock, this.cancellationToken.Token);
                    }

                    // This peer is now available for more work.
                    this.AssignPendingVector();
                }
            });

            this.logger.LogTrace("(-)");
        }
Пример #16
0
        /// <inheritdoc />
        public Block TryGetLookahead(int count)
        {
            this.logger.LogTrace("({0}:{1})", nameof(count), count);

            ChainedBlock chainedBlock = this.Chain.GetBlock(this.location.Height + 1 + count);

            if (chainedBlock == null)
            {
                this.logger.LogTrace("(-)[NOT_KNOWN]");
                return(null);
            }

            DownloadedBlock block = this.GetDownloadedBlock(chainedBlock.HashBlock);

            if (block == null)
            {
                this.logger.LogTrace("(-)[NOT_AVAILABLE]");
                return(null);
            }

            this.logger.LogTrace("(-):'{0}'", block.Block);
            return(block.Block);
        }
Пример #17
0
        /// <summary>
        /// Get and remove a downloaded block from the list of downloaded blocks.
        /// </summary>
        /// <param name="blockHash">Hash of the block to retrieve.</param>
        /// <param name="downloadedBlock">If the function succeeds, this is filled with the downloaded block, which hash is <paramref name="blockHash"/>.</param>
        /// <returns><c>true</c> if the function succeeds, <c>false</c> if the block with the given hash was not in the list.</returns>
        protected bool TryRemoveDownloadedBlock(uint256 blockHash, out DownloadedBlock downloadedBlock)
        {
            this.logger.LogTrace("({0}:'{1}')", nameof(blockHash), blockHash);

            bool res = false;

            lock (this.lockObject)
            {
                if (this.downloadedBlocks.TryGetValue(blockHash, out downloadedBlock))
                {
                    res = this.downloadedBlocks.Remove(blockHash);
                }
            }

            if (res)
            {
                this.logger.LogTrace("(-):{0},*{1}.{2}:{3}", res, nameof(downloadedBlock), nameof(downloadedBlock.Length), downloadedBlock.Length);
            }
            else
            {
                this.logger.LogTrace("(-):{0}", res);
            }
            return(res);
        }
Пример #18
0
        /// <summary>
        /// Get and remove a downloaded block from the list of downloaded blocks.
        /// </summary>
        /// <param name="blockHash">Hash of the block to retrieve.</param>
        /// <param name="downloadedBlock">If the function succeeds, this is filled with the downloaded block, which hash is <paramref name="blockHash"/>.</param>
        /// <returns><c>true</c> if the function succeeds, <c>false</c> if the block with the given hash was not in the list.</returns>
        protected bool TryRemoveDownloadedBlock(uint256 blockHash, out DownloadedBlock downloadedBlock)
        {
            this.logger.LogTrace($"({nameof(blockHash)}:'{blockHash}')");

            bool res = false;

            lock (this.lockObject)
            {
                if (this.downloadedBlocks.TryGetValue(blockHash, out downloadedBlock))
                {
                    res = this.downloadedBlocks.Remove(blockHash);
                }
            }

            if (res)
            {
                this.logger.LogTrace($"(-):{res},*{nameof(downloadedBlock)}.{nameof(downloadedBlock.Length)}:{downloadedBlock.Length}");
            }
            else
            {
                this.logger.LogTrace($"(-):{res}");
            }
            return(res);
        }
        /// <summary> Adds the downloaded block to the store and resets the stall count.</summary>
        private ChainedBlock AddDownloadedBlockToStore(BlockStoreInnerStepContext context, DownloadedBlock downloadedBlock)
        {
            ChainedBlock chainedBlockToStore = context.DownloadStack.Dequeue();

            context.Store.Add(new BlockPair(downloadedBlock.Block, chainedBlockToStore));

            context.InsertBlockSize += downloadedBlock.Length;
            context.StallCount       = 0;

            this.logger.LogTrace("{0}='{1}/{2}' added to the store.", nameof(chainedBlockToStore), chainedBlockToStore.HashBlock, chainedBlockToStore.Height, context.BlocksPushedCount);
            return(chainedBlockToStore);
        }
Пример #20
0
 /// <summary>
 /// Adds the specified downloaded block.
 /// </summary>
 /// <param name="downloadedBlock">The downloaded block.</param>
 internal void Add(DownloadedBlock downloadedBlock)
 {
     lock (this.downloadedBlocksList)
     {
         this.downloadedBlocksList.Add(downloadedBlock.StartOffset, downloadedBlock);
     }
 }
Пример #21
0
        /// <summary> Adds the downloaded block to the store and resets the stall count.</summary>
        private ChainedBlock AddDownloadedBlockToStore(BlockStoreInnerStepContext context, DownloadedBlock downloadedBlock)
        {
            this.logger.LogTrace("({0}.{1}:{2})", nameof(downloadedBlock), nameof(downloadedBlock.Length), downloadedBlock.Length);

            ChainedBlock chainedBlockToStore = context.DownloadStack.Dequeue();

            context.Store.Add(new BlockPair(downloadedBlock.Block, chainedBlockToStore));

            context.InsertBlockSize += downloadedBlock.Length;
            context.StallCount       = 0;

            this.logger.LogTrace("(-):'{0}'", chainedBlockToStore);
            return(chainedBlockToStore);
        }
Пример #22
0
 /// <summary>
 /// Method called when a new block is downloaded and pushed to the puller.
 /// <para>
 /// This method is to be overridden by derived classes. In the base class it only logs the event.
 /// </para>
 /// </summary>
 /// <param name="blockHash">Hash of the newly downloaded block.</param>
 /// <param name="downloadedBlock">Desciption of the newly downloaded block.</param>
 /// <param name="cancellationToken">Cancellation token to be used by derived classes that allows the caller to cancel the execution of the operation.</param>
 public virtual void BlockPushed(uint256 blockHash, DownloadedBlock downloadedBlock, CancellationToken cancellationToken)
 {
     this.logger.LogTrace($"({nameof(blockHash)}:'{blockHash}',{nameof(downloadedBlock)}.{nameof(downloadedBlock.Length)}:{downloadedBlock.Length})");
     this.logger.LogTrace("(-)");
 }
Пример #23
0
        /// <summary>
        /// When a peer downloads a block, it notifies the puller about the block by calling this method.
        /// <para>
        /// The downloaded task is removed from the list of pending downloads
        /// and it is also removed from the <see cref="assignedBlockTasks"/> - i.e. the task is no longer assigned to the peer.
        /// And finally, it is added to the list of downloaded blocks, provided that the block is not present there already.
        /// </para>
        /// </summary>
        /// <param name="peer">Peer that finished the download task.</param>
        /// <param name="blockHash">Hash of the downloaded block.</param>
        /// <param name="downloadedBlock">Description of the downloaded block.</param>
        /// <returns>
        /// <c>true</c> if the download task for the block was assigned to <paramref name="peer"/>
        /// and the task was removed and added to the list of downloaded blocks.
        /// <c>false</c> if the downloaded block has been assigned to another peer
        /// or if the block was already on the list of downloaded blocks.
        /// </returns>
        internal bool DownloadTaskFinished(BlockPullerBehavior peer, uint256 blockHash, DownloadedBlock downloadedBlock)
        {
            this.logger.LogTrace("({0}:'{1:x}',{2}:'{3}',{4}.{5}:{6})", nameof(peer), peer.GetHashCode(), nameof(blockHash), blockHash, nameof(downloadedBlock), nameof(downloadedBlock.Length), downloadedBlock.Length);

            bool error = false;
            bool res   = false;

            double peerQualityAdjustment = 0;

            lock (this.lockObject)
            {
                BlockPullerBehavior peerAssigned;
                if (this.assignedBlockTasks.TryGetValue(blockHash, out peerAssigned))
                {
                    Dictionary <uint256, DownloadAssignment> peerPendingDownloads;
                    if (this.peersPendingDownloads.TryGetValue(peer, out peerPendingDownloads))
                    {
                        if (peer == peerAssigned)
                        {
                            DownloadAssignment downloadTask = null;
                            peerPendingDownloads.TryGetValue(blockHash, out downloadTask);

                            if (this.assignedBlockTasks.Remove(blockHash) && peerPendingDownloads.Remove(blockHash))
                            {
                                // Task was assigned to this peer and was removed.
                                if (this.downloadedBlocks.TryAdd(blockHash, downloadedBlock))
                                {
                                    long blockDownloadTime = downloadTask.Finish();
                                    this.peerQuality.AddSample(peer, blockDownloadTime, downloadedBlock.Length);
                                    peerQualityAdjustment = this.peerQuality.CalculateQualityAdjustment(blockDownloadTime, downloadedBlock.Length);

                                    this.logger.LogTrace("Block '{0}' size '{1}' downloaded by peer '{2:x}' in {3} ms, peer's score will be adjusted by {4}.", blockHash, downloadedBlock.Length, peer.GetHashCode(), blockDownloadTime, peerQualityAdjustment);

                                    res = true;
                                }
                                else
                                {
                                    this.logger.LogTrace("Block '{0}' already present on the list of downloaded blocks.", blockHash);
                                }
                            }
                            else
                            {
                                // Task was assigned to this peer but the data are inconsistent.
                                error = true;
                            }
                        }
                        else
                        {
                            // Before this peer provided the block, it has been assigned to other peer, which is OK.
                            this.logger.LogTrace("Incoming block '{0}' is assigned to peer '{1:x}', not to '{2:x}'.", blockHash, peerAssigned.GetHashCode(), peer.GetHashCode());
                        }
                    }
                    else
                    {
                        // Peer's pending downloads were probably released, which is OK.
                        this.logger.LogTrace("Peer '{0:x}' has no assignments.", peer.GetHashCode());
                    }
                }
                else
                {
                    // The task was probably assigned to other peer and that task completed before this peer provided the block, which is OK.
                    this.logger.LogTrace("Incoming block '{0}' is not pending.", blockHash);
                }
            }

            if (error)
            {
                this.logger.LogCritical("Data structures inconsistency, please notify the devs.");

                // TODO: This exception is going to be silently discarded by Node_MessageReceived.
                throw new InvalidOperationException("Data structures inconsistency, please notify the devs.");
            }

            if (res)
            {
                peer.UpdateQualityScore(peerQualityAdjustment);
            }

            this.logger.LogTrace("(-):{0}", res);
            return(res);
        }
Пример #24
0
 /// <summary>
 /// Method called when a new block is downloaded and pushed to the puller.
 /// <para>
 /// This method is to be overridden by derived classes. In the base class it only logs the event.
 /// </para>
 /// </summary>
 /// <param name="blockHash">Hash of the newly downloaded block.</param>
 /// <param name="downloadedBlock">Desciption of the newly downloaded block.</param>
 /// <param name="cancellationToken">Cancellation token to be used by derived classes that allows the caller to cancel the execution of the operation.</param>
 public virtual void BlockPushed(uint256 blockHash, DownloadedBlock downloadedBlock, CancellationToken cancellationToken)
 {
     this.logger.LogTrace("({0}:'{1}',{2}.{3}:{4})", nameof(blockHash), blockHash, nameof(downloadedBlock), nameof(downloadedBlock.Length), downloadedBlock.Length);
     this.logger.LogTrace("(-)");
 }