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
61 changes: 51 additions & 10 deletions src/llmq/quorums_instantsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,30 +90,30 @@ void CInstantSendDb::RemoveInstantSendLock(CDBBatch& batch, const uint256& hash,
}
}

static std::tuple<std::string, uint32_t, uint256> BuildInversedISLockMinedKey(int nHeight, const uint256& islockHash)
static std::tuple<std::string, uint32_t, uint256> BuildInversedISLockKey(const std::string& k, int nHeight, const uint256& islockHash)
{
return std::make_tuple(std::string("is_m"), htobe32(std::numeric_limits<uint32_t>::max() - nHeight), islockHash);
return std::make_tuple(k, htobe32(std::numeric_limits<uint32_t>::max() - nHeight), islockHash);
}

void CInstantSendDb::WriteInstantSendLockMined(const uint256& hash, int nHeight)
{
db.Write(BuildInversedISLockMinedKey(nHeight, hash), true);
db.Write(BuildInversedISLockKey("is_m", nHeight, hash), true);
}

void CInstantSendDb::RemoveInstantSendLockMined(const uint256& hash, int nHeight)
{
db.Erase(BuildInversedISLockMinedKey(nHeight, hash));
db.Erase(BuildInversedISLockKey("is_m", nHeight, hash));
}

std::unordered_map<uint256, CInstantSendLockPtr> CInstantSendDb::RemoveConfirmedInstantSendLocks(int nUntilHeight)
{
auto it = std::unique_ptr<CDBIterator>(db.NewIterator());

auto firstKey = BuildInversedISLockMinedKey(nUntilHeight, uint256());
auto firstKey = BuildInversedISLockKey("is_m", nUntilHeight, uint256());

it->Seek(firstKey);

CDBBatch deleteBatch(db);
CDBBatch batch(db);
std::unordered_map<uint256, CInstantSendLockPtr> ret;
while (it->Valid()) {
decltype(firstKey) curKey;
Expand All @@ -128,20 +128,58 @@ std::unordered_map<uint256, CInstantSendLockPtr> CInstantSendDb::RemoveConfirmed
auto& islockHash = std::get<2>(curKey);
auto islock = GetInstantSendLockByHash(islockHash);
if (islock) {
RemoveInstantSendLock(deleteBatch, islockHash, islock);
RemoveInstantSendLock(batch, islockHash, islock);
ret.emplace(islockHash, islock);
}

deleteBatch.Erase(curKey);
// archive the islock hash, so that we're still able to check if we've seen the islock in the past
batch.Write(BuildInversedISLockKey("is_a1", nHeight, islockHash), true);
batch.Write(std::make_tuple(std::string("is_a2"), islockHash), true);

batch.Erase(curKey);

it->Next();
}

db.WriteBatch(deleteBatch);
db.WriteBatch(batch);

return ret;
}

void CInstantSendDb::RemoveArchivedInstantSendLocks(int nUntilHeight)
{
auto it = std::unique_ptr<CDBIterator>(db.NewIterator());

auto firstKey = BuildInversedISLockKey("is_a1", nUntilHeight, uint256());

it->Seek(firstKey);

CDBBatch batch(db);
while (it->Valid()) {
decltype(firstKey) curKey;
if (!it->GetKey(curKey) || std::get<0>(curKey) != "is_a1") {
break;
}
uint32_t nHeight = std::numeric_limits<uint32_t>::max() - be32toh(std::get<1>(curKey));
if (nHeight > nUntilHeight) {
break;
}

auto& islockHash = std::get<2>(curKey);
batch.Erase(std::make_tuple(std::string("is_a2"), islockHash));
batch.Erase(curKey);

it->Next();
}

db.WriteBatch(batch);
}

bool CInstantSendDb::HasArchivedInstantSendLock(const uint256& islockHash)
{
return db.Exists(std::make_tuple(std::string("is_a2"), islockHash));
}

CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByHash(const uint256& hash)
{
CInstantSendLockPtr ret;
Expand Down Expand Up @@ -875,6 +913,9 @@ void CInstantSendManager::HandleFullyConfirmedBlock(const CBlockIndex* pindex)
LOCK(cs);

removeISLocks = db.RemoveConfirmedInstantSendLocks(pindex->nHeight);
if (pindex->nHeight > 100) {
db.RemoveArchivedInstantSendLocks(pindex->nHeight - 100);
}
for (auto& p : removeISLocks) {
auto& islockHash = p.first;
auto& islock = p.second;
Expand Down Expand Up @@ -1049,7 +1090,7 @@ bool CInstantSendManager::AlreadyHave(const CInv& inv)
}

LOCK(cs);
return db.GetInstantSendLockByHash(inv.hash) != nullptr || pendingInstantSendLocks.count(inv.hash) != 0;
return db.GetInstantSendLockByHash(inv.hash) != nullptr || pendingInstantSendLocks.count(inv.hash) != 0 || db.HasArchivedInstantSendLock(inv.hash);
}

bool CInstantSendManager::GetInstantSendLockByHash(const uint256& hash, llmq::CInstantSendLock& ret)
Expand Down
2 changes: 2 additions & 0 deletions src/llmq/quorums_instantsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class CInstantSendDb
void WriteInstantSendLockMined(const uint256& hash, int nHeight);
void RemoveInstantSendLockMined(const uint256& hash, int nHeight);
std::unordered_map<uint256, CInstantSendLockPtr> RemoveConfirmedInstantSendLocks(int nUntilHeight);
void RemoveArchivedInstantSendLocks(int nUntilHeight);
bool HasArchivedInstantSendLock(const uint256& islockHash);

CInstantSendLockPtr GetInstantSendLockByHash(const uint256& hash);
uint256 GetInstantSendLockHashByTxid(const uint256& txid);
Expand Down