Skip to content

Commit c0d1dbc

Browse files
committed
Merge #429: [0.17] Connect gen block tx to db, don't validate gen block
d97920c add functional test for coinbase connection to db (Gregory Sanders) e532664 allow grabbing genesis transaction(s) when connected (Gregory Sanders) c7e5549 [#9102] really don't validate genesis block (Gregory Sanders) ccf40db connect genesis block transaction outputs to coin db (Gregory Sanders) Pull request description: Tests should now be working. Tree-SHA512: aa2af6637c534d7f9185e969118b52519fe0609ae79fa8f4d5213f939f9a5915f958cf93d02aa6f4a47795c87cc23c93daff3807347cb1b12a426326e6dea60e
2 parents 866da44 + d97920c commit c0d1dbc

File tree

8 files changed

+68
-9
lines changed

8 files changed

+68
-9
lines changed

src/chainparams.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class CMainParams : public CChainParams {
105105
consensus.defaultAssumeValid = uint256S("0x0000000000000000002e63058c023a9a1de233554f28c7b21380b6c9003f36a8"); //534292
106106

107107
consensus.genesis_subsidy = 50*COIN;
108+
consensus.connect_genesis_outputs = false;
108109

109110
/**
110111
* The message start string is designed to be unlikely to occur in normal data.
@@ -221,6 +222,7 @@ class CTestNetParams : public CChainParams {
221222
consensus.defaultAssumeValid = uint256S("0x0000000000000037a8cd3e06cd5edbfe9dd1dbcc5dacab279376ef7cfc2b4c75"); //1354312
222223

223224
consensus.genesis_subsidy = 50*COIN;
225+
consensus.connect_genesis_outputs = false;
224226

225227
pchMessageStart[0] = 0x0b;
226228
pchMessageStart[1] = 0x11;
@@ -312,6 +314,7 @@ class CRegTestParams : public CChainParams {
312314
consensus.defaultAssumeValid = uint256S("0x00");
313315

314316
consensus.genesis_subsidy = 50*COIN;
317+
consensus.connect_genesis_outputs = false;
315318

316319
pchMessageStart[0] = 0xfa;
317320
pchMessageStart[1] = 0xbf;
@@ -433,6 +436,8 @@ class CCustomParams : public CRegTestParams {
433436
std::vector<unsigned char> man_bytes = ParseHex(gArgs.GetArg("-con_mandatorycoinbase", ""));
434437
consensus.mandatory_coinbase_destination = CScript(man_bytes.begin(), man_bytes.end()); // Blank script allows any coinbase destination
435438

439+
// Custom chains connect coinbase outputs to db by default
440+
consensus.connect_genesis_outputs = gArgs.GetArg("-con_connect_coinbase", true);
436441

437442
nPruneAfterHeight = (uint64_t)args.GetArg("-npruneafterheight", nPruneAfterHeight);
438443
fDefaultConsistencyChecks = args.GetBoolArg("-fdefaultconsistencychecks", fDefaultConsistencyChecks);

src/chainparamsbase.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ void SetupChainParamsBaseOptions()
2525
gArgs.AddArg("-con_mandatorycoinbase", "All non-zero valued coinbase outputs must go to this scriptPubKey, if set.", false, OptionsCategory::CHAINPARAMS);
2626
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);
2727
gArgs.AddArg("-con_blocksubsidy", "Defines the amount of block subsidy to start with, at genesis block.", false, OptionsCategory::CHAINPARAMS);
28+
gArgs.AddArg("-con_connect_coinbase", "Connect outputs in genesis block to utxo database.", false, OptionsCategory::CHAINPARAMS);
2829
}
2930

3031
static std::unique_ptr<CBaseChainParams> globalChainBaseParams;

src/consensus/params.h

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ struct Params {
8282
// Elements-specific chainparams
8383
CScript mandatory_coinbase_destination;
8484
CAmount genesis_subsidy;
85+
bool connect_genesis_outputs;
8586
};
8687
} // namespace Consensus
8788

src/rpc/rawtransaction.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
147147
uint256 hash = ParseHashV(request.params[0], "parameter 1");
148148
CBlockIndex* blockindex = nullptr;
149149

150-
if (hash == Params().GenesisBlock().hashMerkleRoot) {
150+
if (!Params().GetConsensus().connect_genesis_outputs &&
151+
hash == Params().GenesisBlock().hashMerkleRoot) {
151152
// Special exception for the genesis block coinbase transaction
152153
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved");
153154
}

src/validation.cpp

+15-7
Original file line numberDiff line numberDiff line change
@@ -1814,14 +1814,21 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
18141814
int64_t nTimeStart = GetTimeMicros();
18151815

18161816
// verify that the view's current state corresponds to the previous block
1817-
const uint256 hashPrevBlock = pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash();
1817+
uint256 hashPrevBlock = pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash();
18181818
assert(hashPrevBlock == view.GetBestBlock());
18191819

1820-
// Special case for the genesis block, skipping connection of its transactions
1821-
// (its coinbase is unspendable)
1822-
if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) {
1823-
if (!fJustCheck)
1820+
const Consensus::Params& consensusParams = chainparams.GetConsensus();
1821+
// Add genesis outputs but don't validate.
1822+
if (block.GetHash() == consensusParams.hashGenesisBlock) {
1823+
if (!fJustCheck) {
1824+
if (consensusParams.connect_genesis_outputs) {
1825+
for (const auto& tx : block.vtx) {
1826+
// Directly add new coins to DB
1827+
AddCoins(view, *tx, 0);
1828+
}
1829+
}
18241830
view.SetBestBlock(pindex->GetBlockHash());
1831+
}
18251832
return true;
18261833
}
18271834

@@ -3093,9 +3100,10 @@ static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos,
30933100
static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true)
30943101
{
30953102
// Check proof of work matches claimed amount
3096-
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
3103+
if (fCheckPOW && block.GetHash() != consensusParams.hashGenesisBlock
3104+
&& !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) {
30973105
return state.DoS(50, false, REJECT_INVALID, "high-hash", false, "proof of work failed");
3098-
3106+
}
30993107
return true;
31003108
}
31013109

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2014-2018 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""Test connecting genesis coinbase"""
6+
7+
from test_framework.test_framework import BitcoinTestFramework
8+
from test_framework.util import assert_equal, assert_raises_rpc_error
9+
10+
class ConnectGenesisTest(BitcoinTestFramework):
11+
def set_test_params(self):
12+
self.num_nodes = 2
13+
self.setup_clean_chain = True
14+
# First node doesn't connect coinbase output to db, second does
15+
self.extra_args = [["-con_connect_coinbase=0"], ["-con_connect_coinbase=1"]]
16+
17+
def run_test(self):
18+
# Same genesis block
19+
assert_equal(self.nodes[0].getblockhash(0), self.nodes[1].getblockhash(0))
20+
21+
# Different UTXO set
22+
node0_info = self.nodes[0].gettxoutsetinfo()
23+
node1_info = self.nodes[1].gettxoutsetinfo()
24+
print(node0_info)
25+
print(node1_info)
26+
assert_equal(node0_info["txouts"], 0)
27+
assert_equal(node0_info["transactions"], 0)
28+
assert_equal(node0_info["total_amount"], 0)
29+
assert_equal(node1_info["txouts"], 1)
30+
assert_equal(node1_info["transactions"], 1)
31+
assert_equal(node1_info["total_amount"], 50)
32+
33+
coinbase_tx = self.nodes[0].getblock(self.nodes[0].getblockhash(0))["tx"][0]
34+
35+
# Test rpc getraw functionality
36+
assert_raises_rpc_error(-5, "The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved", self.nodes[0].getrawtransaction, coinbase_tx)
37+
self.nodes[1].getrawtransaction(coinbase_tx)
38+
39+
if __name__ == '__main__':
40+
ConnectGenesisTest().main()

test/functional/test_framework/util.py

+1
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ def initialize_datadir(dirname, n, chain):
306306
f.write("listenonion=0\n")
307307
f.write("printtoconsole=0\n")
308308
f.write("con_blocksubsidy=5000000000\n")
309+
f.write("con_connect_coinbase=0\n")
309310
os.makedirs(os.path.join(datadir, 'stderr'), exist_ok=True)
310311
os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
311312
return datadir

test/functional/test_runner.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@
154154
'feature_config_args.py',
155155
'feature_help.py',
156156
'feature_mandatory_coinbase.py',
157-
'feature_block_subsidy.py'
157+
'feature_block_subsidy.py',
158+
'feature_connect_coinbase.py',
158159
# Don't append tests at the end to avoid merge conflicts
159160
# Put them in a random line within the section that fits their approximate run-time
160161
]
@@ -183,6 +184,7 @@
183184
'feature_notifications.py',
184185
'rpc_invalidateblock.py',
185186
'feature_rbf.py',
187+
'feature_connect_coinbase.py'
186188
]
187189

188190
# Place EXTENDED_SCRIPTS first since it has the 3 longest running tests

0 commit comments

Comments
 (0)