Skip to content

Commit ef6b33c

Browse files
instagibbsjtimon
authored andcommitted
blockheaders include block height, nodes validate it
1 parent 806b355 commit ef6b33c

File tree

7 files changed

+47
-4
lines changed

7 files changed

+47
-4
lines changed

src/chain.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
#include <vector>
1616

17+
#include <util.h>
18+
1719
/**
1820
* Maximum amount of time that a block timestamp is allowed to exceed the
1921
* current network-adjusted time before the block will be accepted.
@@ -210,6 +212,7 @@ class CBlockIndex
210212
int32_t nVersion;
211213
uint256 hashMerkleRoot;
212214
uint32_t nTime;
215+
uint32_t block_height;
213216
uint32_t nBits;
214217
uint32_t nNonce;
215218

@@ -238,6 +241,7 @@ class CBlockIndex
238241
nVersion = 0;
239242
hashMerkleRoot = uint256();
240243
nTime = 0;
244+
block_height = 0;
241245
nBits = 0;
242246
nNonce = 0;
243247
}
@@ -254,6 +258,7 @@ class CBlockIndex
254258
nVersion = block.nVersion;
255259
hashMerkleRoot = block.hashMerkleRoot;
256260
nTime = block.nTime;
261+
block_height = block.block_height;
257262
nBits = block.nBits;
258263
nNonce = block.nNonce;
259264
}
@@ -284,6 +289,7 @@ class CBlockIndex
284289
block.hashPrevBlock = pprev->GetBlockHash();
285290
block.hashMerkleRoot = hashMerkleRoot;
286291
block.nTime = nTime;
292+
block.block_height = block_height;
287293
block.nBits = nBits;
288294
block.nNonce = nNonce;
289295
return block;
@@ -403,6 +409,7 @@ class CDiskBlockIndex : public CBlockIndex
403409
READWRITE(hashPrev);
404410
READWRITE(hashMerkleRoot);
405411
READWRITE(nTime);
412+
READWRITE(block_height);
406413
READWRITE(nBits);
407414
READWRITE(nNonce);
408415
}
@@ -414,6 +421,7 @@ class CDiskBlockIndex : public CBlockIndex
414421
block.hashPrevBlock = hashPrev;
415422
block.hashMerkleRoot = hashMerkleRoot;
416423
block.nTime = nTime;
424+
block.block_height = block_height;
417425
block.nBits = nBits;
418426
block.nNonce = nNonce;
419427
return block.GetHash();

src/chainparams.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,11 @@ class CMainParams : public CChainParams {
125125

126126
genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN);
127127
consensus.hashGenesisBlock = genesis.GetHash();
128-
assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
128+
consensus.blockheight_in_header = gArgs.GetBoolArg("-con_blockheightinheader", false);
129+
// Serialization will not match if true
130+
if (!consensus.blockheight_in_header) {
131+
assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
132+
}
129133
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
130134

131135
// Note that of those which support the service bits prefix, most only support a subset of
@@ -234,7 +238,11 @@ class CTestNetParams : public CChainParams {
234238

235239
genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN);
236240
consensus.hashGenesisBlock = genesis.GetHash();
237-
assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
241+
consensus.blockheight_in_header = gArgs.GetBoolArg("-con_blockheightinheader", false);
242+
// Serialization will not match if true
243+
if (!consensus.blockheight_in_header) {
244+
assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
245+
}
238246
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
239247

240248
vFixedSeeds.clear();
@@ -325,7 +333,11 @@ class CRegTestParams : public CChainParams {
325333

326334
genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN);
327335
consensus.hashGenesisBlock = genesis.GetHash();
328-
assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
336+
consensus.blockheight_in_header = gArgs.GetBoolArg("-con_blockheightinheader", false);
337+
// Serialization will not match if true
338+
if (!consensus.blockheight_in_header) {
339+
assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
340+
}
329341
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
330342

331343
vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.
@@ -428,6 +440,10 @@ class CCustomParams : public CRegTestParams {
428440
consensus.nMinimumChainWork = uint256S(args.GetArg("-con_nminimumchainwork", "0x0"));
429441
consensus.defaultAssumeValid = uint256S(args.GetArg("-con_defaultassumevalid", "0x00"));
430442

443+
// Note: This gArg is accessed one more time in block.h for serialization to avoid
444+
// circular dependency
445+
consensus.blockheight_in_header = gArgs.GetBoolArg("-con_blockheightinheader", false);
446+
431447
// All non-zero coinbase outputs must go to this scriptPubKey
432448
std::vector<unsigned char> man_bytes = ParseHex(gArgs.GetArg("-con_mandatorycoinbase", ""));
433449
consensus.mandatory_coinbase_destination = CScript(man_bytes.begin(), man_bytes.end()); // Blank script allows any coinbase destination

src/chainparamsbase.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ void SetupChainParamsBaseOptions()
2525
gArgs.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest or custom only)", true, OptionsCategory::CHAINPARAMS);
2626
gArgs.AddArg("-con_mandatorycoinbase", "All non-zero valued coinbase outputs must go to this scriptPubKey, if set.", false, OptionsCategory::CHAINPARAMS);
2727
gArgs.AddArg("-seednode=<ip>", "Use specified node as seed node. This option can be specified multiple times to connect to multiple nodes. (custom only)", true, OptionsCategory::CHAINPARAMS);
28+
gArgs.AddArg("-con_blockheightinheader", "Whether the chain includes the block height directly in the header, for easier validation of block height in low-resource environments.", false, OptionsCategory::CHAINPARAMS);
2829
}
2930

3031
static std::unique_ptr<CBaseChainParams> globalChainBaseParams;

src/consensus/params.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ struct Params {
7878
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
7979
uint256 nMinimumChainWork;
8080
uint256 defaultAssumeValid;
81-
8281
// Elements-specific chainparams
8382
CScript mandatory_coinbase_destination;
83+
bool blockheight_in_header;
8484
};
8585
} // namespace Consensus
8686

src/miner.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
168168
// Fill in header
169169
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
170170
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
171+
if (Params().GetConsensus().blockheight_in_header) {
172+
pblock->block_height = nHeight;
173+
}
171174
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus());
172175
pblock->nNonce = 0;
173176
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);

src/primitives/block.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <primitives/transaction.h>
1010
#include <serialize.h>
1111
#include <uint256.h>
12+
#include <util.h>
1213

1314
/** Nodes collect new transactions into a block, hash them into a hash tree,
1415
* and scan through nonce values to make the block's hash satisfy proof-of-work
@@ -25,6 +26,9 @@ class CBlockHeader
2526
uint256 hashPrevBlock;
2627
uint256 hashMerkleRoot;
2728
uint32_t nTime;
29+
// Height in header as well as in coinbase for easier hsm validation
30+
// Is set for serialization with `-con_blockheightinheader=1`
31+
uint32_t block_height;
2832
uint32_t nBits;
2933
uint32_t nNonce;
3034

@@ -41,6 +45,10 @@ class CBlockHeader
4145
READWRITE(hashPrevBlock);
4246
READWRITE(hashMerkleRoot);
4347
READWRITE(nTime);
48+
// Also found in consensus params as blockheight_in_header (circular dep otherwise)
49+
if (gArgs.GetBoolArg("-con_blockheightinheader", false)) {
50+
READWRITE(block_height);
51+
}
4452
READWRITE(nBits);
4553
READWRITE(nNonce);
4654
}
@@ -51,6 +59,7 @@ class CBlockHeader
5159
hashPrevBlock.SetNull();
5260
hashMerkleRoot.SetNull();
5361
nTime = 0;
62+
block_height = 0;
5463
nBits = 0;
5564
nNonce = 0;
5665
}
@@ -111,6 +120,7 @@ class CBlock : public CBlockHeader
111120
block.hashPrevBlock = hashPrevBlock;
112121
block.hashMerkleRoot = hashMerkleRoot;
113122
block.nTime = nTime;
123+
block.block_height = block_height;
114124
block.nBits = nBits;
115125
block.nNonce = nNonce;
116126
return block;

src/validation.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3263,6 +3263,11 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
32633263
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
32643264
return state.Invalid(false, REJECT_INVALID, "time-too-old", "block's timestamp is too early");
32653265

3266+
// Check height in header against prev
3267+
if (consensusParams.blockheight_in_header && (uint32_t)nHeight != block.block_height)
3268+
return state.Invalid(error("%s: block height in header is incorrect", __func__),
3269+
REJECT_INVALID, "bad-header-height");
3270+
32663271
// Check timestamp
32673272
if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
32683273
return state.Invalid(false, REJECT_INVALID, "time-too-new", "block timestamp too far in the future");

0 commit comments

Comments
 (0)