| 938 | } |
| 939 | |
| 940 | MempoolAcceptResult |
| 941 | MemPoolAccept::AcceptSingleTransaction(const CTransactionRef &ptx, |
| 942 | ATMPArgs &args) { |
| 943 | AssertLockHeld(cs_main); |
| 944 | // mempool "read lock" (held through |
| 945 | // GetMainSignals().TransactionAddedToMempool()) |
| 946 | LOCK(m_pool.cs); |
| 947 | |
| 948 | const CBlockIndex *tip = m_active_chainstate.m_chain.Tip(); |
| 949 | |
| 950 | Workspace ws(ptx, |
| 951 | GetNextBlockScriptFlags(tip, m_active_chainstate.m_chainman)); |
| 952 | |
| 953 | const std::vector<TxId> single_txid{ws.m_ptx->GetId()}; |
| 954 | |
| 955 | // Perform the inexpensive checks first and avoid hashing and signature |
| 956 | // verification unless those checks pass, to mitigate CPU exhaustion |
| 957 | // denial-of-service attacks. |
| 958 | if (!PreChecks(args, ws)) { |
| 959 | if (ws.m_state.GetResult() == |
| 960 | TxValidationResult::TX_PACKAGE_RECONSIDERABLE) { |
| 961 | // Failed for fee reasons. Provide the effective feerate and which |
| 962 | // tx was included. |
| 963 | return MempoolAcceptResult::FeeFailure( |
| 964 | ws.m_state, CFeeRate(ws.m_modified_fees, ws.m_vsize), |
| 965 | single_txid); |
| 966 | } |
| 967 | return MempoolAcceptResult::Failure(ws.m_state); |
| 968 | } |
| 969 | |
| 970 | if (!ConsensusScriptChecks(args, ws)) { |
| 971 | return MempoolAcceptResult::Failure(ws.m_state); |
| 972 | } |
| 973 | |
| 974 | const TxId txid = ptx->GetId(); |
| 975 | |
| 976 | // Mempool sanity check -- in our new mempool no tx can be added if its |
| 977 | // outputs are already spent in the mempool (that is, no children before |
| 978 | // parents allowed; the mempool must be consistent at all times). |
| 979 | // |
| 980 | // This means that on reorg, the disconnectpool *must* always import |
| 981 | // the existing mempool tx's, clear the mempool, and then re-add |
| 982 | // remaining tx's in topological order via this function. Our new mempool |
| 983 | // has fast adds, so this is ok. |
| 984 | if (auto it = m_pool.mapNextTx.lower_bound(COutPoint{txid, 0}); |
| 985 | it != m_pool.mapNextTx.end() && it->first->GetTxId() == txid) { |
| 986 | LogPrintf("%s: BUG! PLEASE REPORT THIS! Attempt to add txid %s, but " |
| 987 | "its outputs are already spent in the " |
| 988 | "mempool\n", |
| 989 | __func__, txid.ToString()); |
| 990 | ws.m_state.Invalid(TxValidationResult::TX_CHILD_BEFORE_PARENT, |
| 991 | "txn-child-before-parent"); |
| 992 | return MempoolAcceptResult::Failure(ws.m_state); |
| 993 | } |
| 994 | |
| 995 | const CFeeRate effective_feerate{ws.m_modified_fees, |
| 996 | static_cast<uint32_t>(ws.m_vsize)}; |
| 997 | // Tx was accepted, but not added |
no test coverage detected