/// <summary> /// Sends a message to the connected peer requesting specific data. /// </summary> /// <param name="getDataPayload">Specification of the data to download - <see cref="GetDataPayload"/>.</param> /// <returns><c>true</c> if the message was successfully sent to the peer, <c>false</c> if the peer got disconnected.</returns> /// <remarks>Caller is responsible to add the puller to the map if necessary.</remarks> internal async Task <bool> StartDownloadAsync(GetDataPayload getDataPayload) { this.logger.LogTrace("()"); INetworkPeer attachedNode = this.AttachedPeer; if ((attachedNode == null) || (attachedNode.State != NetworkPeerState.HandShaked) || !this.puller.Requirements.Check(attachedNode.PeerVersion)) { this.logger.LogTrace("(-)[ATTACHED_PEER]:false"); return(false); } foreach (InventoryVector inv in getDataPayload.Inventory) { inv.Type = attachedNode.AddSupportedOptions(inv.Type); } try { await attachedNode.SendMessageAsync(getDataPayload).ConfigureAwait(false); // In case job is assigned to a peer with low quality score- // give it enough score so the job is not reassigned right away. this.UpdateQualityScore(BlockPulling.QualityScore.MaxScore / 10); } catch (OperationCanceledException) { this.logger.LogTrace("(-)[CANCELLED]:false"); return(false); } this.logger.LogTrace("(-):true"); return(true); }
/// <inheritdoc/> public async Task RequestBlocksAsync(List <uint256> hashes) { var getDataPayload = new GetDataPayload(); INetworkPeer peer = this.AttachedPeer; if (peer == null) { this.logger.LogTrace("(-)[PEER_DETACHED]"); throw new OperationCanceledException("Peer is detached already!"); } foreach (uint256 uint256 in hashes) { var vector = new InventoryVector(InventoryType.MSG_BLOCK, uint256); vector.Type = peer.AddSupportedOptions(vector.Type); getDataPayload.Inventory.Add(vector); } if (peer.State != NetworkPeerState.HandShaked) { this.logger.LogTrace("(-)[ATTACHED_PEER]"); throw new OperationCanceledException("Peer is in the wrong state!"); } await peer.SendMessageAsync(getDataPayload).ConfigureAwait(false); }
/// <summary> /// If there are any more blocks the node wants to download, this method assigns and starts /// a new download task for a specific peer that this behavior represents. /// </summary> private async Task AssignPendingVectorAsync() { this.logger.LogTrace("()"); INetworkPeer attachedNode = this.AttachedPeer; if ((attachedNode == null) || (attachedNode.State != NetworkPeerState.HandShaked) || !this.puller.Requirements.Check(attachedNode.PeerVersion)) { this.logger.LogTrace("(-)[ATTACHED_NODE]"); return; } uint256 block = null; if (this.puller.AssignPendingDownloadTaskToPeer(this, out block)) { try { var getDataPayload = new GetDataPayload(new InventoryVector(attachedNode.AddSupportedOptions(InventoryType.MSG_BLOCK), block)); await attachedNode.SendMessageAsync(getDataPayload).ConfigureAwait(false); } catch (OperationCanceledException) { } } this.logger.LogTrace("(-)"); }
/// <summary> /// Sends a message to the connected peer requesting specific data. /// </summary> /// <param name="getDataPayload">Specification of the data to download - <see cref="GetDataPayload"/>.</param> /// <returns><c>true</c> if the message was successfully sent to the peer, <c>false</c> if the peer got disconnected.</returns> /// <remarks>Caller is responsible to add the puller to the map if necessary.</remarks> internal async Task <bool> StartDownloadAsync(GetDataPayload getDataPayload) { this.logger.LogTrace("()"); INetworkPeer attachedNode = this.AttachedPeer; if ((attachedNode == null) || (attachedNode.State != NetworkPeerState.HandShaked) || !this.puller.Requirements.Check(attachedNode.PeerVersion)) { this.logger.LogTrace("(-)[ATTACHED_PEER]:false"); return(false); } foreach (InventoryVector inv in getDataPayload.Inventory) { inv.Type = attachedNode.AddSupportedOptions(inv.Type); } try { await attachedNode.SendMessageAsync(getDataPayload).ConfigureAwait(false); } catch (OperationCanceledException) { this.logger.LogTrace("(-)[CANCELLED]:false"); return(false); } this.logger.LogTrace("(-):true"); return(true); }
/// <summary> /// Processing of inventory payload message from the peer. /// Adds inventory to known inventory then sends GetDataPayload to the attached peer. /// </summary> /// <param name="peer">The peer sending the message.</param> /// <param name="invPayload">The inventory payload in the message.</param> private async Task ProcessInvAsync(INetworkPeer peer, InvPayload invPayload) { Guard.NotNull(peer, nameof(peer)); this.logger.LogTrace("({0}:'{1}',{2}.{3}.{4}:{5})", nameof(peer), peer.RemoteSocketEndpoint, nameof(invPayload), nameof(invPayload.Inventory), nameof(invPayload.Inventory.Count), invPayload.Inventory.Count); if (invPayload.Inventory.Count > ConnectionManager.MaxInventorySize) { this.logger.LogTrace("(-)[MAX_INV_SZ]"); //Misbehaving(pfrom->GetId(), 20); // TODO: Misbehaving return; //error("message inv size() = %u", vInv.size()); } if (this.initialBlockDownloadState.IsInitialBlockDownload()) { this.logger.LogTrace("(-)[IS_IBD]"); return; } //uint32_t nFetchFlags = GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()); var send = new GetDataPayload(); foreach (InventoryVector inv in invPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX))) { //inv.type |= nFetchFlags; // TODO: This is incorrect, in blocks only mode we should just add to known inventory but not relay if (this.isBlocksOnlyMode) { this.logger.LogInformation("Transaction ID '{0}' inventory sent in violation of protocol peer '{1}'.", inv.Hash, peer.RemoteSocketEndpoint); } if (await this.orphans.AlreadyHaveAsync(inv.Hash)) { this.logger.LogDebug("Transaction ID '{0}' already in orphans, skipped.", inv.Hash); continue; } send.Inventory.Add(new InventoryVector(peer.AddSupportedOptions(InventoryType.MSG_TX), inv.Hash)); } // add to known inventory lock (this.lockObject) { foreach (InventoryVector inventoryVector in send.Inventory) { this.filterInventoryKnown.Add(inventoryVector.Hash); } } if (peer.IsConnected) { this.logger.LogTrace("Asking for transaction data from peer '{0}'.", peer.RemoteSocketEndpoint); await peer.SendMessageAsync(send).ConfigureAwait(false); } this.logger.LogTrace("(-)"); }
/// <summary> /// Processing of inventory payload message from the peer. /// Adds inventory to known inventory then sends GetDataPayload to the attached peer. /// </summary> /// <param name="peer">The peer sending the message.</param> /// <param name="invPayload">The inventory payload in the message.</param> private async Task ProcessInvAsync(INetworkPeer peer, InvPayload invPayload) { Guard.NotNull(peer, nameof(peer)); if (invPayload.Inventory.Count > ConnectionManager.MaxInventorySize) { this.logger.LogTrace("(-)[MAX_INV_SZ]"); //Misbehaving(pfrom->GetId(), 20); // TODO: Misbehaving return; //error("message inv size() = %u", vInv.size()); } //uint32_t nFetchFlags = GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()); var inventoryTxs = invPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX)); lock (this.lockObject) { foreach (var inv in inventoryTxs) { this.filterInventoryKnown.Add(inv.Hash); } } var send = new GetDataPayload(); foreach (var inv in inventoryTxs) { if (await this.orphans.AlreadyHaveAsync(inv.Hash).ConfigureAwait(false)) { this.logger.LogDebug("Transaction ID '{0}' already in orphans, skipped.", inv.Hash); continue; } if (this.isBlocksOnlyMode) { this.logger.LogDebug("Transaction ID '{0}' inventory sent in violation of protocol peer '{1}'.", inv.Hash, peer.RemoteSocketEndpoint); continue; } send.Inventory.Add(new InventoryVector(peer.AddSupportedOptions(InventoryType.MSG_TX), inv.Hash)); } if (peer.IsConnected && (send.Inventory.Count > 0)) { this.logger.LogDebug("Asking for transaction data from peer '{0}'.", peer.RemoteSocketEndpoint); await peer.SendMessageAsync(send).ConfigureAwait(false); } }
/// <summary> /// Sends transactions as inventory to attached peer. /// </summary> /// <param name="peer">Peer to send transactions to.</param> /// <param name="trxList">List of transactions.</param> private async Task SendAsTxInventoryAsync(INetworkPeer peer, List <uint256> trxList) { var queue = new Queue <InventoryVector>(trxList.Select(s => new InventoryVector(peer.AddSupportedOptions(InventoryType.MSG_TX), s))); while (queue.Count > 0) { InventoryVector[] items = queue.TakeAndRemove(ConnectionManager.MaxInventorySize).ToArray(); if (peer.IsConnected) { this.logger.LogTrace("Sending transaction inventory to peer '{0}'.", peer.RemoteSocketEndpoint); await peer.SendMessageAsync(new InvPayload(items)).ConfigureAwait(false); } } }