Fall back to ReadBlockFromDisk when blockTxs is not filled yet (#2908)

* Fall back to ReadBlockFromDisk when blockTxs is not filled yet

This handles the case where a MN is freshly started and SyncTransaction
was not been called for older transactions/blocks.

* Also update txFirstSeenTime

* Properly handle txids == nullptr
This commit is contained in:
Alexander Block 2019-05-10 15:54:40 +02:00 committed by GitHub
parent 4dc5c0e9ed
commit 56f31195d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 12 deletions

View File

@ -301,17 +301,10 @@ void CChainLocksHandler::TrySignChainTip()
break; break;
} }
decltype(blockTxs.begin()->second) txids; auto txids = GetBlockTxs(pindexWalk->GetBlockHash());
{ if (!txids) {
LOCK(cs); pindexWalk = pindexWalk->pprev;
auto it = blockTxs.find(pindexWalk->GetBlockHash()); continue;
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;
} }
for (auto& txid : *txids) { 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<std::unordered_set<uint256, StaticSaltedHasher>>();
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) bool CChainLocksHandler::IsTxSafeForMining(const uint256& txid)
{ {
if (!sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) { if (!sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) {

View File

@ -68,7 +68,8 @@ private:
uint256 lastSignedMsgHash; uint256 lastSignedMsgHash;
// We keep track of txids from recently received blocks so that we can check if all TXs got ixlocked // We keep track of txids from recently received blocks so that we can check if all TXs got ixlocked
std::unordered_map<uint256, std::shared_ptr<std::unordered_set<uint256, StaticSaltedHasher>>> blockTxs; typedef std::unordered_map<uint256, std::shared_ptr<std::unordered_set<uint256, StaticSaltedHasher>>> BlockTxs;
BlockTxs blockTxs;
std::unordered_map<uint256, int64_t> txFirstSeenTime; std::unordered_map<uint256, int64_t> txFirstSeenTime;
std::map<uint256, int64_t> seenChainLocks; std::map<uint256, int64_t> seenChainLocks;
@ -107,6 +108,8 @@ private:
void DoInvalidateBlock(const CBlockIndex* pindex, bool activateBestChain); void DoInvalidateBlock(const CBlockIndex* pindex, bool activateBestChain);
BlockTxs::mapped_type GetBlockTxs(const uint256& blockHash);
void Cleanup(); void Cleanup();
}; };