diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 66ead16b30112..2011c82ac2b28 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -95,7 +95,7 @@ static CBlock FindDevNetGenesisBlock(const CBlock &prevBlock, const CAmount& rew for (uint32_t nNonce = 0; nNonce < UINT32_MAX; nNonce++) { block.nNonce = nNonce; - uint256 hash = block.GetHash(); + uint256 hash = block.GetHash(/*use_cache=*/false); if (UintToArith256(hash) <= bnTarget) return block; } diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index a7ec5a0823ea7..f04942e2dea80 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -10,12 +10,15 @@ #include #include -uint256 CBlockHeader::GetHash() const +uint256 CBlockHeader::GetHash(bool use_cache) const { - std::vector vch(80); - CVectorWriter ss(SER_GETHASH, PROTOCOL_VERSION, vch, 0); - ss << *this; - return HashX11((const char *)vch.data(), (const char *)vch.data() + vch.size()); + if (!use_cache || cached_hash.IsNull()) { + std::vector vch(80); + CVectorWriter ss(SER_GETHASH, PROTOCOL_VERSION, vch, 0); + ss << *this; + cached_hash = HashX11((const char *)vch.data(), (const char *)vch.data() + vch.size()); + } + return cached_hash; } std::string CBlock::ToString() const diff --git a/src/primitives/block.h b/src/primitives/block.h index f33e44ad39049..561171721b936 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -31,12 +31,18 @@ class CBlockHeader uint32_t nBits; uint32_t nNonce; + // Memory only cached hash as x11 is more expensive than sha256 + mutable uint256 cached_hash; + CBlockHeader() { SetNull(); } - SERIALIZE_METHODS(CBlockHeader, obj) { READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot, obj.nTime, obj.nBits, obj.nNonce); } + SERIALIZE_METHODS(CBlockHeader, obj) { + READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot, obj.nTime, obj.nBits, obj.nNonce); + obj.cached_hash.SetNull(); + } void SetNull() { @@ -46,6 +52,7 @@ class CBlockHeader nTime = 0; nBits = 0; nNonce = 0; + cached_hash.SetNull(); } bool IsNull() const @@ -53,7 +60,7 @@ class CBlockHeader return (nBits == 0); } - uint256 GetHash() const; + uint256 GetHash(bool use_cache = true) const; int64_t GetBlockTime() const { @@ -225,6 +232,7 @@ class CBlock : public CBlockHeader block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; + block.cached_hash = cached_hash; return block; } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 0f7cad75c754c..f538165cd48eb 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -132,7 +132,7 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& CChainParams chainparams(Params()); - while (max_tries > 0 && block.nNonce < std::numeric_limits::max() && !CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus()) && !ShutdownRequested()) { + while (max_tries > 0 && block.nNonce < std::numeric_limits::max() && !CheckProofOfWork(block.GetHash(/*use_cache=*/false), block.nBits, chainparams.GetConsensus()) && !ShutdownRequested()) { ++block.nNonce; --max_tries; } diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index d8e9ef2be47f4..11cda97d7489a 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -44,7 +44,7 @@ static CBlock BuildBlockTestCase() { bool mutated; block.hashMerkleRoot = BlockMerkleRoot(block, &mutated); assert(!mutated); - while (!CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) ++block.nNonce; + while (!CheckProofOfWork(block.GetHash(/*use_cache=*/false), block.nBits, Params().GetConsensus())) ++block.nNonce; return block; } @@ -275,7 +275,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest) bool mutated; block.hashMerkleRoot = BlockMerkleRoot(block, &mutated); assert(!mutated); - while (!CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) ++block.nNonce; + while (!CheckProofOfWork(block.GetHash(/*use_cache=*/false), block.nBits, Params().GetConsensus())) ++block.nNonce; // Test simple header round-trip with only coinbase { diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index 7773f2d7a9a5c..8d97076e43b0a 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -77,7 +77,7 @@ CBlock BuildChainTestingSetup::CreateBlock(const CBlockIndex* prev, unsigned int extraNonce = 0; IncrementExtraNonce(&block, prev, extraNonce); - while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; + while (!CheckProofOfWork(block.GetHash(/*use_cache=*/false), block.nBits, chainparams.GetConsensus())) ++block.nNonce; return block; } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index db9361aaca0d1..a703d0faf5c0f 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -245,7 +245,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // This will usually succeed in the first round as we take the nonce from BLOCKINFO // It's however useful when adding new blocks with unknown nonces (you should add the found block to BLOCKINFO) - while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, chainparams.GetConsensus())) { + while (!CheckProofOfWork(pblock->GetHash(/*use_cache=*/false), pblock->nBits, chainparams.GetConsensus())) { pblock->nNonce++; } } diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp index d09238de750de..18d750ba2f702 100644 --- a/src/test/util/mining.cpp +++ b/src/test/util/mining.cpp @@ -50,7 +50,7 @@ std::vector> CreateBlockChain(size_t total_height, const block.nBits = params.GenesisBlock().nBits; block.nNonce = 0; - while (!CheckProofOfWork(block.GetHash(), block.nBits, params.GetConsensus())) { + while (!CheckProofOfWork(block.GetHash(/*use_cache=*/false), block.nBits, params.GetConsensus())) { ++block.nNonce; assert(block.nNonce); } @@ -62,7 +62,7 @@ CTxIn MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) { auto block = PrepareBlock(node, coinbase_scriptPubKey); - while (!CheckProofOfWork(block->GetHash(), block->nBits, Params().GetConsensus())) { + while (!CheckProofOfWork(block->GetHash(/*use_cache=*/false), block->nBits, Params().GetConsensus())) { ++block->nNonce; assert(block->nNonce); } diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 7285cce2b4e52..b91607c1f9e66 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -504,7 +504,7 @@ CBlock TestChainSetup::CreateBlock( IncrementExtraNonce(&block, chainstate.m_chain.Tip(), extraNonce); } - while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; + while (!CheckProofOfWork(block.GetHash(/*use_cache=*/false), block.nBits, chainparams.GetConsensus())) ++block.nNonce; CBlock result = block; return result; diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index 9ffed27375455..88600067d1cbe 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -90,7 +90,7 @@ std::shared_ptr MinerTestingSetup::FinalizeBlock(std::shared_ptr { pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); - while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { + while (!CheckProofOfWork(pblock->GetHash(/*use_cache=*/false), pblock->nBits, Params().GetConsensus())) { ++(pblock->nNonce); } diff --git a/src/validation.cpp b/src/validation.cpp index 79b1b81dce395..531eb62f07deb 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -4973,6 +4973,8 @@ void CChainState::LoadExternalBlockFile( blkdat.SetPos(nBlockPos); std::shared_ptr pblock{std::make_shared()}; blkdat >> *pblock; + // We calculated the hash of the header earlier, no need to recalculate it. + pblock->cached_hash = hash; nRewind = blkdat.GetPos(); BlockValidationState state;