aboutsummaryrefslogtreecommitdiff
path: root/src/validation.cpp
diff options
context:
space:
mode:
authorMarcoFalke <falke.marco@gmail.com>2021-02-11 14:43:10 +0100
committerMarcoFalke <falke.marco@gmail.com>2021-02-11 14:45:41 +0100
commit8e1913ae025ad8912457abe24ae5c61da02fc17a (patch)
tree9485ad3bd0f4eea1fd583d7b319d6c80b69851aa /src/validation.cpp
parenta1be08405d9bbf771a965dc170ce85ea1ad034c7 (diff)
parent53e716ea119658c28935fee24eb50090907c500e (diff)
Merge #21062: refactor: return MempoolAcceptResult from ATMP
53e716ea119658c28935fee24eb50090907c500e [refactor] improve style for touched code (gzhao408) 174cb5330af4b09f3a66974d3bae783ea43b190e [refactor] const ATMPArgs and non-const Workspace (gzhao408) f82baf0762f60c2ca5ffc339b095f9271d7c2f33 [refactor] return MempoolAcceptResult (gzhao408) 9db10a55061e09021ff8ea1d6637d99f7959035f [refactor] clean up logic in testmempoolaccept (gzhao408) Pull request description: This is the first 4 commits of #20833, and does refactoring only. It should be relatively simple to review, and offers a few nice things: - It makes accessing values that don't make sense (e.g. fee) when the tx is invalid an error. - Returning `MempoolAcceptResult` from ATMP makes the interface cleaner. The caller can get a const instead of passing in a mutable "out" param. - We don't have to be iterating through a bunch of lists for package validation, we can just return a `std::vector<MempoolAcceptResult>`. - We don't have to refactor all ATMP call sites again if/when we want to return more stuff from it. ACKs for top commit: MarcoFalke: ACK 53e716ea119658c28935fee24eb50090907c500e 💿 jnewbery: Code review ACK 53e716ea119658c28935fee24eb50090907c500e ariard: Code Review ACK 53e716e, I did tweak a bit the touched paths to see if we had good test coverage. Didn't find holes. Tree-SHA512: fa6ec324a08ad9e6e55948615cda324cba176255708bf0a0a0f37cedb7a75311aa334ac6f223be7d8df3c7379502b1081102b9589f9a9afa1713ad3d9ab3c24f
Diffstat (limited to 'src/validation.cpp')
-rw-r--r--src/validation.cpp97
1 files changed, 42 insertions, 55 deletions
diff --git a/src/validation.cpp b/src/validation.cpp
index 8f7d36bfd3..9938b62640 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -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);
@@ -463,9 +461,7 @@ public:
// around easier.
struct ATMPArgs {
const CChainParams& m_chainparams;
- TxValidationState &m_state;
const int64_t m_accept_time;
- std::list<CTransactionRef>* m_replaced_transactions;
const bool m_bypass_limits;
/*
* Return any outpoints which were not previously present in the coins
@@ -476,11 +472,10 @@ public:
*/
std::vector<COutPoint>& m_coins_to_uncache;
const bool m_test_accept;
- 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
@@ -491,14 +486,17 @@ private:
CTxMemPool::setEntries m_all_conflicting;
CTxMemPool::setEntries m_ancestors;
std::unique_ptr<CTxMemPoolEntry> m_entry;
+ std::list<CTransactionRef> m_replaced_transactions;
bool m_replacement_transaction;
+ CAmount m_base_fees;
CAmount m_modified_fees;
CAmount m_conflicting_fees;
size_t m_conflicting_size;
const CTransactionRef& m_ptx;
const uint256& m_hash;
+ TxValidationState m_state;
};
// Run the policy checks on a given transaction, excluding any script checks.
@@ -509,18 +507,18 @@ private:
// Run the script checks using our policy flags. As this can be slow, we should
// only invoke this on transactions that have otherwise passed policy checks.
- bool PolicyScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
+ bool PolicyScriptChecks(const ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Re-run the script checks, using consensus flags, and try to cache the
// result in the scriptcache. This should be done after
// PolicyScriptChecks(). This requires that all inputs either be in our
// utxo set or in the mempool.
- bool ConsensusScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData &txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
+ bool ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws, PrecomputedTransactionData &txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Try to add the transaction to the mempool, removing any conflicts first.
// Returns true if the transaction is in the mempool after any size
// limiting is performed, false otherwise.
- bool Finalize(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
+ bool Finalize(const ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Compare a package's feerate against minimum allowed.
bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs)
@@ -558,12 +556,12 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
const uint256& hash = ws.m_hash;
// Copy/alias what we need out of args
- TxValidationState &state = args.m_state;
const int64_t nAcceptTime = args.m_accept_time;
const bool bypass_limits = args.m_bypass_limits;
std::vector<COutPoint>& coins_to_uncache = args.m_coins_to_uncache;
// Alias what we need out of ws
+ TxValidationState& state = ws.m_state;
std::set<uint256>& setConflicts = ws.m_conflicts;
CTxMemPool::setEntries& allConflicting = ws.m_all_conflicting;
CTxMemPool::setEntries& setAncestors = ws.m_ancestors;
@@ -683,16 +681,10 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
if (!CheckSequenceLocks(m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-BIP68-final");
- CAmount nFees = 0;
- if (!Consensus::CheckTxInputs(tx, state, m_view, g_chainman.m_blockman.GetSpendHeight(m_view), nFees)) {
+ if (!Consensus::CheckTxInputs(tx, state, m_view, g_chainman.m_blockman.GetSpendHeight(m_view), ws.m_base_fees)) {
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;
- }
-
// Check for non-standard pay-to-script-hash in inputs
const auto& params = args.m_chainparams.GetConsensus();
auto taproot_state = VersionBitsState(::ChainActive().Tip(), params, Consensus::DEPLOYMENT_TAPROOT, versionbitscache);
@@ -707,7 +699,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
int64_t nSigOpsCost = GetTransactionSigOpCost(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS);
// nModifiedFees includes any fee deltas from PrioritiseTransaction
- nModifiedFees = nFees;
+ nModifiedFees = ws.m_base_fees;
m_pool.ApplyDelta(hash, nModifiedFees);
// Keep track of transactions that spend a coinbase, which we re-scan
@@ -721,7 +713,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
}
}
- entry.reset(new CTxMemPoolEntry(ptx, nFees, nAcceptTime, ::ChainActive().Height(),
+ entry.reset(new CTxMemPoolEntry(ptx, ws.m_base_fees, nAcceptTime, ::ChainActive().Height(),
fSpendsCoinbase, nSigOpsCost, lp));
unsigned int nSize = entry->GetTxSize();
@@ -925,11 +917,10 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return true;
}
-bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata)
+bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata)
{
const CTransaction& tx = *ws.m_ptx;
-
- TxValidationState &state = args.m_state;
+ TxValidationState& state = ws.m_state;
constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
@@ -952,12 +943,11 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, const Workspace& ws, Prec
return true;
}
-bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata)
+bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata)
{
const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash;
-
- TxValidationState &state = args.m_state;
+ TxValidationState& state = ws.m_state;
const CChainParams& chainparams = args.m_chainparams;
// Check again against the current block tip's script verification
@@ -984,11 +974,11 @@ bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, const Workspace& ws, P
return true;
}
-bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws)
+bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
{
const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash;
- TxValidationState &state = args.m_state;
+ TxValidationState& state = ws.m_state;
const bool bypass_limits = args.m_bypass_limits;
CTxMemPool::setEntries& allConflicting = ws.m_all_conflicting;
@@ -1007,8 +997,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());
+ ws.m_replaced_transactions.push_back(it->GetSharedTx());
}
m_pool.RemoveStaged(allConflicting, false, MemPoolRemovalReason::REPLACED);
@@ -1031,14 +1020,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);
+ Workspace ws(ptx);
- if (!PreChecks(args, workspace)) return false;
+ if (!PreChecks(args, ws)) return MempoolAcceptResult(ws.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 +1035,35 @@ 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, ws, txdata)) return MempoolAcceptResult(ws.m_state);
- if (!ConsensusScriptChecks(args, workspace, txdata)) return false;
+ if (!ConsensusScriptChecks(args, ws, txdata)) return MempoolAcceptResult(ws.m_state);
// Tx was accepted, but not added
- if (args.m_test_accept) return true;
+ if (args.m_test_accept) {
+ return MempoolAcceptResult(std::move(ws.m_replaced_transactions), ws.m_base_fees);
+ }
- if (!Finalize(args, workspace)) return false;
+ if (!Finalize(args, ws)) return MempoolAcceptResult(ws.m_state);
GetMainSignals().TransactionAddedToMempool(ptx, m_pool.GetAndIncrementSequence());
- return true;
+ return MempoolAcceptResult(std::move(ws.m_replaced_transactions), ws.m_base_fees);
}
} // 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)
{
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, 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 +1075,12 @@ 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(Params(), 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 +5019,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