/// <summary> /// Decreases the quality score of the peer node. /// <para>This function is called when something goes wrong with the peer.</para> /// <para>If the score reaches the minimal value, the tasks assigned for the node are released.</para> /// </summary> /// <param name="chainedBlock">Block the node wanted to download, but something went wrong during the process.</param> protected void OnStalling(ChainedBlock chainedBlock) { this.logger.LogTrace("({0}:'{1}')", nameof(chainedBlock), chainedBlock.HashBlock); BlockPullerBehavior behavior = null; lock (this.lockObject) { this.assignedBlockTasks.TryGetValue(chainedBlock.HashBlock, out behavior); } if (behavior != null) { double penalty = this.peerQuality.CalculateNextBlockTimeoutQualityPenalty(); this.logger.LogTrace("Block '{0}' assigned to peer {1:x}, penalty is {2}.", chainedBlock.HashBlock, behavior.GetHashCode(), penalty); behavior.UpdateQualityScore(penalty); if (Math.Abs(behavior.QualityScore - QualityScore.MinScore) < 0.00001) { behavior.ReleaseAll(false); this.AssignPendingVectors(); } } else { this.logger.LogTrace("Block '{0}' not assigned to any peer.", chainedBlock.HashBlock); this.AssignPendingVectors(); } this.logger.LogTrace("(-)"); }
/// <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); }