diff --git a/src/validation.cpp b/src/validation.cpp index 59b7c2fe981..0ac04cfa5ff 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -725,8 +725,27 @@ private: private: CTxMemPool& m_pool; + + /** Holds a cached view of available coins from the UTXO set, mempool, and artificial temporary coins (to enable package validation). + * The view doesn't track whether a coin previously existed but has now been spent. We detect conflicts in other ways: + * - conflicts within a transaction are checked in CheckTransaction (bad-txns-inputs-duplicate) + * - conflicts within a package are checked in IsWellFormedPackage (conflict-in-package) + * - conflicts with an existing mempool transaction are found in CTxMemPool::GetConflictTx and replacements are allowed + * The temporary coins should persist between individual transaction checks so that package validation is possible, + * but must be cleaned up when we finish validating a subpackage, whether accepted or rejected. The cache must also + * be cleared when mempool contents change (when a changeset is applied or when the mempool trims itself) because it + * can return cached coins that no longer exist in the backend. Use CleanupTemporaryCoins() anytime you are finished + * with a SubPackageState or call LimitMempoolSize(). + */ CCoinsViewCache m_view; + + // These are the two possible backends for m_view. + /** 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; @@ -1651,7 +1670,8 @@ void MemPoolAccept::CleanupTemporaryCoins() // (3) Confirmed coins don't need to be removed. The chainstate has not changed (we are // holding cs_main and no blocks have been processed) so the confirmed tx cannot disappear like // a mempool tx can. The coin may now be spent after we submitted a tx to mempool, but - // we have already checked that the package does not have 2 transactions spending the same coin. + // we have already checked that the package does not have 2 transactions spending the same coin + // and we check whether a mempool transaction spends conflicting coins (CTxMemPool::GetConflictTx). // Keeping them in m_view is an optimization to not re-fetch confirmed coins if we later look up // inputs for this transaction again. for (const auto& outpoint : m_viewmempool.GetNonBaseCoins()) {