Skip to content

Commit 98a50c5

Browse files
committed
refactor: deduplicate common routines in most ReceiveMessage variants
Also: - Don't start DKG logger if we expect to bail right after in ActiveSession
1 parent eccc296 commit 98a50c5

File tree

3 files changed

+106
-93
lines changed

3 files changed

+106
-93
lines changed

src/active/dkgsession.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ ActiveDKGSession::~ActiveDKGSession() = default;
3737

3838
void ActiveDKGSession::Contribute(CDKGPendingMessages& pendingMessages, PeerManager& peerman)
3939
{
40-
CDKGLogger logger(*this, __func__, __LINE__);
41-
4240
if (!AreWeMember()) {
4341
return;
4442
}
4543

4644
assert(params.threshold > 1); // we should not get there with single-node-quorums
4745

46+
CDKGLogger logger(*this, __func__, __LINE__);
47+
4848
cxxtimer::Timer t1(true);
4949
logger.Batch("generating contributions");
5050
if (!blsWorker.GenerateContributions(params.threshold, memberIds, vvecContribution, m_sk_contributions)) {

src/llmq/dkgsession.cpp

Lines changed: 84 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <array>
2626
#include <atomic>
2727
#include <memory>
28+
#include <type_traits>
2829

2930
namespace llmq {
3031
CDKGLogger::CDKGLogger(const CDKGSession& _quorumDkg, std::string_view _func, int source_line) :
@@ -197,56 +198,27 @@ bool CDKGSession::PreVerifyMessage(const CDKGContribution& qc, bool& retBan) con
197198
return true;
198199
}
199200

200-
// TODO: remove duplicated code between all ReceiveMessage: CDKGContribution, CDKGComplaint, CDKGJustification, CDKGPrematureCommitment
201201
std::optional<CInv> CDKGSession::ReceiveMessage(const CDKGContribution& qc)
202202
{
203203
CDKGLogger logger(*this, __func__, __LINE__);
204-
205-
auto* member = GetMember(qc.proTxHash);
206-
207204
cxxtimer::Timer t1(true);
208-
logger.Batch("received contribution from %s", qc.proTxHash.ToString());
209205

210-
// relay, no matter if further verification fails
211-
// This ensures the whole quorum sees the bad behavior
212-
213-
if (member->contributions.size() >= 2) {
214-
// only relay up to 2 contributions, that's enough to let the other members know about his bad behavior
215-
return std::nullopt;
216-
}
217-
218-
const uint256 hash = ::SerializeHash(qc);
219-
WITH_LOCK(invCs, contributions.emplace(hash, qc));
220-
member->contributions.emplace(hash);
221-
222-
CInv inv(MSG_QUORUM_CONTRIB, hash);
223-
224-
dkgDebugManager.UpdateLocalMemberStatus(params.type, quorumIndex, member->idx, [&](CDKGDebugMemberStatus& status) {
225-
status.statusBits.receivedContribution = true;
226-
return true;
227-
});
228-
229-
if (member->contributions.size() > 1) {
230-
// don't do any further processing if we got more than 1 contribution. we already relayed it,
231-
// so others know about his bad behavior
232-
MarkBadMember(member->idx);
233-
logger.Batch("%s did send multiple contributions", member->dmn->proTxHash.ToString());
234-
return inv;
235-
}
206+
auto state = WITH_LOCK(invCs, return ReceiveMessagePreamble(qc, MsgPhase::Contribution, logger));
207+
if (!state) return std::nullopt;
208+
auto& [member, hash, inv, should_process] = *state;
209+
if (!should_process) return inv;
236210

237211
receivedVvecs[member->idx] = qc.vvec;
238212

239213
int receivedCount = ranges::count_if(members, [](const auto& m){return !m->contributions.empty();});
240214

241215
logger.Batch("received and relayed contribution. received=%d/%d, time=%d", receivedCount, members.size(), t1.count());
242216

243-
cxxtimer::Timer t2(true);
244-
245217
if (!AreWeMember()) {
246-
// can't further validate
247218
return inv;
248219
}
249220

221+
cxxtimer::Timer t2(true);
250222
dkgManager.WriteVerifiedVvecContribution(params.type, m_quorum_base_block_index, qc.proTxHash, qc.vvec);
251223

252224
bool complain = false;
@@ -327,33 +299,10 @@ std::optional<CInv> CDKGSession::ReceiveMessage(const CDKGComplaint& qc)
327299
{
328300
CDKGLogger logger(*this, __func__, __LINE__);
329301

330-
logger.Batch("received complaint from %s", qc.proTxHash.ToString());
331-
332-
auto* member = GetMember(qc.proTxHash);
333-
334-
if (member->complaints.size() >= 2) {
335-
// only relay up to 2 complaints, that's enough to let the other members know about his bad behavior
336-
return std::nullopt;
337-
}
338-
339-
const uint256 hash = ::SerializeHash(qc);
340-
WITH_LOCK(invCs, complaints.emplace(hash, qc));
341-
member->complaints.emplace(hash);
342-
343-
CInv inv(MSG_QUORUM_COMPLAINT, hash);
344-
345-
dkgDebugManager.UpdateLocalMemberStatus(params.type, quorumIndex, member->idx, [&](CDKGDebugMemberStatus& status) {
346-
status.statusBits.receivedComplaint = true;
347-
return true;
348-
});
349-
350-
if (member->complaints.size() > 1) {
351-
// don't do any further processing if we got more than 1 complaint. we already relayed it,
352-
// so others know about his bad behavior
353-
MarkBadMember(member->idx);
354-
logger.Batch("%s did send multiple complaints", member->dmn->proTxHash.ToString());
355-
return inv;
356-
}
302+
auto state = WITH_LOCK(invCs, return ReceiveMessagePreamble(qc, MsgPhase::Complaint, logger));
303+
if (!state) return std::nullopt;
304+
auto& [member, hash, inv, should_process] = *state;
305+
if (!should_process) return inv;
357306

358307
int receivedCount = 0;
359308
for (const auto i : irange::range(members.size())) {
@@ -447,34 +396,10 @@ std::optional<CInv> CDKGSession::ReceiveMessage(const CDKGJustification& qj)
447396
{
448397
CDKGLogger logger(*this, __func__, __LINE__);
449398

450-
logger.Batch("received justification from %s", qj.proTxHash.ToString());
451-
452-
auto* member = GetMember(qj.proTxHash);
453-
454-
if (member->justifications.size() >= 2) {
455-
// only relay up to 2 justifications, that's enough to let the other members know about his bad behavior
456-
return std::nullopt;
457-
}
458-
459-
const uint256 hash = ::SerializeHash(qj);
460-
WITH_LOCK(invCs, justifications.emplace(hash, qj));
461-
member->justifications.emplace(hash);
462-
463-
// we always relay, even if further verification fails
464-
CInv inv(MSG_QUORUM_JUSTIFICATION, hash);
465-
466-
dkgDebugManager.UpdateLocalMemberStatus(params.type, quorumIndex, member->idx, [&](CDKGDebugMemberStatus& status) {
467-
status.statusBits.receivedJustification = true;
468-
return true;
469-
});
470-
471-
if (member->justifications.size() > 1) {
472-
// don't do any further processing if we got more than 1 justification. we already relayed it,
473-
// so others know about his bad behavior
474-
logger.Batch("%s did send multiple justifications", member->dmn->proTxHash.ToString());
475-
MarkBadMember(member->idx);
476-
return inv;
477-
}
399+
auto state = WITH_LOCK(invCs, return ReceiveMessagePreamble(qj, MsgPhase::Justification, logger));
400+
if (!state) return std::nullopt;
401+
auto& [member, hash, inv, should_process] = *state;
402+
if (!should_process) return inv;
478403

479404
if (member->bad) {
480405
// we locally determined him to be bad (sent none or more then one contributions)
@@ -683,6 +608,76 @@ CDKGMember* CDKGSession::GetMember(const uint256& proTxHash) const
683608
return members[it->second].get();
684609
}
685610

611+
template <typename MsgType>
612+
std::optional<CDKGSession::ReceiveMessageState> CDKGSession::ReceiveMessagePreamble(const MsgType& msg, MsgPhase phase, CDKGLogger& logger)
613+
{
614+
auto* member = GetMember(msg.proTxHash);
615+
616+
GetDataMsg inv_type{0};
617+
std::string msg_name;
618+
619+
// Select member set, inv type, and name based on phase
620+
auto& member_set = [&]() -> Uint256HashSet& {
621+
switch (phase) {
622+
case MsgPhase::Contribution:
623+
inv_type = MSG_QUORUM_CONTRIB;
624+
msg_name = "contribution";
625+
return member->contributions;
626+
case MsgPhase::Complaint:
627+
inv_type = MSG_QUORUM_COMPLAINT;
628+
msg_name = "complaint";
629+
return member->complaints;
630+
case MsgPhase::Justification:
631+
inv_type = MSG_QUORUM_JUSTIFICATION;
632+
msg_name = "justification";
633+
return member->justifications;
634+
}
635+
assert(false);
636+
}();
637+
638+
logger.Batch("received %s from %s", msg_name, msg.proTxHash.ToString());
639+
640+
if (member_set.size() >= 2) {
641+
// only relay up to 2 justifications, that's enough to let the other members know about his bad behavior
642+
return std::nullopt;
643+
}
644+
645+
const uint256 hash = ::SerializeHash(msg);
646+
member_set.emplace(hash);
647+
if constexpr (std::is_same_v<MsgType, CDKGContribution>) {
648+
contributions.emplace(hash, msg);
649+
} else if constexpr (std::is_same_v<MsgType, CDKGComplaint>) {
650+
complaints.emplace(hash, msg);
651+
} else if constexpr (std::is_same_v<MsgType, CDKGJustification>) {
652+
justifications.emplace(hash, msg);
653+
}
654+
655+
dkgDebugManager.UpdateLocalMemberStatus(params.type, quorumIndex, member->idx, [phase](CDKGDebugMemberStatus& status) {
656+
switch (phase) {
657+
case MsgPhase::Contribution: status.statusBits.receivedContribution = true; break;
658+
case MsgPhase::Complaint: status.statusBits.receivedComplaint = true; break;
659+
case MsgPhase::Justification: status.statusBits.receivedJustification = true; break;
660+
}
661+
return true;
662+
});
663+
664+
bool should_process{true};
665+
if (member_set.size() > 1) {
666+
// don't do any further processing if we got more than 1 justification. we already relayed it,
667+
// so others know about his bad behavior
668+
MarkBadMember(member->idx);
669+
logger.Batch("%s did send multiple %ss", member->dmn->proTxHash.ToString(), msg_name);
670+
should_process = false;
671+
}
672+
673+
// we always relay, even if further verification fails
674+
return ReceiveMessageState{member, hash, CInv{inv_type, hash}, should_process};
675+
}
676+
677+
template std::optional<CDKGSession::ReceiveMessageState> CDKGSession::ReceiveMessagePreamble<CDKGContribution>(const CDKGContribution&, MsgPhase, CDKGLogger&);
678+
template std::optional<CDKGSession::ReceiveMessageState> CDKGSession::ReceiveMessagePreamble<CDKGComplaint>(const CDKGComplaint&, MsgPhase, CDKGLogger&);
679+
template std::optional<CDKGSession::ReceiveMessageState> CDKGSession::ReceiveMessagePreamble<CDKGJustification>(const CDKGJustification&, MsgPhase, CDKGLogger&);
680+
686681
void CDKGSession::MarkBadMember(size_t idx)
687682
{
688683
auto* member = members.at(idx).get();

src/llmq/dkgsession.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define BITCOIN_LLMQ_DKGSESSION_H
77

88
#include <llmq/commitment.h>
9+
#include <protocol.h>
910

1011
#include <batchedlogger.h>
1112
#include <bls/bls.h>
@@ -21,7 +22,6 @@
2122
#include <unordered_set>
2223

2324
class CActiveMasternodeManager;
24-
class CInv;
2525
class CConnman;
2626
class CDeterministicMN;
2727
class CMasternodeMetaMan;
@@ -281,6 +281,20 @@ class CDKGSession
281281
friend class CDKGSessionManager;
282282
friend class CDKGLogger;
283283

284+
private:
285+
enum class MsgPhase : uint8_t {
286+
Contribution,
287+
Complaint,
288+
Justification
289+
};
290+
291+
struct ReceiveMessageState {
292+
CDKGMember* member;
293+
uint256 hash;
294+
CInv inv;
295+
bool should_process;
296+
};
297+
284298
private:
285299
CBLSWorker& blsWorker;
286300
CBLSWorkerCache cache;
@@ -400,12 +414,16 @@ class CDKGSession
400414

401415
private:
402416
[[nodiscard]] bool ShouldSimulateError(DKGError::type type) const;
417+
418+
template <typename MsgType>
419+
[[nodiscard]] std::optional<ReceiveMessageState> ReceiveMessagePreamble(const MsgType& msg, MsgPhase phase, CDKGLogger& logger)
420+
EXCLUSIVE_LOCKS_REQUIRED(invCs);
421+
403422
void MarkBadMember(size_t idx);
404423
};
405424

406425
void SetSimulatedDKGErrorRate(DKGError::type type, double rate);
407426
double GetSimulatedErrorRate(DKGError::type type);
408-
409427
} // namespace llmq
410428

411429
#endif // BITCOIN_LLMQ_DKGSESSION_H

0 commit comments

Comments
 (0)