LCOV - code coverage report
Current view: top level - src/node - interfaces.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 292 962 30.4 %
Date: 2026-06-25 07:23:43 Functions: 84 326 25.8 %

          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      639490 : bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock, const CChain& active)
    1048             : {
    1049      639490 :     if (!index) return false;
    1050      636345 :     if (block.m_hash) *block.m_hash = index->GetBlockHash();
    1051      636345 :     if (block.m_height) *block.m_height = index->nHeight;
    1052      636345 :     if (block.m_time) *block.m_time = index->GetBlockTime();
    1053      636345 :     if (block.m_max_time) *block.m_max_time = index->GetBlockTimeMax();
    1054      636345 :     if (block.m_mtp_time) *block.m_mtp_time = index->GetMedianTimePast();
    1055      636345 :     if (block.m_in_active_chain) *block.m_in_active_chain = active[index->nHeight] == index;
    1056      636345 :     if (block.m_next_block) FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] : nullptr, *block.m_next_block, lock, active);
    1057      636345 :     if (block.m_data) {
    1058      138677 :         REVERSE_LOCK(lock);
    1059      138677 :         if (!ReadBlockFromDisk(*block.m_data, index, Params().GetConsensus())) block.m_data->SetNull();
    1060      138677 :     }
    1061      636345 :     block.found = true;
    1062      636345 :     return true;
    1063      639490 : }
    1064             : 
    1065             : class NotificationsProxy : public CValidationInterface
    1066             : {
    1067             : public:
    1068        4394 :     explicit NotificationsProxy(std::shared_ptr<Chain::Notifications> notifications)
    1069        4394 :         : m_notifications(std::move(notifications)) {}
    1070        4394 :     virtual ~NotificationsProxy() = default;
    1071       10845 :     void TransactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime, uint64_t mempool_sequence) override
    1072             :     {
    1073       10845 :         m_notifications->transactionAddedToMempool(tx, nAcceptTime);
    1074       10845 :     }
    1075          91 :     void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override
    1076             :     {
    1077          91 :         m_notifications->transactionRemovedFromMempool(tx, reason);
    1078          91 :     }
    1079      105056 :     void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
    1080             :     {
    1081      105056 :         m_notifications->blockConnected(*block, index->nHeight);
    1082      105056 :     }
    1083        3039 :     void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
    1084             :     {
    1085        3039 :         m_notifications->blockDisconnected(*block, index->nHeight);
    1086        3039 :     }
    1087      104472 :     void UpdatedBlockTip(const CBlockIndex* index, const CBlockIndex* fork_index, bool is_ibd) override
    1088             :     {
    1089      104472 :         m_notifications->updatedBlockTip();
    1090      104472 :     }
    1091        1856 :     void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->chainStateFlushed(locator); }
    1092        1768 :     void NotifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr<const chainlock::ChainLockSig>& clsig) override
    1093             :     {
    1094        1768 :         m_notifications->notifyChainLock(pindexChainLock, clsig);
    1095        1768 :     }
    1096         244 :     void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const instantsend::InstantSendLock>& islock) override
    1097             :     {
    1098         244 :         m_notifications->notifyTransactionLock(tx, islock);
    1099         244 :     }
    1100             :     std::shared_ptr<Chain::Notifications> m_notifications;
    1101             : };
    1102             : 
    1103             : class NotificationsHandlerImpl : public Handler
    1104             : {
    1105             : public:
    1106        4394 :     explicit NotificationsHandlerImpl(std::shared_ptr<Chain::Notifications> notifications)
    1107        2197 :         : m_proxy(std::make_shared<NotificationsProxy>(std::move(notifications)))
    1108        4394 :     {
    1109        2197 :         RegisterSharedValidationInterface(m_proxy);
    1110        4394 :     }
    1111        6591 :     ~NotificationsHandlerImpl() override { disconnect(); }
    1112        2197 :     void disconnect() override
    1113             :     {
    1114        2197 :         if (m_proxy) {
    1115        2197 :             UnregisterSharedValidationInterface(m_proxy);
    1116        2197 :             m_proxy.reset();
    1117        2197 :         }
    1118        2197 :     }
    1119             :     std::shared_ptr<NotificationsProxy> m_proxy;
    1120             : };
    1121             : 
    1122             : class RpcHandlerImpl : public Handler
    1123             : {
    1124             : public:
    1125      451056 :     explicit RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)
    1126      300704 :     {
    1127      196620 :         m_command.actor = [this](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
    1128       46268 :             if (!m_wrapped_command) return false;
    1129             :             try {
    1130       46268 :                 return m_wrapped_command->actor(request, result, last_handler);
    1131        5576 :             } 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        2788 :                 if (!last_handler) {
    1136        2788 :                     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        2788 :             }
    1143       49056 :         };
    1144      150352 :         ::tableRPC.appendCommand(m_command.name, &m_command);
    1145      300704 :     }
    1146             : 
    1147      150352 :     void disconnect() override final
    1148             :     {
    1149      150352 :         if (m_wrapped_command) {
    1150      150352 :             m_wrapped_command = nullptr;
    1151      150352 :             ::tableRPC.removeCommand(m_command.name, &m_command);
    1152      150352 :         }
    1153      150352 :     }
    1154             : 
    1155      451056 :     ~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     1304495 :     ChainstateManager& chainman() { return *Assert(m_node.chainman); }
    1165             : public:
    1166        7316 :     explicit ChainImpl(NodeContext& node) : m_node(node) {}
    1167        6613 :     std::optional<int> getHeight() override
    1168             :     {
    1169        6613 :         LOCK(::cs_main);
    1170        6613 :         const CChain& active = chainman().ActiveChain();
    1171        6613 :         int height = active.Height();
    1172        6613 :         if (height >= 0) {
    1173        6523 :             return height;
    1174             :         }
    1175          90 :         return std::nullopt;
    1176        6613 :     }
    1177        6851 :     uint256 getBlockHash(int height) override
    1178             :     {
    1179        6851 :         LOCK(::cs_main);
    1180        6851 :         const CChain& active = chainman().ActiveChain();
    1181        6851 :         CBlockIndex* block = active[height];
    1182        6851 :         assert(block != nullptr);
    1183        6851 :         return block->GetBlockHash();
    1184        6851 :     }
    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        1460 :     CBlockLocator getTipLocator() override
    1211             :     {
    1212        1460 :         LOCK(::cs_main);
    1213        1460 :         return chainman().ActiveChain().GetLocator();
    1214        1460 :     }
    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        2131 :     std::optional<int> findLocatorFork(const CBlockLocator& locator) override
    1223             :     {
    1224        2131 :         LOCK(::cs_main);
    1225        2131 :         const CChainState& active = chainman().ActiveChainstate();
    1226        2131 :         if (const CBlockIndex* fork = active.FindForkInGlobalIndex(locator)) {
    1227        2101 :             return fork->nHeight;
    1228             :         }
    1229          30 :         return std::nullopt;
    1230        2131 :     }
    1231         555 :     bool hasBlockFilterIndex(BlockFilterType filter_type) override
    1232             :     {
    1233         555 :         return GetBlockFilterIndex(filter_type) != nullptr;
    1234             :     }
    1235         828 :     std::optional<bool> blockFilterMatchesAny(BlockFilterType filter_type, const uint256& block_hash, const GCSFilter::ElementSet& filter_set) override
    1236             :     {
    1237         828 :         const BlockFilterIndex* block_filter_index{GetBlockFilterIndex(filter_type)};
    1238         828 :         if (!block_filter_index) return std::nullopt;
    1239             : 
    1240         828 :         BlockFilter filter;
    1241        1656 :         const CBlockIndex* index{WITH_LOCK(::cs_main, return chainman().m_blockman.LookupBlockIndex(block_hash))};
    1242         828 :         if (index == nullptr || !block_filter_index->LookupFilter(index, filter)) return std::nullopt;
    1243         828 :         return filter.GetFilter().MatchAny(filter_set);
    1244         828 :     }
    1245     2304849 :     bool isInstantSendLockedTx(const uint256& hash) override
    1246             :     {
    1247     2304849 :         if (m_node.llmq_ctx == nullptr || m_node.llmq_ctx->isman == nullptr) return false;
    1248     2304849 :         return m_node.llmq_ctx->isman->IsLocked(hash);
    1249     2304849 :     }
    1250        3675 :     bool hasChainLock(int height, const uint256& hash) override
    1251             :     {
    1252        3675 :         if (m_node.chainlocks == nullptr) return false;
    1253        3675 :         return m_node.chainlocks->HasChainLock(height, hash);
    1254        3675 :     }
    1255      112216 :     std::vector<COutPoint> listMNCollaterials(const std::vector<std::pair<const CTransactionRef&, uint32_t>>& outputs) override
    1256             :     {
    1257      224432 :         const CBlockIndex *tip = WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip());
    1258      112216 :         CDeterministicMNList mnList{};
    1259      112216 :         if  (tip != nullptr && m_node.dmnman != nullptr) {
    1260      112156 :             mnList = m_node.dmnman->GetListForBlock(tip);
    1261      112156 :         }
    1262      112216 :         std::vector<COutPoint> listRet;
    1263      342699 :         for (const auto& [tx, index]: outputs) {
    1264      230483 :             COutPoint nextOut{tx->GetHash(), index};
    1265      230483 :             if (CDeterministicMNManager::IsProTxWithCollateral(tx, index) || mnList.HasMNByCollateral(nextOut)) {
    1266        1013 :                 listRet.emplace_back(nextOut);
    1267        1013 :             }
    1268             :         }
    1269      112216 :         return listRet;
    1270      112216 :     }
    1271      498392 :     bool findBlock(const uint256& hash, const FoundBlock& block) override
    1272             :     {
    1273      498392 :         WAIT_LOCK(cs_main, lock);
    1274      498392 :         const CChain& active = chainman().ActiveChain();
    1275      498392 :         return FillBlock(chainman().m_blockman.LookupBlockIndex(hash), block, lock, active);
    1276      498392 :     }
    1277        1384 :     bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override
    1278             :     {
    1279        1384 :         WAIT_LOCK(cs_main, lock);
    1280        1384 :         const CChain& active = chainman().ActiveChain();
    1281        1384 :         return FillBlock(active.FindEarliestAtLeast(min_time, min_height), block, lock, active);
    1282        1384 :     }
    1283         169 :     bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out) override
    1284             :     {
    1285         169 :         WAIT_LOCK(cs_main, lock);
    1286         169 :         const CChain& active = chainman().ActiveChain();
    1287         169 :         if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
    1288         169 :             if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) {
    1289         168 :                 return FillBlock(ancestor, ancestor_out, lock, active);
    1290             :             }
    1291           1 :         }
    1292           1 :         return FillBlock(nullptr, ancestor_out, lock, active);
    1293         169 :     }
    1294          22 :     bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out) override
    1295             :     {
    1296          22 :         WAIT_LOCK(cs_main, lock);
    1297          22 :         const CChain& active = chainman().ActiveChain();
    1298          22 :         const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash);
    1299          22 :         const CBlockIndex* ancestor = chainman().m_blockman.LookupBlockIndex(ancestor_hash);
    1300          22 :         if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr;
    1301          22 :         return FillBlock(ancestor, ancestor_out, lock, active);
    1302          22 :     }
    1303          63 :     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          63 :         WAIT_LOCK(cs_main, lock);
    1306          63 :         const CChain& active = chainman().ActiveChain();
    1307          63 :         const CBlockIndex* block1 = chainman().m_blockman.LookupBlockIndex(block_hash1);
    1308          63 :         const CBlockIndex* block2 = chainman().m_blockman.LookupBlockIndex(block_hash2);
    1309          63 :         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          63 :         return int{FillBlock(ancestor, ancestor_out, lock, active)} &
    1314          63 :                int{FillBlock(block1, block1_out, lock, active)} &
    1315          63 :                int{FillBlock(block2, block2_out, lock, active)};
    1316          63 :     }
    1317        3199 :     void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
    1318      140831 :     double guessVerificationProgress(const uint256& block_hash) override
    1319             :     {
    1320      140831 :         LOCK(::cs_main);
    1321      140831 :         return GuessVerificationProgress(Params().TxData(), chainman().m_blockman.LookupBlockIndex(block_hash));
    1322      140831 :     }
    1323          81 :     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          81 :         LOCK(::cs_main);
    1333          81 :         if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
    1334          81 :             if (max_height && block->nHeight >= *max_height) block = block->GetAncestor(*max_height);
    1335       11822 :             for (; block->nStatus & BLOCK_HAVE_DATA; block = block->pprev) {
    1336             :                 // Check pprev to not segfault if min_height is too low
    1337       11808 :                 if (block->nHeight <= min_height || !block->pprev) return true;
    1338       11741 :             }
    1339          14 :         }
    1340          14 :         return false;
    1341          81 :     }
    1342       67055 :     bool isInMempool(const uint256& txid) override
    1343             :     {
    1344       67055 :         if (!m_node.mempool) return false;
    1345       67055 :         LOCK(m_node.mempool->cs);
    1346       67055 :         return m_node.mempool->exists(txid);
    1347       67055 :     }
    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        5772 :     bool broadcastTransaction(const CTransactionRef& tx, const CAmount& max_tx_fee, bool relay, bilingual_str& err_string) override
    1356             :     {
    1357        5772 :         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        5772 :         return TransactionError::OK == err;
    1362           0 :     }
    1363     2375524 :     void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize, CAmount* ancestorfees) override
    1364             :     {
    1365     2375524 :         ancestors = descendants = 0;
    1366     2375524 :         if (!m_node.mempool) return;
    1367     2375524 :         m_node.mempool->GetTransactionAncestry(txid, ancestors, descendants, ancestorsize, ancestorfees);
    1368     2375524 :     }
    1369       12235 :     void getPackageLimits(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) override
    1370             :     {
    1371       12235 :         limit_ancestor_count = gArgs.GetIntArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
    1372       12235 :         limit_descendant_count = gArgs.GetIntArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
    1373       12235 :     }
    1374       13448 :     bool checkChainLimits(const CTransactionRef& tx) override
    1375             :     {
    1376       13448 :         if (!m_node.mempool) return true;
    1377       13448 :         LockPoints lp;
    1378       13448 :         CTxMemPoolEntry entry(tx, 0, 0, 0, false, 0, lp);
    1379       13448 :         CTxMemPool::setEntries ancestors;
    1380       13448 :         auto limit_ancestor_count = gArgs.GetIntArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
    1381       13448 :         auto limit_ancestor_size = gArgs.GetIntArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * 1000;
    1382       13448 :         auto limit_descendant_count = gArgs.GetIntArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
    1383       13448 :         auto limit_descendant_size = gArgs.GetIntArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000;
    1384       13448 :         std::string unused_error_string;
    1385       13448 :         LOCK(m_node.mempool->cs);
    1386       26896 :         return m_node.mempool->CalculateMemPoolAncestors(
    1387       13448 :             entry, ancestors, limit_ancestor_count, limit_ancestor_size,
    1388       13448 :             limit_descendant_count, limit_descendant_size, unused_error_string);
    1389       13448 :     }
    1390       26041 :     CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
    1391             :     {
    1392       26041 :         if (!m_node.fee_estimator) return {};
    1393       26041 :         return m_node.fee_estimator->estimateSmartFee(num_blocks, calc, conservative);
    1394       26041 :     }
    1395       14496 :     unsigned int estimateMaxBlocks() override
    1396             :     {
    1397       14496 :         if (!m_node.fee_estimator) return 0;
    1398       14496 :         return m_node.fee_estimator->HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
    1399       14496 :     }
    1400       11736 :     CFeeRate mempoolMinFee() override
    1401             :     {
    1402       11736 :         if (!m_node.mempool) return {};
    1403       11736 :         return m_node.mempool->GetMinFee(gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
    1404       11736 :     }
    1405       16306 :     CFeeRate relayMinFee() override { return ::minRelayTxFee; }
    1406           0 :     CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
    1407      145027 :     CFeeRate relayDustFee() override { return ::dustRelayFee; }
    1408         866 :     bool havePruned() override
    1409             :     {
    1410         866 :         LOCK(::cs_main);
    1411         866 :         return chainman().m_blockman.m_have_pruned;
    1412         866 :     }
    1413        1017 :     bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); }
    1414       15008 :     bool isInitialBlockDownload() override {
    1415       15008 :         return chainman().ActiveChainstate().IsInitialBlockDownload();
    1416             :     }
    1417      140472 :     bool shutdownRequested() override { return ShutdownRequested(); }
    1418        3917 :     void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
    1419           6 :     void initWarning(const bilingual_str& message) override { InitWarning(message); }
    1420          71 :     void initError(const bilingual_str& message) override { InitError(message); }
    1421        5290 :     void showProgress(const std::string& title, int progress, bool resume_possible) override
    1422             :     {
    1423        5290 :         ::uiInterface.ShowProgress(title, progress, resume_possible);
    1424        5290 :     }
    1425        2197 :     std::unique_ptr<Handler> handleNotifications(std::shared_ptr<Notifications> notifications) override
    1426             :     {
    1427        2197 :         return std::make_unique<NotificationsHandlerImpl>(std::move(notifications));
    1428             :     }
    1429       18559 :     void waitForNotificationsIfTipChanged(const uint256& old_tip) override
    1430             :     {
    1431       18559 :         if (!old_tip.IsNull()) {
    1432       18559 :             LOCK(::cs_main);
    1433       18559 :             const CChain& active = chainman().ActiveChain();
    1434       18559 :             if (old_tip == active.Tip()->GetBlockHash()) return;
    1435       18559 :         }
    1436         905 :         SyncWithValidationInterfaceQueue();
    1437       18559 :     }
    1438      150352 :     std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
    1439             :     {
    1440      150352 :         return std::make_unique<RpcHandlerImpl>(command);
    1441             :     }
    1442         596 :     bool rpcEnableDeprecated(const std::string& method) override { return IsDeprecatedRPCEnabled(method); }
    1443         140 :     void rpcRunLater(const std::string& name, std::function<void()> fn, int64_t seconds) override
    1444             :     {
    1445         140 :         RPCRunLater(name, std::move(fn), seconds);
    1446         140 :     }
    1447           0 :     util::SettingsValue getSetting(const std::string& name) override
    1448             :     {
    1449           0 :         return gArgs.GetSetting(name);
    1450             :     }
    1451        2764 :     std::vector<util::SettingsValue> getSettingsList(const std::string& name) override
    1452             :     {
    1453        2764 :         return gArgs.GetSettingsList(name);
    1454             :     }
    1455        1202 :     util::SettingsValue getRwSetting(const std::string& name) override
    1456             :     {
    1457        1202 :         util::SettingsValue result;
    1458        2404 :         gArgs.LockSettings([&](const util::Settings& settings) {
    1459        1202 :             if (const util::SettingsValue* value = util::FindKey(settings.rw_settings, name)) {
    1460         532 :                 result = *value;
    1461         532 :             }
    1462        1202 :         });
    1463        1202 :         return result;
    1464        1202 :     }
    1465         634 :     bool updateRwSetting(const std::string& name, const util::SettingsValue& value, bool write) override
    1466             :     {
    1467        1268 :         gArgs.LockSettings([&](util::Settings& settings) {
    1468         634 :             if (value.isNull()) {
    1469           0 :                 settings.rw_settings.erase(name);
    1470           0 :             } else {
    1471         634 :                 settings.rw_settings[name] = value;
    1472             :             }
    1473         634 :         });
    1474         634 :         return !write || gArgs.WriteSettingsFile();
    1475             :     }
    1476        3667 :     void requestMempoolTransactions(Notifications& notifications) override
    1477             :     {
    1478        3667 :         if (!m_node.mempool) return;
    1479        3667 :         LOCK2(::cs_main, m_node.mempool->cs);
    1480        4477 :         for (const CTxMemPoolEntry& entry : m_node.mempool->mapTx) {
    1481         810 :             notifications.transactionAddedToMempool(entry.GetSharedTx(), /*nAcceptTime=*/0);
    1482             :         }
    1483        3667 :     }
    1484         286 :     bool hasAssumedValidChain() override
    1485             :     {
    1486         286 :         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        3658 : std::unique_ptr<Chain> MakeChain(node::NodeContext& node) { return std::make_unique<node::ChainImpl>(node); }
    1497             : } // namespace interfaces

Generated by: LCOV version 1.16