From da3e225592be63309beb2af42e00227e4045c23d Mon Sep 17 00:00:00 2001 From: willcl-ark Date: Mon, 10 Jul 2023 09:48:11 +0100 Subject: [PATCH] [BlockAssembler]: return selected packages feerate and vsize - The commit also test that block assembler now returns selected package vsize's and fee rates. Co-authored-by: Pieter Wuille Co-authored-by: ismaelsadeeq --- src/node/miner.cpp | 3 +++ src/node/miner.h | 4 +++ src/test/miner_tests.cpp | 53 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 291f1d5fc7fa2a..06a4f5c49f5c40 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -173,6 +173,8 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc Ticks(time_2 - time_1), Ticks(time_2 - time_start)); + pblocktemplate->vFeeratePerSize = std::move(feerate_per_size); + return std::move(pblocktemplate); } @@ -414,6 +416,7 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele } ++nPackagesSelected; + feerate_per_size.emplace_back(CFeeRate{packageFees, packageSize}, packageSize); // Update transactions that depend on each of these nDescendantsUpdated += UpdatePackagesForAdded(mempool, ancestors, mapModifiedTx); diff --git a/src/node/miner.h b/src/node/miner.h index 622ca16c8fd172..641d17221d2953 100644 --- a/src/node/miner.h +++ b/src/node/miner.h @@ -6,6 +6,7 @@ #ifndef BITCOIN_NODE_MINER_H #define BITCOIN_NODE_MINER_H +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include @@ -38,6 +40,7 @@ struct CBlockTemplate std::vector vTxFees; std::vector vTxSigOpsCost; std::vector vchCoinbaseCommitment; + std::vector> vFeeratePerSize; }; // Container for tracking updates to ancestor feerate as we include (parent) @@ -143,6 +146,7 @@ class BlockAssembler uint64_t nBlockSigOpsCost; CAmount nFees; std::unordered_set inBlock; + std::vector> feerate_per_size; // Chain context for the block int nHeight; diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index c4cf6f8a400a2f..b916cfeb40a9d9 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,9 @@ #include #include +#include +#include +#include #include @@ -54,6 +58,24 @@ struct MinerTestingSetup : public TestingSetup { return *m_node.mempool; } BlockAssembler AssemblerForTest(CTxMemPool& tx_mempool); + + // Find a CFeeRate in a vector of tuples + std::optional> findFeeRate( + const std::vector>& blockFeeAndVsizes, + const CFeeRate& targetRate) + { + auto iter = std::find_if( + blockFeeAndVsizes.begin(), blockFeeAndVsizes.end(), + [&targetRate](const std::tuple& element) -> bool { + return std::get<0>(element) == targetRate; + }); + + if (iter != blockFeeAndVsizes.end()) { + return *iter; + } else { + return std::nullopt; + } + } }; } // namespace miner_tests @@ -122,26 +144,49 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const tx.vout[0].nValue = 5000000000LL - 1000; // This tx has a low fee: 1000 satoshis Txid hashParentTx = tx.GetHash(); // save this txid for later use - tx_mempool.addUnchecked(entry.Fee(1000).Time(Now()).SpendsCoinbase(true).FromTx(tx)); + const auto lowFeeTx = entry.Fee(1000).Time(Now()).SpendsCoinbase(true).FromTx(tx); + tx_mempool.addUnchecked(lowFeeTx); // This tx has a medium fee: 10000 satoshis tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = 5000000000LL - 10000; Txid hashMediumFeeTx = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(10000).Time(Now()).SpendsCoinbase(true).FromTx(tx)); + const auto mediumFeeTx = entry.Fee(10000).Time(Now()).SpendsCoinbase(true).FromTx(tx); + tx_mempool.addUnchecked(mediumFeeTx); // This tx has a high fee, but depends on the first transaction tx.vin[0].prevout.hash = hashParentTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee Txid hashHighFeeTx = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(50000).Time(Now()).SpendsCoinbase(false).FromTx(tx)); + const auto highFeeChildTx = entry.Fee(50000).Time(Now()).SpendsCoinbase(false).FromTx(tx); + tx_mempool.addUnchecked(highFeeChildTx); - std::unique_ptr pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); + auto assembler = AssemblerForTest(tx_mempool); + std::unique_ptr pblocktemplate = assembler.CreateNewBlock(scriptPubKey); + const auto blockFeeAndVsizes = pblocktemplate->vFeeratePerSize; BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 4U); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx); BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx); BOOST_CHECK(pblocktemplate->block.vtx[3]->GetHash() == hashMediumFeeTx); + BOOST_CHECK(blockFeeAndVsizes.size() == 2); + + // lowFeeTx and highFeeChildTx are added to the block as a package. + const auto packageFee = lowFeeTx.GetFee() + highFeeChildTx.GetFee(); + const auto packageSize = lowFeeTx.GetTxSize() + highFeeChildTx.GetTxSize(); + + CFeeRate packageRate(packageFee, packageSize); + auto packageFeeRateFound = findFeeRate(blockFeeAndVsizes, packageRate); + + CFeeRate mediumRate(mediumFeeTx.GetFee(), mediumFeeTx.GetTxSize()); + auto mediumTxFeeRateFound = findFeeRate(blockFeeAndVsizes, mediumRate); + + BOOST_CHECK(packageFeeRateFound != std::nullopt); + BOOST_CHECK(mediumTxFeeRateFound != std::nullopt); + + BOOST_CHECK(std::get<1>(*packageFeeRateFound) == static_cast(packageSize)); + BOOST_CHECK(std::get<1>(*mediumTxFeeRateFound) == static_cast(mediumFeeTx.GetTxSize())); + // Test that a package below the block min tx fee doesn't get included tx.vin[0].prevout.hash = hashHighFeeTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee