@@ -133,6 +133,7 @@ BOOST_FIXTURE_TEST_CASE(miniminer_1p1c, TestChain100Setup)
133
133
// Make tx5's modified fee much higher than its base fee. This should cause it to pass
134
134
// the fee-related checks despite being low-feerate.
135
135
pool.PrioritiseTransaction (tx5->GetHash (), tx5_delta);
136
+ const CAmount tx5_mod_fee{low_fee + tx5_delta};
136
137
137
138
// Create a high-feerate parent tx6, low-feerate child tx7
138
139
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)
309
310
}
310
311
}
311
312
}
313
+
314
+ // Check m_inclusion_order for equivalent mempool- and manually-constructed MiniMiners.
315
+ // (We cannot check bump fees in manually-constructed MiniMiners because it doesn't know what
316
+ // outpoints are requested).
317
+ std::vector<node::MiniMinerMempoolEntry> miniminer_info;
318
+ {
319
+ const int32_t tx0_vsize{tx_dims.at (tx0->GetHash ()).vsize };
320
+ const int32_t tx1_vsize{tx_dims.at (tx1->GetHash ()).vsize };
321
+ const int32_t tx2_vsize{tx_dims.at (tx2->GetHash ()).vsize };
322
+ const int32_t tx3_vsize{tx_dims.at (tx3->GetHash ()).vsize };
323
+ const int32_t tx4_vsize{tx_dims.at (tx4->GetHash ()).vsize };
324
+ const int32_t tx5_vsize{tx_dims.at (tx5->GetHash ()).vsize };
325
+ const int32_t tx6_vsize{tx_dims.at (tx6->GetHash ()).vsize };
326
+ const int32_t tx7_vsize{tx_dims.at (tx7->GetHash ()).vsize };
327
+
328
+ miniminer_info.emplace_back (/* fee_self=*/ med_fee,/* fee_ancestor=*/ med_fee,/* vsize_self=*/ tx0_vsize,/* vsize_ancestor=*/ tx0_vsize, tx0);
329
+ miniminer_info.emplace_back ( med_fee, 2 *med_fee, tx1_vsize, tx0_vsize + tx1_vsize, tx1);
330
+ miniminer_info.emplace_back ( low_fee, low_fee, tx2_vsize, tx2_vsize, tx2);
331
+ miniminer_info.emplace_back ( high_fee, low_fee + high_fee, tx3_vsize, tx2_vsize + tx3_vsize, tx3);
332
+ miniminer_info.emplace_back ( low_fee, low_fee, tx4_vsize, tx4_vsize, tx4);
333
+ miniminer_info.emplace_back ( tx5_mod_fee, low_fee + tx5_mod_fee, tx5_vsize, tx4_vsize + tx5_vsize, tx5);
334
+ miniminer_info.emplace_back ( high_fee, high_fee, tx6_vsize, tx6_vsize, tx6);
335
+ miniminer_info.emplace_back ( low_fee, high_fee + low_fee, tx7_vsize, tx6_vsize + tx7_vsize, tx7);
336
+ }
337
+ std::map<Txid, std::set<Txid>> descendant_caches;
338
+ descendant_caches.emplace (tx0->GetHash (), std::set<Txid>{tx0->GetHash (), tx1->GetHash ()});
339
+ descendant_caches.emplace (tx1->GetHash (), std::set<Txid>{tx1->GetHash ()});
340
+ descendant_caches.emplace (tx2->GetHash (), std::set<Txid>{tx2->GetHash (), tx3->GetHash ()});
341
+ descendant_caches.emplace (tx3->GetHash (), std::set<Txid>{tx3->GetHash ()});
342
+ descendant_caches.emplace (tx4->GetHash (), std::set<Txid>{tx4->GetHash (), tx5->GetHash ()});
343
+ descendant_caches.emplace (tx5->GetHash (), std::set<Txid>{tx5->GetHash ()});
344
+ descendant_caches.emplace (tx6->GetHash (), std::set<Txid>{tx6->GetHash (), tx7->GetHash ()});
345
+ descendant_caches.emplace (tx7->GetHash (), std::set<Txid>{tx7->GetHash ()});
346
+
347
+ node::MiniMiner miniminer_manual (miniminer_info, descendant_caches);
348
+ // Use unspent outpoints to avoid entries being omitted.
349
+ node::MiniMiner miniminer_pool (pool, all_unspent_outpoints);
350
+ BOOST_CHECK (miniminer_manual.IsReadyToCalculate ());
351
+ BOOST_CHECK (miniminer_pool.IsReadyToCalculate ());
352
+ for (const auto & sequences : {miniminer_manual.Linearize (), miniminer_pool.Linearize ()}) {
353
+ // tx6 is selected first: high feerate with no parents to bump
354
+ BOOST_CHECK_EQUAL (Find (sequences, tx6->GetHash ()), 0 );
355
+
356
+ // tx2 + tx3 CPFP are selected next
357
+ BOOST_CHECK_EQUAL (Find (sequences, tx2->GetHash ()), 1 );
358
+ BOOST_CHECK_EQUAL (Find (sequences, tx3->GetHash ()), 1 );
359
+
360
+ // tx4 + prioritised tx5 CPFP
361
+ BOOST_CHECK_EQUAL (Find (sequences, tx4->GetHash ()), 2 );
362
+ BOOST_CHECK_EQUAL (Find (sequences, tx5->GetHash ()), 2 );
363
+
364
+ BOOST_CHECK_EQUAL (Find (sequences, tx0->GetHash ()), 3 );
365
+ BOOST_CHECK_EQUAL (Find (sequences, tx1->GetHash ()), 3 );
366
+
367
+
368
+ // tx7 is selected last: low feerate with no children
369
+ BOOST_CHECK_EQUAL (Find (sequences, tx7->GetHash ()), 4 );
370
+ }
312
371
}
313
372
314
373
BOOST_FIXTURE_TEST_CASE (miniminer_overlap, TestChain100Setup)
@@ -482,6 +541,50 @@ BOOST_FIXTURE_TEST_CASE(miniminer_overlap, TestChain100Setup)
482
541
BOOST_CHECK (tx7_bumpfee != bump_fees.end ());
483
542
BOOST_CHECK_EQUAL (tx7_bumpfee->second , 0 );
484
543
}
544
+ // Check linearization order
545
+ std::vector<node::MiniMinerMempoolEntry> miniminer_info;
546
+ miniminer_info.emplace_back (/* fee_self=*/ low_fee, /* fee_ancestor=*/ low_fee,/* vsize_self=*/ tx_vsizes[0 ], /* vsize_ancestor=*/ tx_vsizes[0 ], tx0);
547
+ miniminer_info.emplace_back ( med_fee, med_fee, tx_vsizes[1 ], tx_vsizes[1 ], tx1);
548
+ miniminer_info.emplace_back ( high_fee, high_fee, tx_vsizes[2 ], tx_vsizes[2 ], tx2);
549
+ 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);
550
+
551
+ miniminer_info.emplace_back ( high_fee, high_fee, tx_vsizes[4 ], tx_vsizes[4 ], tx4);
552
+ miniminer_info.emplace_back ( low_fee, low_fee + high_fee, tx_vsizes[5 ], tx_vsizes[4 ]+tx_vsizes[5 ], tx5);
553
+ 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);
554
+ 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);
555
+
556
+ std::map<Txid, std::set<Txid>> descendant_caches;
557
+ descendant_caches.emplace (tx0->GetHash (), std::set<Txid>{tx0->GetHash (), tx3->GetHash ()});
558
+ descendant_caches.emplace (tx1->GetHash (), std::set<Txid>{tx1->GetHash (), tx3->GetHash ()});
559
+ descendant_caches.emplace (tx2->GetHash (), std::set<Txid>{tx2->GetHash (), tx3->GetHash ()});
560
+ descendant_caches.emplace (tx3->GetHash (), std::set<Txid>{tx3->GetHash ()});
561
+ descendant_caches.emplace (tx4->GetHash (), std::set<Txid>{tx4->GetHash (), tx5->GetHash (), tx6->GetHash (), tx7->GetHash ()});
562
+ descendant_caches.emplace (tx5->GetHash (), std::set<Txid>{tx5->GetHash (), tx6->GetHash (), tx7->GetHash ()});
563
+ descendant_caches.emplace (tx6->GetHash (), std::set<Txid>{tx6->GetHash ()});
564
+ descendant_caches.emplace (tx7->GetHash (), std::set<Txid>{tx7->GetHash ()});
565
+
566
+ node::MiniMiner miniminer_manual (miniminer_info, descendant_caches);
567
+ // Use unspent outpoints to avoid entries being omitted.
568
+ node::MiniMiner miniminer_pool (pool, all_unspent_outpoints);
569
+ BOOST_CHECK (miniminer_manual.IsReadyToCalculate ());
570
+ BOOST_CHECK (miniminer_pool.IsReadyToCalculate ());
571
+ for (const auto & sequences : {miniminer_manual.Linearize (), miniminer_pool.Linearize ()}) {
572
+ // tx2 and tx4 selected first: high feerate with nothing to bump
573
+ BOOST_CHECK_EQUAL (Find (sequences, tx4->GetHash ()), 0 );
574
+ BOOST_CHECK_EQUAL (Find (sequences, tx2->GetHash ()), 1 );
575
+
576
+ // tx5 + tx7 CPFP
577
+ BOOST_CHECK_EQUAL (Find (sequences, tx5->GetHash ()), 2 );
578
+ BOOST_CHECK_EQUAL (Find (sequences, tx7->GetHash ()), 2 );
579
+
580
+ // tx0 and tx1 CPFP'd by tx3
581
+ BOOST_CHECK_EQUAL (Find (sequences, tx0->GetHash ()), 3 );
582
+ BOOST_CHECK_EQUAL (Find (sequences, tx1->GetHash ()), 3 );
583
+ BOOST_CHECK_EQUAL (Find (sequences, tx3->GetHash ()), 3 );
584
+
585
+ // tx6 at medium feerate
586
+ BOOST_CHECK_EQUAL (Find (sequences, tx6->GetHash ()), 4 );
587
+ }
485
588
}
486
589
BOOST_FIXTURE_TEST_CASE (calculate_cluster, TestChain100Setup)
487
590
{
@@ -539,4 +642,64 @@ BOOST_FIXTURE_TEST_CASE(calculate_cluster, TestChain100Setup)
539
642
}
540
643
}
541
644
645
+ BOOST_FIXTURE_TEST_CASE (manual_ctor, TestChain100Setup)
646
+ {
647
+ CTxMemPool& pool = *Assert (m_node.mempool );
648
+ LOCK2 (cs_main, pool.cs );
649
+ {
650
+ // 3 pairs of fee-bumping grandparent + parent, plus 1 low-feerate child.
651
+ // 0 fee + high fee
652
+ auto grandparent_zero_fee = make_tx ({{m_coinbase_txns.at (0 )->GetHash (), 0 }}, 1 );
653
+ auto parent_high_feerate = make_tx ({{grandparent_zero_fee->GetHash (), 0 }}, 1 );
654
+ // double low fee + med fee
655
+ auto grandparent_double_low_feerate = make_tx ({{m_coinbase_txns.at (2 )->GetHash (), 0 }}, 1 );
656
+ auto parent_med_feerate = make_tx ({{grandparent_double_low_feerate->GetHash (), 0 }}, 1 );
657
+ // low fee + double low fee
658
+ auto grandparent_low_feerate = make_tx ({{m_coinbase_txns.at (1 )->GetHash (), 0 }}, 1 );
659
+ auto parent_double_low_feerate = make_tx ({{grandparent_low_feerate->GetHash (), 0 }}, 1 );
660
+ // child is below the cpfp package feerates because it is larger than everything else
661
+ auto child = make_tx ({{parent_high_feerate->GetHash (), 0 }, {parent_double_low_feerate->GetHash (), 0 }, {parent_med_feerate->GetHash (), 0 }}, 1 );
662
+
663
+ // We artificially record each transaction (except the child) with a uniform vsize of 100vB.
664
+ const int64_t tx_vsize{100 };
665
+ const int64_t child_vsize{1000 };
666
+
667
+ std::vector<node::MiniMinerMempoolEntry> miniminer_info;
668
+ miniminer_info.emplace_back (/* fee_self=*/ 0 , /* fee_ancestor=*/ 0 ,/* vsize_self=*/ tx_vsize,/* vsize_ancestor=*/ tx_vsize, grandparent_zero_fee);
669
+ miniminer_info.emplace_back ( high_fee, high_fee, tx_vsize, 2 *tx_vsize, parent_high_feerate);
670
+ miniminer_info.emplace_back ( 2 *low_fee, 2 *low_fee, tx_vsize, tx_vsize, grandparent_double_low_feerate);
671
+ miniminer_info.emplace_back ( med_fee, 2 *low_fee+med_fee, tx_vsize, 2 *tx_vsize, parent_med_feerate);
672
+ miniminer_info.emplace_back ( low_fee, low_fee, tx_vsize, tx_vsize, grandparent_low_feerate);
673
+ miniminer_info.emplace_back ( 2 *low_fee, 3 *low_fee, tx_vsize, 2 *tx_vsize, parent_double_low_feerate);
674
+ miniminer_info.emplace_back ( low_fee, high_fee+med_fee+6 *low_fee, child_vsize, 6 *tx_vsize+child_vsize, child);
675
+ std::map<Txid, std::set<Txid>> descendant_caches;
676
+ descendant_caches.emplace (grandparent_zero_fee->GetHash (), std::set<Txid>{grandparent_zero_fee->GetHash (), parent_high_feerate->GetHash (), child->GetHash ()});
677
+ descendant_caches.emplace (grandparent_low_feerate->GetHash (), std::set<Txid>{grandparent_low_feerate->GetHash (), parent_double_low_feerate->GetHash (), child->GetHash ()});
678
+ descendant_caches.emplace (grandparent_double_low_feerate->GetHash (), std::set<Txid>{grandparent_double_low_feerate->GetHash (), parent_med_feerate->GetHash (), child->GetHash ()});
679
+ descendant_caches.emplace (parent_high_feerate->GetHash (), std::set<Txid>{parent_high_feerate->GetHash (), child->GetHash ()});
680
+ descendant_caches.emplace (parent_med_feerate->GetHash (), std::set<Txid>{parent_med_feerate->GetHash (), child->GetHash ()});
681
+ descendant_caches.emplace (parent_double_low_feerate->GetHash (), std::set<Txid>{parent_double_low_feerate->GetHash (), child->GetHash ()});
682
+ descendant_caches.emplace (child->GetHash (), std::set<Txid>{child->GetHash ()});
683
+
684
+ node::MiniMiner miniminer_manual (miniminer_info, descendant_caches);
685
+ BOOST_CHECK (miniminer_manual.IsReadyToCalculate ());
686
+ const auto sequences{miniminer_manual.Linearize ()};
687
+
688
+ // CPFP zero + high
689
+ BOOST_CHECK_EQUAL (sequences.at (grandparent_zero_fee->GetHash ()), 0 );
690
+ BOOST_CHECK_EQUAL (sequences.at (parent_high_feerate->GetHash ()), 0 );
691
+
692
+ // CPFP double low + med
693
+ BOOST_CHECK_EQUAL (sequences.at (grandparent_double_low_feerate->GetHash ()), 1 );
694
+ BOOST_CHECK_EQUAL (sequences.at (parent_med_feerate->GetHash ()), 1 );
695
+
696
+ // CPFP low + med
697
+ BOOST_CHECK_EQUAL (sequences.at (grandparent_low_feerate->GetHash ()), 2 );
698
+ BOOST_CHECK_EQUAL (sequences.at (parent_double_low_feerate->GetHash ()), 2 );
699
+
700
+ // Child at the end
701
+ BOOST_CHECK_EQUAL (sequences.at (child->GetHash ()), 3 );
702
+ }
703
+ }
704
+
542
705
BOOST_AUTO_TEST_SUITE_END ()
0 commit comments