/// <summary> /// Erase an specific transaction from orphan pool. /// </summary> /// <param name="hash">hash of the transaction.</param> /// <returns>Whether erased.</returns> private bool EraseOrphanTxLock(uint256 hash) { OrphanTx orphTx = this.mapOrphanTransactions.TryGet(hash); if (orphTx == null) { this.logger.LogTrace("(-)[NOTFOUND_ORPH]:false"); return(false); } foreach (TxIn txin in orphTx.Tx.Inputs) { List <OrphanTx> prevOrphTxList = this.mapOrphanTransactionsByPrev.TryGet(txin.PrevOut); if (prevOrphTxList == null) { continue; } prevOrphTxList.Remove(orphTx); if (!prevOrphTxList.Any()) { this.mapOrphanTransactionsByPrev.Remove(txin.PrevOut); } } this.mapOrphanTransactions.Remove(hash); int orphanSize = this.mapOrphanTransactions.Count; this.Validator.PerformanceCounter.SetMempoolOrphanSize(orphanSize); return(true); }
/// <summary> /// Erase an specific transaction from orphan pool. /// </summary> /// <param name="hash">hash of the transaction.</param> /// <returns>Whether erased.</returns> private Task <bool> EraseOrphanTx(uint256 hash) { return(this.MempoolLock.WriteAsync(() => { OrphanTx it = this.mapOrphanTransactions.TryGet(hash); if (it == null) { return false; } foreach (TxIn txin in it.Tx.Inputs) { List <OrphanTx> itPrev = this.mapOrphanTransactionsByPrev.TryGet(txin.PrevOut); if (itPrev == null) { continue; } itPrev.Remove(it); if (!itPrev.Any()) { this.mapOrphanTransactionsByPrev.Remove(txin.PrevOut); } } this.mapOrphanTransactions.Remove(hash); return true; })); }
/// <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) { this.logger.LogTrace("({0}:{1},{2}:'{3}')", nameof(nodeId), nodeId, nameof(tx), tx.GetHash()); 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.Validator.ConsensusOptions); if (sz >= this.chain.Network.Consensus.Option <PowConsensusOptions>().MaxStandardTxWeight) { this.logger.LogInformation("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.LogInformation("stored orphan tx {0} (mapsz {1} outsz {2})", hash, orphanSize, this.mapOrphanTransactionsByPrev.Count); this.Validator.PerformanceCounter.SetMempoolOrphanSize(orphanSize); } this.logger.LogTrace("(-):true"); return(true); }
public Task <bool> AddOrphanTx(ulong nodeId, Transaction tx) { return(this.MempoolScheduler.WriteAsync(() => { var 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): var sz = MempoolValidator.GetTransactionWeight(tx, this.Validator.ConsensusOptions); if (sz >= this.consensusValidator.ConsensusOptions.MAX_STANDARD_TX_WEIGHT) { Logging.Logs.Mempool.LogInformation($"ignoring large orphan tx (size: {sz}, hash: {hash})"); return false; } var orphan = new OrphanTx { Tx = tx, NodeId = nodeId, TimeExpire = this.dateTimeProvider.GetTime() + ORPHAN_TX_EXPIRE_TIME }; if (this.mapOrphanTransactions.TryAdd(hash, orphan)) { foreach (var txin in tx.Inputs) { var prv = this.mapOrphanTransactionsByPrev.TryGet(txin.PrevOut); if (prv == null) { prv = new List <OrphanTx>(); this.mapOrphanTransactionsByPrev.Add(txin.PrevOut, prv); } prv.Add(orphan); } } var orphanSize = this.mapOrphanTransactions.Count; Logging.Logs.Mempool.LogInformation( $"stored orphan tx {hash} (mapsz {orphanSize} outsz {this.mapOrphanTransactionsByPrev.Count})"); this.Validator.PerformanceCounter.SetMempoolOrphanSize(orphanSize); return true; })); }