Merge bitcoin/bitcoin#28251: validation: fix coins disappearing mid-package evaluation

32c1dd1ad6 [test] mempool coins disappearing mid-package evaluation (glozow)
a67f460c3f [refactor] split setup in mempool_limit test (glozow)
d08696120e [test framework] add ability to spend only confirmed utxos (glozow)
3ea71feb11 [validation] don't LimitMempoolSize in any subpackage submissions (glozow)
d227b7234c [validation] return correct result when already-in-mempool tx gets evicted (glozow)
9698b81828 [refactor] back-fill results in AcceptPackage (glozow)
8ad7ad3392 [validation] make PackageMempoolAcceptResult members mutable (glozow)
03b87c11ca [validation] add AcceptSubPackage to delegate Accept* calls and clean up m_view (glozow)
3f01a3dab1 [CCoinsViewMemPool] track non-base coins and allow Reset (glozow)
7d7f7a1189 [policy] check for duplicate txids in package (glozow)

Pull request description:

  While we are evaluating a package, we split it into "subpackages" for evaluation (currently subpackages all have size 1 except the last one). If a subpackage has size 1, we may add a tx to mempool and call `LimitMempoolSize()`, which evicts transactions if the mempool gets full. We handle the case where the just-submitted transaction is evicted immediately, but we don't handle the case in which a transaction from a previous subpackage (either just submitted or already in mempool) is evicted. Mainly, since the coins created by the evicted transaction are cached in `m_view`, we don't realize the UTXO has disappeared until `CheckInputsFromMempoolAndCache` asserts that they exist. Also, the returned `PackageMempoolAcceptResult` reports that the transaction is in mempool even though it isn't anymore.

  Fix this by not calling `LimitMempoolSize()` until the very end, and editing the results map with "mempool full" if things fall out.

  Pointed out by instagibbs in faeed687e5 on top of the v3 PR.

ACKs for top commit:
  instagibbs:
    reACK 32c1dd1ad6

Tree-SHA512: 61e7f69db4712e5e5bfa27d037ab66bdd97f1bf60a8d9ffb96adb1f0609af012c810d681102ee5c7baec7b5fe8cb7c304a60c63ccc445d00d86a2b7f0e7ddb90
This commit is contained in:
fanquake
2023-09-13 17:50:21 +01:00
9 changed files with 392 additions and 95 deletions

View File

@@ -826,15 +826,27 @@ class CCoinsViewMemPool : public CCoinsViewBacked
* validation, since we can access transaction outputs without submitting them to mempool.
*/
std::unordered_map<COutPoint, Coin, SaltedOutpointHasher> m_temp_added;
/**
* Set of all coins that have been fetched from mempool or created using PackageAddTransaction
* (not base). Used to track the origin of a coin, see GetNonBaseCoins().
*/
mutable std::unordered_set<COutPoint, SaltedOutpointHasher> m_non_base_coins;
protected:
const CTxMemPool& mempool;
public:
CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn);
/** GetCoin, returning whether it exists and is not spent. Also updates m_non_base_coins if the
* coin is not fetched from base. */
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
/** Add the coins created by this transaction. These coins are only temporarily stored in
* m_temp_added and cannot be flushed to the back end. Only used for package validation. */
void PackageAddTransaction(const CTransactionRef& tx);
/** Get all coins in m_non_base_coins. */
std::unordered_set<COutPoint, SaltedOutpointHasher> GetNonBaseCoins() const { return m_non_base_coins; }
/** Clear m_temp_added and m_non_base_coins. */
void Reset();
};
/**