Skip to content

Commit

Permalink
Merge bitcoin#429: [0.17] Connect gen block tx to db, don't validate …
Browse files Browse the repository at this point in the history
…gen block

d97920c add functional test for coinbase connection to db (Gregory Sanders)
e532664 allow grabbing genesis transaction(s) when connected (Gregory Sanders)
c7e5549 [bitcoin#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
  • Loading branch information
instagibbs committed Oct 25, 2018
2 parents 866da44 + d97920c commit c0d1dbc
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 9 deletions.
5 changes: 5 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class CMainParams : public CChainParams {
consensus.defaultAssumeValid = uint256S("0x0000000000000000002e63058c023a9a1de233554f28c7b21380b6c9003f36a8"); //534292

consensus.genesis_subsidy = 50*COIN;
consensus.connect_genesis_outputs = false;

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

consensus.genesis_subsidy = 50*COIN;
consensus.connect_genesis_outputs = false;

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

consensus.genesis_subsidy = 50*COIN;
consensus.connect_genesis_outputs = false;

pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
Expand Down Expand Up @@ -433,6 +436,8 @@ class CCustomParams : public CRegTestParams {
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

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

nPruneAfterHeight = (uint64_t)args.GetArg("-npruneafterheight", nPruneAfterHeight);
fDefaultConsistencyChecks = args.GetBoolArg("-fdefaultconsistencychecks", fDefaultConsistencyChecks);
Expand Down
1 change: 1 addition & 0 deletions src/chainparamsbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ void SetupChainParamsBaseOptions()
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_blocksubsidy", "Defines the amount of block subsidy to start with, at genesis block.", false, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-con_connect_coinbase", "Connect outputs in genesis block to utxo database.", false, OptionsCategory::CHAINPARAMS);
}

static std::unique_ptr<CBaseChainParams> globalChainBaseParams;
Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct Params {
// Elements-specific chainparams
CScript mandatory_coinbase_destination;
CAmount genesis_subsidy;
bool connect_genesis_outputs;
};
} // namespace Consensus

Expand Down
3 changes: 2 additions & 1 deletion src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
uint256 hash = ParseHashV(request.params[0], "parameter 1");
CBlockIndex* blockindex = nullptr;

if (hash == Params().GenesisBlock().hashMerkleRoot) {
if (!Params().GetConsensus().connect_genesis_outputs &&
hash == Params().GenesisBlock().hashMerkleRoot) {
// Special exception for the genesis block coinbase transaction
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved");
}
Expand Down
22 changes: 15 additions & 7 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1814,14 +1814,21 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
int64_t nTimeStart = GetTimeMicros();

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

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

Expand Down Expand Up @@ -3093,9 +3100,10 @@ static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos,
static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true)
{
// Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
if (fCheckPOW && block.GetHash() != consensusParams.hashGenesisBlock
&& !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) {
return state.DoS(50, false, REJECT_INVALID, "high-hash", false, "proof of work failed");

}
return true;
}

Expand Down
40 changes: 40 additions & 0 deletions test/functional/feature_connect_coinbase.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env python3
# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test connecting genesis coinbase"""

from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error

class ConnectGenesisTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
# First node doesn't connect coinbase output to db, second does
self.extra_args = [["-con_connect_coinbase=0"], ["-con_connect_coinbase=1"]]

def run_test(self):
# Same genesis block
assert_equal(self.nodes[0].getblockhash(0), self.nodes[1].getblockhash(0))

# Different UTXO set
node0_info = self.nodes[0].gettxoutsetinfo()
node1_info = self.nodes[1].gettxoutsetinfo()
print(node0_info)
print(node1_info)
assert_equal(node0_info["txouts"], 0)
assert_equal(node0_info["transactions"], 0)
assert_equal(node0_info["total_amount"], 0)
assert_equal(node1_info["txouts"], 1)
assert_equal(node1_info["transactions"], 1)
assert_equal(node1_info["total_amount"], 50)

coinbase_tx = self.nodes[0].getblock(self.nodes[0].getblockhash(0))["tx"][0]

# Test rpc getraw functionality
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)
self.nodes[1].getrawtransaction(coinbase_tx)

if __name__ == '__main__':
ConnectGenesisTest().main()
1 change: 1 addition & 0 deletions test/functional/test_framework/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ def initialize_datadir(dirname, n, chain):
f.write("listenonion=0\n")
f.write("printtoconsole=0\n")
f.write("con_blocksubsidy=5000000000\n")
f.write("con_connect_coinbase=0\n")
os.makedirs(os.path.join(datadir, 'stderr'), exist_ok=True)
os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
return datadir
Expand Down
4 changes: 3 additions & 1 deletion test/functional/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@
'feature_config_args.py',
'feature_help.py',
'feature_mandatory_coinbase.py',
'feature_block_subsidy.py'
'feature_block_subsidy.py',
'feature_connect_coinbase.py',
# Don't append tests at the end to avoid merge conflicts
# Put them in a random line within the section that fits their approximate run-time
]
Expand Down Expand Up @@ -183,6 +184,7 @@
'feature_notifications.py',
'rpc_invalidateblock.py',
'feature_rbf.py',
'feature_connect_coinbase.py'
]

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

0 comments on commit c0d1dbc

Please sign in to comment.