/// <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; }