Skip to content

Commit 29d2633

Browse files
laanwjcodablock
authored andcommitted
Merge bitcoin#7594: Mempool: Add tracking of ancestor packages
ce019bf Check all ancestor state in CTxMemPool::check() (Suhas Daftuar) e2eeb5d Add ancestor feerate index to mempool (Suhas Daftuar) 72abd2c Add ancestor tracking to mempool (Suhas Daftuar) 76a7632 Remove work limit in UpdateForDescendants() (Suhas Daftuar) 5de2baa Rename CTxMemPool::remove -> removeRecursive (Suhas Daftuar) 7659438 CTxMemPool::removeForBlock now uses RemoveStaged (Suhas Daftuar)
1 parent 49a8ed6 commit 29d2633

File tree

4 files changed

+302
-124
lines changed

4 files changed

+302
-124
lines changed

src/test/mempool_tests.cpp

Lines changed: 114 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,12 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
5757
std::list<CTransaction> removed;
5858

5959
// Nothing in pool, remove should do nothing:
60-
testPool.remove(txParent, removed, true);
60+
testPool.removeRecursive(txParent, removed);
6161
BOOST_CHECK_EQUAL(removed.size(), 0);
6262

6363
// Just the parent:
6464
testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent));
65-
testPool.remove(txParent, removed, true);
65+
testPool.removeRecursive(txParent, removed);
6666
BOOST_CHECK_EQUAL(removed.size(), 1);
6767
removed.clear();
6868

@@ -74,16 +74,16 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
7474
testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i]));
7575
}
7676
// Remove Child[0], GrandChild[0] should be removed:
77-
testPool.remove(txChild[0], removed, true);
77+
testPool.removeRecursive(txChild[0], removed);
7878
BOOST_CHECK_EQUAL(removed.size(), 2);
7979
removed.clear();
8080
// ... make sure grandchild and child are gone:
81-
testPool.remove(txGrandChild[0], removed, true);
81+
testPool.removeRecursive(txGrandChild[0], removed);
8282
BOOST_CHECK_EQUAL(removed.size(), 0);
83-
testPool.remove(txChild[0], removed, true);
83+
testPool.removeRecursive(txChild[0], removed);
8484
BOOST_CHECK_EQUAL(removed.size(), 0);
8585
// Remove parent, all children/grandchildren should go:
86-
testPool.remove(txParent, removed, true);
86+
testPool.removeRecursive(txParent, removed);
8787
BOOST_CHECK_EQUAL(removed.size(), 5);
8888
BOOST_CHECK_EQUAL(testPool.size(), 0);
8989
removed.clear();
@@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
9696
}
9797
// Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be
9898
// put into the mempool (maybe because it is non-standard):
99-
testPool.remove(txParent, removed, true);
99+
testPool.removeRecursive(txParent, removed);
100100
BOOST_CHECK_EQUAL(removed.size(), 6);
101101
BOOST_CHECK_EQUAL(testPool.size(), 0);
102102
removed.clear();
@@ -281,11 +281,11 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
281281

282282
// Now try removing tx10 and verify the sort order returns to normal
283283
std::list<CTransaction> removed;
284-
pool.remove(pool.mapTx.find(tx10.GetHash())->GetTx(), removed, true);
284+
pool.removeRecursive(pool.mapTx.find(tx10.GetHash())->GetTx(), removed);
285285
CheckSort<descendant_score>(pool, snapshotOrder);
286286

287-
pool.remove(pool.mapTx.find(tx9.GetHash())->GetTx(), removed, true);
288-
pool.remove(pool.mapTx.find(tx8.GetHash())->GetTx(), removed, true);
287+
pool.removeRecursive(pool.mapTx.find(tx9.GetHash())->GetTx(), removed);
288+
pool.removeRecursive(pool.mapTx.find(tx8.GetHash())->GetTx(), removed);
289289
/* Now check the sort on the mining score index.
290290
* Final order should be:
291291
*
@@ -317,6 +317,110 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
317317
CheckSort<mining_score>(pool, sortedOrder);
318318
}
319319

320+
BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
321+
{
322+
CTxMemPool pool(CFeeRate(0));
323+
TestMemPoolEntryHelper entry;
324+
entry.hadNoDependencies = true;
325+
326+
/* 3rd highest fee */
327+
CMutableTransaction tx1 = CMutableTransaction();
328+
tx1.vout.resize(1);
329+
tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
330+
tx1.vout[0].nValue = 10 * COIN;
331+
pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1));
332+
333+
/* highest fee */
334+
CMutableTransaction tx2 = CMutableTransaction();
335+
tx2.vout.resize(1);
336+
tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
337+
tx2.vout[0].nValue = 2 * COIN;
338+
pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2));
339+
uint64_t tx2Size = ::GetSerializeSize(tx2, SER_NETWORK, PROTOCOL_VERSION);
340+
341+
/* lowest fee */
342+
CMutableTransaction tx3 = CMutableTransaction();
343+
tx3.vout.resize(1);
344+
tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
345+
tx3.vout[0].nValue = 5 * COIN;
346+
pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).Priority(100.0).FromTx(tx3));
347+
348+
/* 2nd highest fee */
349+
CMutableTransaction tx4 = CMutableTransaction();
350+
tx4.vout.resize(1);
351+
tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
352+
tx4.vout[0].nValue = 6 * COIN;
353+
pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4));
354+
355+
/* equal fee rate to tx1, but newer */
356+
CMutableTransaction tx5 = CMutableTransaction();
357+
tx5.vout.resize(1);
358+
tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
359+
tx5.vout[0].nValue = 11 * COIN;
360+
pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5));
361+
BOOST_CHECK_EQUAL(pool.size(), 5);
362+
363+
std::vector<std::string> sortedOrder;
364+
sortedOrder.resize(5);
365+
sortedOrder[0] = tx2.GetHash().ToString(); // 20000
366+
sortedOrder[1] = tx4.GetHash().ToString(); // 15000
367+
// tx1 and tx5 are both 10000
368+
// Ties are broken by hash, not timestamp, so determine which
369+
// hash comes first.
370+
if (tx1.GetHash() < tx5.GetHash()) {
371+
sortedOrder[2] = tx1.GetHash().ToString();
372+
sortedOrder[3] = tx5.GetHash().ToString();
373+
} else {
374+
sortedOrder[2] = tx5.GetHash().ToString();
375+
sortedOrder[3] = tx1.GetHash().ToString();
376+
}
377+
sortedOrder[4] = tx3.GetHash().ToString(); // 0
378+
379+
CheckSort<ancestor_score>(pool, sortedOrder);
380+
381+
/* low fee parent with high fee child */
382+
/* tx6 (0) -> tx7 (high) */
383+
CMutableTransaction tx6 = CMutableTransaction();
384+
tx6.vout.resize(1);
385+
tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
386+
tx6.vout[0].nValue = 20 * COIN;
387+
uint64_t tx6Size = ::GetSerializeSize(tx6, SER_NETWORK, PROTOCOL_VERSION);
388+
389+
pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6));
390+
BOOST_CHECK_EQUAL(pool.size(), 6);
391+
sortedOrder.push_back(tx6.GetHash().ToString());
392+
CheckSort<ancestor_score>(pool, sortedOrder);
393+
394+
CMutableTransaction tx7 = CMutableTransaction();
395+
tx7.vin.resize(1);
396+
tx7.vin[0].prevout = COutPoint(tx6.GetHash(), 0);
397+
tx7.vin[0].scriptSig = CScript() << OP_11;
398+
tx7.vout.resize(1);
399+
tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
400+
tx7.vout[0].nValue = 10 * COIN;
401+
uint64_t tx7Size = ::GetSerializeSize(tx7, SER_NETWORK, PROTOCOL_VERSION);
402+
403+
/* set the fee to just below tx2's feerate when including ancestor */
404+
CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1;
405+
406+
//CTxMemPoolEntry entry7(tx7, fee, 2, 10.0, 1, true);
407+
pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7));
408+
BOOST_CHECK_EQUAL(pool.size(), 7);
409+
sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString());
410+
CheckSort<ancestor_score>(pool, sortedOrder);
411+
412+
/* after tx6 is mined, tx7 should move up in the sort */
413+
std::vector<CTransaction> vtx;
414+
vtx.push_back(tx6);
415+
std::list<CTransaction> dummy;
416+
pool.removeForBlock(vtx, 1, dummy, false);
417+
418+
sortedOrder.erase(sortedOrder.begin()+1);
419+
sortedOrder.pop_back();
420+
sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString());
421+
CheckSort<ancestor_score>(pool, sortedOrder);
422+
}
423+
320424

321425
BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
322426
{

0 commit comments

Comments
 (0)