Skip to content

Commit 19b1e17

Browse files
committed
Merge bitcoin/bitcoin#32155: miner: timelock the coinbase to the mined block's height
a58cb3b qa: sanity check mined block have their coinbase timelocked to height (Antoine Poinsot) 8f2078a miner: timelock coinbase transactions (Antoine Poinsot) 788aeeb qa: use prev height as nLockTime for coinbase txs created in unit tests (Antoine Poinsot) c76dbe9 qa: timelock coinbase transactions created in fuzz targets (Antoine Poinsot) 9c94069 contrib: timelock coinbase transactions in signet miner (Antoine Poinsot) a5f52cf qa: timelock coinbase transactions created in functional tests (Antoine Poinsot) Pull request description: The Consensus Cleanup soft fork proposal includes enforcing that coinbase transactions set their nLockTime field to the block height minus 1, as well as their nSequence such as to not disable the timelock. If such a fork were to be activated by Bitcoin users, miners need to be ready to produce compliant blocks at the risk of losing substantial amounts mining would-be invalid blocks. As miners are unfamously slow to upgrade, it's good to make this change as early as possible. Although Bitcoin Core's GBT implementation does not provide the `coinbasetxn` field, and mining pool software crafts the coinbase on its own, updating the Bitcoin Core mining code is a first step toward convincing pools to update their (often closed source) code. A possible followup is also to introduce new fields to GBT. In addition, this first step also makes it possible to test future Consensus Cleanup changes. The commit making the change also updates a bunch of seemingly-unrelated tests. This is because those tests were asserting error messages based on the txid of transactions involved, and changing the coinbase transaction structure necessarily changes the txid of all tests' transactions. ACKs for top commit: Sjors: Code review ACK a58cb3b achow101: ACK a58cb3b TheCharlatan: Re-ACK a58cb3b Tree-SHA512: a2aae009a187eb760d34435f518a895ee76c6b02a667eb030ddf6bd584da6e8eae2737d974dbf81a928d60c07bcb4820f055adc067e18d8819640db0240bb513
2 parents 6c6ef58 + a58cb3b commit 19b1e17

21 files changed

+88
-58
lines changed

contrib/signet/miner

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ PATH_BASE_TEST_FUNCTIONAL = os.path.abspath(os.path.join(PATH_BASE_CONTRIB_SIGNE
1919
sys.path.insert(0, PATH_BASE_TEST_FUNCTIONAL)
2020

2121
from test_framework.blocktools import get_witness_script, script_BIP34_coinbase_height # noqa: E402
22-
from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, from_binary, from_hex, ser_string, ser_uint256, tx_from_hex # noqa: E402
22+
from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, from_binary, from_hex, ser_string, ser_uint256, tx_from_hex, MAX_SEQUENCE_NONFINAL # noqa: E402
2323
from test_framework.psbt import PSBT, PSBTMap, PSBT_GLOBAL_UNSIGNED_TX, PSBT_IN_FINAL_SCRIPTSIG, PSBT_IN_FINAL_SCRIPTWITNESS, PSBT_IN_NON_WITNESS_UTXO, PSBT_IN_SIGHASH_TYPE # noqa: E402
2424
from test_framework.script import CScript, CScriptOp # noqa: E402
2525

@@ -102,7 +102,8 @@ def generate_psbt(tmpl, reward_spk, *, blocktime=None, poolid=None):
102102
scriptSig = CScript(b"" + scriptSig + CScriptOp.encode_op_pushdata(poolid))
103103

104104
cbtx = CTransaction()
105-
cbtx.vin = [CTxIn(COutPoint(0, 0xffffffff), scriptSig, 0xffffffff)]
105+
cbtx.nLockTime = tmpl["height"] - 1
106+
cbtx.vin = [CTxIn(COutPoint(0, 0xffffffff), scriptSig, MAX_SEQUENCE_NONFINAL)]
106107
cbtx.vout = [CTxOut(tmpl["coinbasevalue"], reward_spk)]
107108
cbtx.vin[0].nSequence = 2**32-2
108109
cbtx.rehash()

src/kernel/chainparams.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -593,23 +593,23 @@ class CRegTestParams : public CChainParams
593593
m_assumeutxo_data = {
594594
{ // For use by unit tests
595595
.height = 110,
596-
.hash_serialized = AssumeutxoHash{uint256{"6657b736d4fe4db0cbc796789e812d5dba7f5c143764b1b6905612f1830609d1"}},
596+
.hash_serialized = AssumeutxoHash{uint256{"b952555c8ab81fec46f3d4253b7af256d766ceb39fb7752b9d18cdf4a0141327"}},
597597
.m_chain_tx_count = 111,
598-
.blockhash = consteval_ctor(uint256{"696e92821f65549c7ee134edceeeeaaa4105647a3c4fd9f298c0aec0ab50425c"}),
598+
.blockhash = consteval_ctor(uint256{"6affe030b7965ab538f820a56ef56c8149b7dc1d1c144af57113be080db7c397"}),
599599
},
600600
{
601601
// For use by fuzz target src/test/fuzz/utxo_snapshot.cpp
602602
.height = 200,
603-
.hash_serialized = AssumeutxoHash{uint256{"7e3b7780fbd2fa479a01f66950dc8f728dc1b11f03d06d5bf223168520df3a48"}},
603+
.hash_serialized = AssumeutxoHash{uint256{"17dcc016d188d16068907cdeb38b75691a118d43053b8cd6a25969419381d13a"}},
604604
.m_chain_tx_count = 201,
605-
.blockhash = consteval_ctor(uint256{"5e93653318f294fb5aa339d00bbf8cf1c3515488ad99412c37608b139ea63b27"}),
605+
.blockhash = consteval_ctor(uint256{"385901ccbd69dff6bbd00065d01fb8a9e464dede7cfe0372443884f9b1dcf6b9"}),
606606
},
607607
{
608608
// For use by test/functional/feature_assumeutxo.py
609609
.height = 299,
610-
.hash_serialized = AssumeutxoHash{uint256{"a4bf3407ccb2cc0145c49ebba8fa91199f8a3903daf0883875941497d2493c27"}},
610+
.hash_serialized = AssumeutxoHash{uint256{"d2b051ff5e8eef46520350776f4100dd710a63447a8e01d917e92e79751a63e2"}},
611611
.m_chain_tx_count = 334,
612-
.blockhash = consteval_ctor(uint256{"3bb7ce5eba0be48939b7a521ac1ba9316afee2c7bada3a0cca24188e6d7d96c0"}),
612+
.blockhash = consteval_ctor(uint256{"7cc695046fec709f8c9394b6f928f81e81fd3ac20977bb68760fa1faa7916ea2"}),
613613
},
614614
};
615615

src/node/miner.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,13 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock()
158158
CMutableTransaction coinbaseTx;
159159
coinbaseTx.vin.resize(1);
160160
coinbaseTx.vin[0].prevout.SetNull();
161+
coinbaseTx.vin[0].nSequence = CTxIn::MAX_SEQUENCE_NONFINAL; // Make sure timelock is enforced.
161162
coinbaseTx.vout.resize(1);
162163
coinbaseTx.vout[0].scriptPubKey = m_options.coinbase_output_script;
163164
coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
164165
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
166+
Assert(nHeight > 0);
167+
coinbaseTx.nLockTime = static_cast<uint32_t>(nHeight - 1);
165168
pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));
166169
pblocktemplate->vchCoinbaseCommitment = m_chainstate.m_chainman.GenerateCoinbaseCommitment(*pblock, pindexPrev);
167170

src/test/blockfilter_index_tests.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ CBlock BuildChainTestingSetup::CreateBlock(const CBlockIndex* prev,
8181
}
8282
{
8383
CMutableTransaction tx_coinbase{*block.vtx.at(0)};
84+
tx_coinbase.nLockTime = static_cast<uint32_t>(prev->nHeight);
8485
tx_coinbase.vin.at(0).scriptSig = CScript{} << prev->nHeight + 1;
8586
block.vtx.at(0) = MakeTransactionRef(std::move(tx_coinbase));
8687
block.hashMerkleRoot = BlockMerkleRoot(block);

src/test/fuzz/utxo_total_supply.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ FUZZ_TARGET(utxo_total_supply)
5252
// Replace OP_FALSE with OP_TRUE
5353
{
5454
CMutableTransaction tx{*block->vtx.back()};
55+
tx.nLockTime = 0; // Use the same nLockTime for all as we want to duplicate one of them.
5556
tx.vout.at(0).scriptPubKey = CScript{} << OP_TRUE;
5657
block->vtx.back() = MakeTransactionRef(tx);
5758
}

src/test/miner_tests.cpp

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,27 +70,27 @@ BOOST_FIXTURE_TEST_SUITE(miner_tests, MinerTestingSetup)
7070
static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
7171

7272
constexpr static struct {
73-
unsigned char extranonce;
73+
unsigned int extranonce;
7474
unsigned int nonce;
75-
} BLOCKINFO[]{{8, 582909131}, {0, 971462344}, {2, 1169481553}, {6, 66147495}, {7, 427785981}, {8, 80538907},
76-
{8, 207348013}, {2, 1951240923}, {4, 215054351}, {1, 491520534}, {8, 1282281282}, {4, 639565734},
77-
{3, 248274685}, {8, 1160085976}, {6, 396349768}, {5, 393780549}, {5, 1096899528}, {4, 965381630},
78-
{0, 728758712}, {5, 318638310}, {3, 164591898}, {2, 274234550}, {2, 254411237}, {7, 561761812},
79-
{2, 268342573}, {0, 402816691}, {1, 221006382}, {6, 538872455}, {7, 393315655}, {4, 814555937},
80-
{7, 504879194}, {6, 467769648}, {3, 925972193}, {2, 200581872}, {3, 168915404}, {8, 430446262},
81-
{5, 773507406}, {3, 1195366164}, {0, 433361157}, {3, 297051771}, {0, 558856551}, {2, 501614039},
82-
{3, 528488272}, {2, 473587734}, {8, 230125274}, {2, 494084400}, {4, 357314010}, {8, 60361686},
83-
{7, 640624687}, {3, 480441695}, {8, 1424447925}, {4, 752745419}, {1, 288532283}, {6, 669170574},
84-
{5, 1900907591}, {3, 555326037}, {3, 1121014051}, {0, 545835650}, {8, 189196651}, {5, 252371575},
85-
{0, 199163095}, {6, 558895874}, {6, 1656839784}, {6, 815175452}, {6, 718677851}, {5, 544000334},
86-
{0, 340113484}, {6, 850744437}, {4, 496721063}, {8, 524715182}, {6, 574361898}, {6, 1642305743},
87-
{6, 355110149}, {5, 1647379658}, {8, 1103005356}, {7, 556460625}, {3, 1139533992}, {5, 304736030},
88-
{2, 361539446}, {2, 143720360}, {6, 201939025}, {7, 423141476}, {4, 574633709}, {3, 1412254823},
89-
{4, 873254135}, {0, 341817335}, {6, 53501687}, {3, 179755410}, {5, 172209688}, {8, 516810279},
90-
{4, 1228391489}, {8, 325372589}, {6, 550367589}, {0, 876291812}, {7, 412454120}, {7, 717202854},
91-
{2, 222677843}, {6, 251778867}, {7, 842004420}, {7, 194762829}, {4, 96668841}, {1, 925485796},
92-
{0, 792342903}, {6, 678455063}, {6, 773251385}, {5, 186617471}, {6, 883189502}, {7, 396077336},
93-
{8, 254702874}, {0, 455592851}};
75+
} BLOCKINFO[]{{0, 3552706918}, {500, 37506755}, {1000, 948987788}, {400, 524762339}, {800, 258510074}, {300, 102309278},
76+
{1300, 54365202}, {600, 1107740426}, {1000, 203094491}, {900, 391178848}, {800, 381177271}, {600, 87188412},
77+
{0, 66522866}, {800, 874942736}, {1000, 89200838}, {400, 312638088}, {400, 66263693}, {500, 924648304},
78+
{400, 369913599}, {500, 47630099}, {500, 115045364}, {100, 277026602}, {1100, 809621409}, {700, 155345322},
79+
{800, 943579953}, {400, 28200730}, {900, 77200495}, {0, 105935488}, {400, 698721821}, {500, 111098863},
80+
{1300, 445389594}, {500, 621849894}, {1400, 56010046}, {1100, 370669776}, {1200, 380301940}, {1200, 110654905},
81+
{400, 213771024}, {1500, 120014726}, {1200, 835019014}, {1500, 624817237}, {900, 1404297}, {400, 189414558},
82+
{400, 293178348}, {1100, 15393789}, {600, 396764180}, {800, 1387046371}, {800, 199368303}, {700, 111496662},
83+
{100, 129759616}, {200, 536577982}, {500, 125881300}, {500, 101053391}, {1200, 471590548}, {900, 86957729},
84+
{1200, 179604104}, {600, 68658642}, {1000, 203295701}, {500, 139615361}, {900, 233693412}, {300, 153225163},
85+
{0, 27616254}, {1200, 9856191}, {100, 220392722}, {200, 66257599}, {1100, 145489641}, {1300, 37859442},
86+
{400, 5816075}, {1200, 215752117}, {1400, 32361482}, {1400, 6529223}, {500, 143332977}, {800, 878392},
87+
{700, 159290408}, {400, 123197595}, {700, 43988693}, {300, 304224916}, {700, 214771621}, {1100, 274148273},
88+
{400, 285632418}, {1100, 923451065}, {600, 12818092}, {1200, 736282054}, {1000, 246683167}, {600, 92950402},
89+
{1400, 29223405}, {1000, 841327192}, {700, 174301283}, {1400, 214009854}, {1000, 6989517}, {1200, 278226956},
90+
{700, 540219613}, {400, 93663104}, {1100, 152345635}, {1500, 464194499}, {1300, 333850111}, {600, 258311263},
91+
{600, 90173162}, {1000, 33590797}, {1500, 332866027}, {100, 204704427}, {1000, 463153545}, {800, 303244785},
92+
{600, 88096214}, {0, 137477892}, {1200, 195514506}, {300, 704114595}, {900, 292087369}, {1400, 758684870},
93+
{1300, 163493028}, {1200, 53151293}};
9494

9595
static std::unique_ptr<CBlockIndex> CreateBlockIndex(int nHeight, CBlockIndex* active_chain_tip) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
9696
{

src/test/rbf_tests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
311311
// Tests for CheckConflictTopology
312312

313313
// Tx4 has 23 descendants
314-
BOOST_CHECK_EQUAL(pool.CheckConflictTopology(set_34_cpfp).value(), strprintf("%s has 23 descendants, max 1 allowed", entry4_high->GetSharedTx()->GetHash().ToString()));
314+
BOOST_CHECK_EQUAL(pool.CheckConflictTopology(set_34_cpfp).value(), strprintf("%s has 24 descendants, max 1 allowed", entry3_low->GetSharedTx()->GetHash().ToString()));
315315

316316
// No descendants yet
317317
BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);
@@ -441,7 +441,7 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)
441441
const auto res3 = ImprovesFeerateDiagram(*changeset);
442442
BOOST_CHECK(res3.has_value());
443443
BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);
444-
BOOST_CHECK(res3.value().second == strprintf("%s has 2 ancestors, max 1 allowed", tx5->GetHash().GetHex()));
444+
BOOST_CHECK_MESSAGE(res3.value().second == strprintf("%s has 2 descendants, max 1 allowed", tx1->GetHash().GetHex()), res3.value().second);
445445
}
446446

447447
BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)
@@ -536,7 +536,7 @@ BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)
536536
changeset->StageAddition(replacement_tx, high_fee, 0, 1, 0, false, 4, LockPoints());
537537
const auto replace_too_large{changeset->CalculateChunksForRBF()};
538538
BOOST_CHECK(!replace_too_large.has_value());
539-
BOOST_CHECK_EQUAL(util::ErrorString(replace_too_large).original, strprintf("%s has 2 ancestors, max 1 allowed", normal_tx->GetHash().GetHex()));
539+
BOOST_CHECK_EQUAL(util::ErrorString(replace_too_large).original, strprintf("%s has both ancestor and descendant, exceeding cluster limit of 2", high_tx->GetHash().GetHex()));
540540
}
541541

542542
// Make a size 2 cluster that is itself two chunks; evict both txns
@@ -623,7 +623,7 @@ BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)
623623
const auto replace_cluster_size_3{changeset->CalculateChunksForRBF()};
624624

625625
BOOST_CHECK(!replace_cluster_size_3.has_value());
626-
BOOST_CHECK_EQUAL(util::ErrorString(replace_cluster_size_3).original, strprintf("%s has both ancestor and descendant, exceeding cluster limit of 2", conflict_1_child->GetHash().GetHex()));
626+
BOOST_CHECK_EQUAL(util::ErrorString(replace_cluster_size_3).original, strprintf("%s has 2 descendants, max 1 allowed", conflict_1->GetHash().GetHex()));
627627
}
628628
}
629629

src/test/util/mining.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <validationinterface.h>
1818
#include <versionbits.h>
1919

20+
#include <algorithm>
21+
2022
using node::BlockAssembler;
2123
using node::NodeContext;
2224

@@ -34,12 +36,15 @@ std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const
3436
{
3537
std::vector<std::shared_ptr<CBlock>> ret{total_height};
3638
auto time{params.GenesisBlock().nTime};
39+
// NOTE: here `height` does not correspond to the block height but the block height - 1.
3740
for (size_t height{0}; height < total_height; ++height) {
3841
CBlock& block{*(ret.at(height) = std::make_shared<CBlock>())};
3942

4043
CMutableTransaction coinbase_tx;
44+
coinbase_tx.nLockTime = static_cast<uint32_t>(height);
4145
coinbase_tx.vin.resize(1);
4246
coinbase_tx.vin[0].prevout.SetNull();
47+
coinbase_tx.vin[0].nSequence = CTxIn::MAX_SEQUENCE_NONFINAL; // Make sure timelock is enforced.
4348
coinbase_tx.vout.resize(1);
4449
coinbase_tx.vout[0].scriptPubKey = P2WSH_OP_TRUE;
4550
coinbase_tx.vout[0].nValue = GetBlockSubsidy(height + 1, params.GetConsensus());

src/test/util/setup_common.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ TestChain100Setup::TestChain100Setup(
370370
LOCK(::cs_main);
371371
assert(
372372
m_node.chainman->ActiveChain().Tip()->GetBlockHash().ToString() ==
373-
"571d80a9967ae599cec0448b0b0ba1cfb606f584d8069bd7166b86854ba7a191");
373+
"0c8c5f79505775a0f6aed6aca2350718ceb9c6f2c878667864d5c7a6d8ffa2a6");
374374
}
375375
}
376376

src/test/validation_block_tests.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ std::shared_ptr<CBlock> MinerTestingSetup::Block(const uint256& prev_hash)
8282
txCoinbase.vout[0].nValue = 0;
8383
txCoinbase.vin[0].scriptWitness.SetNull();
8484
// Always pad with OP_0 at the end to avoid bad-cb-length error
85-
txCoinbase.vin[0].scriptSig = CScript{} << WITH_LOCK(::cs_main, return m_node.chainman->m_blockman.LookupBlockIndex(prev_hash)->nHeight + 1) << OP_0;
85+
const int prev_height{WITH_LOCK(::cs_main, return m_node.chainman->m_blockman.LookupBlockIndex(prev_hash)->nHeight)};
86+
txCoinbase.vin[0].scriptSig = CScript{} << prev_height + 1 << OP_0;
87+
txCoinbase.nLockTime = static_cast<uint32_t>(prev_height);
8688
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
8789

8890
return pblock;

0 commit comments

Comments
 (0)