Skip to content

Commit 97b714f

Browse files
committed
blockheaders include block height, nodes validate it
1 parent de842cb commit 97b714f

File tree

7 files changed

+47
-3
lines changed

7 files changed

+47
-3
lines changed

src/chain.h

+8
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

+19-3
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,11 @@ class CMainParams : public CChainParams {
118118

119119
genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN);
120120
consensus.hashGenesisBlock = genesis.GetHash();
121-
assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
121+
consensus.blockheight_in_header = gArgs.GetBoolArg("-con_blockheightinheader", false);
122+
// Serialization will not match if true
123+
if (!consensus.blockheight_in_header) {
124+
assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
125+
}
122126
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
123127

124128
// Note that of those which support the service bits prefix, most only support a subset of
@@ -227,7 +231,11 @@ class CTestNetParams : public CChainParams {
227231

228232
genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN);
229233
consensus.hashGenesisBlock = genesis.GetHash();
230-
assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
234+
consensus.blockheight_in_header = gArgs.GetBoolArg("-con_blockheightinheader", false);
235+
// Serialization will not match if true
236+
if (!consensus.blockheight_in_header) {
237+
assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
238+
}
231239
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
232240

233241
vFixedSeeds.clear();
@@ -318,7 +326,11 @@ class CRegTestParams : public CChainParams {
318326

319327
genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN);
320328
consensus.hashGenesisBlock = genesis.GetHash();
321-
assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
329+
consensus.blockheight_in_header = gArgs.GetBoolArg("-con_blockheightinheader", false);
330+
// Serialization will not match if true
331+
if (!consensus.blockheight_in_header) {
332+
assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
333+
}
322334
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
323335

324336
vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.
@@ -420,6 +432,10 @@ class CCustomParams : public CRegTestParams {
420432
consensus.nMinimumChainWork = uint256S(args.GetArg("-con_nminimumchainwork", "0x0"));
421433
consensus.defaultAssumeValid = uint256S(args.GetArg("-con_defaultassumevalid", "0x00"));
422434

435+
// Note: This gArg is accessed one more time in block.h for serialization to avoid
436+
// circular dependency
437+
consensus.blockheight_in_header = gArgs.GetBoolArg("-con_blockheightinheader", false);
438+
423439
nPruneAfterHeight = (uint64_t)args.GetArg("-npruneafterheight", nPruneAfterHeight);
424440
fDefaultConsistencyChecks = args.GetBoolArg("-fdefaultconsistencychecks", fDefaultConsistencyChecks);
425441
fMineBlocksOnDemand = args.GetBoolArg("-fmineblocksondemand", fMineBlocksOnDemand);

src/chainparamsbase.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ void SetupChainParamsBaseOptions()
2323
gArgs.AddArg("-testnet", "Use the test chain", false, OptionsCategory::CHAINPARAMS);
2424
gArgs.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest or custom only)", true, OptionsCategory::CHAINPARAMS);
2525
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);
26+
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);
2627
}
2728

2829
static std::unique_ptr<CBaseChainParams> globalChainBaseParams;

src/consensus/params.h

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct Params {
7575
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
7676
uint256 nMinimumChainWork;
7777
uint256 defaultAssumeValid;
78+
bool blockheight_in_header;
7879
};
7980
} // namespace Consensus
8081

src/miner.cpp

+3
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

+10
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

+5
Original file line numberDiff line numberDiff line change
@@ -3252,6 +3252,11 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
32523252
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
32533253
return state.Invalid(false, REJECT_INVALID, "time-too-old", "block's timestamp is too early");
32543254

3255+
// Check height in header against prev
3256+
if (consensusParams.blockheight_in_header && (uint32_t)nHeight != block.block_height)
3257+
return state.Invalid(error("%s: block height in header is incorrect", __func__),
3258+
REJECT_INVALID, "bad-header-height");
3259+
32553260
// Check timestamp
32563261
if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
32573262
return state.Invalid(false, REJECT_INVALID, "time-too-new", "block timestamp too far in the future");

0 commit comments

Comments
 (0)