Merge bitcoin/bitcoin#24732: Remove buggy and confusing IncrementExtraNonce

cccc4e879a8cb9d858a88ea46b28ea27ab79ca55 Remove nHeightEnd and nHeight in generateBlocks helper (MarcoFalke)
fa38b1c8bd29e2c792737f6481ab928e46396b7e Remove buggy and confusing IncrementExtraNonce (MarcoFalke)

Pull request description:

  IncrementExtraNonce has many issues:

  * It is test-only code, but part of bitcoind
  * It is using the block height of the tip, as opposed to the block's previous block as reference for the new height. See https://github.com/bitcoin/bitcoin/issues/24730#issuecomment-1085586193
  * It has no use case in regtest testing. With a low difficulty the extra nonce won't be incremented. With a high difficulty the test-only functions are clumsy to handle anyway. For example, the generate* RPCs will return an empty array once they reached `maxtries`, as opposed to an error. Also the calls can't be aborted early unless the node shuts down completely. So I think it is fine to just remove the extra nonce functionality and leave it to the outside to implement, if needed. For example, a wrapper script can call the `generate*` RPCs once every second, to use the timestamp as extra nonce.

ACKs for top commit:
  ajtowns:
    ACK cccc4e879a8cb9d858a88ea46b28ea27ab79ca55

Tree-SHA512: d8a3989ad280ebd4b1b574159b3a396b8a42134347e6be3c88445162d86624d221c416456f45ae75aea62ed8c8a1a9bb3a2532924abca2ef7a879cb8e6b15654
This commit is contained in:
MarcoFalke 2022-04-06 11:12:05 +02:00
commit 79bf1a0fa2
No known key found for this signature in database
GPG Key ID: CE2B75697E69A548
7 changed files with 24 additions and 56 deletions

View File

@ -430,22 +430,4 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
nDescendantsUpdated += UpdatePackagesForAdded(ancestors, mapModifiedTx); nDescendantsUpdated += UpdatePackagesForAdded(ancestors, mapModifiedTx);
} }
} }
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
{
// Update nExtraNonce
static uint256 hashPrevBlock;
if (hashPrevBlock != pblock->hashPrevBlock) {
nExtraNonce = 0;
hashPrevBlock = pblock->hashPrevBlock;
}
++nExtraNonce;
unsigned int nHeight = pindexPrev->nHeight + 1; // Height first in coinbase required for block.version=2
CMutableTransaction txCoinbase(*pblock->vtx[0]);
txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce));
assert(txCoinbase.vin[0].scriptSig.size() <= 100);
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
}
} // namespace node } // namespace node

View File

@ -200,8 +200,6 @@ private:
int UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded, indexed_modified_transaction_set& mapModifiedTx) EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs); int UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded, indexed_modified_transaction_set& mapModifiedTx) EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs);
}; };
/** Modify the extranonce in a block */
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
/** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */ /** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */

View File

@ -7,6 +7,7 @@
#include <chainparams.h> #include <chainparams.h>
#include <consensus/amount.h> #include <consensus/amount.h>
#include <consensus/consensus.h> #include <consensus/consensus.h>
#include <consensus/merkle.h>
#include <consensus/params.h> #include <consensus/params.h>
#include <consensus/validation.h> #include <consensus/validation.h>
#include <core_io.h> #include <core_io.h>
@ -43,7 +44,6 @@
using node::BlockAssembler; using node::BlockAssembler;
using node::CBlockTemplate; using node::CBlockTemplate;
using node::IncrementExtraNonce;
using node::NodeContext; using node::NodeContext;
using node::RegenerateCommitments; using node::RegenerateCommitments;
using node::UpdateTime; using node::UpdateTime;
@ -116,14 +116,10 @@ static RPCHelpMan getnetworkhashps()
}; };
} }
static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& max_tries, unsigned int& extra_nonce, uint256& block_hash) static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& max_tries, uint256& block_hash)
{ {
block_hash.SetNull(); block_hash.SetNull();
block.hashMerkleRoot = BlockMerkleRoot(block);
{
LOCK(cs_main);
IncrementExtraNonce(&block, chainman.ActiveChain().Tip(), extra_nonce);
}
CChainParams chainparams(Params()); CChainParams chainparams(Params());
@ -149,30 +145,20 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t&
static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& mempool, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries) static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& mempool, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries)
{ {
int nHeightEnd = 0;
int nHeight = 0;
{ // Don't keep cs_main locked
LOCK(cs_main);
nHeight = chainman.ActiveChain().Height();
nHeightEnd = nHeight+nGenerate;
}
unsigned int nExtraNonce = 0;
UniValue blockHashes(UniValue::VARR); UniValue blockHashes(UniValue::VARR);
while (nHeight < nHeightEnd && !ShutdownRequested()) while (nGenerate > 0 && !ShutdownRequested()) {
{
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(chainman.ActiveChainstate(), mempool, Params()).CreateNewBlock(coinbase_script)); std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(chainman.ActiveChainstate(), mempool, Params()).CreateNewBlock(coinbase_script));
if (!pblocktemplate.get()) if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block; CBlock *pblock = &pblocktemplate->block;
uint256 block_hash; uint256 block_hash;
if (!GenerateBlock(chainman, *pblock, nMaxTries, nExtraNonce, block_hash)) { if (!GenerateBlock(chainman, *pblock, nMaxTries, block_hash)) {
break; break;
} }
if (!block_hash.IsNull()) { if (!block_hash.IsNull()) {
++nHeight; --nGenerate;
blockHashes.push_back(block_hash.GetHex()); blockHashes.push_back(block_hash.GetHex());
} }
} }
@ -397,9 +383,8 @@ static RPCHelpMan generateblock()
uint256 block_hash; uint256 block_hash;
uint64_t max_tries{DEFAULT_MAX_TRIES}; uint64_t max_tries{DEFAULT_MAX_TRIES};
unsigned int extra_nonce{0};
if (!GenerateBlock(chainman, block, max_tries, extra_nonce, block_hash) || block_hash.IsNull()) { if (!GenerateBlock(chainman, block, max_tries, block_hash) || block_hash.IsNull()) {
throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block."); throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
} }

View File

@ -4,6 +4,7 @@
#include <blockfilter.h> #include <blockfilter.h>
#include <chainparams.h> #include <chainparams.h>
#include <consensus/merkle.h>
#include <consensus/validation.h> #include <consensus/validation.h>
#include <index/blockfilterindex.h> #include <index/blockfilterindex.h>
#include <node/miner.h> #include <node/miner.h>
@ -18,7 +19,6 @@
using node::BlockAssembler; using node::BlockAssembler;
using node::CBlockTemplate; using node::CBlockTemplate;
using node::IncrementExtraNonce;
BOOST_AUTO_TEST_SUITE(blockfilter_index_tests) BOOST_AUTO_TEST_SUITE(blockfilter_index_tests)
@ -76,9 +76,12 @@ CBlock BuildChainTestingSetup::CreateBlock(const CBlockIndex* prev,
for (const CMutableTransaction& tx : txns) { for (const CMutableTransaction& tx : txns) {
block.vtx.push_back(MakeTransactionRef(tx)); block.vtx.push_back(MakeTransactionRef(tx));
} }
// IncrementExtraNonce creates a valid coinbase and merkleRoot {
unsigned int extraNonce = 0; CMutableTransaction tx_coinbase{*block.vtx.at(0)};
IncrementExtraNonce(&block, prev, extraNonce); tx_coinbase.vin.at(0).scriptSig = CScript{} << prev->nHeight + 1;
block.vtx.at(0) = MakeTransactionRef(std::move(tx_coinbase));
block.hashMerkleRoot = BlockMerkleRoot(block);
}
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;

View File

@ -31,7 +31,7 @@ class FeatureBlockfilterindexPruneTest(BitcoinTestFramework):
pruneheight = self.nodes[0].pruneblockchain(400) pruneheight = self.nodes[0].pruneblockchain(400)
# the prune heights used here and below are magic numbers that are determined by the # the prune heights used here and below are magic numbers that are determined by the
# thresholds at which block files wrap, so they depend on disk serialization and default block file size. # thresholds at which block files wrap, so they depend on disk serialization and default block file size.
assert_equal(pruneheight, 248) assert_equal(pruneheight, 249)
self.log.info("check if we can access the tips blockfilter when we have pruned some blocks") self.log.info("check if we can access the tips blockfilter when we have pruned some blocks")
assert_greater_than(len(self.nodes[0].getblockfilter(self.nodes[0].getbestblockhash())['filter']), 0) assert_greater_than(len(self.nodes[0].getblockfilter(self.nodes[0].getbestblockhash())['filter']), 0)
@ -40,19 +40,19 @@ class FeatureBlockfilterindexPruneTest(BitcoinTestFramework):
assert_greater_than(len(self.nodes[0].getblockfilter(self.nodes[0].getblockhash(2))['filter']), 0) assert_greater_than(len(self.nodes[0].getblockfilter(self.nodes[0].getblockhash(2))['filter']), 0)
# mine and sync index up to a height that will later be the pruneheight # mine and sync index up to a height that will later be the pruneheight
self.generate(self.nodes[0], 298) self.generate(self.nodes[0], 51)
self.sync_index(height=998) self.sync_index(height=751)
self.log.info("start node without blockfilterindex") self.log.info("start node without blockfilterindex")
self.restart_node(0, extra_args=["-fastprune", "-prune=1"]) self.restart_node(0, extra_args=["-fastprune", "-prune=1"])
self.log.info("make sure accessing the blockfilters throws an error") self.log.info("make sure accessing the blockfilters throws an error")
assert_raises_rpc_error(-1, "Index is not enabled for filtertype basic", self.nodes[0].getblockfilter, self.nodes[0].getblockhash(2)) assert_raises_rpc_error(-1, "Index is not enabled for filtertype basic", self.nodes[0].getblockfilter, self.nodes[0].getblockhash(2))
self.generate(self.nodes[0], 502) self.generate(self.nodes[0], 749)
self.log.info("prune exactly up to the blockfilterindexes best block while blockfilters are disabled") self.log.info("prune exactly up to the blockfilterindexes best block while blockfilters are disabled")
pruneheight_2 = self.nodes[0].pruneblockchain(1000) pruneheight_2 = self.nodes[0].pruneblockchain(1000)
assert_equal(pruneheight_2, 998) assert_equal(pruneheight_2, 751)
self.restart_node(0, extra_args=["-fastprune", "-prune=1", "-blockfilterindex=1"]) self.restart_node(0, extra_args=["-fastprune", "-prune=1", "-blockfilterindex=1"])
self.log.info("make sure that we can continue with the partially synced index after having pruned up to the index height") self.log.info("make sure that we can continue with the partially synced index after having pruned up to the index height")
self.sync_index(height=1500) self.sync_index(height=1500)

View File

@ -69,8 +69,8 @@ class UTXOSetHashTest(BitcoinTestFramework):
assert_equal(finalized[::-1].hex(), node_muhash) assert_equal(finalized[::-1].hex(), node_muhash)
self.log.info("Test deterministic UTXO set hash results") self.log.info("Test deterministic UTXO set hash results")
assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "3a570529b4c32e77268de1f81b903c75cc2da53c48df0d125c1e697ba7c8c7b7") assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "f9aa4fb5ffd10489b9a6994e70ccf1de8a8bfa2d5f201d9857332e9954b0855d")
assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "a13e0e70eb8acc786549596e3bc154623f1a5a622ba2f70715f6773ec745f435") assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "d1725b2fe3ef43e55aa4907480aea98d406fc9e0bf8f60169e2305f1fbf5961b")
def run_test(self): def run_test(self):
self.test_muhash_implementation() self.test_muhash_implementation()

View File

@ -37,16 +37,16 @@ class DumptxoutsetTest(BitcoinTestFramework):
# Blockhash should be deterministic based on mocked time. # Blockhash should be deterministic based on mocked time.
assert_equal( assert_equal(
out['base_hash'], out['base_hash'],
'6fd417acba2a8738b06fee43330c50d58e6a725046c3d843c8dd7e51d46d1ed6') '09abf0e7b510f61ca6cf33bab104e9ee99b3528b371d27a2d4b39abb800fba7e')
with open(str(expected_path), 'rb') as f: with open(str(expected_path), 'rb') as f:
digest = hashlib.sha256(f.read()).hexdigest() digest = hashlib.sha256(f.read()).hexdigest()
# UTXO snapshot hash should be deterministic based on mocked time. # UTXO snapshot hash should be deterministic based on mocked time.
assert_equal( assert_equal(
digest, '7ae82c986fa5445678d2a21453bb1c86d39e47af13da137640c2b1cf8093691c') digest, 'b1bacb602eacf5fbc9a7c2ef6eeb0d229c04e98bdf0c2ea5929012cd0eae3830')
assert_equal( assert_equal(
out['txoutset_hash'], 'd4b614f476b99a6e569973bf1c0120d88b1a168076f8ce25691fb41dd1cef149') out['txoutset_hash'], '1f7e3befd45dc13ae198dfbb22869a9c5c4196f8e9ef9735831af1288033f890')
assert_equal(out['nchaintx'], 101) assert_equal(out['nchaintx'], 101)
# Specifying a path to an existing file will fail. # Specifying a path to an existing file will fail.