Skip to content

Commit 78e73f8

Browse files
committed
perf: use tiny cache for best chainlock in CbTx instead running heavy ReadBlockFromDisk
1 parent fc96190 commit 78e73f8

File tree

1 file changed

+35
-1
lines changed

1 file changed

+35
-1
lines changed

src/evo/cbtx.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,13 +331,33 @@ bool CheckCbTxBestChainlock(const CBlock& block, const CBlockIndex* pindex,
331331
return true;
332332
}
333333

334+
static Mutex cached_mutex;
335+
static const CBlockIndex* cached_pindex GUARDED_BY(cached_mutex){nullptr};
336+
static std::optional<std::pair<CBLSSignature, uint32_t>> cached_chainlock GUARDED_BY(cached_mutex){std::nullopt};
337+
334338
auto best_clsig = chainlock_handler.GetBestChainLock();
335339
if (best_clsig.getHeight() == pindex->nHeight - 1 && cbTx.bestCLHeightDiff == 0 && cbTx.bestCLSignature == best_clsig.getSig()) {
336340
// matches our best clsig which still hold values for the previous block
341+
{
342+
LOCK(cached_mutex);
343+
cached_chainlock = std::make_pair(cbTx.bestCLSignature, cbTx.bestCLHeightDiff);
344+
cached_pindex = pindex;
345+
}
337346
return true;
338347
}
339348

340-
const auto prevBlockCoinbaseChainlock = GetNonNullCoinbaseChainlock(pindex->pprev);
349+
std::optional<std::pair<CBLSSignature, uint32_t>> prevBlockCoinbaseChainlock{std::nullopt};
350+
bool use_cached = false;
351+
{
352+
LOCK(cached_mutex);
353+
if (cached_pindex == pindex->pprev) {
354+
use_cached = true;
355+
prevBlockCoinbaseChainlock = cached_chainlock;
356+
}
357+
}
358+
if (!use_cached) {
359+
prevBlockCoinbaseChainlock = GetNonNullCoinbaseChainlock(pindex->pprev);
360+
}
341361
// If std::optional prevBlockCoinbaseChainlock is empty, then up to the previous block, coinbase Chainlock is null.
342362
if (prevBlockCoinbaseChainlock.has_value()) {
343363
// Previous block Coinbase has a non-null Chainlock: current block's Chainlock must be non-null and at least as new as the previous one
@@ -355,12 +375,22 @@ bool CheckCbTxBestChainlock(const CBlock& block, const CBlockIndex* pindex,
355375
int curBlockCoinbaseCLHeight = pindex->nHeight - static_cast<int>(cbTx.bestCLHeightDiff) - 1;
356376
if (best_clsig.getHeight() == curBlockCoinbaseCLHeight && best_clsig.getSig() == cbTx.bestCLSignature) {
357377
// matches our best (but outdated) clsig, no need to verify it again
378+
{
379+
LOCK(cached_mutex);
380+
cached_chainlock = std::make_pair(cbTx.bestCLSignature, cbTx.bestCLHeightDiff);
381+
cached_pindex = pindex;
382+
}
358383
return true;
359384
}
360385
uint256 curBlockCoinbaseCLBlockHash = pindex->GetAncestor(curBlockCoinbaseCLHeight)->GetBlockHash();
361386
if (chainlock_handler.VerifyChainLock(llmq::CChainLockSig(curBlockCoinbaseCLHeight, curBlockCoinbaseCLBlockHash, cbTx.bestCLSignature)) != llmq::VerifyRecSigStatus::Valid) {
362387
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-invalid-clsig");
363388
}
389+
{
390+
LOCK(cached_mutex);
391+
cached_chainlock = std::make_pair(cbTx.bestCLSignature, cbTx.bestCLHeightDiff);
392+
cached_pindex = pindex;
393+
}
364394
} else if (cbTx.bestCLHeightDiff != 0) {
365395
// Null bestCLSignature is allowed only with bestCLHeightDiff = 0
366396
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cbtx-cldiff");
@@ -437,6 +467,10 @@ std::optional<std::pair<CBLSSignature, uint32_t>> GetNonNullCoinbaseChainlock(co
437467
return std::nullopt;
438468
}
439469

470+
// There's no CL in CbTx before v20 activation
471+
if (!DeploymentActiveAt(*pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) {
472+
return std::nullopt;
473+
}
440474
// There's no CbTx before DIP0003 activation
441475
if (!DeploymentActiveAt(*pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0003)) {
442476
return std::nullopt;

0 commit comments

Comments
 (0)