diff --git a/src/llmq/quorums_instantsend.cpp b/src/llmq/quorums_instantsend.cpp index acb72837df42..2506eae2e961 100644 --- a/src/llmq/quorums_instantsend.cpp +++ b/src/llmq/quorums_instantsend.cpp @@ -65,10 +65,10 @@ void CInstantSendDb::WriteNewInstantSendLock(const uint256& hash, const CInstant } } -void CInstantSendDb::RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock) +void CInstantSendDb::RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock, bool keep_cache) { if (!islock) { - islock = GetInstantSendLockByHash(hash); + islock = GetInstantSendLockByHash(hash, false); if (!islock) { return; } @@ -80,10 +80,12 @@ void CInstantSendDb::RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, batch.Erase(std::make_tuple(std::string(DB_HASH_BY_OUTPOINT), in)); } - islockCache.erase(hash); - txidCache.erase(islock->txid); - for (auto& in : islock->inputs) { - outpointCache.erase(in); + if (!keep_cache) { + islockCache.erase(hash); + txidCache.erase(islock->txid); + for (auto& in : islock->inputs) { + outpointCache.erase(in); + } } } @@ -94,12 +96,19 @@ static std::tuple BuildInversedISLockKey(const s void CInstantSendDb::WriteInstantSendLockMined(const uint256& hash, int nHeight) { - db.Write(BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nHeight, hash), true); + CDBBatch batch(db); + WriteInstantSendLockMined(batch, hash, nHeight); + db.WriteBatch(batch); +} + +void CInstantSendDb::WriteInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight) +{ + batch.Write(BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nHeight, hash), true); } -void CInstantSendDb::RemoveInstantSendLockMined(const uint256& hash, int nHeight) +void CInstantSendDb::RemoveInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight) { - db.Erase(BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nHeight, hash)); + batch.Erase(BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nHeight, hash)); } void CInstantSendDb::WriteInstantSendLockArchived(CDBBatch& batch, const uint256& hash, int nHeight) @@ -133,7 +142,7 @@ std::unordered_map CInstantSendDb::RemoveConfirmed } auto& islockHash = std::get<2>(curKey); - auto islock = GetInstantSendLockByHash(islockHash); + auto islock = GetInstantSendLockByHash(islockHash, false); if (islock) { RemoveInstantSendLock(batch, islockHash, islock); ret.emplace(islockHash, islock); @@ -185,6 +194,39 @@ void CInstantSendDb::RemoveArchivedInstantSendLocks(int nUntilHeight) db.WriteBatch(batch); } +void CInstantSendDb::WriteBlockInstantSendLocks(const std::shared_ptr& pblock, const CBlockIndex* pindexConnected) +{ + CDBBatch batch(db); + for (const auto& tx : pblock->vtx) { + if (tx->IsCoinBase() || tx->vin.empty()) { + // coinbase and TXs with no inputs can't be locked + continue; + } + uint256 islockHash = GetInstantSendLockHashByTxid(tx->GetHash()); + // update DB about when an IS lock was mined + if (!islockHash.IsNull()) { + WriteInstantSendLockMined(batch, islockHash, pindexConnected->nHeight); + } + } + db.WriteBatch(batch); +} + +void CInstantSendDb::RemoveBlockInstantSendLocks(const std::shared_ptr& pblock, const CBlockIndex* pindexDisconnected) +{ + CDBBatch batch(db); + for (const auto& tx : pblock->vtx) { + if (tx->IsCoinBase() || tx->vin.empty()) { + // coinbase and TXs with no inputs can't be locked + continue; + } + uint256 islockHash = GetInstantSendLockHashByTxid(tx->GetHash()); + if (!islockHash.IsNull()) { + RemoveInstantSendLockMined(batch, islockHash, pindexDisconnected->nHeight); + } + } + db.WriteBatch(batch); +} + bool CInstantSendDb::KnownInstantSendLock(const uint256& islockHash) const { return GetInstantSendLockByHash(islockHash) != nullptr || db.Exists(std::make_tuple(std::string(DB_ARCHIVED_BY_HASH), islockHash)); @@ -212,14 +254,14 @@ size_t CInstantSendDb::GetInstantSendLockCount() const return cnt; } -CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByHash(const uint256& hash) const +CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByHash(const uint256& hash, bool use_cache) const { if (hash.IsNull()) { return nullptr; } CInstantSendLockPtr ret; - if (islockCache.get(hash, ret)) { + if (use_cache && islockCache.get(hash, ret)) { return ret; } @@ -300,12 +342,12 @@ std::vector CInstantSendDb::RemoveChainedInstantSendLocks(const uint256 stack.pop_back(); for (auto& childIslockHash : children) { - auto childIsLock = GetInstantSendLockByHash(childIslockHash); + auto childIsLock = GetInstantSendLockByHash(childIslockHash, false); if (!childIsLock) { continue; } - RemoveInstantSendLock(batch, childIslockHash, childIsLock); + RemoveInstantSendLock(batch, childIslockHash, childIsLock, false); WriteInstantSendLockArchived(batch, childIslockHash, nHeight); result.emplace_back(childIslockHash); @@ -315,7 +357,7 @@ std::vector CInstantSendDb::RemoveChainedInstantSendLocks(const uint256 } } - RemoveInstantSendLock(batch, islockHash, nullptr); + RemoveInstantSendLock(batch, islockHash, nullptr, false); WriteInstantSendLockArchived(batch, islockHash, nHeight); result.emplace_back(islockHash); @@ -995,49 +1037,34 @@ void CInstantSendManager::BlockConnected(const std::shared_ptr& pb } } - for (const auto& tx : pblock->vtx) { - if (tx->IsCoinBase() || tx->vin.empty()) { - // coinbase and TXs with no inputs can't be locked - continue; - } - - uint256 islockHash; - { - LOCK(cs); - islockHash = db.GetInstantSendLockHashByTxid(tx->GetHash()); - - // update DB about when an IS lock was mined - if (!islockHash.IsNull()) { - db.WriteInstantSendLockMined(islockHash, pindex->nHeight); + if (masternodeSync.IsBlockchainSynced()) { + for (const auto& tx : pblock->vtx) { + if (tx->IsCoinBase() || tx->vin.empty()) { + // coinbase and TXs with no inputs can't be locked + continue; } - } - if (!masternodeSync.IsBlockchainSynced()) { - continue; - } - - if (islockHash.IsNull() && !chainLocksHandler->HasChainLock(pindex->nHeight, pindex->GetBlockHash())) { - ProcessTx(*tx, true, Params().GetConsensus()); - // TX is not locked, so make sure it is tracked - LOCK(cs); - AddNonLockedTx(tx, pindex); - } else { - // TX is locked, so make sure we don't track it anymore - LOCK(cs); - RemoveNonLockedTx(tx->GetHash(), true); + if (!IsLocked(tx->GetHash()) && !chainLocksHandler->HasChainLock(pindex->nHeight, pindex->GetBlockHash())) { + ProcessTx(*tx, true, Params().GetConsensus()); + // TX is not locked, so make sure it is tracked + LOCK(cs); + AddNonLockedTx(tx, pindex); + } else { + // TX is locked, so make sure we don't track it anymore + LOCK(cs); + RemoveNonLockedTx(tx->GetHash(), true); + } } } + + LOCK(cs); + db.WriteBlockInstantSendLocks(pblock, pindex); } void CInstantSendManager::BlockDisconnected(const std::shared_ptr& pblock, const CBlockIndex* pindexDisconnected) { LOCK(cs); - for (auto& tx : pblock->vtx) { - auto islockHash = db.GetInstantSendLockHashByTxid(tx->GetHash()); - if (!islockHash.IsNull()) { - db.RemoveInstantSendLockMined(islockHash, pindexDisconnected->nHeight); - } - } + db.RemoveBlockInstantSendLocks(pblock, pindexDisconnected); } void CInstantSendManager::AddNonLockedTx(const CTransactionRef& tx, const CBlockIndex* pindexMined) diff --git a/src/llmq/quorums_instantsend.h b/src/llmq/quorums_instantsend.h index cfd7e2d26999..e8792182a5c5 100644 --- a/src/llmq/quorums_instantsend.h +++ b/src/llmq/quorums_instantsend.h @@ -49,21 +49,25 @@ class CInstantSendDb mutable unordered_lru_cache txidCache; mutable unordered_lru_cache outpointCache; + void WriteInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight); + void RemoveInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight); + public: explicit CInstantSendDb(CDBWrapper& _db) : db(_db) {} void WriteNewInstantSendLock(const uint256& hash, const CInstantSendLock& islock); - void RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock); + void RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock, bool keep_cache = true); void WriteInstantSendLockMined(const uint256& hash, int nHeight); - void RemoveInstantSendLockMined(const uint256& hash, int nHeight); static void WriteInstantSendLockArchived(CDBBatch& batch, const uint256& hash, int nHeight); std::unordered_map RemoveConfirmedInstantSendLocks(int nUntilHeight); void RemoveArchivedInstantSendLocks(int nUntilHeight); + void WriteBlockInstantSendLocks(const std::shared_ptr& pblock, const CBlockIndex* pindexConnected); + void RemoveBlockInstantSendLocks(const std::shared_ptr& pblock, const CBlockIndex* pindexDisconnected); bool KnownInstantSendLock(const uint256& islockHash) const; size_t GetInstantSendLockCount() const; - CInstantSendLockPtr GetInstantSendLockByHash(const uint256& hash) const; + CInstantSendLockPtr GetInstantSendLockByHash(const uint256& hash, bool use_cache = true) const; uint256 GetInstantSendLockHashByTxid(const uint256& txid) const; CInstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid) const; CInstantSendLockPtr GetInstantSendLockByInput(const COutPoint& outpoint) const;