Skip to content

[0.17] MODIFIED: blockheaders include block height, nodes validate it #442

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ class CBlockIndex
int32_t nVersion;
uint256 hashMerkleRoot;
uint32_t nTime;
uint32_t block_height;
uint32_t nBits;
uint32_t nNonce;

Expand Down Expand Up @@ -238,6 +239,7 @@ class CBlockIndex
nVersion = 0;
hashMerkleRoot = uint256();
nTime = 0;
block_height = 0;
nBits = 0;
nNonce = 0;
}
Expand All @@ -254,6 +256,7 @@ class CBlockIndex
nVersion = block.nVersion;
hashMerkleRoot = block.hashMerkleRoot;
nTime = block.nTime;
block_height = block.block_height;
nBits = block.nBits;
nNonce = block.nNonce;
}
Expand Down Expand Up @@ -284,6 +287,7 @@ class CBlockIndex
block.hashPrevBlock = pprev->GetBlockHash();
block.hashMerkleRoot = hashMerkleRoot;
block.nTime = nTime;
block.block_height = block_height;
block.nBits = nBits;
block.nNonce = nNonce;
return block;
Expand Down Expand Up @@ -403,6 +407,9 @@ class CDiskBlockIndex : public CBlockIndex
READWRITE(hashPrev);
READWRITE(hashMerkleRoot);
READWRITE(nTime);
if (g_con_blockheightinheader) {
READWRITE(block_height);
}
READWRITE(nBits);
READWRITE(nNonce);
}
Expand All @@ -414,6 +421,7 @@ class CDiskBlockIndex : public CBlockIndex
block.hashPrevBlock = hashPrev;
block.hashMerkleRoot = hashMerkleRoot;
block.nTime = nTime;
block.block_height = block_height;
block.nBits = nBits;
block.nNonce = nNonce;
return block.GetHash();
Expand Down
38 changes: 34 additions & 4 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <consensus/merkle.h>

#include <chainparamsseeds.h>
#include <consensus/merkle.h>
#include <hash.h>
#include <tinyformat.h>
#include <util.h>
#include <utilstrencodings.h>
Expand All @@ -17,13 +18,13 @@
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>

static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
static CBlock CreateGenesisBlock(const CScript& coinbase_sig, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
CMutableTransaction txNew;
txNew.nVersion = 1;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
txNew.vin[0].scriptSig = coinbase_sig;
txNew.vout[0].nValue = genesisReward;
txNew.vout[0].scriptPubKey = genesisOutputScript;

Expand All @@ -38,6 +39,12 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi
return genesis;
}

static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
CScript coinbase_sig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
return CreateGenesisBlock(coinbase_sig, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
}

/**
* Build the genesis block. Note that the output of its generation
* transaction cannot be spent since it did not originally exist in the
Expand Down Expand Up @@ -403,6 +410,7 @@ class CCustomParams : public CRegTestParams {
{
UpdateVersionBitsParametersFromArgs(args);

consensus.genesis_style = args.GetArg("-con_genesis_style", "default_style");
consensus.nSubsidyHalvingInterval = args.GetArg("-con_nsubsidyhalvinginterval", consensus.nSubsidyHalvingInterval);
consensus.BIP16Exception = uint256S(args.GetArg("-con_bip16exception", "0x0"));
consensus.BIP34Height = args.GetArg("-con_bip34height", consensus.BIP34Height);
Expand All @@ -420,6 +428,10 @@ class CCustomParams : public CRegTestParams {
consensus.nMinimumChainWork = uint256S(args.GetArg("-con_nminimumchainwork", "0x0"));
consensus.defaultAssumeValid = uint256S(args.GetArg("-con_defaultassumevalid", "0x00"));

// Note: g_con_blockheightinheader is used instead of consensus.blockheight_in_header to avoid
// circular dependency
consensus.blockheight_in_header = g_con_blockheightinheader = gArgs.GetBoolArg("-con_blockheightinheader", false);

// All non-zero coinbase outputs must go to this scriptPubKey
std::vector<unsigned char> man_bytes = ParseHex(gArgs.GetArg("-con_mandatorycoinbase", ""));
consensus.mandatory_coinbase_destination = CScript(man_bytes.begin(), man_bytes.end()); // Blank script allows any coinbase destination
Expand Down Expand Up @@ -457,12 +469,30 @@ class CCustomParams : public CRegTestParams {
}
}

void SetGenesisBlock()
{
if (consensus.genesis_style == "regtest2_style") {
// Same style as in https://github.com/bitcoin/bitcoin/pull/8994
genesis = CreateGenesisBlock(strNetworkID.c_str(), CScript(OP_TRUE), 1296688602, 2, 0x207fffff, 1, 50 * COIN);

} else if (consensus.genesis_style == "default_style") {
CHashWriter h(SER_DISK, 0);
h << strNetworkID;
uint256 hash = h.GetHash();
CScript coinbase_sig = CScript() << std::vector<uint8_t>(hash.begin(), hash.end());
genesis = CreateGenesisBlock(coinbase_sig, CScript(OP_TRUE), 1296688602, 2, 0x207fffff, 1, 50 * COIN);

} else {
throw std::runtime_error(strprintf("%s: Unknown consensus.genesis_style %s.", __func__, consensus.genesis_style));
}
}

public:
CCustomParams(const std::string& chain, ArgsManager& args) : CRegTestParams(args)
{
strNetworkID = chain;
UpdateFromArgs(args);
genesis = CreateGenesisBlock(strNetworkID.c_str(), CScript(OP_TRUE), 1296688602, 2, 0x207fffff, 1, 50 * COIN);
SetGenesisBlock();
consensus.hashGenesisBlock = genesis.GetHash();
}
};
Expand Down
2 changes: 2 additions & 0 deletions src/chainparamsbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ void SetupChainParamsBaseOptions()
gArgs.AddArg("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
"This is intended for regression testing tools and app development.", true, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-testnet", "Use the test chain", false, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-con_genesis_style=<style>", "Use genesis style <style> (default: default_style). Allowed values: default_style, regtest2_style", true, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest or custom only)", true, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-con_mandatorycoinbase", "All non-zero valued coinbase outputs must go to this scriptPubKey, if set.", false, OptionsCategory::CHAINPARAMS);
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);
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);
}

static std::unique_ptr<CBaseChainParams> globalChainBaseParams;
Expand Down
2 changes: 2 additions & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct BIP9Deployment {
* Parameters that influence chain consensus.
*/
struct Params {
std::string genesis_style;
uint256 hashGenesisBlock;
int nSubsidyHalvingInterval;
/* Block hash that is excepted from BIP16 enforcement */
Expand Down Expand Up @@ -80,6 +81,7 @@ struct Params {

// Elements-specific chainparams
CScript mandatory_coinbase_destination;
bool blockheight_in_header;
};
} // namespace Consensus

Expand Down
3 changes: 3 additions & 0 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
if (g_con_blockheightinheader) {
pblock->block_height = nHeight;
}
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus());
pblock->nNonce = 0;
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
Expand Down
2 changes: 2 additions & 0 deletions src/primitives/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <utilstrencodings.h>
#include <crypto/common.h>

bool g_con_blockheightinheader = false;

uint256 CBlockHeader::GetHash() const
{
return SerializeHash(*this);
Expand Down
13 changes: 13 additions & 0 deletions src/primitives/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
#include <serialize.h>
#include <uint256.h>

/**
* Also found in consensus params as blockheight_in_header (circular dep otherwise)
*/
extern bool g_con_blockheightinheader;

/** Nodes collect new transactions into a block, hash them into a hash tree,
* and scan through nonce values to make the block's hash satisfy proof-of-work
* requirements. When they solve the proof-of-work, they broadcast the block
Expand All @@ -25,6 +30,9 @@ class CBlockHeader
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
uint32_t nTime;
// Height in header as well as in coinbase for easier hsm validation
// Is set for serialization with `-con_blockheightinheader=1`
uint32_t block_height;
uint32_t nBits;
uint32_t nNonce;

Expand All @@ -41,6 +49,9 @@ class CBlockHeader
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
READWRITE(nTime);
if (g_con_blockheightinheader) {
READWRITE(block_height);
}
READWRITE(nBits);
READWRITE(nNonce);
}
Expand All @@ -51,6 +62,7 @@ class CBlockHeader
hashPrevBlock.SetNull();
hashMerkleRoot.SetNull();
nTime = 0;
block_height = 0;
nBits = 0;
nNonce = 0;
}
Expand Down Expand Up @@ -111,6 +123,7 @@ class CBlock : public CBlockHeader
block.hashPrevBlock = hashPrevBlock;
block.hashMerkleRoot = hashMerkleRoot;
block.nTime = nTime;
block.block_height = block_height;
block.nBits = nBits;
block.nNonce = nNonce;
return block;
Expand Down
5 changes: 5 additions & 0 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3263,6 +3263,11 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
return state.Invalid(false, REJECT_INVALID, "time-too-old", "block's timestamp is too early");

// Check height in header against prev
if (g_con_blockheightinheader && (uint32_t)nHeight != block.block_height)
return state.Invalid(error("%s: block height in header is incorrect", __func__),
REJECT_INVALID, "bad-header-height");

// Check timestamp
if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
return state.Invalid(false, REJECT_INVALID, "time-too-new", "block timestamp too far in the future");
Expand Down
Loading