diff --git a/src/llmq/quorums_chainlocks.cpp b/src/llmq/quorums_chainlocks.cpp index 0c6e5e431d..0cba352672 100644 --- a/src/llmq/quorums_chainlocks.cpp +++ b/src/llmq/quorums_chainlocks.cpp @@ -301,17 +301,10 @@ void CChainLocksHandler::TrySignChainTip() break; } - decltype(blockTxs.begin()->second) txids; - { - LOCK(cs); - auto it = blockTxs.find(pindexWalk->GetBlockHash()); - if (it == blockTxs.end()) { - // this should actually not happen as NewPoWValidBlock should have been called before - LogPrint("chainlocks", "CChainLocksHandler::%s -- blockTxs for %s not found\n", __func__, - pindexWalk->GetBlockHash().ToString()); - return; - } - txids = it->second; + auto txids = GetBlockTxs(pindexWalk->GetBlockHash()); + if (!txids) { + pindexWalk = pindexWalk->pprev; + continue; } for (auto& txid : *txids) { @@ -382,6 +375,55 @@ void CChainLocksHandler::SyncTransaction(const CTransaction& tx, const CBlockInd } } +CChainLocksHandler::BlockTxs::mapped_type CChainLocksHandler::GetBlockTxs(const uint256& blockHash) +{ + AssertLockNotHeld(cs); + AssertLockNotHeld(cs_main); + + CChainLocksHandler::BlockTxs::mapped_type ret; + + { + LOCK(cs); + auto it = blockTxs.find(blockHash); + if (it != blockTxs.end()) { + ret = it->second; + } + } + if (!ret) { + // This should only happen when freshly started. + // If running for some time, SyncTransaction should have been called before which fills blockTxs. + LogPrint("chainlocks", "CChainLocksHandler::%s -- blockTxs for %s not found. Trying ReadBlockFromDisk\n", __func__, + blockHash.ToString()); + + uint32_t blockTime; + { + LOCK(cs_main); + auto pindex = mapBlockIndex.at(blockHash); + CBlock block; + if (!ReadBlockFromDisk(block, pindex, Params().GetConsensus())) { + return nullptr; + } + + ret = std::make_shared>(); + for (auto& tx : block.vtx) { + if (tx->IsCoinBase() || tx->vin.empty()) { + continue; + } + ret->emplace(tx->GetHash()); + } + + blockTime = block.nTime; + } + + LOCK(cs); + blockTxs.emplace(blockHash, ret); + for (auto& txid : *ret) { + txFirstSeenTime.emplace(txid, blockTime); + } + } + return ret; +} + bool CChainLocksHandler::IsTxSafeForMining(const uint256& txid) { if (!sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) { diff --git a/src/llmq/quorums_chainlocks.h b/src/llmq/quorums_chainlocks.h index e057a25242..98378f7a14 100644 --- a/src/llmq/quorums_chainlocks.h +++ b/src/llmq/quorums_chainlocks.h @@ -68,7 +68,8 @@ private: uint256 lastSignedMsgHash; // We keep track of txids from recently received blocks so that we can check if all TXs got ixlocked - std::unordered_map>> blockTxs; + typedef std::unordered_map>> BlockTxs; + BlockTxs blockTxs; std::unordered_map txFirstSeenTime; std::map seenChainLocks; @@ -107,6 +108,8 @@ private: void DoInvalidateBlock(const CBlockIndex* pindex, bool activateBestChain); + BlockTxs::mapped_type GetBlockTxs(const uint256& blockHash); + void Cleanup(); };