/// <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(Node 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.AttachedNode) { this.logger.LogDebug("Attached node '{0}' does not match the originating node '{1}'.", this.AttachedNode?.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("(-)"); }
/// <summary> /// Sends transaction inventory to attached node. /// This is executed on a 10 second loop when MempoolSignaled is constructed. /// </summary> public async Task SendTrickleAsync() { this.logger.LogTrace("()"); if (!this.CanSend) { this.logger.LogTrace("(-)[NO_SEND]"); return; } // before locking an exclusive task // check if there is anything to processes if (!await this.manager.MempoolLock.ReadAsync(() => this.inventoryTxToSend.Keys.Any())) { this.logger.LogTrace("(-)[NO_TXS]"); return; } List <uint256> sends = await this.manager.MempoolLock.WriteAsync(() => { this.logger.LogTrace("Creating list of transaction inventory to send."); // Determine transactions to relay // Produce a vector with all candidates for sending List <uint256> invs = this.inventoryTxToSend.Keys.Take(InventoryBroadcastMax).ToList(); List <uint256> ret = new List <uint256>(); foreach (uint256 hash in invs) { // Remove it from the to-be-sent set this.inventoryTxToSend.Remove(hash); // Check if not in the filter already if (this.filterInventoryKnown.ContainsKey(hash)) { continue; } // Not in the mempool anymore? don't bother sending it. TxMempoolInfo txInfo = this.manager.Info(hash); if (txInfo == null) { continue; } //if (filterrate && txinfo.feeRate.GetFeePerK() < filterrate) // TODO:filterrate //{ // continue; //} ret.Add(hash); } this.logger.LogTrace("Transaction inventory list created."); return(ret); }); if (sends.Any()) { this.logger.LogTrace("Sending transaction inventory to peer '{0}'.", this.AttachedNode.RemoteSocketEndpoint); await this.SendAsTxInventoryAsync(this.AttachedNode, sends); } this.logger.LogTrace("(-)"); }
/// <inheritdoc /> public async Task <UnspentOutputs> GetUnspentTransactionAsync(uint256 trxid) { TxMempoolInfo txInfo = await this.InfoAsync(trxid); if (txInfo == null) { return(null); } var memPoolCoinView = new MempoolCoinView(this.coinView, this.memPool, this.MempoolLock, this.Validator); await memPoolCoinView.LoadViewAsync(txInfo.Trx); return(memPoolCoinView.GetCoins(trxid)); }
/// <inheritdoc /> public async Task <UnspentOutputs> GetUnspentTransactionAsync(uint256 trxid) { TxMempoolInfo txInfo = await this.InfoAsync(trxid); if (txInfo == null) { this.logger.LogTrace("(-):[TX_IS_NULL]"); return(null); } var memPoolCoinView = new MempoolCoinView(this.coinView, this.memPool, this.MempoolLock, this.Validator); await memPoolCoinView.LoadViewAsync(txInfo.Trx); UnspentOutputs unspentOutputs = memPoolCoinView.GetCoins(trxid); return(unspentOutputs); }
/// <inheritdoc /> public async Task <UnspentOutput> GetUnspentTransactionAsync(OutPoint outPoint) { TxMempoolInfo txInfo = this.Info(outPoint.Hash); if (txInfo == null) { this.logger.LogTrace("(-):[TX_IS_NULL]"); return(null); } var memPoolCoinView = new MempoolCoinView(this.network, this.coinView, this.memPool, this.MempoolLock, this.Validator); await this.MempoolLock.ReadAsync(() => { memPoolCoinView.LoadViewLocked(txInfo.Trx); }); UnspentOutput unspentOutput = memPoolCoinView.Set.AccessCoins(outPoint); return(unspentOutput); }
/// <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(Node node, GetDataPayload getDataPayload) { Guard.Assert(node == this.AttachedNode); // just in case 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) { await node.SendMessageAsync(new TxPayload(trxInfo.Trx.WithOptions(node.SupportedTransactionOptions))).ConfigureAwait(false); } } } }
/// <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) { // TODO: strip block of witness if peer does not support if (peer.IsConnected) { this.logger.LogTrace("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); } } } }
/// <summary> /// Sends transaction inventory to attached peer. /// This is executed on a 5 second loop when MempoolSignaled is constructed. /// </summary> public async Task SendTrickleAsync() { INetworkPeer peer = this.AttachedPeer; if (peer == null) { this.logger.LogTrace("(-)[NO_PEER]"); return; } var transactionsToSend = new List <uint256>(); lock (this.lockObject) { if (!this.inventoryTxToSend.Any()) { this.logger.LogTrace("(-)[NO_TXS]"); return; } this.logger.LogTrace("Creating list of transaction inventory to send."); // Determine transactions to relay // Produce a vector with all candidates for sending List <uint256> invs = this.inventoryTxToSend.Take(InventoryBroadcastMax).ToList(); foreach (uint256 hash in invs) { // Remove it from the to-be-sent set this.inventoryTxToSend.Remove(hash); this.logger.LogTrace("Transaction ID '{0}' removed from pending sends list.", hash); // Check if not in the filter already if (this.filterInventoryKnown.Contains(hash)) { this.logger.LogTrace("Transaction ID '{0}' not added to inventory list, exists in known inventory filter.", hash); continue; } //if (filterrate && txinfo.feeRate.GetFeePerK() < filterrate) // TODO:filterrate //{ // continue; //} transactionsToSend.Add(hash); this.logger.LogTrace("Transaction ID '{0}' added to inventory list.", hash); } this.logger.LogTrace("Transaction inventory list created."); } List <uint256> findInMempool = transactionsToSend.ToList(); foreach (uint256 hash in findInMempool) { // Not in the mempool anymore? don't bother sending it. TxMempoolInfo txInfo = await this.mempoolManager.InfoAsync(hash); if (txInfo == null) { this.logger.LogTrace("Transaction ID '{0}' not added to inventory list, no longer in mempool.", hash); transactionsToSend.Remove(hash); } } if (transactionsToSend.Any()) { this.logger.LogTrace("Sending transaction inventory to peer '{0}'.", peer.RemoteSocketEndpoint); try { await this.SendAsTxInventoryAsync(peer, transactionsToSend).ConfigureAwait(false); } catch (OperationCanceledException) { this.logger.LogTrace("(-)[CANCELED_EXCEPTION]"); return; } } }