Line data Source code
1 : // Copyright (c) 2018-2021 The Bitcoin 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 <interfaces/node.h>
6 :
7 : #include <addrdb.h>
8 : #include <banman.h>
9 : #include <blockfilter.h>
10 : #include <chain.h>
11 : #include <chainlock/chainlock.h>
12 : #include <chainparams.h>
13 : #include <coinjoin/common.h>
14 : #include <deploymentstatus.h>
15 : #include <evo/chainhelper.h>
16 : #include <evo/creditpool.h>
17 : #include <evo/deterministicmns.h>
18 : #include <external_signer.h>
19 : #include <governance/governance.h>
20 : #include <governance/object.h>
21 : #include <governance/superblock.h>
22 : #include <governance/vote.h>
23 : #include <index/blockfilterindex.h>
24 : #include <init.h>
25 : #include <interfaces/chain.h>
26 : #include <interfaces/coinjoin.h>
27 : #include <interfaces/handler.h>
28 : #include <interfaces/wallet.h>
29 : #include <instantsend/instantsend.h>
30 : #include <llmq/commitment.h>
31 : #include <llmq/context.h>
32 : #include <llmq/options.h>
33 : #include <llmq/quorums.h>
34 : #include <llmq/quorumsman.h>
35 : #include <mapport.h>
36 : #include <masternode/sync.h>
37 : #include <net.h>
38 : #include <net_processing.h>
39 : #include <netaddress.h>
40 : #include <netbase.h>
41 : #include <node/blockstorage.h>
42 : #include <node/coin.h>
43 : #include <node/context.h>
44 : #include <node/interface_ui.h>
45 : #include <node/transaction.h>
46 : #include <policy/feerate.h>
47 : #include <policy/fees.h>
48 : #include <policy/policy.h>
49 : #include <policy/settings.h>
50 : #include <primitives/block.h>
51 : #include <primitives/transaction.h>
52 : #include <rpc/protocol.h>
53 : #include <rpc/server.h>
54 : #include <rpc/server_util.h>
55 : #include <shutdown.h>
56 : #include <support/allocators/secure.h>
57 : #include <sync.h>
58 : #include <txmempool.h>
59 : #include <uint256.h>
60 : #include <util/check.h>
61 : #include <util/system.h>
62 : #include <util/translation.h>
63 : #include <validation.h>
64 : #include <validationinterface.h>
65 : #include <warnings.h>
66 :
67 : #include <governance/common.h>
68 :
69 : #if defined(HAVE_CONFIG_H)
70 : #include <config/bitcoin-config.h>
71 : #endif
72 :
73 : #include <coinjoin/coinjoin.h>
74 : #include <coinjoin/options.h>
75 :
76 : #include <univalue.h>
77 :
78 : #include <boost/signals2/signal.hpp>
79 :
80 : #include <algorithm>
81 : #include <memory>
82 : #include <optional>
83 : #include <ranges>
84 : #include <utility>
85 : #include <variant>
86 :
87 : using interfaces::BlockTip;
88 : using interfaces::Chain;
89 : using interfaces::EVO;
90 : using interfaces::FoundBlock;
91 : using interfaces::GOV;
92 : using interfaces::Handler;
93 : using interfaces::LLMQ;
94 : using interfaces::MakeHandler;
95 : using interfaces::MnEntry;
96 : using interfaces::MnEntryCPtr;
97 : using interfaces::MnList;
98 : using interfaces::MnListPtr;
99 : using interfaces::Node;
100 : using interfaces::WalletLoader;
101 :
102 : namespace node {
103 : namespace {
104 : class MnEntryImpl : public MnEntry
105 : {
106 : private:
107 : CDeterministicMNCPtr m_dmn;
108 :
109 : public:
110 0 : MnEntryImpl(const CDeterministicMNCPtr& dmn) :
111 0 : MnEntry{dmn},
112 0 : m_dmn{Assert(dmn)}
113 0 : {
114 0 : }
115 0 : ~MnEntryImpl() = default;
116 :
117 0 : bool isBanned() const override { return m_dmn->pdmnState->IsBanned(); }
118 :
119 0 : CService getNetInfoPrimary() const override { return m_dmn->pdmnState->netInfo->GetPrimary(); }
120 0 : MnType getType() const override { return m_dmn->nType; }
121 0 : UniValue toJson() const override { return m_dmn->ToJson(); }
122 0 : const CKeyID& getKeyIdOwner() const override { return m_dmn->pdmnState->keyIDOwner; }
123 0 : const CKeyID& getKeyIdVoting() const override { return m_dmn->pdmnState->keyIDVoting; }
124 0 : const COutPoint& getCollateralOutpoint() const override { return m_dmn->collateralOutpoint; }
125 0 : const CScript& getScriptPayout() const override { return m_dmn->pdmnState->scriptPayout; }
126 0 : const CScript& getScriptOperatorPayout() const override { return m_dmn->pdmnState->scriptOperatorPayout; }
127 0 : const int32_t& getLastPaidHeight() const override { return m_dmn->pdmnState->nLastPaidHeight; }
128 0 : const int32_t& getPoSePenalty() const override { return m_dmn->pdmnState->nPoSePenalty; }
129 0 : const int32_t& getRegisteredHeight() const override { return m_dmn->pdmnState->nRegisteredHeight; }
130 0 : const uint16_t& getOperatorReward() const override { return m_dmn->nOperatorReward; }
131 0 : const uint256& getProTxHash() const override { return m_dmn->proTxHash; }
132 : };
133 :
134 0 : class MnListImpl : public MnList
135 : {
136 : private:
137 : CDeterministicMNList m_list;
138 :
139 : public:
140 0 : MnListImpl(const CDeterministicMNList& mn_list) :
141 0 : MnList{mn_list},
142 0 : m_list{mn_list}
143 0 : {
144 0 : }
145 0 : ~MnListImpl() = default;
146 :
147 0 : Counts getCounts() const override
148 : {
149 0 : const auto counts{m_list.GetCounts()};
150 0 : return {
151 0 : .m_total_evo = counts.m_total_evo,
152 0 : .m_total_mn = counts.m_total_mn,
153 0 : .m_total_weighted = counts.m_total_weighted,
154 0 : .m_valid_evo = counts.m_valid_evo,
155 0 : .m_valid_mn = counts.m_valid_mn,
156 0 : .m_valid_weighted = counts.m_valid_weighted,
157 : };
158 : }
159 0 : int32_t getHeight() const override { return m_list.GetHeight(); }
160 0 : uint256 getBlockHash() const override { return m_list.GetBlockHash(); }
161 :
162 0 : void forEachMN(bool only_valid, std::function<void(const MnEntryCPtr&)> cb) const override
163 : {
164 0 : m_list.ForEachMNShared(only_valid, [&cb](const auto& dmn) {
165 0 : cb(std::make_shared<const MnEntryImpl>(dmn));
166 0 : });
167 0 : }
168 0 : std::vector<MnEntryCPtr> getProjectedMNPayees(const CBlockIndex* pindex) const override
169 : {
170 0 : std::vector<MnEntryCPtr> ret;
171 0 : for (const auto& payee : m_list.GetProjectedMNPayees(pindex)) {
172 0 : ret.emplace_back(std::make_shared<const MnEntryImpl>(payee));
173 : }
174 0 : return ret;
175 0 : }
176 :
177 0 : void setContext(NodeContext* context) override
178 : {
179 0 : m_context = context;
180 0 : }
181 :
182 : private:
183 : // Note: Currently we do nothing with m_context but in the future, if we have a hard fork
184 : // that requires checking for deployment information in deterministic masternode logic,
185 : // we will need NodeContext::chainman. This has been kept around to retain those code
186 : // paths.
187 0 : [[maybe_unused]] NodeContext* m_context{nullptr};
188 : };
189 :
190 0 : class EVOImpl : public EVO
191 : {
192 : private:
193 0 : ChainstateManager& chainman() { return *Assert(m_context->chainman); }
194 0 : NodeContext& context() { return *Assert(m_context); }
195 :
196 : public:
197 0 : std::pair<MnListPtr, const CBlockIndex*> getListAtChainTip() override
198 : {
199 0 : const auto *tip = WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip());
200 0 : if (tip && context().dmnman) {
201 0 : MnListImpl mnList = context().dmnman->GetListForBlock(tip);
202 0 : if (!mnList.getBlockHash().IsNull()) {
203 0 : mnList.setContext(m_context);
204 0 : return {std::make_shared<MnListImpl>(mnList), tip};
205 : }
206 0 : }
207 0 : return {nullptr, nullptr};
208 0 : }
209 0 : void setContext(NodeContext* context) override
210 : {
211 0 : m_context = context;
212 0 : }
213 :
214 : private:
215 0 : NodeContext* m_context{nullptr};
216 : };
217 :
218 0 : class GOVImpl : public GOV
219 : {
220 : private:
221 0 : NodeContext& context() { return *Assert(m_context); }
222 :
223 : public:
224 0 : void getAllNewerThan(std::vector<CGovernanceObject> &objs, int64_t nMoreThanTime,
225 : bool include_postponed) override
226 : {
227 0 : if (context().govman != nullptr) {
228 0 : context().govman->GetAllNewerThan(objs, nMoreThanTime, include_postponed);
229 0 : }
230 0 : }
231 0 : Votes getObjVotes(const CGovernanceObject& obj, vote_signal_enum_t vote_signal) override
232 : {
233 0 : Votes ret;
234 0 : if (context().govman != nullptr && context().dmnman != nullptr) {
235 0 : const auto& tip_mn_list{context().dmnman->GetListAtChainTip()};
236 0 : if (auto govobj{context().govman->FindGovernanceObject(obj.GetHash())}) {
237 0 : ret.m_abs = govobj->GetAbstainCount(tip_mn_list, vote_signal);
238 0 : ret.m_no = govobj->GetNoCount(tip_mn_list, vote_signal);
239 0 : ret.m_yes = govobj->GetYesCount(tip_mn_list, vote_signal);
240 0 : } else {
241 0 : ret.m_abs = obj.GetAbstainCount(tip_mn_list, vote_signal);
242 0 : ret.m_no = obj.GetNoCount(tip_mn_list, vote_signal);
243 0 : ret.m_yes = obj.GetYesCount(tip_mn_list, vote_signal);
244 : }
245 0 : }
246 0 : return ret;
247 0 : }
248 0 : UniqueVoters getObjUniqueVoters(const CGovernanceObject& obj, vote_signal_enum_t vote_signal) override
249 : {
250 0 : if (context().govman != nullptr && context().dmnman != nullptr) {
251 0 : const auto& tip_mn_list{context().dmnman->GetListAtChainTip()};
252 0 : if (auto govobj{context().govman->FindGovernanceObject(obj.GetHash())}) {
253 0 : const auto count = govobj->GetUniqueVoterCount(tip_mn_list, vote_signal);
254 0 : return {.m_regular = count.m_regular, .m_evo = count.m_evo};
255 : } else {
256 0 : const auto count = obj.GetUniqueVoterCount(tip_mn_list, vote_signal);
257 0 : return {.m_regular = count.m_regular, .m_evo = count.m_evo};
258 : }
259 0 : }
260 0 : return {0, 0};
261 0 : }
262 0 : bool existsObj(const uint256& hash) override
263 : {
264 0 : if (context().govman != nullptr) {
265 0 : return context().govman->HaveObjectForHash(hash);
266 : }
267 0 : return false;
268 0 : }
269 0 : bool isEnabled() override
270 : {
271 0 : if (context().govman != nullptr) {
272 0 : return context().govman->IsValid();
273 : }
274 0 : return false;
275 0 : }
276 0 : bool processVoteAndRelay(const CGovernanceVote& vote, std::string& error) override
277 : {
278 0 : if (context().govman != nullptr && context().connman != nullptr) {
279 0 : CGovernanceException exception;
280 0 : bool result = context().govman->ProcessVoteAndRelay(vote, exception, *context().connman);
281 0 : if (!result) {
282 0 : error = exception.GetMessage();
283 0 : }
284 0 : return result;
285 0 : }
286 0 : error = "Governance manager not available";
287 0 : return false;
288 0 : }
289 0 : GovernanceInfo getGovernanceInfo() override
290 : {
291 0 : GovernanceInfo info;
292 0 : const Consensus::Params& consensusParams = Params().GetConsensus();
293 0 : if (context().chainman) {
294 0 : LOCK(::cs_main);
295 0 : CSuperblock::GetNearestSuperblocksHeights(context().chainman->ActiveHeight(), info.lastsuperblock, info.nextsuperblock);
296 0 : info.governancebudget = CSuperblock::GetPaymentsLimit(context().chainman->ActiveChain(), info.nextsuperblock);
297 0 : if (context().dmnman) {
298 0 : info.fundingthreshold = static_cast<int>(context().dmnman->GetListAtChainTip().GetCounts().m_valid_weighted / 10);
299 0 : }
300 0 : }
301 0 : info.proposalfee = GOVERNANCE_PROPOSAL_FEE_TX;
302 0 : info.superblockcycle = consensusParams.nSuperblockCycle;
303 0 : info.superblockmaturitywindow = consensusParams.nSuperblockMaturityWindow;
304 0 : info.targetSpacing = consensusParams.nPowTargetSpacing;
305 0 : info.relayRequiredConfs = GOVERNANCE_MIN_RELAY_FEE_CONFIRMATIONS;
306 0 : info.requiredConfs = GOVERNANCE_FEE_CONFIRMATIONS;
307 0 : return info;
308 0 : }
309 0 : std::optional<int32_t> getProposalFundedHeight(const uint256& proposal_hash) override
310 : {
311 0 : if (context().chain_helper != nullptr && context().chainman != nullptr) {
312 0 : const int32_t nTipHeight = context().chainman->ActiveHeight();
313 0 : for (const auto& trigger : context().chain_helper->superblocks->GetActiveTriggers()) {
314 0 : if (!trigger || trigger->GetBlockHeight() > nTipHeight) continue;
315 0 : for (const auto& hash : trigger->GetProposalHashes()) {
316 0 : if (hash == proposal_hash) {
317 0 : return trigger->GetBlockHeight();
318 : }
319 : }
320 : }
321 0 : }
322 0 : return std::nullopt;
323 0 : }
324 0 : FundableResult getFundableProposalHashes() override
325 : {
326 0 : FundableResult result;
327 0 : if (context().govman != nullptr && context().chainman != nullptr && context().dmnman != nullptr) {
328 0 : const auto tip_mn_list{context().dmnman->GetListAtChainTip()};
329 0 : if (const auto proposals{context().govman->GetApprovedProposals(tip_mn_list)}; !proposals.empty()) {
330 0 : int32_t last_sb{0}, next_sb{0};
331 0 : CSuperblock::GetNearestSuperblocksHeights(context().chainman->ActiveHeight(), last_sb, next_sb);
332 0 : const CAmount budget{CSuperblock::GetPaymentsLimit(context().chainman->ActiveChain(), next_sb)};
333 0 : for (const auto& proposal : proposals) {
334 0 : UniValue json = proposal->GetJSONObject();
335 0 : CAmount payment_amount{0};
336 : try {
337 0 : payment_amount = ParsePaymentAmount(json["payment_amount"].getValStr());
338 0 : } catch (...) {
339 : continue;
340 0 : }
341 0 : if (result.allocated + payment_amount > budget) {
342 : // Budget is saturated, cannot fulfill proposal
343 0 : continue;
344 : }
345 0 : result.allocated += payment_amount;
346 0 : result.hashes.insert(proposal->GetHash());
347 0 : }
348 0 : return result;
349 : }
350 0 : }
351 0 : return result;
352 0 : }
353 0 : std::optional<CGovernanceObject> createProposal(int32_t revision, int64_t created_time,
354 : const std::string& data_hex, std::string& error) override
355 : {
356 0 : CGovernanceObject govobj(uint256{}, revision, created_time, uint256{}, data_hex);
357 0 : if (govobj.GetObjectType() != GovernanceObject::PROPOSAL) {
358 0 : error = "Invalid object type, only proposals can be validated";
359 0 : return std::nullopt;
360 : }
361 0 : std::string strValidationError;
362 0 : if (!governance::ValidateProposal(data_hex, strValidationError)) {
363 0 : error = "Invalid proposal data: " + strValidationError;
364 0 : return std::nullopt;
365 : }
366 0 : const ChainstateManager& chainman = *Assert(context().chainman);
367 : {
368 0 : LOCK(::cs_main);
369 0 : std::string strError;
370 0 : if (!govobj.IsValidLocally(Assert(context().dmnman)->GetListAtChainTip(), chainman, strError, false)) {
371 0 : error = "Governance object is not valid - " + govobj.GetHash().ToString() + " - " + strError;
372 0 : return std::nullopt;
373 : }
374 0 : }
375 0 : return govobj;
376 0 : }
377 :
378 0 : bool submitProposal(const uint256& parent, int32_t revision, int64_t created_time, const std::string& data_hex,
379 : const uint256& fee_txid, std::string& out_object_hash, std::string& error) override
380 : {
381 0 : if (!context().govman || !context().dmnman || !context().chainman) { error = "Governance not available"; return false; }
382 0 : if(!Assert(context().mn_sync)->IsBlockchainSynced()) { error = "Client not synced"; return false; }
383 0 : const auto mnList = Assert(context().dmnman)->GetListAtChainTip();
384 0 : CGovernanceObject govobj(parent, revision, created_time, fee_txid, data_hex);
385 0 : if (govobj.GetObjectType() == GovernanceObject::TRIGGER) { error = "Submission of triggers is not available"; return false; }
386 0 : if (govobj.GetObjectType() == GovernanceObject::PROPOSAL) {
387 0 : std::string strValidationError;
388 0 : if (!governance::ValidateProposal(data_hex, strValidationError)) { error = "Invalid proposal data: " + strValidationError; return false; }
389 0 : }
390 0 : const CTxMemPool& mempool = *Assert(context().mempool);
391 0 : bool fMissingConfirmations{false};
392 : {
393 0 : LOCK2(cs_main, mempool.cs);
394 0 : std::string strError;
395 0 : if (!govobj.IsValidLocally(mnList, *Assert(context().chainman), strError, fMissingConfirmations, true) && !fMissingConfirmations) {
396 0 : error = "Governance object is not valid - " + govobj.GetHash().ToString() + " - " + strError;
397 0 : return false;
398 : }
399 0 : }
400 0 : if (!Assert(context().govman)->MasternodeRateCheck(govobj)) { error = "Object creation rate limit exceeded"; return false; }
401 0 : if (fMissingConfirmations) {
402 0 : context().govman->AddPostponedObject(govobj);
403 0 : context().govman->RelayObject(govobj);
404 0 : } else {
405 0 : context().govman->AddGovernanceObject(govobj, "<local>");
406 : }
407 0 : out_object_hash = govobj.GetHash().ToString();
408 0 : return true;
409 0 : }
410 0 : void setContext(NodeContext* context) override
411 : {
412 0 : m_context = context;
413 0 : }
414 :
415 : private:
416 0 : NodeContext* m_context{nullptr};
417 : };
418 :
419 0 : class LLMQImpl : public LLMQ
420 : {
421 : private:
422 0 : NodeContext& context() { return *Assert(m_context); }
423 :
424 : public:
425 0 : CreditPoolCounts getCreditPoolCounts() override
426 : {
427 0 : CreditPoolCounts ret{};
428 : if (!context().chainman) {
429 : return ret;
430 : }
431 0 : const auto* pindex{WITH_LOCK(::cs_main, return context().chainman->ActiveChain().Tip())};
432 : if (!pindex || !pindex->pprev) {
433 : return ret;
434 : }
435 : auto& chain_helper{context().chainman->ActiveChainstate().ChainHelper()};
436 : const auto pool{chain_helper.GetCreditPool(pindex)};
437 : ret.m_locked = pool.locked;
438 : ret.m_limit = pool.currentLimit;
439 : ret.m_diff = pool.locked - chain_helper.GetCreditPool(pindex->pprev).locked;
440 : return ret;
441 : }
442 0 : ChainLockInfo getBestChainLock() override
443 : {
444 0 : if (!context().chainlocks) {
445 0 : return {};
446 : }
447 : const auto [clsig, pindex] = context().chainlocks->GetBestChainlockWithPindex();
448 : if (!pindex) {
449 : return {};
450 : }
451 : return {
452 : .m_height = clsig.getHeight(),
453 : .m_block_time = pindex->GetBlockTime(),
454 : .m_hash = clsig.getBlockHash(),
455 : };
456 : }
457 0 : InstantSendCounts getInstantSendCounts() override
458 : {
459 0 : if (!context().llmq_ctx || !context().llmq_ctx->isman) {
460 0 : return {};
461 : }
462 : const auto counts{context().llmq_ctx->isman->GetCounts()};
463 : return {
464 : .m_verified = counts.m_verified,
465 : .m_unverified = counts.m_unverified,
466 : .m_awaiting_tx = counts.m_awaiting_tx,
467 : .m_unprotected_tx = counts.m_unprotected_tx,
468 : };
469 : }
470 0 : size_t getPendingAssetUnlocks() override
471 : {
472 0 : if (!context().mempool) {
473 0 : return 0;
474 : }
475 0 : LOCK(context().mempool->cs);
476 0 : return static_cast<size_t>(std::ranges::count_if(context().mempool->mapTx, [](const auto& entry) {
477 0 : return entry.GetTx().IsPlatformTransfer();
478 : }));
479 0 : }
480 0 : std::vector<QuorumInfo> getQuorumStats() override
481 : {
482 0 : std::vector<QuorumInfo> stats{};
483 0 : if (!context().llmq_ctx || !context().llmq_ctx->qman || !context().chainman) {
484 0 : return stats;
485 : }
486 0 : const auto* pindex{WITH_LOCK(::cs_main, return context().chainman->ActiveChain().Tip())};
487 0 : if (!pindex) {
488 0 : return stats;
489 : }
490 0 : for (const auto& type : llmq::GetEnabledQuorumTypes(*context().chainman, pindex)) {
491 0 : const auto llmq_params{Params().GetLLMQ(type)};
492 0 : if (!llmq_params.has_value()) {
493 0 : continue;
494 : }
495 0 : const auto quorums{context().llmq_ctx->qman->ScanQuorums(type, pindex, llmq_params->signingActiveQuorumCount)};
496 0 : double health{0.0};
497 0 : for (const auto& q : quorums) {
498 0 : size_t numMembers = q->members.size();
499 0 : size_t numValidMembers = q->qc->CountValidMembers();
500 0 : health += (numMembers > 0) ? (double(numValidMembers) / double(numMembers)) : 0.0;
501 : }
502 0 : health = quorums.empty() ? 0.0 : (health / quorums.size());
503 0 : const int32_t newest_height{(!quorums.empty() && quorums[0]->m_quorum_base_block_index)
504 0 : ? quorums[0]->m_quorum_base_block_index->nHeight : 0};
505 0 : const int32_t expiry_height{(newest_height > 0)
506 0 : ? newest_height + llmq_params->signingActiveQuorumCount * llmq_params->dkgInterval
507 : : 0};
508 0 : stats.emplace_back(QuorumInfo{
509 0 : .m_name = std::string(llmq_params->name),
510 0 : .m_count = quorums.size(),
511 0 : .m_health = health,
512 0 : .m_rotates = llmq_params->useRotation,
513 0 : .m_data_retention_blocks = llmq_params->max_store_depth(),
514 0 : .m_newest_height = newest_height,
515 0 : .m_expiry_height = expiry_height,
516 : });
517 0 : }
518 0 : return stats;
519 0 : }
520 0 : void setContext(NodeContext* context) override
521 : {
522 0 : m_context = context;
523 0 : }
524 :
525 : private:
526 0 : NodeContext* m_context{nullptr};
527 : };
528 :
529 : namespace Masternode = interfaces::Masternode;
530 0 : class MasternodeSyncImpl : public Masternode::Sync
531 : {
532 : private:
533 0 : NodeContext& context() { return *Assert(m_context); }
534 :
535 : public:
536 0 : bool isSynced() override
537 : {
538 0 : if (context().mn_sync != nullptr) {
539 0 : return context().mn_sync->IsSynced();
540 : }
541 0 : return false;
542 0 : }
543 0 : bool isBlockchainSynced() override
544 : {
545 0 : if (context().mn_sync != nullptr) {
546 0 : return context().mn_sync->IsBlockchainSynced();
547 : }
548 0 : return false;
549 0 : }
550 0 : bool isGovernanceSynced() override
551 : {
552 0 : if (context().mn_sync != nullptr) {
553 0 : return context().mn_sync->GetAssetID() > MASTERNODE_SYNC_GOVERNANCE;
554 : }
555 0 : return false;
556 0 : }
557 0 : std::string getSyncStatus() override
558 : {
559 0 : if (context().mn_sync != nullptr) {
560 0 : return context().mn_sync->GetSyncStatus();
561 : }
562 0 : return "";
563 0 : }
564 0 : void setContext(NodeContext* context) override
565 : {
566 0 : m_context = context;
567 0 : }
568 :
569 : private:
570 0 : NodeContext* m_context{nullptr};
571 : };
572 :
573 : namespace CoinJoin = interfaces::CoinJoin;
574 : class CoinJoinOptionsImpl : public CoinJoin::Options
575 : {
576 : public:
577 0 : int getSessions() override
578 : {
579 0 : return CCoinJoinClientOptions::GetSessions();
580 : }
581 0 : int getRounds() override
582 : {
583 0 : return CCoinJoinClientOptions::GetRounds();
584 : }
585 0 : int getAmount() override
586 : {
587 0 : return CCoinJoinClientOptions::GetAmount();
588 : }
589 0 : int getDenomsGoal() override
590 : {
591 0 : return CCoinJoinClientOptions::GetDenomsGoal();
592 : }
593 0 : int getDenomsHardCap() override
594 : {
595 0 : return CCoinJoinClientOptions::GetDenomsHardCap();
596 : }
597 0 : void setEnabled(bool fEnabled) override
598 : {
599 0 : return CCoinJoinClientOptions::SetEnabled(fEnabled);
600 : }
601 0 : void setMultiSessionEnabled(bool fEnabled) override
602 : {
603 0 : CCoinJoinClientOptions::SetMultiSessionEnabled(fEnabled);
604 0 : }
605 0 : void setSessions(int sessions) override
606 : {
607 0 : CCoinJoinClientOptions::SetSessions(sessions);
608 0 : }
609 0 : void setRounds(int nRounds) override
610 : {
611 0 : CCoinJoinClientOptions::SetRounds(nRounds);
612 0 : }
613 0 : void setAmount(CAmount amount) override
614 : {
615 0 : CCoinJoinClientOptions::SetAmount(amount);
616 0 : }
617 0 : void setDenomsGoal(int denoms_goal) override
618 : {
619 0 : CCoinJoinClientOptions::SetDenomsGoal(denoms_goal);
620 0 : }
621 0 : void setDenomsHardCap(int denoms_hardcap) override
622 : {
623 0 : CCoinJoinClientOptions::SetDenomsHardCap(denoms_hardcap);
624 0 : }
625 0 : bool isEnabled() override
626 : {
627 0 : return CCoinJoinClientOptions::IsEnabled();
628 : }
629 0 : bool isMultiSessionEnabled() override
630 : {
631 0 : return CCoinJoinClientOptions::IsMultiSessionEnabled();
632 : }
633 0 : bool isCollateralAmount(CAmount nAmount) override
634 : {
635 0 : return ::CoinJoin::IsCollateralAmount(nAmount);
636 : }
637 0 : CAmount getMinCollateralAmount() override
638 : {
639 0 : return ::CoinJoin::GetCollateralAmount();
640 : }
641 0 : CAmount getMaxCollateralAmount() override
642 : {
643 0 : return ::CoinJoin::GetMaxCollateralAmount();
644 : }
645 0 : CAmount getSmallestDenomination() override
646 : {
647 0 : return ::CoinJoin::GetSmallestDenomination();
648 : }
649 0 : bool isDenominated(CAmount nAmount) override
650 : {
651 0 : return ::CoinJoin::IsDenominatedAmount(nAmount);
652 : }
653 0 : std::array<CAmount, 5> getStandardDenominations() override
654 : {
655 0 : return ::CoinJoin::GetStandardDenominations();
656 : }
657 : };
658 :
659 : #ifdef ENABLE_EXTERNAL_SIGNER
660 : class ExternalSignerImpl : public interfaces::ExternalSigner
661 : {
662 : public:
663 0 : ExternalSignerImpl(::ExternalSigner signer) : m_signer(std::move(signer)) {}
664 0 : std::string getName() override { return m_signer.m_name; }
665 : private:
666 : ::ExternalSigner m_signer;
667 : };
668 : #endif
669 :
670 : class NodeImpl : public Node
671 : {
672 : private:
673 0 : ChainstateManager& chainman() { return *Assert(m_context->chainman); }
674 : public:
675 : EVOImpl m_evo;
676 : GOVImpl m_gov;
677 : LLMQImpl m_llmq;
678 : MasternodeSyncImpl m_masternodeSync;
679 : CoinJoinOptionsImpl m_coinjoin;
680 :
681 0 : explicit NodeImpl(NodeContext& context) { setContext(&context); }
682 0 : void initLogging() override { InitLogging(*Assert(m_context->args)); }
683 0 : void initParameterInteraction() override { InitParameterInteraction(*Assert(m_context->args)); }
684 0 : bilingual_str getWarnings() override { return GetWarnings(true); }
685 0 : uint64_t getLogCategories() override { return LogInstance().GetCategoryMask(); }
686 0 : bool baseInitialize() override
687 : {
688 0 : return AppInitBasicSetup(gArgs) && AppInitParameterInteraction(gArgs) && AppInitSanityChecks() &&
689 0 : AppInitLockDataDirectory() && AppInitInterfaces(*m_context);
690 : }
691 0 : bool appInitMain(interfaces::BlockAndHeaderTipInfo* tip_info) override
692 : {
693 0 : return AppInitMain(*m_context, tip_info);
694 : }
695 0 : void appShutdown() override
696 : {
697 0 : Interrupt(*m_context);
698 0 : Shutdown(*m_context);
699 0 : }
700 0 : void appPrepareShutdown() override
701 : {
702 0 : Interrupt(*m_context);
703 0 : StartRestart();
704 0 : PrepareShutdown(*m_context);
705 0 : }
706 0 : void startShutdown() override
707 : {
708 0 : StartShutdown();
709 : // Stop RPC for clean shutdown if any of waitfor* commands is executed.
710 0 : if (gArgs.GetBoolArg("-server", false)) {
711 0 : InterruptRPC();
712 0 : StopRPC();
713 0 : }
714 0 : }
715 0 : bool shutdownRequested() override { return ShutdownRequested(); }
716 0 : bool isSettingIgnored(const std::string& name) override
717 : {
718 0 : bool ignored = false;
719 0 : gArgs.LockSettings([&](util::Settings& settings) {
720 0 : if (auto* options = util::FindKey(settings.command_line_options, name)) {
721 0 : ignored = !options->empty();
722 0 : }
723 0 : });
724 0 : return ignored;
725 : }
726 0 : util::SettingsValue getPersistentSetting(const std::string& name) override { return gArgs.GetPersistentSetting(name); }
727 0 : void updateRwSetting(const std::string& name, const util::SettingsValue& value) override
728 : {
729 0 : gArgs.LockSettings([&](util::Settings& settings) {
730 0 : if (value.isNull()) {
731 0 : settings.rw_settings.erase(name);
732 0 : } else {
733 0 : settings.rw_settings[name] = value;
734 : }
735 0 : });
736 0 : gArgs.WriteSettingsFile();
737 0 : }
738 0 : void forceSetting(const std::string& name, const util::SettingsValue& value) override
739 : {
740 0 : gArgs.LockSettings([&](util::Settings& settings) {
741 0 : if (value.isNull()) {
742 0 : settings.forced_settings.erase(name);
743 0 : } else {
744 0 : settings.forced_settings[name] = value;
745 : }
746 0 : });
747 0 : }
748 0 : void resetSettings() override
749 : {
750 0 : gArgs.WriteSettingsFile(/*errors=*/nullptr, /*backup=*/true);
751 0 : gArgs.LockSettings([&](util::Settings& settings) {
752 0 : settings.rw_settings.clear();
753 0 : });
754 0 : gArgs.WriteSettingsFile();
755 0 : }
756 0 : void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); }
757 0 : bool getProxy(Network net, Proxy& proxy_info) override { return GetProxy(net, proxy_info); }
758 0 : size_t getNodeCount(ConnectionDirection flags) override
759 : {
760 0 : return m_context->connman ? m_context->connman->GetNodeCount(flags) : 0;
761 : }
762 0 : bool getNodesStats(NodesStats& stats) override
763 : {
764 0 : stats.clear();
765 :
766 0 : if (m_context->connman) {
767 0 : std::vector<CNodeStats> stats_temp;
768 0 : m_context->connman->GetNodeStats(stats_temp);
769 :
770 0 : stats.reserve(stats_temp.size());
771 0 : for (auto& node_stats_temp : stats_temp) {
772 0 : stats.emplace_back(std::move(node_stats_temp), false, CNodeStateStats());
773 : }
774 :
775 : // Try to retrieve the CNodeStateStats for each node.
776 0 : if (m_context->peerman) {
777 0 : TRY_LOCK(::cs_main, lockMain);
778 0 : if (lockMain) {
779 0 : for (auto& node_stats : stats) {
780 0 : std::get<1>(node_stats) =
781 0 : m_context->peerman->GetNodeStateStats(std::get<0>(node_stats).nodeid, std::get<2>(node_stats));
782 : }
783 0 : }
784 0 : }
785 0 : return true;
786 0 : }
787 0 : return false;
788 0 : }
789 0 : bool getBanned(banmap_t& banmap) override
790 : {
791 0 : if (m_context->banman) {
792 0 : m_context->banman->GetBanned(banmap);
793 0 : return true;
794 : }
795 0 : return false;
796 0 : }
797 0 : bool ban(const CNetAddr& net_addr, int64_t ban_time_offset) override
798 : {
799 0 : if (m_context->banman) {
800 0 : m_context->banman->Ban(net_addr, ban_time_offset);
801 0 : return true;
802 : }
803 0 : return false;
804 0 : }
805 0 : bool unban(const CSubNet& ip) override
806 : {
807 0 : if (m_context->banman) {
808 0 : m_context->banman->Unban(ip);
809 0 : return true;
810 : }
811 0 : return false;
812 0 : }
813 0 : bool disconnectByAddress(const CNetAddr& net_addr) override
814 : {
815 0 : if (m_context->connman) {
816 0 : return m_context->connman->DisconnectNode(net_addr);
817 : }
818 0 : return false;
819 0 : }
820 0 : bool disconnectById(NodeId id) override
821 : {
822 0 : if (m_context->connman) {
823 0 : return m_context->connman->DisconnectNode(id);
824 : }
825 0 : return false;
826 0 : }
827 0 : std::vector<std::unique_ptr<interfaces::ExternalSigner>> listExternalSigners() override
828 : {
829 : #ifdef ENABLE_EXTERNAL_SIGNER
830 0 : std::vector<ExternalSigner> signers = {};
831 0 : const std::string command = gArgs.GetArg("-signer", "");
832 0 : if (command == "") return {};
833 0 : ExternalSigner::Enumerate(command, signers, Params().NetworkIDString());
834 0 : std::vector<std::unique_ptr<interfaces::ExternalSigner>> result;
835 0 : for (auto& signer : signers) {
836 0 : result.emplace_back(std::make_unique<ExternalSignerImpl>(std::move(signer)));
837 : }
838 0 : return result;
839 : #else
840 : // This result is indistinguishable from a successful call that returns
841 : // no signers. For the current GUI this doesn't matter, because the wallet
842 : // creation dialog disables the external signer checkbox in both
843 : // cases. The return type could be changed to std::optional<std::vector>
844 : // (or something that also includes error messages) if this distinction
845 : // becomes important.
846 : return {};
847 : #endif // ENABLE_EXTERNAL_SIGNER
848 0 : }
849 0 : int64_t getTotalBytesRecv() override { return m_context->connman ? m_context->connman->GetTotalBytesRecv() : 0; }
850 0 : int64_t getTotalBytesSent() override { return m_context->connman ? m_context->connman->GetTotalBytesSent() : 0; }
851 0 : size_t getMempoolSize() override { return m_context->mempool ? m_context->mempool->size() : 0; }
852 0 : size_t getMempoolDynamicUsage() override { return m_context->mempool ? m_context->mempool->DynamicMemoryUsage() : 0; }
853 0 : size_t getMempoolMaxUsage() override { return gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; }
854 0 : bool getHeaderTip(int& height, int64_t& block_time) override
855 : {
856 0 : LOCK(::cs_main);
857 0 : auto best_header = chainman().m_best_header;
858 0 : if (best_header) {
859 0 : height = best_header->nHeight;
860 0 : block_time = best_header->GetBlockTime();
861 0 : return true;
862 : }
863 0 : return false;
864 0 : }
865 0 : std::map<CNetAddr, LocalServiceInfo> getNetLocalAddresses() override
866 : {
867 0 : if (m_context->connman)
868 0 : return m_context->connman->getNetLocalAddresses();
869 : else
870 0 : return {};
871 0 : }
872 0 : int getNumBlocks() override
873 : {
874 0 : LOCK(::cs_main);
875 0 : return chainman().ActiveChain().Height();
876 0 : }
877 0 : uint256 getBestBlockHash() override
878 : {
879 0 : const CBlockIndex* tip = WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip());
880 0 : return tip ? tip->GetBlockHash() : Params().GenesisBlock().GetHash();
881 : }
882 0 : int64_t getLastBlockTime() override
883 : {
884 0 : LOCK(::cs_main);
885 0 : if (chainman().ActiveChain().Tip()) {
886 0 : return chainman().ActiveChain().Tip()->GetBlockTime();
887 : }
888 0 : return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network
889 0 : }
890 0 : std::string getLastBlockHash() override
891 : {
892 0 : LOCK(::cs_main);
893 0 : if (m_context->chainman->ActiveChain().Tip()) {
894 0 : return m_context->chainman->ActiveChain().Tip()->GetBlockHash().ToString();
895 : }
896 0 : return Params().GenesisBlock().GetHash().ToString(); // Genesis block's hash of current network
897 0 : }
898 0 : double getVerificationProgress() override
899 : {
900 : const CBlockIndex* tip;
901 : {
902 0 : LOCK(::cs_main);
903 0 : tip = chainman().ActiveChain().Tip();
904 0 : }
905 0 : return GuessVerificationProgress(Params().TxData(), tip);
906 0 : }
907 0 : bool isInitialBlockDownload() override {
908 0 : return chainman().ActiveChainstate().IsInitialBlockDownload();
909 : }
910 0 : bool isMasternode() override
911 : {
912 0 : return m_context->active_ctx != nullptr;
913 : }
914 0 : bool isLoadingBlocks() override { return node::fReindex || node::fImporting; }
915 0 : void setNetworkActive(bool active) override
916 : {
917 0 : if (m_context->connman) {
918 0 : m_context->connman->SetNetworkActive(active, m_context->mn_sync.get());
919 0 : }
920 0 : }
921 0 : bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); }
922 0 : CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
923 0 : UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
924 : {
925 0 : JSONRPCRequest req;
926 0 : req.context = *m_context;
927 0 : req.params = params;
928 0 : req.strMethod = command;
929 0 : req.URI = uri;
930 0 : return ::tableRPC.execute(req);
931 0 : }
932 0 : std::vector<std::string> listRpcCommands() override { return ::tableRPC.listCommands(); }
933 0 : void rpcSetTimerInterfaceIfUnset(RPCTimerInterface* iface) override { RPCSetTimerInterfaceIfUnset(iface); }
934 0 : void rpcUnsetTimerInterface(RPCTimerInterface* iface) override { RPCUnsetTimerInterface(iface); }
935 0 : bool getUnspentOutput(const COutPoint& output, Coin& coin) override
936 : {
937 0 : LOCK(::cs_main);
938 0 : return chainman().ActiveChainstate().CoinsTip().GetCoin(output, coin);
939 0 : }
940 0 : TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, bilingual_str& err_string) override
941 : {
942 0 : return BroadcastTransaction(*m_context, std::move(tx), err_string, max_tx_fee, /*relay=*/ true, /*wait_callback=*/ false);
943 0 : }
944 0 : WalletLoader& walletLoader() override
945 : {
946 0 : return *Assert(m_context->wallet_loader);
947 : }
948 :
949 0 : EVO& evo() override { return m_evo; }
950 0 : GOV& gov() override { return m_gov; }
951 0 : LLMQ& llmq() override { return m_llmq; }
952 0 : Masternode::Sync& masternodeSync() override { return m_masternodeSync; }
953 0 : CoinJoin::Options& coinJoinOptions() override { return m_coinjoin; }
954 0 : std::unique_ptr<interfaces::CoinJoin::Loader>& coinJoinLoader() override { return m_context->coinjoin_loader; }
955 :
956 0 : std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
957 : {
958 0 : return MakeHandler(::uiInterface.InitMessage_connect(fn));
959 0 : }
960 0 : std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) override
961 : {
962 0 : return MakeHandler(::uiInterface.ThreadSafeMessageBox_connect(fn));
963 0 : }
964 0 : std::unique_ptr<Handler> handleQuestion(QuestionFn fn) override
965 : {
966 0 : return MakeHandler(::uiInterface.ThreadSafeQuestion_connect(fn));
967 0 : }
968 0 : std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
969 : {
970 0 : return MakeHandler(::uiInterface.ShowProgress_connect(fn));
971 0 : }
972 0 : std::unique_ptr<Handler> handleInitWallet(InitWalletFn fn) override
973 : {
974 0 : return MakeHandler(::uiInterface.InitWallet_connect(fn));
975 0 : }
976 0 : std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override
977 : {
978 0 : return MakeHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn));
979 0 : }
980 0 : std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) override
981 : {
982 0 : return MakeHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn));
983 0 : }
984 0 : std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) override
985 : {
986 0 : return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn));
987 0 : }
988 0 : std::unique_ptr<Handler> handleBannedListChanged(BannedListChangedFn fn) override
989 : {
990 0 : return MakeHandler(::uiInterface.BannedListChanged_connect(fn));
991 0 : }
992 0 : std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override
993 : {
994 0 : return MakeHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
995 0 : fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()},
996 0 : GuessVerificationProgress(Params().TxData(), block));
997 0 : }));
998 0 : }
999 0 : std::unique_ptr<Handler> handleNotifyChainLock(NotifyChainLockFn fn) override
1000 : {
1001 0 : return MakeHandler(::uiInterface.NotifyChainLock_connect([fn](const std::string& bestChainLockHash, int bestChainLockHeight) {
1002 0 : fn(bestChainLockHash, bestChainLockHeight);
1003 0 : }));
1004 0 : }
1005 0 : std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override
1006 : {
1007 0 : return MakeHandler(
1008 0 : ::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
1009 0 : fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()},
1010 : /* verification progress is unused when a header was received */ 0);
1011 0 : }));
1012 0 : }
1013 0 : std::unique_ptr<Handler> handleNotifyInstantSendChanged(NotifyInstantSendChangedFn fn) override
1014 : {
1015 0 : return MakeHandler(::uiInterface.NotifyInstantSendChanged_connect(fn));
1016 0 : }
1017 0 : std::unique_ptr<Handler> handleNotifyGovernanceChanged(NotifyGovernanceChangedFn fn) override
1018 : {
1019 0 : return MakeHandler(::uiInterface.NotifyGovernanceChanged_connect(fn));
1020 0 : }
1021 0 : std::unique_ptr<Handler> handleNotifyMasternodeListChanged(NotifyMasternodeListChangedFn fn) override
1022 : {
1023 0 : return MakeHandler(
1024 0 : ::uiInterface.NotifyMasternodeListChanged_connect([fn](const CDeterministicMNList& newList, const CBlockIndex* pindex) {
1025 0 : fn(newList, pindex);
1026 0 : }));
1027 0 : }
1028 0 : std::unique_ptr<Handler> handleNotifyAdditionalDataSyncProgressChanged(NotifyAdditionalDataSyncProgressChangedFn fn) override
1029 : {
1030 0 : return MakeHandler(
1031 0 : ::uiInterface.NotifyAdditionalDataSyncProgressChanged_connect([fn](double nSyncProgress) {
1032 0 : fn(nSyncProgress);
1033 0 : }));
1034 0 : }
1035 0 : NodeContext* context() override { return m_context; }
1036 0 : void setContext(NodeContext* context) override
1037 : {
1038 0 : m_context = context;
1039 0 : m_evo.setContext(context);
1040 0 : m_gov.setContext(context);
1041 0 : m_llmq.setContext(context);
1042 0 : m_masternodeSync.setContext(context);
1043 0 : }
1044 0 : NodeContext* m_context{nullptr};
1045 : };
1046 :
1047 4447 : bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock, const CChain& active)
1048 : {
1049 4447 : if (!index) return false;
1050 4422 : if (block.m_hash) *block.m_hash = index->GetBlockHash();
1051 4422 : if (block.m_height) *block.m_height = index->nHeight;
1052 4422 : if (block.m_time) *block.m_time = index->GetBlockTime();
1053 4422 : if (block.m_max_time) *block.m_max_time = index->GetBlockTimeMax();
1054 4422 : if (block.m_mtp_time) *block.m_mtp_time = index->GetMedianTimePast();
1055 4422 : if (block.m_in_active_chain) *block.m_in_active_chain = active[index->nHeight] == index;
1056 4422 : if (block.m_next_block) FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] : nullptr, *block.m_next_block, lock, active);
1057 4422 : if (block.m_data) {
1058 932 : REVERSE_LOCK(lock);
1059 932 : if (!ReadBlockFromDisk(*block.m_data, index, Params().GetConsensus())) block.m_data->SetNull();
1060 932 : }
1061 4422 : block.found = true;
1062 4422 : return true;
1063 4447 : }
1064 :
1065 : class NotificationsProxy : public CValidationInterface
1066 : {
1067 : public:
1068 36 : explicit NotificationsProxy(std::shared_ptr<Chain::Notifications> notifications)
1069 36 : : m_notifications(std::move(notifications)) {}
1070 36 : virtual ~NotificationsProxy() = default;
1071 2 : void TransactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime, uint64_t mempool_sequence) override
1072 : {
1073 2 : m_notifications->transactionAddedToMempool(tx, nAcceptTime);
1074 2 : }
1075 0 : void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override
1076 : {
1077 0 : m_notifications->transactionRemovedFromMempool(tx, reason);
1078 0 : }
1079 6 : void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
1080 : {
1081 6 : m_notifications->blockConnected(*block, index->nHeight);
1082 6 : }
1083 0 : void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
1084 : {
1085 0 : m_notifications->blockDisconnected(*block, index->nHeight);
1086 0 : }
1087 6 : void UpdatedBlockTip(const CBlockIndex* index, const CBlockIndex* fork_index, bool is_ibd) override
1088 : {
1089 6 : m_notifications->updatedBlockTip();
1090 6 : }
1091 0 : void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->chainStateFlushed(locator); }
1092 0 : void NotifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr<const chainlock::ChainLockSig>& clsig) override
1093 : {
1094 0 : m_notifications->notifyChainLock(pindexChainLock, clsig);
1095 0 : }
1096 0 : void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const instantsend::InstantSendLock>& islock) override
1097 : {
1098 0 : m_notifications->notifyTransactionLock(tx, islock);
1099 0 : }
1100 : std::shared_ptr<Chain::Notifications> m_notifications;
1101 : };
1102 :
1103 : class NotificationsHandlerImpl : public Handler
1104 : {
1105 : public:
1106 36 : explicit NotificationsHandlerImpl(std::shared_ptr<Chain::Notifications> notifications)
1107 18 : : m_proxy(std::make_shared<NotificationsProxy>(std::move(notifications)))
1108 36 : {
1109 18 : RegisterSharedValidationInterface(m_proxy);
1110 36 : }
1111 54 : ~NotificationsHandlerImpl() override { disconnect(); }
1112 18 : void disconnect() override
1113 : {
1114 18 : if (m_proxy) {
1115 18 : UnregisterSharedValidationInterface(m_proxy);
1116 18 : m_proxy.reset();
1117 18 : }
1118 18 : }
1119 : std::shared_ptr<NotificationsProxy> m_proxy;
1120 : };
1121 :
1122 : class RpcHandlerImpl : public Handler
1123 : {
1124 : public:
1125 3024 : explicit RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)
1126 2016 : {
1127 1008 : m_command.actor = [this](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
1128 0 : if (!m_wrapped_command) return false;
1129 : try {
1130 0 : return m_wrapped_command->actor(request, result, last_handler);
1131 0 : } catch (const UniValue& e) {
1132 : // If this is not the last handler and a wallet not found
1133 : // exception was thrown, return false so the next handler can
1134 : // try to handle the request. Otherwise, reraise the exception.
1135 0 : if (!last_handler) {
1136 0 : const UniValue& code = e["code"];
1137 0 : if (code.isNum() && code.getInt<int>() == RPC_WALLET_NOT_FOUND) {
1138 0 : return false;
1139 : }
1140 0 : }
1141 0 : throw;
1142 0 : }
1143 0 : };
1144 1008 : ::tableRPC.appendCommand(m_command.name, &m_command);
1145 2016 : }
1146 :
1147 1008 : void disconnect() override final
1148 : {
1149 1008 : if (m_wrapped_command) {
1150 1008 : m_wrapped_command = nullptr;
1151 1008 : ::tableRPC.removeCommand(m_command.name, &m_command);
1152 1008 : }
1153 1008 : }
1154 :
1155 3024 : ~RpcHandlerImpl() override { disconnect(); }
1156 :
1157 : CRPCCommand m_command;
1158 : const CRPCCommand* m_wrapped_command;
1159 : };
1160 :
1161 : class ChainImpl : public Chain
1162 : {
1163 : private:
1164 9033 : ChainstateManager& chainman() { return *Assert(m_node.chainman); }
1165 : public:
1166 1256 : explicit ChainImpl(NodeContext& node) : m_node(node) {}
1167 46 : std::optional<int> getHeight() override
1168 : {
1169 46 : LOCK(::cs_main);
1170 46 : const CChain& active = chainman().ActiveChain();
1171 46 : int height = active.Height();
1172 46 : if (height >= 0) {
1173 46 : return height;
1174 : }
1175 0 : return std::nullopt;
1176 46 : }
1177 49 : uint256 getBlockHash(int height) override
1178 : {
1179 49 : LOCK(::cs_main);
1180 49 : const CChain& active = chainman().ActiveChain();
1181 49 : CBlockIndex* block = active[height];
1182 49 : assert(block != nullptr);
1183 49 : return block->GetBlockHash();
1184 49 : }
1185 0 : bool haveBlockOnDisk(int height) override
1186 : {
1187 0 : LOCK(::cs_main);
1188 0 : const CChain& active = chainman().ActiveChain();
1189 0 : CBlockIndex* block = active[height];
1190 0 : return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
1191 0 : }
1192 0 : std::optional<int> findFork(const uint256& hash, std::optional<int>* height) override
1193 : {
1194 0 : LOCK(cs_main);
1195 0 : const CChain& active = chainman().ActiveChain();
1196 0 : const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(hash);
1197 0 : const CBlockIndex* fork = block ? active.FindFork(block) : nullptr;
1198 0 : if (height) {
1199 0 : if (block) {
1200 0 : *height = block->nHeight;
1201 0 : } else {
1202 0 : height->reset();
1203 : }
1204 0 : }
1205 0 : if (fork) {
1206 0 : return fork->nHeight;
1207 : }
1208 0 : return std::nullopt;
1209 0 : }
1210 3 : CBlockLocator getTipLocator() override
1211 : {
1212 3 : LOCK(::cs_main);
1213 3 : return chainman().ActiveChain().GetLocator();
1214 3 : }
1215 2 : CBlockLocator getActiveChainLocator(const uint256& block_hash) override
1216 : {
1217 2 : LOCK(::cs_main);
1218 2 : const CBlockIndex* index = chainman().m_blockman.LookupBlockIndex(block_hash);
1219 2 : if (!index) return {};
1220 2 : return chainman().ActiveChain().GetLocator(index);
1221 2 : }
1222 4 : std::optional<int> findLocatorFork(const CBlockLocator& locator) override
1223 : {
1224 4 : LOCK(::cs_main);
1225 4 : const CChainState& active = chainman().ActiveChainstate();
1226 4 : if (const CBlockIndex* fork = active.FindForkInGlobalIndex(locator)) {
1227 4 : return fork->nHeight;
1228 : }
1229 0 : return std::nullopt;
1230 4 : }
1231 9 : bool hasBlockFilterIndex(BlockFilterType filter_type) override
1232 : {
1233 9 : return GetBlockFilterIndex(filter_type) != nullptr;
1234 : }
1235 0 : std::optional<bool> blockFilterMatchesAny(BlockFilterType filter_type, const uint256& block_hash, const GCSFilter::ElementSet& filter_set) override
1236 : {
1237 0 : const BlockFilterIndex* block_filter_index{GetBlockFilterIndex(filter_type)};
1238 0 : if (!block_filter_index) return std::nullopt;
1239 :
1240 0 : BlockFilter filter;
1241 0 : const CBlockIndex* index{WITH_LOCK(::cs_main, return chainman().m_blockman.LookupBlockIndex(block_hash))};
1242 0 : if (index == nullptr || !block_filter_index->LookupFilter(index, filter)) return std::nullopt;
1243 0 : return filter.GetFilter().MatchAny(filter_set);
1244 0 : }
1245 598529 : bool isInstantSendLockedTx(const uint256& hash) override
1246 : {
1247 598529 : if (m_node.llmq_ctx == nullptr || m_node.llmq_ctx->isman == nullptr) return false;
1248 598529 : return m_node.llmq_ctx->isman->IsLocked(hash);
1249 598529 : }
1250 0 : bool hasChainLock(int height, const uint256& hash) override
1251 : {
1252 0 : if (m_node.chainlocks == nullptr) return false;
1253 0 : return m_node.chainlocks->HasChainLock(height, hash);
1254 0 : }
1255 758 : std::vector<COutPoint> listMNCollaterials(const std::vector<std::pair<const CTransactionRef&, uint32_t>>& outputs) override
1256 : {
1257 1516 : const CBlockIndex *tip = WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip());
1258 758 : CDeterministicMNList mnList{};
1259 758 : if (tip != nullptr && m_node.dmnman != nullptr) {
1260 758 : mnList = m_node.dmnman->GetListForBlock(tip);
1261 758 : }
1262 758 : std::vector<COutPoint> listRet;
1263 1640 : for (const auto& [tx, index]: outputs) {
1264 882 : COutPoint nextOut{tx->GetHash(), index};
1265 882 : if (CDeterministicMNManager::IsProTxWithCollateral(tx, index) || mnList.HasMNByCollateral(nextOut)) {
1266 0 : listRet.emplace_back(nextOut);
1267 0 : }
1268 : }
1269 758 : return listRet;
1270 758 : }
1271 3495 : bool findBlock(const uint256& hash, const FoundBlock& block) override
1272 : {
1273 3495 : WAIT_LOCK(cs_main, lock);
1274 3495 : const CChain& active = chainman().ActiveChain();
1275 3495 : return FillBlock(chainman().m_blockman.LookupBlockIndex(hash), block, lock, active);
1276 3495 : }
1277 5 : bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override
1278 : {
1279 5 : WAIT_LOCK(cs_main, lock);
1280 5 : const CChain& active = chainman().ActiveChain();
1281 5 : return FillBlock(active.FindEarliestAtLeast(min_time, min_height), block, lock, active);
1282 5 : }
1283 3 : bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out) override
1284 : {
1285 3 : WAIT_LOCK(cs_main, lock);
1286 3 : const CChain& active = chainman().ActiveChain();
1287 3 : if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
1288 3 : if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) {
1289 2 : return FillBlock(ancestor, ancestor_out, lock, active);
1290 : }
1291 1 : }
1292 1 : return FillBlock(nullptr, ancestor_out, lock, active);
1293 3 : }
1294 2 : bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out) override
1295 : {
1296 2 : WAIT_LOCK(cs_main, lock);
1297 2 : const CChain& active = chainman().ActiveChain();
1298 2 : const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash);
1299 2 : const CBlockIndex* ancestor = chainman().m_blockman.LookupBlockIndex(ancestor_hash);
1300 2 : if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr;
1301 2 : return FillBlock(ancestor, ancestor_out, lock, active);
1302 2 : }
1303 3 : bool findCommonAncestor(const uint256& block_hash1, const uint256& block_hash2, const FoundBlock& ancestor_out, const FoundBlock& block1_out, const FoundBlock& block2_out) override
1304 : {
1305 3 : WAIT_LOCK(cs_main, lock);
1306 3 : const CChain& active = chainman().ActiveChain();
1307 3 : const CBlockIndex* block1 = chainman().m_blockman.LookupBlockIndex(block_hash1);
1308 3 : const CBlockIndex* block2 = chainman().m_blockman.LookupBlockIndex(block_hash2);
1309 3 : const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr;
1310 : // Using & instead of && below to avoid short circuiting and leaving
1311 : // output uninitialized. Cast bool to int to avoid -Wbitwise-instead-of-logical
1312 : // compiler warnings.
1313 3 : return int{FillBlock(ancestor, ancestor_out, lock, active)} &
1314 3 : int{FillBlock(block1, block1_out, lock, active)} &
1315 3 : int{FillBlock(block2, block2_out, lock, active)};
1316 3 : }
1317 0 : void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
1318 947 : double guessVerificationProgress(const uint256& block_hash) override
1319 : {
1320 947 : LOCK(::cs_main);
1321 947 : return GuessVerificationProgress(Params().TxData(), chainman().m_blockman.LookupBlockIndex(block_hash));
1322 947 : }
1323 23 : bool hasBlocks(const uint256& block_hash, int min_height, std::optional<int> max_height) override
1324 : {
1325 : // hasBlocks returns true if all ancestors of block_hash in specified
1326 : // range have block data (are not pruned), false if any ancestors in
1327 : // specified range are missing data.
1328 : //
1329 : // For simplicity and robustness, min_height and max_height are only
1330 : // used to limit the range, and passing min_height that's too low or
1331 : // max_height that's too high will not crash or change the result.
1332 23 : LOCK(::cs_main);
1333 23 : if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
1334 23 : if (max_height && block->nHeight >= *max_height) block = block->GetAncestor(*max_height);
1335 1290 : for (; block->nStatus & BLOCK_HAVE_DATA; block = block->pprev) {
1336 : // Check pprev to not segfault if min_height is too low
1337 1276 : if (block->nHeight <= min_height || !block->pprev) return true;
1338 1267 : }
1339 14 : }
1340 14 : return false;
1341 23 : }
1342 7 : bool isInMempool(const uint256& txid) override
1343 : {
1344 7 : if (!m_node.mempool) return false;
1345 7 : LOCK(m_node.mempool->cs);
1346 7 : return m_node.mempool->exists(txid);
1347 7 : }
1348 0 : bool hasDescendantsInMempool(const uint256& txid) override
1349 : {
1350 0 : if (!m_node.mempool) return false;
1351 0 : LOCK(m_node.mempool->cs);
1352 0 : auto it = m_node.mempool->GetIter(txid);
1353 0 : return it && (*it)->GetCountWithDescendants() > 1;
1354 0 : }
1355 2 : bool broadcastTransaction(const CTransactionRef& tx, const CAmount& max_tx_fee, bool relay, bilingual_str& err_string) override
1356 : {
1357 2 : const TransactionError err = BroadcastTransaction(m_node, tx, err_string, max_tx_fee, relay, /*wait_callback=*/false);
1358 : // Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures.
1359 : // Note: this will need to be updated if BroadcastTransactions() is updated to return other non-mempool failures
1360 : // that Chain clients do not need to know about.
1361 2 : return TransactionError::OK == err;
1362 0 : }
1363 598543 : void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize, CAmount* ancestorfees) override
1364 : {
1365 598543 : ancestors = descendants = 0;
1366 598543 : if (!m_node.mempool) return;
1367 598543 : m_node.mempool->GetTransactionAncestry(txid, ancestors, descendants, ancestorsize, ancestorfees);
1368 598543 : }
1369 196 : void getPackageLimits(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) override
1370 : {
1371 196 : limit_ancestor_count = gArgs.GetIntArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
1372 196 : limit_descendant_count = gArgs.GetIntArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
1373 196 : }
1374 156 : bool checkChainLimits(const CTransactionRef& tx) override
1375 : {
1376 156 : if (!m_node.mempool) return true;
1377 156 : LockPoints lp;
1378 156 : CTxMemPoolEntry entry(tx, 0, 0, 0, false, 0, lp);
1379 156 : CTxMemPool::setEntries ancestors;
1380 156 : auto limit_ancestor_count = gArgs.GetIntArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
1381 156 : auto limit_ancestor_size = gArgs.GetIntArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * 1000;
1382 156 : auto limit_descendant_count = gArgs.GetIntArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
1383 156 : auto limit_descendant_size = gArgs.GetIntArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000;
1384 156 : std::string unused_error_string;
1385 156 : LOCK(m_node.mempool->cs);
1386 312 : return m_node.mempool->CalculateMemPoolAncestors(
1387 156 : entry, ancestors, limit_ancestor_count, limit_ancestor_size,
1388 156 : limit_descendant_count, limit_descendant_size, unused_error_string);
1389 156 : }
1390 243 : CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
1391 : {
1392 243 : if (!m_node.fee_estimator) return {};
1393 243 : return m_node.fee_estimator->estimateSmartFee(num_blocks, calc, conservative);
1394 243 : }
1395 223 : unsigned int estimateMaxBlocks() override
1396 : {
1397 223 : if (!m_node.fee_estimator) return 0;
1398 223 : return m_node.fee_estimator->HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
1399 223 : }
1400 20 : CFeeRate mempoolMinFee() override
1401 : {
1402 20 : if (!m_node.mempool) return {};
1403 20 : return m_node.mempool->GetMinFee(gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
1404 20 : }
1405 344 : CFeeRate relayMinFee() override { return ::minRelayTxFee; }
1406 0 : CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
1407 9759 : CFeeRate relayDustFee() override { return ::dustRelayFee; }
1408 2 : bool havePruned() override
1409 : {
1410 2 : LOCK(::cs_main);
1411 2 : return chainman().m_blockman.m_have_pruned;
1412 2 : }
1413 0 : bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); }
1414 178 : bool isInitialBlockDownload() override {
1415 178 : return chainman().ActiveChainstate().IsInitialBlockDownload();
1416 : }
1417 946 : bool shutdownRequested() override { return ShutdownRequested(); }
1418 5 : void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
1419 0 : void initWarning(const bilingual_str& message) override { InitWarning(message); }
1420 3 : void initError(const bilingual_str& message) override { InitError(message); }
1421 14 : void showProgress(const std::string& title, int progress, bool resume_possible) override
1422 : {
1423 14 : ::uiInterface.ShowProgress(title, progress, resume_possible);
1424 14 : }
1425 18 : std::unique_ptr<Handler> handleNotifications(std::shared_ptr<Notifications> notifications) override
1426 : {
1427 18 : return std::make_unique<NotificationsHandlerImpl>(std::move(notifications));
1428 : }
1429 2 : void waitForNotificationsIfTipChanged(const uint256& old_tip) override
1430 : {
1431 2 : if (!old_tip.IsNull()) {
1432 2 : LOCK(::cs_main);
1433 2 : const CChain& active = chainman().ActiveChain();
1434 2 : if (old_tip == active.Tip()->GetBlockHash()) return;
1435 2 : }
1436 0 : SyncWithValidationInterfaceQueue();
1437 2 : }
1438 1008 : std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
1439 : {
1440 1008 : return std::make_unique<RpcHandlerImpl>(command);
1441 : }
1442 0 : bool rpcEnableDeprecated(const std::string& method) override { return IsDeprecatedRPCEnabled(method); }
1443 0 : void rpcRunLater(const std::string& name, std::function<void()> fn, int64_t seconds) override
1444 : {
1445 0 : RPCRunLater(name, std::move(fn), seconds);
1446 0 : }
1447 0 : util::SettingsValue getSetting(const std::string& name) override
1448 : {
1449 0 : return gArgs.GetSetting(name);
1450 : }
1451 4 : std::vector<util::SettingsValue> getSettingsList(const std::string& name) override
1452 : {
1453 4 : return gArgs.GetSettingsList(name);
1454 : }
1455 0 : util::SettingsValue getRwSetting(const std::string& name) override
1456 : {
1457 0 : util::SettingsValue result;
1458 0 : gArgs.LockSettings([&](const util::Settings& settings) {
1459 0 : if (const util::SettingsValue* value = util::FindKey(settings.rw_settings, name)) {
1460 0 : result = *value;
1461 0 : }
1462 0 : });
1463 0 : return result;
1464 0 : }
1465 0 : bool updateRwSetting(const std::string& name, const util::SettingsValue& value, bool write) override
1466 : {
1467 0 : gArgs.LockSettings([&](util::Settings& settings) {
1468 0 : if (value.isNull()) {
1469 0 : settings.rw_settings.erase(name);
1470 0 : } else {
1471 0 : settings.rw_settings[name] = value;
1472 : }
1473 0 : });
1474 0 : return !write || gArgs.WriteSettingsFile();
1475 : }
1476 15 : void requestMempoolTransactions(Notifications& notifications) override
1477 : {
1478 15 : if (!m_node.mempool) return;
1479 15 : LOCK2(::cs_main, m_node.mempool->cs);
1480 16 : for (const CTxMemPoolEntry& entry : m_node.mempool->mapTx) {
1481 1 : notifications.transactionAddedToMempool(entry.GetSharedTx(), /*nAcceptTime=*/0);
1482 : }
1483 15 : }
1484 1 : bool hasAssumedValidChain() override
1485 : {
1486 1 : return chainman().IsSnapshotActive();
1487 : }
1488 :
1489 : NodeContext& m_node;
1490 : };
1491 : } // namespace
1492 : } // namespace node
1493 :
1494 : namespace interfaces {
1495 0 : std::unique_ptr<Node> MakeNode(node::NodeContext& context) { return std::make_unique<node::NodeImpl>(context); }
1496 628 : std::unique_ptr<Chain> MakeChain(node::NodeContext& node) { return std::make_unique<node::ChainImpl>(node); }
1497 : } // namespace interfaces
|