Пример #1
0
        /** For each transaction being removed, update ancestors and any direct children.
         * If updateDescendants is true, then also update in-mempool descendants'
         * ancestor state. */

        private void UpdateForRemoveFromMempool(SetEntries entriesToRemove, bool updateDescendants)
        {
            // For each entry, walk back all ancestors and decrement size associated with this
            // transaction
            var nNoLimit = long.MaxValue;

            if (updateDescendants)
            {
                // updateDescendants should be true whenever we're not recursively
                // removing a tx and all its descendants, eg when a transaction is
                // confirmed in a block.
                // Here we only update statistics and not data in mapLinks (which
                // we need to preserve until we're finished with all operations that
                // need to traverse the mempool).
                foreach (var removeIt in entriesToRemove)
                {
                    SetEntries setDescendants = new SetEntries();
                    CalculateDescendants(removeIt, setDescendants);
                    setDescendants.Remove(removeIt);                     // don't update state for self
                    var modifySize   = -removeIt.GetTxSize();
                    var modifyFee    = -removeIt.ModifiedFee;
                    var modifySigOps = -removeIt.SigOpCost;

                    foreach (var dit in setDescendants)
                    {
                        dit.UpdateAncestorState(modifySize, modifyFee, -1, modifySigOps);
                    }
                }
            }

            foreach (var entry in entriesToRemove)
            {
                SetEntries setAncestors = new SetEntries();
                string     dummy        = string.Empty;
                // Since this is a tx that is already in the mempool, we can call CMPA
                // with fSearchForParents = false.  If the mempool is in a consistent
                // state, then using true or false should both be correct, though false
                // should be a bit faster.
                // However, if we happen to be in the middle of processing a reorg, then
                // the mempool can be in an inconsistent state.  In this case, the set
                // of ancestors reachable via mapLinks will be the same as the set of
                // ancestors whose packages include this transaction, because when we
                // add a new transaction to the mempool in addUnchecked(), we assume it
                // has no children, and in the case of a reorg where that assumption is
                // false, the in-mempool children aren't linked to the in-block tx's
                // until UpdateTransactionsFromBlock() is called.
                // So if we're being called during a reorg, ie before
                // UpdateTransactionsFromBlock() has been called, then mapLinks[] will
                // differ from the set of mempool parents we'd calculate by searching,
                // and it's important that we use the mapLinks[] notion of ancestor
                // transactions as the set of things to update for removal.
                CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, out dummy, false);
                // Note that UpdateAncestorsOf severs the child links that point to
                // removeIt in the entries for the parents of removeIt.
                UpdateAncestorsOf(false, entry, setAncestors);
            }

            // After updating all the ancestor sizes, we can now sever the link between each
            // transaction being removed and any mempool children (ie, update setMemPoolParents
            // for each direct child of a transaction being removed).
            foreach (var removeIt in entriesToRemove)
            {
                UpdateChildrenForRemoval(removeIt);
            }
        }
Пример #2
0
        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)
                {
                    UpdateParent(entry, pit, true);
                }
            }

            UpdateAncestorsOf(true, entry, setAncestors);
            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);
        }
Пример #3
0
        /** 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 = 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 = 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);
        }
Пример #4
0
 public bool Equals(SetEntries other)
 {
     return(this.SequenceEqual(other, this));
 }