Line data Source code
1 : // Copyright (c) 2018-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 <active/dkgsessionhandler.h>
6 :
7 : #include <active/dkgsession.h>
8 : #include <active/masternode.h>
9 : #include <llmq/debug.h>
10 : #include <llmq/dkgsession.h>
11 : #include <llmq/net_quorum.h>
12 :
13 : #include <chainparams.h>
14 : #include <deploymentstatus.h>
15 : #include <logging.h>
16 : #include <util/time.h>
17 :
18 : namespace llmq {
19 7920 : ActiveDKGSessionHandler::ActiveDKGSessionHandler(
20 : CBLSWorker& bls_worker, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman,
21 : llmq::CDKGDebugManager& dkgdbgman, llmq::CDKGSessionManager& qdkgsman, llmq::CQuorumBlockProcessor& qblockman,
22 : llmq::CQuorumSnapshotManager& qsnapman, const CActiveMasternodeManager& mn_activeman, const ChainstateManager& chainman,
23 : const CSporkManager& sporkman, const Consensus::LLMQParams& llmq_params, bool quorums_watch, int quorums_idx) :
24 3960 : llmq::CDKGSessionHandler(llmq_params),
25 3960 : m_bls_worker{bls_worker},
26 3960 : m_dmnman{dmnman},
27 3960 : m_mn_metaman{mn_metaman},
28 3960 : m_dkgdbgman{dkgdbgman},
29 3960 : m_qdkgsman{qdkgsman},
30 3960 : m_qblockman{qblockman},
31 3960 : m_qsnapman{qsnapman},
32 3960 : m_mn_activeman{mn_activeman},
33 3960 : m_chainman{chainman},
34 3960 : m_sporkman{sporkman},
35 3960 : m_quorums_watch{quorums_watch},
36 3960 : quorumIndex{quorums_idx}
37 7920 : {
38 3960 : }
39 :
40 11880 : ActiveDKGSessionHandler::~ActiveDKGSessionHandler() = default;
41 :
42 341916 : void ActiveDKGSessionHandler::UpdatedBlockTip(const CBlockIndex* pindexNew)
43 : {
44 : //AssertLockNotHeld(cs_main);
45 : //Indexed quorums (greater than 0) are enabled with Quorum Rotation
46 341916 : if (quorumIndex > 0 && !IsQuorumRotationEnabled(params, pindexNew)) {
47 1026 : return;
48 : }
49 340890 : LOCK(cs_phase_qhash);
50 :
51 340890 : int quorumStageInt = (pindexNew->nHeight - quorumIndex) % params.dkgInterval;
52 :
53 340890 : const CBlockIndex* pQuorumBaseBlockIndex = pindexNew->GetAncestor(pindexNew->nHeight - quorumStageInt);
54 :
55 340890 : currentHeight = pindexNew->nHeight;
56 340890 : quorumHash = pQuorumBaseBlockIndex->GetBlockHash();
57 :
58 340890 : bool fNewPhase = (quorumStageInt % params.dkgPhaseBlocks) == 0;
59 340890 : int phaseInt = quorumStageInt / params.dkgPhaseBlocks + 1;
60 340890 : QuorumPhase oldPhase = phase;
61 340890 : if (fNewPhase && phaseInt >= std23::to_underlying(QuorumPhase::Initialized) && phaseInt <= std23::to_underlying(QuorumPhase::Idle)) {
62 97863 : phase = static_cast<QuorumPhase>(phaseInt);
63 97863 : }
64 :
65 340890 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] currentHeight=%d, pQuorumBaseBlockIndex->nHeight=%d, oldPhase=%d, newPhase=%d\n", __func__,
66 : params.name, quorumIndex, currentHeight, pQuorumBaseBlockIndex->nHeight, std23::to_underlying(oldPhase), std23::to_underlying(phase));
67 341916 : }
68 :
69 22086 : uint256 ActiveDKGSessionHandler::GetCurrentQuorumHash() const { return WITH_LOCK(cs_phase_qhash, return quorumHash); }
70 :
71 1340066 : std::pair<QuorumPhase, uint256> ActiveDKGSessionHandler::GetPhaseAndQuorumHash() const
72 : {
73 1340066 : LOCK(cs_phase_qhash);
74 1340066 : return std::make_pair(phase, quorumHash);
75 1340066 : }
76 :
77 11043 : bool ActiveDKGSessionHandler::InitNewQuorum(gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex)
78 : {
79 11043 : if (!DeploymentDIP0003Enforced(pQuorumBaseBlockIndex->nHeight, Params().GetConsensus())) {
80 0 : return false;
81 : }
82 :
83 22086 : curSession = std::make_unique<ActiveDKGSession>(m_bls_worker, m_dmnman, m_dkgdbgman, m_qdkgsman, m_mn_metaman,
84 11043 : m_qsnapman, m_mn_activeman, m_chainman, m_sporkman,
85 11043 : pQuorumBaseBlockIndex, params);
86 :
87 11043 : if (!curSession->Init(m_mn_activeman.GetProTxHash(), quorumIndex)) {
88 6170 : LogPrintf("ActiveDKGSessionHandler::%s -- height[%d] quorum initialization failed for %s qi[%d]\n", __func__,
89 : pQuorumBaseBlockIndex->nHeight, params.name, quorumIndex);
90 6170 : return false;
91 : }
92 :
93 4873 : LogPrintf("ActiveDKGSessionHandler::%s -- height[%d] quorum initialization OK for %s qi[%d]\n", __func__, pQuorumBaseBlockIndex->nHeight, params.name, quorumIndex);
94 4873 : return true;
95 11043 : }
96 :
97 34581 : void ActiveDKGSessionHandler::WaitForNextPhase(std::optional<QuorumPhase> curPhase, QuorumPhase nextPhase,
98 : const uint256& expectedQuorumHash, const WhileWaitFunc& shouldNotWait) const
99 : {
100 34581 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - starting, curPhase=%d, nextPhase=%d\n", __func__, params.name, quorumIndex, curPhase.has_value() ? std23::to_underlying(*curPhase) : -1, std23::to_underlying(nextPhase));
101 :
102 894123 : while (true) {
103 894123 : if (stopRequested) {
104 2755 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - aborting due to stop/shutdown requested\n", __func__, params.name, quorumIndex);
105 2755 : throw AbortPhaseException();
106 : }
107 1075425 : auto [_phase, _quorumHash] = GetPhaseAndQuorumHash();
108 891368 : if (!expectedQuorumHash.IsNull() && _quorumHash != expectedQuorumHash) {
109 67 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - aborting due unexpected expectedQuorumHash change\n", __func__, params.name, quorumIndex);
110 67 : throw AbortPhaseException();
111 : }
112 891301 : if (_phase == nextPhase) {
113 30866 : break;
114 : }
115 860435 : if (curPhase.has_value() && _phase != curPhase) {
116 893 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - aborting due unexpected phase change, _phase=%d, curPhase=%d\n", __func__, params.name, quorumIndex, std23::to_underlying(_phase), curPhase.has_value() ? std23::to_underlying(*curPhase) : -1);
117 893 : throw AbortPhaseException();
118 : }
119 859542 : if (!shouldNotWait()) {
120 845533 : UninterruptibleSleep(std::chrono::milliseconds{100});
121 845533 : }
122 : }
123 :
124 30866 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - done, curPhase=%d, nextPhase=%d\n", __func__, params.name, quorumIndex, curPhase.has_value() ? std23::to_underlying(*curPhase) : -1, std23::to_underlying(nextPhase));
125 :
126 30866 : if (nextPhase == QuorumPhase::Initialized) {
127 11043 : m_dkgdbgman.ResetLocalSessionStatus(params.type, quorumIndex);
128 11043 : } else {
129 31869 : m_dkgdbgman.UpdateLocalSessionStatus(params.type, quorumIndex, [&](CDKGDebugSessionStatus& status) {
130 12046 : bool changed = status.phase != nextPhase;
131 12046 : status.phase = nextPhase;
132 12046 : return changed;
133 : });
134 : }
135 30866 : }
136 :
137 6170 : void ActiveDKGSessionHandler::WaitForNewQuorum(const uint256& oldQuorumHash) const
138 : {
139 6170 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d]- starting\n", __func__, params.name, quorumIndex);
140 :
141 450273 : while (true) {
142 450273 : if (stopRequested) {
143 1205 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - aborting due to stop/shutdown requested\n", __func__, params.name, quorumIndex);
144 1205 : throw AbortPhaseException();
145 : }
146 449068 : auto [_, _quorumHash] = GetPhaseAndQuorumHash();
147 449068 : if (_quorumHash != oldQuorumHash) {
148 4965 : break;
149 : }
150 444103 : UninterruptibleSleep(std::chrono::milliseconds{100});
151 : }
152 :
153 4965 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - done\n", __func__, params.name, quorumIndex);
154 4965 : }
155 :
156 : // Sleep some time to not fully overload the whole network
157 16071 : void ActiveDKGSessionHandler::SleepBeforePhase(QuorumPhase curPhase, const uint256& expectedQuorumHash,
158 : double randomSleepFactor, const WhileWaitFunc& runWhileWaiting) const
159 : {
160 16071 : if (!curSession->AreWeMember()) {
161 : // Non-members do not participate and do not create any network load, no need to sleep.
162 6289 : return;
163 : }
164 :
165 9782 : if (Params().MineBlocksOnDemand()) {
166 : // On regtest, blocks can be mined on demand without any significant time passing between these.
167 : // We shouldn't wait before phases in this case.
168 9782 : return;
169 : }
170 :
171 : // Two blocks can come very close to each other, this happens pretty regularly. We don't want to be
172 : // left behind and marked as a bad member. This means that we should not count the last block of the
173 : // phase as a safe one to keep sleeping, that's why we calculate the phase sleep time as a time of
174 : // the full phase minus one block here.
175 0 : double phaseSleepTime = (params.dkgPhaseBlocks - 1) * Params().GetConsensus().nPowTargetSpacing * 1000;
176 : // Expected phase sleep time per member
177 0 : double phaseSleepTimePerMember = phaseSleepTime / params.size;
178 : // Don't expect perfect block times and thus reduce the phase time to be on the secure side (caller chooses factor)
179 0 : double adjustedPhaseSleepTimePerMember = phaseSleepTimePerMember * randomSleepFactor;
180 :
181 0 : int64_t sleepTime = (int64_t)(adjustedPhaseSleepTimePerMember * curSession->GetMyMemberIndex().value_or(0));
182 0 : const auto endTime = SteadyClock::now() + std::chrono::milliseconds{sleepTime};
183 0 : int heightTmp{currentHeight.load()};
184 0 : int heightStart{heightTmp};
185 :
186 0 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - starting sleep for %d ms, curPhase=%d\n", __func__, params.name, quorumIndex, sleepTime, std23::to_underlying(curPhase));
187 :
188 0 : while (SteadyClock::now() < endTime) {
189 0 : if (stopRequested) {
190 0 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - aborting due to stop/shutdown requested\n", __func__, params.name, quorumIndex);
191 0 : throw AbortPhaseException();
192 : }
193 0 : auto cur_height = currentHeight.load();
194 0 : if (cur_height > heightTmp) {
195 : // New block(s) just came in
196 0 : int64_t expectedBlockTime = (cur_height - heightStart) * Params().GetConsensus().nPowTargetSpacing * 1000;
197 0 : if (expectedBlockTime > sleepTime) {
198 : // Blocks came faster than we expected, jump into the phase func asap
199 0 : break;
200 : }
201 0 : heightTmp = cur_height;
202 0 : }
203 0 : if (WITH_LOCK(cs_phase_qhash, return phase != curPhase || quorumHash != expectedQuorumHash)) {
204 : // Something went wrong and/or we missed quite a few blocks and it's just too late now
205 0 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - aborting due unexpected phase/expectedQuorumHash change\n", __func__, params.name, quorumIndex);
206 0 : throw AbortPhaseException();
207 : }
208 0 : if (!runWhileWaiting()) {
209 0 : UninterruptibleSleep(std::chrono::milliseconds{100});
210 0 : }
211 : }
212 :
213 0 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - done, curPhase=%d\n", __func__, params.name, quorumIndex, std23::to_underlying(curPhase));
214 16071 : }
215 :
216 16071 : void ActiveDKGSessionHandler::HandlePhase(QuorumPhase curPhase, QuorumPhase nextPhase,
217 : const uint256& expectedQuorumHash, double randomSleepFactor,
218 : const StartPhaseFunc& startPhaseFunc, const WhileWaitFunc& runWhileWaiting)
219 : {
220 16071 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - starting, curPhase=%d, nextPhase=%d\n", __func__, params.name, quorumIndex, std23::to_underlying(curPhase), std23::to_underlying(nextPhase));
221 :
222 16071 : SleepBeforePhase(curPhase, expectedQuorumHash, randomSleepFactor, runWhileWaiting);
223 16071 : startPhaseFunc();
224 16071 : WaitForNextPhase(curPhase, nextPhase, expectedQuorumHash, runWhileWaiting);
225 :
226 16071 : LogPrint(BCLog::LLMQ_DKG, "ActiveDKGSessionHandler::%s -- %s qi[%d] - done, curPhase=%d, nextPhase=%d\n", __func__, params.name, quorumIndex, std23::to_underlying(curPhase), std23::to_underlying(nextPhase));
227 16071 : }
228 :
229 13037 : bool ActiveDKGSessionHandler::GetContribution(const uint256& hash, CDKGContribution& ret) const
230 : {
231 13037 : return curSession && curSession->GetContribution(hash, ret);
232 : }
233 :
234 1629 : bool ActiveDKGSessionHandler::GetComplaint(const uint256& hash, CDKGComplaint& ret) const
235 : {
236 1629 : return curSession && curSession->GetComplaint(hash, ret);
237 : }
238 :
239 16 : bool ActiveDKGSessionHandler::GetJustification(const uint256& hash, CDKGJustification& ret) const
240 : {
241 16 : return curSession && curSession->GetJustification(hash, ret);
242 : }
243 :
244 11235 : bool ActiveDKGSessionHandler::GetPrematureCommitment(const uint256& hash, CDKGPrematureCommitment& ret) const
245 : {
246 11235 : return curSession && curSession->GetPrematureCommitment(hash, ret);
247 : }
248 :
249 34707 : QuorumPhase ActiveDKGSessionHandler::GetPhase() const
250 : {
251 69414 : return WITH_LOCK(cs_phase_qhash, return phase);
252 : }
253 : } // namespace llmq
|