Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove recovered sigs from the LLMQ db when corresponding IS locks get confirmed #3048

Merged
merged 5 commits into from
Aug 12, 2019
Merged
Show file tree
Hide file tree
Changes from 4 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
16 changes: 9 additions & 7 deletions src/llmq/quorums_instantsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,6 @@ void CInstantSendDb::WriteNewInstantSendLock(const uint256& hash, const CInstant
}
}

void CInstantSendDb::RemoveInstantSendLock(const uint256& hash, CInstantSendLockPtr islock)
{
CDBBatch batch(db);
RemoveInstantSendLock(batch, hash, islock);
db.WriteBatch(batch);
}

void CInstantSendDb::RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock)
{
if (!islock) {
Expand Down Expand Up @@ -1091,6 +1084,8 @@ void CInstantSendManager::UpdatedBlockTip(const CBlockIndex* pindexNew)

void CInstantSendManager::HandleFullyConfirmedBlock(const CBlockIndex* pindex)
{
auto& consensusParams = Params().GetConsensus();

std::unordered_map<uint256, CInstantSendLockPtr> removeISLocks;
{
LOCK(cs);
Expand All @@ -1108,7 +1103,14 @@ void CInstantSendManager::HandleFullyConfirmedBlock(const CBlockIndex* pindex)
for (auto& in : islock->inputs) {
auto inputRequestId = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in));
inputRequestIds.erase(inputRequestId);

// no need to keep recovered sigs for fully confirmed IS locks, as there is no chance for conflicts
// from now on. All inputs are spent now and can't be spend in any other TX.
quorumSigningManager->RemoveRecoveredSig(consensusParams.llmqForInstantSend, inputRequestId);
}

// same as in the loop
quorumSigningManager->RemoveRecoveredSig(consensusParams.llmqForInstantSend, islock->GetRequestId());
}

// Find all previously unlocked TXs that got locked by this fully confirmed (ChainLock) block and remove them
Expand Down
1 change: 0 additions & 1 deletion src/llmq/quorums_instantsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ class CInstantSendDb
CInstantSendDb(CDBWrapper& _db) : db(_db) {}

void WriteNewInstantSendLock(const uint256& hash, const CInstantSendLock& islock);
void RemoveInstantSendLock(const uint256& hash, CInstantSendLockPtr islock);
void RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock);

void WriteInstantSendLockMined(const uint256& hash, int nHeight);
Expand Down
75 changes: 54 additions & 21 deletions src/llmq/quorums_signing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,15 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig)
{
CDBBatch batch(db);

uint32_t curTime = GetAdjustedTime();

// we put these close to each other to leverage leveldb's key compaction
// this way, the second key can be used for fast HasRecoveredSig checks while the first key stores the recSig
auto k1 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id);
auto k2 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id, recSig.msgHash);
batch.Write(k1, recSig);
batch.Write(k2, (uint8_t)1);
// this key is also used to store the current time, so that we can easily get to the "rs_t" key when we have the id
batch.Write(k2, curTime);

// store by object hash
auto k3 = std::make_tuple(std::string("rs_h"), recSig.GetHash());
Expand All @@ -241,7 +244,7 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig)
batch.Write(k4, (uint8_t)1);

// store by current time. Allows fast cleanup of old recSigs
auto k5 = std::make_tuple(std::string("rs_t"), (uint32_t)htobe32(GetAdjustedTime()), recSig.llmqType, recSig.id);
auto k5 = std::make_tuple(std::string("rs_t"), (uint32_t)htobe32(curTime), recSig.llmqType, recSig.id);
batch.Write(k5, (uint8_t)1);

db.WriteBatch(batch);
Expand All @@ -256,6 +259,49 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig)
}
}

void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteTimeKey)
{
AssertLockHeld(cs);

CRecoveredSig recSig;
if (!ReadRecoveredSig(llmqType, id, recSig)) {
return;
}

auto signHash = CLLMQUtils::BuildSignHash(recSig);

auto k1 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id);
auto k2 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id, recSig.msgHash);
auto k3 = std::make_tuple(std::string("rs_h"), recSig.GetHash());
auto k4 = std::make_tuple(std::string("rs_s"), signHash);
batch.Erase(k1);
batch.Erase(k2);
batch.Erase(k3);
batch.Erase(k4);

if (deleteTimeKey) {
CDataStream writeTimeDs(SER_DISK, CLIENT_VERSION);
if (db.ReadDataStream(k2, writeTimeDs) && writeTimeDs.size() == sizeof(uint32_t)) {
UdjinM6 marked this conversation as resolved.
Show resolved Hide resolved
uint32_t writeTime;
writeTimeDs >> writeTime;
auto k5 = std::make_tuple(std::string("rs_t"), (uint32_t) htobe32(writeTime), recSig.llmqType, recSig.id);
batch.Erase(k5);
}
}

hasSigForIdCache.erase(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id));
hasSigForSessionCache.erase(signHash);
hasSigForHashCache.erase(recSig.GetHash());
}

void CRecoveredSigsDb::RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id)
{
LOCK(cs);
CDBBatch batch(db);
RemoveRecoveredSig(batch, llmqType, id, true);
db.WriteBatch(batch);
}

void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge)
{
std::unique_ptr<CDBIterator> pcursor(db.NewIterator());
Expand Down Expand Up @@ -292,25 +338,7 @@ void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge)
{
LOCK(cs);
for (auto& e : toDelete) {
CRecoveredSig recSig;
if (!ReadRecoveredSig(e.first, e.second, recSig)) {
continue;
}

auto signHash = CLLMQUtils::BuildSignHash(recSig);

auto k1 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id);
auto k2 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id, recSig.msgHash);
auto k3 = std::make_tuple(std::string("rs_h"), recSig.GetHash());
auto k4 = std::make_tuple(std::string("rs_s"), signHash);
batch.Erase(k1);
batch.Erase(k2);
batch.Erase(k3);
batch.Erase(k4);

hasSigForIdCache.erase(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id));
hasSigForSessionCache.erase(signHash);
hasSigForHashCache.erase(recSig.GetHash());
RemoveRecoveredSig(batch, e.first, e.second, false);

if (batch.SizeEstimate() >= (1 << 24)) {
db.WriteBatch(batch);
Expand Down Expand Up @@ -680,6 +708,11 @@ void CSigningManager::PushReconstructedRecoveredSig(const llmq::CRecoveredSig& r
pendingReconstructedRecoveredSigs.emplace_back(recoveredSig, quorum);
}

void CSigningManager::RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id)
{
db.RemoveRecoveredSig(llmqType, id);
}

void CSigningManager::Cleanup()
{
int64_t now = GetTimeMillis();
Expand Down
6 changes: 6 additions & 0 deletions src/llmq/quorums_signing.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class CRecoveredSigsDb
bool GetRecoveredSigByHash(const uint256& hash, CRecoveredSig& ret);
bool GetRecoveredSigById(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret);
void WriteRecoveredSig(const CRecoveredSig& recSig);
void RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id);

void CleanupOldRecoveredSigs(int64_t maxAge);

Expand All @@ -96,6 +97,7 @@ class CRecoveredSigsDb

private:
bool ReadRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret);
void RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteTimeKey);
};

class CRecoveredSigsListener
Expand Down Expand Up @@ -144,6 +146,10 @@ class CSigningManager
// This is the case for example when a signature appears as part of InstantSend or ChainLocks
void PushReconstructedRecoveredSig(const CRecoveredSig& recoveredSig, const CQuorumCPtr& quorum);

// This is called when a recovered signature can be safely removed from the DB. This is only safe when some other
// mechanism prevents possible conflicts. As an example, ChainLocks prevent conflicts in confirmed TXs InstantSend votes
void RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id);

private:
void ProcessMessageRecoveredSig(CNode* pfrom, const CRecoveredSig& recoveredSig, CConnman& connman);
bool PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig& recoveredSig, bool& retBan);
Expand Down