coins: add explicit CoinsViewEmpty noop backend

Introduce `CoinsViewEmpty` as an explicit no-op `CCoinsView` implementation, and define its singleton accessor out of line in `coins.cpp` to avoid `-Wunique-object-duplication` in shared-library builds.`
Use it at call sites that intentionally want a no-op backend instead of constructing anonymous placeholder views.

`CCoinsViewTest` and `CoinsViewBottom` now inherit defaults from `CoinsViewEmpty` (e.g. the unused `EstimateSize()`, which now returns 0).

Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
This commit is contained in:
Lőrinc
2026-02-15 15:16:27 +01:00
parent 90c635c01c
commit b637566c8d
15 changed files with 54 additions and 63 deletions

View File

@@ -437,7 +437,7 @@ class MemPoolAccept
public:
explicit MemPoolAccept(CTxMemPool& mempool, Chainstate& active_chainstate) :
m_pool(mempool),
m_view(&m_dummy),
m_view(&CoinsViewEmpty::Get()),
m_viewmempool(&active_chainstate.CoinsTip(), m_pool),
m_active_chainstate(active_chainstate)
{
@@ -737,10 +737,6 @@ private:
/** When m_view is connected to m_viewmempool as its backend, it can pull coins from the mempool and from the UTXO
* set. This is also where temporary coins are stored. */
CCoinsViewMemPool m_viewmempool;
/** When m_view is connected to m_dummy, it can no longer look up coins from the mempool or UTXO set (meaning no disk
* operations happen), but can still return coins it accessed previously. Useful for keeping track of which coins
* were pulled from disk. */
CCoinsView m_dummy;
Chainstate& m_active_chainstate;
@@ -867,14 +863,14 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
}
}
// This is const, but calls into the back end CoinsViews. The CCoinsViewDB at the bottom of the
// hierarchy brings the best block into scope. See CCoinsViewDB::GetBestBlock().
m_view.GetBestBlock();
// This is const, but calls into `CCoinsViewCache::GetBestBlock()` to refresh
// the cached best block through `m_viewmempool` after caching inputs.
(void)m_view.GetBestBlock();
// we have all inputs cached now, so switch back to dummy (to protect
// against bugs where we pull more inputs from disk that miss being added
// to coins_to_uncache)
m_view.SetBackend(m_dummy);
// All required inputs are cached now, so switch m_view to the empty backend.
// This keeps already-fetched cache entries for later checks and prevents new
// backend lookups (which would avoid coins_to_uncache tracking).
m_view.SetBackend(CoinsViewEmpty::Get());
assert(m_active_chainstate.m_blockman.LookupBlockIndex(m_view.GetBestBlock()) == m_active_chainstate.m_chain.Tip());