1111#include < util/check.h>
1212#include < util/time.h>
1313#include < util/translation.h>
14+ #include < validation.h>
1415
1516using node::NodeContext;
1617
@@ -36,3 +37,80 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransactionRef& tx) const
3637{
3738 return CTxMemPoolEntry{tx, nFee, TicksSinceEpoch<std::chrono::seconds>(time), nHeight, m_sequence, spendsCoinbase, sigOpCost, lp};
3839}
40+
41+ std::optional<std::string> CheckPackageMempoolAcceptResult (const Package& txns,
42+ const PackageMempoolAcceptResult& result,
43+ bool expect_valid,
44+ const CTxMemPool* mempool)
45+ {
46+ if (expect_valid) {
47+ if (result.m_state .IsInvalid ()) {
48+ return strprintf (" Package validation unexpectedly failed: %s" , result.m_state .ToString ());
49+ }
50+ } else {
51+ if (result.m_state .IsValid ()) {
52+ strprintf (" Package validation unexpectedly succeeded. %s" , result.m_state .ToString ());
53+ }
54+ }
55+ if (result.m_state .GetResult () != PackageValidationResult::PCKG_POLICY && txns.size () != result.m_tx_results .size ()) {
56+ strprintf (" txns size %u does not match tx results size %u" , txns.size (), result.m_tx_results .size ());
57+ }
58+ for (const auto & tx : txns) {
59+ const auto & wtxid = tx->GetWitnessHash ();
60+ if (result.m_tx_results .count (wtxid) == 0 ) {
61+ return strprintf (" result not found for tx %s" , wtxid.ToString ());
62+ }
63+
64+ const auto & atmp_result = result.m_tx_results .at (wtxid);
65+ const bool valid{atmp_result.m_result_type == MempoolAcceptResult::ResultType::VALID};
66+ if (expect_valid && atmp_result.m_state .IsInvalid ()) {
67+ return strprintf (" tx %s unexpectedly failed: %s" , wtxid.ToString (), atmp_result.m_state .ToString ());
68+ }
69+
70+ // m_replaced_transactions should exist iff the result was VALID
71+ if (atmp_result.m_replaced_transactions .has_value () != valid) {
72+ return strprintf (" tx %s result should %shave m_replaced_transactions" ,
73+ wtxid.ToString (), valid ? " " : " not " );
74+ }
75+
76+ // m_vsize and m_base_fees should exist iff the result was VALID or MEMPOOL_ENTRY
77+ const bool mempool_entry{atmp_result.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY};
78+ if (atmp_result.m_base_fees .has_value () != (valid || mempool_entry)) {
79+ return strprintf (" tx %s result should %shave m_base_fees" , wtxid.ToString (), valid || mempool_entry ? " " : " not " );
80+ }
81+ if (atmp_result.m_vsize .has_value () != (valid || mempool_entry)) {
82+ return strprintf (" tx %s result should %shave m_vsize" , wtxid.ToString (), valid || mempool_entry ? " " : " not " );
83+ }
84+
85+ // m_other_wtxid should exist iff the result was DIFFERENT_WITNESS
86+ const bool diff_witness{atmp_result.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS};
87+ if (atmp_result.m_other_wtxid .has_value () != diff_witness) {
88+ return strprintf (" tx %s result should %shave m_other_wtxid" , wtxid.ToString (), diff_witness ? " " : " not " );
89+ }
90+
91+ // m_effective_feerate and m_wtxids_fee_calculations should exist iff the result was valid
92+ if (atmp_result.m_effective_feerate .has_value () != valid) {
93+ return strprintf (" tx %s result should %shave m_effective_feerate" ,
94+ wtxid.ToString (), valid ? " " : " not " );
95+ }
96+ if (atmp_result.m_wtxids_fee_calculations .has_value () != valid) {
97+ return strprintf (" tx %s result should %shave m_effective_feerate" ,
98+ wtxid.ToString (), valid ? " " : " not " );
99+ }
100+
101+ if (mempool) {
102+ // The tx by txid should be in the mempool iff the result was not INVALID.
103+ const bool txid_in_mempool{atmp_result.m_result_type != MempoolAcceptResult::ResultType::INVALID};
104+ if (mempool->exists (GenTxid::Txid (tx->GetHash ())) != txid_in_mempool) {
105+ strprintf (" tx %s should %sbe in mempool" , wtxid.ToString (), txid_in_mempool ? " " : " not " );
106+ }
107+ // Additionally, if the result was DIFFERENT_WITNESS, we shouldn't be able to find the tx in mempool by wtxid.
108+ if (tx->HasWitness () && atmp_result.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS) {
109+ if (mempool->exists (GenTxid::Wtxid (wtxid))) {
110+ strprintf (" wtxid %s should not be in mempool" , wtxid.ToString ());
111+ }
112+ }
113+ }
114+ }
115+ return std::nullopt ;
116+ }
0 commit comments