Bitcoin Core  31.0.0
P2P Digital Currency
mempool_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-present 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 <common/system.h>
6 #include <policy/policy.h>
7 #include <test/util/txmempool.h>
8 #include <txmempool.h>
9 #include <util/time.h>
10 
11 #include <test/util/setup_common.h>
12 
13 #include <boost/test/unit_test.hpp>
14 #include <vector>
15 
17 
18 static constexpr auto REMOVAL_REASON_DUMMY = MemPoolRemovalReason::REPLACED;
19 
20 class MemPoolTest final : public CTxMemPool
21 {
22 public:
24 };
25 
26 BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
27 {
28  // Test CTxMemPool::remove functionality
29 
31  // Parent transaction with three children,
32  // and three grand-children:
33  CMutableTransaction txParent;
34  txParent.vin.resize(1);
35  txParent.vin[0].scriptSig = CScript() << OP_11;
36  txParent.vout.resize(3);
37  for (int i = 0; i < 3; i++)
38  {
39  txParent.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
40  txParent.vout[i].nValue = 33000LL;
41  }
42  CMutableTransaction txChild[3];
43  for (int i = 0; i < 3; i++)
44  {
45  txChild[i].vin.resize(1);
46  txChild[i].vin[0].scriptSig = CScript() << OP_11;
47  txChild[i].vin[0].prevout.hash = txParent.GetHash();
48  txChild[i].vin[0].prevout.n = i;
49  txChild[i].vout.resize(1);
50  txChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
51  txChild[i].vout[0].nValue = 11000LL;
52  }
53  CMutableTransaction txGrandChild[3];
54  for (int i = 0; i < 3; i++)
55  {
56  txGrandChild[i].vin.resize(1);
57  txGrandChild[i].vin[0].scriptSig = CScript() << OP_11;
58  txGrandChild[i].vin[0].prevout.hash = txChild[i].GetHash();
59  txGrandChild[i].vin[0].prevout.n = 0;
60  txGrandChild[i].vout.resize(1);
61  txGrandChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
62  txGrandChild[i].vout[0].nValue = 11000LL;
63  }
64 
65 
66  CTxMemPool& testPool = *Assert(m_node.mempool);
67  LOCK2(::cs_main, testPool.cs);
68 
69  // Nothing in pool, remove should do nothing:
70  unsigned int poolSize = testPool.size();
72  BOOST_CHECK_EQUAL(testPool.size(), poolSize);
73 
74  // Just the parent:
75  TryAddToMempool(testPool, entry.FromTx(txParent));
76  poolSize = testPool.size();
78  BOOST_CHECK_EQUAL(testPool.size(), poolSize - 1);
79 
80  // Parent, children, grandchildren:
81  TryAddToMempool(testPool, entry.FromTx(txParent));
82  for (int i = 0; i < 3; i++)
83  {
84  TryAddToMempool(testPool, entry.FromTx(txChild[i]));
85  TryAddToMempool(testPool, entry.FromTx(txGrandChild[i]));
86  }
87  // Remove Child[0], GrandChild[0] should be removed:
88  poolSize = testPool.size();
89  testPool.removeRecursive(CTransaction(txChild[0]), REMOVAL_REASON_DUMMY);
90  BOOST_CHECK_EQUAL(testPool.size(), poolSize - 2);
91  // ... make sure grandchild and child are gone:
92  poolSize = testPool.size();
93  testPool.removeRecursive(CTransaction(txGrandChild[0]), REMOVAL_REASON_DUMMY);
94  BOOST_CHECK_EQUAL(testPool.size(), poolSize);
95  poolSize = testPool.size();
96  testPool.removeRecursive(CTransaction(txChild[0]), REMOVAL_REASON_DUMMY);
97  BOOST_CHECK_EQUAL(testPool.size(), poolSize);
98  // Remove parent, all children/grandchildren should go:
99  poolSize = testPool.size();
101  BOOST_CHECK_EQUAL(testPool.size(), poolSize - 5);
102  BOOST_CHECK_EQUAL(testPool.size(), 0U);
103 
104  // Add children and grandchildren, but NOT the parent (simulate the parent being in a block)
105  for (int i = 0; i < 3; i++)
106  {
107  TryAddToMempool(testPool, entry.FromTx(txChild[i]));
108  TryAddToMempool(testPool, entry.FromTx(txGrandChild[i]));
109  }
110  // Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be
111  // put into the mempool (maybe because it is non-standard):
112  poolSize = testPool.size();
114  BOOST_CHECK_EQUAL(testPool.size(), poolSize - 6);
115  BOOST_CHECK_EQUAL(testPool.size(), 0U);
116 }
117 
118 BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
119 {
120  auto& pool = static_cast<MemPoolTest&>(*Assert(m_node.mempool));
121  LOCK2(cs_main, pool.cs);
123 
125  tx1.vin.resize(1);
126  tx1.vin[0].scriptSig = CScript() << OP_1;
127  tx1.vout.resize(1);
128  tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
129  tx1.vout[0].nValue = 10 * COIN;
130  TryAddToMempool(pool, entry.Fee(1000LL).FromTx(tx1));
131 
133  tx2.vin.resize(1);
134  tx2.vin[0].scriptSig = CScript() << OP_2;
135  tx2.vout.resize(1);
136  tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
137  tx2.vout[0].nValue = 10 * COIN;
138  TryAddToMempool(pool, entry.Fee(500LL).FromTx(tx2));
139 
140  pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing
141  BOOST_CHECK(pool.exists(tx1.GetHash()));
142  BOOST_CHECK(pool.exists(tx2.GetHash()));
143 
144  pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // should remove the lower-feerate transaction
145  BOOST_CHECK(pool.exists(tx1.GetHash()));
146  BOOST_CHECK(!pool.exists(tx2.GetHash()));
147 
148  TryAddToMempool(pool, entry.FromTx(tx2));
150  tx3.vin.resize(1);
151  tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
152  tx3.vin[0].scriptSig = CScript() << OP_2;
153  tx3.vout.resize(1);
154  tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
155  tx3.vout[0].nValue = 10 * COIN;
156  TryAddToMempool(pool, entry.Fee(2000LL).FromTx(tx3));
157 
158  pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)
159  BOOST_CHECK(!pool.exists(tx1.GetHash()));
160  BOOST_CHECK(pool.exists(tx2.GetHash()));
161  BOOST_CHECK(pool.exists(tx3.GetHash()));
162 
163  pool.TrimToSize(GetVirtualTransactionSize(CTransaction(tx1))); // mempool is limited to tx1's size in memory usage, so nothing fits
164  BOOST_CHECK(!pool.exists(tx1.GetHash()));
165  BOOST_CHECK(!pool.exists(tx2.GetHash()));
166  BOOST_CHECK(!pool.exists(tx3.GetHash()));
167 
169  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE);
170 
172  tx4.vin.resize(2);
173  tx4.vin[0].prevout.SetNull();
174  tx4.vin[0].scriptSig = CScript() << OP_4;
175  tx4.vin[1].prevout.SetNull();
176  tx4.vin[1].scriptSig = CScript() << OP_4;
177  tx4.vout.resize(2);
178  tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
179  tx4.vout[0].nValue = 10 * COIN;
180  tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
181  tx4.vout[1].nValue = 10 * COIN;
182 
184  tx5.vin.resize(2);
185  tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0);
186  tx5.vin[0].scriptSig = CScript() << OP_4;
187  tx5.vin[1].prevout.SetNull();
188  tx5.vin[1].scriptSig = CScript() << OP_5;
189  tx5.vout.resize(2);
190  tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
191  tx5.vout[0].nValue = 10 * COIN;
192  tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
193  tx5.vout[1].nValue = 10 * COIN;
194 
196  tx6.vin.resize(2);
197  tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1);
198  tx6.vin[0].scriptSig = CScript() << OP_4;
199  tx6.vin[1].prevout.SetNull();
200  tx6.vin[1].scriptSig = CScript() << OP_6;
201  tx6.vout.resize(2);
202  tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
203  tx6.vout[0].nValue = 10 * COIN;
204  tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
205  tx6.vout[1].nValue = 10 * COIN;
206 
208  tx7.vin.resize(2);
209  tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0);
210  tx7.vin[0].scriptSig = CScript() << OP_5;
211  tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);
212  tx7.vin[1].scriptSig = CScript() << OP_6;
213  tx7.vout.resize(2);
214  tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
215  tx7.vout[0].nValue = 10 * COIN;
216  tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
217  tx7.vout[1].nValue = 10 * COIN;
218 
219  TryAddToMempool(pool, entry.Fee(700LL).FromTx(tx4));
220  auto usage_with_tx4_only = pool.DynamicMemoryUsage();
221  TryAddToMempool(pool, entry.Fee(100LL).FromTx(tx5));
222  TryAddToMempool(pool, entry.Fee(110LL).FromTx(tx6));
223  TryAddToMempool(pool, entry.Fee(900LL).FromTx(tx7));
224 
225  // From the topology above, tx7 must be sorted last, so it should
226  // definitely evicted first if we must trim. tx4 should definitely remain
227  // in the mempool since it has a higher feerate than its descendants and
228  // should be in its own chunk.
229  pool.TrimToSize(pool.DynamicMemoryUsage() - 1);
230  BOOST_CHECK(pool.exists(tx4.GetHash()));
231  BOOST_CHECK(!pool.exists(tx7.GetHash()));
232 
233  // Tx5 and Tx6 may be removed as well because they're in the same chunk as
234  // tx7, but this behavior need not be guaranteed.
235 
236  if (!pool.exists(tx5.GetHash()))
237  TryAddToMempool(pool, entry.Fee(100LL).FromTx(tx5));
238  if (!pool.exists(tx6.GetHash()))
239  TryAddToMempool(pool, entry.Fee(110LL).FromTx(tx6));
240  TryAddToMempool(pool, entry.Fee(900LL).FromTx(tx7));
241 
242  // If we trim sufficiently, everything but tx4 should be removed.
243  pool.TrimToSize(usage_with_tx4_only + 1);
244  BOOST_CHECK(pool.exists(tx4.GetHash()));
245  BOOST_CHECK(!pool.exists(tx5.GetHash()));
246  BOOST_CHECK(!pool.exists(tx6.GetHash()));
247  BOOST_CHECK(!pool.exists(tx7.GetHash()));
248 
249  TryAddToMempool(pool, entry.Fee(100LL).FromTx(tx5));
250  TryAddToMempool(pool, entry.Fee(110LL).FromTx(tx6));
251  TryAddToMempool(pool, entry.Fee(900LL).FromTx(tx7));
252 
253  std::vector<CTransactionRef> vtx;
254  SetMockTime(42);
256  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE);
257  // ... we should keep the same min fee until we get a block
258  pool.removeForBlock(vtx, 1);
260  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE)/2.0));
261  // ... then feerate should drop 1/2 each halflife
262 
264  BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE)/4.0));
265  // ... with a 1/2 halflife when mempool is < 1/2 its target size
266 
268  BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE)/8.0));
269  // ... with a 1/4 halflife when mempool is < 1/4 its target size
270 
272  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), DEFAULT_INCREMENTAL_RELAY_FEE);
273  // ... but feerate should never drop below DEFAULT_INCREMENTAL_RELAY_FEE
274 
276  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0);
277  // ... unless it has gone all the way to 0 (after getting past DEFAULT_INCREMENTAL_RELAY_FEE/2)
278 }
279 
280 inline CTransactionRef make_tx(std::vector<CAmount>&& output_values, std::vector<CTransactionRef>&& inputs=std::vector<CTransactionRef>(), std::vector<uint32_t>&& input_indices=std::vector<uint32_t>())
281 {
283  tx.vin.resize(inputs.size());
284  tx.vout.resize(output_values.size());
285  for (size_t i = 0; i < inputs.size(); ++i) {
286  tx.vin[i].prevout.hash = inputs[i]->GetHash();
287  tx.vin[i].prevout.n = input_indices.size() > i ? input_indices[i] : 0;
288  }
289  for (size_t i = 0; i < output_values.size(); ++i) {
290  tx.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
291  tx.vout[i].nValue = output_values[i];
292  }
293  return MakeTransactionRef(tx);
294 }
295 
296 
297 BOOST_AUTO_TEST_CASE(MempoolAncestryTests)
298 {
299  size_t ancestors, clustersize;
300 
301  CTxMemPool& pool = *Assert(m_node.mempool);
302  LOCK2(cs_main, pool.cs);
304 
305  /* Base transaction */
306  //
307  // [tx1]
308  //
309  CTransactionRef tx1 = make_tx(/*output_values=*/{10 * COIN});
310  TryAddToMempool(pool, entry.Fee(10000LL).FromTx(tx1));
311 
312  // Ancestors / clustersize should be 1 / 1 (itself / itself)
313  pool.GetTransactionAncestry(tx1->GetHash(), ancestors, clustersize);
314  BOOST_CHECK_EQUAL(ancestors, 1ULL);
315  BOOST_CHECK_EQUAL(clustersize, 1ULL);
316 
317  /* Child transaction */
318  //
319  // [tx1].0 <- [tx2]
320  //
321  CTransactionRef tx2 = make_tx(/*output_values=*/{495 * CENT, 5 * COIN}, /*inputs=*/{tx1});
322  TryAddToMempool(pool, entry.Fee(10000LL).FromTx(tx2));
323 
324  // Ancestors / clustersize should be:
325  // transaction ancestors clustersize
326  // ============ =========== ===========
327  // tx1 1 (tx1) 2 (tx1,2)
328  // tx2 2 (tx1,2) 2 (tx1,2)
329  pool.GetTransactionAncestry(tx1->GetHash(), ancestors, clustersize);
330  BOOST_CHECK_EQUAL(ancestors, 1ULL);
331  BOOST_CHECK_EQUAL(clustersize, 2ULL);
332  pool.GetTransactionAncestry(tx2->GetHash(), ancestors, clustersize);
333  BOOST_CHECK_EQUAL(ancestors, 2ULL);
334  BOOST_CHECK_EQUAL(clustersize, 2ULL);
335 
336  /* Grand-child 1 */
337  //
338  // [tx1].0 <- [tx2].0 <- [tx3]
339  //
340  CTransactionRef tx3 = make_tx(/*output_values=*/{290 * CENT, 200 * CENT}, /*inputs=*/{tx2});
341  TryAddToMempool(pool, entry.Fee(10000LL).FromTx(tx3));
342 
343  // Ancestors / clustersize should be:
344  // transaction ancestors clustersize
345  // ============ =========== ===========
346  // tx1 1 (tx1) 3 (tx1,2,3)
347  // tx2 2 (tx1,2) 3 (tx1,2,3)
348  // tx3 3 (tx1,2,3) 3 (tx1,2,3)
349  pool.GetTransactionAncestry(tx1->GetHash(), ancestors, clustersize);
350  BOOST_CHECK_EQUAL(ancestors, 1ULL);
351  BOOST_CHECK_EQUAL(clustersize, 3ULL);
352  pool.GetTransactionAncestry(tx2->GetHash(), ancestors, clustersize);
353  BOOST_CHECK_EQUAL(ancestors, 2ULL);
354  BOOST_CHECK_EQUAL(clustersize, 3ULL);
355  pool.GetTransactionAncestry(tx3->GetHash(), ancestors, clustersize);
356  BOOST_CHECK_EQUAL(ancestors, 3ULL);
357  BOOST_CHECK_EQUAL(clustersize, 3ULL);
358 
359  /* Grand-child 2 */
360  //
361  // [tx1].0 <- [tx2].0 <- [tx3]
362  // |
363  // \---1 <- [tx4]
364  //
365  CTransactionRef tx4 = make_tx(/*output_values=*/{290 * CENT, 250 * CENT}, /*inputs=*/{tx2}, /*input_indices=*/{1});
366  TryAddToMempool(pool, entry.Fee(10000LL).FromTx(tx4));
367 
368  // Ancestors / clustersize should be:
369  // transaction ancestors clustersize
370  // ============ =========== ===========
371  // tx1 1 (tx1) 4 (tx1,2,3,4)
372  // tx2 2 (tx1,2) 4 (tx1,2,3,4)
373  // tx3 3 (tx1,2,3) 4 (tx1,2,3,4)
374  // tx4 3 (tx1,2,4) 4 (tx1,2,3,4)
375  pool.GetTransactionAncestry(tx1->GetHash(), ancestors, clustersize);
376  BOOST_CHECK_EQUAL(ancestors, 1ULL);
377  BOOST_CHECK_EQUAL(clustersize, 4ULL);
378  pool.GetTransactionAncestry(tx2->GetHash(), ancestors, clustersize);
379  BOOST_CHECK_EQUAL(ancestors, 2ULL);
380  BOOST_CHECK_EQUAL(clustersize, 4ULL);
381  pool.GetTransactionAncestry(tx3->GetHash(), ancestors, clustersize);
382  BOOST_CHECK_EQUAL(ancestors, 3ULL);
383  BOOST_CHECK_EQUAL(clustersize, 4ULL);
384  pool.GetTransactionAncestry(tx4->GetHash(), ancestors, clustersize);
385  BOOST_CHECK_EQUAL(ancestors, 3ULL);
386  BOOST_CHECK_EQUAL(clustersize, 4ULL);
387 
388  /* Make an alternate branch that is longer and connect it to tx3 */
389  //
390  // [ty1].0 <- [ty2].0 <- [ty3].0 <- [ty4].0 <- [ty5].0
391  // |
392  // [tx1].0 <- [tx2].0 <- [tx3].0 <- [ty6] --->--/
393  // |
394  // \---1 <- [tx4]
395  //
396  CTransactionRef ty1, ty2, ty3, ty4, ty5;
397  CTransactionRef* ty[5] = {&ty1, &ty2, &ty3, &ty4, &ty5};
398  CAmount v = 5 * COIN;
399  for (uint64_t i = 0; i < 5; i++) {
400  CTransactionRef& tyi = *ty[i];
401  tyi = make_tx(/*output_values=*/{v}, /*inputs=*/i > 0 ? std::vector<CTransactionRef>{*ty[i - 1]} : std::vector<CTransactionRef>{});
402  v -= 50 * CENT;
403  TryAddToMempool(pool, entry.Fee(10000LL).FromTx(tyi));
404  pool.GetTransactionAncestry(tyi->GetHash(), ancestors, clustersize);
405  BOOST_CHECK_EQUAL(ancestors, i+1);
406  BOOST_CHECK_EQUAL(clustersize, i+1);
407  }
408  CTransactionRef ty6 = make_tx(/*output_values=*/{5 * COIN}, /*inputs=*/{tx3, ty5});
409  TryAddToMempool(pool, entry.Fee(10000LL).FromTx(ty6));
410 
411  // Ancestors / clustersize should be:
412  // transaction ancestors clustersize
413  // ============ =================== ===========
414  // tx1 1 (tx1) 10 (tx1-5, ty1-5)
415  // tx2 2 (tx1,2) 10
416  // tx3 3 (tx1,2,3) 10
417  // tx4 3 (tx1,2,4) 10
418  // ty1 1 (ty1) 10
419  // ty2 2 (ty1,2) 10
420  // ty3 3 (ty1,2,3) 10
421  // ty4 4 (y1234) 10
422  // ty5 5 (y12345) 10
423  // ty6 9 (tx123, ty123456) 10
424  pool.GetTransactionAncestry(tx1->GetHash(), ancestors, clustersize);
425  BOOST_CHECK_EQUAL(ancestors, 1ULL);
426  BOOST_CHECK_EQUAL(clustersize, 10ULL);
427  pool.GetTransactionAncestry(tx2->GetHash(), ancestors, clustersize);
428  BOOST_CHECK_EQUAL(ancestors, 2ULL);
429  BOOST_CHECK_EQUAL(clustersize, 10ULL);
430  pool.GetTransactionAncestry(tx3->GetHash(), ancestors, clustersize);
431  BOOST_CHECK_EQUAL(ancestors, 3ULL);
432  BOOST_CHECK_EQUAL(clustersize, 10ULL);
433  pool.GetTransactionAncestry(tx4->GetHash(), ancestors, clustersize);
434  BOOST_CHECK_EQUAL(ancestors, 3ULL);
435  BOOST_CHECK_EQUAL(clustersize, 10ULL);
436  pool.GetTransactionAncestry(ty1->GetHash(), ancestors, clustersize);
437  BOOST_CHECK_EQUAL(ancestors, 1ULL);
438  BOOST_CHECK_EQUAL(clustersize, 10ULL);
439  pool.GetTransactionAncestry(ty2->GetHash(), ancestors, clustersize);
440  BOOST_CHECK_EQUAL(ancestors, 2ULL);
441  BOOST_CHECK_EQUAL(clustersize, 10ULL);
442  pool.GetTransactionAncestry(ty3->GetHash(), ancestors, clustersize);
443  BOOST_CHECK_EQUAL(ancestors, 3ULL);
444  BOOST_CHECK_EQUAL(clustersize, 10ULL);
445  pool.GetTransactionAncestry(ty4->GetHash(), ancestors, clustersize);
446  BOOST_CHECK_EQUAL(ancestors, 4ULL);
447  BOOST_CHECK_EQUAL(clustersize, 10ULL);
448  pool.GetTransactionAncestry(ty5->GetHash(), ancestors, clustersize);
449  BOOST_CHECK_EQUAL(ancestors, 5ULL);
450  BOOST_CHECK_EQUAL(clustersize, 10ULL);
451  pool.GetTransactionAncestry(ty6->GetHash(), ancestors, clustersize);
452  BOOST_CHECK_EQUAL(ancestors, 9ULL);
453  BOOST_CHECK_EQUAL(clustersize, 10ULL);
454 }
455 
456 BOOST_AUTO_TEST_CASE(MempoolAncestryTestsDiamond)
457 {
458  size_t ancestors, descendants;
459 
460  CTxMemPool& pool = *Assert(m_node.mempool);
461  LOCK2(::cs_main, pool.cs);
463 
464  /* Ancestors represented more than once ("diamond") */
465  //
466  // [ta].0 <- [tb].0 -----<------- [td].0
467  // | |
468  // \---1 <- [tc].0 --<--/
469  //
470  CTransactionRef ta, tb, tc, td;
471  ta = make_tx(/*output_values=*/{10 * COIN});
472  tb = make_tx(/*output_values=*/{5 * COIN, 3 * COIN}, /*inputs=*/ {ta});
473  tc = make_tx(/*output_values=*/{2 * COIN}, /*inputs=*/{tb}, /*input_indices=*/{1});
474  td = make_tx(/*output_values=*/{6 * COIN}, /*inputs=*/{tb, tc}, /*input_indices=*/{0, 0});
475  TryAddToMempool(pool, entry.Fee(10000LL).FromTx(ta));
476  TryAddToMempool(pool, entry.Fee(10000LL).FromTx(tb));
477  TryAddToMempool(pool, entry.Fee(10000LL).FromTx(tc));
478  TryAddToMempool(pool, entry.Fee(10000LL).FromTx(td));
479 
480  // Ancestors / descendants should be:
481  // transaction ancestors descendants
482  // ============ =================== ===========
483  // ta 1 (ta 4 (ta,tb,tc,td)
484  // tb 2 (ta,tb) 4 (ta,tb,tc,td)
485  // tc 3 (ta,tb,tc) 4 (ta,tb,tc,td)
486  // td 4 (ta,tb,tc,td) 4 (ta,tb,tc,td)
487  pool.GetTransactionAncestry(ta->GetHash(), ancestors, descendants);
488  BOOST_CHECK_EQUAL(ancestors, 1ULL);
489  BOOST_CHECK_EQUAL(descendants, 4ULL);
490  pool.GetTransactionAncestry(tb->GetHash(), ancestors, descendants);
491  BOOST_CHECK_EQUAL(ancestors, 2ULL);
492  BOOST_CHECK_EQUAL(descendants, 4ULL);
493  pool.GetTransactionAncestry(tc->GetHash(), ancestors, descendants);
494  BOOST_CHECK_EQUAL(ancestors, 3ULL);
495  BOOST_CHECK_EQUAL(descendants, 4ULL);
496  pool.GetTransactionAncestry(td->GetHash(), ancestors, descendants);
497  BOOST_CHECK_EQUAL(ancestors, 4ULL);
498  BOOST_CHECK_EQUAL(descendants, 4ULL);
499 }
500 
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:403
static constexpr unsigned int DEFAULT_INCREMENTAL_RELAY_FEE
Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or rep...
Definition: policy.h:47
Definition: txmempool.h:19
TestMemPoolEntryHelper & Fee(CAmount _fee)
Definition: txmempool.h:33
node::NodeContext m_node
Definition: bitcoin-gui.cpp:43
std::vector< CTxIn > vin
Definition: transaction.h:359
MemPoolRemovalReason
Reason why a transaction was removed from the mempool, this is passed to the notification signal...
unsigned long size() const
Definition: txmempool.h:485
TryAddToMempool(pool, CTxMemPoolEntry(tx, fee, 0, 1, 0, false, 4, lp))
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:381
CTxMemPoolEntry FromTx(const CMutableTransaction &tx) const
Definition: txmempool.cpp:34
void check(const CCoinsViewCache &active_coins_tip, int64_t spendheight) const EXCLUSIVE_LOCKS_REQUIRED(void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs)
If sanity-checking is turned on, check makes sure the pool is consistent (does not contain two transa...
Definition: txmempool.h:325
CFeeRate GetMinFee() const
The minimum fee to get into the mempool, which may itself not be enough for larger-sized transactions...
Definition: txmempool.h:452
CTransactionRef make_tx(std::vector< CAmount > &&output_values, std::vector< CTransactionRef > &&inputs=std::vector< CTransactionRef >(), std::vector< uint32_t > &&input_indices=std::vector< uint32_t >())
Definition: script.h:88
std::unique_ptr< CTxMemPool > mempool
Definition: context.h:68
Definition: script.h:83
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
Definition: script.h:94
#define LOCK2(cs1, cs2)
Definition: sync.h:259
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
static constexpr auto REMOVAL_REASON_DUMMY
BOOST_AUTO_TEST_SUITE_END()
static const int ROLLING_FEE_HALFLIFE
Definition: txmempool.h:212
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:69
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:28
std::vector< CTxOut > vout
Definition: transaction.h:360
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:404
Definition: script.h:90
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:186
void GetTransactionAncestry(const Txid &txid, size_t &ancestors, size_t &cluster_count, size_t *ancestorsize=nullptr, CAmount *ancestorfees=nullptr) const
Calculate the ancestor and cluster count for the given transaction.
Definition: txmempool.cpp:943
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:17
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:404
Definition: script.h:86
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac...
Definition: feerate.h:31
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
Definition: time.cpp:44
A mutable version of CTransaction.
Definition: transaction.h:357
Definition: script.h:85
static constexpr CAmount CENT
Definition: setup_common.h:47
BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: transaction.h:280
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
Definition: cs_main.cpp:8
Definition: script.h:89
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
Definition: feerate.h:62
Testing setup that configures a complete environment.
Definition: setup_common.h:121
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it...
Definition: txmempool.h:260
#define Assert(val)
Identity function.
Definition: check.h:113
Definition: script.h:87
#define BOOST_CHECK(expr)
Definition: object.cpp:16
static constexpr CAmount COIN
The amount of satoshis in one BTC.
Definition: amount.h:15