v31.1-roots.1 · Commit 4: [PATCH 04/17] feat(mining): preserve Roots priority and template policies
src/test/miner_tests.cpp
Before: src/test/miner_tests.cpp · After: src/test/miner_tests.cpp
File metadata
index 6b4e85a59e45ad84c4a8c7d1e6df912580638723..032ccc35cec02d754efb4386c22dabbd763b628c 100644
Download original patch · Release notes
Diff rows 1–336 of 336. Line numbers refer to the original before/after files.
+ Added− RemovedUnmarked lines are context.
Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.
src/test/miner_tests.cpp
CHANGED
|
@@ -42,6 +42,7 @@ namespace miner_tests {
|
|
|
42
42
|
struct MinerTestingSetup : public TestingSetup {
|
|
43
43
|
void TestPackageSelection(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
|
44
44
|
void TestBasicMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
|
45
|
+
void TestPriorityPhaseStaleAncestors(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
|
45
46
|
void TestPrioritisedMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
|
46
47
|
bool TestSequenceLocks(const CTransaction& tx, CTxMemPool& tx_mempool) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
|
|
47
48
|
{
|
|
@@ -116,6 +117,8 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
|
|
116
117
|
CTxMemPool& tx_mempool{MakeMempool()};
|
|
117
118
|
auto mining{MakeMining()};
|
|
118
119
|
BlockAssembler::Options options;
|
|
120
|
+
options.nBlockPrioritySize = 0;
|
|
121
|
+
options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
|
|
119
122
|
options.coinbase_output_script = scriptPubKey;
|
|
120
123
|
options.include_dummy_extranonce = true;
|
|
121
124
|
|
|
@@ -250,7 +253,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
|
|
250
253
|
// This tx can't be mined by itself
|
|
251
254
|
tx.vin[0].prevout.hash = hashFreeTx2;
|
|
252
255
|
tx.vout.resize(1);
|
|
253
|
-
feeToUse = blockMinFeeRate.GetFee(freeTxSize);
|
|
256
|
+
feeToUse = blockMinFeeRate.GetFee(GetVirtualTransactionSize(CTransaction{tx}));
|
|
254
257
|
tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
|
|
255
258
|
Txid hashLowFeeTx2 = tx.GetHash();
|
|
256
259
|
TryAddToMempool(tx_mempool, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
|
|
@@ -335,6 +338,8 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
|
|
335
338
|
BOOST_REQUIRE(mining);
|
|
336
339
|
|
|
337
340
|
BlockAssembler::Options options;
|
|
341
|
+
options.nBlockPrioritySize = 0;
|
|
342
|
+
options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
|
|
338
343
|
options.coinbase_output_script = scriptPubKey;
|
|
339
344
|
options.include_dummy_extranonce = true;
|
|
340
345
|
|
|
@@ -662,6 +667,8 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const
|
|
|
662
667
|
BOOST_REQUIRE(mining);
|
|
663
668
|
|
|
664
669
|
BlockAssembler::Options options;
|
|
670
|
+
options.nBlockPrioritySize = 0;
|
|
671
|
+
options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
|
|
665
672
|
options.coinbase_output_script = scriptPubKey;
|
|
666
673
|
options.include_dummy_extranonce = true;
|
|
667
674
|
|
|
@@ -743,15 +750,290 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const
|
|
|
743
750
|
}
|
|
744
751
|
}
|
|
745
752
|
|
|
753
|
+
void MinerTestingSetup::TestPriorityPhaseStaleAncestors(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst)
|
|
754
|
+
{
|
|
755
|
+
CTxMemPool& tx_mempool{MakeMempool()};
|
|
756
|
+
BlockAssembler::Options options;
|
|
757
|
+
options.coinbase_output_script = scriptPubKey;
|
|
758
|
+
options.include_dummy_extranonce = true;
|
|
759
|
+
options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
|
|
760
|
+
|
|
761
|
+
LOCK(tx_mempool.cs);
|
|
762
|
+
TestMemPoolEntryHelper entry;
|
|
763
|
+
|
|
764
|
+
CMutableTransaction tx;
|
|
765
|
+
tx.vin.resize(1);
|
|
766
|
+
tx.vin[0].scriptSig = CScript() << OP_1;
|
|
767
|
+
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
|
|
768
|
+
tx.vin[0].prevout.n = 0;
|
|
769
|
+
tx.vout.resize(1);
|
|
770
|
+
tx.vout[0].nValue = 5000000000LL - 100000;
|
|
771
|
+
const Txid parent_txid = tx.GetHash();
|
|
772
|
+
TryAddToMempool(tx_mempool, entry.Fee(100000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
|
|
773
|
+
|
|
774
|
+
tx.vin[0].prevout.hash = parent_txid;
|
|
775
|
+
const Txid child_txid = tx.GetHash();
|
|
776
|
+
TryAddToMempool(tx_mempool, entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
|
|
777
|
+
|
|
778
|
+
options.nBlockPrioritySize = DEFAULT_BLOCK_RESERVED_SIZE + GetSerializeSize(TX_WITH_WITNESS(tx_mempool.mapTx.find(parent_txid)->GetTx()));
|
|
779
|
+
const auto block_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
|
780
|
+
BOOST_REQUIRE(block_template);
|
|
781
|
+
const CBlock& block{block_template->block};
|
|
782
|
+
BOOST_REQUIRE_EQUAL(block.vtx.size(), 2U);
|
|
783
|
+
BOOST_CHECK(block.vtx[1]->GetHash() == parent_txid);
|
|
784
|
+
for (const auto& btx : block.vtx) BOOST_CHECK(btx->GetHash() != child_txid);
|
|
785
|
+
|
|
786
|
+
// Template policy must not make the otherwise-valid zero-fee child invalid.
|
|
787
|
+
CBlock block_with_child{block};
|
|
788
|
+
block_with_child.vtx.push_back(MakeTransactionRef(tx));
|
|
789
|
+
node::RegenerateCommitments(block_with_child, *m_node.chainman);
|
|
790
|
+
const BlockValidationState state{TestBlockValidity(m_node.chainman->ActiveChainstate(), block_with_child,
|
|
791
|
+
/*check_pow=*/false, /*check_merkle_root=*/true)};
|
|
792
|
+
BOOST_CHECK_MESSAGE(state.IsValid(), state.ToString());
|
|
793
|
+
|
|
794
|
+
// With the priority phase disabled, ordinary package selection must still
|
|
795
|
+
// include the parent and stop subsidising its zero-fee child afterwards.
|
|
796
|
+
options.nBlockPrioritySize = 0;
|
|
797
|
+
const auto no_priority_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
|
798
|
+
BOOST_REQUIRE(no_priority_template);
|
|
799
|
+
BOOST_REQUIRE_EQUAL(no_priority_template->block.vtx.size(), 2U);
|
|
800
|
+
BOOST_CHECK(no_priority_template->block.vtx[1]->GetHash() == parent_txid);
|
|
801
|
+
|
|
802
|
+
// A zero mining fee floor may still select the child.
|
|
803
|
+
options.blockMinFeeRate = CFeeRate{0};
|
|
804
|
+
const auto zero_floor_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
|
805
|
+
BOOST_REQUIRE(zero_floor_template);
|
|
806
|
+
BOOST_REQUIRE_EQUAL(zero_floor_template->block.vtx.size(), 3U);
|
|
807
|
+
BOOST_CHECK(zero_floor_template->block.vtx[2]->GetHash() == child_txid);
|
|
808
|
+
|
|
809
|
+
tx_mempool.removeRecursive(*block.vtx[1], MemPoolRemovalReason::REPLACED);
|
|
810
|
+
|
|
811
|
+
// Confirmed coin age selects zero-fee parents first. The child's own fee
|
|
812
|
+
// meets the mining floor, but its stale package including those parents
|
|
813
|
+
// does not. Exercise both one ancestor and a shared descendant of two
|
|
814
|
+
// ancestors, which must each be subtracted exactly once.
|
|
815
|
+
for (const size_t parent_count : {1U, 2U}) {
|
|
816
|
+
BOOST_TEST_CONTEXT("priority-selected parents: " << parent_count) {
|
|
817
|
+
options.blockMinFeeRate = CFeeRate{1000};
|
|
818
|
+
std::vector<CTransactionRef> parents;
|
|
819
|
+
size_t priority_tx_size{0};
|
|
820
|
+
for (size_t i{0}; i < parent_count; ++i) {
|
|
821
|
+
CMutableTransaction parent;
|
|
822
|
+
parent.vin.resize(1);
|
|
823
|
+
parent.vin[0].prevout = COutPoint{txFirst[i]->GetHash(), 0};
|
|
824
|
+
parent.vin[0].scriptSig = CScript() << OP_1;
|
|
825
|
+
parent.vout.emplace_back(50 * COIN, CScript{});
|
|
826
|
+
parents.push_back(MakeTransactionRef(parent));
|
|
827
|
+
TryAddToMempool(tx_mempool, entry.Fee(0).SpendsCoinbase(true).FromTx(parents.back()));
|
|
828
|
+
priority_tx_size += GetSerializeSize(TX_WITH_WITNESS(*parents.back()));
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
CMutableTransaction child;
|
|
832
|
+
for (const auto& parent : parents) {
|
|
833
|
+
child.vin.emplace_back(COutPoint{parent->GetHash(), 0}, CScript() << OP_1);
|
|
834
|
+
}
|
|
835
|
+
child.vout.emplace_back(parent_count * 50 * COIN, CScript{});
|
|
836
|
+
const CAmount child_fee = options.blockMinFeeRate.GetFee(GetVirtualTransactionSize(CTransaction{child}));
|
|
837
|
+
child.vout[0].nValue -= child_fee;
|
|
838
|
+
const auto child_ref = MakeTransactionRef(child);
|
|
839
|
+
TryAddToMempool(tx_mempool, entry.Fee(child_fee).SpendsCoinbase(false).FromTx(child_ref));
|
|
840
|
+
|
|
841
|
+
// Without priority selection the entire package is below the floor.
|
|
842
|
+
options.nBlockPrioritySize = 0;
|
|
843
|
+
const auto below_floor_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
|
844
|
+
BOOST_REQUIRE(below_floor_template);
|
|
845
|
+
BOOST_CHECK_EQUAL(below_floor_template->block.vtx.size(), 1U);
|
|
846
|
+
|
|
847
|
+
// The assembler reserves 1000 bytes before adding transactions;
|
|
848
|
+
// end the priority phase immediately after including the parents.
|
|
849
|
+
options.nBlockPrioritySize = DEFAULT_BLOCK_RESERVED_SIZE + priority_tx_size;
|
|
850
|
+
const auto priority_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
|
851
|
+
BOOST_REQUIRE(priority_template);
|
|
852
|
+
BOOST_REQUIRE_EQUAL(priority_template->block.vtx.size(), parent_count + 2);
|
|
853
|
+
BOOST_CHECK(priority_template->block.vtx.back()->GetHash() == child_ref->GetHash());
|
|
854
|
+
BOOST_CHECK_EQUAL(priority_template->vTxFees.back(), child_fee);
|
|
855
|
+
// Equality is excluded by Roots' conservative resource boundary.
|
|
856
|
+
const auto weight = *BlockAssembler::m_last_block_weight;
|
|
857
|
+
options.nBlockMaxWeight = weight;
|
|
858
|
+
const auto capped = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
|
859
|
+
BOOST_CHECK_EQUAL(capped->block.vtx.size(), parent_count + 1);
|
|
860
|
+
options.nBlockMaxWeight = weight + 1;
|
|
861
|
+
const auto fits = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
|
862
|
+
BOOST_CHECK_EQUAL(fits->block.vtx.size(), parent_count + 2);
|
|
863
|
+
options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
|
|
864
|
+
options.nBlockMaxSize = DEFAULT_BLOCK_RESERVED_SIZE + priority_tx_size + GetSerializeSize(TX_WITH_WITNESS(*child_ref));
|
|
865
|
+
const auto size_capped = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
|
866
|
+
BOOST_CHECK_EQUAL(size_capped->block.vtx.size(), parent_count + 1);
|
|
867
|
+
++options.nBlockMaxSize;
|
|
868
|
+
const auto size_fits = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
|
869
|
+
BOOST_CHECK_EQUAL(size_fits->block.vtx.size(), parent_count + 2);
|
|
870
|
+
options.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
|
|
871
|
+
for (const auto& parent : parents) tx_mempool.removeRecursive(*parent, MemPoolRemovalReason::REPLACED);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// A child can outrank its parent using a second, older confirmed input.
|
|
876
|
+
// It must wait, then be revisited exactly once after its parent is selected.
|
|
877
|
+
options.nBlockPrioritySize = DEFAULT_BLOCK_PRIORITY_SIZE;
|
|
878
|
+
options.blockMinFeeRate = CFeeRate{1'000'000};
|
|
879
|
+
CMutableTransaction waiting_parent;
|
|
880
|
+
waiting_parent.vin.emplace_back(COutPoint{txFirst[1]->GetHash(), 0}, CScript() << OP_1);
|
|
881
|
+
waiting_parent.vout.emplace_back(50 * COIN, CScript{});
|
|
882
|
+
const auto parent_ref = MakeTransactionRef(waiting_parent);
|
|
883
|
+
TryAddToMempool(tx_mempool, entry.Fee(0).SpendsCoinbase(true).FromTx(parent_ref));
|
|
884
|
+
CMutableTransaction waiting_child;
|
|
885
|
+
waiting_child.vin.emplace_back(COutPoint{parent_ref->GetHash(), 0}, CScript() << OP_1);
|
|
886
|
+
waiting_child.vin.emplace_back(COutPoint{txFirst[0]->GetHash(), 0}, CScript() << OP_1);
|
|
887
|
+
waiting_child.vout.emplace_back(100 * COIN - 500, CScript{});
|
|
888
|
+
const auto waiting_child_ref = MakeTransactionRef(waiting_child);
|
|
889
|
+
TryAddToMempool(tx_mempool, entry.Fee(500).SpendsCoinbase(true).FromTx(waiting_child_ref));
|
|
890
|
+
const auto pool_size = tx_mempool.size();
|
|
891
|
+
const auto pool_fee = tx_mempool.GetTotalFee();
|
|
892
|
+
for (int repeat = 0; repeat < 2; ++repeat) {
|
|
893
|
+
const auto ready = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
|
894
|
+
BOOST_REQUIRE_EQUAL(ready->block.vtx.size(), 3U);
|
|
895
|
+
BOOST_CHECK(ready->block.vtx[1]->GetHash() == parent_ref->GetHash());
|
|
896
|
+
BOOST_CHECK(ready->block.vtx[2]->GetHash() == waiting_child_ref->GetHash());
|
|
897
|
+
BOOST_CHECK_EQUAL(ready->vTxFees[1], 500);
|
|
898
|
+
BOOST_CHECK_EQUAL(tx_mempool.size(), pool_size);
|
|
899
|
+
BOOST_CHECK_EQUAL(tx_mempool.GetTotalFee(), pool_fee);
|
|
900
|
+
}
|
|
901
|
+
options.nBlockPrioritySize = 0;
|
|
902
|
+
const auto disabled = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
|
903
|
+
BOOST_CHECK_EQUAL(disabled->block.vtx.size(), 1U);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
BOOST_AUTO_TEST_CASE(priority_tie_policy)
|
|
907
|
+
{
|
|
908
|
+
CTxMemPool& pool = MakeMempool();
|
|
909
|
+
LOCK2(cs_main, pool.cs);
|
|
910
|
+
BlockAssembler::Options options;
|
|
911
|
+
options.test_block_validity = false;
|
|
912
|
+
options.blockMinFeeRate = CFeeRate{1'000'000'000};
|
|
913
|
+
TestMemPoolEntryHelper entry;
|
|
914
|
+
CMutableTransaction high;
|
|
915
|
+
high.vin.emplace_back(COutPoint{Txid::FromUint256(uint256::ONE), 0});
|
|
916
|
+
high.vout.emplace_back(COIN, CScript{});
|
|
917
|
+
CMutableTransaction low = high;
|
|
918
|
+
low.vin[0].prevout.n = 1;
|
|
919
|
+
const auto high_ref = MakeTransactionRef(high);
|
|
920
|
+
const auto low_ref = MakeTransactionRef(low);
|
|
921
|
+
TryAddToMempool(pool, entry.Fee(100).FromTx(high_ref));
|
|
922
|
+
TryAddToMempool(pool, entry.Fee(10).FromTx(low_ref));
|
|
923
|
+
BOOST_REQUIRE(pool.PrioritiseTransaction(low_ref->GetHash(), 1'000'000));
|
|
924
|
+
// Both have zero coin age. Actual fee breaks the tie even when operator
|
|
925
|
+
// deltas reverse their modified-fee ordering. Threshold stops after one.
|
|
926
|
+
const auto actual_fee = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
|
|
927
|
+
BOOST_REQUIRE_EQUAL(actual_fee->block.vtx.size(), 2U);
|
|
928
|
+
BOOST_CHECK(actual_fee->block.vtx[1]->GetHash() == high_ref->GetHash());
|
|
929
|
+
pool.removeRecursive(*low_ref, MemPoolRemovalReason::REPLACED);
|
|
930
|
+
TryAddToMempool(pool, entry.Fee(100).FromTx(low_ref));
|
|
931
|
+
const auto hash_tie = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
|
|
932
|
+
BOOST_REQUIRE_EQUAL(hash_tie->block.vtx.size(), 2U);
|
|
933
|
+
BOOST_CHECK(hash_tie->block.vtx[1]->GetHash() == std::max(high_ref->GetHash(), low_ref->GetHash()));
|
|
934
|
+
options.nBlockPrioritySize = 0;
|
|
935
|
+
const auto disabled = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
|
|
936
|
+
BOOST_CHECK_EQUAL(disabled->block.vtx.size(), 1U);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
BOOST_AUTO_TEST_CASE(residual_policy_accounting)
|
|
940
|
+
{
|
|
941
|
+
CTxMemPool& pool = MakeMempool();
|
|
942
|
+
LOCK2(cs_main, pool.cs);
|
|
943
|
+
BlockAssembler::Options options;
|
|
944
|
+
options.test_block_validity = false;
|
|
945
|
+
options.blockMinFeeRate = CFeeRate{1000};
|
|
946
|
+
CMutableTransaction parent;
|
|
947
|
+
parent.vin.emplace_back(COutPoint{Txid::FromUint256(uint256::ONE), 0});
|
|
948
|
+
parent.vout.emplace_back(COIN, CScript{});
|
|
949
|
+
const auto parent_ref = MakeTransactionRef(parent);
|
|
950
|
+
CMutableTransaction child;
|
|
951
|
+
child.vin.emplace_back(COutPoint{parent_ref->GetHash(), 0});
|
|
952
|
+
child.vout.emplace_back(COIN - 20000, CScript{});
|
|
953
|
+
const auto child_ref = MakeTransactionRef(child);
|
|
954
|
+
const int32_t extra_weight = 401;
|
|
955
|
+
const int64_t adjusted_weight = GetTransactionWeight(*child_ref) + extra_weight;
|
|
956
|
+
const CAmount policy_vsize = (adjusted_weight + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
|
|
957
|
+
{
|
|
958
|
+
auto stage = pool.GetChangeSet();
|
|
959
|
+
stage->StageAddition(parent_ref, 100000, 0, 1, 0, false, 0, {}, 0, 110000);
|
|
960
|
+
stage->StageAddition(child_ref, 20000, 0, 1, 0, false, 0, {}, extra_weight, 20000 - policy_vsize);
|
|
961
|
+
BOOST_REQUIRE(stage->CheckMemPoolPolicyLimits());
|
|
962
|
+
stage->Apply();
|
|
963
|
+
}
|
|
964
|
+
// Priority uses actual fees on this zero-age tie and selects the parent.
|
|
965
|
+
// Its negative modified fee disappears; the child meets the exact rounded
|
|
966
|
+
// policy-vsize fee floor without stale ancestor debt or carrier resources.
|
|
967
|
+
const auto selected = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
|
|
968
|
+
BOOST_REQUIRE_EQUAL(selected->block.vtx.size(), 3U);
|
|
969
|
+
BOOST_CHECK(selected->block.vtx[1]->GetHash() == parent_ref->GetHash());
|
|
970
|
+
BOOST_CHECK(selected->block.vtx[2]->GetHash() == child_ref->GetHash());
|
|
971
|
+
BOOST_CHECK_EQUAL(selected->vTxFees[0], 100000);
|
|
972
|
+
BOOST_CHECK_EQUAL(selected->vTxFees[1], 20000);
|
|
973
|
+
BOOST_CHECK_EQUAL(selected->block.vtx[0]->vout[0].nValue,
|
|
974
|
+
GetBlockSubsidy(1, m_node.chainman->GetParams().GetConsensus()) + 120000);
|
|
975
|
+
BOOST_REQUIRE_EQUAL(selected->m_package_feerates.size(), 1U);
|
|
976
|
+
BOOST_CHECK(selected->m_package_feerates[0] == FeePerVSize(policy_vsize, policy_vsize));
|
|
977
|
+
BOOST_REQUIRE(pool.PrioritiseTransaction(child_ref->GetHash(), -1));
|
|
978
|
+
const auto below = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
|
|
979
|
+
BOOST_CHECK_EQUAL(below->block.vtx.size(), 2U);
|
|
980
|
+
BOOST_REQUIRE(pool.PrioritiseTransaction(child_ref->GetHash(), 1));
|
|
981
|
+
options.nBlockMaxWeight = DEFAULT_BLOCK_RESERVED_WEIGHT + GetTransactionWeight(*parent_ref) + adjusted_weight;
|
|
982
|
+
const auto capped = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
|
|
983
|
+
BOOST_CHECK_EQUAL(capped->block.vtx.size(), 2U);
|
|
984
|
+
++options.nBlockMaxWeight;
|
|
985
|
+
const auto fits = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
|
|
986
|
+
BOOST_CHECK_EQUAL(fits->block.vtx.size(), 3U);
|
|
987
|
+
options.nBlockPrioritySize = 0;
|
|
988
|
+
const auto disabled = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
|
|
989
|
+
BOOST_CHECK_EQUAL(disabled->block.vtx.size(), 1U);
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
BOOST_AUTO_TEST_CASE(template_option_normalization)
|
|
993
|
+
{
|
|
994
|
+
ArgsManager args;
|
|
995
|
+
BlockAssembler::Options options;
|
|
996
|
+
node::ApplyArgsManOptions(args, options);
|
|
997
|
+
BOOST_CHECK_EQUAL(options.nBlockMaxWeight, 1'200'000U);
|
|
998
|
+
BOOST_CHECK_EQUAL(options.nBlockMaxSize, MAX_BLOCK_SERIALIZED_SIZE);
|
|
999
|
+
BOOST_CHECK_EQUAL(options.nBlockPrioritySize, 100'000U);
|
|
1000
|
+
BOOST_CHECK_EQUAL(options.blockMinFeeRate.GetFeePerK(), 1000);
|
|
1001
|
+
args.ForceSetArg("-blockmaxsize", "120000");
|
|
1002
|
+
node::ApplyArgsManOptions(args, options);
|
|
1003
|
+
BOOST_CHECK_EQUAL(options.nBlockMaxWeight, MAX_BLOCK_WEIGHT);
|
|
1004
|
+
BOOST_CHECK_EQUAL(options.nBlockMaxSize, 120'000U);
|
|
1005
|
+
args.ForceSetArg("-blockmaxweight", "600000");
|
|
1006
|
+
args.ForceSetArg("-blockprioritysize", "0");
|
|
1007
|
+
args.ForceSetArg("-blockreservedweight", "9000");
|
|
1008
|
+
args.ForceSetArg("-blockmintxfee", "0.00002000");
|
|
1009
|
+
node::ApplyArgsManOptions(args, options);
|
|
1010
|
+
BOOST_CHECK_EQUAL(options.nBlockMaxWeight, 600'000U);
|
|
1011
|
+
BOOST_CHECK_EQUAL(options.nBlockMaxSize, 120'000U);
|
|
1012
|
+
BOOST_CHECK_EQUAL(options.nBlockPrioritySize, 0U);
|
|
1013
|
+
BOOST_REQUIRE(options.block_reserved_weight);
|
|
1014
|
+
BOOST_CHECK_EQUAL(*options.block_reserved_weight, 9000U);
|
|
1015
|
+
BOOST_CHECK_EQUAL(options.blockMinFeeRate.GetFeePerK(), 2000);
|
|
1016
|
+
ArgsManager weight_only;
|
|
1017
|
+
weight_only.ForceSetArg("-blockmaxweight", "700000");
|
|
1018
|
+
options = {};
|
|
1019
|
+
node::ApplyArgsManOptions(weight_only, options);
|
|
1020
|
+
BOOST_CHECK_EQUAL(options.nBlockMaxWeight, 700'000U);
|
|
1021
|
+
BOOST_CHECK_EQUAL(options.nBlockMaxSize, MAX_BLOCK_SERIALIZED_SIZE);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
746
1024
|
// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
|
|
747
1025
|
BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|
748
1026
|
{
|
|
1027
|
+
m_node.args->ForceSetArg("-blockprioritysize", "0");
|
|
1028
|
+
m_node.args->ForceSetArg("-blockmaxweight", "4000000");
|
|
749
1029
|
auto mining{MakeMining()};
|
|
750
1030
|
BOOST_REQUIRE(mining);
|
|
751
1031
|
|
|
752
1032
|
// Note that by default, these tests run with size accounting enabled.
|
|
753
1033
|
CScript scriptPubKey = CScript() << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"_hex << OP_CHECKSIG;
|
|
754
1034
|
BlockAssembler::Options options;
|
|
1035
|
+
options.nBlockPrioritySize = 0;
|
|
1036
|
+
options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
|
|
755
1037
|
options.coinbase_output_script = scriptPubKey;
|
|
756
1038
|
options.include_dummy_extranonce = true;
|
|
757
1039
|
|
|
@@ -867,6 +1149,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|
|
867
1149
|
SetMockTime(0);
|
|
868
1150
|
|
|
869
1151
|
TestPrioritisedMining(scriptPubKey, txFirst);
|
|
1152
|
+
TestPriorityPhaseStaleAncestors(scriptPubKey, txFirst);
|
|
870
1153
|
}
|
|
871
1154
|
|
|
872
1155
|
BOOST_AUTO_TEST_SUITE_END()
|