Skip to content

Commit 08eb5bb

Browse files
committed
Merge #2951: Dash LLMQ backports part 5
a85b450 Merge pull request dashpay#3399 from codablock/pr_speedups2 (Alexander Block) 136f900 cherry-pick dashpay#2833 (Alexander Block) d942439 Merge pull request dashpay#3389 from codablock/pr_concentrated_recovery (Alexander Block) 36790d2 cherry pick dashpay#3368 (Author Alexander Block) dac01a9 cherry-pick dashpay#2780 (Alexander Block) 39d0ed9 cherry-pick dashpay#3367 (Alexander Block) 5084bbf Allow re-signing of IS locks when performing retroactive signing (dashpay#3219) (Alexander Block) 802c006 Only track last seen time instead of first and last seen time (dashpay#3165) (Alexander Block) 479b64b Avoid propagating InstantSend related old recovered sigs (dashpay#3145) (Alexander Block) 27fa2af cherry-pick dashpay#3117 (Pasta) cf138e0 cherry-pick dashpay#3097 (Pasta) 23b140e Introduce getbestchainlock rpc and fix llmq-is-cl-conflicts.py (dashpay#3094) (UdjinM6) Pull request description: as usual each commit backports a different PR ACKs for top commit: a85b450 Duddino: utACK a85b450 Liquid369: uTACK a85b450 Fuzzbawls: ACK a85b450 Tree-SHA512: e9024d180888d8a6cc300ba9df74fc15929e3ade1773e5d312bd8cc93f6c9fd3898c5bf2d14672abf4faba576575c33936708e6e1dfd01a393479d264d3f2c57
2 parents e0463fb + a85b450 commit 08eb5bb

19 files changed

+424
-105
lines changed

src/llmq/quorums.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ static uint256 MakeQuorumKey(const CQuorum& q)
3434
{
3535
CHashWriter hw(SER_NETWORK, 0);
3636
hw << (uint8_t)q.params.type;
37-
hw << q.pindexQuorum->GetBlockHash();
37+
hw << q.qc.quorumHash;
3838
for (const auto& dmn : q.members) {
3939
hw << dmn->proTxHash;
4040
}
@@ -52,13 +52,12 @@ CQuorum::~CQuorum()
5252
}
5353
}
5454

55-
void CQuorum::Init(const uint256& _minedBlockHash, const CBlockIndex* _pindexQuorum, const std::vector<CDeterministicMNCPtr>& _members, const std::vector<bool>& _validMembers, const CBLSPublicKey& _quorumPublicKey)
55+
void CQuorum::Init(const CFinalCommitment& _qc, const CBlockIndex* _pindexQuorum, const uint256& _minedBlockHash, const std::vector<CDeterministicMNCPtr>& _members)
5656
{
57-
minedBlockHash = _minedBlockHash;
57+
qc = _qc;
5858
pindexQuorum = _pindexQuorum;
5959
members = _members;
60-
validMembers = _validMembers;
61-
quorumPublicKey = _quorumPublicKey;
60+
minedBlockHash = _minedBlockHash;
6261
}
6362

6463
bool CQuorum::IsMember(const uint256& proTxHash) const
@@ -75,15 +74,15 @@ bool CQuorum::IsValidMember(const uint256& proTxHash) const
7574
{
7675
for (size_t i = 0; i < members.size(); i++) {
7776
if (members[i]->proTxHash == proTxHash) {
78-
return validMembers[i];
77+
return qc.validMembers[i];
7978
}
8079
}
8180
return false;
8281
}
8382

8483
CBLSPublicKey CQuorum::GetPubKeyShare(size_t memberIdx) const
8584
{
86-
if (quorumVvec == nullptr || memberIdx >= members.size() || !validMembers[memberIdx]) {
85+
if (quorumVvec == nullptr || memberIdx >= members.size() || !qc.validMembers[memberIdx]) {
8786
return CBLSPublicKey();
8887
}
8988
auto& m = members[memberIdx];
@@ -148,7 +147,7 @@ void CQuorum::StartCachePopulatorThread(std::shared_ptr<CQuorum> _this)
148147
// when then later some other thread tries to get keys, it will be much faster
149148
_this->cachePopulatorThread = std::thread(&TraceThread<std::function<void()> >, "quorum-cachepop", [_this, t] {
150149
for (size_t i = 0; i < _this->members.size() && !_this->stopCachePopulatorThread && !ShutdownRequested(); i++) {
151-
if (_this->validMembers[i]) {
150+
if (_this->qc.validMembers[i]) {
152151
_this->GetPubKeyShare(i);
153152
}
154153
}
@@ -186,7 +185,7 @@ bool CQuorumManager::BuildQuorumFromCommitment(const CFinalCommitment& qc, const
186185
assert(qc.quorumHash == pindexQuorum->GetBlockHash());
187186

188187
auto members = deterministicMNManager->GetAllQuorumMembers((Consensus::LLMQType)qc.llmqType, pindexQuorum);
189-
quorum->Init(minedBlockHash, pindexQuorum, members, qc.validMembers, qc.quorumPublicKey);
188+
quorum->Init(qc, pindexQuorum, minedBlockHash, members);
190189

191190
bool hasValidVvec = false;
192191
if (quorum->ReadContributions(evoDb)) {

src/llmq/quorums.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,10 @@ class CQuorum
3535

3636
public:
3737
const Consensus::LLMQParams& params;
38-
uint256 minedBlockHash;
38+
CFinalCommitment qc;
3939
const CBlockIndex* pindexQuorum;
40+
uint256 minedBlockHash;
4041
std::vector<CDeterministicMNCPtr> members;
41-
std::vector<bool> validMembers;
42-
CBLSPublicKey quorumPublicKey;
4342

4443
// These are only valid when we either participated in the DKG or fully watched it
4544
BLSVerificationVectorPtr quorumVvec;
@@ -55,7 +54,7 @@ class CQuorum
5554
public:
5655
CQuorum(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker) : params(_params), blsCache(_blsWorker), stopCachePopulatorThread(false) {}
5756
~CQuorum();
58-
void Init(const uint256& minedBlockHash, const CBlockIndex* pindexQuorum, const std::vector<CDeterministicMNCPtr>& members, const std::vector<bool>& validMembers, const CBLSPublicKey& quorumPublicKey);
57+
void Init(const CFinalCommitment& _qc, const CBlockIndex* _pindexQuorum, const uint256& _minedBlockHash, const std::vector<CDeterministicMNCPtr>& _members);
5958

6059
bool IsMember(const uint256& proTxHash) const;
6160
bool IsValidMember(const uint256& proTxHash) const;

src/llmq/quorums_chainlocks.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ static const std::string CLSIG_REQUESTID_PREFIX = "clsig";
2323

2424
std::unique_ptr<CChainLocksHandler> chainLocksHandler{nullptr};
2525

26+
bool CChainLockSig::IsNull() const
27+
{
28+
return nHeight == -1 && blockHash == uint256();
29+
}
30+
2631
std::string CChainLockSig::ToString() const
2732
{
2833
return strprintf("CChainLockSig(nHeight=%d, blockHash=%s)", nHeight, blockHash.ToString());
@@ -72,6 +77,12 @@ bool CChainLocksHandler::GetChainLockByHash(const uint256& hash, llmq::CChainLoc
7277
return true;
7378
}
7479

80+
CChainLockSig CChainLocksHandler::GetBestChainLock()
81+
{
82+
LOCK(cs);
83+
return bestChainLock;
84+
}
85+
7586
void CChainLocksHandler::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
7687
{
7788
if (!sporkManager.IsSporkActive(SPORK_23_CHAINLOCKS_ENFORCEMENT)) {
@@ -101,7 +112,7 @@ void CChainLocksHandler::ProcessNewChainLock(NodeId from, const llmq::CChainLock
101112
return;
102113
}
103114

104-
if (bestChainLock.nHeight != -1 && clsig.nHeight <= bestChainLock.nHeight) {
115+
if (!bestChainLock.IsNull() && clsig.nHeight <= bestChainLock.nHeight) {
105116
// no need to process/relay older CLSIGs
106117
return;
107118
}
@@ -133,7 +144,7 @@ void CChainLocksHandler::ProcessNewChainLock(NodeId from, const llmq::CChainLock
133144
bestChainLock = clsig;
134145

135146
CInv inv(MSG_CLSIG, hash);
136-
g_connman->RelayInv(inv);
147+
g_connman->RelayInv(inv, LLMQS_PROTO_VERSION);
137148

138149
auto blockIt = mapBlockIndex.find(clsig.blockHash);
139150
if (blockIt == mapBlockIndex.end()) {

src/llmq/quorums_chainlocks.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class CChainLockSig
3434
READWRITE(obj.blockHash);
3535
READWRITE(obj.sig);
3636
}
37+
38+
bool IsNull() const;
3739
std::string ToString() const;
3840
};
3941

@@ -70,6 +72,7 @@ class CChainLocksHandler : public CRecoveredSigsListener
7072
public:
7173
bool AlreadyHave(const CInv& inv);
7274
bool GetChainLockByHash(const uint256& hash, CChainLockSig& ret);
75+
CChainLockSig GetBestChainLock();
7376

7477
void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman);
7578
void ProcessNewChainLock(NodeId from, const CChainLockSig& clsig, const uint256& hash);

src/llmq/quorums_connections.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,8 @@ void EnsureLatestQuorumConnections(Consensus::LLMQType llmqType, const CBlockInd
124124
continue;
125125
}
126126

127-
if (!connman->hasQuorumNodes(llmqType, quorum->pindexQuorum->GetBlockHash())) {
128-
EnsureQuorumConnections(llmqType, quorum->pindexQuorum, myProTxHash);
129-
}
127+
EnsureQuorumConnections(llmqType, quorum->pindexQuorum, myProTxHash);
128+
130129
connmanQuorumsToDelete.erase(quorum->pindexQuorum->GetBlockHash());
131130
}
132131

src/llmq/quorums_signing.cpp

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig)
246246
}
247247
}
248248

249-
void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteTimeKey)
249+
void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteHashKey, bool deleteTimeKey)
250250
{
251251
AssertLockHeld(cs);
252252

@@ -263,7 +263,9 @@ void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType l
263263
auto k4 = std::make_tuple(std::string("rs_s"), signHash);
264264
batch.Erase(k1);
265265
batch.Erase(k2);
266-
batch.Erase(k3);
266+
if (deleteHashKey) {
267+
batch.Erase(k3);
268+
}
267269
batch.Erase(k4);
268270

269271
if (deleteTimeKey) {
@@ -279,14 +281,27 @@ void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType l
279281

280282
hasSigForIdCache.erase(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id));
281283
hasSigForSessionCache.erase(signHash);
282-
hasSigForHashCache.erase(recSig.GetHash());
284+
if (deleteHashKey) {
285+
hasSigForHashCache.erase(recSig.GetHash());
286+
}
283287
}
284288

289+
// Completely remove any traces of the recovered sig
285290
void CRecoveredSigsDb::RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id)
286291
{
287292
LOCK(cs);
288293
CDBBatch batch(CLIENT_VERSION | ADDRV2_FORMAT);
289-
RemoveRecoveredSig(batch, llmqType, id, true);
294+
RemoveRecoveredSig(batch, llmqType, id, true, true);
295+
db.WriteBatch(batch);
296+
}
297+
298+
// Remove the recovered sig itself and all keys required to get from id -> recSig
299+
// This will leave the byHash key in-place so that HasRecoveredSigForHash still returns true
300+
void CRecoveredSigsDb::TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id)
301+
{
302+
LOCK(cs);
303+
CDBBatch batch(CLIENT_VERSION | ADDRV2_FORMAT);
304+
RemoveRecoveredSig(batch, llmqType, id, false, false);
290305
db.WriteBatch(batch);
291306
}
292307

@@ -326,7 +341,7 @@ void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge)
326341
{
327342
LOCK(cs);
328343
for (auto& e : toDelete) {
329-
RemoveRecoveredSig(batch, e.first, e.second, false);
344+
RemoveRecoveredSig(batch, e.first, e.second, true, false);
330345

331346
if (batch.SizeEstimate() >= (1 << 24)) {
332347
db.WriteBatch(batch);
@@ -417,8 +432,10 @@ CSigningManager::CSigningManager(CDBWrapper& llmqDb, bool fMemory) : db(llmqDb)
417432

418433
bool CSigningManager::AlreadyHave(const CInv& inv)
419434
{
420-
LOCK(cs);
421-
return inv.type == MSG_QUORUM_RECOVERED_SIG && db.HasRecoveredSigForHash(inv.hash);
435+
if (inv.type != MSG_QUORUM_RECOVERED_SIG) {
436+
return false;
437+
}
438+
return db.HasRecoveredSigForHash(inv.hash);
422439
}
423440

424441
bool CSigningManager::GetRecoveredSigForGetData(const uint256& hash, CRecoveredSig& ret)
@@ -459,7 +476,8 @@ void CSigningManager::ProcessMessageRecoveredSig(CNode* pfrom, const CRecoveredS
459476
return;
460477
}
461478

462-
LogPrint(BCLog::LLMQ, "CSigningManager::%s -- signHash=%s, node=%d\n", __func__, llmq::utils::BuildSignHash(recoveredSig).ToString(), pfrom->GetId());
479+
LogPrint(BCLog::LLMQ, "CSigningManager::%s -- signHash=%s, id=%s, msgHash=%s, node=%d\n", __func__,
480+
llmq::utils::BuildSignHash(recoveredSig).ToString(), recoveredSig.id.ToString(), recoveredSig.msgHash.ToString(), pfrom->GetId());
463481

464482
LOCK(cs);
465483
pendingRecoveredSigs[pfrom->GetId()].emplace_back(recoveredSig);
@@ -482,7 +500,7 @@ bool CSigningManager::PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig&
482500
recoveredSig.quorumHash.ToString(), nodeId);
483501
return false;
484502
}
485-
if (!llmq::utils::IsQuorumActive(llmqType, quorum->pindexQuorum->GetBlockHash())) {
503+
if (!llmq::utils::IsQuorumActive(llmqType, quorum->qc.quorumHash)) {
486504
return false;
487505
}
488506

@@ -537,7 +555,7 @@ void CSigningManager::CollectPendingRecoveredSigsToVerify(
537555
it = v.erase(it);
538556
continue;
539557
}
540-
if (!llmq::utils::IsQuorumActive(llmqType, quorum->pindexQuorum->GetBlockHash())) {
558+
if (!llmq::utils::IsQuorumActive(llmqType, quorum->qc.quorumHash)) {
541559
LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not active anymore, node=%d\n", __func__,
542560
recSig.quorumHash.ToString(), nodeId);
543561
it = v.erase(it);
@@ -579,7 +597,7 @@ bool CSigningManager::ProcessPendingRecoveredSigs(CConnman& connman)
579597
}
580598

581599
const auto& quorum = quorums.at(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.quorumHash));
582-
batchVerifier.PushMessage(nodeId, recSig.GetHash(), llmq::utils::BuildSignHash(recSig), recSig.sig.Get(), quorum->quorumPublicKey);
600+
batchVerifier.PushMessage(nodeId, recSig.GetHash(), llmq::utils::BuildSignHash(recSig), recSig.sig.Get(), quorum->qc.quorumPublicKey);
583601
verifyCount++;
584602
}
585603
}
@@ -624,6 +642,11 @@ void CSigningManager::ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& re
624642
LOCK(cs_main);
625643
connman.RemoveAskFor(recoveredSig.GetHash(), MSG_QUORUM_RECOVERED_SIG);
626644
}
645+
646+
if (db.HasRecoveredSigForHash(recoveredSig.GetHash())) {
647+
return;
648+
}
649+
627650
std::vector<CRecoveredSigsListener*> listeners;
628651
{
629652
LOCK(cs);
@@ -661,7 +684,7 @@ void CSigningManager::ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& re
661684

662685
CInv inv(MSG_QUORUM_RECOVERED_SIG, recoveredSig.GetHash());
663686
g_connman->ForEachNode([&](CNode* pnode) {
664-
if (pnode->m_wants_recsigs) {
687+
if (pnode->nVersion >= LLMQS_PROTO_VERSION && pnode->m_wants_recsigs && pnode->CanRelay()) {
665688
pnode->PushInventory(inv);
666689
}
667690
});
@@ -670,9 +693,9 @@ void CSigningManager::ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& re
670693
}
671694
}
672695

673-
void CSigningManager::RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id)
696+
void CSigningManager::TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id)
674697
{
675-
db.RemoveRecoveredSig(llmqType, id);
698+
db.TruncateRecoveredSig(llmqType, id);
676699
}
677700

678701
void CSigningManager::Cleanup()
@@ -703,7 +726,7 @@ void CSigningManager::UnregisterRecoveredSigsListener(CRecoveredSigsListener* l)
703726
recoveredSigsListeners.erase(itRem, recoveredSigsListeners.end());
704727
}
705728

706-
bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash)
729+
bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash, bool allowReSign)
707730
{
708731
auto& params = Params().GetConsensus().llmqs.at(llmqType);
709732

@@ -714,24 +737,31 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint
714737
{
715738
LOCK(cs);
716739

717-
if (db.HasVotedOnId(llmqType, id)) {
740+
bool hasVoted = db.HasVotedOnId(llmqType, id);
741+
if (hasVoted) {
718742
uint256 prevMsgHash;
719743
db.GetVoteForId(llmqType, id, prevMsgHash);
720744
if (msgHash != prevMsgHash) {
721745
LogPrintf("CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting on conflicting msgHash=%s\n", __func__,
722746
id.ToString(), prevMsgHash.ToString(), msgHash.ToString());
747+
return false;
748+
} else if (allowReSign) {
749+
LogPrint(BCLog::LLMQ, "CSigningManager::%s -- already voted for id=%s and msgHash=%s. Resigning!\n", __func__,
750+
id.ToString(), prevMsgHash.ToString());
723751
} else {
724752
LogPrint(BCLog::LLMQ, "CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting again.\n", __func__,
725753
id.ToString(), prevMsgHash.ToString());
754+
return false;
726755
}
727-
return false;
728756
}
729757

730758
if (db.HasRecoveredSigForId(llmqType, id)) {
731759
// no need to sign it if we already have a recovered sig
732760
return true;
733761
}
734-
db.WriteVoteForId(llmqType, id, msgHash);
762+
if (!hasVoted) {
763+
db.WriteVoteForId(llmqType, id, msgHash);
764+
}
735765
}
736766

737767
int tipHeight;
@@ -752,10 +782,13 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint
752782
}
753783

754784
if (!quorum->IsValidMember(activeMasternodeManager->GetProTx())) {
755-
// LogPrint(BCLog::LLMQ, "CSigningManager::%s -- we're not a valid member of quorum %s\n", __func__, quorum->quorumHash.ToString());
756785
return false;
757786
}
758787

788+
if (allowReSign) {
789+
// make us re-announce all known shares (other nodes might have run into a timeout)
790+
quorumSigSharesManager->ForceReAnnouncement(quorum, llmqType, id, msgHash);
791+
}
759792
quorumSigSharesManager->AsyncSign(quorum, id, msgHash);
760793

761794
return true;
@@ -832,7 +865,7 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType
832865
for (size_t i = 0; i < quorums.size(); i++) {
833866
CHashWriter h(SER_NETWORK, 0);
834867
h << (uint8_t)llmqType;
835-
h << quorums[i]->pindexQuorum->GetBlockHash();
868+
h << quorums[i]->qc.quorumHash;
836869
h << selectionHash;
837870
scores.emplace_back(h.GetHash(), i);
838871
}
@@ -849,8 +882,8 @@ bool CSigningManager::VerifyRecoveredSig(Consensus::LLMQType llmqType, int signe
849882
return false;
850883
}
851884

852-
uint256 signHash = llmq::utils::BuildSignHash(llmqParams.type, quorum->pindexQuorum->GetBlockHash(), id, msgHash);
853-
return sig.VerifyInsecure(quorum->quorumPublicKey, signHash);
885+
uint256 signHash = llmq::utils::BuildSignHash(llmqParams.type, quorum->qc.quorumHash, id, msgHash);
886+
return sig.VerifyInsecure(quorum->qc.quorumPublicKey, signHash);
854887
}
855888

856889
} // namespace llmq

0 commit comments

Comments
 (0)