/// <summary>
 /// Creates a persistence entry from a memory pool transaction entry.
 /// </summary>
 /// <param name="tx">Memory pool transaction entry.</param>
 /// <returns>Persistence entry.</returns>
 public static MempoolPersistenceEntry FromTxMempoolEntry(TxMempoolEntry tx)
 {
     return(new MempoolPersistenceEntry
     {
         Tx = tx.Transaction,
         Time = tx.Time,
         FeeDelta = tx.feeDelta
     });
 }
        /** Sever link between specified transaction and direct children. */
        private void UpdateChildrenForRemoval(TxMempoolEntry it)
        {
            var setMemPoolChildren = this.GetMemPoolChildren(it);

            foreach (var updateIt in setMemPoolChildren)
            {
                this.UpdateParent(updateIt, it, false);
            }
        }
        private SetEntries GetMemPoolChildren(TxMempoolEntry entry)
        {
            Guard.NotNull(entry, nameof(entry));

            Utilities.Guard.Assert(this.MapTx.ContainsKey(entry.TransactionHash));
            var it = this.mapLinks.TryGet(entry);

            Utilities.Guard.Assert(it != null);
            return(it.Children);
        }
        // addUnchecked must updated state for all ancestors of a given transaction,
        // to track size/count of descendant transactions.  First version of
        // addUnchecked can be used to have it call CalculateMemPoolAncestors(), and
        // then invoke the second version.
        public bool AddUnchecked(uint256 hash, TxMempoolEntry entry, bool validFeeEstimate = true)
        {
            //LOCK(cs);
            SetEntries setAncestors = new SetEntries();
            long       nNoLimit     = long.MaxValue;
            string     dummy;

            this.CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, out dummy);
            return(this.AddUnchecked(hash, entry, setAncestors, validFeeEstimate));
        }
        /// <summary>
        /// Gets transaction information for a specific transaction.
        /// </summary>
        /// <param name="hash">Hash of the transaction to query.</param>
        /// <returns>Transaction information.</returns>
        public TxMempoolInfo Info(uint256 hash)
        {
            TxMempoolEntry item = this.memPool.MapTx.TryGet(hash);

            return(item == null ? null : new TxMempoolInfo
            {
                Trx = item.Transaction,
                Time = item.Time,
                FeeRate = new FeeRate(item.Fee, (int)item.GetTxSize()),
                FeeDelta = item.ModifiedFee - item.Fee
            });
        }
 private void UpdateParent(TxMempoolEntry entry, TxMempoolEntry parent, bool add)
 {
     // todo: find how to take a memory size of SetEntries
     //SetEntries s;
     if (add && this.mapLinks[entry].Parents.Add(parent))
     {
         this.cachedInnerUsage += parent.DynamicMemoryUsage();
     }
     else if (!add && this.mapLinks[entry].Parents.Remove(parent))
     {
         this.cachedInnerUsage -= parent.DynamicMemoryUsage();
     }
 }
 private void UpdateChild(TxMempoolEntry entry, TxMempoolEntry child, bool add)
 {
     // todo: find how to take a memory size of SetEntries
     //setEntries s;
     if (add && this.mapLinks[entry].Children.Add(child))
     {
         this.cachedInnerUsage += child.DynamicMemoryUsage();
     }
     else if (!add && this.mapLinks[entry].Children.Remove(child))
     {
         this.cachedInnerUsage -= child.DynamicMemoryUsage();
     }
 }
        /** Set ancestor state for an entry */

        void UpdateEntryForAncestors(TxMempoolEntry it, SetEntries setAncestors)
        {
            long  updateCount      = setAncestors.Count;
            long  updateSize       = 0;
            Money updateFee        = 0;
            long  updateSigOpsCost = 0;

            foreach (var ancestorIt in setAncestors)
            {
                updateSize       += ancestorIt.GetTxSize();
                updateFee        += ancestorIt.ModifiedFee;
                updateSigOpsCost += ancestorIt.SigOpCost;
            }
            it.UpdateAncestorState(updateSize, updateFee, updateCount, updateSigOpsCost);
        }
示例#9
0
        /// <summary>
        /// Gets transaction information for a specific transaction.
        /// </summary>
        /// <param name="hash">Hash of the transaction to query.</param>
        /// <returns>Transaction information.</returns>
        public TxMempoolInfo Info(uint256 hash)
        {
            this.logger.LogTrace("({0}:'{1}')", nameof(hash), hash);

            TxMempoolEntry item     = this.memPool.MapTx.TryGet(hash);
            var            infoItem = item == null ? null : new TxMempoolInfo
            {
                Trx      = item.Transaction,
                Time     = item.Time,
                FeeRate  = new FeeRate(item.Fee, (int)item.GetTxSize()),
                FeeDelta = item.ModifiedFee - item.Fee
            };

            this.logger.LogTrace("(-):{0}.{1}='{2}'", nameof(TxMempoolInfo), nameof(TxMempoolInfo.Trx), infoItem?.Trx?.GetHash());
            return(infoItem);
        }
        /** Update ancestors of hash to add/remove it as a descendant transaction. */
        private void UpdateAncestorsOf(bool add, TxMempoolEntry it, SetEntries setAncestors)
        {
            SetEntries parentIters = this.GetMemPoolParents(it);

            // add or remove this tx as a child of each parent
            foreach (var piter in parentIters)
            {
                this.UpdateChild(piter, it, add);
            }

            long  updateCount = (add ? 1 : -1);
            long  updateSize  = updateCount * it.GetTxSize();
            Money updateFee   = updateCount * it.ModifiedFee;

            foreach (var ancestorIt in setAncestors)
            {
                ancestorIt.UpdateDescendantState(updateSize, updateFee, updateCount);
            }
        }
 /// <summary>
 /// Copy constructor for a transaction memory pool entry.
 /// </summary>
 /// <param name="other">Entry to copy.</param>
 /// <exception cref="NotImplementedException"/>
 public TxMempoolEntry(TxMempoolEntry other)
 {
     throw new NotImplementedException();
 }
        /** Try to calculate all in-mempool ancestors of entry.
         *  (these are all calculated including the tx itself)
         *  limitAncestorCount = max number of ancestorsUpdateTransactionsFromBlock
         *  limitAncestorSize = max size of ancestors
         *  limitDescendantCount = max number of descendants any ancestor can have
         *  limitDescendantSize = max size of descendants any ancestor can have
         *  errString = populated with error reason if any limits are hit
         *  fSearchForParents = whether to search a tx's vin for in-mempool parents, or
         *    look up parents from mapLinks. Must be true for entries not in the mempool
         */
        public bool CalculateMemPoolAncestors(TxMempoolEntry entry, SetEntries setAncestors, long limitAncestorCount,
                                              long limitAncestorSize, long limitDescendantCount, long limitDescendantSize, out string errString,
                                              bool fSearchForParents = true)
        {
            errString = string.Empty;
            SetEntries parentHashes = new SetEntries();
            var        tx           = entry.Transaction;

            if (fSearchForParents)
            {
                // Get parents of this transaction that are in the mempool
                // GetMemPoolParents() is only valid for entries in the mempool, so we
                // iterate mapTx to find parents.
                foreach (var txInput in tx.Inputs)
                {
                    var piter = this.MapTx.TryGet(txInput.PrevOut.Hash);
                    if (piter != null)
                    {
                        parentHashes.Add(piter);
                        if (parentHashes.Count + 1 > limitAncestorCount)
                        {
                            errString = $"too many unconfirmed parents [limit: {limitAncestorCount}]";
                            return(false);
                        }
                    }
                }
            }
            else
            {
                // If we're not searching for parents, we require this to be an
                // entry in the mempool already.
                //var it = mapTx.Txids.TryGet(entry.TransactionHash);
                var memPoolParents = this.GetMemPoolParents(entry);
                foreach (var item in memPoolParents)
                {
                    parentHashes.Add(item);
                }
            }

            var totalSizeWithAncestors = entry.GetTxSize();

            while (parentHashes.Any())
            {
                var stageit = parentHashes.First();

                setAncestors.Add(stageit);
                parentHashes.Remove(stageit);
                totalSizeWithAncestors += stageit.GetTxSize();

                if (stageit.SizeWithDescendants + entry.GetTxSize() > limitDescendantSize)
                {
                    errString = $"exceeds descendant size limit for tx {stageit.TransactionHash} [limit: {limitDescendantSize}]";
                    return(false);
                }
                else if (stageit.CountWithDescendants + 1 > limitDescendantCount)
                {
                    errString = $"too many descendants for tx {stageit.TransactionHash} [limit: {limitDescendantCount}]";
                    return(false);
                }
                else if (totalSizeWithAncestors > limitAncestorSize)
                {
                    errString = $"exceeds ancestor size limit [limit: {limitAncestorSize}]";
                    return(false);
                }

                var setMemPoolParents = this.GetMemPoolParents(stageit);
                foreach (var phash in setMemPoolParents)
                {
                    // If this is a new ancestor, add it.
                    if (!setAncestors.Contains(phash))
                    {
                        parentHashes.Add(phash);
                    }
                    if (parentHashes.Count + setAncestors.Count + 1 > limitAncestorCount)
                    {
                        errString = $"too many unconfirmed ancestors [limit: {limitAncestorCount}]";
                        return(false);
                    }
                }
            }

            return(true);
        }
        public bool AddUnchecked(uint256 hash, TxMempoolEntry entry, SetEntries setAncestors, bool validFeeEstimate = true)
        {
            // Add to memory pool without checking anything.
            // Used by main.cpp AcceptToMemoryPool(), which DOES do
            // all the appropriate checks.
            //LOCK(cs);
            this.MapTx.Add(entry);
            this.mapLinks.Add(entry, new TxLinks {
                Parents = new SetEntries(), Children = new SetEntries()
            });

            // Update transaction for any feeDelta created by PrioritiseTransaction
            // TODO: refactor so that the fee delta is calculated before inserting
            // into mapTx.
            var pos = this.mapDeltas.TryGet(hash);

            if (pos != null)
            {
                if (pos.Amount != null)
                {
                    entry.UpdateFeeDelta(pos.Amount.Satoshi);
                }
            }

            // Update cachedInnerUsage to include contained transaction's usage.
            // (When we update the entry for in-mempool parents, memory usage will be
            // further updated.)
            this.cachedInnerUsage += entry.DynamicMemoryUsage();

            var tx = entry.Transaction;
            HashSet <uint256> setParentTransactions = new HashSet <uint256>();

            foreach (var txInput in tx.Inputs)
            {
                this.MapNextTx.Add(new NextTxPair {
                    OutPoint = txInput.PrevOut, Transaction = tx
                });
                setParentTransactions.Add(txInput.PrevOut.Hash);
            }
            // Don't bother worrying about child transactions of this one.
            // Normal case of a new transaction arriving is that there can't be any
            // children, because such children would be orphans.
            // An exception to that is if a transaction enters that used to be in a block.
            // In that case, our disconnect block logic will call UpdateTransactionsFromBlock
            // to clean up the mess we're leaving here.

            // Update ancestors with information about this tx
            foreach (var phash in setParentTransactions)
            {
                var pit = this.MapTx.TryGet(phash);
                if (pit != null)
                {
                    this.UpdateParent(entry, pit, true);
                }
            }

            this.UpdateAncestorsOf(true, entry, setAncestors);
            this.UpdateEntryForAncestors(entry, setAncestors);

            this.nTransactionsUpdated++;
            this.totalTxSize += entry.GetTxSize();

            this.MinerPolicyEstimator.ProcessTransaction(entry, validFeeEstimate);

            this.vTxHashes.Add(entry, tx.GetWitHash());
            //entry.vTxHashesIdx = vTxHashes.size() - 1;

            return(true);
        }