Skip to content

Commit 2d03a07

Browse files
Allow genesis output to be spent
1 parent a360280 commit 2d03a07

File tree

3 files changed

+18
-17
lines changed

3 files changed

+18
-17
lines changed

src/rpc/rawtransaction.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,9 @@ static RPCHelpMan getrawtransaction()
324324

325325
if (hash == chainman.GetParams().GenesisBlock().hashMerkleRoot) {
326326
// Special exception for the genesis block coinbase transaction
327-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved");
327+
//throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved");
328+
LOCK(cs_main);
329+
blockindex = chainman.m_blockman.LookupBlockIndex(chainman.GetParams().GetConsensus().hashGenesisBlock);
328330
}
329331

330332
int verbosity{ParseVerbosity(request.params[1], /*default_verbosity=*/0, /*allow_bool=*/true)};

src/test/coins_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
using namespace util::hex_literals;
2525

26-
int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out);
26+
int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out, const uint256& genesisTxid = uint256::ZERO);
2727
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight);
2828

2929
namespace

src/validation.cpp

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2259,15 +2259,17 @@ bool FatalError(Notifications& notifications, BlockValidationState& state, const
22592259
* @param undo The Coin to be restored.
22602260
* @param view The coins view to which to apply the changes.
22612261
* @param out The out point that corresponds to the tx input.
2262+
* @param genesisTxid The genesis coinbase transaction id which lacks undo metadata.
22622263
* @return A DisconnectResult as an int
22632264
*/
2264-
int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
2265+
int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out, const uint256& genesisTxid = uint256::ZERO)
22652266
{
22662267
bool fClean = true;
22672268

22682269
if (view.HaveCoin(out)) fClean = false; // overwriting transaction output
22692270

2270-
if (undo.nHeight == 0) {
2271+
// We have to exclude the genesis coinbase from this check because its height actually is zero and the wallet will think there is database corruption otherwise
2272+
if (undo.nHeight == 0 && out.hash != genesisTxid) {
22712273
// Missing undo metadata (height and coinbase). Older versions included this
22722274
// information only in undo records for the last spend of a transactions'
22732275
// outputs. This implies that it must be present for some other output of the same tx.
@@ -2348,7 +2350,7 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn
23482350
for (unsigned int j = tx.vin.size(); j > 0;) {
23492351
--j;
23502352
const COutPoint& out = tx.vin[j].prevout;
2351-
int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out);
2353+
int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out, m_chainman.GetParams().GenesisBlock().hashMerkleRoot);
23522354
if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED;
23532355
fClean = fClean && res != DISCONNECT_UNCLEAN;
23542356
}
@@ -2476,14 +2478,6 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
24762478

24772479
m_chainman.num_blocks_total++;
24782480

2479-
// Special case for the genesis block, skipping connection of its transactions
2480-
// (its coinbase is unspendable)
2481-
if (block_hash == params.GetConsensus().hashGenesisBlock) {
2482-
if (!fJustCheck)
2483-
view.SetBestBlock(pindex->GetBlockHash());
2484-
return true;
2485-
}
2486-
24872481
bool fScriptChecks = true;
24882482
if (!m_chainman.AssumedValidBlock().IsNull()) {
24892483
// We've been configured with the hash of a block which has been externally verified to have a valid history.
@@ -2560,7 +2554,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
25602554
// future consensus change to do a new and improved version of BIP34 that
25612555
// will actually prevent ever creating any duplicate coinbases in the
25622556
// future.
2563-
static constexpr int BIP34_IMPLIES_BIP30_LIMIT = 1983702;
2557+
static constexpr int BIP34_IMPLIES_BIP30_LIMIT = std::numeric_limits<int>::max();
25642558

25652559
// There is no potential to create a duplicate coinbase at block 209,921
25662560
// because this is still before the BIP34 height and so explicit BIP30
@@ -2589,8 +2583,13 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
25892583
// testnet3 has no blocks before the BIP34 height with indicated heights
25902584
// post BIP34 before approximately height 486,000,000. After block
25912585
// 1,983,702 testnet3 starts doing unnecessary BIP30 checking again.
2592-
assert(pindex->pprev);
2593-
CBlockIndex* pindexBIP34height = pindex->pprev->GetAncestor(params.GetConsensus().BIP34Height);
2586+
CBlockIndex* pindexBIP34height = nullptr;
2587+
if (pindex->GetBlockHash() != params.GetConsensus().hashGenesisBlock) {
2588+
assert(pindex->pprev);
2589+
pindexBIP34height = pindex->pprev->GetAncestor(params.GetConsensus().BIP34Height);
2590+
} else {
2591+
fEnforceBIP30 = false;
2592+
}
25942593
//Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond.
25952594
fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == params.GetConsensus().BIP34Hash));
25962595

@@ -2743,7 +2742,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
27432742
return true;
27442743
}
27452744

2746-
if (!m_blockman.WriteBlockUndo(blockundo, state, *pindex)) {
2745+
if (pindex->GetBlockHash() != params.GetConsensus().hashGenesisBlock && !m_blockman.WriteBlockUndo(blockundo, state, *pindex)) {
27472746
return false;
27482747
}
27492748

0 commit comments

Comments
 (0)