LCOV - code coverage report
Current view: top level - src/node - interfaces.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 403 537 75.0 %
Date: 2022-08-30 15:50:09 Functions: 108 139 77.7 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 109 190 57.4 %

           Branch data     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 <addrdb.h>
#       6                 :            : #include <banman.h>
#       7                 :            : #include <chain.h>
#       8                 :            : #include <chainparams.h>
#       9                 :            : #include <deploymentstatus.h>
#      10                 :            : #include <external_signer.h>
#      11                 :            : #include <init.h>
#      12                 :            : #include <interfaces/chain.h>
#      13                 :            : #include <interfaces/handler.h>
#      14                 :            : #include <interfaces/node.h>
#      15                 :            : #include <interfaces/wallet.h>
#      16                 :            : #include <mapport.h>
#      17                 :            : #include <net.h>
#      18                 :            : #include <net_processing.h>
#      19                 :            : #include <netaddress.h>
#      20                 :            : #include <netbase.h>
#      21                 :            : #include <node/blockstorage.h>
#      22                 :            : #include <kernel/chain.h>
#      23                 :            : #include <node/coin.h>
#      24                 :            : #include <node/context.h>
#      25                 :            : #include <node/transaction.h>
#      26                 :            : #include <node/interface_ui.h>
#      27                 :            : #include <policy/feerate.h>
#      28                 :            : #include <policy/fees.h>
#      29                 :            : #include <policy/policy.h>
#      30                 :            : #include <policy/rbf.h>
#      31                 :            : #include <policy/settings.h>
#      32                 :            : #include <primitives/block.h>
#      33                 :            : #include <primitives/transaction.h>
#      34                 :            : #include <rpc/protocol.h>
#      35                 :            : #include <rpc/server.h>
#      36                 :            : #include <shutdown.h>
#      37                 :            : #include <support/allocators/secure.h>
#      38                 :            : #include <sync.h>
#      39                 :            : #include <txmempool.h>
#      40                 :            : #include <uint256.h>
#      41                 :            : #include <univalue.h>
#      42                 :            : #include <util/check.h>
#      43                 :            : #include <util/system.h>
#      44                 :            : #include <util/translation.h>
#      45                 :            : #include <validation.h>
#      46                 :            : #include <validationinterface.h>
#      47                 :            : #include <warnings.h>
#      48                 :            : 
#      49                 :            : #if defined(HAVE_CONFIG_H)
#      50                 :            : #include <config/bitcoin-config.h>
#      51                 :            : #endif
#      52                 :            : 
#      53                 :            : #include <any>
#      54                 :            : #include <memory>
#      55                 :            : #include <optional>
#      56                 :            : #include <utility>
#      57                 :            : 
#      58                 :            : #include <boost/signals2/signal.hpp>
#      59                 :            : 
#      60                 :            : using interfaces::BlockTip;
#      61                 :            : using interfaces::Chain;
#      62                 :            : using interfaces::FoundBlock;
#      63                 :            : using interfaces::Handler;
#      64                 :            : using interfaces::MakeHandler;
#      65                 :            : using interfaces::Node;
#      66                 :            : using interfaces::WalletLoader;
#      67                 :            : 
#      68                 :            : namespace node {
#      69                 :            : // All members of the classes in this namespace are intentionally public, as the
#      70                 :            : // classes themselves are private.
#      71                 :            : namespace {
#      72                 :            : #ifdef ENABLE_EXTERNAL_SIGNER
#      73                 :            : class ExternalSignerImpl : public interfaces::ExternalSigner
#      74                 :            : {
#      75                 :            : public:
#      76                 :          0 :     ExternalSignerImpl(::ExternalSigner signer) : m_signer(std::move(signer)) {}
#      77                 :          0 :     std::string getName() override { return m_signer.m_name; }
#      78                 :            :     ::ExternalSigner m_signer;
#      79                 :            : };
#      80                 :            : #endif
#      81                 :            : 
#      82                 :            : class NodeImpl : public Node
#      83                 :            : {
#      84                 :            : public:
#      85                 :          1 :     explicit NodeImpl(NodeContext& context) { setContext(&context); }
#      86                 :          0 :     void initLogging() override { InitLogging(*Assert(m_context->args)); }
#      87                 :          6 :     void initParameterInteraction() override { InitParameterInteraction(*Assert(m_context->args)); }
#      88                 :          0 :     bilingual_str getWarnings() override { return GetWarnings(true); }
#      89                 :          0 :     uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); }
#      90                 :            :     bool baseInitialize() override
#      91                 :          1 :     {
#      92         [ -  + ]:          1 :         if (!AppInitBasicSetup(gArgs)) return false;
#      93         [ -  + ]:          1 :         if (!AppInitParameterInteraction(gArgs, /*use_syscall_sandbox=*/false)) return false;
#      94                 :            : 
#      95                 :          1 :         m_context->kernel = std::make_unique<kernel::Context>();
#      96         [ -  + ]:          1 :         if (!AppInitSanityChecks(*m_context->kernel)) return false;
#      97                 :            : 
#      98         [ -  + ]:          1 :         if (!AppInitLockDataDirectory()) return false;
#      99         [ -  + ]:          1 :         if (!AppInitInterfaces(*m_context)) return false;
#     100                 :            : 
#     101                 :          1 :         return true;
#     102                 :          1 :     }
#     103                 :            :     bool appInitMain(interfaces::BlockAndHeaderTipInfo* tip_info) override
#     104                 :          1 :     {
#     105                 :          1 :         return AppInitMain(*m_context, tip_info);
#     106                 :          1 :     }
#     107                 :            :     void appShutdown() override
#     108                 :          1 :     {
#     109                 :          1 :         Interrupt(*m_context);
#     110                 :          1 :         Shutdown(*m_context);
#     111                 :          1 :     }
#     112                 :            :     void startShutdown() override
#     113                 :          1 :     {
#     114                 :          1 :         StartShutdown();
#     115                 :            :         // Stop RPC for clean shutdown if any of waitfor* commands is executed.
#     116         [ -  + ]:          1 :         if (gArgs.GetBoolArg("-server", false)) {
#     117                 :          0 :             InterruptRPC();
#     118                 :          0 :             StopRPC();
#     119                 :          0 :         }
#     120                 :          1 :     }
#     121                 :          0 :     bool shutdownRequested() override { return ShutdownRequested(); }
#     122                 :            :     bool isSettingIgnored(const std::string& name) override
#     123                 :         72 :     {
#     124                 :         72 :         bool ignored = false;
#     125                 :         72 :         gArgs.LockSettings([&](util::Settings& settings) {
#     126         [ -  + ]:         72 :             if (auto* options = util::FindKey(settings.command_line_options, name)) {
#     127                 :          0 :                 ignored = !options->empty();
#     128                 :          0 :             }
#     129                 :         72 :         });
#     130                 :         72 :         return ignored;
#     131                 :         72 :     }
#     132                 :        120 :     util::SettingsValue getPersistentSetting(const std::string& name) override { return gArgs.GetPersistentSetting(name); }
#     133                 :            :     void updateRwSetting(const std::string& name, const util::SettingsValue& value) override
#     134                 :          7 :     {
#     135                 :          7 :         gArgs.LockSettings([&](util::Settings& settings) {
#     136         [ -  + ]:          7 :             if (value.isNull()) {
#     137                 :          0 :                 settings.rw_settings.erase(name);
#     138                 :          7 :             } else {
#     139                 :          7 :                 settings.rw_settings[name] = value;
#     140                 :          7 :             }
#     141                 :          7 :         });
#     142                 :          7 :         gArgs.WriteSettingsFile();
#     143                 :          7 :     }
#     144                 :            :     void forceSetting(const std::string& name, const util::SettingsValue& value) override
#     145                 :          0 :     {
#     146                 :          0 :         gArgs.LockSettings([&](util::Settings& settings) {
#     147         [ #  # ]:          0 :             if (value.isNull()) {
#     148                 :          0 :                 settings.forced_settings.erase(name);
#     149                 :          0 :             } else {
#     150                 :          0 :                 settings.forced_settings[name] = value;
#     151                 :          0 :             }
#     152                 :          0 :         });
#     153                 :          0 :     }
#     154                 :            :     void resetSettings() override
#     155                 :          1 :     {
#     156                 :          1 :         gArgs.WriteSettingsFile(/*errors=*/nullptr, /*backup=*/true);
#     157                 :          1 :         gArgs.LockSettings([&](util::Settings& settings) {
#     158                 :          1 :             settings.rw_settings.clear();
#     159                 :          1 :         });
#     160                 :          1 :         gArgs.WriteSettingsFile();
#     161                 :          1 :     }
#     162                 :          0 :     void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); }
#     163                 :          1 :     bool getProxy(Network net, Proxy& proxy_info) override { return GetProxy(net, proxy_info); }
#     164                 :            :     size_t getNodeCount(ConnectionDirection flags) override
#     165                 :          9 :     {
#     166         [ +  - ]:          9 :         return m_context->connman ? m_context->connman->GetNodeCount(flags) : 0;
#     167                 :          9 :     }
#     168                 :            :     bool getNodesStats(NodesStats& stats) override
#     169                 :          3 :     {
#     170                 :          3 :         stats.clear();
#     171                 :            : 
#     172         [ +  - ]:          3 :         if (m_context->connman) {
#     173                 :          3 :             std::vector<CNodeStats> stats_temp;
#     174                 :          3 :             m_context->connman->GetNodeStats(stats_temp);
#     175                 :            : 
#     176                 :          3 :             stats.reserve(stats_temp.size());
#     177         [ -  + ]:          3 :             for (auto& node_stats_temp : stats_temp) {
#     178                 :          0 :                 stats.emplace_back(std::move(node_stats_temp), false, CNodeStateStats());
#     179                 :          0 :             }
#     180                 :            : 
#     181                 :            :             // Try to retrieve the CNodeStateStats for each node.
#     182         [ +  - ]:          3 :             if (m_context->peerman) {
#     183                 :          3 :                 TRY_LOCK(::cs_main, lockMain);
#     184         [ +  - ]:          3 :                 if (lockMain) {
#     185         [ -  + ]:          3 :                     for (auto& node_stats : stats) {
#     186                 :          0 :                         std::get<1>(node_stats) =
#     187                 :          0 :                             m_context->peerman->GetNodeStateStats(std::get<0>(node_stats).nodeid, std::get<2>(node_stats));
#     188                 :          0 :                     }
#     189                 :          3 :                 }
#     190                 :          3 :             }
#     191                 :          3 :             return true;
#     192                 :          3 :         }
#     193                 :          0 :         return false;
#     194                 :          3 :     }
#     195                 :            :     bool getBanned(banmap_t& banmap) override
#     196                 :          3 :     {
#     197         [ +  - ]:          3 :         if (m_context->banman) {
#     198                 :          3 :             m_context->banman->GetBanned(banmap);
#     199                 :          3 :             return true;
#     200                 :          3 :         }
#     201                 :          0 :         return false;
#     202                 :          3 :     }
#     203                 :            :     bool ban(const CNetAddr& net_addr, int64_t ban_time_offset) override
#     204                 :          0 :     {
#     205         [ #  # ]:          0 :         if (m_context->banman) {
#     206                 :          0 :             m_context->banman->Ban(net_addr, ban_time_offset);
#     207                 :          0 :             return true;
#     208                 :          0 :         }
#     209                 :          0 :         return false;
#     210                 :          0 :     }
#     211                 :            :     bool unban(const CSubNet& ip) override
#     212                 :          0 :     {
#     213         [ #  # ]:          0 :         if (m_context->banman) {
#     214                 :          0 :             m_context->banman->Unban(ip);
#     215                 :          0 :             return true;
#     216                 :          0 :         }
#     217                 :          0 :         return false;
#     218                 :          0 :     }
#     219                 :            :     bool disconnectByAddress(const CNetAddr& net_addr) override
#     220                 :          0 :     {
#     221         [ #  # ]:          0 :         if (m_context->connman) {
#     222                 :          0 :             return m_context->connman->DisconnectNode(net_addr);
#     223                 :          0 :         }
#     224                 :          0 :         return false;
#     225                 :          0 :     }
#     226                 :            :     bool disconnectById(NodeId id) override
#     227                 :          0 :     {
#     228         [ #  # ]:          0 :         if (m_context->connman) {
#     229                 :          0 :             return m_context->connman->DisconnectNode(id);
#     230                 :          0 :         }
#     231                 :          0 :         return false;
#     232                 :          0 :     }
#     233                 :            :     std::vector<std::unique_ptr<interfaces::ExternalSigner>> listExternalSigners() override
#     234                 :          0 :     {
#     235                 :          0 : #ifdef ENABLE_EXTERNAL_SIGNER
#     236                 :          0 :         std::vector<ExternalSigner> signers = {};
#     237                 :          0 :         const std::string command = gArgs.GetArg("-signer", "");
#     238         [ #  # ]:          0 :         if (command == "") return {};
#     239                 :          0 :         ExternalSigner::Enumerate(command, signers, Params().NetworkIDString());
#     240                 :          0 :         std::vector<std::unique_ptr<interfaces::ExternalSigner>> result;
#     241         [ #  # ]:          0 :         for (auto& signer : signers) {
#     242                 :          0 :             result.emplace_back(std::make_unique<ExternalSignerImpl>(std::move(signer)));
#     243                 :          0 :         }
#     244                 :          0 :         return result;
#     245                 :            : #else
#     246                 :            :         // This result is indistinguishable from a successful call that returns
#     247                 :            :         // no signers. For the current GUI this doesn't matter, because the wallet
#     248                 :            :         // creation dialog disables the external signer checkbox in both
#     249                 :            :         // cases. The return type could be changed to std::optional<std::vector>
#     250                 :            :         // (or something that also includes error messages) if this distinction
#     251                 :            :         // becomes important.
#     252                 :            :         return {};
#     253                 :            : #endif // ENABLE_EXTERNAL_SIGNER
#     254                 :          0 :     }
#     255         [ +  - ]:          2 :     int64_t getTotalBytesRecv() override { return m_context->connman ? m_context->connman->GetTotalBytesRecv() : 0; }
#     256         [ +  - ]:          2 :     int64_t getTotalBytesSent() override { return m_context->connman ? m_context->connman->GetTotalBytesSent() : 0; }
#     257         [ #  # ]:          0 :     size_t getMempoolSize() override { return m_context->mempool ? m_context->mempool->size() : 0; }
#     258         [ #  # ]:          0 :     size_t getMempoolDynamicUsage() override { return m_context->mempool ? m_context->mempool->DynamicMemoryUsage() : 0; }
#     259                 :            :     bool getHeaderTip(int& height, int64_t& block_time) override
#     260                 :          0 :     {
#     261                 :          0 :         LOCK(::cs_main);
#     262                 :          0 :         auto best_header = chainman().m_best_header;
#     263         [ #  # ]:          0 :         if (best_header) {
#     264                 :          0 :             height = best_header->nHeight;
#     265                 :          0 :             block_time = best_header->GetBlockTime();
#     266                 :          0 :             return true;
#     267                 :          0 :         }
#     268                 :          0 :         return false;
#     269                 :          0 :     }
#     270                 :            :     int getNumBlocks() override
#     271                 :          0 :     {
#     272                 :          0 :         LOCK(::cs_main);
#     273                 :          0 :         return chainman().ActiveChain().Height();
#     274                 :          0 :     }
#     275                 :            :     uint256 getBestBlockHash() override
#     276                 :          1 :     {
#     277                 :          1 :         const CBlockIndex* tip = WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip());
#     278         [ +  - ]:          1 :         return tip ? tip->GetBlockHash() : chainman().GetParams().GenesisBlock().GetHash();
#     279                 :          1 :     }
#     280                 :            :     int64_t getLastBlockTime() override
#     281                 :          0 :     {
#     282                 :          0 :         LOCK(::cs_main);
#     283         [ #  # ]:          0 :         if (chainman().ActiveChain().Tip()) {
#     284                 :          0 :             return chainman().ActiveChain().Tip()->GetBlockTime();
#     285                 :          0 :         }
#     286                 :          0 :         return chainman().GetParams().GenesisBlock().GetBlockTime(); // Genesis block's time of current network
#     287                 :          0 :     }
#     288                 :            :     double getVerificationProgress() override
#     289                 :          0 :     {
#     290                 :          0 :         return GuessVerificationProgress(chainman().GetParams().TxData(), WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip()));
#     291                 :          0 :     }
#     292                 :          0 :     bool isInitialBlockDownload() override {
#     293                 :          0 :         return chainman().ActiveChainstate().IsInitialBlockDownload();
#     294                 :          0 :     }
#     295                 :          1 :     bool getReindex() override { return node::fReindex; }
#     296                 :          1 :     bool getImporting() override { return node::fImporting; }
#     297                 :            :     void setNetworkActive(bool active) override
#     298                 :          0 :     {
#     299         [ #  # ]:          0 :         if (m_context->connman) {
#     300                 :          0 :             m_context->connman->SetNetworkActive(active);
#     301                 :          0 :         }
#     302                 :          0 :     }
#     303 [ +  - ][ +  - ]:          4 :     bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); }
#     304                 :            :     CFeeRate getDustRelayFee() override
#     305                 :          2 :     {
#     306         [ -  + ]:          2 :         if (!m_context->mempool) return CFeeRate{DUST_RELAY_TX_FEE};
#     307                 :          2 :         return m_context->mempool->m_dust_relay_feerate;
#     308                 :          2 :     }
#     309                 :            :     UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
#     310                 :         36 :     {
#     311                 :         36 :         JSONRPCRequest req;
#     312                 :         36 :         req.context = m_context;
#     313                 :         36 :         req.params = params;
#     314                 :         36 :         req.strMethod = command;
#     315                 :         36 :         req.URI = uri;
#     316                 :         36 :         return ::tableRPC.execute(req);
#     317                 :         36 :     }
#     318                 :          1 :     std::vector<std::string> listRpcCommands() override { return ::tableRPC.listCommands(); }
#     319                 :          1 :     void rpcSetTimerInterfaceIfUnset(RPCTimerInterface* iface) override { RPCSetTimerInterfaceIfUnset(iface); }
#     320                 :          1 :     void rpcUnsetTimerInterface(RPCTimerInterface* iface) override { RPCUnsetTimerInterface(iface); }
#     321                 :            :     bool getUnspentOutput(const COutPoint& output, Coin& coin) override
#     322                 :          0 :     {
#     323                 :          0 :         LOCK(::cs_main);
#     324                 :          0 :         return chainman().ActiveChainstate().CoinsTip().GetCoin(output, coin);
#     325                 :          0 :     }
#     326                 :            :     TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) override
#     327                 :          0 :     {
#     328                 :          0 :         return BroadcastTransaction(*m_context, std::move(tx), err_string, max_tx_fee, /*relay=*/ true, /*wait_callback=*/ false);
#     329                 :          0 :     }
#     330                 :            :     WalletLoader& walletLoader() override
#     331                 :          6 :     {
#     332                 :          6 :         return *Assert(m_context->wallet_loader);
#     333                 :          6 :     }
#     334                 :            :     std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
#     335                 :          0 :     {
#     336                 :          0 :         return MakeHandler(::uiInterface.InitMessage_connect(fn));
#     337                 :          0 :     }
#     338                 :            :     std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) override
#     339                 :          1 :     {
#     340                 :          1 :         return MakeHandler(::uiInterface.ThreadSafeMessageBox_connect(fn));
#     341                 :          1 :     }
#     342                 :            :     std::unique_ptr<Handler> handleQuestion(QuestionFn fn) override
#     343                 :          1 :     {
#     344                 :          1 :         return MakeHandler(::uiInterface.ThreadSafeQuestion_connect(fn));
#     345                 :          1 :     }
#     346                 :            :     std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
#     347                 :          3 :     {
#     348                 :          3 :         return MakeHandler(::uiInterface.ShowProgress_connect(fn));
#     349                 :          3 :     }
#     350                 :            :     std::unique_ptr<Handler> handleInitWallet(InitWalletFn fn) override
#     351                 :          0 :     {
#     352                 :          0 :         return MakeHandler(::uiInterface.InitWallet_connect(fn));
#     353                 :          0 :     }
#     354                 :            :     std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override
#     355                 :          3 :     {
#     356                 :          3 :         return MakeHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn));
#     357                 :          3 :     }
#     358                 :            :     std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) override
#     359                 :          3 :     {
#     360                 :          3 :         return MakeHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn));
#     361                 :          3 :     }
#     362                 :            :     std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) override
#     363                 :          3 :     {
#     364                 :          3 :         return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn));
#     365                 :          3 :     }
#     366                 :            :     std::unique_ptr<Handler> handleBannedListChanged(BannedListChangedFn fn) override
#     367                 :          3 :     {
#     368                 :          3 :         return MakeHandler(::uiInterface.BannedListChanged_connect(fn));
#     369                 :          3 :     }
#     370                 :            :     std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override
#     371                 :          3 :     {
#     372                 :          3 :         return MakeHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
#     373                 :          0 :             fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()},
#     374                 :          0 :                 GuessVerificationProgress(Params().TxData(), block));
#     375                 :          0 :         }));
#     376                 :          3 :     }
#     377                 :            :     std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override
#     378                 :          3 :     {
#     379                 :          3 :         return MakeHandler(
#     380                 :          3 :             ::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, int64_t height, int64_t timestamp, bool presync) {
#     381                 :          0 :                 fn(sync_state, BlockTip{(int)height, timestamp, uint256{}}, presync);
#     382                 :          0 :             }));
#     383                 :          3 :     }
#     384                 :          8 :     NodeContext* context() override { return m_context; }
#     385                 :            :     void setContext(NodeContext* context) override
#     386                 :          4 :     {
#     387                 :          4 :         m_context = context;
#     388                 :          4 :     }
#     389                 :          1 :     ChainstateManager& chainman() { return *Assert(m_context->chainman); }
#     390                 :            :     NodeContext* m_context{nullptr};
#     391                 :            : };
#     392                 :            : 
#     393                 :            : bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock, const CChain& active)
#     394                 :     372867 : {
#     395         [ +  + ]:     372867 :     if (!index) return false;
#     396         [ +  + ]:     371476 :     if (block.m_hash) *block.m_hash = index->GetBlockHash();
#     397         [ +  + ]:     371476 :     if (block.m_height) *block.m_height = index->nHeight;
#     398         [ +  + ]:     371476 :     if (block.m_time) *block.m_time = index->GetBlockTime();
#     399         [ +  + ]:     371476 :     if (block.m_max_time) *block.m_max_time = index->GetBlockTimeMax();
#     400         [ +  + ]:     371476 :     if (block.m_mtp_time) *block.m_mtp_time = index->GetMedianTimePast();
#     401         [ +  + ]:     371476 :     if (block.m_in_active_chain) *block.m_in_active_chain = active[index->nHeight] == index;
#     402         [ +  + ]:     371476 :     if (block.m_locator) { *block.m_locator = GetLocator(index); }
#     403 [ +  + ][ +  - ]:     371476 :     if (block.m_next_block) FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] : nullptr, *block.m_next_block, lock, active);
#     404         [ +  + ]:     371476 :     if (block.m_data) {
#     405                 :     111001 :         REVERSE_LOCK(lock);
#     406         [ +  + ]:     111001 :         if (!ReadBlockFromDisk(*block.m_data, index, Params().GetConsensus())) block.m_data->SetNull();
#     407                 :     111001 :     }
#     408                 :     371476 :     block.found = true;
#     409                 :     371476 :     return true;
#     410                 :     372867 : }
#     411                 :            : 
#     412                 :            : class NotificationsProxy : public CValidationInterface
#     413                 :            : {
#     414                 :            : public:
#     415                 :            :     explicit NotificationsProxy(std::shared_ptr<Chain::Notifications> notifications)
#     416                 :        808 :         : m_notifications(std::move(notifications)) {}
#     417                 :        808 :     virtual ~NotificationsProxy() = default;
#     418                 :            :     void TransactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override
#     419                 :       6711 :     {
#     420                 :       6711 :         m_notifications->transactionAddedToMempool(tx, mempool_sequence);
#     421                 :       6711 :     }
#     422                 :            :     void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override
#     423                 :        217 :     {
#     424                 :        217 :         m_notifications->transactionRemovedFromMempool(tx, reason, mempool_sequence);
#     425                 :        217 :     }
#     426                 :            :     void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
#     427                 :      38268 :     {
#     428                 :      38268 :         m_notifications->blockConnected(kernel::MakeBlockInfo(index, block.get()));
#     429                 :      38268 :     }
#     430                 :            :     void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
#     431                 :        807 :     {
#     432                 :        807 :         m_notifications->blockDisconnected(kernel::MakeBlockInfo(index, block.get()));
#     433                 :        807 :     }
#     434                 :            :     void UpdatedBlockTip(const CBlockIndex* index, const CBlockIndex* fork_index, bool is_ibd) override
#     435                 :      38048 :     {
#     436                 :      38048 :         m_notifications->updatedBlockTip();
#     437                 :      38048 :     }
#     438                 :        655 :     void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->chainStateFlushed(locator); }
#     439                 :            :     std::shared_ptr<Chain::Notifications> m_notifications;
#     440                 :            : };
#     441                 :            : 
#     442                 :            : class NotificationsHandlerImpl : public Handler
#     443                 :            : {
#     444                 :            : public:
#     445                 :            :     explicit NotificationsHandlerImpl(std::shared_ptr<Chain::Notifications> notifications)
#     446                 :            :         : m_proxy(std::make_shared<NotificationsProxy>(std::move(notifications)))
#     447                 :        808 :     {
#     448                 :        808 :         RegisterSharedValidationInterface(m_proxy);
#     449                 :        808 :     }
#     450                 :        808 :     ~NotificationsHandlerImpl() override { disconnect(); }
#     451                 :            :     void disconnect() override
#     452                 :        808 :     {
#     453         [ +  - ]:        808 :         if (m_proxy) {
#     454                 :        808 :             UnregisterSharedValidationInterface(m_proxy);
#     455                 :        808 :             m_proxy.reset();
#     456                 :        808 :         }
#     457                 :        808 :     }
#     458                 :            :     std::shared_ptr<NotificationsProxy> m_proxy;
#     459                 :            : };
#     460                 :            : 
#     461                 :            : class RpcHandlerImpl : public Handler
#     462                 :            : {
#     463                 :            : public:
#     464                 :            :     explicit RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)
#     465                 :      54252 :     {
#     466                 :      54252 :         m_command.actor = [this](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
#     467         [ -  + ]:      22874 :             if (!m_wrapped_command) return false;
#     468                 :      22874 :             try {
#     469                 :      22874 :                 return m_wrapped_command->actor(request, result, last_handler);
#     470                 :      22874 :             } catch (const UniValue& e) {
#     471                 :            :                 // If this is not the last handler and a wallet not found
#     472                 :            :                 // exception was thrown, return false so the next handler can
#     473                 :            :                 // try to handle the request. Otherwise, reraise the exception.
#     474         [ -  + ]:       1118 :                 if (!last_handler) {
#     475                 :          0 :                     const UniValue& code = e["code"];
#     476 [ #  # ][ #  # ]:          0 :                     if (code.isNum() && code.getInt<int>() == RPC_WALLET_NOT_FOUND) {
#     477                 :          0 :                         return false;
#     478                 :          0 :                     }
#     479                 :          0 :                 }
#     480                 :       1118 :                 throw;
#     481                 :       1118 :             }
#     482                 :      22874 :         };
#     483                 :      54252 :         ::tableRPC.appendCommand(m_command.name, &m_command);
#     484                 :      54252 :     }
#     485                 :            : 
#     486                 :            :     void disconnect() final
#     487                 :      54252 :     {
#     488         [ +  - ]:      54252 :         if (m_wrapped_command) {
#     489                 :      54252 :             m_wrapped_command = nullptr;
#     490                 :      54252 :             ::tableRPC.removeCommand(m_command.name, &m_command);
#     491                 :      54252 :         }
#     492                 :      54252 :     }
#     493                 :            : 
#     494                 :      54252 :     ~RpcHandlerImpl() override { disconnect(); }
#     495                 :            : 
#     496                 :            :     CRPCCommand m_command;
#     497                 :            :     const CRPCCommand* m_wrapped_command;
#     498                 :            : };
#     499                 :            : 
#     500                 :            : class ChainImpl : public Chain
#     501                 :            : {
#     502                 :            : public:
#     503                 :       1732 :     explicit ChainImpl(NodeContext& node) : m_node(node) {}
#     504                 :            :     std::optional<int> getHeight() override
#     505                 :       1588 :     {
#     506                 :       1588 :         const int height{WITH_LOCK(::cs_main, return chainman().ActiveChain().Height())};
#     507         [ +  + ]:       1588 :         return height >= 0 ? std::optional{height} : std::nullopt;
#     508                 :       1588 :     }
#     509                 :            :     uint256 getBlockHash(int height) override
#     510                 :       1655 :     {
#     511                 :       1655 :         LOCK(::cs_main);
#     512                 :       1655 :         return Assert(chainman().ActiveChain()[height])->GetBlockHash();
#     513                 :       1655 :     }
#     514                 :            :     bool haveBlockOnDisk(int height) override
#     515                 :          0 :     {
#     516                 :          0 :         LOCK(::cs_main);
#     517                 :          0 :         const CBlockIndex* block{chainman().ActiveChain()[height]};
#     518 [ #  # ][ #  # ]:          0 :         return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
#                 [ #  # ]
#     519                 :          0 :     }
#     520                 :            :     CBlockLocator getTipLocator() override
#     521                 :        552 :     {
#     522                 :        552 :         LOCK(::cs_main);
#     523                 :        552 :         return chainman().ActiveChain().GetLocator();
#     524                 :        552 :     }
#     525                 :            :     CBlockLocator getActiveChainLocator(const uint256& block_hash) override
#     526                 :          2 :     {
#     527                 :          2 :         LOCK(::cs_main);
#     528                 :          2 :         const CBlockIndex* index = chainman().m_blockman.LookupBlockIndex(block_hash);
#     529                 :          2 :         return GetLocator(index);
#     530                 :          2 :     }
#     531                 :            :     std::optional<int> findLocatorFork(const CBlockLocator& locator) override
#     532                 :        793 :     {
#     533                 :        793 :         LOCK(::cs_main);
#     534         [ +  + ]:        793 :         if (const CBlockIndex* fork = chainman().ActiveChainstate().FindForkInGlobalIndex(locator)) {
#     535                 :        783 :             return fork->nHeight;
#     536                 :        783 :         }
#     537                 :         10 :         return std::nullopt;
#     538                 :        793 :     }
#     539                 :            :     bool findBlock(const uint256& hash, const FoundBlock& block) override
#     540                 :     260859 :     {
#     541                 :     260859 :         WAIT_LOCK(cs_main, lock);
#     542                 :     260859 :         return FillBlock(chainman().m_blockman.LookupBlockIndex(hash), block, lock, chainman().ActiveChain());
#     543                 :     260859 :     }
#     544                 :            :     bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override
#     545                 :        830 :     {
#     546                 :        830 :         WAIT_LOCK(cs_main, lock);
#     547                 :        830 :         const CChain& active = chainman().ActiveChain();
#     548                 :        830 :         return FillBlock(active.FindEarliestAtLeast(min_time, min_height), block, lock, active);
#     549                 :        830 :     }
#     550                 :            :     bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out) override
#     551                 :         77 :     {
#     552                 :         77 :         WAIT_LOCK(cs_main, lock);
#     553                 :         77 :         const CChain& active = chainman().ActiveChain();
#     554         [ +  - ]:         77 :         if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
#     555         [ +  + ]:         77 :             if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) {
#     556                 :         75 :                 return FillBlock(ancestor, ancestor_out, lock, active);
#     557                 :         75 :             }
#     558                 :         77 :         }
#     559                 :          2 :         return FillBlock(nullptr, ancestor_out, lock, active);
#     560                 :         77 :     }
#     561                 :            :     bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out) override
#     562                 :         14 :     {
#     563                 :         14 :         WAIT_LOCK(cs_main, lock);
#     564                 :         14 :         const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash);
#     565                 :         14 :         const CBlockIndex* ancestor = chainman().m_blockman.LookupBlockIndex(ancestor_hash);
#     566 [ +  - ][ +  + ]:         14 :         if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr;
#                 [ +  + ]
#     567                 :         14 :         return FillBlock(ancestor, ancestor_out, lock, chainman().ActiveChain());
#     568                 :         14 :     }
#     569                 :            :     bool findCommonAncestor(const uint256& block_hash1, const uint256& block_hash2, const FoundBlock& ancestor_out, const FoundBlock& block1_out, const FoundBlock& block2_out) override
#     570                 :         36 :     {
#     571                 :         36 :         WAIT_LOCK(cs_main, lock);
#     572                 :         36 :         const CChain& active = chainman().ActiveChain();
#     573                 :         36 :         const CBlockIndex* block1 = chainman().m_blockman.LookupBlockIndex(block_hash1);
#     574                 :         36 :         const CBlockIndex* block2 = chainman().m_blockman.LookupBlockIndex(block_hash2);
#     575 [ +  + ][ +  + ]:         36 :         const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr;
#     576                 :            :         // Using & instead of && below to avoid short circuiting and leaving
#     577                 :            :         // output uninitialized. Cast bool to int to avoid -Wbitwise-instead-of-logical
#     578                 :            :         // compiler warnings.
#     579                 :         36 :         return int{FillBlock(ancestor, ancestor_out, lock, active)} &
#     580                 :         36 :                int{FillBlock(block1, block1_out, lock, active)} &
#     581                 :         36 :                int{FillBlock(block2, block2_out, lock, active)};
#     582                 :         36 :     }
#     583                 :       1649 :     void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
#     584                 :            :     double guessVerificationProgress(const uint256& block_hash) override
#     585                 :     111824 :     {
#     586                 :     111824 :         LOCK(::cs_main);
#     587                 :     111824 :         return GuessVerificationProgress(chainman().GetParams().TxData(), chainman().m_blockman.LookupBlockIndex(block_hash));
#     588                 :     111824 :     }
#     589                 :            :     bool hasBlocks(const uint256& block_hash, int min_height, std::optional<int> max_height) override
#     590                 :         60 :     {
#     591                 :            :         // hasBlocks returns true if all ancestors of block_hash in specified
#     592                 :            :         // range have block data (are not pruned), false if any ancestors in
#     593                 :            :         // specified range are missing data.
#     594                 :            :         //
#     595                 :            :         // For simplicity and robustness, min_height and max_height are only
#     596                 :            :         // used to limit the range, and passing min_height that's too low or
#     597                 :            :         // max_height that's too high will not crash or change the result.
#     598                 :         60 :         LOCK(::cs_main);
#     599         [ +  - ]:         60 :         if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
#     600 [ +  + ][ +  + ]:         60 :             if (max_height && block->nHeight >= *max_height) block = block->GetAncestor(*max_height);
#     601         [ +  + ]:       4834 :             for (; block->nStatus & BLOCK_HAVE_DATA; block = block->pprev) {
#     602                 :            :                 // Check pprev to not segfault if min_height is too low
#     603 [ +  + ][ +  + ]:       4806 :                 if (block->nHeight <= min_height || !block->pprev) return true;
#     604                 :       4806 :             }
#     605                 :         60 :         }
#     606                 :         28 :         return false;
#     607                 :         60 :     }
#     608                 :            :     RBFTransactionState isRBFOptIn(const CTransaction& tx) override
#     609                 :       1091 :     {
#     610         [ -  + ]:       1091 :         if (!m_node.mempool) return IsRBFOptInEmptyMempool(tx);
#     611                 :       1091 :         LOCK(m_node.mempool->cs);
#     612                 :       1091 :         return IsRBFOptIn(tx, *m_node.mempool);
#     613                 :       1091 :     }
#     614                 :            :     bool isInMempool(const uint256& txid) override
#     615                 :      25425 :     {
#     616         [ -  + ]:      25425 :         if (!m_node.mempool) return false;
#     617                 :      25425 :         LOCK(m_node.mempool->cs);
#     618                 :      25425 :         return m_node.mempool->exists(GenTxid::Txid(txid));
#     619                 :      25425 :     }
#     620                 :            :     bool hasDescendantsInMempool(const uint256& txid) override
#     621                 :        377 :     {
#     622         [ -  + ]:        377 :         if (!m_node.mempool) return false;
#     623                 :        377 :         LOCK(m_node.mempool->cs);
#     624                 :        377 :         auto it = m_node.mempool->GetIter(txid);
#     625 [ +  + ][ +  + ]:        377 :         return it && (*it)->GetCountWithDescendants() > 1;
#     626                 :        377 :     }
#     627                 :            :     bool broadcastTransaction(const CTransactionRef& tx,
#     628                 :            :         const CAmount& max_tx_fee,
#     629                 :            :         bool relay,
#     630                 :            :         std::string& err_string) override
#     631                 :       2950 :     {
#     632                 :       2950 :         const TransactionError err = BroadcastTransaction(m_node, tx, err_string, max_tx_fee, relay, /*wait_callback=*/false);
#     633                 :            :         // Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures.
#     634                 :            :         // Note: this will need to be updated if BroadcastTransactions() is updated to return other non-mempool failures
#     635                 :            :         // that Chain clients do not need to know about.
#     636                 :       2950 :         return TransactionError::OK == err;
#     637                 :       2950 :     }
#     638                 :            :     void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize, CAmount* ancestorfees) override
#     639                 :    1568916 :     {
#     640                 :    1568916 :         ancestors = descendants = 0;
#     641         [ -  + ]:    1568916 :         if (!m_node.mempool) return;
#     642                 :    1568916 :         m_node.mempool->GetTransactionAncestry(txid, ancestors, descendants, ancestorsize, ancestorfees);
#     643                 :    1568916 :     }
#     644                 :            :     void getPackageLimits(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) override
#     645                 :       5696 :     {
#     646                 :       5696 :         const CTxMemPool::Limits default_limits{};
#     647                 :            : 
#     648         [ +  - ]:       5696 :         const CTxMemPool::Limits& limits{m_node.mempool ? m_node.mempool->m_limits : default_limits};
#     649                 :            : 
#     650                 :       5696 :         limit_ancestor_count = limits.ancestor_count;
#     651                 :       5696 :         limit_descendant_count = limits.descendant_count;
#     652                 :       5696 :     }
#     653                 :            :     bool checkChainLimits(const CTransactionRef& tx) override
#     654                 :       5431 :     {
#     655         [ -  + ]:       5431 :         if (!m_node.mempool) return true;
#     656                 :       5431 :         LockPoints lp;
#     657                 :       5431 :         CTxMemPoolEntry entry(tx, 0, 0, 0, false, 0, lp);
#     658                 :       5431 :         CTxMemPool::setEntries ancestors;
#     659                 :       5431 :         const CTxMemPool::Limits& limits{m_node.mempool->m_limits};
#     660                 :       5431 :         std::string unused_error_string;
#     661                 :       5431 :         LOCK(m_node.mempool->cs);
#     662                 :       5431 :         return m_node.mempool->CalculateMemPoolAncestors(
#     663                 :       5431 :             entry, ancestors, limits.ancestor_count, limits.ancestor_size_vbytes,
#     664                 :       5431 :             limits.descendant_count, limits.descendant_size_vbytes, unused_error_string);
#     665                 :       5431 :     }
#     666                 :            :     CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
#     667                 :      10287 :     {
#     668         [ -  + ]:      10287 :         if (!m_node.fee_estimator) return {};
#     669                 :      10287 :         return m_node.fee_estimator->estimateSmartFee(num_blocks, calc, conservative);
#     670                 :      10287 :     }
#     671                 :            :     unsigned int estimateMaxBlocks() override
#     672                 :       5771 :     {
#     673         [ -  + ]:       5771 :         if (!m_node.fee_estimator) return 0;
#     674                 :       5771 :         return m_node.fee_estimator->HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
#     675                 :       5771 :     }
#     676                 :            :     CFeeRate mempoolMinFee() override
#     677                 :       4599 :     {
#     678         [ -  + ]:       4599 :         if (!m_node.mempool) return {};
#     679                 :       4599 :         return m_node.mempool->GetMinFee();
#     680                 :       4599 :     }
#     681                 :            :     CFeeRate relayMinFee() override
#     682                 :       6444 :     {
#     683         [ -  + ]:       6444 :         if (!m_node.mempool) return CFeeRate{DEFAULT_MIN_RELAY_TX_FEE};
#     684                 :       6444 :         return m_node.mempool->m_min_relay_feerate;
#     685                 :       6444 :     }
#     686                 :            :     CFeeRate relayIncrementalFee() override
#     687                 :        196 :     {
#     688         [ -  + ]:        196 :         if (!m_node.mempool) return CFeeRate{DEFAULT_INCREMENTAL_RELAY_FEE};
#     689                 :        196 :         return m_node.mempool->m_incremental_relay_feerate;
#     690                 :        196 :     }
#     691                 :            :     CFeeRate relayDustFee() override
#     692                 :      64990 :     {
#     693         [ -  + ]:      64990 :         if (!m_node.mempool) return CFeeRate{DUST_RELAY_TX_FEE};
#     694                 :      64990 :         return m_node.mempool->m_dust_relay_feerate;
#     695                 :      64990 :     }
#     696                 :            :     bool havePruned() override
#     697                 :        331 :     {
#     698                 :        331 :         LOCK(::cs_main);
#     699                 :        331 :         return chainman().m_blockman.m_have_pruned;
#     700                 :        331 :     }
#     701 [ +  - ][ +  - ]:       8342 :     bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); }
#                 [ +  + ]
#     702                 :      13950 :     bool isInitialBlockDownload() override {
#     703                 :      13950 :         return chainman().ActiveChainstate().IsInitialBlockDownload();
#     704                 :      13950 :     }
#     705                 :     111649 :     bool shutdownRequested() override { return ShutdownRequested(); }
#     706                 :       1680 :     void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
#     707                 :          3 :     void initWarning(const bilingual_str& message) override { InitWarning(message); }
#     708                 :         28 :     void initError(const bilingual_str& message) override { InitError(message); }
#     709                 :            :     void showProgress(const std::string& title, int progress, bool resume_possible) override
#     710                 :       3526 :     {
#     711                 :       3526 :         ::uiInterface.ShowProgress(title, progress, resume_possible);
#     712                 :       3526 :     }
#     713                 :            :     std::unique_ptr<Handler> handleNotifications(std::shared_ptr<Notifications> notifications) override
#     714                 :        808 :     {
#     715                 :        808 :         return std::make_unique<NotificationsHandlerImpl>(std::move(notifications));
#     716                 :        808 :     }
#     717                 :            :     void waitForNotificationsIfTipChanged(const uint256& old_tip) override
#     718                 :       9678 :     {
#     719 [ +  - ][ +  + ]:       9678 :         if (!old_tip.IsNull() && old_tip == WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip()->GetBlockHash())) return;
#                 [ +  + ]
#     720                 :        283 :         SyncWithValidationInterfaceQueue();
#     721                 :        283 :     }
#     722                 :            :     std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
#     723                 :      54252 :     {
#     724                 :      54252 :         return std::make_unique<RpcHandlerImpl>(command);
#     725                 :      54252 :     }
#     726                 :          0 :     bool rpcEnableDeprecated(const std::string& method) override { return IsDeprecatedRPCEnabled(method); }
#     727                 :            :     void rpcRunLater(const std::string& name, std::function<void()> fn, int64_t seconds) override
#     728                 :         62 :     {
#     729                 :         62 :         RPCRunLater(name, std::move(fn), seconds);
#     730                 :         62 :     }
#     731                 :        507 :     int rpcSerializationFlags() override { return RPCSerializationFlags(); }
#     732                 :            :     util::SettingsValue getSetting(const std::string& name) override
#     733                 :          0 :     {
#     734                 :          0 :         return gArgs.GetSetting(name);
#     735                 :          0 :     }
#     736                 :            :     std::vector<util::SettingsValue> getSettingsList(const std::string& name) override
#     737                 :       1531 :     {
#     738                 :       1531 :         return gArgs.GetSettingsList(name);
#     739                 :       1531 :     }
#     740                 :            :     util::SettingsValue getRwSetting(const std::string& name) override
#     741                 :        240 :     {
#     742                 :        240 :         util::SettingsValue result;
#     743                 :        240 :         gArgs.LockSettings([&](const util::Settings& settings) {
#     744         [ +  + ]:        240 :             if (const util::SettingsValue* value = util::FindKey(settings.rw_settings, name)) {
#     745                 :         18 :                 result = *value;
#     746                 :         18 :             }
#     747                 :        240 :         });
#     748                 :        240 :         return result;
#     749                 :        240 :     }
#     750                 :            :     bool updateRwSetting(const std::string& name, const util::SettingsValue& value, bool write) override
#     751                 :        232 :     {
#     752                 :        232 :         gArgs.LockSettings([&](util::Settings& settings) {
#     753         [ -  + ]:        232 :             if (value.isNull()) {
#     754                 :          0 :                 settings.rw_settings.erase(name);
#     755                 :        232 :             } else {
#     756                 :        232 :                 settings.rw_settings[name] = value;
#     757                 :        232 :             }
#     758                 :        232 :         });
#     759 [ +  + ][ +  - ]:        232 :         return !write || gArgs.WriteSettingsFile();
#     760                 :        232 :     }
#     761                 :            :     void requestMempoolTransactions(Notifications& notifications) override
#     762                 :       1635 :     {
#     763         [ -  + ]:       1635 :         if (!m_node.mempool) return;
#     764                 :       1635 :         LOCK2(::cs_main, m_node.mempool->cs);
#     765         [ +  + ]:       1678 :         for (const CTxMemPoolEntry& entry : m_node.mempool->mapTx) {
#     766                 :       1678 :             notifications.transactionAddedToMempool(entry.GetSharedTx(), 0 /* mempool_sequence */);
#     767                 :       1678 :         }
#     768                 :       1635 :     }
#     769                 :            :     bool hasAssumedValidChain() override
#     770                 :         87 :     {
#     771                 :         87 :         return chainman().IsSnapshotActive();
#     772                 :         87 :     }
#     773                 :            : 
#     774                 :         57 :     NodeContext* context() override { return &m_node; }
#     775                 :     775196 :     ChainstateManager& chainman() { return *Assert(m_node.chainman); }
#     776                 :            :     NodeContext& m_node;
#     777                 :            : };
#     778                 :            : } // namespace
#     779                 :            : } // namespace node
#     780                 :            : 
#     781                 :            : namespace interfaces {
#     782                 :          1 : std::unique_ptr<Node> MakeNode(node::NodeContext& context) { return std::make_unique<node::NodeImpl>(context); }
#     783                 :       1732 : std::unique_ptr<Chain> MakeChain(node::NodeContext& context) { return std::make_unique<node::ChainImpl>(context); }
#     784                 :            : } // namespace interfaces

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a