Exemple #1
0
        /// <summary>
        /// Calculates the priority of a transaction based upon transaction size and priority inputs.
        /// </summary>
        /// <param name="trx">Memory pool transaction.</param>
        /// <param name="dPriorityInputs">Priority weighting of inputs.</param>
        /// <param name="nTxSize">Transaction size, 0 will compute.</param>
        /// <returns>Priority value.</returns>
        private double ComputePriority(Transaction trx, double dPriorityInputs, int nTxSize = 0)
        {
            nTxSize = MempoolValidator.CalculateModifiedSize(this.network.Consensus.ConsensusFactory, nTxSize, trx, this.mempoolValidator.ConsensusOptions);
            if (nTxSize == 0)
            {
                return(0.0);
            }

            return(dPriorityInputs / nTxSize);
        }
        /// <summary>
        /// Add an orphan transaction to the orphan pool.
        /// </summary>
        /// <param name="nodeId">Node id of the source node.</param>
        /// <param name="tx">The transaction to add.</param>
        /// <returns>Whether the orphan transaction was added.</returns>
        public bool AddOrphanTx(ulong nodeId, Transaction tx)
        {
            lock (this.lockObject)
            {
                uint256 hash = tx.GetHash();
                if (this.mapOrphanTransactions.ContainsKey(hash))
                {
                    this.logger.LogTrace("(-)[DUP_ORPH]:false");
                    return(false);
                }

                // Ignore big transactions, to avoid a
                // send-big-orphans memory exhaustion attack. If a peer has a legitimate
                // large transaction with a missing parent then we assume
                // it will rebroadcast it later, after the parent transaction(s)
                // have been mined or received.
                // 100 orphans, each of which is at most 99,999 bytes big is
                // at most 10 megabytes of orphans and somewhat more byprev index (in the worst case):
                int sz = MempoolValidator.GetTransactionWeight(tx, this.chainIndexer.Network.Consensus.ConsensusFactory, this.Validator.ConsensusOptions);
                if (sz >= this.chainIndexer.Network.Consensus.Options.MaxStandardTxWeight)
                {
                    this.logger.LogDebug("ignoring large orphan tx (size: {0}, hash: {1})", sz, hash);
                    this.logger.LogTrace("(-)[LARGE_ORPH]:false");
                    return(false);
                }

                var orphan = new OrphanTx
                {
                    Tx         = tx,
                    NodeId     = nodeId,
                    TimeExpire = this.dateTimeProvider.GetTime() + OrphanTxExpireTime
                };

                if (this.mapOrphanTransactions.TryAdd(hash, orphan))
                {
                    foreach (TxIn txin in tx.Inputs)
                    {
                        List <OrphanTx> prv = this.mapOrphanTransactionsByPrev.TryGet(txin.PrevOut);
                        if (prv == null)
                        {
                            prv = new List <OrphanTx>();
                            this.mapOrphanTransactionsByPrev.Add(txin.PrevOut, prv);
                        }
                        prv.Add(orphan);
                    }
                }

                int orphanSize = this.mapOrphanTransactions.Count;
                this.logger.LogDebug("stored orphan tx {0} (mapsz {1} outsz {2})", hash, orphanSize, this.mapOrphanTransactionsByPrev.Count);
                this.Validator.PerformanceCounter.SetMempoolOrphanSize(orphanSize);
            }

            return(true);
        }
        /// <summary>
        /// Constructs a transaction memory pool entry.
        /// </summary>
        /// <param name="transaction">Transaction for the entry.</param>
        /// <param name="nFee">Fee for the transaction in the entry in the memory pool.</param>
        /// <param name="nTime">The local time when entering the memory pool.</param>
        /// <param name="entryPriority">Priority when entering the memory pool.</param>
        /// <param name="entryHeight">The chain height when entering the mempool.</param>
        /// <param name="inChainInputValue">The sum of all txin values that are already in blockchain.</param>
        /// <param name="spendsCoinbase">Whether the transaction spends a coinbase.</param>
        /// <param name="nSigOpsCost">The total signature operations cost.</param>
        /// <param name="lp">Tthe lock points that track the height and time at which tx was final.</param>
        /// <param name="consensusOptions">Proof of work consensus options used to compute transaction weight and modified size.</param>
        public TxMempoolEntry(Transaction transaction, Money nFee,
                              long nTime, double entryPriority, int entryHeight,
                              Money inChainInputValue, bool spendsCoinbase,
                              long nSigOpsCost, LockPoints lp, ConsensusOptions consensusOptions,
                              ConsensusFactory consensusFactory)
        {
            this.Transaction       = transaction;
            this.TransactionHash   = transaction.GetHash();
            this.Fee               = nFee;
            this.Time              = nTime;
            this.entryPriority     = entryPriority;
            this.EntryHeight       = entryHeight;
            this.InChainInputValue = inChainInputValue;
            this.SpendsCoinbase    = spendsCoinbase;
            this.SigOpCost         = nSigOpsCost;
            this.LockPoints        = lp;
            this.consensusOptions  = consensusOptions;
            this.consensusFactory  = consensusFactory;

            this.TxWeight = MempoolValidator.GetTransactionWeight(transaction, consensusFactory, consensusOptions);
            this.nModSize = MempoolValidator.CalculateModifiedSize(consensusFactory, this.Transaction.GetSerializedSize(), this.Transaction, consensusOptions);

            this.nUsageSize = transaction.GetSerializedSize(); // RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(Transaction);

            this.CountWithDescendants   = 1;
            this.SizeWithDescendants    = this.GetTxSize();
            this.ModFeesWithDescendants = this.Fee;
            Money nValueIn = transaction.TotalOut + this.Fee;

            Guard.Assert(this.InChainInputValue <= nValueIn);

            this.feeDelta = 0;

            this.CountWithAncestors     = 1;
            this.SizeWithAncestors      = this.GetTxSize();
            this.ModFeesWithAncestors   = this.Fee;
            this.SigOpCostWithAncestors = this.SigOpCost;
        }