Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 76 additions & 49 deletions src/llmq/quorums_instantsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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);
}
}
}

Expand All @@ -94,12 +96,19 @@ static std::tuple<std::string, uint32_t, uint256> 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)
Expand Down Expand Up @@ -133,7 +142,7 @@ std::unordered_map<uint256, CInstantSendLockPtr> 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);
Expand Down Expand Up @@ -185,6 +194,39 @@ void CInstantSendDb::RemoveArchivedInstantSendLocks(int nUntilHeight)
db.WriteBatch(batch);
}

void CInstantSendDb::WriteBlockInstantSendLocks(const std::shared_ptr<const CBlock>& 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<const CBlock>& 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));
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -300,12 +342,12 @@ std::vector<uint256> 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);

Expand All @@ -315,7 +357,7 @@ std::vector<uint256> CInstantSendDb::RemoveChainedInstantSendLocks(const uint256
}
}

RemoveInstantSendLock(batch, islockHash, nullptr);
RemoveInstantSendLock(batch, islockHash, nullptr, false);
WriteInstantSendLockArchived(batch, islockHash, nHeight);
result.emplace_back(islockHash);

Expand Down Expand Up @@ -995,49 +1037,34 @@ void CInstantSendManager::BlockConnected(const std::shared_ptr<const CBlock>& 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<const CBlock>& 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)
Expand Down
10 changes: 7 additions & 3 deletions src/llmq/quorums_instantsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,25 @@ class CInstantSendDb
mutable unordered_lru_cache<uint256, uint256, StaticSaltedHasher, 10000> txidCache;
mutable unordered_lru_cache<COutPoint, uint256, SaltedOutpointHasher, 10000> 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<uint256, CInstantSendLockPtr> RemoveConfirmedInstantSendLocks(int nUntilHeight);
void RemoveArchivedInstantSendLocks(int nUntilHeight);
void WriteBlockInstantSendLocks(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected);
void RemoveBlockInstantSendLocks(const std::shared_ptr<const CBlock>& 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;
Expand Down