Bitcoin Core 30.99.0
P2P Digital Currency
mempool_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-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 <common/system.h>
6#include <policy/policy.h>
8#include <txmempool.h>
9#include <util/time.h>
10
12
13#include <boost/test/unit_test.hpp>
14#include <vector>
15
17
18static constexpr auto REMOVAL_REASON_DUMMY = MemPoolRemovalReason::REPLACED;
19
20class MemPoolTest final : public CTxMemPool
21{
22public:
24};
25
26BOOST_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();
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();
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
118BOOST_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
280inline 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
297BOOST_AUTO_TEST_CASE(MempoolAncestryTests)
298{
299 size_t ancestors, clustersize;
300
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
456BOOST_AUTO_TEST_CASE(MempoolAncestryTestsDiamond)
457{
458 size_t ancestors, descendants;
459
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
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
TryAddToMempool(pool, CTxMemPoolEntry(TxGraph::Ref(), tx, fee, 0, 1, 0, false, 4, lp))
node::NodeContext m_node
Definition: bitcoin-gui.cpp:43
#define Assert(val)
Identity function.
Definition: check.h:113
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac.
Definition: feerate.h:35
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
Definition: feerate.h:65
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:413
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:296
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:189
CFeeRate GetMinFee() const
The minimum fee to get into the mempool, which may itself not be enough for larger-sized transactions...
Definition: txmempool.h:455
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:263
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:328
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:926
static const int ROLLING_FEE_HALFLIFE
Definition: txmempool.h:215
unsigned long size() const
Definition: txmempool.h:488
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:8
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
MemPoolRemovalReason
Reason why a transaction was removed from the mempool, this is passed to the notification signal.
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 >())
static constexpr auto REMOVAL_REASON_DUMMY
BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK(expr)
Definition: object.cpp:17
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
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:45
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:424
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:423
@ OP_2
Definition: script.h:85
@ OP_EQUAL
Definition: script.h:146
@ OP_4
Definition: script.h:87
@ OP_1
Definition: script.h:83
@ OP_3
Definition: script.h:86
@ OP_11
Definition: script.h:94
@ OP_6
Definition: script.h:89
@ OP_7
Definition: script.h:90
@ OP_5
Definition: script.h:88
static constexpr CAmount CENT
Definition: setup_common.h:47
A mutable version of CTransaction.
Definition: transaction.h:378
std::vector< CTxOut > vout
Definition: transaction.h:380
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:69
std::vector< CTxIn > vin
Definition: transaction.h:379
Definition: txmempool.h:19
CTxMemPoolEntry FromTx(const CMutableTransaction &tx) const
Definition: txmempool.cpp:34
TestMemPoolEntryHelper & Fee(CAmount _fee)
Definition: txmempool.h:33
Testing setup that configures a complete environment.
Definition: setup_common.h:121
std::unique_ptr< CTxMemPool > mempool
Definition: context.h:68
#define LOCK2(cs1, cs2)
Definition: sync.h:260
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
Definition: time.cpp:40