/// <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, PowConsensusOptions consensusOptions) { 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.TxWeight = MempoolValidator.GetTransactionWeight(transaction, consensusOptions); this.nModSize = MempoolValidator.CalculateModifiedSize(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; }
/// <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 Task <bool> AddOrphanTx(ulong nodeId, Transaction tx) { return(this.MempoolLock.WriteAsync(() => { uint256 hash = tx.GetHash(); if (this.mapOrphanTransactions.ContainsKey(hash)) { 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.Validator.ConsensusOptions); if (sz >= this.consensusValidator.ConsensusOptions.MaxStandardTxWeight) { this.mempoolLogger.LogInformation($"ignoring large orphan tx (size: {sz}, hash: {hash})"); return false; } var orphan = new OrphanTx { Tx = tx, NodeId = nodeId, TimeExpire = this.dateTimeProvider.GetTime() + OrphanTxExpireTime }; if (this.mapOrphanTransactions.TryAdd(hash, orphan)) { foreach (var 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.mempoolLogger.LogInformation($"stored orphan tx {hash} (mapsz {orphanSize} outsz {this.mapOrphanTransactionsByPrev.Count})"); this.Validator.PerformanceCounter.SetMempoolOrphanSize(orphanSize); return true; })); }