mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-20 07:09:15 +01:00
[refactor] return MempoolAcceptResult
This creates a cleaner interface with ATMP, allows us to make results const, and makes accessing values that don't make sense (e.g. fee when tx is invalid) an error.
This commit is contained in:
@@ -380,10 +380,8 @@ static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransact
|
||||
auto it = disconnectpool.queuedTx.get<insertion_order>().rbegin();
|
||||
while (it != disconnectpool.queuedTx.get<insertion_order>().rend()) {
|
||||
// ignore validation errors in resurrected transactions
|
||||
TxValidationState stateDummy;
|
||||
if (!fAddToMempool || (*it)->IsCoinBase() ||
|
||||
!AcceptToMemoryPool(mempool, stateDummy, *it,
|
||||
nullptr /* plTxnReplaced */, true /* bypass_limits */)) {
|
||||
AcceptToMemoryPool(mempool, *it, true /* bypass_limits */).m_result_type != MempoolAcceptResult::ResultType::VALID) {
|
||||
// If the transaction doesn't make it in to the mempool, remove any
|
||||
// transactions that depend on it (which would now be orphans).
|
||||
mempool.removeRecursive(**it, MemPoolRemovalReason::REORG);
|
||||
@@ -465,7 +463,7 @@ public:
|
||||
const CChainParams& m_chainparams;
|
||||
TxValidationState &m_state;
|
||||
const int64_t m_accept_time;
|
||||
std::list<CTransactionRef>* m_replaced_transactions;
|
||||
std::list<CTransactionRef> m_replaced_transactions;
|
||||
const bool m_bypass_limits;
|
||||
/*
|
||||
* Return any outpoints which were not previously present in the coins
|
||||
@@ -476,11 +474,11 @@ public:
|
||||
*/
|
||||
std::vector<COutPoint>& m_coins_to_uncache;
|
||||
const bool m_test_accept;
|
||||
CAmount* m_fee_out;
|
||||
CAmount m_fee_out;
|
||||
};
|
||||
|
||||
// Single transaction acceptance
|
||||
bool AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs& args) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
MempoolAcceptResult AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs& args) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
private:
|
||||
// All the intermediate state that gets passed between the various levels
|
||||
@@ -688,10 +686,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
||||
return false; // state filled in by CheckTxInputs
|
||||
}
|
||||
|
||||
// If fee_out is passed, return the fee to the caller
|
||||
if (args.m_fee_out) {
|
||||
*args.m_fee_out = nFees;
|
||||
}
|
||||
args.m_fee_out = nFees;
|
||||
|
||||
// Check for non-standard pay-to-script-hash in inputs
|
||||
const auto& params = args.m_chainparams.GetConsensus();
|
||||
@@ -1007,8 +1002,7 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws)
|
||||
hash.ToString(),
|
||||
FormatMoney(nModifiedFees - nConflictingFees),
|
||||
(int)entry->GetTxSize() - (int)nConflictingSize);
|
||||
if (args.m_replaced_transactions)
|
||||
args.m_replaced_transactions->push_back(it->GetSharedTx());
|
||||
args.m_replaced_transactions.push_back(it->GetSharedTx());
|
||||
}
|
||||
m_pool.RemoveStaged(allConflicting, false, MemPoolRemovalReason::REPLACED);
|
||||
|
||||
@@ -1031,14 +1025,14 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs& args)
|
||||
MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs& args)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
LOCK(m_pool.cs); // mempool "read lock" (held through GetMainSignals().TransactionAddedToMempool())
|
||||
|
||||
Workspace workspace(ptx);
|
||||
|
||||
if (!PreChecks(args, workspace)) return false;
|
||||
if (!PreChecks(args, workspace)) return MempoolAcceptResult(args.m_state);
|
||||
|
||||
// Only compute the precomputed transaction data if we need to verify
|
||||
// scripts (ie, other policy checks pass). We perform the inexpensive
|
||||
@@ -1046,31 +1040,36 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs
|
||||
// checks pass, to mitigate CPU exhaustion denial-of-service attacks.
|
||||
PrecomputedTransactionData txdata;
|
||||
|
||||
if (!PolicyScriptChecks(args, workspace, txdata)) return false;
|
||||
if (!PolicyScriptChecks(args, workspace, txdata)) return MempoolAcceptResult(args.m_state);
|
||||
|
||||
if (!ConsensusScriptChecks(args, workspace, txdata)) return false;
|
||||
if (!ConsensusScriptChecks(args, workspace, txdata)) return MempoolAcceptResult(args.m_state);
|
||||
|
||||
// Tx was accepted, but not added
|
||||
if (args.m_test_accept) return true;
|
||||
if (args.m_test_accept) {
|
||||
return MempoolAcceptResult(std::move(args.m_replaced_transactions), args.m_fee_out);
|
||||
}
|
||||
|
||||
if (!Finalize(args, workspace)) return false;
|
||||
if (!Finalize(args, workspace)) return MempoolAcceptResult(args.m_state);
|
||||
|
||||
GetMainSignals().TransactionAddedToMempool(ptx, m_pool.GetAndIncrementSequence());
|
||||
|
||||
return true;
|
||||
return MempoolAcceptResult(std::move(args.m_replaced_transactions), args.m_fee_out);
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
/** (try to) add transaction to memory pool with a specified acceptance time **/
|
||||
static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
|
||||
int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
|
||||
bool bypass_limits, bool test_accept, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
static MempoolAcceptResult AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool,
|
||||
const CTransactionRef &tx, int64_t nAcceptTime,
|
||||
bool bypass_limits, bool test_accept)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
{
|
||||
TxValidationState state;
|
||||
std::vector<COutPoint> coins_to_uncache;
|
||||
MemPoolAccept::ATMPArgs args { chainparams, state, nAcceptTime, plTxnReplaced, bypass_limits, coins_to_uncache, test_accept, fee_out };
|
||||
bool res = MemPoolAccept(pool).AcceptSingleTransaction(tx, args);
|
||||
if (!res) {
|
||||
MemPoolAccept::ATMPArgs args { chainparams, state, nAcceptTime, {}, bypass_limits, coins_to_uncache, test_accept, {} };
|
||||
|
||||
const MempoolAcceptResult result = MemPoolAccept(pool).AcceptSingleTransaction(tx, args);
|
||||
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
|
||||
// Remove coins that were not present in the coins cache before calling ATMPW;
|
||||
// this is to prevent memory DoS in case we receive a large number of
|
||||
// invalid transactions that attempt to overrun the in-memory coins cache
|
||||
@@ -1082,15 +1081,13 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
|
||||
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
|
||||
BlockValidationState state_dummy;
|
||||
::ChainstateActive().FlushStateToDisk(chainparams, state_dummy, FlushStateMode::PERIODIC);
|
||||
return res;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
|
||||
std::list<CTransactionRef>* plTxnReplaced,
|
||||
bool bypass_limits, bool test_accept, CAmount* fee_out)
|
||||
MempoolAcceptResult AcceptToMemoryPool(CTxMemPool& pool, const CTransactionRef &tx, bool bypass_limits, bool test_accept)
|
||||
{
|
||||
const CChainParams& chainparams = Params();
|
||||
return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, GetTime(), plTxnReplaced, bypass_limits, test_accept, fee_out);
|
||||
return AcceptToMemoryPoolWithTime(chainparams, pool, tx, GetTime(), bypass_limits, test_accept);
|
||||
}
|
||||
|
||||
CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock)
|
||||
@@ -5029,13 +5026,10 @@ bool LoadMempool(CTxMemPool& pool)
|
||||
if (amountdelta) {
|
||||
pool.PrioritiseTransaction(tx->GetHash(), amountdelta);
|
||||
}
|
||||
TxValidationState state;
|
||||
if (nTime > nNow - nExpiryTimeout) {
|
||||
LOCK(cs_main);
|
||||
AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, nTime,
|
||||
nullptr /* plTxnReplaced */, false /* bypass_limits */,
|
||||
false /* test_accept */);
|
||||
if (state.IsValid()) {
|
||||
if (AcceptToMemoryPoolWithTime(chainparams, pool, tx, nTime, false /* bypass_limits */,
|
||||
false /* test_accept */).m_result_type == MempoolAcceptResult::ResultType::VALID) {
|
||||
++count;
|
||||
} else {
|
||||
// mempool may contain the transaction already, e.g. from
|
||||
|
||||
Reference in New Issue
Block a user