/// <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); // 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); }
private void StartDownload(InventoryVector[] vectors, BlockingPullerBehavior[] nodes) { if (vectors.Length == 0) { return; } if (nodes.Length == 0) { foreach (var v in vectors) { this.pendingInventoryVectors.Add(v.Hash); } return; } // find the node with the height score var selected = nodes.OrderByDescending(n => n.QualityScore).First(); var getdata = new GetDataPayload(); foreach (var inv in vectors) { if (this.map.TryAdd(inv.Hash, selected)) { getdata.Inventory.Add(inv); } } selected.StartDownload(getdata); }
public static async Task <Block> DownloadBlockAsync(this Node node, uint256 hash, CancellationToken cancellationToken) { if (node.State == NodeState.Connected) { node.VersionHandshake(cancellationToken); } using var listener = node.CreateListener(); var getdata = new GetDataPayload(new InventoryVector(node.AddSupportedOptions(InventoryType.MSG_BLOCK), hash)); await node.SendMessageAsync(getdata).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); // Bitcoin Core processes the messages sequentially and does not send a NOTFOUND message if the remote node is pruned and the data not available. // A good way to get any feedback about whether the node knows the block or not is to send a ping request. // If block is not known by the remote node, the pong will be sent immediately, else it will be sent after the block download. ulong pingNonce = RandomUtils.GetUInt64(); await node.SendMessageAsync(new PingPayload() { Nonce = pingNonce }).ConfigureAwait(false); while (true) { cancellationToken.ThrowIfCancellationRequested(); var message = listener.ReceiveMessage(cancellationToken); if (message.Message.Payload is NotFoundPayload || (message.Message.Payload is PongPayload p && p.Nonce == pingNonce)) { throw new InvalidOperationException($"Disconnected local node, because it does not have the block data."); }
private async Task ProcessInvAsync(Node node, InvPayload invPayload) { if (invPayload.Inventory.Count > MAX_INV_SIZE) { Logger.LogDebug($"Received inventory too big. {nameof(MAX_INV_SIZE)}: {MAX_INV_SIZE}, Node: {node.RemoteSocketEndpoint}"); return; } var payload = new GetDataPayload(); foreach (var inv in invPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX))) { // if we already have it continue; if (!MemPoolService.TransactionHashes.Add(inv.Hash)) { continue; } payload.Inventory.Add(inv); } if (node.IsConnected) { // ask for the whole transaction await node.SendMessageAsync(payload); } }
private void AttachedNode_MessageReceived(Node node, IncomingMessage message) { if (message.Message.Payload is InvPayload invs) { // Do not asks transactions if we are synching so that we can process blocks faster if (IsSynching()) { return; } var data = new GetDataPayload(); foreach (var inv in invs.Inventory.Where(t => t.Type.HasFlag(InventoryType.MSG_TX))) { inv.Type = node.AddSupportedOptions(inv.Type); data.Inventory.Add(inv); } if (data.Inventory.Count != 0) { node.SendMessageAsync(data); } } else if (message.Message.Payload is HeadersPayload headers) { if (headers.Headers.Count == 0) { return; } _NewBlock.Set(); } else if (message.Message.Payload is TxPayload txPayload) { Run(() => SaveMatches(txPayload.Object, true)); } }
/// <summary> /// Handler for processing node messages. /// Handles the following message payloads: TxPayload, MempoolPayload, GetDataPayload, InvPayload. /// </summary> /// <param name="node">Node sending the message.</param> /// <param name="message">Incoming message.</param> private Task AttachedNode_MessageReceivedAsync(Node node, IncomingMessage message) { TxPayload txPayload = message.Message.Payload as TxPayload; if (txPayload != null) { return(this.ProcessTxPayloadAsync(node, txPayload)); } MempoolPayload mempoolPayload = message.Message.Payload as MempoolPayload; if (mempoolPayload != null) { return(this.SendMempoolPayload(node, mempoolPayload)); } GetDataPayload getDataPayload = message.Message.Payload as GetDataPayload; if (getDataPayload != null) { return(this.ProcessGetDataAsync(node, getDataPayload)); } InvPayload invPayload = message.Message.Payload as InvPayload; if (invPayload != null) { return(this.ProcessInvAsync(node, invPayload)); } return(Task.CompletedTask); }
private void AttachedNode_MessageReceived(Node node, IncomingMessage message) { if (message.Message.Payload is InvPayload invs) { var data = new GetDataPayload(); foreach (var inv in invs.Inventory) { inv.Type = node.AddSupportedOptions(inv.Type); if (inv.Type.HasFlag(InventoryType.MSG_TX)) { data.Inventory.Add(inv); } } if (data.Inventory.Count != 0) { node.SendMessageAsync(data); } } else if (message.Message.Payload is HeadersPayload headers) { if (headers.Headers.Count == 0) { return; } AskBlocks(); } else if (message.Message.Payload is BlockPayload block) { Task.Run(() => SaveMatches(block.Object)); } else if (message.Message.Payload is TxPayload txPayload) { Task.Run(() => SaveMatches(txPayload.Object)); } }
/// <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> /// Processing of the get data payload message from node. /// Sends the memory pool transaction info via TxPayload to the attached node. /// </summary> /// <param name="node">Node sending the message.</param> /// <param name="getDataPayload">The payload for the message.</param> private async Task ProcessGetDataAsync(NetworkPeer node, GetDataPayload getDataPayload) { Guard.NotNull(node, nameof(node)); this.logger.LogTrace("({0}:'{1}',{2}.{3}.{4}:{5})", nameof(node), node.RemoteSocketEndpoint, nameof(getDataPayload), nameof(getDataPayload.Inventory), nameof(getDataPayload.Inventory.Count), getDataPayload.Inventory.Count); if (node != this.AttachedPeer) { this.logger.LogDebug("Attached node '{0}' does not match the originating node '{1}'.", this.AttachedPeer?.RemoteSocketEndpoint, node.RemoteSocketEndpoint); this.logger.LogTrace("(-)[NODE_MISMATCH]"); return; } foreach (InventoryVector item in getDataPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX))) { // TODO: check if we need to add support for "not found" TxMempoolInfo trxInfo = await this.manager.InfoAsync(item.Hash).ConfigureAwait(false); if (trxInfo != null) { //TODO strip block of witness if node does not support if (node.IsConnected) { this.logger.LogTrace("Sending transaction '{0}' to peer '{1}'.", item.Hash, node.RemoteSocketEndpoint); await node.SendMessageAsync(new TxPayload(trxInfo.Trx.WithOptions(node.SupportedTransactionOptions))).ConfigureAwait(false); } } } this.logger.LogTrace("(-)"); }
private async Task ProcessInvAsync(Node node, InvPayload invPayload) { Guard.Assert(node == this.AttachedNode); // just in case if (invPayload.Inventory.Count > ConnectionManager.MAX_INV_SZ) { //Misbehaving(pfrom->GetId(), 20); // TODO: Misbehaving return; //error("message inv size() = %u", vInv.size()); } if (this.chainState.IsInitialBlockDownload) { return; } bool blocksOnly = !this.manager.NodeArgs.Mempool.RelayTxes; // Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true if (node.Behavior <ConnectionManagerBehavior>().Whitelisted&& this.manager.NodeArgs.Mempool.Whitelistrelay) { blocksOnly = false; } //uint32_t nFetchFlags = GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()); var send = new GetDataPayload(); foreach (var inv in invPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX))) { //inv.type |= nFetchFlags; if (blocksOnly) { Logging.Logs.Mempool.LogInformation( $"transaction ({inv.Hash}) inv sent in violation of protocol peer={node.RemoteSocketEndpoint}"); } if (await this.orphans.AlreadyHave(inv.Hash)) { continue; } send.Inventory.Add(inv); } // add to known inventory await this.manager.MempoolScheduler.WriteAsync(() => { foreach (var inventoryVector in send.Inventory) { this.filterInventoryKnown.TryAdd(inventoryVector.Hash, inventoryVector.Hash); } }); if (node.IsConnected) { await node.SendMessageAsync(send).ConfigureAwait(false); } }
public void ConstructorTest() { var invs = new Inventory[2]; var pl = new GetDataPayload(invs); Assert.Equal(PayloadType.GetData, pl.PayloadType); Assert.Same(invs, pl.InventoryList); }
/// <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(inv); } // add to known inventory lock (this.lockObject) { foreach (InventoryVector inventoryVector in send.Inventory) { this.filterInventoryKnown.Add(inventoryVector.Hash); } } if (peer.IsConnected) { this.logger.LogTrace("Sending transaction inventory to peer '{0}'.", peer.RemoteSocketEndpoint); await peer.SendMessageAsync(send).ConfigureAwait(false); } this.logger.LogTrace("(-)"); }
//Caller should add to the puller map internal void StartDownload(GetDataPayload getDataPayload) { foreach (var inv in getDataPayload.Inventory) { inv.Type = AttachedNode.AddSupportedOptions(inv.Type); _PendingDownloads.TryAdd(inv.Hash, inv.Hash); } AttachedNode.SendMessageAsync(getDataPayload); }
void AttachedNode_MessageReceived(Node node, IncomingMessage message) { InvPayload invPayload = message.Message.Payload as InvPayload; if (invPayload != null) { foreach (var hash in invPayload.Where(i => i.Type == InventoryType.MSG_TX).Select(i => i.Hash)) { var tx = GetTransaction(hash, true); if (tx != null) { tx.State = BroadcastState.Accepted; } Transaction unused; if (_BroadcastHub.BroadcastedTransaction.TryRemove(hash, out unused)) { _BroadcastHub.OnTransactionBroadcasted(tx.Transaction); } } } GetDataPayload getData = message.Message.Payload as GetDataPayload; if (getData != null) { foreach (var inventory in getData.Inventory.Where(i => i.Type == InventoryType.MSG_TX)) { var tx = GetTransaction(inventory.Hash, false); if (tx != null) { tx.State = BroadcastState.Broadcasted; var ping = new PingPayload(); tx.PingValue = ping.Nonce; _PingToTransaction.TryAdd(tx.PingValue, tx); node.SendMessageAsync(new TxPayload(tx.Transaction)); node.SendMessageAsync(ping); } } } PongPayload pong = message.Message.Payload as PongPayload; if (pong != null) { var tx = GetTransaction(pong.Nonce, true); if (tx != null) { tx.State = BroadcastState.Accepted; Transaction unused; if (_BroadcastHub.BroadcastedTransaction.TryRemove(tx.Transaction.GetHash(), out unused)) { _BroadcastHub.OnTransactionBroadcasted(tx.Transaction); } } } }
/// <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> 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()); } if (this.initialBlockDownloadState.IsInitialBlockDownload()) { this.logger.LogTrace("(-)[IS_IBD]"); return; } //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); } }
private void DistributeDownload(InventoryVector[] vectors, BlockPullerBehavior[] innernodes, int minHight) { if (vectors.Length == 0) { return; } // Be careful to not ask block to a node that do not have it // (we can check the ChainHeadersBehavior.PendingTip to know where the node is standing) var selectnodes = new List <BlockPullerBehavior>(); foreach (BlockPullerBehavior behavior in innernodes) { // filter nodes that are still behind using the // pending tip in the chain behaviour if (behavior.ChainHeadersBehavior?.PendingTip?.Height >= minHight) { selectnodes.Add(behavior); } } innernodes = selectnodes.ToArray(); if (innernodes.Length == 0) { foreach (InventoryVector v in vectors) { this.pendingInventoryVectors.Add(v.Hash); } return; } int[] scores = innernodes.Select(n => n.QualityScore == MaxQualityScore ? MaxQualityScore * 2 : n.QualityScore).ToArray(); var totalScore = scores.Sum(); GetDataPayload[] getDatas = innernodes.Select(n => new GetDataPayload()).ToArray(); foreach (InventoryVector inv in vectors) { int index = GetNodeIndex(scores, totalScore); BlockPullerBehavior node = innernodes[index]; GetDataPayload getData = getDatas[index]; if (this.map.TryAdd(inv.Hash, node)) { getData.Inventory.Add(inv); } } for (int i = 0; i < innernodes.Length; i++) { if (getDatas[i].Inventory.Count == 0) { continue; } innernodes[i].StartDownload(getDatas[i]); } }
async Task ProcessGetDataAsync(INetworkPeer peer, GetDataPayload getDataPayload) { // TODO: bring logic from core foreach (var item in getDataPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_BLOCK))) { var chainedHeaderBlock = this.consensusManager.GetBlockData(item.Hash); if (chainedHeaderBlock?.Block != null) { this.logger.LogDebug("Sending block '{0}' to peer '{1}'.", chainedHeaderBlock.ChainedHeader, peer.RemoteSocketEndpoint); //TODO strip block of witness if node does not support await peer.SendMessageAsync(new BlockPayload(chainedHeaderBlock.Block.WithOptions( this.ChainIndexer.Network.Consensus.ConsensusFactory, peer.SupportedTransactionOptions))) .ConfigureAwait(false); } else { this.logger.LogDebug("Block with hash '{0}' requested from peer '{1}' was not found in store.", item.Hash, peer.RemoteSocketEndpoint); } // If the peer is syncing using "getblocks" message we are supposed to send // an "inv" message with our tip to it once it asks for all blocks // from the previous batch. if (item.Hash == this.getBlocksBatchLastItemHash) { // Reset the hash to indicate that no continuation is pending anymore. this.getBlocksBatchLastItemHash = null; // Announce last block we have in the store. var blockStoreTip = this.blockStoreQueue.BlockStoreCacheTip; if (blockStoreTip != null) { this.logger.LogDebug("Sending continuation inventory message for block '{0}' to peer '{1}'.", blockStoreTip, peer.RemoteSocketEndpoint); var invContinue = new InvPayload(); invContinue.Inventory.Add(new InventoryVector(InventoryType.MSG_BLOCK, blockStoreTip.HashBlock)); await peer.SendMessageAsync(invContinue).ConfigureAwait(false); } else { this.logger.LogDebug("Reorg in blockstore, inventory continuation won't be sent to peer '{0}'.", peer.RemoteSocketEndpoint); } } } }
private async Task ProcessInventoryAsync(Node node, InvPayload invPayload) { var getDataPayload = new GetDataPayload(); foreach (var inv in invPayload.Inventory) { if (ProcessInventoryVector(inv, node.RemoteSocketEndpoint)) { getDataPayload.Inventory.Add(inv); } } if (getDataPayload.Inventory.Any() && node.IsConnected) { await node.SendMessageAsync(getDataPayload).ConfigureAwait(false); } }
private async void AttachedNode_MessageReceivedAsync(Node node, IncomingMessage message) { try { if (message.Message.Payload is TxPayload txPayload) { Transaction?.Invoke(this, new SmartTransaction(txPayload.Object, Height.Mempool)); } else if (message.Message.Payload is BlockPayload blockPayload) { Block?.Invoke(this, blockPayload.Object); } else if (message.Message.Payload is InvPayload invPayload) { var getDataPayload = new GetDataPayload(); foreach (var inv in invPayload.Inventory) { if (inv.Type.HasFlag(InventoryType.MSG_TX)) { TransactionInv?.Invoke(this, inv.Hash); getDataPayload.Inventory.Add(inv); } if (inv.Type.HasFlag(InventoryType.MSG_BLOCK)) { BlockInv?.Invoke(this, inv.Hash); getDataPayload.Inventory.Add(inv); } } if (getDataPayload.Inventory.Any() && node.IsConnected) { // ask for the whole transaction await node.SendMessageAsync(getDataPayload).ConfigureAwait(false); } } } catch (OperationCanceledException ex) { Logger.LogDebug(ex); } catch (Exception ex) { Logger.LogInfo($"Ignoring {ex.GetType()}: {ex.Message}"); Logger.LogDebug(ex); } }
protected async Task ProcessGetDataPayloadAsync(NetworkPeer peer, GetDataPayload getDataPayload) { // If node asks for tx we want to broadcast. foreach (InventoryVector inv in getDataPayload.Inventory.Where(x => x.Type == InventoryType.MSG_TX)) { TransactionBroadcastEntry txEntry = this.broadcasterManager.GetTransaction(inv.Hash); if ((txEntry != null) && (txEntry.State != State.CantBroadcast)) { await peer.SendMessageAsync(new TxPayload(txEntry.Transaction)).ConfigureAwait(false); if (txEntry.State == State.ToBroadcast) { this.broadcasterManager.AddOrUpdate(txEntry.Transaction, State.Broadcasted); } } } }
private async Task ProcessGetDataAsync(Node node, GetDataPayload getDataPayload) { Guard.Assert(node != null); // TODO: bring logic from core foreach (var item in getDataPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_BLOCK))) { // TODO: check if we need to add support for "not found" var block = await this.blockStoreCache.GetBlockAsync(item.Hash).ConfigureAwait(false); if (block != null) //TODO strip block of witness if node does not support await node.SendMessageAsync(new BlockPayload(block.WithOptions(node.SupportedTransactionOptions))).ConfigureAwait(false); } }
private async void AttachedNode_MessageReceivedAsync(Node node, IncomingMessage message) { try { if (message.Message.Payload is InvPayload invPayload) { var payload = new GetDataPayload(); foreach (var inv in invPayload.Inventory) { if (inv.Type.HasFlag(InventoryType.MSG_TX)) { TransactionInv?.Invoke(this, inv.Hash); payload.Inventory.Add(inv); } else if (inv.Type.HasFlag(InventoryType.MSG_BLOCK)) { BlockInv?.Invoke(this, inv.Hash); payload.Inventory.Add(inv); } } if (payload.Inventory.Any() && node.IsConnected) { // ask for the whole transaction await node.SendMessageAsync(payload); } } else if (message.Message.Payload is TxPayload txPayload) { Transaction?.Invoke(this, txPayload.Object); } else if (message.Message.Payload is BlockPayload blockPayload) { Block?.Invoke(this, blockPayload.Object); } } catch (OperationCanceledException ex) { Logger.LogDebug <TrustedNodeNotifyingBehavior>(ex); } catch (Exception ex) { Logger.LogInfo <TrustedNodeNotifyingBehavior>($"Ignoring {ex.GetType()}: {ex.Message}"); Logger.LogDebug <TrustedNodeNotifyingBehavior>(ex); } }
private GetDataPayload CreateGetDataPayload(IEnumerable <uint256> hashes) { var message = new GetDataPayload(); foreach (var hash in hashes) { if (!this.blockSyncHub.ChainIndex.Contains(hash)) { message.Inventory.Add(new InventoryVector() { Type = InventoryType.MSG_BLOCK, Hash = hash }); } } return(message); }
private async Task ProcessGetDataAsync(INetworkPeer peer, GetDataPayload getDataPayload) { this.logger.LogTrace("({0}:'{1}',{2}.{3}.{4}:{5})", nameof(peer), peer.RemoteSocketEndpoint, nameof(getDataPayload), nameof(getDataPayload.Inventory), nameof(getDataPayload.Inventory.Count), getDataPayload.Inventory.Count); // TODO: bring logic from core foreach (InventoryVector item in getDataPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_BLOCK))) { // TODO: check if we need to add support for "not found" Block block = await this.blockStoreCache.GetBlockAsync(item.Hash).ConfigureAwait(false); if (block != null) { this.logger.LogTrace("Sending block '{0}' to peer '{1}'.", item.Hash, peer.RemoteSocketEndpoint); //TODO strip block of witness if node does not support await peer.SendMessageAsync(new BlockPayload(block.WithOptions(this.chain.Network.Consensus.ConsensusFactory, peer.SupportedTransactionOptions))).ConfigureAwait(false); } // If the peer is syncing using "getblocks" message we are supposed to send // an "inv" message with our tip to it once it asks for all blocks // from the previous batch. if (item.Hash == this.getBlocksBatchLastItemHash) { // Reset the hash to indicate that no continuation is pending anymore. this.getBlocksBatchLastItemHash = null; // Announce last block we have in the store. ChainedHeader blockStoreTip = this.chain.GetBlock(this.blockRepository.BlockHash); if (blockStoreTip != null) { this.logger.LogTrace("Sending continuation inventory message for block '{0}' to peer '{1}'.", blockStoreTip, peer.RemoteSocketEndpoint); var invContinue = new InvPayload(); invContinue.Inventory.Add(new InventoryVector(InventoryType.MSG_BLOCK, blockStoreTip.HashBlock)); await peer.SendMessageAsync(invContinue).ConfigureAwait(false); } else { this.logger.LogTrace("Reorg in blockstore, inventory continuation won't be sent to peer '{0}'.", peer.RemoteSocketEndpoint); } } } this.logger.LogTrace("(-)"); }
private async Task ProcessInvAsync(Node node, InvPayload payload) { if (payload.Inventory.Count > MaxInvSize) { Logger.LogDebug($"Received inventory too big. {nameof(MaxInvSize)}: {MaxInvSize}, Node: {node.RemoteSocketEndpoint}"); return; } var getDataPayload = new GetDataPayload(); foreach (var inv in payload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX))) { if (MempoolService.TryGetFromBroadcastStore(inv.Hash, out TransactionBroadcastEntry entry)) // If we have the transaction then adjust confirmation. { try { if (entry.NodeRemoteSocketEndpoint == node.RemoteSocketEndpoint.ToString()) { continue; // Wtf, why are you trying to broadcast it back to us? } entry.ConfirmPropagationOnce(); } catch (Exception ex) { Logger.LogInfo(ex); } } // if we already processed it continue; if (MempoolService.IsProcessed(inv.Hash)) { continue; } getDataPayload.Inventory.Add(inv); } if (getDataPayload.Inventory.Any() && node.IsConnected) { // ask for the whole transaction await node.SendMessageAsync(getDataPayload).ConfigureAwait(false); } }
void StartScan(object unused) { var node = AttachedNode; if (_RunningPing != null) { _PlannedScan = true; return; } if (!IsScanning(node)) { if (Monitor.TryEnter(cs)) { try { if (!IsScanning(node)) { GetDataPayload payload = new GetDataPayload(); var fork = _Chain.FindFork(_CurrentProgress); foreach (var block in _Chain .EnumerateAfter(fork) .Where(b => b.Header.BlockTime + TimeSpan.FromHours(5.0) > _SkipBefore) //Take 5 more hours, block time might not be right .Partition(10000) .FirstOrDefault() ?? new List <ChainedBlock>()) { if (block.HashBlock != _LastSeen) { payload.Inventory.Add(new InventoryVector(InventoryType.MSG_FILTERED_BLOCK, block.HashBlock)); _InFlight.TryAdd(block.HashBlock, block.HashBlock); } } if (payload.Inventory.Count > 0) { node.SendMessageAsync(payload); } } } finally { Monitor.Exit(cs); } } } }
private void RespondToGetDataPayload(Node node, GetDataPayload getDataPayload) { this.blockSyncHub.GetDataItems.TryAdd(new HubGetDataItem { Behaviour = this, Payload = getDataPayload, Node = this.AttachedNode }); RequestCounter requestCounter; foreach (var vector in getDataPayload.Inventory) { if (this.blockSyncHub.RequestCount.TryGetValue(vector.Hash, out requestCounter)) { Interlocked.Increment(ref requestCounter.Count); } } }
protected void ProcessGetDataPayload(NetworkPeer node, GetDataPayload getDataPayload) { // if node asks for tx we want to broadcast foreach (var inv in getDataPayload.Inventory.Where(x => x.Type == InventoryType.MSG_TX)) { var txEntry = this.manager.GetTransaction(inv.Hash); if (txEntry != null) { if (txEntry.State != State.CantBroadcast) { node.SendMessage(new TxPayload(txEntry.Transaction)); if (txEntry.State == State.ToBroadcast) { this.manager.AddOrUpdate(txEntry.Transaction, State.Broadcasted); } } } } }
/// <summary> /// Processing of the get data payload message from the peer. /// Sends the memory pool transaction info via TxPayload to the attached peer. /// </summary> /// <param name="peer">Peer sending the message.</param> /// <param name="getDataPayload">The payload for the message.</param> private async Task ProcessGetDataAsync(INetworkPeer peer, GetDataPayload getDataPayload) { Guard.NotNull(peer, nameof(peer)); foreach (InventoryVector item in getDataPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX))) { // TODO: check if we need to add support for "not found" TxMempoolInfo trxInfo = await this.mempoolManager.InfoAsync(item.Hash).ConfigureAwait(false); if (trxInfo != null) { if (peer.IsConnected) { this.logger.LogDebug("Sending transaction '{0}' to peer '{1}'.", item.Hash, peer.RemoteSocketEndpoint); await peer.SendMessageAsync(new TxPayload(trxInfo.Trx.WithOptions(peer.SupportedTransactionOptions, this.network.Consensus.ConsensusFactory))).ConfigureAwait(false); } } } }