Skip to content

Commit

Permalink
[BlockAssembler]: return selected packages feerate and vsize
Browse files Browse the repository at this point in the history
- The commit also test that block assembler now returns selected package
  vsize's and fee rates.

Co-authored-by: Pieter Wuille <bitcoin-dev@wuille.net>

Co-authored-by: ismaelsadeeq <ask4ismailsadiq@gmail.com>
  • Loading branch information
willcl-ark and ismaelsadeeq committed Jul 7, 2024
1 parent 3714692 commit 5b96430
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 6 deletions.
7 changes: 5 additions & 2 deletions src/node/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
Ticks<MillisecondsDouble>(time_2 - time_1),
Ticks<MillisecondsDouble>(time_2 - time_start));

pblocktemplate->vFeeratePerSize = std::move(feerate_per_size);

return std::move(pblocktemplate);
}

Expand Down Expand Up @@ -353,11 +355,11 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele
// contain anything that is inBlock.
assert(!inBlock.count(iter->GetSharedTx()->GetHash()));

uint64_t packageSize = iter->GetSizeWithAncestors();
uint32_t packageSize = static_cast<uint32_t>(iter->GetSizeWithAncestors());
CAmount packageFees = iter->GetModFeesWithAncestors();
int64_t packageSigOpsCost = iter->GetSigOpCostWithAncestors();
if (fUsingModified) {
packageSize = modit->nSizeWithAncestors;
packageSize = static_cast<uint32_t>modit->nSizeWithAncestors;
packageFees = modit->nModFeesWithAncestors;
packageSigOpsCost = modit->nSigOpCostWithAncestors;
}
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions src/node/miner.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
#ifndef BITCOIN_NODE_MINER_H
#define BITCOIN_NODE_MINER_H

#include <policy/feerate.h>
#include <policy/policy.h>
#include <primitives/block.h>
#include <txmempool.h>

#include <memory>
#include <optional>
#include <stdint.h>
#include <tuple>

#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/indexed_by.hpp>
Expand All @@ -38,6 +40,7 @@ struct CBlockTemplate
std::vector<CAmount> vTxFees;
std::vector<int64_t> vTxSigOpsCost;
std::vector<unsigned char> vchCoinbaseCommitment;
std::vector<std::tuple<CFeeRate, uint64_t>> vFeeratePerSize;
};

// Container for tracking updates to ancestor feerate as we include (parent)
Expand Down Expand Up @@ -143,6 +146,7 @@ class BlockAssembler
uint64_t nBlockSigOpsCost;
CAmount nFees;
std::unordered_set<Txid, SaltedTxidHasher> inBlock;
std::vector<std::tuple<CFeeRate, uint64_t>> feerate_per_size;

// Chain context for the block
int nHeight;
Expand Down
53 changes: 49 additions & 4 deletions src/test/miner_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <consensus/merkle.h>
#include <consensus/tx_verify.h>
#include <node/miner.h>
#include <policy/feerate.h>
#include <policy/policy.h>
#include <test/util/random.h>
#include <test/util/txmempool.h>
Expand All @@ -24,6 +25,9 @@
#include <test/util/setup_common.h>

#include <memory>
#include <optional>
#include <tuple>
#include <vector>

#include <boost/test/unit_test.hpp>

Expand Down Expand Up @@ -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<std::tuple<CFeeRate, uint64_t>> findFeeRate(
const std::vector<std::tuple<CFeeRate, uint64_t>>& blockFeeAndVsizes,
const CFeeRate& targetRate)
{
auto iter = std::find_if(
blockFeeAndVsizes.begin(), blockFeeAndVsizes.end(),
[&targetRate](const std::tuple<CFeeRate, uint64_t>& element) -> bool {
return std::get<0>(element) == targetRate;
});

if (iter != blockFeeAndVsizes.end()) {
return *iter;
} else {
return std::nullopt;
}
}
};
} // namespace miner_tests

Expand Down Expand Up @@ -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<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
const auto lowFeeTx = entry.Fee(1000).Time(Now<NodeSeconds>()).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<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
const auto mediumFeeTx = entry.Fee(10000).Time(Now<NodeSeconds>()).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<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
const auto highFeeChildTx = entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx);
tx_mempool.addUnchecked(highFeeChildTx);

std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
auto assembler = AssemblerForTest(tx_mempool);
std::unique_ptr<CBlockTemplate> 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<uint64_t>(packageSize));
BOOST_CHECK(std::get<1>(*mediumTxFeeRateFound) == static_cast<uint64_t>(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
Expand Down

0 comments on commit 5b96430

Please sign in to comment.