diff options
author | glozow <gloriajzhao@gmail.com> | 2023-10-31 09:24:23 +0000 |
---|---|---|
committer | glozow <gloriajzhao@gmail.com> | 2023-11-03 10:39:29 +0000 |
commit | d9cc99d04e813caed51c5f7b6ebdc4c39c8823c9 (patch) | |
tree | 5a744b534edb9a467d2ab635b86ef06ebdb99aeb | |
parent | dfd6a3788c35be121eba1ad84f20effadcb7e7dc (diff) |
[test] MiniMiner::Linearize and manual construction
-rw-r--r-- | src/test/miniminer_tests.cpp | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/src/test/miniminer_tests.cpp b/src/test/miniminer_tests.cpp index 840093f524..76c079a6e7 100644 --- a/src/test/miniminer_tests.cpp +++ b/src/test/miniminer_tests.cpp @@ -133,6 +133,7 @@ BOOST_FIXTURE_TEST_CASE(miniminer_1p1c, TestChain100Setup) // Make tx5's modified fee much higher than its base fee. This should cause it to pass // the fee-related checks despite being low-feerate. pool.PrioritiseTransaction(tx5->GetHash(), tx5_delta); + const CAmount tx5_mod_fee{low_fee + tx5_delta}; // Create a high-feerate parent tx6, low-feerate child tx7 const auto tx6 = make_tx({COutPoint{m_coinbase_txns[3]->GetHash(), 0}}, /*num_outputs=*/2); @@ -309,6 +310,64 @@ BOOST_FIXTURE_TEST_CASE(miniminer_1p1c, TestChain100Setup) } } } + + // Check m_inclusion_order for equivalent mempool- and manually-constructed MiniMiners. + // (We cannot check bump fees in manually-constructed MiniMiners because it doesn't know what + // outpoints are requested). + std::vector<node::MiniMinerMempoolEntry> miniminer_info; + { + const int32_t tx0_vsize{tx_dims.at(tx0->GetHash()).vsize}; + const int32_t tx1_vsize{tx_dims.at(tx1->GetHash()).vsize}; + const int32_t tx2_vsize{tx_dims.at(tx2->GetHash()).vsize}; + const int32_t tx3_vsize{tx_dims.at(tx3->GetHash()).vsize}; + const int32_t tx4_vsize{tx_dims.at(tx4->GetHash()).vsize}; + const int32_t tx5_vsize{tx_dims.at(tx5->GetHash()).vsize}; + const int32_t tx6_vsize{tx_dims.at(tx6->GetHash()).vsize}; + const int32_t tx7_vsize{tx_dims.at(tx7->GetHash()).vsize}; + + miniminer_info.emplace_back(/*fee_self=*/med_fee,/*fee_ancestor=*/med_fee,/*vsize_self=*/tx0_vsize,/*vsize_ancestor=*/tx0_vsize, tx0); + miniminer_info.emplace_back( med_fee, 2*med_fee, tx1_vsize, tx0_vsize + tx1_vsize, tx1); + miniminer_info.emplace_back( low_fee, low_fee, tx2_vsize, tx2_vsize, tx2); + miniminer_info.emplace_back( high_fee, low_fee + high_fee, tx3_vsize, tx2_vsize + tx3_vsize, tx3); + miniminer_info.emplace_back( low_fee, low_fee, tx4_vsize, tx4_vsize, tx4); + miniminer_info.emplace_back( tx5_mod_fee, low_fee + tx5_mod_fee, tx5_vsize, tx4_vsize + tx5_vsize, tx5); + miniminer_info.emplace_back( high_fee, high_fee, tx6_vsize, tx6_vsize, tx6); + miniminer_info.emplace_back( low_fee, high_fee + low_fee, tx7_vsize, tx6_vsize + tx7_vsize, tx7); + } + std::map<Txid, std::set<Txid>> descendant_caches; + descendant_caches.emplace(tx0->GetHash(), std::set<Txid>{tx0->GetHash(), tx1->GetHash()}); + descendant_caches.emplace(tx1->GetHash(), std::set<Txid>{tx1->GetHash()}); + descendant_caches.emplace(tx2->GetHash(), std::set<Txid>{tx2->GetHash(), tx3->GetHash()}); + descendant_caches.emplace(tx3->GetHash(), std::set<Txid>{tx3->GetHash()}); + descendant_caches.emplace(tx4->GetHash(), std::set<Txid>{tx4->GetHash(), tx5->GetHash()}); + descendant_caches.emplace(tx5->GetHash(), std::set<Txid>{tx5->GetHash()}); + descendant_caches.emplace(tx6->GetHash(), std::set<Txid>{tx6->GetHash(), tx7->GetHash()}); + descendant_caches.emplace(tx7->GetHash(), std::set<Txid>{tx7->GetHash()}); + + node::MiniMiner miniminer_manual(miniminer_info, descendant_caches); + // Use unspent outpoints to avoid entries being omitted. + node::MiniMiner miniminer_pool(pool, all_unspent_outpoints); + BOOST_CHECK(miniminer_manual.IsReadyToCalculate()); + BOOST_CHECK(miniminer_pool.IsReadyToCalculate()); + for (const auto& sequences : {miniminer_manual.Linearize(), miniminer_pool.Linearize()}) { + // tx6 is selected first: high feerate with no parents to bump + BOOST_CHECK_EQUAL(Find(sequences, tx6->GetHash()), 0); + + // tx2 + tx3 CPFP are selected next + BOOST_CHECK_EQUAL(Find(sequences, tx2->GetHash()), 1); + BOOST_CHECK_EQUAL(Find(sequences, tx3->GetHash()), 1); + + // tx4 + prioritised tx5 CPFP + BOOST_CHECK_EQUAL(Find(sequences, tx4->GetHash()), 2); + BOOST_CHECK_EQUAL(Find(sequences, tx5->GetHash()), 2); + + BOOST_CHECK_EQUAL(Find(sequences, tx0->GetHash()), 3); + BOOST_CHECK_EQUAL(Find(sequences, tx1->GetHash()), 3); + + + // tx7 is selected last: low feerate with no children + BOOST_CHECK_EQUAL(Find(sequences, tx7->GetHash()), 4); + } } BOOST_FIXTURE_TEST_CASE(miniminer_overlap, TestChain100Setup) @@ -482,6 +541,50 @@ BOOST_FIXTURE_TEST_CASE(miniminer_overlap, TestChain100Setup) BOOST_CHECK(tx7_bumpfee != bump_fees.end()); BOOST_CHECK_EQUAL(tx7_bumpfee->second, 0); } + // Check linearization order + std::vector<node::MiniMinerMempoolEntry> miniminer_info; + miniminer_info.emplace_back(/*fee_self=*/low_fee, /*fee_ancestor=*/low_fee,/*vsize_self=*/tx_vsizes[0], /*vsize_ancestor=*/tx_vsizes[0], tx0); + miniminer_info.emplace_back( med_fee, med_fee, tx_vsizes[1], tx_vsizes[1], tx1); + miniminer_info.emplace_back( high_fee, high_fee, tx_vsizes[2], tx_vsizes[2], tx2); + miniminer_info.emplace_back( high_fee, low_fee+med_fee+2*high_fee, tx_vsizes[3], tx_vsizes[0]+tx_vsizes[1]+tx_vsizes[2]+tx_vsizes[3], tx3); + + miniminer_info.emplace_back( high_fee, high_fee, tx_vsizes[4], tx_vsizes[4], tx4); + miniminer_info.emplace_back( low_fee, low_fee + high_fee, tx_vsizes[5], tx_vsizes[4]+tx_vsizes[5], tx5); + miniminer_info.emplace_back( med_fee, high_fee+low_fee+med_fee, tx_vsizes[6], tx_vsizes[4]+tx_vsizes[5]+tx_vsizes[6], tx6); + miniminer_info.emplace_back( high_fee, high_fee+low_fee+high_fee, tx_vsizes[7], tx_vsizes[4]+tx_vsizes[5]+tx_vsizes[7], tx7); + + std::map<Txid, std::set<Txid>> descendant_caches; + descendant_caches.emplace(tx0->GetHash(), std::set<Txid>{tx0->GetHash(), tx3->GetHash()}); + descendant_caches.emplace(tx1->GetHash(), std::set<Txid>{tx1->GetHash(), tx3->GetHash()}); + descendant_caches.emplace(tx2->GetHash(), std::set<Txid>{tx2->GetHash(), tx3->GetHash()}); + descendant_caches.emplace(tx3->GetHash(), std::set<Txid>{tx3->GetHash()}); + descendant_caches.emplace(tx4->GetHash(), std::set<Txid>{tx4->GetHash(), tx5->GetHash(), tx6->GetHash(), tx7->GetHash()}); + descendant_caches.emplace(tx5->GetHash(), std::set<Txid>{tx5->GetHash(), tx6->GetHash(), tx7->GetHash()}); + descendant_caches.emplace(tx6->GetHash(), std::set<Txid>{tx6->GetHash()}); + descendant_caches.emplace(tx7->GetHash(), std::set<Txid>{tx7->GetHash()}); + + node::MiniMiner miniminer_manual(miniminer_info, descendant_caches); + // Use unspent outpoints to avoid entries being omitted. + node::MiniMiner miniminer_pool(pool, all_unspent_outpoints); + BOOST_CHECK(miniminer_manual.IsReadyToCalculate()); + BOOST_CHECK(miniminer_pool.IsReadyToCalculate()); + for (const auto& sequences : {miniminer_manual.Linearize(), miniminer_pool.Linearize()}) { + // tx2 and tx4 selected first: high feerate with nothing to bump + BOOST_CHECK_EQUAL(Find(sequences, tx4->GetHash()), 0); + BOOST_CHECK_EQUAL(Find(sequences, tx2->GetHash()), 1); + + // tx5 + tx7 CPFP + BOOST_CHECK_EQUAL(Find(sequences, tx5->GetHash()), 2); + BOOST_CHECK_EQUAL(Find(sequences, tx7->GetHash()), 2); + + // tx0 and tx1 CPFP'd by tx3 + BOOST_CHECK_EQUAL(Find(sequences, tx0->GetHash()), 3); + BOOST_CHECK_EQUAL(Find(sequences, tx1->GetHash()), 3); + BOOST_CHECK_EQUAL(Find(sequences, tx3->GetHash()), 3); + + // tx6 at medium feerate + BOOST_CHECK_EQUAL(Find(sequences, tx6->GetHash()), 4); + } } BOOST_FIXTURE_TEST_CASE(calculate_cluster, TestChain100Setup) { @@ -539,4 +642,64 @@ BOOST_FIXTURE_TEST_CASE(calculate_cluster, TestChain100Setup) } } +BOOST_FIXTURE_TEST_CASE(manual_ctor, TestChain100Setup) +{ + CTxMemPool& pool = *Assert(m_node.mempool); + LOCK2(cs_main, pool.cs); + { + // 3 pairs of fee-bumping grandparent + parent, plus 1 low-feerate child. + // 0 fee + high fee + auto grandparent_zero_fee = make_tx({{m_coinbase_txns.at(0)->GetHash(), 0}}, 1); + auto parent_high_feerate = make_tx({{grandparent_zero_fee->GetHash(), 0}}, 1); + // double low fee + med fee + auto grandparent_double_low_feerate = make_tx({{m_coinbase_txns.at(2)->GetHash(), 0}}, 1); + auto parent_med_feerate = make_tx({{grandparent_double_low_feerate->GetHash(), 0}}, 1); + // low fee + double low fee + auto grandparent_low_feerate = make_tx({{m_coinbase_txns.at(1)->GetHash(), 0}}, 1); + auto parent_double_low_feerate = make_tx({{grandparent_low_feerate->GetHash(), 0}}, 1); + // child is below the cpfp package feerates because it is larger than everything else + auto child = make_tx({{parent_high_feerate->GetHash(), 0}, {parent_double_low_feerate->GetHash(), 0}, {parent_med_feerate->GetHash(), 0}}, 1); + + // We artificially record each transaction (except the child) with a uniform vsize of 100vB. + const int64_t tx_vsize{100}; + const int64_t child_vsize{1000}; + + std::vector<node::MiniMinerMempoolEntry> miniminer_info; + miniminer_info.emplace_back(/*fee_self=*/0, /*fee_ancestor=*/0,/*vsize_self=*/tx_vsize,/*vsize_ancestor=*/tx_vsize, grandparent_zero_fee); + miniminer_info.emplace_back( high_fee, high_fee, tx_vsize, 2*tx_vsize, parent_high_feerate); + miniminer_info.emplace_back( 2*low_fee, 2*low_fee, tx_vsize, tx_vsize, grandparent_double_low_feerate); + miniminer_info.emplace_back( med_fee, 2*low_fee+med_fee, tx_vsize, 2*tx_vsize, parent_med_feerate); + miniminer_info.emplace_back( low_fee, low_fee, tx_vsize, tx_vsize, grandparent_low_feerate); + miniminer_info.emplace_back( 2*low_fee, 3*low_fee, tx_vsize, 2*tx_vsize, parent_double_low_feerate); + miniminer_info.emplace_back( low_fee, high_fee+med_fee+6*low_fee, child_vsize, 6*tx_vsize+child_vsize, child); + std::map<Txid, std::set<Txid>> descendant_caches; + descendant_caches.emplace(grandparent_zero_fee->GetHash(), std::set<Txid>{grandparent_zero_fee->GetHash(), parent_high_feerate->GetHash(), child->GetHash()}); + descendant_caches.emplace(grandparent_low_feerate->GetHash(), std::set<Txid>{grandparent_low_feerate->GetHash(), parent_double_low_feerate->GetHash(), child->GetHash()}); + descendant_caches.emplace(grandparent_double_low_feerate->GetHash(), std::set<Txid>{grandparent_double_low_feerate->GetHash(), parent_med_feerate->GetHash(), child->GetHash()}); + descendant_caches.emplace(parent_high_feerate->GetHash(), std::set<Txid>{parent_high_feerate->GetHash(), child->GetHash()}); + descendant_caches.emplace(parent_med_feerate->GetHash(), std::set<Txid>{parent_med_feerate->GetHash(), child->GetHash()}); + descendant_caches.emplace(parent_double_low_feerate->GetHash(), std::set<Txid>{parent_double_low_feerate->GetHash(), child->GetHash()}); + descendant_caches.emplace(child->GetHash(), std::set<Txid>{child->GetHash()}); + + node::MiniMiner miniminer_manual(miniminer_info, descendant_caches); + BOOST_CHECK(miniminer_manual.IsReadyToCalculate()); + const auto sequences{miniminer_manual.Linearize()}; + + // CPFP zero + high + BOOST_CHECK_EQUAL(sequences.at(grandparent_zero_fee->GetHash()), 0); + BOOST_CHECK_EQUAL(sequences.at(parent_high_feerate->GetHash()), 0); + + // CPFP double low + med + BOOST_CHECK_EQUAL(sequences.at(grandparent_double_low_feerate->GetHash()), 1); + BOOST_CHECK_EQUAL(sequences.at(parent_med_feerate->GetHash()), 1); + + // CPFP low + med + BOOST_CHECK_EQUAL(sequences.at(grandparent_low_feerate->GetHash()), 2); + BOOST_CHECK_EQUAL(sequences.at(parent_double_low_feerate->GetHash()), 2); + + // Child at the end + BOOST_CHECK_EQUAL(sequences.at(child->GetHash()), 3); + } +} + BOOST_AUTO_TEST_SUITE_END() |