Bitcoin Core  24.99.0
P2P Digital Currency
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 
5 #include <consensus/validation.h>
6 #include <key_io.h>
7 #include <policy/packages.h>
8 #include <policy/policy.h>
10 #include <script/script.h>
11 #include <script/standard.h>
12 #include <test/util/random.h>
13 #include <test/util/setup_common.h>
14 #include <validation.h>
15 
16 #include <boost/test/unit_test.hpp>
17 
18 BOOST_AUTO_TEST_SUITE(txpackage_tests)
19 
20 // Create placeholder transactions that have no meaning.
21 inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outputs)
22 {
24  mtx.vin.resize(num_inputs);
25  mtx.vout.resize(num_outputs);
26  auto random_script = CScript() << ToByteVector(InsecureRand256()) << ToByteVector(InsecureRand256());
27  for (size_t i{0}; i < num_inputs; ++i) {
28  mtx.vin[i].prevout.hash = InsecureRand256();
29  mtx.vin[i].prevout.n = 0;
30  mtx.vin[i].scriptSig = random_script;
31  }
32  for (size_t o{0}; o < num_outputs; ++o) {
33  mtx.vout[o].nValue = 1 * CENT;
34  mtx.vout[o].scriptPubKey = random_script;
35  }
36  return MakeTransactionRef(mtx);
37 }
38 
39 BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup)
40 {
41  // Packages can't have more than 25 transactions.
42  Package package_too_many;
43  package_too_many.reserve(MAX_PACKAGE_COUNT + 1);
44  for (size_t i{0}; i < MAX_PACKAGE_COUNT + 1; ++i) {
45  package_too_many.emplace_back(create_placeholder_tx(1, 1));
46  }
47  PackageValidationState state_too_many;
48  BOOST_CHECK(!CheckPackage(package_too_many, state_too_many));
50  BOOST_CHECK_EQUAL(state_too_many.GetRejectReason(), "package-too-many-transactions");
51 
52  // Packages can't have a total size of more than 101KvB.
53  CTransactionRef large_ptx = create_placeholder_tx(150, 150);
54  Package package_too_large;
55  auto size_large = GetVirtualTransactionSize(*large_ptx);
56  size_t total_size{0};
57  while (total_size <= MAX_PACKAGE_SIZE * 1000) {
58  package_too_large.push_back(large_ptx);
59  total_size += size_large;
60  }
61  BOOST_CHECK(package_too_large.size() <= MAX_PACKAGE_COUNT);
62  PackageValidationState state_too_large;
63  BOOST_CHECK(!CheckPackage(package_too_large, state_too_large));
65  BOOST_CHECK_EQUAL(state_too_large.GetRejectReason(), "package-too-large");
66 }
67 
68 BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup)
69 {
70  LOCK(cs_main);
71  unsigned int initialPoolSize = m_node.mempool->size();
72 
73  // Parent and Child Package
74  CKey parent_key;
75  parent_key.MakeNewKey(true);
76  CScript parent_locking_script = GetScriptForDestination(PKHash(parent_key.GetPubKey()));
77  auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
78  /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
79  /*output_destination=*/parent_locking_script,
80  /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
81  CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
82 
83  CKey child_key;
84  child_key.MakeNewKey(true);
85  CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey()));
86  auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
87  /*input_height=*/101, /*input_signing_key=*/parent_key,
88  /*output_destination=*/child_locking_script,
89  /*output_amount=*/CAmount(48 * COIN), /*submit=*/false);
90  CTransactionRef tx_child = MakeTransactionRef(mtx_child);
91  const auto result_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, {tx_parent, tx_child}, /*test_accept=*/true);
92  BOOST_CHECK_MESSAGE(result_parent_child.m_state.IsValid(),
93  "Package validation unexpectedly failed: " << result_parent_child.m_state.GetRejectReason());
94  BOOST_CHECK(result_parent_child.m_tx_results.size() == 2);
95  auto it_parent = result_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
96  auto it_child = result_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
97  BOOST_CHECK(it_parent != result_parent_child.m_tx_results.end());
98  BOOST_CHECK_MESSAGE(it_parent->second.m_state.IsValid(),
99  "Package validation unexpectedly failed: " << it_parent->second.m_state.GetRejectReason());
100  BOOST_CHECK(it_parent->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_parent)) == COIN);
101  BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
102  BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
103  BOOST_CHECK(it_child != result_parent_child.m_tx_results.end());
104  BOOST_CHECK_MESSAGE(it_child->second.m_state.IsValid(),
105  "Package validation unexpectedly failed: " << it_child->second.m_state.GetRejectReason());
106  BOOST_CHECK(it_child->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_child)) == COIN);
107  BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1);
108  BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
109 
110  // A single, giant transaction submitted through ProcessNewPackage fails on single tx policy.
111  CTransactionRef giant_ptx = create_placeholder_tx(999, 999);
113  auto result_single_large = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, {giant_ptx}, /*test_accept=*/true);
114  BOOST_CHECK(result_single_large.m_state.IsInvalid());
115  BOOST_CHECK_EQUAL(result_single_large.m_state.GetResult(), PackageValidationResult::PCKG_TX);
116  BOOST_CHECK_EQUAL(result_single_large.m_state.GetRejectReason(), "transaction failed");
117  BOOST_CHECK(result_single_large.m_tx_results.size() == 1);
118  auto it_giant_tx = result_single_large.m_tx_results.find(giant_ptx->GetWitnessHash());
119  BOOST_CHECK(it_giant_tx != result_single_large.m_tx_results.end());
120  BOOST_CHECK_EQUAL(it_giant_tx->second.m_state.GetRejectReason(), "tx-size");
121 
122  // Check that mempool size hasn't changed.
123  BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize);
124 }
125 
126 BOOST_FIXTURE_TEST_CASE(noncontextual_package_tests, TestChain100Setup)
127 {
128  // The signatures won't be verified so we can just use a placeholder
129  CKey placeholder_key;
130  placeholder_key.MakeNewKey(true);
131  CScript spk = GetScriptForDestination(PKHash(placeholder_key.GetPubKey()));
132  CKey placeholder_key_2;
133  placeholder_key_2.MakeNewKey(true);
134  CScript spk2 = GetScriptForDestination(PKHash(placeholder_key_2.GetPubKey()));
135 
136  // Parent and Child Package
137  {
138  auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0, 0, coinbaseKey, spk,
139  CAmount(49 * COIN), /*submit=*/false);
140  CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
141 
142  auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0, 101, placeholder_key, spk2,
143  CAmount(48 * COIN), /*submit=*/false);
144  CTransactionRef tx_child = MakeTransactionRef(mtx_child);
145 
147  BOOST_CHECK(CheckPackage({tx_parent, tx_child}, state));
148  BOOST_CHECK(!CheckPackage({tx_child, tx_parent}, state));
150  BOOST_CHECK_EQUAL(state.GetRejectReason(), "package-not-sorted");
151  BOOST_CHECK(IsChildWithParents({tx_parent, tx_child}));
152  }
153 
154  // 24 Parents and 1 Child
155  {
156  Package package;
157  CMutableTransaction child;
158  for (int i{0}; i < 24; ++i) {
159  auto parent = MakeTransactionRef(CreateValidMempoolTransaction(m_coinbase_txns[i + 1],
160  0, 0, coinbaseKey, spk, CAmount(48 * COIN), false));
161  package.emplace_back(parent);
162  child.vin.push_back(CTxIn(COutPoint(parent->GetHash(), 0)));
163  }
164  child.vout.push_back(CTxOut(47 * COIN, spk2));
165 
166  // The child must be in the package.
167  BOOST_CHECK(!IsChildWithParents(package));
168 
169  // The parents can be in any order.
170  FastRandomContext rng;
171  Shuffle(package.begin(), package.end(), rng);
172  package.push_back(MakeTransactionRef(child));
173 
175  BOOST_CHECK(CheckPackage(package, state));
177 
178  package.erase(package.begin());
180 
181  // The package cannot have unrelated transactions.
182  package.insert(package.begin(), m_coinbase_txns[0]);
183  BOOST_CHECK(!IsChildWithParents(package));
184  }
185 
186  // 2 Parents and 1 Child where one parent depends on the other.
187  {
188  CMutableTransaction mtx_parent;
189  mtx_parent.vin.push_back(CTxIn(COutPoint(m_coinbase_txns[0]->GetHash(), 0)));
190  mtx_parent.vout.push_back(CTxOut(20 * COIN, spk));
191  mtx_parent.vout.push_back(CTxOut(20 * COIN, spk2));
192  CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
193 
194  CMutableTransaction mtx_parent_also_child;
195  mtx_parent_also_child.vin.push_back(CTxIn(COutPoint(tx_parent->GetHash(), 0)));
196  mtx_parent_also_child.vout.push_back(CTxOut(20 * COIN, spk));
197  CTransactionRef tx_parent_also_child = MakeTransactionRef(mtx_parent_also_child);
198 
199  CMutableTransaction mtx_child;
200  mtx_child.vin.push_back(CTxIn(COutPoint(tx_parent->GetHash(), 1)));
201  mtx_child.vin.push_back(CTxIn(COutPoint(tx_parent_also_child->GetHash(), 0)));
202  mtx_child.vout.push_back(CTxOut(39 * COIN, spk));
203  CTransactionRef tx_child = MakeTransactionRef(mtx_child);
204 
206  BOOST_CHECK(IsChildWithParents({tx_parent, tx_parent_also_child}));
207  BOOST_CHECK(IsChildWithParents({tx_parent, tx_child}));
208  BOOST_CHECK(IsChildWithParents({tx_parent, tx_parent_also_child, tx_child}));
209  // IsChildWithParents does not detect unsorted parents.
210  BOOST_CHECK(IsChildWithParents({tx_parent_also_child, tx_parent, tx_child}));
211  BOOST_CHECK(CheckPackage({tx_parent, tx_parent_also_child, tx_child}, state));
212  BOOST_CHECK(!CheckPackage({tx_parent_also_child, tx_parent, tx_child}, state));
214  BOOST_CHECK_EQUAL(state.GetRejectReason(), "package-not-sorted");
215  }
216 }
217 
218 BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup)
219 {
220  LOCK(cs_main);
221  unsigned int expected_pool_size = m_node.mempool->size();
222  CKey parent_key;
223  parent_key.MakeNewKey(true);
224  CScript parent_locking_script = GetScriptForDestination(PKHash(parent_key.GetPubKey()));
225 
226  // Unrelated transactions are not allowed in package submission.
227  Package package_unrelated;
228  for (size_t i{0}; i < 10; ++i) {
229  auto mtx = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[i + 25], /*input_vout=*/0,
230  /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
231  /*output_destination=*/parent_locking_script,
232  /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
233  package_unrelated.emplace_back(MakeTransactionRef(mtx));
234  }
235  auto result_unrelated_submit = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
236  package_unrelated, /*test_accept=*/false);
237  BOOST_CHECK(result_unrelated_submit.m_state.IsInvalid());
238  BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
239  BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetRejectReason(), "package-not-child-with-parents");
240  BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
241 
242  // Parent and Child (and Grandchild) Package
243  Package package_parent_child;
244  Package package_3gen;
245  auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
246  /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
247  /*output_destination=*/parent_locking_script,
248  /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
249  CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
250  package_parent_child.push_back(tx_parent);
251  package_3gen.push_back(tx_parent);
252 
253  CKey child_key;
254  child_key.MakeNewKey(true);
255  CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey()));
256  auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
257  /*input_height=*/101, /*input_signing_key=*/parent_key,
258  /*output_destination=*/child_locking_script,
259  /*output_amount=*/CAmount(48 * COIN), /*submit=*/false);
260  CTransactionRef tx_child = MakeTransactionRef(mtx_child);
261  package_parent_child.push_back(tx_child);
262  package_3gen.push_back(tx_child);
263 
264  CKey grandchild_key;
265  grandchild_key.MakeNewKey(true);
266  CScript grandchild_locking_script = GetScriptForDestination(PKHash(grandchild_key.GetPubKey()));
267  auto mtx_grandchild = CreateValidMempoolTransaction(/*input_transaction=*/tx_child, /*input_vout=*/0,
268  /*input_height=*/101, /*input_signing_key=*/child_key,
269  /*output_destination=*/grandchild_locking_script,
270  /*output_amount=*/CAmount(47 * COIN), /*submit=*/false);
271  CTransactionRef tx_grandchild = MakeTransactionRef(mtx_grandchild);
272  package_3gen.push_back(tx_grandchild);
273 
274  // 3 Generations is not allowed.
275  {
276  auto result_3gen_submit = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
277  package_3gen, /*test_accept=*/false);
278  BOOST_CHECK(result_3gen_submit.m_state.IsInvalid());
279  BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
280  BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetRejectReason(), "package-not-child-with-parents");
281  BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
282  }
283 
284  // Parent and child package where transactions are invalid for reasons other than fee and
285  // missing inputs, so the package validation isn't expected to happen.
286  {
287  CScriptWitness bad_witness;
288  bad_witness.stack.push_back(std::vector<unsigned char>(1));
289  CMutableTransaction mtx_parent_invalid{mtx_parent};
290  mtx_parent_invalid.vin[0].scriptWitness = bad_witness;
291  CTransactionRef tx_parent_invalid = MakeTransactionRef(mtx_parent_invalid);
292  auto result_quit_early = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
293  {tx_parent_invalid, tx_child}, /*test_accept=*/ false);
294  BOOST_CHECK(result_quit_early.m_state.IsInvalid());
295  BOOST_CHECK_EQUAL(result_quit_early.m_state.GetResult(), PackageValidationResult::PCKG_TX);
296  BOOST_CHECK(!result_quit_early.m_tx_results.empty());
297  BOOST_CHECK_EQUAL(result_quit_early.m_tx_results.size(), 2);
298  auto it_parent = result_quit_early.m_tx_results.find(tx_parent_invalid->GetWitnessHash());
299  auto it_child = result_quit_early.m_tx_results.find(tx_child->GetWitnessHash());
300  BOOST_CHECK(it_parent != result_quit_early.m_tx_results.end());
301  BOOST_CHECK(it_child != result_quit_early.m_tx_results.end());
302  BOOST_CHECK_EQUAL(it_parent->second.m_state.GetResult(), TxValidationResult::TX_WITNESS_MUTATED);
303  BOOST_CHECK_EQUAL(it_parent->second.m_state.GetRejectReason(), "bad-witness-nonstandard");
304  BOOST_CHECK_EQUAL(it_child->second.m_state.GetResult(), TxValidationResult::TX_MISSING_INPUTS);
305  BOOST_CHECK_EQUAL(it_child->second.m_state.GetRejectReason(), "bad-txns-inputs-missingorspent");
306  }
307 
308  // Child with missing parent.
309  mtx_child.vin.push_back(CTxIn(COutPoint(package_unrelated[0]->GetHash(), 0)));
310  Package package_missing_parent;
311  package_missing_parent.push_back(tx_parent);
312  package_missing_parent.push_back(MakeTransactionRef(mtx_child));
313  {
314  const auto result_missing_parent = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
315  package_missing_parent, /*test_accept=*/false);
316  BOOST_CHECK(result_missing_parent.m_state.IsInvalid());
317  BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
318  BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetRejectReason(), "package-not-child-with-unconfirmed-parents");
319  BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
320  }
321 
322  // Submit package with parent + child.
323  {
324  const auto submit_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
325  package_parent_child, /*test_accept=*/false);
326  expected_pool_size += 2;
327  BOOST_CHECK_MESSAGE(submit_parent_child.m_state.IsValid(),
328  "Package validation unexpectedly failed: " << submit_parent_child.m_state.GetRejectReason());
329  BOOST_CHECK_EQUAL(submit_parent_child.m_tx_results.size(), package_parent_child.size());
330  auto it_parent = submit_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
331  auto it_child = submit_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
332  BOOST_CHECK(it_parent != submit_parent_child.m_tx_results.end());
333  BOOST_CHECK(it_parent->second.m_state.IsValid());
334  BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_parent)));
335  BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
336  BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
337  BOOST_CHECK(it_child != submit_parent_child.m_tx_results.end());
338  BOOST_CHECK(it_child->second.m_state.IsValid());
339  BOOST_CHECK(it_child->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_child)));
340  BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1);
341  BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
342 
343  BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
344  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_parent->GetHash())));
345  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_child->GetHash())));
346  }
347 
348  // Already-in-mempool transactions should be detected and de-duplicated.
349  {
350  const auto submit_deduped = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
351  package_parent_child, /*test_accept=*/false);
352  BOOST_CHECK_MESSAGE(submit_deduped.m_state.IsValid(),
353  "Package validation unexpectedly failed: " << submit_deduped.m_state.GetRejectReason());
354  BOOST_CHECK_EQUAL(submit_deduped.m_tx_results.size(), package_parent_child.size());
355  auto it_parent_deduped = submit_deduped.m_tx_results.find(tx_parent->GetWitnessHash());
356  auto it_child_deduped = submit_deduped.m_tx_results.find(tx_child->GetWitnessHash());
357  BOOST_CHECK(it_parent_deduped != submit_deduped.m_tx_results.end());
358  BOOST_CHECK(it_parent_deduped->second.m_state.IsValid());
359  BOOST_CHECK(it_parent_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
360  BOOST_CHECK(it_child_deduped != submit_deduped.m_tx_results.end());
361  BOOST_CHECK(it_child_deduped->second.m_state.IsValid());
362  BOOST_CHECK(it_child_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
363 
364  BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
365  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_parent->GetHash())));
366  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_child->GetHash())));
367  }
368 }
369 
370 // Tests for packages containing transactions that have same-txid-different-witness equivalents in
371 // the mempool.
372 BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
373 {
374  // Mine blocks to mature coinbases.
375  mineBlocks(5);
376  LOCK(cs_main);
377 
378  // Transactions with a same-txid-different-witness transaction in the mempool should be ignored,
379  // and the mempool entry's wtxid returned.
380  CScript witnessScript = CScript() << OP_DROP << OP_TRUE;
381  CScript scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
382  auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
383  /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
384  /*output_destination=*/scriptPubKey,
385  /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
386  CTransactionRef ptx_parent = MakeTransactionRef(mtx_parent);
387 
388  // Make two children with the same txid but different witnesses.
389  CScriptWitness witness1;
390  witness1.stack.push_back(std::vector<unsigned char>(1));
391  witness1.stack.push_back(std::vector<unsigned char>(witnessScript.begin(), witnessScript.end()));
392 
393  CScriptWitness witness2(witness1);
394  witness2.stack.push_back(std::vector<unsigned char>(2));
395  witness2.stack.push_back(std::vector<unsigned char>(witnessScript.begin(), witnessScript.end()));
396 
397  CKey child_key;
398  child_key.MakeNewKey(true);
399  CScript child_locking_script = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey()));
400  CMutableTransaction mtx_child1;
401  mtx_child1.nVersion = 1;
402  mtx_child1.vin.resize(1);
403  mtx_child1.vin[0].prevout.hash = ptx_parent->GetHash();
404  mtx_child1.vin[0].prevout.n = 0;
405  mtx_child1.vin[0].scriptSig = CScript();
406  mtx_child1.vin[0].scriptWitness = witness1;
407  mtx_child1.vout.resize(1);
408  mtx_child1.vout[0].nValue = CAmount(48 * COIN);
409  mtx_child1.vout[0].scriptPubKey = child_locking_script;
410 
411  CMutableTransaction mtx_child2{mtx_child1};
412  mtx_child2.vin[0].scriptWitness = witness2;
413 
414  CTransactionRef ptx_child1 = MakeTransactionRef(mtx_child1);
415  CTransactionRef ptx_child2 = MakeTransactionRef(mtx_child2);
416 
417  // child1 and child2 have the same txid
418  BOOST_CHECK_EQUAL(ptx_child1->GetHash(), ptx_child2->GetHash());
419  // child1 and child2 have different wtxids
420  BOOST_CHECK(ptx_child1->GetWitnessHash() != ptx_child2->GetWitnessHash());
421 
422  // Try submitting Package1{parent, child1} and Package2{parent, child2} where the children are
423  // same-txid-different-witness.
424  {
425  const auto submit_witness1 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
426  {ptx_parent, ptx_child1}, /*test_accept=*/false);
427  BOOST_CHECK_MESSAGE(submit_witness1.m_state.IsValid(),
428  "Package validation unexpectedly failed: " << submit_witness1.m_state.GetRejectReason());
429  BOOST_CHECK_EQUAL(submit_witness1.m_tx_results.size(), 2);
430  auto it_parent1 = submit_witness1.m_tx_results.find(ptx_parent->GetWitnessHash());
431  auto it_child1 = submit_witness1.m_tx_results.find(ptx_child1->GetWitnessHash());
432  BOOST_CHECK(it_parent1 != submit_witness1.m_tx_results.end());
433  BOOST_CHECK_MESSAGE(it_parent1->second.m_state.IsValid(),
434  "Transaction unexpectedly failed: " << it_parent1->second.m_state.GetRejectReason());
435  BOOST_CHECK(it_child1 != submit_witness1.m_tx_results.end());
436  BOOST_CHECK_MESSAGE(it_child1->second.m_state.IsValid(),
437  "Transaction unexpectedly failed: " << it_child1->second.m_state.GetRejectReason());
438 
439  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_parent->GetHash())));
440  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_child1->GetHash())));
441 
442  // Child2 would have been validated individually.
443  const auto submit_witness2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
444  {ptx_parent, ptx_child2}, /*test_accept=*/false);
445  BOOST_CHECK_MESSAGE(submit_witness2.m_state.IsValid(),
446  "Package validation unexpectedly failed: " << submit_witness2.m_state.GetRejectReason());
447  BOOST_CHECK_EQUAL(submit_witness2.m_tx_results.size(), 2);
448  auto it_parent2_deduped = submit_witness2.m_tx_results.find(ptx_parent->GetWitnessHash());
449  auto it_child2 = submit_witness2.m_tx_results.find(ptx_child2->GetWitnessHash());
450  BOOST_CHECK(it_parent2_deduped != submit_witness2.m_tx_results.end());
451  BOOST_CHECK(it_parent2_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
452  BOOST_CHECK(it_child2 != submit_witness2.m_tx_results.end());
453  BOOST_CHECK(it_child2->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS);
454  BOOST_CHECK_EQUAL(ptx_child1->GetWitnessHash(), it_child2->second.m_other_wtxid.value());
455 
456  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_child2->GetHash())));
457  BOOST_CHECK(!m_node.mempool->exists(GenTxid::Wtxid(ptx_child2->GetWitnessHash())));
458 
459  // Deduplication should work when wtxid != txid. Submit package with the already-in-mempool
460  // transactions again, which should not fail.
461  const auto submit_segwit_dedup = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
462  {ptx_parent, ptx_child1}, /*test_accept=*/false);
463  BOOST_CHECK_MESSAGE(submit_segwit_dedup.m_state.IsValid(),
464  "Package validation unexpectedly failed: " << submit_segwit_dedup.m_state.GetRejectReason());
465  BOOST_CHECK_EQUAL(submit_segwit_dedup.m_tx_results.size(), 2);
466  auto it_parent_dup = submit_segwit_dedup.m_tx_results.find(ptx_parent->GetWitnessHash());
467  auto it_child_dup = submit_segwit_dedup.m_tx_results.find(ptx_child1->GetWitnessHash());
468  BOOST_CHECK(it_parent_dup->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
469  BOOST_CHECK(it_child_dup->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
470  }
471 
472  // Try submitting Package1{child2, grandchild} where child2 is same-txid-different-witness as
473  // the in-mempool transaction, child1. Since child1 exists in the mempool and its outputs are
474  // available, child2 should be ignored and grandchild should be accepted.
475  //
476  // This tests a potential censorship vector in which an attacker broadcasts a competing package
477  // where a parent's witness is mutated. The honest package should be accepted despite the fact
478  // that we don't allow witness replacement.
479  CKey grandchild_key;
480  grandchild_key.MakeNewKey(true);
481  CScript grandchild_locking_script = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
482  auto mtx_grandchild = CreateValidMempoolTransaction(/*input_transaction=*/ptx_child2, /*input_vout=*/0,
483  /*input_height=*/0, /*input_signing_key=*/child_key,
484  /*output_destination=*/grandchild_locking_script,
485  /*output_amount=*/CAmount(47 * COIN), /*submit=*/false);
486  CTransactionRef ptx_grandchild = MakeTransactionRef(mtx_grandchild);
487 
488  // We already submitted child1 above.
489  {
490  const auto submit_spend_ignored = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
491  {ptx_child2, ptx_grandchild}, /*test_accept=*/false);
492  BOOST_CHECK_MESSAGE(submit_spend_ignored.m_state.IsValid(),
493  "Package validation unexpectedly failed: " << submit_spend_ignored.m_state.GetRejectReason());
494  BOOST_CHECK_EQUAL(submit_spend_ignored.m_tx_results.size(), 2);
495  auto it_child2_ignored = submit_spend_ignored.m_tx_results.find(ptx_child2->GetWitnessHash());
496  auto it_grandchild = submit_spend_ignored.m_tx_results.find(ptx_grandchild->GetWitnessHash());
497  BOOST_CHECK(it_child2_ignored != submit_spend_ignored.m_tx_results.end());
498  BOOST_CHECK(it_child2_ignored->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS);
499  BOOST_CHECK(it_grandchild != submit_spend_ignored.m_tx_results.end());
500  BOOST_CHECK(it_grandchild->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
501 
502  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_child2->GetHash())));
503  BOOST_CHECK(!m_node.mempool->exists(GenTxid::Wtxid(ptx_child2->GetWitnessHash())));
504  BOOST_CHECK(m_node.mempool->exists(GenTxid::Wtxid(ptx_grandchild->GetWitnessHash())));
505  }
506 
507  // A package Package{parent1, parent2, parent3, child} where the parents are a mixture of
508  // identical-tx-in-mempool, same-txid-different-witness-in-mempool, and new transactions.
509  Package package_mixed;
510 
511  // Give all the parents anyone-can-spend scripts so we don't have to deal with signing the child.
512  CScript acs_script = CScript() << OP_TRUE;
513  CScript acs_spk = GetScriptForDestination(WitnessV0ScriptHash(acs_script));
514  CScriptWitness acs_witness;
515  acs_witness.stack.push_back(std::vector<unsigned char>(acs_script.begin(), acs_script.end()));
516 
517  // parent1 will already be in the mempool
518  auto mtx_parent1 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,
519  /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
520  /*output_destination=*/acs_spk,
521  /*output_amount=*/CAmount(49 * COIN), /*submit=*/true);
522  CTransactionRef ptx_parent1 = MakeTransactionRef(mtx_parent1);
523  package_mixed.push_back(ptx_parent1);
524 
525  // parent2 will have a same-txid-different-witness tx already in the mempool
526  CScript grandparent2_script = CScript() << OP_DROP << OP_TRUE;
527  CScript grandparent2_spk = GetScriptForDestination(WitnessV0ScriptHash(grandparent2_script));
528  CScriptWitness parent2_witness1;
529  parent2_witness1.stack.push_back(std::vector<unsigned char>(1));
530  parent2_witness1.stack.push_back(std::vector<unsigned char>(grandparent2_script.begin(), grandparent2_script.end()));
531  CScriptWitness parent2_witness2;
532  parent2_witness2.stack.push_back(std::vector<unsigned char>(2));
533  parent2_witness2.stack.push_back(std::vector<unsigned char>(grandparent2_script.begin(), grandparent2_script.end()));
534 
535  // Create grandparent2 creating an output with multiple spending paths. Submit to mempool.
536  auto mtx_grandparent2 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[2], /*input_vout=*/0,
537  /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
538  /*output_destination=*/grandparent2_spk,
539  /*output_amount=*/CAmount(49 * COIN), /*submit=*/true);
540  CTransactionRef ptx_grandparent2 = MakeTransactionRef(mtx_grandparent2);
541 
542  CMutableTransaction mtx_parent2_v1;
543  mtx_parent2_v1.nVersion = 1;
544  mtx_parent2_v1.vin.resize(1);
545  mtx_parent2_v1.vin[0].prevout.hash = ptx_grandparent2->GetHash();
546  mtx_parent2_v1.vin[0].prevout.n = 0;
547  mtx_parent2_v1.vin[0].scriptSig = CScript();
548  mtx_parent2_v1.vin[0].scriptWitness = parent2_witness1;
549  mtx_parent2_v1.vout.resize(1);
550  mtx_parent2_v1.vout[0].nValue = CAmount(48 * COIN);
551  mtx_parent2_v1.vout[0].scriptPubKey = acs_spk;
552 
553  CMutableTransaction mtx_parent2_v2{mtx_parent2_v1};
554  mtx_parent2_v2.vin[0].scriptWitness = parent2_witness2;
555 
556  CTransactionRef ptx_parent2_v1 = MakeTransactionRef(mtx_parent2_v1);
557  CTransactionRef ptx_parent2_v2 = MakeTransactionRef(mtx_parent2_v2);
558  // Put parent2_v1 in the package, submit parent2_v2 to the mempool.
559  const MempoolAcceptResult parent2_v2_result = m_node.chainman->ProcessTransaction(ptx_parent2_v2);
561  package_mixed.push_back(ptx_parent2_v1);
562 
563  // parent3 will be a new transaction. Put 0 fees on it to make it invalid on its own.
564  auto mtx_parent3 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[3], /*input_vout=*/0,
565  /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
566  /*output_destination=*/acs_spk,
567  /*output_amount=*/CAmount(50 * COIN), /*submit=*/false);
568  CTransactionRef ptx_parent3 = MakeTransactionRef(mtx_parent3);
569  package_mixed.push_back(ptx_parent3);
570 
571  // child spends parent1, parent2, and parent3
572  CKey mixed_grandchild_key;
573  mixed_grandchild_key.MakeNewKey(true);
574  CScript mixed_child_spk = GetScriptForDestination(WitnessV0KeyHash(mixed_grandchild_key.GetPubKey()));
575 
576  CMutableTransaction mtx_mixed_child;
577  mtx_mixed_child.vin.push_back(CTxIn(COutPoint(ptx_parent1->GetHash(), 0)));
578  mtx_mixed_child.vin.push_back(CTxIn(COutPoint(ptx_parent2_v1->GetHash(), 0)));
579  mtx_mixed_child.vin.push_back(CTxIn(COutPoint(ptx_parent3->GetHash(), 0)));
580  mtx_mixed_child.vin[0].scriptWitness = acs_witness;
581  mtx_mixed_child.vin[1].scriptWitness = acs_witness;
582  mtx_mixed_child.vin[2].scriptWitness = acs_witness;
583  mtx_mixed_child.vout.push_back(CTxOut((48 + 49 + 50 - 1) * COIN, mixed_child_spk));
584  CTransactionRef ptx_mixed_child = MakeTransactionRef(mtx_mixed_child);
585  package_mixed.push_back(ptx_mixed_child);
586 
587  // Submit package:
588  // parent1 should be ignored
589  // parent2_v1 should be ignored (and v2 wtxid returned)
590  // parent3 should be accepted
591  // child should be accepted
592  {
593  const auto mixed_result = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_mixed, false);
594  BOOST_CHECK_MESSAGE(mixed_result.m_state.IsValid(), mixed_result.m_state.GetRejectReason());
595  BOOST_CHECK_EQUAL(mixed_result.m_tx_results.size(), package_mixed.size());
596  auto it_parent1 = mixed_result.m_tx_results.find(ptx_parent1->GetWitnessHash());
597  auto it_parent2 = mixed_result.m_tx_results.find(ptx_parent2_v1->GetWitnessHash());
598  auto it_parent3 = mixed_result.m_tx_results.find(ptx_parent3->GetWitnessHash());
599  auto it_child = mixed_result.m_tx_results.find(ptx_mixed_child->GetWitnessHash());
600  BOOST_CHECK(it_parent1 != mixed_result.m_tx_results.end());
601  BOOST_CHECK(it_parent2 != mixed_result.m_tx_results.end());
602  BOOST_CHECK(it_parent3 != mixed_result.m_tx_results.end());
603  BOOST_CHECK(it_child != mixed_result.m_tx_results.end());
604 
605  BOOST_CHECK(it_parent1->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
606  BOOST_CHECK(it_parent2->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS);
607  BOOST_CHECK(it_parent3->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
608  BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
609  BOOST_CHECK_EQUAL(ptx_parent2_v2->GetWitnessHash(), it_parent2->second.m_other_wtxid.value());
610 
611  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_parent1->GetHash())));
612  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_parent2_v1->GetHash())));
613  BOOST_CHECK(!m_node.mempool->exists(GenTxid::Wtxid(ptx_parent2_v1->GetWitnessHash())));
614  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_parent3->GetHash())));
615  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_mixed_child->GetHash())));
616 
617  // package feerate should include parent3 and child. It should not include parent1 or parent2_v1.
618  const CFeeRate expected_feerate(1 * COIN, GetVirtualTransactionSize(*ptx_parent3) + GetVirtualTransactionSize(*ptx_mixed_child));
619  BOOST_CHECK(it_parent3->second.m_effective_feerate.value() == expected_feerate);
620  BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
621  std::vector<uint256> expected_wtxids({ptx_parent3->GetWitnessHash(), ptx_mixed_child->GetWitnessHash()});
622  BOOST_CHECK(it_parent3->second.m_wtxids_fee_calculations.value() == expected_wtxids);
623  BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
624  }
625 }
626 
628 {
629  mineBlocks(5);
630  LOCK(::cs_main);
631  size_t expected_pool_size = m_node.mempool->size();
632  CKey child_key;
633  child_key.MakeNewKey(true);
634  CScript parent_spk = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey()));
635  CKey grandchild_key;
636  grandchild_key.MakeNewKey(true);
637  CScript child_spk = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
638 
639  // zero-fee parent and high-fee child package
640  const CAmount coinbase_value{50 * COIN};
641  const CAmount parent_value{coinbase_value - 0};
642  const CAmount child_value{parent_value - COIN};
643 
644  Package package_cpfp;
645  auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
646  /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
647  /*output_destination=*/parent_spk,
648  /*output_amount=*/parent_value, /*submit=*/false);
649  CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
650  package_cpfp.push_back(tx_parent);
651 
652  auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
653  /*input_height=*/101, /*input_signing_key=*/child_key,
654  /*output_destination=*/child_spk,
655  /*output_amount=*/child_value, /*submit=*/false);
656  CTransactionRef tx_child = MakeTransactionRef(mtx_child);
657  package_cpfp.push_back(tx_child);
658 
659  // Package feerate is calculated using modified fees, and prioritisetransaction accepts negative
660  // fee deltas. This should be taken into account. De-prioritise the parent transaction by -1BTC,
661  // bringing the package feerate to 0.
662  m_node.mempool->PrioritiseTransaction(tx_parent->GetHash(), -1 * COIN);
663  {
664  BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
665  const auto submit_cpfp_deprio = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
666  package_cpfp, /*test_accept=*/ false);
667  BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
668  BOOST_CHECK_MESSAGE(submit_cpfp_deprio.m_state.IsInvalid(),
669  "Package validation unexpectedly succeeded: " << submit_cpfp_deprio.m_state.GetRejectReason());
670  BOOST_CHECK(submit_cpfp_deprio.m_tx_results.empty());
671  BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
672  const CFeeRate expected_feerate(0, GetVirtualTransactionSize(*tx_parent) + GetVirtualTransactionSize(*tx_child));
673  }
674 
675  // Clear the prioritisation of the parent transaction.
676  WITH_LOCK(m_node.mempool->cs, m_node.mempool->ClearPrioritisation(tx_parent->GetHash()));
677 
678  // Package CPFP: Even though the parent pays 0 absolute fees, the child pays 1 BTC which is
679  // enough for the package feerate to meet the threshold.
680  {
681  BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
682  const auto submit_cpfp = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
683  package_cpfp, /*test_accept=*/ false);
684  expected_pool_size += 2;
685  BOOST_CHECK_MESSAGE(submit_cpfp.m_state.IsValid(),
686  "Package validation unexpectedly failed: " << submit_cpfp.m_state.GetRejectReason());
687  BOOST_CHECK_EQUAL(submit_cpfp.m_tx_results.size(), package_cpfp.size());
688  auto it_parent = submit_cpfp.m_tx_results.find(tx_parent->GetWitnessHash());
689  auto it_child = submit_cpfp.m_tx_results.find(tx_child->GetWitnessHash());
690  BOOST_CHECK(it_parent != submit_cpfp.m_tx_results.end());
691  BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
692  BOOST_CHECK(it_parent->second.m_base_fees.value() == 0);
693  BOOST_CHECK(it_child != submit_cpfp.m_tx_results.end());
694  BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
695  BOOST_CHECK(it_child->second.m_base_fees.value() == COIN);
696 
697  BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
698  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_parent->GetHash())));
699  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_child->GetHash())));
700 
701  const CFeeRate expected_feerate(coinbase_value - child_value,
702  GetVirtualTransactionSize(*tx_parent) + GetVirtualTransactionSize(*tx_child));
703  BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
704  BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
705  std::vector<uint256> expected_wtxids({tx_parent->GetWitnessHash(), tx_child->GetWitnessHash()});
706  BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
707  BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
708  BOOST_CHECK(expected_feerate.GetFeePerK() > 1000);
709  }
710 
711  // Just because we allow low-fee parents doesn't mean we allow low-feerate packages.
712  // This package just pays 200 satoshis total. This would be enough to pay for the child alone,
713  // but isn't enough for the entire package to meet the 1sat/vbyte minimum.
714  Package package_still_too_low;
715  auto mtx_parent_cheap = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,
716  /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
717  /*output_destination=*/parent_spk,
718  /*output_amount=*/coinbase_value, /*submit=*/false);
719  CTransactionRef tx_parent_cheap = MakeTransactionRef(mtx_parent_cheap);
720  package_still_too_low.push_back(tx_parent_cheap);
721 
722  auto mtx_child_cheap = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent_cheap, /*input_vout=*/0,
723  /*input_height=*/101, /*input_signing_key=*/child_key,
724  /*output_destination=*/child_spk,
725  /*output_amount=*/coinbase_value - 200, /*submit=*/false);
726  CTransactionRef tx_child_cheap = MakeTransactionRef(mtx_child_cheap);
727  package_still_too_low.push_back(tx_child_cheap);
728 
729  // Cheap package should fail with package-fee-too-low.
730  {
731  BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
732  const auto submit_package_too_low = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
733  package_still_too_low, /*test_accept=*/false);
734  BOOST_CHECK_MESSAGE(submit_package_too_low.m_state.IsInvalid(), "Package validation unexpectedly succeeded");
735  BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
736  BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetRejectReason(), "package-fee-too-low");
737  BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
738  const CFeeRate child_feerate(200, GetVirtualTransactionSize(*tx_child_cheap));
739  BOOST_CHECK(child_feerate.GetFeePerK() > 1000);
740  const CFeeRate expected_feerate(200,
741  GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap));
742  BOOST_CHECK(expected_feerate.GetFeePerK() < 1000);
743  }
744 
745  // Package feerate includes the modified fees of the transactions.
746  // This means a child with its fee delta from prioritisetransaction can pay for a parent.
747  m_node.mempool->PrioritiseTransaction(tx_child_cheap->GetHash(), 1 * COIN);
748  // Now that the child's fees have "increased" by 1 BTC, the cheap package should succeed.
749  {
750  const auto submit_prioritised_package = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
751  package_still_too_low, /*test_accept=*/false);
752  expected_pool_size += 2;
753  BOOST_CHECK_MESSAGE(submit_prioritised_package.m_state.IsValid(),
754  "Package validation unexpectedly failed" << submit_prioritised_package.m_state.GetRejectReason());
755  const CFeeRate expected_feerate(1 * COIN + 200,
756  GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap));
757  BOOST_CHECK_EQUAL(submit_prioritised_package.m_tx_results.size(), package_still_too_low.size());
758  auto it_parent = submit_prioritised_package.m_tx_results.find(tx_parent_cheap->GetWitnessHash());
759  auto it_child = submit_prioritised_package.m_tx_results.find(tx_child_cheap->GetWitnessHash());
760  BOOST_CHECK(it_parent != submit_prioritised_package.m_tx_results.end());
761  BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
762  BOOST_CHECK(it_parent->second.m_base_fees.value() == 0);
763  BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
764  BOOST_CHECK(it_child != submit_prioritised_package.m_tx_results.end());
765  BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
766  BOOST_CHECK(it_child->second.m_base_fees.value() == 200);
767  BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
768  std::vector<uint256> expected_wtxids({tx_parent_cheap->GetWitnessHash(), tx_child_cheap->GetWitnessHash()});
769  BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
770  BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
771  }
772 
773  // Package feerate is calculated without topology in mind; it's just aggregating fees and sizes.
774  // However, this should not allow parents to pay for children. Each transaction should be
775  // validated individually first, eliminating sufficient-feerate parents before they are unfairly
776  // included in the package feerate. It's also important that the low-fee child doesn't prevent
777  // the parent from being accepted.
778  Package package_rich_parent;
779  const CAmount high_parent_fee{1 * COIN};
780  auto mtx_parent_rich = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[2], /*input_vout=*/0,
781  /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
782  /*output_destination=*/parent_spk,
783  /*output_amount=*/coinbase_value - high_parent_fee, /*submit=*/false);
784  CTransactionRef tx_parent_rich = MakeTransactionRef(mtx_parent_rich);
785  package_rich_parent.push_back(tx_parent_rich);
786 
787  auto mtx_child_poor = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent_rich, /*input_vout=*/0,
788  /*input_height=*/101, /*input_signing_key=*/child_key,
789  /*output_destination=*/child_spk,
790  /*output_amount=*/coinbase_value - high_parent_fee, /*submit=*/false);
791  CTransactionRef tx_child_poor = MakeTransactionRef(mtx_child_poor);
792  package_rich_parent.push_back(tx_child_poor);
793 
794  // Parent pays 1 BTC and child pays none. The parent should be accepted without the child.
795  {
796  BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
797  const auto submit_rich_parent = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
798  package_rich_parent, /*test_accept=*/false);
799  expected_pool_size += 1;
800  BOOST_CHECK_MESSAGE(submit_rich_parent.m_state.IsInvalid(), "Package validation unexpectedly succeeded");
801 
802  // The child would have been validated on its own and failed, then submitted as a "package" of 1.
803  BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
804  BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetRejectReason(), "package-fee-too-low");
805 
806  auto it_parent = submit_rich_parent.m_tx_results.find(tx_parent_rich->GetWitnessHash());
807  BOOST_CHECK(it_parent != submit_rich_parent.m_tx_results.end());
808  BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
809  BOOST_CHECK(it_parent->second.m_state.GetRejectReason() == "");
810  BOOST_CHECK_MESSAGE(it_parent->second.m_base_fees.value() == high_parent_fee,
811  strprintf("rich parent: expected fee %s, got %s", high_parent_fee, it_parent->second.m_base_fees.value()));
812  BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(high_parent_fee, GetVirtualTransactionSize(*tx_parent_rich)));
813 
814  BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
815  BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_parent_rich->GetHash())));
816  BOOST_CHECK(!m_node.mempool->exists(GenTxid::Txid(tx_child_poor->GetHash())));
817  }
818 }
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
Definition: bitcoin-gui.cpp:37
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:65
An encapsulated private key.
Definition: key.h:27
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:160
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:187
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:36
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:411
An input of a transaction.
Definition: transaction.h:75
An output of a transaction.
Definition: transaction.h:158
Fast randomness source.
Definition: random.h:144
static GenTxid Wtxid(const uint256 &hash)
Definition: transaction.h:433
static GenTxid Txid(const uint256 &hash)
Definition: transaction.h:432
std::string GetRejectReason() const
Definition: validation.h:125
Result GetResult() const
Definition: validation.h:124
iterator begin()
Definition: prevector.h:292
iterator end()
Definition: prevector.h:294
@ TX_MISSING_INPUTS
transaction was missing some of its inputs
@ TX_WITNESS_MUTATED
Transaction might have a witness prior to SegWit activation, or witness may have been malleated (whic...
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()
#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:68
bool CheckPackage(const Package &txns, PackageValidationState &state)
Context-free package policy checks:
Definition: packages.cpp:18
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
Definition: packages.h:44
static constexpr uint32_t MAX_PACKAGE_COUNT
Default maximum number of transactions in a package.
Definition: packages.h:17
static constexpr uint32_t MAX_PACKAGE_SIZE
Default maximum total virtual size of transactions in a package in KvB.
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:295
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:422
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:421
void Shuffle(I first, I last, R &&rng)
More efficient than using std::shuffle on a FastRandomContext.
Definition: random.h:260
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:63
@ OP_TRUE
Definition: script.h:80
@ OP_DROP
Definition: script.h:120
static constexpr CAmount CENT
Definition: setup_common.h:74
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:334
A mutable version of CTransaction.
Definition: transaction.h:380
std::vector< CTxOut > vout
Definition: transaction.h:382
std::vector< CTxIn > vin
Definition: transaction.h:381
std::vector< std::vector< unsigned char > > stack
Definition: script.h:566
Validation result for a single transaction mempool acceptance.
Definition: validation.h:117
const ResultType m_result_type
Result type.
Definition: validation.h:126
@ DIFFERENT_WITNESS
Valid, transaction was already in the mempool.
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
Definition: setup_common.h:128
std::unique_ptr< CTxMemPool > mempool
Definition: context.h:50
std::unique_ptr< ChainstateManager > chainman
Definition: context.h:54
#define LOCK(cs)
Definition: sync.h:258
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:302
static uint256 InsecureRand256()
Definition: random.h:20
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1162
BOOST_FIXTURE_TEST_CASE(package_sanitization_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)
Validate (and maybe submit) a package to the mempool.