Skip to content

Commit dfb7d58

Browse files
committed
Merge bitcoin/bitcoin#31897: mining: drop unused -nFees and sigops from CBlockTemplate
226d81f mining: drop unused -nFees and sigops from CBlockTemplate (Sjors Provoost) 53ad845 test: check fees and sigops in getblocktemplate (Sjors Provoost) Pull request description: For the coinbase `vTxFees` used a dummy value of -nFees. Similarly the first `vTxSigOpsCost` entry was calculated from the dummy coinbase transaction. This was introduced in #2115, but the values were never returned by the RPC or used in a test. Drop 'm and add code comments to prevent confusion. This PR also adds test coverage for the `fees` and `sigops` fields in `getblocktemplate`, so it closes #32053. ACKs for top commit: ismaelsadeeq: re-ACK 226d81f ryanofsky: Code review ACK 226d81f. New test was added since last review, which seems very cleanly written and fixes some missing coverage. glozow: ACK 226d81f Tree-SHA512: 79c534e6bc4810d29114b04dd6db798877732cb473e773bf3cc28f83d14ee3982392587bd0baa39857bd53a79eae3b730d7a7029b08a9b6c3b5c51f86657ca5d
2 parents 1d281da + 226d81f commit dfb7d58

File tree

5 files changed

+64
-7
lines changed

5 files changed

+64
-7
lines changed

src/interfaces/mining.h

+3
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@ class BlockTemplate
3434
virtual ~BlockTemplate() = default;
3535

3636
virtual CBlockHeader getBlockHeader() = 0;
37+
// Block contains a dummy coinbase transaction that should not be used.
3738
virtual CBlock getBlock() = 0;
3839

40+
// Fees per transaction, not including coinbase transaction.
3941
virtual std::vector<CAmount> getTxFees() = 0;
42+
// Sigop cost per transaction, not including coinbase transaction.
4043
virtual std::vector<int64_t> getTxSigops() = 0;
4144

4245
virtual CTransactionRef getCoinbaseTx() = 0;

src/node/miner.cpp

+2-5
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,9 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock()
124124
pblocktemplate.reset(new CBlockTemplate());
125125
CBlock* const pblock = &pblocktemplate->block; // pointer for convenience
126126

127-
// Add dummy coinbase tx as first transaction
127+
// Add dummy coinbase tx as first transaction. It is skipped by the
128+
// getblocktemplate RPC and mining interface consumers must not use it.
128129
pblock->vtx.emplace_back();
129-
pblocktemplate->vTxFees.push_back(-1); // updated at end
130-
pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end
131130

132131
LOCK(::cs_main);
133132
CBlockIndex* pindexPrev = m_chainstate.m_chain.Tip();
@@ -165,7 +164,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock()
165164
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
166165
pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));
167166
pblocktemplate->vchCoinbaseCommitment = m_chainstate.m_chainman.GenerateCoinbaseCommitment(*pblock, pindexPrev);
168-
pblocktemplate->vTxFees[0] = -nFees;
169167

170168
LogPrintf("CreateNewBlock(): block weight: %u txs: %u fees: %ld sigops %d\n", GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost);
171169

@@ -174,7 +172,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock()
174172
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
175173
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus());
176174
pblock->nNonce = 0;
177-
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
178175

179176
BlockValidationState state;
180177
if (m_options.test_block_validity && !TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev,

src/node/miner.h

+2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ static const bool DEFAULT_PRINT_MODIFIED_FEE = false;
3737
struct CBlockTemplate
3838
{
3939
CBlock block;
40+
// Fees per transaction, not including coinbase transaction (unlike CBlock::vtx).
4041
std::vector<CAmount> vTxFees;
42+
// Sigops per transaction, not including coinbase transaction (unlike CBlock::vtx).
4143
std::vector<int64_t> vTxSigOpsCost;
4244
std::vector<unsigned char> vchCoinbaseCommitment;
4345
/* A vector of package fee rates, ordered by the sequence in which

src/rpc/mining.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -893,7 +893,7 @@ static RPCHelpMan getblocktemplate()
893893
}
894894
entry.pushKV("depends", std::move(deps));
895895

896-
int index_in_template = i - 1;
896+
int index_in_template = i - 2;
897897
entry.pushKV("fee", tx_fees.at(index_in_template));
898898
int64_t nTxSigOps{tx_sigops.at(index_in_template)};
899899
if (fPreSegWit) {

test/functional/mining_basic.py

+56-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@
4040
assert_raises_rpc_error,
4141
get_fee,
4242
)
43-
from test_framework.wallet import MiniWallet
43+
from test_framework.wallet import (
44+
MiniWallet,
45+
MiniWalletMode,
46+
)
4447

4548

4649
DIFFICULTY_ADJUSTMENT_INTERVAL = 144
@@ -93,6 +96,57 @@ def mine_chain(self):
9396
self.restart_node(0)
9497
self.connect_nodes(0, 1)
9598

99+
def test_fees_and_sigops(self):
100+
self.log.info("Test fees and sigops in getblocktemplate result")
101+
node = self.nodes[0]
102+
103+
# Generate a coinbases with p2pk transactions for its sigops.
104+
wallet_sigops = MiniWallet(node, mode=MiniWalletMode.RAW_P2PK)
105+
self.generate(wallet_sigops, 1, sync_fun=self.no_op)
106+
107+
# Mature with regular coinbases to prevent inteference with other tests
108+
self.generate(self.wallet, 100, sync_fun=self.no_op)
109+
110+
# Generate three transactions that must be mined in sequence
111+
#
112+
# tx_a (1 sat/vbyte)
113+
# |
114+
# |
115+
# tx_b (2 sat/vbyte)
116+
# |
117+
# |
118+
# tx_c (3 sat/vbyte)
119+
#
120+
tx_a = wallet_sigops.send_self_transfer(from_node=node,
121+
fee_rate=Decimal("0.00001"))
122+
tx_b = wallet_sigops.send_self_transfer(from_node=node,
123+
fee_rate=Decimal("0.00002"),
124+
utxo_to_spend=tx_a["new_utxo"])
125+
tx_c = wallet_sigops.send_self_transfer(from_node=node,
126+
fee_rate=Decimal("0.00003"),
127+
utxo_to_spend=tx_b["new_utxo"])
128+
129+
# Generate transaction without sigops. It will go first because it pays
130+
# higher fees (100 sat/vbyte) and descends from a different coinbase.
131+
tx_d = self.wallet.send_self_transfer(from_node=node,
132+
fee_rate=Decimal("0.00100"))
133+
134+
block_template_txs = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)['transactions']
135+
136+
block_template_fees = [tx['fee'] for tx in block_template_txs]
137+
assert_equal(block_template_fees, [
138+
tx_d["fee"] * COIN,
139+
tx_a["fee"] * COIN,
140+
tx_b["fee"] * COIN,
141+
tx_c["fee"] * COIN
142+
])
143+
144+
block_template_sigops = [tx['sigops'] for tx in block_template_txs]
145+
assert_equal(block_template_sigops, [0, 4, 4, 4])
146+
147+
# Clear mempool
148+
self.generate(self.wallet, 1, sync_fun=self.no_op)
149+
96150
def test_blockmintxfee_parameter(self):
97151
self.log.info("Test -blockmintxfee setting")
98152
self.restart_node(0, extra_args=['-minrelaytxfee=0', '-persistmempool=0'])
@@ -533,6 +587,7 @@ def chain_tip(b_hash, *, status='headers-only', branchlen=1):
533587
node.submitheader(hexdata=CBlockHeader(bad_block_root).serialize().hex())
534588
assert_equal(node.submitblock(hexdata=block.serialize().hex()), 'duplicate') # valid
535589

590+
self.test_fees_and_sigops()
536591
self.test_blockmintxfee_parameter()
537592
self.test_block_max_weight()
538593
self.test_timewarp()

0 commit comments

Comments
 (0)