PIVX Core  5.6.99
P2P Digital Currency
mempool_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2014 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 "test/test_pivx.h"
6 
7 #include "policy/feerate.h"
8 #include "txmempool.h"
9 #include "util/system.h"
10 
11 #include <boost/test/unit_test.hpp>
12 
14 
15 BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
16 {
17  // Test CTxMemPool::remove functionality
18 
20  // Parent transaction with three children,
21  // and three grand-children:
22  CMutableTransaction txParent;
23  txParent.vin.resize(1);
24  txParent.vin[0].scriptSig = CScript() << OP_11;
25  txParent.vout.resize(3);
26  for (int i = 0; i < 3; i++)
27  {
28  txParent.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
29  txParent.vout[i].nValue = 33000LL;
30  }
31  CMutableTransaction txChild[3];
32  for (int i = 0; i < 3; i++)
33  {
34  txChild[i].vin.resize(1);
35  txChild[i].vin[0].scriptSig = CScript() << OP_11;
36  txChild[i].vin[0].prevout.hash = txParent.GetHash();
37  txChild[i].vin[0].prevout.n = i;
38  txChild[i].vout.resize(1);
39  txChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
40  txChild[i].vout[0].nValue = 11000LL;
41  }
42  CMutableTransaction txGrandChild[3];
43  for (int i = 0; i < 3; i++)
44  {
45  txGrandChild[i].vin.resize(1);
46  txGrandChild[i].vin[0].scriptSig = CScript() << OP_11;
47  txGrandChild[i].vin[0].prevout.hash = txChild[i].GetHash();
48  txGrandChild[i].vin[0].prevout.n = 0;
49  txGrandChild[i].vout.resize(1);
50  txGrandChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
51  txGrandChild[i].vout[0].nValue = 11000LL;
52  }
53 
54 
55  CTxMemPool testPool(CFeeRate(0));
56 
57  // Nothing in pool, remove should do nothing:
58  unsigned int poolSize = testPool.size();
59  testPool.removeRecursive(txParent);
60  BOOST_CHECK_EQUAL(testPool.size(), poolSize);
61 
62  // Just the parent:
63  testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent));
64  poolSize = testPool.size();
65  testPool.removeRecursive(txParent);
66  BOOST_CHECK_EQUAL(testPool.size(), poolSize - 1);
67 
68  // Parent, children, grandchildren:
69  testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent));
70  for (int i = 0; i < 3; i++)
71  {
72  testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i]));
73  testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i]));
74  }
75  // Remove Child[0], GrandChild[0] should be removed:
76  poolSize = testPool.size();
77  testPool.removeRecursive(txChild[0]);
78  BOOST_CHECK_EQUAL(testPool.size(), poolSize - 2);
79  // ... make sure grandchild and child are gone:
80  poolSize = testPool.size();
81  testPool.removeRecursive(txGrandChild[0]);
82  BOOST_CHECK_EQUAL(testPool.size(), poolSize);
83  poolSize = testPool.size();
84  testPool.removeRecursive(txChild[0]);
85  BOOST_CHECK_EQUAL(testPool.size(), poolSize);
86  // Remove parent, all children/grandchildren should go:
87  poolSize = testPool.size();
88  testPool.removeRecursive(txParent);
89  BOOST_CHECK_EQUAL(testPool.size(), poolSize - 5);
90  BOOST_CHECK_EQUAL(testPool.size(), 0);
91 
92  // Add children and grandchildren, but NOT the parent (simulate the parent being in a block)
93  for (int i = 0; i < 3; i++)
94  {
95  testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i]));
96  testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i]));
97  }
98  // Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be
99  // put into the mempool (maybe because it is non-standard):
100  poolSize = testPool.size();
101  testPool.removeRecursive(txParent);
102  BOOST_CHECK_EQUAL(testPool.size(), poolSize - 6);
103  BOOST_CHECK_EQUAL(testPool.size(), 0);
104 }
105 
106 template<typename name>
107 void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder)
108 {
109  BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size());
110  typename CTxMemPool::indexed_transaction_set::index<name>::type::iterator it = pool.mapTx.get<name>().begin();
111  int count=0;
112  for (; it != pool.mapTx.get<name>().end(); ++it, ++count) {
113  BOOST_CHECK_EQUAL(it->GetTx().GetHash().ToString(), sortedOrder[count]);
114  }
115 }
116 
117 BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
118 {
119  CTxMemPool pool(CFeeRate(0));
121 
122  /* 3rd highest fee */
124  tx1.vout.resize(1);
125  tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
126  tx1.vout[0].nValue = 10 * COIN;
127  pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));
128 
129  /* highest fee */
131  tx2.vout.resize(1);
132  tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
133  tx2.vout[0].nValue = 2 * COIN;
134  pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2));
135 
136  /* lowest fee */
138  tx3.vout.resize(1);
139  tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
140  tx3.vout[0].nValue = 5 * COIN;
141  pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3));
142 
143  /* 2nd highest fee */
145  tx4.vout.resize(1);
146  tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
147  tx4.vout[0].nValue = 6 * COIN;
148  pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4));
149 
150  /* equal fee rate to tx1, but newer */
152  tx5.vout.resize(1);
153  tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
154  tx5.vout[0].nValue = 11 * COIN;
155  entry.nTime = 1;
156  pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5));
157  BOOST_CHECK_EQUAL(pool.size(), 5);
158 
159  std::vector<std::string> sortedOrder;
160  sortedOrder.resize(5);
161  sortedOrder[0] = tx3.GetHash().ToString(); // 0
162  sortedOrder[1] = tx5.GetHash().ToString(); // 10000
163  sortedOrder[2] = tx1.GetHash().ToString(); // 10000
164  sortedOrder[3] = tx4.GetHash().ToString(); // 15000
165  sortedOrder[4] = tx2.GetHash().ToString(); // 20000
166  CheckSort<descendant_score>(pool, sortedOrder);
167 
168  /* low fee but with high fee child */
169  /* tx6 -> tx7 -> tx8, tx9 -> tx10 */
171  tx6.vout.resize(1);
172  tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
173  tx6.vout[0].nValue = 20 * COIN;
174  pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6));
175  BOOST_CHECK_EQUAL(pool.size(), 6);
176  // Check that at this point, tx6 is sorted low
177  sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString());
178  CheckSort<descendant_score>(pool, sortedOrder);
179 
180  CTxMemPool::setEntries setAncestors;
181  setAncestors.insert(pool.mapTx.find(tx6.GetHash()));
183  tx7.vin.resize(1);
184  tx7.vin[0].prevout = COutPoint(tx6.GetHash(), 0);
185  tx7.vin[0].scriptSig = CScript() << OP_11;
186  tx7.vout.resize(2);
187  tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
188  tx7.vout[0].nValue = 10 * COIN;
189  tx7.vout[1].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
190  tx7.vout[1].nValue = 1 * COIN;
191 
192  CTxMemPool::setEntries setAncestorsCalculated;
193  std::string dummy;
194  BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(2000000LL).FromTx(tx7), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true);
195  BOOST_CHECK(setAncestorsCalculated == setAncestors);
196 
197  pool.addUnchecked(tx7.GetHash(), entry.FromTx(tx7), setAncestors);
198  BOOST_CHECK_EQUAL(pool.size(), 7);
199 
200  // Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ...
201  sortedOrder.erase(sortedOrder.begin());
202  sortedOrder.push_back(tx6.GetHash().ToString());
203  sortedOrder.push_back(tx7.GetHash().ToString());
204  CheckSort<descendant_score>(pool, sortedOrder);
205 
206  /* low fee child of tx7 */
208  tx8.vin.resize(1);
209  tx8.vin[0].prevout = COutPoint(tx7.GetHash(), 0);
210  tx8.vin[0].scriptSig = CScript() << OP_11;
211  tx8.vout.resize(1);
212  tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
213  tx8.vout[0].nValue = 10 * COIN;
214  setAncestors.insert(pool.mapTx.find(tx7.GetHash()));
215  pool.addUnchecked(tx8.GetHash(), entry.Fee(0LL).Time(2).FromTx(tx8), setAncestors);
216 
217  // Now tx8 should be sorted low, but tx6/tx both high
218  sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString());
219  CheckSort<descendant_score>(pool, sortedOrder);
220 
221  /* low fee child of tx7 */
223  tx9.vin.resize(1);
224  tx9.vin[0].prevout = COutPoint(tx7.GetHash(), 1);
225  tx9.vin[0].scriptSig = CScript() << OP_11;
226  tx9.vout.resize(1);
227  tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
228  tx9.vout[0].nValue = 1 * COIN;
229  pool.addUnchecked(tx9.GetHash(), entry.Fee(0LL).Time(3).FromTx(tx9), setAncestors);
230 
231  // tx9 should be sorted low
232  BOOST_CHECK_EQUAL(pool.size(), 9);
233  sortedOrder.insert(sortedOrder.begin(), tx9.GetHash().ToString());
234  CheckSort<descendant_score>(pool, sortedOrder);
235 
236  std::vector<std::string> snapshotOrder = sortedOrder;
237 
238  setAncestors.insert(pool.mapTx.find(tx8.GetHash()));
239  setAncestors.insert(pool.mapTx.find(tx9.GetHash()));
240  /* tx10 depends on tx8 and tx9 and has a high fee*/
242  tx10.vin.resize(2);
243  tx10.vin[0].prevout = COutPoint(tx8.GetHash(), 0);
244  tx10.vin[0].scriptSig = CScript() << OP_11;
245  tx10.vin[1].prevout = COutPoint(tx9.GetHash(), 0);
246  tx10.vin[1].scriptSig = CScript() << OP_11;
247  tx10.vout.resize(1);
248  tx10.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
249  tx10.vout[0].nValue = 10 * COIN;
250 
251  setAncestorsCalculated.clear();
252  BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(4).FromTx(tx10), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true);
253  BOOST_CHECK(setAncestorsCalculated == setAncestors);
254 
255  pool.addUnchecked(tx10.GetHash(), entry.FromTx(tx10), setAncestors);
256 
272  sortedOrder.erase(sortedOrder.begin(), sortedOrder.begin()+2); // take out tx9, tx8 from the beginning
273  sortedOrder.insert(sortedOrder.begin()+5, tx9.GetHash().ToString());
274  sortedOrder.insert(sortedOrder.begin()+6, tx8.GetHash().ToString());
275  sortedOrder.insert(sortedOrder.begin()+7, tx10.GetHash().ToString()); // tx10 is just before tx6
276  CheckSort<descendant_score>(pool, sortedOrder);
277 
278  // there should be 10 transactions in the mempool
279  BOOST_CHECK_EQUAL(pool.size(), 10);
280 
281  // Now try removing tx10 and verify the sort order returns to normal
282  pool.removeRecursive(pool.mapTx.find(tx10.GetHash())->GetTx());
283  CheckSort<descendant_score>(pool, snapshotOrder);
284 
285  pool.removeRecursive(pool.mapTx.find(tx9.GetHash())->GetTx());
286  pool.removeRecursive(pool.mapTx.find(tx8.GetHash())->GetTx());
287  /* Now check the sort on the mining score index.
288  * Final order should be:
289  *
290  * tx7 (2M)
291  * tx2 (20k)
292  * tx4 (15000)
293  * tx1/tx5 (10000)
294  * tx3/6 (0)
295  * (Ties resolved by hash)
296  */
297  sortedOrder.clear();
298  sortedOrder.push_back(tx7.GetHash().ToString());
299  sortedOrder.push_back(tx2.GetHash().ToString());
300  sortedOrder.push_back(tx4.GetHash().ToString());
301  if (tx1.GetHash() < tx5.GetHash()) {
302  sortedOrder.push_back(tx5.GetHash().ToString());
303  sortedOrder.push_back(tx1.GetHash().ToString());
304  } else {
305  sortedOrder.push_back(tx1.GetHash().ToString());
306  sortedOrder.push_back(tx5.GetHash().ToString());
307  }
308  if (tx3.GetHash() < tx6.GetHash()) {
309  sortedOrder.push_back(tx6.GetHash().ToString());
310  sortedOrder.push_back(tx3.GetHash().ToString());
311  } else {
312  sortedOrder.push_back(tx3.GetHash().ToString());
313  sortedOrder.push_back(tx6.GetHash().ToString());
314  }
315  CheckSort<mining_score>(pool, sortedOrder);
316 }
317 
318 BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
319 {
320  CTxMemPool pool(CFeeRate(0));
322 
323  /* 3rd highest fee */
325  tx1.vout.resize(1);
326  tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
327  tx1.vout[0].nValue = 10 * COIN;
328  pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));
329 
330  /* highest fee */
332  tx2.vout.resize(1);
333  tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
334  tx2.vout[0].nValue = 2 * COIN;
335  pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2));
336  uint64_t tx2Size = ::GetSerializeSize(tx2, PROTOCOL_VERSION);
337 
338  /* lowest fee */
340  tx3.vout.resize(1);
341  tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
342  tx3.vout[0].nValue = 5 * COIN;
343  pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3));
344 
345  /* 2nd highest fee */
347  tx4.vout.resize(1);
348  tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
349  tx4.vout[0].nValue = 6 * COIN;
350  pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4));
351 
352  /* equal fee rate to tx1, but newer */
354  tx5.vout.resize(1);
355  tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
356  tx5.vout[0].nValue = 11 * COIN;
357  pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5));
358  BOOST_CHECK_EQUAL(pool.size(), 5);
359 
360  std::vector<std::string> sortedOrder;
361  sortedOrder.resize(5);
362  sortedOrder[0] = tx2.GetHash().ToString(); // 20000
363  sortedOrder[1] = tx4.GetHash().ToString(); // 15000
364  // tx1 and tx5 are both 10000
365  // Ties are broken by hash, not timestamp, so determine which
366  // hash comes first.
367  if (tx1.GetHash() < tx5.GetHash()) {
368  sortedOrder[2] = tx1.GetHash().ToString();
369  sortedOrder[3] = tx5.GetHash().ToString();
370  } else {
371  sortedOrder[2] = tx5.GetHash().ToString();
372  sortedOrder[3] = tx1.GetHash().ToString();
373  }
374  sortedOrder[4] = tx3.GetHash().ToString(); // 0
375 
376  CheckSort<ancestor_score>(pool, sortedOrder);
377 
378  /* low fee parent with high fee child */
379  /* tx6 (0) -> tx7 (high) */
381  tx6.vout.resize(1);
382  tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
383  tx6.vout[0].nValue = 20 * COIN;
384  uint64_t tx6Size = ::GetSerializeSize(tx6, PROTOCOL_VERSION);
385 
386  pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6));
387  BOOST_CHECK_EQUAL(pool.size(), 6);
388  // Ties are broken by hash
389  if (tx3.GetHash() < tx6.GetHash())
390  sortedOrder.push_back(tx6.GetHash().ToString());
391  else
392  sortedOrder.insert(sortedOrder.end()-1,tx6.GetHash().ToString());
393 
394  CheckSort<ancestor_score>(pool, sortedOrder);
395 
397  tx7.vin.resize(1);
398  tx7.vin[0].prevout = COutPoint(tx6.GetHash(), 0);
399  tx7.vin[0].scriptSig = CScript() << OP_11;
400  tx7.vout.resize(1);
401  tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
402  tx7.vout[0].nValue = 10 * COIN;
403  uint64_t tx7Size = ::GetSerializeSize(tx7, PROTOCOL_VERSION);
404 
405  /* set the fee to just below tx2's feerate when including ancestor */
406  CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1;
407 
408  pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7));
409  BOOST_CHECK_EQUAL(pool.size(), 7);
410  sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString());
411  CheckSort<ancestor_score>(pool, sortedOrder);
412 
413  /* after tx6 is mined, tx7 should move up in the sort */
414  std::vector<CTransactionRef> vtx;
415  vtx.emplace_back(MakeTransactionRef(tx6));
416  pool.removeForBlock(vtx, 1);
417 
418  sortedOrder.erase(sortedOrder.begin()+1);
419  // Ties are broken by hash
420  if (tx3.GetHash() < tx6.GetHash())
421  sortedOrder.pop_back();
422  else
423  sortedOrder.erase(sortedOrder.end()-2);
424  sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString());
425  CheckSort<ancestor_score>(pool, sortedOrder);
426 }
427 
428 
429 BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
430 {
431  CTxMemPool pool(CFeeRate(1000));
433 
435  tx1.vin.resize(1);
436  tx1.vin[0].scriptSig = CScript() << OP_1;
437  tx1.vout.resize(1);
438  tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
439  tx1.vout[0].nValue = 10 * COIN;
440  pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));
441 
443  tx2.vin.resize(1);
444  tx2.vin[0].scriptSig = CScript() << OP_2;
445  tx2.vout.resize(1);
446  tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
447  tx2.vout[0].nValue = 10 * COIN;
448  pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2));
449 
450  pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing
451  BOOST_CHECK(pool.exists(tx1.GetHash()));
452  BOOST_CHECK(pool.exists(tx2.GetHash()));
453 
454  pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // should remove the lower-feerate transaction
455  BOOST_CHECK(pool.exists(tx1.GetHash()));
456  BOOST_CHECK(!pool.exists(tx2.GetHash()));
457 
458  pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2));
460  tx3.vin.resize(1);
461  tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
462  tx3.vin[0].scriptSig = CScript() << OP_2;
463  tx3.vout.resize(1);
464  tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
465  tx3.vout[0].nValue = 10 * COIN;
466  pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3));
467 
468  pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)
469  BOOST_CHECK(!pool.exists(tx1.GetHash()));
470  BOOST_CHECK(pool.exists(tx2.GetHash()));
471  BOOST_CHECK(pool.exists(tx3.GetHash()));
472 
473  pool.TrimToSize(::GetSerializeSize(CTransaction(tx1), PROTOCOL_VERSION)); // mempool is limited to tx1's size in memory usage, so nothing fits
474  BOOST_CHECK(!pool.exists(tx1.GetHash()));
475  BOOST_CHECK(!pool.exists(tx2.GetHash()));
476  BOOST_CHECK(!pool.exists(tx3.GetHash()));
477 
478  CFeeRate maxFeeRateRemoved(25000, ::GetSerializeSize(CTransaction(tx3), PROTOCOL_VERSION) + ::GetSerializeSize(CTransaction(tx2), PROTOCOL_VERSION));
479  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
480 
482  tx4.vin.resize(2);
483  tx4.vin[0].prevout.SetNull();
484  tx4.vin[0].scriptSig = CScript() << OP_4;
485  tx4.vin[1].prevout.SetNull();
486  tx4.vin[1].scriptSig = CScript() << OP_4;
487  tx4.vout.resize(2);
488  tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
489  tx4.vout[0].nValue = 10 * COIN;
490  tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
491  tx4.vout[1].nValue = 10 * COIN;
492 
494  tx5.vin.resize(2);
495  tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0);
496  tx5.vin[0].scriptSig = CScript() << OP_4;
497  tx5.vin[1].prevout.SetNull();
498  tx5.vin[1].scriptSig = CScript() << OP_5;
499  tx5.vout.resize(2);
500  tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
501  tx5.vout[0].nValue = 10 * COIN;
502  tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
503  tx5.vout[1].nValue = 10 * COIN;
504 
506  tx6.vin.resize(2);
507  tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1);
508  tx6.vin[0].scriptSig = CScript() << OP_4;
509  tx6.vin[1].prevout.SetNull();
510  tx6.vin[1].scriptSig = CScript() << OP_6;
511  tx6.vout.resize(2);
512  tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
513  tx6.vout[0].nValue = 10 * COIN;
514  tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
515  tx6.vout[1].nValue = 10 * COIN;
516 
518  tx7.vin.resize(2);
519  tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0);
520  tx7.vin[0].scriptSig = CScript() << OP_5;
521  tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);
522  tx7.vin[1].scriptSig = CScript() << OP_6;
523  tx7.vout.resize(2);
524  tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
525  tx7.vout[0].nValue = 10 * COIN;
526  tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
527  tx7.vout[1].nValue = 10 * COIN;
528 
529  pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4));
530  pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
531  pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6));
532  pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
533 
534  // we only require this remove, at max, 2 txn, because its not clear what we're really optimizing for aside from that
535  pool.TrimToSize(pool.DynamicMemoryUsage() - 1);
536  BOOST_CHECK(pool.exists(tx4.GetHash()));
537  BOOST_CHECK(pool.exists(tx6.GetHash()));
538  BOOST_CHECK(!pool.exists(tx7.GetHash()));
539 
540  if (!pool.exists(tx5.GetHash()))
541  pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
542  pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
543 
544  pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7
545  BOOST_CHECK(pool.exists(tx4.GetHash()));
546  BOOST_CHECK(!pool.exists(tx5.GetHash()));
547  BOOST_CHECK(pool.exists(tx6.GetHash()));
548  BOOST_CHECK(!pool.exists(tx7.GetHash()));
549 
550  pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
551  pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
552 
553  std::vector<CTransactionRef> vtx;
554  SetMockTime(42);
556  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
557  // ... we should keep the same min fee until we get a block
558  pool.removeForBlock(vtx, 1);
560  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/2);
561  // ... then feerate should drop 1/2 each halflife
562 
564  BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/4);
565  // ... with a 1/2 halflife when mempool is < 1/2 its target size
566 
568  BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/8);
569  // ... with a 1/4 halflife when mempool is < 1/4 its target size
570 
572  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 1000);
573  // ... but feerate should never drop below 1000
574 
576  BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0);
577  // ... unless it has gone all the way to 0 (after getting past 1000/2)
578 
579  SetMockTime(0);
580 }
581 
int64_t CAmount
Amount in PIV (Can be negative)
Definition: amount.h:13
Fee rate in PIV per kilobyte: CAmount / kB.
Definition: feerate.h:20
CAmount GetFeePerK() const
Definition: feerate.h:29
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:72
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:244
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:384
void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason=MemPoolRemovalReason::UNKNOWN)
Definition: txmempool.cpp:601
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:1412
bool addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry, bool validFeeEstimate=true)
Definition: txmempool.cpp:1366
size_t DynamicMemoryUsage() const
Definition: txmempool.cpp:1327
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
Try to calculate all in-mempool ancestors of entry.
Definition: txmempool.cpp:149
bool exists(uint256 hash) const
Definition: txmempool.h:640
static const int ROLLING_FEE_HALFLIFE
Definition: txmempool.h:410
std::set< txiter, CompareIteratorByHash > setEntries
Definition: txmempool.h:481
indexed_transaction_set mapTx
Definition: txmempool.h:472
unsigned long size() const
Definition: txmempool.h:629
void TrimToSize(size_t sizelimit, std::vector< COutPoint > *pvNoSpendsRemaining=nullptr)
Remove transactions from the mempool until its dynamic size is <= sizelimit.
Definition: txmempool.cpp:1446
void removeForBlock(const std::vector< CTransactionRef > &vtx, unsigned int nBlockHeight)
Called when a block is connected.
Definition: txmempool.cpp:844
std::string ToString() const
Definition: uint256.cpp:65
BOOST_AUTO_TEST_SUITE_END()
void CheckSort(CTxMemPool &pool, std::vector< std::string > &sortedOrder)
BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK(expr)
Definition: object.cpp:17
const char * name
Definition: rest.cpp:37
@ OP_2
Definition: script.h:61
@ OP_EQUAL
Definition: script.h:122
@ OP_4
Definition: script.h:63
@ OP_1
Definition: script.h:59
@ OP_3
Definition: script.h:62
@ OP_11
Definition: script.h:70
@ OP_6
Definition: script.h:65
@ OP_7
Definition: script.h:66
@ OP_5
Definition: script.h:64
unsigned int GetSerializeSize(const std::array< T, N > &item)
array
Definition: serialize.h:847
A mutable version of CTransaction.
Definition: transaction.h:409
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:96
std::vector< CTxOut > vout
Definition: transaction.h:411
std::vector< CTxIn > vin
Definition: transaction.h:410
Definition: test_pivx.h:137
int64_t nTime
Definition: test_pivx.h:140
TestMemPoolEntryHelper & Time(int64_t _time)
Definition: test_pivx.h:154
TestMemPoolEntryHelper & Fee(CAmount _fee)
Definition: test_pivx.h:153
CTxMemPoolEntry FromTx(const CMutableTransaction &tx)
Definition: test_pivx.cpp:250
void SetMockTime(int64_t nMockTimeIn)
For testing.
Definition: utiltime.cpp:51