Bitcoin Core 28.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
txpackage_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2021-2022 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
6#include <key_io.h>
7#include <policy/packages.h>
8#include <policy/policy.h>
9#include <policy/rbf.h>
11#include <script/script.h>
12#include <serialize.h>
13#include <streams.h>
14#include <test/util/random.h>
15#include <test/util/script.h>
17#include <util/strencodings.h>
18#include <test/util/txmempool.h>
19#include <validation.h>
20
21#include <boost/test/unit_test.hpp>
22
23BOOST_AUTO_TEST_SUITE(txpackage_tests)
24// A fee amount that is above 1sat/vB but below 5sat/vB for most transactions created within these
25// unit tests.
26static const CAmount low_fee_amt{200};
27
28// Create placeholder transactions that have no meaning.
29inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outputs)
30{
32 mtx.vin.resize(num_inputs);
33 mtx.vout.resize(num_outputs);
34 auto random_script = CScript() << ToByteVector(InsecureRand256()) << ToByteVector(InsecureRand256());
35 for (size_t i{0}; i < num_inputs; ++i) {
36 mtx.vin[i].prevout.hash = Txid::FromUint256(InsecureRand256());
37 mtx.vin[i].prevout.n = 0;
38 mtx.vin[i].scriptSig = random_script;
39 }
40 for (size_t o{0}; o < num_outputs; ++o) {
41 mtx.vout[o].nValue = 1 * CENT;
42 mtx.vout[o].scriptPubKey = random_script;
43 }
44 return MakeTransactionRef(mtx);
45}
47{
48 // Random real segwit transaction
49 DataStream stream_1{
50 ParseHex("02000000000101964b8aa63509579ca6086e6012eeaa4c2f4dd1e283da29b67c8eea38b3c6fd220000000000fdffffff0294c618000000000017a9145afbbb42f4e83312666d0697f9e66259912ecde38768fa2c0000000000160014897388a0889390fd0e153a22bb2cf9d8f019faf50247304402200547406380719f84d68cf4e96cc3e4a1688309ef475b150be2b471c70ea562aa02206d255f5acc40fd95981874d77201d2eb07883657ce1c796513f32b6079545cdf0121023ae77335cefcb5ab4c1dc1fb0d2acfece184e593727d7d5906c78e564c7c11d125cf0c00"),
51 };
54
55 // Random real nonsegwit transaction
56 DataStream stream_2{
57 ParseHex("01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e88607d722c190000000008b4830450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a0141046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339ffffffff021bff3d11000000001976a91404943fdd508053c75000106d3bc6e2754dbcff1988ac2f15de00000000001976a914a266436d2965547608b9e15d9032a7b9d64fa43188ac00000000"),
58 };
61
62 // Random real segwit transaction
63 DataStream stream_3{
64 ParseHex("0200000000010177862801f77c2c068a70372b4c435ef8dd621291c36a64eb4dd491f02218f5324600000000fdffffff014a0100000000000022512035ea312034cfac01e956a269f3bf147f569c2fbb00180677421262da042290d803402be713325ff285e66b0380f53f2fae0d0fb4e16f378a440fed51ce835061437566729d4883bc917632f3cff474d6384bc8b989961a1d730d4a87ed38ad28bd337b20f1d658c6c138b1c312e072b4446f50f01ae0da03a42e6274f8788aae53416a7fac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d3800357b2270223a226272632d3230222c226f70223a226d696e74222c227469636b223a224342414c222c22616d74223a2236393639227d6821c1f1d658c6c138b1c312e072b4446f50f01ae0da03a42e6274f8788aae53416a7f00000000"),
65 };
68
69 // It's easy to see that wtxids are sorted in lexicographical order:
70 Wtxid wtxid_1{Wtxid::FromHex("85cd1a31eb38f74ed5742ec9cb546712ab5aaf747de28a9168b53e846cbda17f").value()};
71 Wtxid wtxid_2{Wtxid::FromHex("b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b").value()};
72 Wtxid wtxid_3{Wtxid::FromHex("e065bac15f62bb4e761d761db928ddee65a47296b2b776785abb912cdec474e3").value()};
73 BOOST_CHECK_EQUAL(tx_1.GetWitnessHash(), wtxid_1);
74 BOOST_CHECK_EQUAL(tx_2.GetWitnessHash(), wtxid_2);
75 BOOST_CHECK_EQUAL(tx_3.GetWitnessHash(), wtxid_3);
76
77 BOOST_CHECK(wtxid_1.GetHex() < wtxid_2.GetHex());
78 BOOST_CHECK(wtxid_2.GetHex() < wtxid_3.GetHex());
79
80 // The txids are not (we want to test that sorting and hashing use wtxid, not txid):
81 Txid txid_1{Txid::FromHex("bd0f71c1d5e50589063e134fad22053cdae5ab2320db5bf5e540198b0b5a4e69").value()};
82 Txid txid_2{Txid::FromHex("b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b").value()};
83 Txid txid_3{Txid::FromHex("ee707be5201160e32c4fc715bec227d1aeea5940fb4295605e7373edce3b1a93").value()};
84 BOOST_CHECK_EQUAL(tx_1.GetHash(), txid_1);
85 BOOST_CHECK_EQUAL(tx_2.GetHash(), txid_2);
86 BOOST_CHECK_EQUAL(tx_3.GetHash(), txid_3);
87
88 BOOST_CHECK(txid_2.GetHex() < txid_1.GetHex());
89
90 BOOST_CHECK(txid_1.ToUint256() != wtxid_1.ToUint256());
91 BOOST_CHECK(txid_2.ToUint256() == wtxid_2.ToUint256());
92 BOOST_CHECK(txid_3.ToUint256() != wtxid_3.ToUint256());
93
94 // We are testing that both functions compare using GetHex() and not uint256.
95 // (in this pair of wtxids, hex string order != uint256 order)
96 BOOST_CHECK(wtxid_2 < wtxid_1);
97 // (in this pair of wtxids, hex string order == uint256 order)
98 BOOST_CHECK(wtxid_2 < wtxid_3);
99
100 // All permutations of the package containing ptx_1, ptx_2, ptx_3 have the same package hash
101 std::vector<CTransactionRef> package_123{ptx_1, ptx_2, ptx_3};
102 std::vector<CTransactionRef> package_132{ptx_1, ptx_3, ptx_2};
103 std::vector<CTransactionRef> package_231{ptx_2, ptx_3, ptx_1};
104 std::vector<CTransactionRef> package_213{ptx_2, ptx_1, ptx_3};
105 std::vector<CTransactionRef> package_312{ptx_3, ptx_1, ptx_2};
106 std::vector<CTransactionRef> package_321{ptx_3, ptx_2, ptx_1};
107
108 uint256 calculated_hash_123 = (HashWriter() << wtxid_1 << wtxid_2 << wtxid_3).GetSHA256();
109
110 uint256 hash_if_by_txid = (HashWriter() << wtxid_2 << wtxid_1 << wtxid_3).GetSHA256();
111 BOOST_CHECK(hash_if_by_txid != calculated_hash_123);
112
113 uint256 hash_if_use_txid = (HashWriter() << txid_2 << txid_1 << txid_3).GetSHA256();
114 BOOST_CHECK(hash_if_use_txid != calculated_hash_123);
115
116 uint256 hash_if_use_int_order = (HashWriter() << wtxid_2 << wtxid_1 << wtxid_3).GetSHA256();
117 BOOST_CHECK(hash_if_use_int_order != calculated_hash_123);
118
119 BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_123));
120 BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_132));
121 BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_231));
122 BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_213));
123 BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_312));
124 BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_321));
125}
126
127BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup)
128{
129 // Packages can't have more than 25 transactions.
130 Package package_too_many;
131 package_too_many.reserve(MAX_PACKAGE_COUNT + 1);
132 for (size_t i{0}; i < MAX_PACKAGE_COUNT + 1; ++i) {
133 package_too_many.emplace_back(create_placeholder_tx(1, 1));
134 }
135 PackageValidationState state_too_many;
136 BOOST_CHECK(!IsWellFormedPackage(package_too_many, state_too_many, /*require_sorted=*/true));
138 BOOST_CHECK_EQUAL(state_too_many.GetRejectReason(), "package-too-many-transactions");
139
140 // Packages can't have a total weight of more than 404'000WU.
141 CTransactionRef large_ptx = create_placeholder_tx(150, 150);
142 Package package_too_large;
143 auto size_large = GetTransactionWeight(*large_ptx);
144 size_t total_weight{0};
145 while (total_weight <= MAX_PACKAGE_WEIGHT) {
146 package_too_large.push_back(large_ptx);
147 total_weight += size_large;
148 }
149 BOOST_CHECK(package_too_large.size() <= MAX_PACKAGE_COUNT);
150 PackageValidationState state_too_large;
151 BOOST_CHECK(!IsWellFormedPackage(package_too_large, state_too_large, /*require_sorted=*/true));
153 BOOST_CHECK_EQUAL(state_too_large.GetRejectReason(), "package-too-large");
154
155 // Packages can't contain transactions with the same txid.
156 Package package_duplicate_txids_empty;
157 for (auto i{0}; i < 3; ++i) {
158 CMutableTransaction empty_tx;
159 package_duplicate_txids_empty.emplace_back(MakeTransactionRef(empty_tx));
160 }
161 PackageValidationState state_duplicates;
162 BOOST_CHECK(!IsWellFormedPackage(package_duplicate_txids_empty, state_duplicates, /*require_sorted=*/true));
164 BOOST_CHECK_EQUAL(state_duplicates.GetRejectReason(), "package-contains-duplicates");
165 BOOST_CHECK(!IsConsistentPackage(package_duplicate_txids_empty));
166
167 // Packages can't have transactions spending the same prevout
168 CMutableTransaction tx_zero_1;
169 CMutableTransaction tx_zero_2;
170 COutPoint same_prevout{Txid::FromUint256(InsecureRand256()), 0};
171 tx_zero_1.vin.emplace_back(same_prevout);
172 tx_zero_2.vin.emplace_back(same_prevout);
173 // Different vouts (not the same tx)
174 tx_zero_1.vout.emplace_back(CENT, P2WSH_OP_TRUE);
175 tx_zero_2.vout.emplace_back(2 * CENT, P2WSH_OP_TRUE);
176 Package package_conflicts{MakeTransactionRef(tx_zero_1), MakeTransactionRef(tx_zero_2)};
177 BOOST_CHECK(!IsConsistentPackage(package_conflicts));
178 // Transactions are considered sorted when they have no dependencies.
179 BOOST_CHECK(IsTopoSortedPackage(package_conflicts));
180 PackageValidationState state_conflicts;
181 BOOST_CHECK(!IsWellFormedPackage(package_conflicts, state_conflicts, /*require_sorted=*/true));
183 BOOST_CHECK_EQUAL(state_conflicts.GetRejectReason(), "conflict-in-package");
184
185 // IsConsistentPackage only cares about conflicts between transactions, not about a transaction
186 // conflicting with itself (i.e. duplicate prevouts in vin).
187 CMutableTransaction dup_tx;
188 const COutPoint rand_prevout{Txid::FromUint256(InsecureRand256()), 0};
189 dup_tx.vin.emplace_back(rand_prevout);
190 dup_tx.vin.emplace_back(rand_prevout);
191 Package package_with_dup_tx{MakeTransactionRef(dup_tx)};
192 BOOST_CHECK(IsConsistentPackage(package_with_dup_tx));
193 package_with_dup_tx.emplace_back(create_placeholder_tx(1, 1));
194 BOOST_CHECK(IsConsistentPackage(package_with_dup_tx));
195}
196
198{
199 LOCK(cs_main);
200 unsigned int initialPoolSize = m_node.mempool->size();
201
202 // Parent and Child Package
203 CKey parent_key = GenerateRandomKey();
204 CScript parent_locking_script = GetScriptForDestination(PKHash(parent_key.GetPubKey()));
205 auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
206 /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
207 /*output_destination=*/parent_locking_script,
208 /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
209 CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
210
211 CKey child_key = GenerateRandomKey();
212 CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey()));
213 auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
214 /*input_height=*/101, /*input_signing_key=*/parent_key,
215 /*output_destination=*/child_locking_script,
216 /*output_amount=*/CAmount(48 * COIN), /*submit=*/false);
217 CTransactionRef tx_child = MakeTransactionRef(mtx_child);
218 Package package_parent_child{tx_parent, tx_child};
219 const auto result_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_parent_child, /*test_accept=*/true, /*client_maxfeerate=*/{});
220 if (auto err_parent_child{CheckPackageMempoolAcceptResult(package_parent_child, result_parent_child, /*expect_valid=*/true, nullptr)}) {
221 BOOST_ERROR(err_parent_child.value());
222 } else {
223 auto it_parent = result_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
224 auto it_child = result_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
225
226 BOOST_CHECK(it_parent->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_parent)) == COIN);
227 BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
228 BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
229
230 BOOST_CHECK(it_child->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_child)) == COIN);
231 BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1);
232 BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
233 }
234 // A single, giant transaction submitted through ProcessNewPackage fails on single tx policy.
235 CTransactionRef giant_ptx = create_placeholder_tx(999, 999);
237 Package package_single_giant{giant_ptx};
238 auto result_single_large = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_single_giant, /*test_accept=*/true, /*client_maxfeerate=*/{});
239 if (auto err_single_large{CheckPackageMempoolAcceptResult(package_single_giant, result_single_large, /*expect_valid=*/false, nullptr)}) {
240 BOOST_ERROR(err_single_large.value());
241 } else {
242 BOOST_CHECK_EQUAL(result_single_large.m_state.GetResult(), PackageValidationResult::PCKG_TX);
243 BOOST_CHECK_EQUAL(result_single_large.m_state.GetRejectReason(), "transaction failed");
244 auto it_giant_tx = result_single_large.m_tx_results.find(giant_ptx->GetWitnessHash());
245 BOOST_CHECK_EQUAL(it_giant_tx->second.m_state.GetRejectReason(), "tx-size");
246 }
247
248 // Check that mempool size hasn't changed.
249 BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize);
250}
251
252BOOST_FIXTURE_TEST_CASE(noncontextual_package_tests, TestChain100Setup)
253{
254 // The signatures won't be verified so we can just use a placeholder
255 CKey placeholder_key = GenerateRandomKey();
256 CScript spk = GetScriptForDestination(PKHash(placeholder_key.GetPubKey()));
257 CKey placeholder_key_2 = GenerateRandomKey();
258 CScript spk2 = GetScriptForDestination(PKHash(placeholder_key_2.GetPubKey()));
259
260 // Parent and Child Package
261 {
262 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0, 0, coinbaseKey, spk,
263 CAmount(49 * COIN), /*submit=*/false);
264 CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
265
266 auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0, 101, placeholder_key, spk2,
267 CAmount(48 * COIN), /*submit=*/false);
268 CTransactionRef tx_child = MakeTransactionRef(mtx_child);
269
271 BOOST_CHECK(IsWellFormedPackage({tx_parent, tx_child}, state, /*require_sorted=*/true));
272 BOOST_CHECK(!IsWellFormedPackage({tx_child, tx_parent}, state, /*require_sorted=*/true));
274 BOOST_CHECK_EQUAL(state.GetRejectReason(), "package-not-sorted");
275 BOOST_CHECK(IsChildWithParents({tx_parent, tx_child}));
276 BOOST_CHECK(IsChildWithParentsTree({tx_parent, tx_child}));
277 BOOST_CHECK(GetPackageHash({tx_parent}) != GetPackageHash({tx_child}));
278 BOOST_CHECK(GetPackageHash({tx_child, tx_child}) != GetPackageHash({tx_child}));
279 BOOST_CHECK(GetPackageHash({tx_child, tx_parent}) != GetPackageHash({tx_child, tx_child}));
280 }
281
282 // 24 Parents and 1 Child
283 {
284 Package package;
286 for (int i{0}; i < 24; ++i) {
287 auto parent = MakeTransactionRef(CreateValidMempoolTransaction(m_coinbase_txns[i + 1],
288 0, 0, coinbaseKey, spk, CAmount(48 * COIN), false));
289 package.emplace_back(parent);
290 child.vin.emplace_back(COutPoint(parent->GetHash(), 0));
291 }
292 child.vout.emplace_back(47 * COIN, spk2);
293
294 // The child must be in the package.
296
297 // The parents can be in any order.
299 std::shuffle(package.begin(), package.end(), rng);
300 package.push_back(MakeTransactionRef(child));
301
303 BOOST_CHECK(IsWellFormedPackage(package, state, /*require_sorted=*/true));
306
307 package.erase(package.begin());
309
310 // The package cannot have unrelated transactions.
311 package.insert(package.begin(), m_coinbase_txns[0]);
313 }
314
315 // 2 Parents and 1 Child where one parent depends on the other.
316 {
317 CMutableTransaction mtx_parent;
318 mtx_parent.vin.emplace_back(COutPoint(m_coinbase_txns[0]->GetHash(), 0));
319 mtx_parent.vout.emplace_back(20 * COIN, spk);
320 mtx_parent.vout.emplace_back(20 * COIN, spk2);
321 CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
322
323 CMutableTransaction mtx_parent_also_child;
324 mtx_parent_also_child.vin.emplace_back(COutPoint(tx_parent->GetHash(), 0));
325 mtx_parent_also_child.vout.emplace_back(20 * COIN, spk);
326 CTransactionRef tx_parent_also_child = MakeTransactionRef(mtx_parent_also_child);
327
328 CMutableTransaction mtx_child;
329 mtx_child.vin.emplace_back(COutPoint(tx_parent->GetHash(), 1));
330 mtx_child.vin.emplace_back(COutPoint(tx_parent_also_child->GetHash(), 0));
331 mtx_child.vout.emplace_back(39 * COIN, spk);
332 CTransactionRef tx_child = MakeTransactionRef(mtx_child);
333
335 BOOST_CHECK(IsChildWithParents({tx_parent, tx_parent_also_child}));
336 BOOST_CHECK(IsChildWithParents({tx_parent, tx_child}));
337 BOOST_CHECK(IsChildWithParents({tx_parent, tx_parent_also_child, tx_child}));
338 BOOST_CHECK(!IsChildWithParentsTree({tx_parent, tx_parent_also_child, tx_child}));
339 // IsChildWithParents does not detect unsorted parents.
340 BOOST_CHECK(IsChildWithParents({tx_parent_also_child, tx_parent, tx_child}));
341 BOOST_CHECK(IsWellFormedPackage({tx_parent, tx_parent_also_child, tx_child}, state, /*require_sorted=*/true));
342 BOOST_CHECK(!IsWellFormedPackage({tx_parent_also_child, tx_parent, tx_child}, state, /*require_sorted=*/true));
344 BOOST_CHECK_EQUAL(state.GetRejectReason(), "package-not-sorted");
345 }
346}
347
349{
350 LOCK(cs_main);
351 unsigned int expected_pool_size = m_node.mempool->size();
352 CKey parent_key = GenerateRandomKey();
353 CScript parent_locking_script = GetScriptForDestination(PKHash(parent_key.GetPubKey()));
354
355 // Unrelated transactions are not allowed in package submission.
356 Package package_unrelated;
357 for (size_t i{0}; i < 10; ++i) {
358 auto mtx = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[i + 25], /*input_vout=*/0,
359 /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
360 /*output_destination=*/parent_locking_script,
361 /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
362 package_unrelated.emplace_back(MakeTransactionRef(mtx));
363 }
364 auto result_unrelated_submit = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
365 package_unrelated, /*test_accept=*/false, /*client_maxfeerate=*/{});
366 // We don't expect m_tx_results for each transaction when basic sanity checks haven't passed.
367 BOOST_CHECK(result_unrelated_submit.m_state.IsInvalid());
368 BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
369 BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetRejectReason(), "package-not-child-with-parents");
370 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
371
372 // Parent and Child (and Grandchild) Package
373 Package package_parent_child;
374 Package package_3gen;
375 auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
376 /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
377 /*output_destination=*/parent_locking_script,
378 /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
379 CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
380 package_parent_child.push_back(tx_parent);
381 package_3gen.push_back(tx_parent);
382
383 CKey child_key = GenerateRandomKey();
384 CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey()));
385 auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
386 /*input_height=*/101, /*input_signing_key=*/parent_key,
387 /*output_destination=*/child_locking_script,
388 /*output_amount=*/CAmount(48 * COIN), /*submit=*/false);
389 CTransactionRef tx_child = MakeTransactionRef(mtx_child);
390 package_parent_child.push_back(tx_child);
391 package_3gen.push_back(tx_child);
392
393 CKey grandchild_key = GenerateRandomKey();
394 CScript grandchild_locking_script = GetScriptForDestination(PKHash(grandchild_key.GetPubKey()));
395 auto mtx_grandchild = CreateValidMempoolTransaction(/*input_transaction=*/tx_child, /*input_vout=*/0,
396 /*input_height=*/101, /*input_signing_key=*/child_key,
397 /*output_destination=*/grandchild_locking_script,
398 /*output_amount=*/CAmount(47 * COIN), /*submit=*/false);
399 CTransactionRef tx_grandchild = MakeTransactionRef(mtx_grandchild);
400 package_3gen.push_back(tx_grandchild);
401
402 // 3 Generations is not allowed.
403 {
404 auto result_3gen_submit = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
405 package_3gen, /*test_accept=*/false, /*client_maxfeerate=*/{});
406 BOOST_CHECK(result_3gen_submit.m_state.IsInvalid());
407 BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
408 BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetRejectReason(), "package-not-child-with-parents");
409 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
410 }
411
412 // Parent and child package where transactions are invalid for reasons other than fee and
413 // missing inputs, so the package validation isn't expected to happen.
414 {
415 CScriptWitness bad_witness;
416 bad_witness.stack.emplace_back(1);
417 CMutableTransaction mtx_parent_invalid{mtx_parent};
418 mtx_parent_invalid.vin[0].scriptWitness = bad_witness;
419 CTransactionRef tx_parent_invalid = MakeTransactionRef(mtx_parent_invalid);
420 Package package_invalid_parent{tx_parent_invalid, tx_child};
421 auto result_quit_early = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
422 package_invalid_parent, /*test_accept=*/ false, /*client_maxfeerate=*/{});
423 if (auto err_parent_invalid{CheckPackageMempoolAcceptResult(package_invalid_parent, result_quit_early, /*expect_valid=*/false, m_node.mempool.get())}) {
424 BOOST_ERROR(err_parent_invalid.value());
425 } else {
426 auto it_parent = result_quit_early.m_tx_results.find(tx_parent_invalid->GetWitnessHash());
427 auto it_child = result_quit_early.m_tx_results.find(tx_child->GetWitnessHash());
428 BOOST_CHECK_EQUAL(it_parent->second.m_state.GetResult(), TxValidationResult::TX_WITNESS_MUTATED);
429 BOOST_CHECK_EQUAL(it_parent->second.m_state.GetRejectReason(), "bad-witness-nonstandard");
430 BOOST_CHECK_EQUAL(it_child->second.m_state.GetResult(), TxValidationResult::TX_MISSING_INPUTS);
431 BOOST_CHECK_EQUAL(it_child->second.m_state.GetRejectReason(), "bad-txns-inputs-missingorspent");
432 }
433 BOOST_CHECK_EQUAL(result_quit_early.m_state.GetResult(), PackageValidationResult::PCKG_TX);
434 }
435
436 // Child with missing parent.
437 mtx_child.vin.emplace_back(COutPoint(package_unrelated[0]->GetHash(), 0));
438 Package package_missing_parent;
439 package_missing_parent.push_back(tx_parent);
440 package_missing_parent.push_back(MakeTransactionRef(mtx_child));
441 {
442 const auto result_missing_parent = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
443 package_missing_parent, /*test_accept=*/false, /*client_maxfeerate=*/{});
444 BOOST_CHECK(result_missing_parent.m_state.IsInvalid());
445 BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
446 BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetRejectReason(), "package-not-child-with-unconfirmed-parents");
447 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
448 }
449
450 // Submit package with parent + child.
451 {
452 const auto submit_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
453 package_parent_child, /*test_accept=*/false, /*client_maxfeerate=*/{});
454 expected_pool_size += 2;
455 BOOST_CHECK_MESSAGE(submit_parent_child.m_state.IsValid(),
456 "Package validation unexpectedly failed: " << submit_parent_child.m_state.GetRejectReason());
457 BOOST_CHECK_EQUAL(submit_parent_child.m_tx_results.size(), package_parent_child.size());
458 auto it_parent = submit_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
459 auto it_child = submit_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
460 BOOST_CHECK(it_parent != submit_parent_child.m_tx_results.end());
461 BOOST_CHECK(it_parent->second.m_state.IsValid());
462 BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_parent)));
463 BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
464 BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
465 BOOST_CHECK(it_child->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_child)));
466 BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1);
467 BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
468
469 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
470 }
471
472 // Already-in-mempool transactions should be detected and de-duplicated.
473 {
474 const auto submit_deduped = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
475 package_parent_child, /*test_accept=*/false, /*client_maxfeerate=*/{});
476 if (auto err_deduped{CheckPackageMempoolAcceptResult(package_parent_child, submit_deduped, /*expect_valid=*/true, m_node.mempool.get())}) {
477 BOOST_ERROR(err_deduped.value());
478 } else {
479 auto it_parent_deduped = submit_deduped.m_tx_results.find(tx_parent->GetWitnessHash());
480 auto it_child_deduped = submit_deduped.m_tx_results.find(tx_child->GetWitnessHash());
481 BOOST_CHECK(it_parent_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
482 BOOST_CHECK(it_child_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
483 }
484
485 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
486 }
487}
488
489// Tests for packages containing transactions that have same-txid-different-witness equivalents in
490// the mempool.
491BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
492{
493 // Mine blocks to mature coinbases.
494 mineBlocks(5);
495 MockMempoolMinFee(CFeeRate(5000));
496 LOCK(cs_main);
497
498 // Transactions with a same-txid-different-witness transaction in the mempool should be ignored,
499 // and the mempool entry's wtxid returned.
500 CScript witnessScript = CScript() << OP_DROP << OP_TRUE;
501 CScript scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
502 auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
503 /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
504 /*output_destination=*/scriptPubKey,
505 /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
506 CTransactionRef ptx_parent = MakeTransactionRef(mtx_parent);
507
508 // Make two children with the same txid but different witnesses.
509 CScriptWitness witness1;
510 witness1.stack.emplace_back(1);
511 witness1.stack.emplace_back(witnessScript.begin(), witnessScript.end());
512
513 CScriptWitness witness2(witness1);
514 witness2.stack.emplace_back(2);
515 witness2.stack.emplace_back(witnessScript.begin(), witnessScript.end());
516
517 CKey child_key = GenerateRandomKey();
518 CScript child_locking_script = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey()));
519 CMutableTransaction mtx_child1;
520 mtx_child1.version = 1;
521 mtx_child1.vin.resize(1);
522 mtx_child1.vin[0].prevout.hash = ptx_parent->GetHash();
523 mtx_child1.vin[0].prevout.n = 0;
524 mtx_child1.vin[0].scriptSig = CScript();
525 mtx_child1.vin[0].scriptWitness = witness1;
526 mtx_child1.vout.resize(1);
527 mtx_child1.vout[0].nValue = CAmount(48 * COIN);
528 mtx_child1.vout[0].scriptPubKey = child_locking_script;
529
530 CMutableTransaction mtx_child2{mtx_child1};
531 mtx_child2.vin[0].scriptWitness = witness2;
532
533 CTransactionRef ptx_child1 = MakeTransactionRef(mtx_child1);
534 CTransactionRef ptx_child2 = MakeTransactionRef(mtx_child2);
535
536 // child1 and child2 have the same txid
537 BOOST_CHECK_EQUAL(ptx_child1->GetHash(), ptx_child2->GetHash());
538 // child1 and child2 have different wtxids
539 BOOST_CHECK(ptx_child1->GetWitnessHash() != ptx_child2->GetWitnessHash());
540 // Check that they have different package hashes
541 BOOST_CHECK(GetPackageHash({ptx_parent, ptx_child1}) != GetPackageHash({ptx_parent, ptx_child2}));
542
543 // Try submitting Package1{parent, child1} and Package2{parent, child2} where the children are
544 // same-txid-different-witness.
545 {
546 Package package_parent_child1{ptx_parent, ptx_child1};
547 const auto submit_witness1 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
548 package_parent_child1, /*test_accept=*/false, /*client_maxfeerate=*/{});
549 if (auto err_witness1{CheckPackageMempoolAcceptResult(package_parent_child1, submit_witness1, /*expect_valid=*/true, m_node.mempool.get())}) {
550 BOOST_ERROR(err_witness1.value());
551 }
552
553 // Child2 would have been validated individually.
554 Package package_parent_child2{ptx_parent, ptx_child2};
555 const auto submit_witness2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
556 package_parent_child2, /*test_accept=*/false, /*client_maxfeerate=*/{});
557 if (auto err_witness2{CheckPackageMempoolAcceptResult(package_parent_child2, submit_witness2, /*expect_valid=*/true, m_node.mempool.get())}) {
558 BOOST_ERROR(err_witness2.value());
559 } else {
560 auto it_parent2_deduped = submit_witness2.m_tx_results.find(ptx_parent->GetWitnessHash());
561 auto it_child2 = submit_witness2.m_tx_results.find(ptx_child2->GetWitnessHash());
562 BOOST_CHECK(it_parent2_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
563 BOOST_CHECK(it_child2->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS);
564 BOOST_CHECK_EQUAL(ptx_child1->GetWitnessHash(), it_child2->second.m_other_wtxid.value());
565 }
566
567 // Deduplication should work when wtxid != txid. Submit package with the already-in-mempool
568 // transactions again, which should not fail.
569 const auto submit_segwit_dedup = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
570 package_parent_child1, /*test_accept=*/false, /*client_maxfeerate=*/{});
571 if (auto err_segwit_dedup{CheckPackageMempoolAcceptResult(package_parent_child1, submit_segwit_dedup, /*expect_valid=*/true, m_node.mempool.get())}) {
572 BOOST_ERROR(err_segwit_dedup.value());
573 } else {
574 auto it_parent_dup = submit_segwit_dedup.m_tx_results.find(ptx_parent->GetWitnessHash());
575 auto it_child_dup = submit_segwit_dedup.m_tx_results.find(ptx_child1->GetWitnessHash());
576 BOOST_CHECK(it_parent_dup->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
577 BOOST_CHECK(it_child_dup->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
578 }
579 }
580
581 // Try submitting Package1{child2, grandchild} where child2 is same-txid-different-witness as
582 // the in-mempool transaction, child1. Since child1 exists in the mempool and its outputs are
583 // available, child2 should be ignored and grandchild should be accepted.
584 //
585 // This tests a potential censorship vector in which an attacker broadcasts a competing package
586 // where a parent's witness is mutated. The honest package should be accepted despite the fact
587 // that we don't allow witness replacement.
588 CKey grandchild_key = GenerateRandomKey();
589 CScript grandchild_locking_script = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
590 auto mtx_grandchild = CreateValidMempoolTransaction(/*input_transaction=*/ptx_child2, /*input_vout=*/0,
591 /*input_height=*/0, /*input_signing_key=*/child_key,
592 /*output_destination=*/grandchild_locking_script,
593 /*output_amount=*/CAmount(47 * COIN), /*submit=*/false);
594 CTransactionRef ptx_grandchild = MakeTransactionRef(mtx_grandchild);
595 // Check that they have different package hashes
596 BOOST_CHECK(GetPackageHash({ptx_child1, ptx_grandchild}) != GetPackageHash({ptx_child2, ptx_grandchild}));
597 // We already submitted child1 above.
598 {
599 Package package_child2_grandchild{ptx_child2, ptx_grandchild};
600 const auto submit_spend_ignored = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
601 package_child2_grandchild, /*test_accept=*/false, /*client_maxfeerate=*/{});
602 if (auto err_spend_ignored{CheckPackageMempoolAcceptResult(package_child2_grandchild, submit_spend_ignored, /*expect_valid=*/true, m_node.mempool.get())}) {
603 BOOST_ERROR(err_spend_ignored.value());
604 } else {
605 auto it_child2_ignored = submit_spend_ignored.m_tx_results.find(ptx_child2->GetWitnessHash());
606 auto it_grandchild = submit_spend_ignored.m_tx_results.find(ptx_grandchild->GetWitnessHash());
607 BOOST_CHECK(it_child2_ignored->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS);
608 BOOST_CHECK(it_grandchild->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
609 }
610 }
611
612 // A package Package{parent1, parent2, parent3, child} where the parents are a mixture of
613 // identical-tx-in-mempool, same-txid-different-witness-in-mempool, and new transactions.
614 Package package_mixed;
615
616 // Give all the parents anyone-can-spend scripts so we don't have to deal with signing the child.
617 CScript acs_script = CScript() << OP_TRUE;
619 CScriptWitness acs_witness;
620 acs_witness.stack.emplace_back(acs_script.begin(), acs_script.end());
621
622 // parent1 will already be in the mempool
623 auto mtx_parent1 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,
624 /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
625 /*output_destination=*/acs_spk,
626 /*output_amount=*/CAmount(49 * COIN), /*submit=*/true);
627 CTransactionRef ptx_parent1 = MakeTransactionRef(mtx_parent1);
628 package_mixed.push_back(ptx_parent1);
629
630 // parent2 will have a same-txid-different-witness tx already in the mempool
631 CScript grandparent2_script = CScript() << OP_DROP << OP_TRUE;
632 CScript grandparent2_spk = GetScriptForDestination(WitnessV0ScriptHash(grandparent2_script));
633 CScriptWitness parent2_witness1;
634 parent2_witness1.stack.emplace_back(1);
635 parent2_witness1.stack.emplace_back(grandparent2_script.begin(), grandparent2_script.end());
636 CScriptWitness parent2_witness2;
637 parent2_witness2.stack.emplace_back(2);
638 parent2_witness2.stack.emplace_back(grandparent2_script.begin(), grandparent2_script.end());
639
640 // Create grandparent2 creating an output with multiple spending paths. Submit to mempool.
641 auto mtx_grandparent2 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[2], /*input_vout=*/0,
642 /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
643 /*output_destination=*/grandparent2_spk,
644 /*output_amount=*/CAmount(49 * COIN), /*submit=*/true);
645 CTransactionRef ptx_grandparent2 = MakeTransactionRef(mtx_grandparent2);
646
647 CMutableTransaction mtx_parent2_v1;
648 mtx_parent2_v1.version = 1;
649 mtx_parent2_v1.vin.resize(1);
650 mtx_parent2_v1.vin[0].prevout.hash = ptx_grandparent2->GetHash();
651 mtx_parent2_v1.vin[0].prevout.n = 0;
652 mtx_parent2_v1.vin[0].scriptSig = CScript();
653 mtx_parent2_v1.vin[0].scriptWitness = parent2_witness1;
654 mtx_parent2_v1.vout.resize(1);
655 mtx_parent2_v1.vout[0].nValue = CAmount(48 * COIN);
656 mtx_parent2_v1.vout[0].scriptPubKey = acs_spk;
657
658 CMutableTransaction mtx_parent2_v2{mtx_parent2_v1};
659 mtx_parent2_v2.vin[0].scriptWitness = parent2_witness2;
660
661 CTransactionRef ptx_parent2_v1 = MakeTransactionRef(mtx_parent2_v1);
662 CTransactionRef ptx_parent2_v2 = MakeTransactionRef(mtx_parent2_v2);
663 // Put parent2_v1 in the package, submit parent2_v2 to the mempool.
664 const MempoolAcceptResult parent2_v2_result = m_node.chainman->ProcessTransaction(ptx_parent2_v2);
666 package_mixed.push_back(ptx_parent2_v1);
667
668 // parent3 will be a new transaction. Put a low feerate to make it invalid on its own.
669 auto mtx_parent3 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[3], /*input_vout=*/0,
670 /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
671 /*output_destination=*/acs_spk,
672 /*output_amount=*/CAmount(50 * COIN - low_fee_amt), /*submit=*/false);
673 CTransactionRef ptx_parent3 = MakeTransactionRef(mtx_parent3);
674 package_mixed.push_back(ptx_parent3);
675 BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*ptx_parent3)) > low_fee_amt);
676 BOOST_CHECK(m_node.mempool->m_opts.min_relay_feerate.GetFee(GetVirtualTransactionSize(*ptx_parent3)) <= low_fee_amt);
677
678 // child spends parent1, parent2, and parent3
679 CKey mixed_grandchild_key = GenerateRandomKey();
680 CScript mixed_child_spk = GetScriptForDestination(WitnessV0KeyHash(mixed_grandchild_key.GetPubKey()));
681
682 CMutableTransaction mtx_mixed_child;
683 mtx_mixed_child.vin.emplace_back(COutPoint(ptx_parent1->GetHash(), 0));
684 mtx_mixed_child.vin.emplace_back(COutPoint(ptx_parent2_v1->GetHash(), 0));
685 mtx_mixed_child.vin.emplace_back(COutPoint(ptx_parent3->GetHash(), 0));
686 mtx_mixed_child.vin[0].scriptWitness = acs_witness;
687 mtx_mixed_child.vin[1].scriptWitness = acs_witness;
688 mtx_mixed_child.vin[2].scriptWitness = acs_witness;
689 mtx_mixed_child.vout.emplace_back((48 + 49 + 50 - 1) * COIN, mixed_child_spk);
690 CTransactionRef ptx_mixed_child = MakeTransactionRef(mtx_mixed_child);
691 package_mixed.push_back(ptx_mixed_child);
692
693 // Submit package:
694 // parent1 should be ignored
695 // parent2_v1 should be ignored (and v2 wtxid returned)
696 // parent3 should be accepted
697 // child should be accepted
698 {
699 const auto mixed_result = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_mixed, false, /*client_maxfeerate=*/{});
700 if (auto err_mixed{CheckPackageMempoolAcceptResult(package_mixed, mixed_result, /*expect_valid=*/true, m_node.mempool.get())}) {
701 BOOST_ERROR(err_mixed.value());
702 } else {
703 auto it_parent1 = mixed_result.m_tx_results.find(ptx_parent1->GetWitnessHash());
704 auto it_parent2 = mixed_result.m_tx_results.find(ptx_parent2_v1->GetWitnessHash());
705 auto it_parent3 = mixed_result.m_tx_results.find(ptx_parent3->GetWitnessHash());
706 auto it_child = mixed_result.m_tx_results.find(ptx_mixed_child->GetWitnessHash());
707
708 BOOST_CHECK(it_parent1->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
709 BOOST_CHECK(it_parent2->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS);
710 BOOST_CHECK(it_parent3->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
711 BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
712 BOOST_CHECK_EQUAL(ptx_parent2_v2->GetWitnessHash(), it_parent2->second.m_other_wtxid.value());
713
714 // package feerate should include parent3 and child. It should not include parent1 or parent2_v1.
715 const CFeeRate expected_feerate(1 * COIN, GetVirtualTransactionSize(*ptx_parent3) + GetVirtualTransactionSize(*ptx_mixed_child));
716 BOOST_CHECK(it_parent3->second.m_effective_feerate.value() == expected_feerate);
717 BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
718 std::vector<Wtxid> expected_wtxids({ptx_parent3->GetWitnessHash(), ptx_mixed_child->GetWitnessHash()});
719 BOOST_CHECK(it_parent3->second.m_wtxids_fee_calculations.value() == expected_wtxids);
720 BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
721 }
722 }
723}
724
726{
727 mineBlocks(5);
728 MockMempoolMinFee(CFeeRate(5000));
730 size_t expected_pool_size = m_node.mempool->size();
731 CKey child_key = GenerateRandomKey();
733 CKey grandchild_key = GenerateRandomKey();
734 CScript child_spk = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
735
736 // low-fee parent and high-fee child package
737 const CAmount coinbase_value{50 * COIN};
738 const CAmount parent_value{coinbase_value - low_fee_amt};
739 const CAmount child_value{parent_value - COIN};
740
741 Package package_cpfp;
742 auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
743 /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
744 /*output_destination=*/parent_spk,
745 /*output_amount=*/parent_value, /*submit=*/false);
746 CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
747 package_cpfp.push_back(tx_parent);
748
749 auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
750 /*input_height=*/101, /*input_signing_key=*/child_key,
751 /*output_destination=*/child_spk,
752 /*output_amount=*/child_value, /*submit=*/false);
753 CTransactionRef tx_child = MakeTransactionRef(mtx_child);
754 package_cpfp.push_back(tx_child);
755
756 // Package feerate is calculated using modified fees, and prioritisetransaction accepts negative
757 // fee deltas. This should be taken into account. De-prioritise the parent transaction
758 // to bring the package feerate to 0.
759 m_node.mempool->PrioritiseTransaction(tx_parent->GetHash(), child_value - coinbase_value);
760 {
761 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
762 const auto submit_cpfp_deprio = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
763 package_cpfp, /*test_accept=*/ false, /*client_maxfeerate=*/{});
764 if (auto err_cpfp_deprio{CheckPackageMempoolAcceptResult(package_cpfp, submit_cpfp_deprio, /*expect_valid=*/false, m_node.mempool.get())}) {
765 BOOST_ERROR(err_cpfp_deprio.value());
766 } else {
767 BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_state.GetResult(), PackageValidationResult::PCKG_TX);
768 BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_tx_results.find(tx_parent->GetWitnessHash())->second.m_state.GetResult(),
770 BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_tx_results.find(tx_child->GetWitnessHash())->second.m_state.GetResult(),
772 BOOST_CHECK(submit_cpfp_deprio.m_tx_results.find(tx_parent->GetWitnessHash())->second.m_state.GetRejectReason() == "min relay fee not met");
773 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
774 }
775 }
776
777 // Clear the prioritisation of the parent transaction.
778 WITH_LOCK(m_node.mempool->cs, m_node.mempool->ClearPrioritisation(tx_parent->GetHash()));
779
780 // Package CPFP: Even though the parent's feerate is below the mempool minimum feerate, the
781 // child pays enough for the package feerate to meet the threshold.
782 {
783 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
784 const auto submit_cpfp = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
785 package_cpfp, /*test_accept=*/ false, /*client_maxfeerate=*/{});
786 if (auto err_cpfp{CheckPackageMempoolAcceptResult(package_cpfp, submit_cpfp, /*expect_valid=*/true, m_node.mempool.get())}) {
787 BOOST_ERROR(err_cpfp.value());
788 } else {
789 auto it_parent = submit_cpfp.m_tx_results.find(tx_parent->GetWitnessHash());
790 auto it_child = submit_cpfp.m_tx_results.find(tx_child->GetWitnessHash());
791 BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
792 BOOST_CHECK(it_parent->second.m_base_fees.value() == coinbase_value - parent_value);
793 BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
794 BOOST_CHECK(it_child->second.m_base_fees.value() == COIN);
795
796 const CFeeRate expected_feerate(coinbase_value - child_value,
798 BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
799 BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
800 std::vector<Wtxid> expected_wtxids({tx_parent->GetWitnessHash(), tx_child->GetWitnessHash()});
801 BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
802 BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
803 BOOST_CHECK(expected_feerate.GetFeePerK() > 1000);
804 }
805 expected_pool_size += 2;
806 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
807 }
808
809 // Just because we allow low-fee parents doesn't mean we allow low-feerate packages.
810 // The mempool minimum feerate is 5sat/vB, but this package just pays 800 satoshis total.
811 // The child fees would be able to pay for itself, but isn't enough for the entire package.
812 Package package_still_too_low;
813 const CAmount parent_fee{200};
814 const CAmount child_fee{600};
815 auto mtx_parent_cheap = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,
816 /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
817 /*output_destination=*/parent_spk,
818 /*output_amount=*/coinbase_value - parent_fee, /*submit=*/false);
819 CTransactionRef tx_parent_cheap = MakeTransactionRef(mtx_parent_cheap);
820 package_still_too_low.push_back(tx_parent_cheap);
821 BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_parent_cheap)) > parent_fee);
822 BOOST_CHECK(m_node.mempool->m_opts.min_relay_feerate.GetFee(GetVirtualTransactionSize(*tx_parent_cheap)) <= parent_fee);
823
824 auto mtx_child_cheap = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent_cheap, /*input_vout=*/0,
825 /*input_height=*/101, /*input_signing_key=*/child_key,
826 /*output_destination=*/child_spk,
827 /*output_amount=*/coinbase_value - parent_fee - child_fee, /*submit=*/false);
828 CTransactionRef tx_child_cheap = MakeTransactionRef(mtx_child_cheap);
829 package_still_too_low.push_back(tx_child_cheap);
830 BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_child_cheap)) <= child_fee);
831 BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap)) > parent_fee + child_fee);
832 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
833
834 // Cheap package should fail for being too low fee.
835 {
836 const auto submit_package_too_low = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
837 package_still_too_low, /*test_accept=*/false, /*client_maxfeerate=*/{});
838 if (auto err_package_too_low{CheckPackageMempoolAcceptResult(package_still_too_low, submit_package_too_low, /*expect_valid=*/false, m_node.mempool.get())}) {
839 BOOST_ERROR(err_package_too_low.value());
840 } else {
841 // Individual feerate of parent is too low.
842 BOOST_CHECK_EQUAL(submit_package_too_low.m_tx_results.at(tx_parent_cheap->GetWitnessHash()).m_state.GetResult(),
844 BOOST_CHECK(submit_package_too_low.m_tx_results.at(tx_parent_cheap->GetWitnessHash()).m_effective_feerate.value() ==
845 CFeeRate(parent_fee, GetVirtualTransactionSize(*tx_parent_cheap)));
846 // Package feerate of parent + child is too low.
847 BOOST_CHECK_EQUAL(submit_package_too_low.m_tx_results.at(tx_child_cheap->GetWitnessHash()).m_state.GetResult(),
849 BOOST_CHECK(submit_package_too_low.m_tx_results.at(tx_child_cheap->GetWitnessHash()).m_effective_feerate.value() ==
850 CFeeRate(parent_fee + child_fee, GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap)));
851 }
852 BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetResult(), PackageValidationResult::PCKG_TX);
853 BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetRejectReason(), "transaction failed");
854 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
855 }
856
857 // Package feerate includes the modified fees of the transactions.
858 // This means a child with its fee delta from prioritisetransaction can pay for a parent.
859 m_node.mempool->PrioritiseTransaction(tx_child_cheap->GetHash(), 1 * COIN);
860 // Now that the child's fees have "increased" by 1 BTC, the cheap package should succeed.
861 {
862 const auto submit_prioritised_package = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
863 package_still_too_low, /*test_accept=*/false, /*client_maxfeerate=*/{});
864 if (auto err_prioritised{CheckPackageMempoolAcceptResult(package_still_too_low, submit_prioritised_package, /*expect_valid=*/true, m_node.mempool.get())}) {
865 BOOST_ERROR(err_prioritised.value());
866 } else {
867 const CFeeRate expected_feerate(1 * COIN + parent_fee + child_fee,
868 GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap));
869 BOOST_CHECK_EQUAL(submit_prioritised_package.m_tx_results.size(), package_still_too_low.size());
870 auto it_parent = submit_prioritised_package.m_tx_results.find(tx_parent_cheap->GetWitnessHash());
871 auto it_child = submit_prioritised_package.m_tx_results.find(tx_child_cheap->GetWitnessHash());
872 BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
873 BOOST_CHECK(it_parent->second.m_base_fees.value() == parent_fee);
874 BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
875 BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
876 BOOST_CHECK(it_child->second.m_base_fees.value() == child_fee);
877 BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
878 std::vector<Wtxid> expected_wtxids({tx_parent_cheap->GetWitnessHash(), tx_child_cheap->GetWitnessHash()});
879 BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
880 BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
881 }
882 expected_pool_size += 2;
883 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
884 }
885
886 // Package feerate is calculated without topology in mind; it's just aggregating fees and sizes.
887 // However, this should not allow parents to pay for children. Each transaction should be
888 // validated individually first, eliminating sufficient-feerate parents before they are unfairly
889 // included in the package feerate. It's also important that the low-fee child doesn't prevent
890 // the parent from being accepted.
891 Package package_rich_parent;
892 const CAmount high_parent_fee{1 * COIN};
893 auto mtx_parent_rich = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[2], /*input_vout=*/0,
894 /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
895 /*output_destination=*/parent_spk,
896 /*output_amount=*/coinbase_value - high_parent_fee, /*submit=*/false);
897 CTransactionRef tx_parent_rich = MakeTransactionRef(mtx_parent_rich);
898 package_rich_parent.push_back(tx_parent_rich);
899
900 auto mtx_child_poor = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent_rich, /*input_vout=*/0,
901 /*input_height=*/101, /*input_signing_key=*/child_key,
902 /*output_destination=*/child_spk,
903 /*output_amount=*/coinbase_value - high_parent_fee, /*submit=*/false);
904 CTransactionRef tx_child_poor = MakeTransactionRef(mtx_child_poor);
905 package_rich_parent.push_back(tx_child_poor);
906
907 // Parent pays 1 BTC and child pays none. The parent should be accepted without the child.
908 {
909 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
910 const auto submit_rich_parent = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
911 package_rich_parent, /*test_accept=*/false, /*client_maxfeerate=*/{});
912 if (auto err_rich_parent{CheckPackageMempoolAcceptResult(package_rich_parent, submit_rich_parent, /*expect_valid=*/false, m_node.mempool.get())}) {
913 BOOST_ERROR(err_rich_parent.value());
914 } else {
915 // The child would have been validated on its own and failed.
916 BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetResult(), PackageValidationResult::PCKG_TX);
917 BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetRejectReason(), "transaction failed");
918
919 auto it_parent = submit_rich_parent.m_tx_results.find(tx_parent_rich->GetWitnessHash());
920 auto it_child = submit_rich_parent.m_tx_results.find(tx_child_poor->GetWitnessHash());
921 BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
922 BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::INVALID);
923 BOOST_CHECK(it_parent->second.m_state.GetRejectReason() == "");
924 BOOST_CHECK_MESSAGE(it_parent->second.m_base_fees.value() == high_parent_fee,
925 strprintf("rich parent: expected fee %s, got %s", high_parent_fee, it_parent->second.m_base_fees.value()));
926 BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(high_parent_fee, GetVirtualTransactionSize(*tx_parent_rich)));
927 BOOST_CHECK_EQUAL(it_child->second.m_result_type, MempoolAcceptResult::ResultType::INVALID);
928 BOOST_CHECK_EQUAL(it_child->second.m_state.GetResult(), TxValidationResult::TX_MEMPOOL_POLICY);
929 BOOST_CHECK(it_child->second.m_state.GetRejectReason() == "min relay fee not met");
930 }
931 expected_pool_size += 1;
932 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
933 }
934}
935
937{
938 mineBlocks(5);
940 size_t expected_pool_size = m_node.mempool->size();
941 CKey child_key{GenerateRandomKey()};
942 CScript parent_spk = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey()));
943 CKey grandchild_key{GenerateRandomKey()};
944 CScript child_spk = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
945
946 const CAmount coinbase_value{50 * COIN};
947 // Test that de-duplication works. This is not actually package rbf.
948 {
949 // 1 parent paying 200sat, 1 child paying 300sat
950 Package package1;
951 // 1 parent paying 200sat, 1 child paying 500sat
952 Package package2;
953 // Package1 and package2 have the same parent. The children conflict.
954 auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
955 /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
956 /*output_destination=*/parent_spk,
957 /*output_amount=*/coinbase_value - low_fee_amt, /*submit=*/false);
958 CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
959 package1.push_back(tx_parent);
960 package2.push_back(tx_parent);
961
962 CTransactionRef tx_child_1 = MakeTransactionRef(CreateValidMempoolTransaction(tx_parent, 0, 101, child_key, child_spk, coinbase_value - low_fee_amt - 300, false));
963 package1.push_back(tx_child_1);
964 CTransactionRef tx_child_2 = MakeTransactionRef(CreateValidMempoolTransaction(tx_parent, 0, 101, child_key, child_spk, coinbase_value - low_fee_amt - 500, false));
965 package2.push_back(tx_child_2);
966
967 LOCK(m_node.mempool->cs);
968 const auto submit1 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package1, /*test_accept=*/false, std::nullopt);
969 if (auto err_1{CheckPackageMempoolAcceptResult(package1, submit1, /*expect_valid=*/true, m_node.mempool.get())}) {
970 BOOST_ERROR(err_1.value());
971 }
972
973 // Check precise ResultTypes and mempool size. We know it_parent_1 and it_child_1 exist from above call
974 auto it_parent_1 = submit1.m_tx_results.find(tx_parent->GetWitnessHash());
975 auto it_child_1 = submit1.m_tx_results.find(tx_child_1->GetWitnessHash());
976 BOOST_CHECK_EQUAL(it_parent_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
977 BOOST_CHECK_EQUAL(it_child_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
978 expected_pool_size += 2;
979 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
980
981 const auto submit2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package2, /*test_accept=*/false, std::nullopt);
982 if (auto err_2{CheckPackageMempoolAcceptResult(package2, submit2, /*expect_valid=*/true, m_node.mempool.get())}) {
983 BOOST_ERROR(err_2.value());
984 }
985
986 // Check precise ResultTypes and mempool size. We know it_parent_2 and it_child_2 exist from above call
987 auto it_parent_2 = submit2.m_tx_results.find(tx_parent->GetWitnessHash());
988 auto it_child_2 = submit2.m_tx_results.find(tx_child_2->GetWitnessHash());
989 BOOST_CHECK_EQUAL(it_parent_2->second.m_result_type, MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
990 BOOST_CHECK_EQUAL(it_child_2->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
991 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
992
993 // child1 has been replaced
994 BOOST_CHECK(!m_node.mempool->exists(GenTxid::Txid(tx_child_1->GetHash())));
995 }
996
997 // Test package rbf.
998 {
999 CTransactionRef tx_parent_1 = MakeTransactionRef(CreateValidMempoolTransaction(
1000 m_coinbase_txns[1], /*input_vout=*/0, /*input_height=*/0,
1001 coinbaseKey, parent_spk, coinbase_value - 200, /*submit=*/false));
1002 CTransactionRef tx_child_1 = MakeTransactionRef(CreateValidMempoolTransaction(
1003 tx_parent_1, /*input_vout=*/0, /*input_height=*/101,
1004 child_key, child_spk, coinbase_value - 400, /*submit=*/false));
1005
1006 CTransactionRef tx_parent_2 = MakeTransactionRef(CreateValidMempoolTransaction(
1007 m_coinbase_txns[1], /*input_vout=*/0, /*input_height=*/0,
1008 coinbaseKey, parent_spk, coinbase_value - 800, /*submit=*/false));
1009 CTransactionRef tx_child_2 = MakeTransactionRef(CreateValidMempoolTransaction(
1010 tx_parent_2, /*input_vout=*/0, /*input_height=*/101,
1011 child_key, child_spk, coinbase_value - 800 - 200, /*submit=*/false));
1012
1013 CTransactionRef tx_parent_3 = MakeTransactionRef(CreateValidMempoolTransaction(
1014 m_coinbase_txns[1], /*input_vout=*/0, /*input_height=*/0,
1015 coinbaseKey, parent_spk, coinbase_value - 199, /*submit=*/false));
1016 CTransactionRef tx_child_3 = MakeTransactionRef(CreateValidMempoolTransaction(
1017 tx_parent_3, /*input_vout=*/0, /*input_height=*/101,
1018 child_key, child_spk, coinbase_value - 199 - 1300, /*submit=*/false));
1019
1020 // In all packages, the parents conflict with each other
1021 BOOST_CHECK(tx_parent_1->GetHash() != tx_parent_2->GetHash() && tx_parent_2->GetHash() != tx_parent_3->GetHash());
1022
1023 // 1 parent paying 200sat, 1 child paying 200sat.
1024 Package package1{tx_parent_1, tx_child_1};
1025 // 1 parent paying 800sat, 1 child paying 200sat.
1026 Package package2{tx_parent_2, tx_child_2};
1027 // 1 parent paying 199sat, 1 child paying 1300sat.
1028 Package package3{tx_parent_3, tx_child_3};
1029
1030 const auto submit1 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package1, false, std::nullopt);
1031 if (auto err_1{CheckPackageMempoolAcceptResult(package1, submit1, /*expect_valid=*/true, m_node.mempool.get())}) {
1032 BOOST_ERROR(err_1.value());
1033 }
1034 auto it_parent_1 = submit1.m_tx_results.find(tx_parent_1->GetWitnessHash());
1035 auto it_child_1 = submit1.m_tx_results.find(tx_child_1->GetWitnessHash());
1036 BOOST_CHECK_EQUAL(it_parent_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1037 BOOST_CHECK_EQUAL(it_child_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1038 expected_pool_size += 2;
1039 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
1040
1041 // This replacement is actually not package rbf; the parent carries enough fees
1042 // to replace the entire package on its own.
1043 const auto submit2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package2, false, std::nullopt);
1044 if (auto err_2{CheckPackageMempoolAcceptResult(package2, submit2, /*expect_valid=*/true, m_node.mempool.get())}) {
1045 BOOST_ERROR(err_2.value());
1046 }
1047 auto it_parent_2 = submit2.m_tx_results.find(tx_parent_2->GetWitnessHash());
1048 auto it_child_2 = submit2.m_tx_results.find(tx_child_2->GetWitnessHash());
1049 BOOST_CHECK_EQUAL(it_parent_2->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1050 BOOST_CHECK_EQUAL(it_child_2->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1051 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
1052
1053 // Package RBF, in which the replacement transaction's child sponsors the fees to meet RBF feerate rules
1054 const auto submit3 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package3, false, std::nullopt);
1055 if (auto err_3{CheckPackageMempoolAcceptResult(package3, submit3, /*expect_valid=*/true, m_node.mempool.get())}) {
1056 BOOST_ERROR(err_3.value());
1057 }
1058 auto it_parent_3 = submit3.m_tx_results.find(tx_parent_3->GetWitnessHash());
1059 auto it_child_3 = submit3.m_tx_results.find(tx_child_3->GetWitnessHash());
1060 BOOST_CHECK_EQUAL(it_parent_3->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1061 BOOST_CHECK_EQUAL(it_child_3->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1062
1063 // package3 was considered as a package to replace both package2 transactions
1064 BOOST_CHECK(it_parent_3->second.m_replaced_transactions.size() == 2);
1065 BOOST_CHECK(it_child_3->second.m_replaced_transactions.empty());
1066
1067 std::vector<Wtxid> expected_package3_wtxids({tx_parent_3->GetWitnessHash(), tx_child_3->GetWitnessHash()});
1068 const auto package3_total_vsize{GetVirtualTransactionSize(*tx_parent_3) + GetVirtualTransactionSize(*tx_child_3)};
1069 BOOST_CHECK(it_parent_3->second.m_wtxids_fee_calculations.value() == expected_package3_wtxids);
1070 BOOST_CHECK(it_child_3->second.m_wtxids_fee_calculations.value() == expected_package3_wtxids);
1071 BOOST_CHECK_EQUAL(it_parent_3->second.m_effective_feerate.value().GetFee(package3_total_vsize), 199 + 1300);
1072 BOOST_CHECK_EQUAL(it_child_3->second.m_effective_feerate.value().GetFee(package3_total_vsize), 199 + 1300);
1073
1074 BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
1075 }
1076
1077}
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
int64_t CAmount
Amount in satoshis (Can be negative)
Definition amount.h:12
static constexpr CAmount COIN
The amount of satoshis in one BTC.
Definition amount.h:15
node::NodeContext m_node
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
Definition feerate.h:33
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
Definition feerate.h:63
An encapsulated private key.
Definition key.h:35
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition key.cpp:182
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition transaction.h:29
Serialized script, used inside transaction inputs and outputs.
Definition script.h:414
The basic transaction that is broadcasted on the network and contained in blocks.
const Wtxid & GetWitnessHash() const LIFETIMEBOUND
const Txid & GetHash() const LIFETIMEBOUND
Double ended buffer combining vector and stream-like interfaces.
Definition streams.h:147
Fast randomness source.
Definition random.h:377
static GenTxid Txid(const uint256 &hash)
A writer stream (for serialization) that computes a 256-bit hash.
Definition hash.h:101
std::string GetRejectReason() const
Definition validation.h:126
Result GetResult() const
Definition validation.h:125
iterator begin()
Definition prevector.h:304
iterator end()
Definition prevector.h:306
transaction_identifier represents the two canonical transaction identifier types (txid,...
static transaction_identifier FromUint256(const uint256 &id)
static std::optional< transaction_identifier > FromHex(std::string_view hex)
256-bit opaque blob.
Definition uint256.h:178
static int32_t GetTransactionWeight(const CTransaction &tx)
Definition validation.h:149
@ TX_MISSING_INPUTS
transaction was missing some of its inputs
@ TX_MEMPOOL_POLICY
violated mempool's fee/size/descendant/RBF/etc limits
@ TX_WITNESS_MUTATED
Transaction might have a witness prior to SegWit activation, or witness may have been malleated (whic...
@ TX_RECONSIDERABLE
fails some policy, but might be acceptable if submitted in a (different) package
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition cs_main.cpp:8
BOOST_AUTO_TEST_SUITE(cuckoocache_tests)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
CKey GenerateRandomKey(bool compressed) noexcept
Definition key.cpp:352
#define BOOST_CHECK_EQUAL(v1, v2)
Definition object.cpp:18
#define BOOST_CHECK(expr)
Definition object.cpp:17
bool IsChildWithParents(const Package &package)
Context-free check that a package is exactly one child and its parents; not all parents need to be pr...
Definition packages.cpp:119
bool IsConsistentPackage(const Package &txns)
Checks that these transactions don't conflict, i.e., spend the same prevout.
Definition packages.cpp:52
bool IsWellFormedPackage(const Package &txns, PackageValidationState &state, bool require_sorted)
Context-free package policy checks:
Definition packages.cpp:79
bool IsChildWithParentsTree(const Package &package)
Context-free check that a package IsChildWithParents() and none of the parents depend on each other (...
Definition packages.cpp:136
uint256 GetPackageHash(const std::vector< CTransactionRef > &transactions)
Get the hash of these transactions' wtxids, concatenated in lexicographical order (treating the wtxid...
Definition packages.cpp:151
bool IsTopoSortedPackage(const Package &txns, std::unordered_set< uint256, SaltedTxidHasher > &later_txids)
IsTopoSortedPackage where a set of txids has been pre-populated.
Definition packages.cpp:19
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
Definition packages.h:50
static constexpr uint32_t MAX_PACKAGE_WEIGHT
Default maximum total weight of transactions in a package in weight to allow for context-less checks.
Definition packages.h:24
static constexpr uint32_t MAX_PACKAGE_COUNT
Default maximum number of transactions in a package.
Definition packages.h:19
@ PCKG_POLICY
The package itself is invalid (e.g. too many transactions).
@ PCKG_TX
At least one tx is invalid.
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost, unsigned int bytes_per_sigop)
Compute the virtual transaction size (weight reinterpreted as bytes).
Definition policy.cpp:300
static constexpr unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT_KVB
Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors.
Definition policy.h:61
static constexpr TransactionSerParams TX_WITH_WITNESS
static CTransactionRef MakeTransactionRef(Tx &&txIn)
std::shared_ptr< const CTransaction > CTransactionRef
@ OP_TRUE
Definition script.h:83
@ OP_DROP
Definition script.h:123
std::vector< unsigned char > ToByteVector(const T &in)
Definition script.h:66
constexpr deserialize_type deserialize
Definition serialize.h:49
static constexpr CAmount CENT
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
A mutable version of CTransaction.
std::vector< CTxOut > vout
std::vector< CTxIn > vin
std::vector< std::vector< unsigned char > > stack
Definition script.h:577
Validation result for a transaction evaluated by MemPoolAccept (single or package).
Definition validation.h:128
const ResultType m_result_type
Result type.
Definition validation.h:137
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
std::unique_ptr< CTxMemPool > mempool
Definition context.h:65
std::unique_ptr< ChainstateManager > chainman
Definition context.h:69
#define LOCK(cs)
Definition sync.h:257
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition sync.h:301
static uint256 InsecureRand256()
Definition random.h:35
static const CScript P2WSH_OP_TRUE
Definition script.h:12
std::optional< std::string > CheckPackageMempoolAcceptResult(const Package &txns, const PackageMempoolAcceptResult &result, bool expect_valid, const CTxMemPool *mempool)
Check expected properties for every PackageMempoolAcceptResult, regardless of value.
Definition txmempool.cpp:43
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
static const CAmount low_fee_amt
BOOST_FIXTURE_TEST_CASE(package_hash_tests, TestChain100Setup)
CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outputs)
PackageMempoolAcceptResult ProcessNewPackage(Chainstate &active_chainstate, CTxMemPool &pool, const Package &package, bool test_accept, const std::optional< CFeeRate > &client_maxfeerate)
Validate (and maybe submit) a package to the mempool.