/// <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("(-)");
        }
Beispiel #3
0
        /// <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;
                }
            }
        }