diff options
author | MarcoFalke <falke.marco@gmail.com> | 2021-12-01 17:55:44 +0100 |
---|---|---|
committer | MarcoFalke <falke.marco@gmail.com> | 2021-12-01 17:56:08 +0100 |
commit | 4633199cc8a466b8a2cfa14ba9d7793dd4c469f4 (patch) | |
tree | 61d7d1a8af34ef7086fa051eacecffceccced745 /src/validation.cpp | |
parent | 1c06e1a7b661efc5bfe8eed794e06e4eb78d23d5 (diff) | |
parent | a64078e38563ef3ac5e5ec20c07569441c87eeee (diff) | |
download | bitcoin-4633199cc8a466b8a2cfa14ba9d7793dd4c469f4.tar.xz |
Merge bitcoin/bitcoin#22677: cut the validation <-> txmempool circular dependency 2/2
a64078e38563ef3ac5e5ec20c07569441c87eeee Break validation <-> txmempool circular dependency (glozow)
64e4963c635ec3a73a5fa3f32f6ec08e70609f60 [mempool] always assert coin spent (glozow)
bb9078ed51159fa162484f16993313ed6cf980e3 [refactor] put finality and maturity checking into a lambda (glozow)
bedf246f1e2497a3641093c6e8fa11fb34dddac4 [mempool] only update lockpoints for non-removed entries (glozow)
1b3a11e126b258fba975ed7c452221608f2c5472 MOVEONLY: 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 ACK a64078e38563ef3ac5e5ec20c07569441c87eeee
mjdietzx:
reACK a64078e38563ef3ac5e5ec20c07569441c87eeee
theStack:
re-ACK a64078e38563ef3ac5e5ec20c07569441c87eeee
Tree-SHA512: f75995200569c09dfb8ddc09729da66ddb32167ff1e8a7e72f105ec062d2d6a9a390e6b4a2a115e7ad8ad3525f891ee1503f3cd2bed11773abcaf7c3230b1136
Diffstat (limited to 'src/validation.cpp')
-rw-r--r-- | src/validation.cpp | 51 |
1 files changed, 32 insertions, 19 deletions
diff --git a/src/validation.cpp b/src/validation.cpp index a9b8dba367..6ed5e7a548 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -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, |