Skip to content

Commit 8a472b9

Browse files
committed
Merge #431: [0.17] blockheaders include block height, nodes validate it
2bfabb3 blockheaders include block height, nodes validate it (Gregory Sanders) 8f6bedf functional framework support for CScriptNum decode (Gregory Sanders) Pull request description: The feature is enabled by default in custom chains; cannot be activated in legacy chains. Tree-SHA512: d033b7dd0d853e5693efda584494cf58ed7ff43ce32d1f5d44e4ee52907b989e434c8dbb28a0f843da8b799548924d2499e8759a96ed5a7191b95f22b29c7f6e
2 parents 823b909 + 2bfabb3 commit 8a472b9

24 files changed

+200
-132
lines changed

src/chain.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ class CBlockIndex
210210
int32_t nVersion;
211211
uint256 hashMerkleRoot;
212212
uint32_t nTime;
213+
uint32_t block_height;
213214
uint32_t nBits;
214215
uint32_t nNonce;
215216

@@ -238,6 +239,7 @@ class CBlockIndex
238239
nVersion = 0;
239240
hashMerkleRoot = uint256();
240241
nTime = 0;
242+
block_height = 0;
241243
nBits = 0;
242244
nNonce = 0;
243245
}
@@ -254,6 +256,7 @@ class CBlockIndex
254256
nVersion = block.nVersion;
255257
hashMerkleRoot = block.hashMerkleRoot;
256258
nTime = block.nTime;
259+
block_height = block.block_height;
257260
nBits = block.nBits;
258261
nNonce = block.nNonce;
259262
}
@@ -284,6 +287,7 @@ class CBlockIndex
284287
block.hashPrevBlock = pprev->GetBlockHash();
285288
block.hashMerkleRoot = hashMerkleRoot;
286289
block.nTime = nTime;
290+
block.block_height = block_height;
287291
block.nBits = nBits;
288292
block.nNonce = nNonce;
289293
return block;
@@ -403,6 +407,7 @@ class CDiskBlockIndex : public CBlockIndex
403407
READWRITE(hashPrev);
404408
READWRITE(hashMerkleRoot);
405409
READWRITE(nTime);
410+
READWRITE(block_height);
406411
READWRITE(nBits);
407412
READWRITE(nNonce);
408413
}
@@ -414,6 +419,7 @@ class CDiskBlockIndex : public CBlockIndex
414419
block.hashPrevBlock = hashPrev;
415420
block.hashMerkleRoot = hashMerkleRoot;
416421
block.nTime = nTime;
422+
block.block_height = block_height;
417423
block.nBits = nBits;
418424
block.nNonce = nNonce;
419425
return block.GetHash();

src/chainparams.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,10 @@ class CCustomParams : public CRegTestParams {
435435
// No subsidy for custom chains by default
436436
consensus.genesis_subsidy = args.GetArg("-con_blocksubsidy", 0);
437437

438+
// Note: This global is needed to avoid circular dependency
439+
// Defaults to true for custom chains.
440+
g_con_blockheightinheader = gArgs.GetBoolArg("-con_blockheightinheader", true);
441+
438442
// All non-zero coinbase outputs must go to this scriptPubKey
439443
std::vector<unsigned char> man_bytes = ParseHex(gArgs.GetArg("-con_mandatorycoinbase", ""));
440444
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
@@ -26,6 +26,7 @@ void SetupChainParamsBaseOptions()
2626
gArgs.AddArg("-con_mandatorycoinbase", "All non-zero valued coinbase outputs must go to this scriptPubKey, if set.", false, OptionsCategory::ELEMENTS);
2727
gArgs.AddArg("-con_blocksubsidy", "Defines the amount of block subsidy to start with, at genesis block.", false, OptionsCategory::ELEMENTS);
2828
gArgs.AddArg("-con_connect_coinbase", "Connect outputs in genesis block to utxo database.", false, OptionsCategory::ELEMENTS);
29+
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. (default: true)", false, OptionsCategory::CHAINPARAMS);
2930
}
3031

3132
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,11 +78,11 @@ 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;
8483
CAmount genesis_subsidy;
8584
bool connect_genesis_outputs;
85+
// g_con_blockheightinheader global hack instead of proper arg due to circular dep
8686
};
8787
} // namespace Consensus
8888

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 (g_con_blockheightinheader) {
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.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <utilstrencodings.h>
1111
#include <crypto/common.h>
1212

13+
bool g_con_blockheightinheader = false;
14+
1315
uint256 CBlockHeader::GetHash() const
1416
{
1517
return SerializeHash(*this);

src/primitives/block.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <serialize.h>
1111
#include <uint256.h>
1212

13+
extern bool g_con_blockheightinheader;
14+
1315
/** Nodes collect new transactions into a block, hash them into a hash tree,
1416
* and scan through nonce values to make the block's hash satisfy proof-of-work
1517
* requirements. When they solve the proof-of-work, they broadcast the block
@@ -25,6 +27,9 @@ class CBlockHeader
2527
uint256 hashPrevBlock;
2628
uint256 hashMerkleRoot;
2729
uint32_t nTime;
30+
// Height in header as well as in coinbase for easier hsm validation
31+
// Is set for serialization with `-con_blockheightinheader=1`
32+
uint32_t block_height;
2833
uint32_t nBits;
2934
uint32_t nNonce;
3035

@@ -41,6 +46,9 @@ class CBlockHeader
4146
READWRITE(hashPrevBlock);
4247
READWRITE(hashMerkleRoot);
4348
READWRITE(nTime);
49+
if (g_con_blockheightinheader) {
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/txdb.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
263263
CBlockIndex* pindexNew = insertBlockIndex(diskindex.GetBlockHash());
264264
pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
265265
pindexNew->nHeight = diskindex.nHeight;
266+
pindexNew->block_height = diskindex.block_height;
266267
pindexNew->nFile = diskindex.nFile;
267268
pindexNew->nDataPos = diskindex.nDataPos;
268269
pindexNew->nUndoPos = diskindex.nUndoPos;

src/validation.cpp

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

3274+
// Check height in header against prev
3275+
if (g_con_blockheightinheader && (uint32_t)nHeight != block.block_height)
3276+
return state.Invalid(error("%s: block height in header is incorrect", __func__),
3277+
REJECT_INVALID, "bad-header-height");
3278+
32743279
// Check timestamp
32753280
if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
32763281
return state.Invalid(false, REJECT_INVALID, "time-too-new", "block timestamp too far in the future");

test/bitcoin_functional/functional/test_framework/util.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ def initialize_datadir(dirname, n, chain):
308308
f.write("con_blocksubsidy=5000000000\n")
309309
f.write("con_connect_coinbase=0\n")
310310
f.write("anyonecanspendaremine=0\n")
311+
f.write("con_blockheightinheader=0\n")
311312
os.makedirs(os.path.join(datadir, 'stderr'), exist_ok=True)
312313
os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
313314
return datadir

0 commit comments

Comments
 (0)