예제 #1
0
        /// <summary>
        /// Adds download task to the peer's list of pending download tasks.
        /// </summary>
        /// <param name="peer">Peer to add task to.</param>
        /// <param name="blockHash">Hash of the block being assigned to <paramref name="peer"/> for download.</param>
        /// <remarks>The caller of this method is responsible for holding <see cref="lockObject"/>.</remarks>
        private void AddPeerPendingDownloadLocked(BlockPullerBehavior peer, uint256 blockHash)
        {
            this.logger.LogTrace("({0}:'{1:x}',{2}:'{3}')", nameof(peer), peer.GetHashCode(), nameof(blockHash), blockHash);

            Dictionary <uint256, DownloadAssignment> peerPendingDownloads;

            if (!this.peersPendingDownloads.TryGetValue(peer, out peerPendingDownloads))
            {
                peerPendingDownloads = new Dictionary <uint256, DownloadAssignment>();
                this.peersPendingDownloads.Add(peer, peerPendingDownloads);
            }

            var downloadTask = new DownloadAssignment(blockHash);

            peerPendingDownloads.Add(blockHash, downloadTask);
            this.logger.LogTrace("(-)");
        }
예제 #2
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);
        }