Skip to content

Commit 22ea97d

Browse files
committed
refactor: use new NetHandler for llmq/signing module
1 parent 4bbdc7f commit 22ea97d

File tree

12 files changed

+305
-240
lines changed

12 files changed

+305
-240
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ BITCOIN_CORE_H = \
273273
llmq/quorums.h \
274274
llmq/signhash.h \
275275
llmq/signing.h \
276+
llmq/net_signing.h \
276277
llmq/signing_shares.h \
277278
llmq/snapshot.h \
278279
llmq/types.h \
@@ -535,6 +536,7 @@ libbitcoin_node_a_SOURCES = \
535536
llmq/dkgsessionhandler.cpp \
536537
llmq/dkgsessionmgr.cpp \
537538
llmq/ehf_signals.cpp \
539+
llmq/net_signing.cpp \
538540
llmq/options.cpp \
539541
llmq/quorums.cpp \
540542
llmq/signhash.cpp \

src/init.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
#include <llmq/context.h>
9494
#include <llmq/dkgsessionmgr.h>
9595
#include <llmq/options.h>
96+
#include <llmq/net_signing.h>
9697
#include <llmq/signing.h>
9798
#include <masternode/active/context.h>
9899
#include <masternode/active/notificationinterface.h>
@@ -2203,6 +2204,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
22032204
RegisterValidationInterface(g_active_notification_interface.get());
22042205
}
22052206
node.peerman->AddExtraHandler(std::make_unique<NetInstantSend>(node.peerman.get(), *node.llmq_ctx->isman, *node.llmq_ctx->qman, chainman.ActiveChainstate()));
2207+
node.peerman->AddExtraHandler(std::make_unique<NetSigning>(node.peerman.get(), *node.llmq_ctx->sigman));
22062208

22072209
// ********************************************************* Step 7d: Setup other Dash services
22082210

src/llmq/context.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ LLMQContext::LLMQContext(ChainstateManager& chainman, CDeterministicMNManager& d
3030
qman{std::make_unique<llmq::CQuorumManager>(*bls_worker, chainman.ActiveChainstate(), dmnman, *qdkgsman, evo_db,
3131
*quorum_block_processor, *qsnapman, mn_activeman, mn_sync, sporkman,
3232
db_params)},
33-
sigman{std::make_unique<llmq::CSigningManager>(chainman.ActiveChainstate(), *qman, db_params)},
33+
sigman{std::make_unique<llmq::CSigningManager>(*qman, db_params)},
3434
clhandler{std::make_unique<llmq::CChainLocksHandler>(chainman.ActiveChainstate(), *qman, sporkman, mempool, mn_sync)},
3535
isman{std::make_unique<llmq::CInstantSendManager>(*clhandler, chainman.ActiveChainstate(), *sigman, sporkman,
3636
mempool, mn_sync, db_params)}
@@ -44,19 +44,16 @@ LLMQContext::~LLMQContext() {
4444
}
4545

4646
void LLMQContext::Interrupt() {
47-
sigman->InterruptWorkerThread();
4847
}
4948

5049
void LLMQContext::Start(PeerManager& peerman)
5150
{
5251
qman->Start();
53-
sigman->StartWorkerThread(peerman);
5452
clhandler->Start(*isman);
5553
}
5654

5755
void LLMQContext::Stop()
5856
{
5957
clhandler->Stop();
60-
sigman->StopWorkerThread();
6158
qman->Stop();
6259
}

src/llmq/net_signing.cpp

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// Copyright (c) 2025 The Dash Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <llmq/net_signing.h>
6+
7+
#include <llmq/commitment.h>
8+
#include <llmq/quorums.h>
9+
#include <llmq/signhash.h>
10+
#include <llmq/signing.h>
11+
12+
#include <bls/bls_batchverifier.h>
13+
#include <cxxtimer.hpp>
14+
#include <logging.h>
15+
#include <streams.h>
16+
#include <util/thread.h>
17+
#include <validationinterface.h>
18+
19+
#include <unordered_map>
20+
21+
static bool PreVerifyRecoveredSig(Consensus::LLMQType& llmqType, const llmq::CQuorumManager& quorum_manager,
22+
const llmq::CRecoveredSig& recoveredSig)
23+
{
24+
auto quorum = quorum_manager.GetQuorum(llmqType, recoveredSig.getQuorumHash());
25+
26+
if (!quorum) {
27+
LogPrint(BCLog::LLMQ, "NetSigning::%s -- quorum %s not found\n", __func__, recoveredSig.getQuorumHash().ToString());
28+
return false;
29+
}
30+
if (!llmq::IsQuorumActive(llmqType, quorum_manager, quorum->qc->quorumHash)) {
31+
return false;
32+
}
33+
34+
return true;
35+
}
36+
37+
void NetSigning::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv)
38+
{
39+
if (msg_type != NetMsgType::QSIGREC) return;
40+
41+
auto recoveredSig = std::make_shared<llmq::CRecoveredSig>();
42+
vRecv >> *recoveredSig;
43+
44+
WITH_LOCK(cs_main, m_peer_manager->PeerEraseObjectRequest(pfrom.GetId(),
45+
CInv{MSG_QUORUM_RECOVERED_SIG, recoveredSig->GetHash()}));
46+
47+
auto llmqType = recoveredSig->getLlmqType();
48+
if (!Params().GetLLMQ(llmqType).has_value()) {
49+
m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100);
50+
}
51+
if (!PreVerifyRecoveredSig(llmqType, m_sig_manager.Qman(), *recoveredSig)) {
52+
return;
53+
}
54+
55+
m_sig_manager.ProcessRecoveredSig(pfrom.GetId(), std::move(recoveredSig));
56+
}
57+
58+
void NetSigning::Start()
59+
{
60+
// can't start new thread if we have one running already
61+
if (workThread.joinable()) {
62+
assert(false);
63+
}
64+
65+
workThread = std::thread(&util::TraceThread, "recsigs", [this] { WorkThreadMain(); });
66+
}
67+
68+
void NetSigning::Stop()
69+
{
70+
// make sure to call InterruptWorkerThread() first
71+
if (!workInterrupt) {
72+
assert(false);
73+
}
74+
75+
if (workThread.joinable()) {
76+
workThread.join();
77+
}
78+
}
79+
80+
void NetSigning::ProcessRecoveredSig(std::shared_ptr<const llmq::CRecoveredSig> recoveredSig, bool consider_proactive_relay)
81+
{
82+
if (!m_sig_manager.ProcessRecoveredSig(recoveredSig)) return;
83+
84+
auto listeners = m_sig_manager.GetListeners();
85+
for (auto& l : listeners) {
86+
m_peer_manager->PeerPostProcessMessage(l->HandleNewRecoveredSig(*recoveredSig));
87+
}
88+
89+
// TODO refactor to use a better abstraction analogous to IsAllMembersConnectedEnabled
90+
auto proactive_relay = consider_proactive_relay && recoveredSig->getLlmqType() != Consensus::LLMQType::LLMQ_100_67 &&
91+
recoveredSig->getLlmqType() != Consensus::LLMQType::LLMQ_400_60 &&
92+
recoveredSig->getLlmqType() != Consensus::LLMQType::LLMQ_400_85;
93+
GetMainSignals().NotifyRecoveredSig(recoveredSig, recoveredSig->GetHash().ToString(), proactive_relay);
94+
}
95+
96+
bool NetSigning::ProcessPendingRecoveredSigs()
97+
{
98+
Uint256HashMap<std::shared_ptr<const llmq::CRecoveredSig>> pending{m_sig_manager.FetchPendingReconstructed()};
99+
100+
for (const auto& p : pending) {
101+
ProcessRecoveredSig(p.second, true);
102+
}
103+
104+
std::unordered_map<NodeId, std::list<std::shared_ptr<const llmq::CRecoveredSig>>> recSigsByNode;
105+
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, llmq::CQuorumCPtr, StaticSaltedHasher> quorums;
106+
107+
const size_t nMaxBatchSize{32};
108+
bool more_work = m_sig_manager.CollectPendingRecoveredSigsToVerify(nMaxBatchSize, recSigsByNode, quorums);
109+
if (recSigsByNode.empty()) {
110+
return false;
111+
}
112+
113+
// It's ok to perform insecure batched verification here as we verify against the quorum public keys, which are not
114+
// craftable by individual entities, making the rogue public key attack impossible
115+
CBLSBatchVerifier<NodeId, uint256> batchVerifier(false, false);
116+
117+
size_t verifyCount = 0;
118+
for (const auto& p : recSigsByNode) {
119+
NodeId nodeId = p.first;
120+
const auto& v = p.second;
121+
122+
for (const auto& recSig : v) {
123+
// we didn't verify the lazy signature until now
124+
if (!recSig->sig.Get().IsValid()) {
125+
batchVerifier.badSources.emplace(nodeId);
126+
break;
127+
}
128+
129+
const auto& quorum = quorums.at(std::make_pair(recSig->getLlmqType(), recSig->getQuorumHash()));
130+
batchVerifier.PushMessage(nodeId, recSig->GetHash(), recSig->buildSignHash().Get(), recSig->sig.Get(),
131+
quorum->qc->quorumPublicKey);
132+
verifyCount++;
133+
}
134+
}
135+
136+
cxxtimer::Timer verifyTimer(true);
137+
batchVerifier.Verify();
138+
verifyTimer.stop();
139+
140+
LogPrint(BCLog::LLMQ, "CSigningManager::%s -- verified recovered sig(s). count=%d, vt=%d, nodes=%d\n", __func__,
141+
verifyCount, verifyTimer.count(), recSigsByNode.size());
142+
143+
Uint256HashSet processed;
144+
for (const auto& p : recSigsByNode) {
145+
NodeId nodeId = p.first;
146+
const auto& v = p.second;
147+
148+
if (batchVerifier.badSources.count(nodeId)) {
149+
LogPrint(BCLog::LLMQ, "CSigningManager::%s -- invalid recSig from other node, banning peer=%d\n", __func__,
150+
nodeId);
151+
m_peer_manager->PeerMisbehaving(nodeId, 100);
152+
continue;
153+
}
154+
155+
for (const auto& recSig : v) {
156+
if (!processed.emplace(recSig->GetHash()).second) {
157+
continue;
158+
}
159+
160+
ProcessRecoveredSig(recSig, nodeId == -1);
161+
}
162+
}
163+
164+
return more_work;
165+
}
166+
167+
void NetSigning::WorkThreadMain()
168+
{
169+
while (!workInterrupt) {
170+
bool fMoreWork = ProcessPendingRecoveredSigs();
171+
172+
m_sig_manager.Cleanup();
173+
174+
// TODO Wakeup when pending signing is needed?
175+
if (!fMoreWork && !workInterrupt.sleep_for(std::chrono::milliseconds(100))) {
176+
return;
177+
}
178+
}
179+
}

src/llmq/net_signing.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) 2025 The Dash Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_LLMQ_NET_SIGNING_H
6+
#define BITCOIN_LLMQ_NET_SIGNING_H
7+
8+
#include <net_processing.h>
9+
10+
#include <util/threadinterrupt.h>
11+
12+
#include <thread>
13+
14+
namespace llmq {
15+
class CSigningManager;
16+
} // namespace llmq
17+
18+
class NetSigning final : public NetHandler
19+
{
20+
public:
21+
NetSigning(PeerManagerInternal* peer_manager, llmq::CSigningManager& sig_manager) :
22+
NetHandler(peer_manager),
23+
m_sig_manager(sig_manager)
24+
{
25+
workInterrupt.reset();
26+
}
27+
void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) override;
28+
29+
bool ProcessPendingRecoveredSigs();
30+
void ProcessRecoveredSig(std::shared_ptr<const llmq::CRecoveredSig> recoveredSig, bool consider_proactive_relay);
31+
32+
void Start() override;
33+
void Stop() override;
34+
void Interrupt() override { workInterrupt(); };
35+
36+
void WorkThreadMain();
37+
38+
private:
39+
llmq::CSigningManager& m_sig_manager;
40+
41+
std::thread workThread;
42+
CThreadInterrupt workInterrupt;
43+
};
44+
45+
#endif // BITCOIN_LLMQ_NET_SIGNING_H

0 commit comments

Comments
 (0)