Bitcoin Core  22.99.0
P2P Digital Currency
mempool_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2019 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 <policy/policy.h>
6 #include <txmempool.h>
7 #include <util/system.h>
8 #include <util/time.h>
9 
10 #include <test/util/setup_common.h>
11 
12 #include <boost/test/unit_test.hpp>
13 #include <vector>
14 
16 
17 static constexpr auto REMOVAL_REASON_DUMMY = MemPoolRemovalReason::REPLACED;
18 
19 BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
20 {
21  // Test CTxMemPool::remove functionality
22 
24  // Parent transaction with three children,
25  // and three grand-children:
26  CMutableTransaction txParent;
27  txParent.vin.resize(1);
28  txParent.vin[0].scriptSig = CScript() << OP_11;
29  txParent.vout.resize(3);
30  for (int i = 0; i < 3; i++)
31  {
32  txParent.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
33  txParent.vout[i].nValue = 33000LL;
34  }
35  CMutableTransaction txChild[3];
36  for (int i = 0; i < 3; i++)
37  {
38  txChild[i].vin.resize(1);
39  txChild[i].vin[0].scriptSig = CScript() << OP_11;
40  txChild[i].vin[0].prevout.hash = txParent.GetHash();
41  txChild[i].vin[0].prevout.n = i;
42  txChild[i].vout.resize(1);
43  txChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
44  txChild[i].vout[0].nValue = 11000LL;
45  }
46  CMutableTransaction txGrandChild[3];
47  for (int i = 0; i < 3; i++)
48  {
49  txGrandChild[i].vin.resize(1);
50  txGrandChild[i].vin[0].scriptSig = CScript() << OP_11;
51  txGrandChild[i].vin[0].prevout.hash = txChild[i].GetHash();
52  txGrandChild[i].vin[0].prevout.n = 0;
53  txGrandChild[i].vout.resize(1);
54  txGrandChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
55  txGrandChild[i].vout[0].nValue = 11000LL;
56  }
57 
58 
59  CTxMemPool testPool;
60  LOCK2(cs_main, testPool.cs);
61 
62  // Nothing in pool, remove should do nothing:
63  unsigned int poolSize = testPool.size();
65  BOOST_CHECK_EQUAL(testPool.size(), poolSize);
66 
67  // Just the parent:
68  testPool.addUnchecked(entry.FromTx(txParent));
69  poolSize = testPool.size();
71  BOOST_CHECK_EQUAL(testPool.size(), poolSize - 1);
72 
73  // Parent, children, grandchildren:
74  testPool.addUnchecked(entry.FromTx(txParent));
75  for (int i = 0; i < 3; i++)
76  {
77  testPool.addUnchecked(entry.FromTx(txChild[i]));
78  testPool.addUnchecked(entry.FromTx(txGrandChild[i]));
79  }
80  // Remove Child[0], GrandChild[0] should be removed:
81  poolSize = testPool.size();
82  testPool.removeRecursive(CTransaction(txChild[0]), REMOVAL_REASON_DUMMY);
83  BOOST_CHECK_EQUAL(testPool.size(), poolSize - 2);
84  // ... make sure grandchild and child are gone:
85  poolSize = testPool.size();
86  testPool.removeRecursive(CTransaction(txGrandChild[0]), REMOVAL_REASON_DUMMY);
87  BOOST_CHECK_EQUAL(testPool.size(), poolSize);
88  poolSize = testPool.size();
89  testPool.removeRecursive(CTransaction(txChild[0]), REMOVAL_REASON_DUMMY);
90  BOOST_CHECK_EQUAL(testPool.size(), poolSize);
91  // Remove parent, all children/grandchildren should go:
92  poolSize = testPool.size();
94  BOOST_CHECK_EQUAL(testPool.size(), poolSize - 5);
95  BOOST_CHECK_EQUAL(testPool.size(), 0U);
96 
97  // Add children and grandchildren, but NOT the parent (simulate the parent being in a block)
98  for (int i = 0; i < 3; i++)
99  {
100  testPool.addUnchecked(entry.FromTx(txChild[i]));
101  testPool.addUnchecked(entry.FromTx(txGrandChild[i]));
102  }
103  // Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be
104  // put into the mempool (maybe because it is non-standard):
105  poolSize = testPool.size();
107  BOOST_CHECK_EQUAL(testPool.size(), poolSize - 6);
108  BOOST_CHECK_EQUAL(testPool.size(), 0U);
109 }
110 
111 template<typename name>
112 static void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
113 {
114  BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size());
115  typename CTxMemPool::indexed_transaction_set::index<name>::type::iterator it = pool.mapTx.get<name>().begin();
116  int count=0;
117  for (; it != pool.mapTx.get<name>().end(); ++it, ++count) {
118  BOOST_CHECK_EQUAL(it->GetTx().GetHash().ToString(), sortedOrder[count]);
119  }
120 }
121 
122 BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
123 {
124  CTxMemPool pool;
125  LOCK2(cs_main, pool.cs);
127 
128  /* 3rd highest fee */
130  tx1.vout.resize(1);
131  tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
132  tx1.vout[0].nValue = 10 * COIN;
133  pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1));
134 
135  /* highest fee */
137  tx2.vout.resize(1);
138  tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
139  tx2.vout[0].nValue = 2 * COIN;
140  pool.addUnchecked(entry.Fee(20000LL).FromTx(tx2));
141 
142  /* lowest fee */
144  tx3.vout.resize(1);
145  tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
146  tx3.vout[0].nValue = 5 * COIN;
147  pool.addUnchecked(entry.Fee(0LL).FromTx(tx3));
148 
149  /* 2nd highest fee */
151  tx4.vout.resize(1);
152  tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
153  tx4.vout[0].nValue = 6 * COIN;
154  pool.addUnchecked(entry.Fee(15000LL).FromTx(tx4));
155 
156  /* equal fee rate to tx1, but newer */
158  tx5.vout.resize(1);
159  tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
160  tx5.vout[0].nValue = 11 * COIN;
161  entry.nTime = 1;
162  pool.addUnchecked(entry.Fee(10000LL).FromTx(tx5));
163  BOOST_CHECK_EQUAL(pool.size(), 5U);
164 
165  std::vector<std::string> sortedOrder;
166  sortedOrder.resize(5);
167  sortedOrder[0] = tx3.GetHash().ToString(); // 0
168  sortedOrder[1] = tx5.GetHash().ToString(); // 10000
169  sortedOrder[2] = tx1.GetHash().ToString(); // 10000
170  sortedOrder[3] = tx4.GetHash().ToString(); // 15000
171  sortedOrder[4] = tx2.GetHash().ToString(); // 20000
172  CheckSort<descendant_score>(pool, sortedOrder);
173 
174  /* low fee but with high fee child */
175  /* tx6 -> tx7 -> tx8, tx9 -> tx10 */
177  tx6.vout.resize(1);
178  tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
179  tx6.vout[0].nValue = 20 * COIN;
180  pool.addUnchecked(entry.Fee(0LL).FromTx(tx6));
181  BOOST_CHECK_EQUAL(pool.size(), 6U);
182  // Check that at this point, tx6 is sorted low
183  sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString());
184  CheckSort<descendant_score>(pool, sortedOrder);
185 
186  CTxMemPool::setEntries setAncestors;
187  setAncestors.insert(pool.mapTx.find(tx6.GetHash()));
189  tx7.vin.resize(1);
190  tx7.vin[0].prevout = COutPoint(tx6.GetHash(), 0);
191  tx7.vin[0].scriptSig = CScript() << OP_11;
192  tx7.vout.resize(2);
193  tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
194  tx7.vout[0].nValue = 10 * COIN;
195  tx7.vout[1].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
196  tx7.vout[1].nValue = 1 * COIN;
197 
198  CTxMemPool::setEntries setAncestorsCalculated;
199  std::string dummy;
200  BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(2000000LL).FromTx(tx7), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true);
201  BOOST_CHECK(setAncestorsCalculated == setAncestors);
202 
203  pool.addUnchecked(entry.FromTx(tx7), setAncestors);
204  BOOST_CHECK_EQUAL(pool.size(), 7U);
205 
206  // Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ...
207  sortedOrder.erase(sortedOrder.begin());
208  sortedOrder.push_back(tx6.GetHash().ToString());
209  sortedOrder.push_back(tx7.GetHash().ToString());
210  CheckSort<descendant_score>(pool, sortedOrder);
211 
212  /* low fee child of tx7 */
214  tx8.vin.resize(1);
215  tx8.vin[0].prevout = COutPoint(tx7.GetHash(), 0);
216  tx8.vin[0].scriptSig = CScript() << OP_11;
217  tx8.vout.resize(1);
218  tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
219  tx8.vout[0].nValue = 10 * COIN;
220  setAncestors.insert(pool.mapTx.find(tx7.GetHash()));
221  pool.addUnchecked(entry.Fee(0LL).Time(2).FromTx(tx8), setAncestors);
222 
223  // Now tx8 should be sorted low, but tx6/tx both high
224  sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString());
225  CheckSort<descendant_score>(pool, sortedOrder);
226 
227  /* low fee child of tx7 */
229  tx9.vin.resize(1);
230  tx9.vin[0].prevout = COutPoint(tx7.GetHash(), 1);
231  tx9.vin[0].scriptSig = CScript() << OP_11;
232  tx9.vout.resize(1);
233  tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
234  tx9.vout[0].nValue = 1 * COIN;
235  pool.addUnchecked(entry.Fee(0LL).Time(3).FromTx(tx9), setAncestors);
236 
237  // tx9 should be sorted low
238  BOOST_CHECK_EQUAL(pool.size(), 9U);
239  sortedOrder.insert(sortedOrder.begin(), tx9.GetHash().ToString());
240  CheckSort<descendant_score>(pool, sortedOrder);
241 
242  std::vector<std::string> snapshotOrder = sortedOrder;
243 
244  setAncestors.insert(pool.mapTx.find(tx8.GetHash()));
245  setAncestors.insert(pool.mapTx.find(tx9.GetHash()));
246  /* tx10 depends on tx8 and tx9 and has a high fee*/
248  tx10.vin.resize(2);
249  tx10.vin[0].prevout = COutPoint(tx8.GetHash(), 0);
250  tx10.vin[0].scriptSig = CScript() << OP_11;
251  tx10.vin[1].prevout = COutPoint(tx9.GetHash(), 0);
252  tx10.vin[1].scriptSig = CScript() << OP_11;
253  tx10.vout.resize(1);
254  tx10.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
255  tx10.vout[0].nValue = 10 * COIN;
256 
257  setAncestorsCalculated.clear();
258  BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(4).FromTx(tx10), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true);
259  BOOST_CHECK(setAncestorsCalculated == setAncestors);
260 
261  pool.addUnchecked(entry.FromTx(tx10), setAncestors);
262 
278  sortedOrder.erase(sortedOrder.begin(), sortedOrder.begin()+2); // take out tx9, tx8 from the beginning
279  sortedOrder.insert(sortedOrder.begin()+5, tx9.GetHash().ToString());
280  sortedOrder.insert(sortedOrder.begin()+6, tx8.GetHash().ToString());
281  sortedOrder.insert(sortedOrder.begin()+7, tx10.GetHash().ToString()); // tx10 is just before tx6
282  CheckSort<descendant_score>(pool, sortedOrder);
283 
284  // there should be 10 transactions in the mempool
285  BOOST_CHECK_EQUAL(pool.size(), 10U);
286 
287  // Now try removing tx10 and verify the sort order returns to normal
288  pool.removeRecursive(pool.mapTx.find(tx10.GetHash())->GetTx(), REMOVAL_REASON_DUMMY);
289  CheckSort<descendant_score>(pool, snapshotOrder);
290 
291  pool.removeRecursive(pool.mapTx.find(tx9.GetHash())->GetTx(), REMOVAL_REASON_DUMMY);
292  pool.removeRecursive(pool.mapTx.find(tx8.GetHash())->GetTx(), REMOVAL_REASON_DUMMY);
293 }
294 
295 BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
296 {
297  CTxMemPool pool;
298  LOCK2(cs_main, pool.cs);
300 
301  /* 3rd highest fee */
303  tx1.vout.resize(1);
304  tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
305  tx1.vout[0].nValue = 10 * COIN;
306  pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1));
307 
308  /* highest fee */
310  tx2.vout.resize(1);
311  tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
312  tx2.vout[0].nValue = 2 * COIN;
313  pool.addUnchecked(entry.Fee(20000LL).FromTx(tx2));
314  uint64_t tx2Size = GetVirtualTransactionSize(CTransaction(tx2));
315 
316  /* lowest fee */
318  tx3.vout.resize(1);
319  tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
320  tx3.vout[0].nValue = 5 * COIN;
321  pool.addUnchecked(entry.Fee(0LL).FromTx(tx3));
322 
323  /* 2nd highest fee */
325  tx4.vout.resize(1);
326  tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
327  tx4.vout[0].nValue = 6 * COIN;
328  pool.addUnchecked(entry.Fee(15000LL).FromTx(tx4));
329 
330  /* equal fee rate to tx1, but newer */
332  tx5.vout.resize(1);
333  tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
334  tx5.vout[0].nValue = 11 * COIN;
335  pool.addUnchecked(entry.Fee(10000LL).FromTx(tx5));
336  BOOST_CHECK_EQUAL(pool.size(), 5U);
337 
338  std::vector<std::string> sortedOrder;
339  sortedOrder.resize(5);
340  sortedOrder[0] = tx2.GetHash().ToString(); // 20000
341  sortedOrder[1] = tx4.GetHash().ToString(); // 15000
342  // tx1 and tx5 are both 10000
343  // Ties are broken by hash, not timestamp, so determine which
344  // hash comes first.
345  if (tx1.GetHash() < tx5.GetHash()) {
346  sortedOrder[2] = tx1.GetHash().ToString();
347  sortedOrder[3] = tx5.GetHash().ToString();
348  } else {
349  sortedOrder[2] = tx5.GetHash().ToString();
350  sortedOrder[3] = tx1.GetHash().ToString();
351  }
352  sortedOrder[4] = tx3.GetHash().ToString(); // 0
353 
354  CheckSort<ancestor_score>(pool, sortedOrder);
355 
356  /* low fee parent with high fee child */
357  /* tx6 (0) -> tx7 (high) */
359  tx6.vout.resize(1);
360  tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
361  tx6.vout[0].nValue = 20 * COIN;
362  uint64_t tx6Size = GetVirtualTransactionSize(CTransaction(tx6));
363 
364  pool.addUnchecked(entry.Fee(0LL).FromTx(tx6));
365  BOOST_CHECK_EQUAL(pool.size(), 6U);
366  // Ties are broken by hash
367  if (tx3.GetHash() < tx6.GetHash())
368  sortedOrder.push_back(tx6.GetHash().ToString());
369  else
370  sortedOrder.insert(sortedOrder.end()-1,tx6.GetHash().ToString());
371 
372  CheckSort<ancestor_score>(pool, sortedOrder);
373 
375  tx7.vin.resize(1);
376  tx7.vin[0].prevout = COutPoint(tx6.GetHash(), 0);
377  tx7.vin[0].scriptSig = CScript() << OP_11;
378  tx7.vout.resize(1);
379  tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
380  tx7.vout[0].nValue = 10 * COIN;
381  uint64_t tx7Size = GetVirtualTransactionSize(CTransaction(tx7));
382 
383  /* set the fee to just below tx2's feerate when including ancestor */
384  CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1;
385 
386  pool.addUnchecked(entry.Fee(fee).FromTx(tx7));
387  BOOST_CHECK_EQUAL(pool.size(), 7U);
388  sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString());
389  CheckSort<ancestor_score>(pool, sortedOrder);
390 
391  /* after tx6 is mined, tx7 should move up in the sort */
392  std::vector<CTransactionRef> vtx;
393  vtx.push_back(MakeTransactionRef(tx6));
394  pool.removeForBlock(vtx, 1);
395 
396  sortedOrder.erase(sortedOrder.begin()+1);
397  // Ties are broken by hash
398  if (tx3.GetHash() < tx6.GetHash())
399  sortedOrder.pop_back();
400  else
401  sortedOrder.erase(sortedOrder.end()-2);
402  sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString());
403  CheckSort<ancestor_score>(pool, sortedOrder);
404 
405  // High-fee parent, low-fee child
406  // tx7 -> tx8
408  tx8.vin.resize(1);
409  tx8.vin[0].prevout = COutPoint(tx7.GetHash(), 0);
410  tx8.vin[0].scriptSig = CScript() << OP_11;
411  tx8.vout.resize(1);
412  tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
413  tx8.vout[0].nValue = 10*COIN;
414 
415  // Check that we sort by min(feerate, ancestor_feerate):
416  // set the fee so that the ancestor feerate is above tx1/5,
417  // but the transaction's own feerate is lower
418  pool.addUnchecked(entry.Fee(5000LL).FromTx(tx8));
419  sortedOrder.insert(sortedOrder.end()-1, tx8.GetHash().ToString());
420  CheckSort<ancestor_score>(pool, sortedOrder);
421 }
422 
423 
424 BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
425 {
426  CTxMemPool pool;
427  LOCK2(cs_main, pool.cs);
429 
431  tx1.vin.resize(1);
432  tx1.vin[0].scriptSig = CScript() << OP_1;
433  tx1.vout.resize(1);
434  tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
435  tx1.vout[0].nValue = 10 * COIN;
436  pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1));
437 
439  tx2.vin.resize(1);
440  tx2.vin[0].scriptSig = CScript() << OP_2;
441  tx2.vout.resize(1);
442  tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
443  tx2.vout[0].nValue = 10 * COIN;
444  pool.addUnchecked(entry.Fee(5000LL).FromTx(tx2));
445 
446  pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing
447  BOOST_CHECK(pool.exists(tx1.GetHash()));
448  BOOST_CHECK(pool.exists(tx2.GetHash()));
449 
450  pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // should remove the lower-feerate transaction
451  BOOST_CHECK(pool.exists(tx1.GetHash()));
452  BOOST_CHECK(!pool.exists(tx2.GetHash()));
453 
454  pool.addUnchecked(entry.FromTx(tx2));
456  tx3.vin.resize(1);
457  tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
458  tx3.vin[0].scriptSig = CScript() << OP_2;
459  tx3.vout.resize(1);
460  tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
461  tx3.vout[0].nValue = 10 * COIN;
462  pool.addUnchecked(entry.Fee(20000LL).FromTx(tx3));
463 
464  pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)
465  BOOST_CHECK(!pool.exists(tx1.GetHash()));
466  BOOST_CHECK(pool.exists(tx2.GetHash()));
467  BOOST_CHECK(pool.exists(tx3.GetHash()));
468 
469  pool.TrimToSize(GetVirtualTransactionSize(CTransaction(tx1))); // mempool is limited to tx1's size in memory usage, so nothing fits
470  BOOST_CHECK(!pool.exists(tx1.GetHash()));
471  BOOST_CHECK(!pool.exists(tx2.GetHash()));
472  BOOST_CHECK(!pool.exists(tx3.GetHash()));
473 
475  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
476 
478  tx4.vin.resize(2);
479  tx4.vin[0].prevout.SetNull();
480  tx4.vin[0].scriptSig = CScript() << OP_4;
481  tx4.vin[1].prevout.SetNull();
482  tx4.vin[1].scriptSig = CScript() << OP_4;
483  tx4.vout.resize(2);
484  tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
485  tx4.vout[0].nValue = 10 * COIN;
486  tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
487  tx4.vout[1].nValue = 10 * COIN;
488 
490  tx5.vin.resize(2);
491  tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0);
492  tx5.vin[0].scriptSig = CScript() << OP_4;
493  tx5.vin[1].prevout.SetNull();
494  tx5.vin[1].scriptSig = CScript() << OP_5;
495  tx5.vout.resize(2);
496  tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
497  tx5.vout[0].nValue = 10 * COIN;
498  tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
499  tx5.vout[1].nValue = 10 * COIN;
500 
502  tx6.vin.resize(2);
503  tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1);
504  tx6.vin[0].scriptSig = CScript() << OP_4;
505  tx6.vin[1].prevout.SetNull();
506  tx6.vin[1].scriptSig = CScript() << OP_6;
507  tx6.vout.resize(2);
508  tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
509  tx6.vout[0].nValue = 10 * COIN;
510  tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
511  tx6.vout[1].nValue = 10 * COIN;
512 
514  tx7.vin.resize(2);
515  tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0);
516  tx7.vin[0].scriptSig = CScript() << OP_5;
517  tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);
518  tx7.vin[1].scriptSig = CScript() << OP_6;
519  tx7.vout.resize(2);
520  tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
521  tx7.vout[0].nValue = 10 * COIN;
522  tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
523  tx7.vout[1].nValue = 10 * COIN;
524 
525  pool.addUnchecked(entry.Fee(7000LL).FromTx(tx4));
526  pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5));
527  pool.addUnchecked(entry.Fee(1100LL).FromTx(tx6));
528  pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7));
529 
530  // we only require this to remove, at max, 2 txn, because it's not clear what we're really optimizing for aside from that
531  pool.TrimToSize(pool.DynamicMemoryUsage() - 1);
532  BOOST_CHECK(pool.exists(tx4.GetHash()));
533  BOOST_CHECK(pool.exists(tx6.GetHash()));
534  BOOST_CHECK(!pool.exists(tx7.GetHash()));
535 
536  if (!pool.exists(tx5.GetHash()))
537  pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5));
538  pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7));
539 
540  pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7
541  BOOST_CHECK(pool.exists(tx4.GetHash()));
542  BOOST_CHECK(!pool.exists(tx5.GetHash()));
543  BOOST_CHECK(pool.exists(tx6.GetHash()));
544  BOOST_CHECK(!pool.exists(tx7.GetHash()));
545 
546  pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5));
547  pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7));
548 
549  std::vector<CTransactionRef> vtx;
550  SetMockTime(42);
552  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
553  // ... we should keep the same min fee until we get a block
554  pool.removeForBlock(vtx, 1);
556  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/2.0));
557  // ... then feerate should drop 1/2 each halflife
558 
560  BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/4.0));
561  // ... with a 1/2 halflife when mempool is < 1/2 its target size
562 
564  BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/8.0));
565  // ... with a 1/4 halflife when mempool is < 1/4 its target size
566 
568  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 1000);
569  // ... but feerate should never drop below 1000
570 
572  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0);
573  // ... unless it has gone all the way to 0 (after getting past 1000/2)
574 }
575 
576 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>())
577 {
579  tx.vin.resize(inputs.size());
580  tx.vout.resize(output_values.size());
581  for (size_t i = 0; i < inputs.size(); ++i) {
582  tx.vin[i].prevout.hash = inputs[i]->GetHash();
583  tx.vin[i].prevout.n = input_indices.size() > i ? input_indices[i] : 0;
584  }
585  for (size_t i = 0; i < output_values.size(); ++i) {
586  tx.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
587  tx.vout[i].nValue = output_values[i];
588  }
589  return MakeTransactionRef(tx);
590 }
591 
592 
593 BOOST_AUTO_TEST_CASE(MempoolAncestryTests)
594 {
595  size_t ancestors, descendants;
596 
597  CTxMemPool pool;
598  LOCK2(cs_main, pool.cs);
600 
601  /* Base transaction */
602  //
603  // [tx1]
604  //
605  CTransactionRef tx1 = make_tx(/* output_values */ {10 * COIN});
606  pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1));
607 
608  // Ancestors / descendants should be 1 / 1 (itself / itself)
609  pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
610  BOOST_CHECK_EQUAL(ancestors, 1ULL);
611  BOOST_CHECK_EQUAL(descendants, 1ULL);
612 
613  /* Child transaction */
614  //
615  // [tx1].0 <- [tx2]
616  //
617  CTransactionRef tx2 = make_tx(/* output_values */ {495 * CENT, 5 * COIN}, /* inputs */ {tx1});
618  pool.addUnchecked(entry.Fee(10000LL).FromTx(tx2));
619 
620  // Ancestors / descendants should be:
621  // transaction ancestors descendants
622  // ============ =========== ===========
623  // tx1 1 (tx1) 2 (tx1,2)
624  // tx2 2 (tx1,2) 2 (tx1,2)
625  pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
626  BOOST_CHECK_EQUAL(ancestors, 1ULL);
627  BOOST_CHECK_EQUAL(descendants, 2ULL);
628  pool.GetTransactionAncestry(tx2->GetHash(), ancestors, descendants);
629  BOOST_CHECK_EQUAL(ancestors, 2ULL);
630  BOOST_CHECK_EQUAL(descendants, 2ULL);
631 
632  /* Grand-child 1 */
633  //
634  // [tx1].0 <- [tx2].0 <- [tx3]
635  //
636  CTransactionRef tx3 = make_tx(/* output_values */ {290 * CENT, 200 * CENT}, /* inputs */ {tx2});
637  pool.addUnchecked(entry.Fee(10000LL).FromTx(tx3));
638 
639  // Ancestors / descendants should be:
640  // transaction ancestors descendants
641  // ============ =========== ===========
642  // tx1 1 (tx1) 3 (tx1,2,3)
643  // tx2 2 (tx1,2) 3 (tx1,2,3)
644  // tx3 3 (tx1,2,3) 3 (tx1,2,3)
645  pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
646  BOOST_CHECK_EQUAL(ancestors, 1ULL);
647  BOOST_CHECK_EQUAL(descendants, 3ULL);
648  pool.GetTransactionAncestry(tx2->GetHash(), ancestors, descendants);
649  BOOST_CHECK_EQUAL(ancestors, 2ULL);
650  BOOST_CHECK_EQUAL(descendants, 3ULL);
651  pool.GetTransactionAncestry(tx3->GetHash(), ancestors, descendants);
652  BOOST_CHECK_EQUAL(ancestors, 3ULL);
653  BOOST_CHECK_EQUAL(descendants, 3ULL);
654 
655  /* Grand-child 2 */
656  //
657  // [tx1].0 <- [tx2].0 <- [tx3]
658  // |
659  // \---1 <- [tx4]
660  //
661  CTransactionRef tx4 = make_tx(/* output_values */ {290 * CENT, 250 * CENT}, /* inputs */ {tx2}, /* input_indices */ {1});
662  pool.addUnchecked(entry.Fee(10000LL).FromTx(tx4));
663 
664  // Ancestors / descendants should be:
665  // transaction ancestors descendants
666  // ============ =========== ===========
667  // tx1 1 (tx1) 4 (tx1,2,3,4)
668  // tx2 2 (tx1,2) 4 (tx1,2,3,4)
669  // tx3 3 (tx1,2,3) 4 (tx1,2,3,4)
670  // tx4 3 (tx1,2,4) 4 (tx1,2,3,4)
671  pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
672  BOOST_CHECK_EQUAL(ancestors, 1ULL);
673  BOOST_CHECK_EQUAL(descendants, 4ULL);
674  pool.GetTransactionAncestry(tx2->GetHash(), ancestors, descendants);
675  BOOST_CHECK_EQUAL(ancestors, 2ULL);
676  BOOST_CHECK_EQUAL(descendants, 4ULL);
677  pool.GetTransactionAncestry(tx3->GetHash(), ancestors, descendants);
678  BOOST_CHECK_EQUAL(ancestors, 3ULL);
679  BOOST_CHECK_EQUAL(descendants, 4ULL);
680  pool.GetTransactionAncestry(tx4->GetHash(), ancestors, descendants);
681  BOOST_CHECK_EQUAL(ancestors, 3ULL);
682  BOOST_CHECK_EQUAL(descendants, 4ULL);
683 
684  /* Make an alternate branch that is longer and connect it to tx3 */
685  //
686  // [ty1].0 <- [ty2].0 <- [ty3].0 <- [ty4].0 <- [ty5].0
687  // |
688  // [tx1].0 <- [tx2].0 <- [tx3].0 <- [ty6] --->--/
689  // |
690  // \---1 <- [tx4]
691  //
692  CTransactionRef ty1, ty2, ty3, ty4, ty5;
693  CTransactionRef* ty[5] = {&ty1, &ty2, &ty3, &ty4, &ty5};
694  CAmount v = 5 * COIN;
695  for (uint64_t i = 0; i < 5; i++) {
696  CTransactionRef& tyi = *ty[i];
697  tyi = make_tx(/* output_values */ {v}, /* inputs */ i > 0 ? std::vector<CTransactionRef>{*ty[i - 1]} : std::vector<CTransactionRef>{});
698  v -= 50 * CENT;
699  pool.addUnchecked(entry.Fee(10000LL).FromTx(tyi));
700  pool.GetTransactionAncestry(tyi->GetHash(), ancestors, descendants);
701  BOOST_CHECK_EQUAL(ancestors, i+1);
702  BOOST_CHECK_EQUAL(descendants, i+1);
703  }
704  CTransactionRef ty6 = make_tx(/* output_values */ {5 * COIN}, /* inputs */ {tx3, ty5});
705  pool.addUnchecked(entry.Fee(10000LL).FromTx(ty6));
706 
707  // Ancestors / descendants should be:
708  // transaction ancestors descendants
709  // ============ =================== ===========
710  // tx1 1 (tx1) 5 (tx1,2,3,4, ty6)
711  // tx2 2 (tx1,2) 5 (tx1,2,3,4, ty6)
712  // tx3 3 (tx1,2,3) 5 (tx1,2,3,4, ty6)
713  // tx4 3 (tx1,2,4) 5 (tx1,2,3,4, ty6)
714  // ty1 1 (ty1) 6 (ty1,2,3,4,5,6)
715  // ty2 2 (ty1,2) 6 (ty1,2,3,4,5,6)
716  // ty3 3 (ty1,2,3) 6 (ty1,2,3,4,5,6)
717  // ty4 4 (y1234) 6 (ty1,2,3,4,5,6)
718  // ty5 5 (y12345) 6 (ty1,2,3,4,5,6)
719  // ty6 9 (tx123, ty123456) 6 (ty1,2,3,4,5,6)
720  pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
721  BOOST_CHECK_EQUAL(ancestors, 1ULL);
722  BOOST_CHECK_EQUAL(descendants, 5ULL);
723  pool.GetTransactionAncestry(tx2->GetHash(), ancestors, descendants);
724  BOOST_CHECK_EQUAL(ancestors, 2ULL);
725  BOOST_CHECK_EQUAL(descendants, 5ULL);
726  pool.GetTransactionAncestry(tx3->GetHash(), ancestors, descendants);
727  BOOST_CHECK_EQUAL(ancestors, 3ULL);
728  BOOST_CHECK_EQUAL(descendants, 5ULL);
729  pool.GetTransactionAncestry(tx4->GetHash(), ancestors, descendants);
730  BOOST_CHECK_EQUAL(ancestors, 3ULL);
731  BOOST_CHECK_EQUAL(descendants, 5ULL);
732  pool.GetTransactionAncestry(ty1->GetHash(), ancestors, descendants);
733  BOOST_CHECK_EQUAL(ancestors, 1ULL);
734  BOOST_CHECK_EQUAL(descendants, 6ULL);
735  pool.GetTransactionAncestry(ty2->GetHash(), ancestors, descendants);
736  BOOST_CHECK_EQUAL(ancestors, 2ULL);
737  BOOST_CHECK_EQUAL(descendants, 6ULL);
738  pool.GetTransactionAncestry(ty3->GetHash(), ancestors, descendants);
739  BOOST_CHECK_EQUAL(ancestors, 3ULL);
740  BOOST_CHECK_EQUAL(descendants, 6ULL);
741  pool.GetTransactionAncestry(ty4->GetHash(), ancestors, descendants);
742  BOOST_CHECK_EQUAL(ancestors, 4ULL);
743  BOOST_CHECK_EQUAL(descendants, 6ULL);
744  pool.GetTransactionAncestry(ty5->GetHash(), ancestors, descendants);
745  BOOST_CHECK_EQUAL(ancestors, 5ULL);
746  BOOST_CHECK_EQUAL(descendants, 6ULL);
747  pool.GetTransactionAncestry(ty6->GetHash(), ancestors, descendants);
748  BOOST_CHECK_EQUAL(ancestors, 9ULL);
749  BOOST_CHECK_EQUAL(descendants, 6ULL);
750 
751  /* Ancestors represented more than once ("diamond") */
752  //
753  // [ta].0 <- [tb].0 -----<------- [td].0
754  // | |
755  // \---1 <- [tc].0 --<--/
756  //
757  CTransactionRef ta, tb, tc, td;
758  ta = make_tx(/* output_values */ {10 * COIN});
759  tb = make_tx(/* output_values */ {5 * COIN, 3 * COIN}, /* inputs */ {ta});
760  tc = make_tx(/* output_values */ {2 * COIN}, /* inputs */ {tb}, /* input_indices */ {1});
761  td = make_tx(/* output_values */ {6 * COIN}, /* inputs */ {tb, tc}, /* input_indices */ {0, 0});
762  pool.clear();
763  pool.addUnchecked(entry.Fee(10000LL).FromTx(ta));
764  pool.addUnchecked(entry.Fee(10000LL).FromTx(tb));
765  pool.addUnchecked(entry.Fee(10000LL).FromTx(tc));
766  pool.addUnchecked(entry.Fee(10000LL).FromTx(td));
767 
768  // Ancestors / descendants should be:
769  // transaction ancestors descendants
770  // ============ =================== ===========
771  // ta 1 (ta 4 (ta,tb,tc,td)
772  // tb 2 (ta,tb) 4 (ta,tb,tc,td)
773  // tc 3 (ta,tb,tc) 4 (ta,tb,tc,td)
774  // td 4 (ta,tb,tc,td) 4 (ta,tb,tc,td)
775  pool.GetTransactionAncestry(ta->GetHash(), ancestors, descendants);
776  BOOST_CHECK_EQUAL(ancestors, 1ULL);
777  BOOST_CHECK_EQUAL(descendants, 4ULL);
778  pool.GetTransactionAncestry(tb->GetHash(), ancestors, descendants);
779  BOOST_CHECK_EQUAL(ancestors, 2ULL);
780  BOOST_CHECK_EQUAL(descendants, 4ULL);
781  pool.GetTransactionAncestry(tc->GetHash(), ancestors, descendants);
782  BOOST_CHECK_EQUAL(ancestors, 3ULL);
783  BOOST_CHECK_EQUAL(descendants, 4ULL);
784  pool.GetTransactionAncestry(td->GetHash(), ancestors, descendants);
785  BOOST_CHECK_EQUAL(ancestors, 4ULL);
786  BOOST_CHECK_EQUAL(descendants, 4ULL);
787 }
788 
LOCK2
#define LOCK2(cs1, cs2)
Definition: sync.h:227
CTxMemPool::setEntries
std::set< txiter, CompareIteratorByHash > setEntries
Definition: txmempool.h:572
policy.h
CMutableTransaction::vin
std::vector< CTxIn > vin
Definition: transaction.h:346
CTxMemPool::GetMinFee
CFeeRate GetMinFee(size_t sizelimit) const
The minimum fee to get into the mempool, which may itself not be enough for larger-sized transactions...
Definition: txmempool.cpp:1080
count
static int count
Definition: tests.c:41
TestMemPoolEntryHelper
Definition: setup_common.h:173
CTxMemPool::ROLLING_FEE_HALFLIFE
static const int ROLLING_FEE_HALFLIFE
Definition: txmempool.h:505
setup_common.h
CTxMemPool
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:478
CTxMemPool::TrimToSize
void TrimToSize(size_t sizelimit, std::vector< COutPoint > *pvNoSpendsRemaining=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
Remove transactions from the mempool until its dynamic size is <= sizelimit.
Definition: txmempool.cpp:1112
MakeTransactionRef
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:387
OP_3
@ OP_3
Definition: script.h:79
TestMemPoolEntryHelper::nTime
int64_t nTime
Definition: setup_common.h:177
CTxMemPool::CalculateMemPoolAncestors
bool CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents=true) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Try to calculate all in-mempool ancestors of entry.
Definition: txmempool.cpp:238
make_tx
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: mempool_tests.cpp:576
CTransactionRef
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:386
BOOST_FIXTURE_TEST_SUITE
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
BOOST_AUTO_TEST_SUITE_END
BOOST_AUTO_TEST_SUITE_END()
CFeeRate
Fee rate in satoshis per kilobyte: CAmount / kB.
Definition: feerate.h:29
CTransaction
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:259
CheckSort
static void CheckSort(CTxMemPool &pool, std::vector< std::string > &sortedOrder) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
Definition: mempool_tests.cpp:112
txmempool.h
OP_1
@ OP_1
Definition: script.h:76
CTxMemPool::cs
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:566
OP_EQUAL
@ OP_EQUAL
Definition: script.h:139
SetMockTime
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
Definition: time.cpp:101
CTxMemPool::GetTransactionAncestry
void GetTransactionAncestry(const uint256 &txid, size_t &ancestors, size_t &descendants, size_t *ancestorsize=nullptr, CAmount *ancestorfees=nullptr) const
Calculate the ancestor and descendant count for the given transaction.
Definition: txmempool.cpp:1177
CENT
static constexpr CAmount CENT
Definition: setup_common.h:71
time.h
CAmount
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
OP_4
@ OP_4
Definition: script.h:80
OP_2
@ OP_2
Definition: script.h:78
OP_5
@ OP_5
Definition: script.h:81
base_blob::ToString
std::string ToString() const
Definition: uint256.cpp:64
OP_6
@ OP_6
Definition: script.h:82
CScript
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:405
REMOVAL_REASON_DUMMY
static constexpr auto REMOVAL_REASON_DUMMY
Definition: mempool_tests.cpp:17
name
const char * name
Definition: rest.cpp:43
OP_7
@ OP_7
Definition: script.h:83
system.h
CMutableTransaction::vout
std::vector< CTxOut > vout
Definition: transaction.h:347
CTxMemPool::exists
bool exists(const GenTxid &gtxid) const
Definition: txmempool.h:780
TestMemPoolEntryHelper::Fee
TestMemPoolEntryHelper & Fee(CAmount _fee)
Definition: setup_common.h:191
cs_main
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: validation.cpp:117
CTxMemPool::addUnchecked
void check(CChainState &active_chainstate) const EXCLUSIVE_LOCKS_REQUIRED(void addUnchecked(const CTxMemPoolEntry &entry, bool validFeeEstimate=true) 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:637
EXCLUSIVE_LOCKS_REQUIRED
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
MemPoolRemovalReason
MemPoolRemovalReason
Reason why a transaction was removed from the mempool, this is passed to the notification signal.
Definition: txmempool.h:396
CTxMemPool::size
unsigned long size() const
Definition: txmempool.h:762
TestingSetup
Testing setup that configures a complete environment.
Definition: setup_common.h:99
COIN
static const CAmount COIN
Definition: amount.h:14
CTxMemPool::DynamicMemoryUsage
size_t DynamicMemoryUsage() const
Definition: txmempool.cpp:1009
COutPoint
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:26
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
Definition: mempool_tests.cpp:19
CMutableTransaction::GetHash
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:62
TestMemPoolEntryHelper::FromTx
CTxMemPoolEntry FromTx(const CMutableTransaction &tx) const
Definition: setup_common.cpp:312
CMutableTransaction
A mutable version of CTransaction.
Definition: transaction.h:344
CFeeRate::GetFeePerK
CAmount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
Definition: feerate.h:56
OP_11
@ OP_11
Definition: script.h:87
CTxMemPool::clear
void clear()
Definition: txmempool.cpp:668
GetVirtualTransactionSize
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:280
BOOST_CHECK
#define BOOST_CHECK(expr)
Definition: object.cpp:17
BOOST_CHECK_EQUAL
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
TestMemPoolEntryHelper::Time
TestMemPoolEntryHelper & Time(int64_t _time)
Definition: setup_common.h:192
CTxMemPool::removeForBlock
void removeForBlock(const std::vector< CTransactionRef > &vtx, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(cs)
Called when a block is connected.
Definition: txmempool.cpp:626
CTxMemPool::removeRecursive
void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.cpp:536