Skip to content

Commit 42cf8b2

Browse files
committed
[validation] make CheckSequenceLocks context-free
Allow CheckSequenceLocks to use heights and coins from any CoinsView and CBlockIndex provided. This means that CheckSequenceLocks() doesn't need to hold the mempool lock or cs_main. The caller is responsible for ensuring the CoinsView and CBlockIndex are consistent before passing them in. The typical usage is still to create a CCoinsViewMemPool from the mempool and grab the CBlockIndex from the chainstate tip.
1 parent 710c8ba commit 42cf8b2

File tree

4 files changed

+21
-21
lines changed

4 files changed

+21
-21
lines changed

src/test/miner_tests.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ struct MinerTestingSetup : public TestingSetup {
2828
void TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
2929
bool TestSequenceLocks(const CTransaction& tx, int flags) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs)
3030
{
31-
return CheckSequenceLocks(::ChainstateActive(), *m_node.mempool, tx, flags);
31+
CCoinsViewMemPool viewMempool(&m_node.chainman->ActiveChainstate().CoinsTip(), *m_node.mempool);
32+
return CheckSequenceLocks(m_node.chainman->ActiveChain().Tip(), viewMempool, tx, flags);
3233
}
3334
BlockAssembler AssemblerForTest(const CChainParams& params);
3435
};

src/txmempool.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,9 @@ void CTxMemPool::removeForReorg(CChainState& active_chainstate, int flags)
515515
LockPoints lp = it->GetLockPoints();
516516
assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate));
517517
bool validLP = TestLockPointValidity(active_chainstate.m_chain, &lp);
518-
if (!CheckFinalTx(active_chainstate.m_chain.Tip(), tx, flags) || !CheckSequenceLocks(active_chainstate, *this, tx, flags, &lp, validLP)) {
518+
CCoinsViewMemPool viewMempool(&active_chainstate.CoinsTip(), *this);
519+
if (!CheckFinalTx(active_chainstate.m_chain.Tip(), tx, flags)
520+
|| !CheckSequenceLocks(active_chainstate.m_chain.Tip(), viewMempool, tx, flags, &lp, validLP)) {
519521
// Note if CheckSequenceLocks fails the LockPoints may still be invalid
520522
// So it's critical that we remove the tx and not depend on the LockPoints.
521523
txToRemove.insert(it);

src/validation.cpp

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -245,18 +245,13 @@ bool TestLockPointValidity(CChain& active_chain, const LockPoints* lp)
245245
return true;
246246
}
247247

248-
bool CheckSequenceLocks(CChainState& active_chainstate,
249-
const CTxMemPool& pool,
248+
bool CheckSequenceLocks(CBlockIndex* tip,
249+
const CCoinsView& coins_view,
250250
const CTransaction& tx,
251251
int flags,
252252
LockPoints* lp,
253253
bool useExistingLockPoints)
254254
{
255-
AssertLockHeld(cs_main);
256-
AssertLockHeld(pool.cs);
257-
assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate));
258-
259-
CBlockIndex* tip = active_chainstate.m_chain.Tip();
260255
assert(tip != nullptr);
261256

262257
CBlockIndex index;
@@ -276,14 +271,12 @@ bool CheckSequenceLocks(CChainState& active_chainstate,
276271
lockPair.second = lp->time;
277272
}
278273
else {
279-
// CoinsTip() contains the UTXO set for active_chainstate.m_chain.Tip()
280-
CCoinsViewMemPool viewMemPool(&active_chainstate.CoinsTip(), pool);
281274
std::vector<int> prevheights;
282275
prevheights.resize(tx.vin.size());
283276
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
284277
const CTxIn& txin = tx.vin[txinIndex];
285278
Coin coin;
286-
if (!viewMemPool.GetCoin(txin.prevout, coin)) {
279+
if (!coins_view.GetCoin(txin.prevout, coin)) {
287280
return error("%s: Missing input", __func__);
288281
}
289282
if (coin.nHeight == MEMPOOL_HEIGHT) {
@@ -686,10 +679,10 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
686679
// Only accept BIP68 sequence locked transactions that can be mined in the next
687680
// block; we don't want our mempool filled up with transactions that can't
688681
// be mined yet.
689-
// Must keep pool.cs for this unless we change CheckSequenceLocks to take a
690-
// CoinsViewCache instead of create its own
682+
// Pass in m_view which has all of the relevant inputs cached. Note that, since m_view's
683+
// backend was removed, it no longer pulls coins from the mempool.
691684
assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate));
692-
if (!CheckSequenceLocks(m_active_chainstate, m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
685+
if (!CheckSequenceLocks(m_active_chainstate.m_chain.Tip(), m_view, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
693686
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-BIP68-final");
694687

695688
assert(std::addressof(g_chainman.m_blockman) == std::addressof(m_active_chainstate.m_blockman));

src/validation.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -226,22 +226,26 @@ bool CheckFinalTx(const CBlockIndex* active_chain_tip, const CTransaction &tx, i
226226
bool TestLockPointValidity(CChain& active_chain, const LockPoints* lp) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
227227

228228
/**
229-
* Check if transaction will be BIP 68 final in the next block to be created.
230-
*
231-
* Simulates calling SequenceLocks() with data from the tip of the current active chain.
229+
* Check if transaction will be BIP68 final in the next block to be created on top of tip.
230+
* @param[in] tip Chain tip to check tx sequence locks against. For example,
231+
* the tip of the current active chain.
232+
* @param[in] coins_view Any CCoinsView that provides access to the relevant coins
233+
* for checking sequence locks. Any CCoinsView can be passed in;
234+
* it is assumed to be consistent with the tip.
235+
* Simulates calling SequenceLocks() with data from the tip passed in.
232236
* Optionally stores in LockPoints the resulting height and time calculated and the hash
233237
* of the block needed for calculation or skips the calculation and uses the LockPoints
234238
* passed in for evaluation.
235239
* The LockPoints should not be considered valid if CheckSequenceLocks returns false.
236240
*
237241
* See consensus/consensus.h for flag definitions.
238242
*/
239-
bool CheckSequenceLocks(CChainState& active_chainstate,
240-
const CTxMemPool& pool,
243+
bool CheckSequenceLocks(CBlockIndex* tip,
244+
const CCoinsView& coins_view,
241245
const CTransaction& tx,
242246
int flags,
243247
LockPoints* lp = nullptr,
244-
bool useExistingLockPoints = false) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs);
248+
bool useExistingLockPoints = false);
245249

246250
/**
247251
* Closure representing one script verification

0 commit comments

Comments
 (0)