perf: pass around a cached block hash during block validation (#5613)

this change saw a ~38% performance improvement in header sync reindex

reproduce via `time ./src/qt/dash-qt --nowallet --testnet --reindex
--stopatheight=5`

On Develop this took average of 1:48 to finish, on this branch it took
1:07

## Issue being fixed or feature implemented
Slow header / block validation

## What was done?
Pass around cached block hash

## How Has This Been Tested?
Reindexed testnet

## Breaking Changes
None

## Checklist:
_Go over all the following points, and put an `x` in all the boxes that
apply._
- [x] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have added or updated relevant unit/integration/functional/e2e
tests
- [ ] I have made corresponding changes to the documentation
- [x] I have assigned this pull request to a milestone _(for repository
code-owners and collaborators only)_

Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
This commit is contained in:
PastaPastaPasta 2023-10-16 12:05:03 -05:00 committed by GitHub
parent 13b99e2401
commit 7ad7cbf98a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 10 additions and 11 deletions

View File

@ -3566,13 +3566,12 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
} }
} }
CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, enum BlockStatus nStatus) CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, const uint256& hash, enum BlockStatus nStatus)
{ {
assert(!(nStatus & BLOCK_FAILED_MASK)); // no failed blocks allowed assert(!(nStatus & BLOCK_FAILED_MASK)); // no failed blocks allowed
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
// Check for duplicate // Check for duplicate
uint256 hash = block.GetHash();
BlockMap::iterator it = m_block_index.find(hash); BlockMap::iterator it = m_block_index.find(hash);
if (it != m_block_index.end()) if (it != m_block_index.end())
return it->second; return it->second;
@ -3737,16 +3736,16 @@ static bool FindUndoPos(BlockValidationState &state, int nFile, FlatFilePos &pos
return true; return true;
} }
static bool CheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true) static bool CheckBlockHeader(const CBlockHeader& block, const uint256& hash, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true)
{ {
// Check proof of work matches claimed amount // Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) if (fCheckPOW && !CheckProofOfWork(hash, block.nBits, consensusParams))
return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "high-hash", "proof of work failed"); return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "high-hash", "proof of work failed");
// Check DevNet // Check DevNet
if (!consensusParams.hashDevnetGenesisBlock.IsNull() && if (!consensusParams.hashDevnetGenesisBlock.IsNull() &&
block.hashPrevBlock == consensusParams.hashGenesisBlock && block.hashPrevBlock == consensusParams.hashGenesisBlock &&
block.GetHash() != consensusParams.hashDevnetGenesisBlock) { hash != consensusParams.hashDevnetGenesisBlock) {
LogPrintf("ERROR: CheckBlockHeader(): wrong devnet genesis\n"); LogPrintf("ERROR: CheckBlockHeader(): wrong devnet genesis\n");
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "devnet-genesis"); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "devnet-genesis");
} }
@ -3765,7 +3764,7 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
// Check that the header is valid (particularly PoW). This is mostly // Check that the header is valid (particularly PoW). This is mostly
// redundant with the call in AcceptBlockHeader. // redundant with the call in AcceptBlockHeader.
if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW)) if (!CheckBlockHeader(block, block.GetHash(), state, consensusParams, fCheckPOW))
return false; return false;
// Check the merkle root. // Check the merkle root.
@ -4005,7 +4004,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationS
return true; return true;
} }
if (!CheckBlockHeader(block, state, chainparams.GetConsensus())) { if (!CheckBlockHeader(block, hash, state, chainparams.GetConsensus())) {
LogPrint(BCLog::VALIDATION, "%s: Consensus::CheckBlockHeader: %s, %s\n", __func__, hash.ToString(), state.ToString()); LogPrint(BCLog::VALIDATION, "%s: Consensus::CheckBlockHeader: %s, %s\n", __func__, hash.ToString(), state.ToString());
return false; return false;
} }
@ -4075,14 +4074,14 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationS
if (llmq::chainLocksHandler->HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) { if (llmq::chainLocksHandler->HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) {
if (pindex == nullptr) { if (pindex == nullptr) {
AddToBlockIndex(block, BLOCK_CONFLICT_CHAINLOCK); AddToBlockIndex(block, hash, BLOCK_CONFLICT_CHAINLOCK);
} }
LogPrintf("ERROR: %s: header %s conflicts with chainlock\n", __func__, hash.ToString()); LogPrintf("ERROR: %s: header %s conflicts with chainlock\n", __func__, hash.ToString());
return state.Invalid(BlockValidationResult::BLOCK_CHAINLOCK, "bad-chainlock"); return state.Invalid(BlockValidationResult::BLOCK_CHAINLOCK, "bad-chainlock");
} }
} }
if (pindex == nullptr) if (pindex == nullptr)
pindex = AddToBlockIndex(block); pindex = AddToBlockIndex(block, hash);
if (ppindex) if (ppindex)
*ppindex = pindex; *ppindex = pindex;
@ -5058,7 +5057,7 @@ bool CChainState::AddGenesisBlock(const CBlock& block, BlockValidationState& sta
FlatFilePos blockPos = SaveBlockToDisk(block, 0, m_chain, m_params, nullptr); FlatFilePos blockPos = SaveBlockToDisk(block, 0, m_chain, m_params, nullptr);
if (blockPos.IsNull()) if (blockPos.IsNull())
return error("%s: writing genesis block to disk failed (%s)", __func__, state.ToString()); return error("%s: writing genesis block to disk failed (%s)", __func__, state.ToString());
CBlockIndex* pindex = m_blockman.AddToBlockIndex(block); CBlockIndex* pindex = m_blockman.AddToBlockIndex(block, block.GetHash());
ReceivedBlockTransactions(block, pindex, blockPos); ReceivedBlockTransactions(block, pindex, blockPos);
return true; return true;
} }

View File

@ -447,7 +447,7 @@ public:
/** Clear all data members. */ /** Clear all data members. */
void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main); void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CBlockIndex* AddToBlockIndex(const CBlockHeader& block, enum BlockStatus nStatus = BLOCK_VALID_TREE) EXCLUSIVE_LOCKS_REQUIRED(cs_main); CBlockIndex* AddToBlockIndex(const CBlockHeader& block, const uint256& hash, enum BlockStatus nStatus = BLOCK_VALID_TREE) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Create a new block index entry for a given block hash */ /** Create a new block index entry for a given block hash */
CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);