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