Skip to content

Commit d2bf923

Browse files
committed
unit test: make calc_feerate_diagram_rbf less brittle
1 parent defe023 commit d2bf923

File tree

1 file changed

+62
-79
lines changed

1 file changed

+62
-79
lines changed

src/test/rbf_tests.cpp

Lines changed: 62 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -420,73 +420,62 @@ BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)
420420
const auto entry_low = pool.GetIter(low_tx->GetHash()).value();
421421
const auto low_size = entry_low->GetTxSize();
422422

423-
std::vector<FeeFrac> old_diagram, new_diagram;
424-
425423
// Replacement of size 1
426-
const auto replace_one{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low})};
427-
BOOST_CHECK(replace_one.has_value());
428-
old_diagram = replace_one->first;
429-
new_diagram = replace_one->second;
430-
BOOST_CHECK(old_diagram.size() == 2);
431-
BOOST_CHECK(new_diagram.size() == 2);
432-
BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));
433-
BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));
434-
BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));
435-
BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));
424+
{
425+
const auto replace_one{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low})};
426+
BOOST_CHECK(replace_one.has_value());
427+
std::vector<FeeFrac> expected_old_diagram{FeeFrac(0, 0), FeeFrac(low_fee, low_size)};
428+
BOOST_CHECK(replace_one->first == expected_old_diagram);
429+
std::vector<FeeFrac> expected_new_diagram{FeeFrac(0, 0), FeeFrac(0, 1)};
430+
BOOST_CHECK(replace_one->second == expected_new_diagram);
431+
}
436432

437433
// Non-zero replacement fee/size
438-
const auto replace_one_fee{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low})};
439-
BOOST_CHECK(replace_one_fee.has_value());
440-
old_diagram = replace_one_fee->first;
441-
new_diagram = replace_one_fee->second;
442-
BOOST_CHECK(old_diagram.size() == 2);
443-
BOOST_CHECK(new_diagram.size() == 2);
444-
BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));
445-
BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));
446-
BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));
447-
BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));
434+
{
435+
const auto replace_one_fee{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low})};
436+
BOOST_CHECK(replace_one_fee.has_value());
437+
std::vector<FeeFrac> expected_old_diagram{FeeFrac(0, 0), FeeFrac(low_fee, low_size)};
438+
BOOST_CHECK(replace_one_fee->first == expected_old_diagram);
439+
std::vector<FeeFrac> expected_new_diagram{FeeFrac(0, 0), FeeFrac(high_fee, low_size)};
440+
BOOST_CHECK(replace_one_fee->second == expected_new_diagram);
441+
}
448442

449443
// Add a second transaction to the cluster that will make a single chunk, to be evicted in the RBF
450444
const auto high_tx = make_tx(/*inputs=*/ {low_tx}, /*output_values=*/ {995 * CENT});
451445
pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx));
452446
const auto entry_high = pool.GetIter(high_tx->GetHash()).value();
453447
const auto high_size = entry_high->GetTxSize();
454448

455-
const auto replace_single_chunk{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low, entry_high})};
456-
BOOST_CHECK(replace_single_chunk.has_value());
457-
old_diagram = replace_single_chunk->first;
458-
new_diagram = replace_single_chunk->second;
459-
BOOST_CHECK(old_diagram.size() == 2);
460-
BOOST_CHECK(new_diagram.size() == 2);
461-
BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));
462-
BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));
463-
BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));
464-
BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));
449+
{
450+
const auto replace_single_chunk{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low, entry_high})};
451+
BOOST_CHECK(replace_single_chunk.has_value());
452+
std::vector<FeeFrac> expected_old_diagram{FeeFrac(0, 0), FeeFrac(low_fee + high_fee, low_size + high_size)};
453+
BOOST_CHECK(replace_single_chunk->first == expected_old_diagram);
454+
std::vector<FeeFrac> expected_new_diagram{FeeFrac(0, 0), FeeFrac(high_fee, low_size)};
455+
BOOST_CHECK(replace_single_chunk->second == expected_new_diagram);
456+
}
465457

466458
// Conflict with the 2nd tx, resulting in new diagram with three entries
467-
const auto replace_cpfp_child{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high}, {entry_high})};
468-
BOOST_CHECK(replace_cpfp_child.has_value());
469-
old_diagram = replace_cpfp_child->first;
470-
new_diagram = replace_cpfp_child->second;
471-
BOOST_CHECK(old_diagram.size() == 2);
472-
BOOST_CHECK(new_diagram.size() == 3);
473-
BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));
474-
BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));
475-
BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));
476-
BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));
477-
BOOST_CHECK(new_diagram[2] == FeeFrac(low_fee + high_fee, low_size + low_size));
459+
{
460+
const auto replace_cpfp_child{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high}, {entry_high})};
461+
BOOST_CHECK(replace_cpfp_child.has_value());
462+
std::vector<FeeFrac> expected_old_diagram{FeeFrac(0, 0), FeeFrac(low_fee + high_fee, low_size + high_size)};
463+
BOOST_CHECK(replace_cpfp_child->first == expected_old_diagram);
464+
std::vector<FeeFrac> expected_new_diagram{FeeFrac(0, 0), FeeFrac(high_fee, low_size), FeeFrac(low_fee + high_fee, low_size + low_size)};
465+
BOOST_CHECK(replace_cpfp_child->second == expected_new_diagram);
466+
}
478467

479468
// third transaction causes the topology check to fail
480469
const auto normal_tx = make_tx(/*inputs=*/ {high_tx}, /*output_values=*/ {995 * CENT});
481470
pool.addUnchecked(entry.Fee(normal_fee).FromTx(normal_tx));
482471
const auto entry_normal = pool.GetIter(normal_tx->GetHash()).value();
483472
const auto normal_size = entry_normal->GetTxSize();
484473

485-
const auto replace_too_large{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/normal_fee, /*replacement_vsize=*/normal_size, {entry_low}, {entry_low, entry_high, entry_normal})};
486-
BOOST_CHECK(!replace_too_large.has_value());
487-
BOOST_CHECK_EQUAL(util::ErrorString(replace_too_large).original, strprintf("%s has 2 descendants, max 1 allowed", low_tx->GetHash().GetHex()));
488-
old_diagram.clear();
489-
new_diagram.clear();
474+
{
475+
const auto replace_too_large{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/normal_fee, /*replacement_vsize=*/normal_size, {entry_low}, {entry_low, entry_high, entry_normal})};
476+
BOOST_CHECK(!replace_too_large.has_value());
477+
BOOST_CHECK_EQUAL(util::ErrorString(replace_too_large).original, strprintf("%s has 2 descendants, max 1 allowed", low_tx->GetHash().GetHex()));
478+
}
490479

491480
// Make a size 2 cluster that is itself two chunks; evict both txns
492481
const auto high_tx_2 = make_tx(/*inputs=*/ {m_coinbase_txns[1]}, /*output_values=*/ {10 * COIN});
@@ -499,17 +488,14 @@ BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)
499488
const auto entry_low_2 = pool.GetIter(low_tx_2->GetHash()).value();
500489
const auto low_size_2 = entry_low_2->GetTxSize();
501490

502-
const auto replace_two_chunks_single_cluster{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high_2}, {entry_high_2, entry_low_2})};
503-
BOOST_CHECK(replace_two_chunks_single_cluster.has_value());
504-
old_diagram = replace_two_chunks_single_cluster->first;
505-
new_diagram = replace_two_chunks_single_cluster->second;
506-
BOOST_CHECK(old_diagram.size() == 3);
507-
BOOST_CHECK(new_diagram.size() == 2);
508-
BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));
509-
BOOST_CHECK(old_diagram[1] == FeeFrac(high_fee, high_size_2));
510-
BOOST_CHECK(old_diagram[2] == FeeFrac(low_fee + high_fee, low_size_2 + high_size_2));
511-
BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));
512-
BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size_2));
491+
{
492+
const auto replace_two_chunks_single_cluster{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high_2}, {entry_high_2, entry_low_2})};
493+
BOOST_CHECK(replace_two_chunks_single_cluster.has_value());
494+
std::vector<FeeFrac> expected_old_diagram{FeeFrac(0, 0), FeeFrac(high_fee, high_size_2), FeeFrac(low_fee + high_fee, low_size_2 + high_size_2)};
495+
BOOST_CHECK(replace_two_chunks_single_cluster->first == expected_old_diagram);
496+
std::vector<FeeFrac> expected_new_diagram{FeeFrac(0, 0), FeeFrac(high_fee, low_size_2)};
497+
BOOST_CHECK(replace_two_chunks_single_cluster->second == expected_new_diagram);
498+
}
513499

514500
// You can have more than two direct conflicts if the there are multiple effected clusters, all of size 2 or less
515501
const auto conflict_1 = make_tx(/*inputs=*/ {m_coinbase_txns[2]}, /*output_values=*/ {10 * COIN});
@@ -524,40 +510,37 @@ BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)
524510
pool.addUnchecked(entry.Fee(low_fee).FromTx(conflict_3));
525511
const auto conflict_3_entry = pool.GetIter(conflict_3->GetHash()).value();
526512

527-
const auto replace_multiple_clusters{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry})};
528-
529-
BOOST_CHECK(replace_multiple_clusters.has_value());
530-
old_diagram = replace_multiple_clusters->first;
531-
new_diagram = replace_multiple_clusters->second;
532-
BOOST_CHECK(old_diagram.size() == 4);
533-
BOOST_CHECK(new_diagram.size() == 2);
513+
{
514+
const auto replace_multiple_clusters{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry})};
515+
BOOST_CHECK(replace_multiple_clusters.has_value());
516+
BOOST_CHECK(replace_multiple_clusters->first.size() == 4);
517+
BOOST_CHECK(replace_multiple_clusters->second.size() == 2);
518+
}
534519

535520
// Add a child transaction to conflict_1 and make it cluster size 2, still one chunk due to same feerate
536521
const auto conflict_1_child = make_tx(/*inputs=*/{conflict_1}, /*output_values=*/ {995 * CENT});
537522
pool.addUnchecked(entry.Fee(low_fee).FromTx(conflict_1_child));
538523
const auto conflict_1_child_entry = pool.GetIter(conflict_1_child->GetHash()).value();
539524

540-
const auto replace_multiple_clusters_2{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry, conflict_1_child_entry})};
525+
{
526+
const auto replace_multiple_clusters_2{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry, conflict_1_child_entry})};
541527

542-
BOOST_CHECK(replace_multiple_clusters_2.has_value());
543-
old_diagram = replace_multiple_clusters_2->first;
544-
new_diagram = replace_multiple_clusters_2->second;
545-
BOOST_CHECK(old_diagram.size() == 4);
546-
BOOST_CHECK(new_diagram.size() == 2);
547-
old_diagram.clear();
548-
new_diagram.clear();
528+
BOOST_CHECK(replace_multiple_clusters_2.has_value());
529+
BOOST_CHECK(replace_multiple_clusters_2->first.size() == 4);
530+
BOOST_CHECK(replace_multiple_clusters_2->second.size() == 2);
531+
}
549532

550533
// Add another descendant to conflict_1, making the cluster size > 2 should fail at this point.
551534
const auto conflict_1_grand_child = make_tx(/*inputs=*/{conflict_1_child}, /*output_values=*/ {995 * CENT});
552535
pool.addUnchecked(entry.Fee(high_fee).FromTx(conflict_1_grand_child));
553536
const auto conflict_1_grand_child_entry = pool.GetIter(conflict_1_child->GetHash()).value();
554537

555-
const auto replace_cluster_size_3{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry, conflict_1_child_entry, conflict_1_grand_child_entry})};
538+
{
539+
const auto replace_cluster_size_3{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry, conflict_1_child_entry, conflict_1_grand_child_entry})};
556540

557-
BOOST_CHECK(!replace_cluster_size_3.has_value());
558-
BOOST_CHECK_EQUAL(util::ErrorString(replace_cluster_size_3).original, strprintf("%s has 2 descendants, max 1 allowed", conflict_1->GetHash().GetHex()));
559-
BOOST_CHECK(old_diagram.empty());
560-
BOOST_CHECK(new_diagram.empty());
541+
BOOST_CHECK(!replace_cluster_size_3.has_value());
542+
BOOST_CHECK_EQUAL(util::ErrorString(replace_cluster_size_3).original, strprintf("%s has 2 descendants, max 1 allowed", conflict_1->GetHash().GetHex()));
543+
}
561544
}
562545

563546
BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)

0 commit comments

Comments
 (0)