mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-12-07 11:12:50 +01:00
Merge bitcoin/bitcoin#22677: cut the validation <-> txmempool circular dependency 2/2
a64078e385Break validation <-> txmempool circular dependency (glozow)64e4963c63[mempool] always assert coin spent (glozow)bb9078ed51[refactor] put finality and maturity checking into a lambda (glozow)bedf246f1e[mempool] only update lockpoints for non-removed entries (glozow)1b3a11e126MOVEONLY: TestLockPointValidity to txmempool (glozow) Pull request description: Remove 2 circular dependencies: validation - txmempool and validation - policy/rbf - txmempool Validation should depend on txmempool (e.g. `CChainstateManager` has a mempool and we often need to know what's in our mempool to validate transactions), but txmempool is a data structure that shouldn't really need to know about chain state. - Changes `removeForReorg()` to be parameterized by a callable that returns true/false (i.e. whether the transaction should be removed due to being now immature or nonfinal) instead of a `CChainState`. The mempool really shouldn't need to know about coinbase maturity or lockpoints, it just needs to know which entries to remove. ACKs for top commit: laanwj: Code review ACKa64078e385mjdietzx: reACKa64078e385theStack: re-ACKa64078e385Tree-SHA512: f75995200569c09dfb8ddc09729da66ddb32167ff1e8a7e72f105ec062d2d6a9a390e6b4a2a115e7ad8ad3525f891ee1503f3cd2bed11773abcaf7c3230b1136
This commit is contained in:
@@ -212,24 +212,6 @@ bool CheckFinalTx(const CBlockIndex* active_chain_tip, const CTransaction &tx, i
|
||||
return IsFinalTx(tx, nBlockHeight, nBlockTime);
|
||||
}
|
||||
|
||||
bool TestLockPointValidity(CChain& active_chain, const LockPoints* lp)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
assert(lp);
|
||||
// If there are relative lock times then the maxInputBlock will be set
|
||||
// If there are no relative lock times, the LockPoints don't depend on the chain
|
||||
if (lp->maxInputBlock) {
|
||||
// Check whether active_chain is an extension of the block at which the LockPoints
|
||||
// calculation was valid. If not LockPoints are no longer valid
|
||||
if (!active_chain.Contains(lp->maxInputBlock)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// LockPoints still valid
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckSequenceLocks(CBlockIndex* tip,
|
||||
const CCoinsView& coins_view,
|
||||
const CTransaction& tx,
|
||||
@@ -368,8 +350,39 @@ void CChainState::MaybeUpdateMempoolForReorg(
|
||||
// the disconnectpool that were added back and cleans up the mempool state.
|
||||
m_mempool->UpdateTransactionsFromBlock(vHashUpdate);
|
||||
|
||||
const auto check_final_and_mature = [this, flags=STANDARD_LOCKTIME_VERIFY_FLAGS](CTxMemPool::txiter it)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(m_mempool->cs, ::cs_main) {
|
||||
bool should_remove = false;
|
||||
AssertLockHeld(m_mempool->cs);
|
||||
AssertLockHeld(::cs_main);
|
||||
const CTransaction& tx = it->GetTx();
|
||||
LockPoints lp = it->GetLockPoints();
|
||||
bool validLP = TestLockPointValidity(m_chain, &lp);
|
||||
CCoinsViewMemPool view_mempool(&CoinsTip(), *m_mempool);
|
||||
if (!CheckFinalTx(m_chain.Tip(), tx, flags)
|
||||
|| !CheckSequenceLocks(m_chain.Tip(), view_mempool, tx, flags, &lp, validLP)) {
|
||||
// Note if CheckSequenceLocks fails the LockPoints may still be invalid
|
||||
// So it's critical that we remove the tx and not depend on the LockPoints.
|
||||
should_remove = true;
|
||||
} else if (it->GetSpendsCoinbase()) {
|
||||
for (const CTxIn& txin : tx.vin) {
|
||||
auto it2 = m_mempool->mapTx.find(txin.prevout.hash);
|
||||
if (it2 != m_mempool->mapTx.end())
|
||||
continue;
|
||||
const Coin &coin = CoinsTip().AccessCoin(txin.prevout);
|
||||
assert(!coin.IsSpent());
|
||||
unsigned int nMemPoolHeight = m_chain.Tip()->nHeight + 1;
|
||||
if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) {
|
||||
should_remove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return should_remove;
|
||||
};
|
||||
|
||||
// We also need to remove any now-immature transactions
|
||||
m_mempool->removeForReorg(*this, STANDARD_LOCKTIME_VERIFY_FLAGS);
|
||||
m_mempool->removeForReorg(m_chain, check_final_and_mature);
|
||||
// Re-limit mempool size, in case we added any transactions
|
||||
LimitMempoolSize(
|
||||
*m_mempool,
|
||||
|
||||
Reference in New Issue
Block a user