diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 503e86680b..b8604e155c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -105,6 +105,7 @@ public: 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. @@ -221,6 +222,7 @@ public: consensus.defaultAssumeValid = uint256S("0x0000000000000037a8cd3e06cd5edbfe9dd1dbcc5dacab279376ef7cfc2b4c75"); //1354312 consensus.genesis_subsidy = 50*COIN; + consensus.connect_genesis_outputs = false; pchMessageStart[0] = 0x0b; pchMessageStart[1] = 0x11; @@ -312,6 +314,7 @@ public: consensus.defaultAssumeValid = uint256S("0x00"); consensus.genesis_subsidy = 50*COIN; + consensus.connect_genesis_outputs = false; pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0xbf; @@ -433,6 +436,8 @@ class CCustomParams : public CRegTestParams { std::vector 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); diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 4fb9b05da0..8db4690b41 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -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=", "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 globalChainBaseParams; diff --git a/src/consensus/params.h b/src/consensus/params.h index e0018ca65b..7a217e755d 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -82,6 +82,7 @@ struct Params { // Elements-specific chainparams CScript mandatory_coinbase_destination; CAmount genesis_subsidy; + bool connect_genesis_outputs; }; } // namespace Consensus diff --git a/src/validation.cpp b/src/validation.cpp index 93adf5d503..f2b973c75e 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1813,18 +1813,6 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl assert(*pindex->phashBlock == block.GetHash()); 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(); - 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) - view.SetBestBlock(pindex->GetBlockHash()); - return true; - } - // Check it again in case a previous version let a bad block in // NOTE: We don't currently (re-)invoke ContextualCheckBlock() or // ContextualCheckBlockHeader() here. This means that if we add a new @@ -1848,6 +1836,25 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); } + // verify that the view's current state corresponds to the previous block + uint256 hashPrevBlock = pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash(); + assert(hashPrevBlock == view.GetBestBlock()); + + 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; + } + nBlocksTotal++; // Check that all non-zero coinbase outputs pay to the required destination diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 6240b0e716..e081aab825 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -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 diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 5fc7ae7cfe..d0f5731bfd 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -183,6 +183,7 @@ EXTENDED_SCRIPTS = [ '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