diff --git a/src/banman.h b/src/banman.h --- a/src/banman.h +++ b/src/banman.h @@ -69,6 +69,5 @@ const int64_t m_default_ban_time; }; -extern std::unique_ptr g_banman; #endif // BITCOIN_BANMAN_H diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -87,10 +87,6 @@ // Dump addresses to banlist.dat every 15 minutes (900s) static constexpr int DUMP_BANS_INTERVAL = 60 * 15; -std::unique_ptr g_connman; -std::unique_ptr peerLogic; -std::unique_ptr g_banman; - #ifdef WIN32 // Win32 LevelDB doesn't use filedescriptors, and the ones used for accessing // block files don't count towards the fd_set size limit anyway. @@ -194,8 +190,8 @@ // the scheduler will stop working then. g_avalanche->stopEventLoop(); } - if (g_connman) { - g_connman->Interrupt(); + if (node.connman) { + node.connman->Interrupt(); } if (g_txindex) { g_txindex->Interrupt(); @@ -239,11 +235,11 @@ // Because these depend on each-other, we make sure that neither can be // using the other before destroying them. - if (peerLogic) { - UnregisterValidationInterface(peerLogic.get()); + if (node.peer_logic) { + UnregisterValidationInterface(node.peer_logic.get()); } - if (g_connman) { - g_connman->Stop(); + if (node.connman) { + node.connman->Stop(); } if (g_txindex) { g_txindex->Stop(); @@ -259,12 +255,12 @@ // After the threads that potentially access these pointers have been // stopped, destruct and reset all to nullptr. - peerLogic.reset(); + node.peer_logic.reset(); // Destroy various global instances g_avalanche.reset(); - g_connman.reset(); - g_banman.reset(); + node.connman.reset(); + node.banman.reset(); g_txindex.reset(); DestroyAllBlockFilterIndexes(); @@ -2172,19 +2168,19 @@ // is not yet setup and may end up being set up twice if we // need to reindex later. - assert(!g_banman); - g_banman = std::make_unique( + assert(!node.banman); + node.banman = std::make_unique( GetDataDir() / "banlist.dat", config.GetChainParams(), &uiInterface, gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME)); - assert(!g_connman); - g_connman = std::make_unique( + assert(!node.connman); + node.connman = std::make_unique( config, GetRand(std::numeric_limits::max()), GetRand(std::numeric_limits::max())); - peerLogic = std::make_unique( - g_connman.get(), g_banman.get(), scheduler, + node.peer_logic = std::make_unique( + node.connman.get(), node.banman.get(), scheduler, gArgs.GetBoolArg("-enablebip61", DEFAULT_ENABLE_BIP61)); - RegisterValidationInterface(peerLogic.get()); + RegisterValidationInterface(node.peer_logic.get()); // sanitize comments per BIP-0014, format user agent and check total size std::vector uacomments; @@ -2321,7 +2317,7 @@ } // Step 6.5 (I guess ?): Initialize Avalanche. - g_avalanche = std::make_unique(g_connman.get()); + g_avalanche = std::make_unique(node.connman.get()); // Step 7: load block chain @@ -2696,8 +2692,8 @@ connOptions.nMaxFeeler = 1; connOptions.nBestHeight = chain_active_height; connOptions.uiInterface = &uiInterface; - connOptions.m_banman = g_banman.get(); - connOptions.m_msgproc = peerLogic.get(); + connOptions.m_banman = node.banman.get(); + connOptions.m_msgproc = node.peer_logic.get(); connOptions.nSendBufferMaxSize = 1000 * gArgs.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); connOptions.nReceiveFloodSize = @@ -2744,7 +2740,7 @@ connOptions.m_specified_outgoing = connect; } } - if (!g_connman->Start(scheduler, connOptions)) { + if (!node.connman->Start(scheduler, connOptions)) { return false; } @@ -2757,7 +2753,7 @@ client->start(scheduler); } - BanMan *banman = g_banman.get(); + BanMan *banman = node.banman.get(); scheduler.scheduleEvery( [banman] { banman->DumpBanlist(); diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -296,7 +296,7 @@ return it && (*it)->GetCountWithDescendants() > 1; } void relayTransaction(const TxId &txid) override { - RelayTransaction(txid, *g_connman); + RelayTransaction(txid, *m_node.connman); } bool broadcastTransaction(const Config &config, const CTransactionRef &tx, @@ -346,7 +346,7 @@ CFeeRate relayMinFee() override { return ::minRelayTxFee; } CFeeRate relayDustFee() override { return ::dustRelayFee; } bool getPruneMode() override { return ::fPruneMode; } - bool p2pEnabled() override { return g_connman != nullptr; } + bool p2pEnabled() override { return m_node.connman != nullptr; } bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); } diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -120,14 +120,15 @@ return GetProxy(net, proxy_info); } size_t getNodeCount(CConnman::NumConnections flags) override { - return g_connman ? g_connman->GetNodeCount(flags) : 0; + return m_context.connman ? m_context.connman->GetNodeCount(flags) + : 0; } bool getNodesStats(NodesStats &stats) override { stats.clear(); - if (g_connman) { + if (m_context.connman) { std::vector stats_temp; - g_connman->GetNodeStats(stats_temp); + m_context.connman->GetNodeStats(stats_temp); stats.reserve(stats_temp.size()); for (auto &node_stats_temp : stats_temp) { @@ -149,44 +150,46 @@ return false; } bool getBanned(banmap_t &banmap) override { - if (g_banman) { - g_banman->GetBanned(banmap); + if (m_context.banman) { + m_context.banman->GetBanned(banmap); return true; } return false; } bool ban(const CNetAddr &net_addr, BanReason reason, int64_t ban_time_offset) override { - if (g_banman) { - g_banman->Ban(net_addr, reason, ban_time_offset); + if (m_context.banman) { + m_context.banman->Ban(net_addr, reason, ban_time_offset); return true; } return false; } bool unban(const CSubNet &ip) override { - if (g_banman) { - g_banman->Unban(ip); + if (m_context.banman) { + m_context.banman->Unban(ip); return true; } return false; } bool disconnect(const CNetAddr &net_addr) override { - if (g_connman) { - return g_connman->DisconnectNode(net_addr); + if (m_context.connman) { + return m_context.connman->DisconnectNode(net_addr); } return false; } bool disconnect(NodeId id) override { - if (g_connman) { - return g_connman->DisconnectNode(id); + if (m_context.connman) { + return m_context.connman->DisconnectNode(id); } return false; } int64_t getTotalBytesRecv() override { - return g_connman ? g_connman->GetTotalBytesRecv() : 0; + return m_context.connman ? m_context.connman->GetTotalBytesRecv() + : 0; } int64_t getTotalBytesSent() override { - return g_connman ? g_connman->GetTotalBytesSent() : 0; + return m_context.connman ? m_context.connman->GetTotalBytesSent() + : 0; } size_t getMempoolSize() override { return g_mempool.size(); } size_t getMempoolDynamicUsage() override { @@ -227,12 +230,12 @@ bool getReindex() override { return ::fReindex; } bool getImporting() override { return ::fImporting; } void setNetworkActive(bool active) override { - if (g_connman) { - g_connman->SetNetworkActive(active); + if (m_context.connman) { + m_context.connman->SetNetworkActive(active); } } bool getNetworkActive() override { - return g_connman && g_connman->GetNetworkActive(); + return m_context.connman && m_context.connman->GetNetworkActive(); } CFeeRate estimateSmartFee() override { return g_mempool.estimateFee(); } CFeeRate getDustRelayFee() override { return ::dustRelayFee; } diff --git a/src/net.h b/src/net.h --- a/src/net.h +++ b/src/net.h @@ -471,8 +471,6 @@ friend struct CConnmanTest; }; -extern std::unique_ptr g_connman; -extern std::unique_ptr g_banman; void Discover(); void StartMapPort(); void InterruptMapPort(); diff --git a/src/node/context.h b/src/node/context.h --- a/src/node/context.h +++ b/src/node/context.h @@ -8,6 +8,9 @@ #include #include +class BanMan; +class CConnman; +class PeerLogicValidation; namespace interfaces { class Chain; class ChainClient; @@ -24,6 +27,9 @@ //! any member functions. It should just be a collection of references that can //! be used without pulling in unwanted dependencies or functionality. struct NodeContext { + std::unique_ptr connman; + std::unique_ptr peer_logic; + std::unique_ptr banman; std::unique_ptr chain; std::vector> chain_clients; diff --git a/src/node/context.cpp b/src/node/context.cpp --- a/src/node/context.cpp +++ b/src/node/context.cpp @@ -4,7 +4,10 @@ #include +#include #include +#include +#include NodeContext::NodeContext() {} NodeContext::~NodeContext() {} diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -23,7 +23,7 @@ std::string &err_string, const Amount max_tx_fee, bool relay, bool wait_callback) { - assert(g_connman); + assert(node.connman); std::promise promise; TxId txid = tx->GetId(); bool callback_set = false; @@ -77,7 +77,7 @@ } if (relay) { - RelayTransaction(txid, *g_connman); + RelayTransaction(txid, *node.connman); } return TransactionError::OK; diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -112,6 +112,7 @@ test.CreateAndProcessBlock( {}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey())); } + node.context()->connman = std::move(test.m_node.connman); std::shared_ptr wallet = std::make_shared( Params(), node.context()->chain.get(), WalletLocation(), WalletDatabase::CreateMock()); diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -14,6 +14,7 @@ class Config; class CTxMemPool; class JSONRPCRequest; +struct NodeContext; extern RecursiveMutex cs_main; @@ -46,4 +47,9 @@ const CBlockIndex *blockindex) LOCKS_EXCLUDED(cs_main); +//! Pointer to node state that needs to be declared as a global to be accessible +//! RPC methods. Due to limitations of the RPC framework, there's currently no +//! direct way to pass in state to RPC methods without globals. +extern NodeContext *g_rpc_node; + #endif // BITCOIN_RPC_BLOCKCHAIN_H diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -548,13 +548,13 @@ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); } - if (!g_connman) { + if (!g_rpc_node->connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } - if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) { + if (g_rpc_node->connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) { throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Bitcoin is not connected!"); } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -41,13 +41,13 @@ .ToString()); } - if (!g_connman) { + if (!g_rpc_node->connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } - return int(g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)); + return int(g_rpc_node->connman->GetNodeCount(CConnman::CONNECTIONS_ALL)); } static UniValue ping(const Config &config, const JSONRPCRequest &request) { @@ -68,14 +68,15 @@ .ToString()); } - if (!g_connman) { + if (!g_rpc_node->connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } // Request that each node send a ping during next message processing pass - g_connman->ForEachNode([](CNode *pnode) { pnode->fPingQueued = true; }); + g_rpc_node->connman->ForEachNode( + [](CNode *pnode) { pnode->fPingQueued = true; }); return NullUniValue; } @@ -163,14 +164,14 @@ .ToString()); } - if (!g_connman) { + if (!g_rpc_node->connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } std::vector vstats; - g_connman->GetNodeStats(vstats); + g_rpc_node->connman->GetNodeStats(vstats); UniValue ret(UniValue::VARR); @@ -285,7 +286,7 @@ .ToString()); } - if (!g_connman) { + if (!g_rpc_node->connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -295,16 +296,16 @@ if (strCommand == "onetry") { CAddress addr; - g_connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), - false, false, true); + g_rpc_node->connman->OpenNetworkConnection( + addr, false, nullptr, strNode.c_str(), false, false, true); return NullUniValue; } - if ((strCommand == "add") && (!g_connman->AddNode(strNode))) { + if ((strCommand == "add") && (!g_rpc_node->connman->AddNode(strNode))) { throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added"); } else if ((strCommand == "remove") && - (!g_connman->RemoveAddedNode(strNode))) { + (!g_rpc_node->connman->RemoveAddedNode(strNode))) { throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); } @@ -341,7 +342,7 @@ .ToString()); } - if (!g_connman) { + if (!g_rpc_node->connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -353,13 +354,13 @@ if (!address_arg.isNull() && id_arg.isNull()) { /* handle disconnect-by-address */ - success = g_connman->DisconnectNode(address_arg.get_str()); + success = g_rpc_node->connman->DisconnectNode(address_arg.get_str()); } else if (!id_arg.isNull() && (address_arg.isNull() || (address_arg.isStr() && address_arg.get_str().empty()))) { /* handle disconnect-by-id */ NodeId nodeid = (NodeId)id_arg.get_int64(); - success = g_connman->DisconnectNode(nodeid); + success = g_rpc_node->connman->DisconnectNode(nodeid); } else { throw JSONRPCError( RPC_INVALID_PARAMS, @@ -413,13 +414,13 @@ .ToString()); } - if (!g_connman) { + if (!g_rpc_node->connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } - std::vector vInfo = g_connman->GetAddedNodeInfo(); + std::vector vInfo = g_rpc_node->connman->GetAddedNodeInfo(); if (!request.params[0].isNull()) { bool found = false; @@ -493,28 +494,29 @@ .ToString()); } - if (!g_connman) { + if (!g_rpc_node->connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } UniValue obj(UniValue::VOBJ); - obj.pushKV("totalbytesrecv", g_connman->GetTotalBytesRecv()); - obj.pushKV("totalbytessent", g_connman->GetTotalBytesSent()); + obj.pushKV("totalbytesrecv", g_rpc_node->connman->GetTotalBytesRecv()); + obj.pushKV("totalbytessent", g_rpc_node->connman->GetTotalBytesSent()); obj.pushKV("timemillis", GetTimeMillis()); UniValue outboundLimit(UniValue::VOBJ); - outboundLimit.pushKV("timeframe", g_connman->GetMaxOutboundTimeframe()); - outboundLimit.pushKV("target", g_connman->GetMaxOutboundTarget()); + outboundLimit.pushKV("timeframe", + g_rpc_node->connman->GetMaxOutboundTimeframe()); + outboundLimit.pushKV("target", g_rpc_node->connman->GetMaxOutboundTarget()); outboundLimit.pushKV("target_reached", - g_connman->OutboundTargetReached(false)); + g_rpc_node->connman->OutboundTargetReached(false)); outboundLimit.pushKV("serve_historical_blocks", - !g_connman->OutboundTargetReached(true)); + !g_rpc_node->connman->OutboundTargetReached(true)); outboundLimit.pushKV("bytes_left_in_cycle", - g_connman->GetOutboundTargetBytesLeft()); + g_rpc_node->connman->GetOutboundTargetBytesLeft()); outboundLimit.pushKV("time_left_in_cycle", - g_connman->GetMaxOutboundTimeLeftInCycle()); + g_rpc_node->connman->GetMaxOutboundTimeLeftInCycle()); obj.pushKV("uploadtarget", outboundLimit); return obj; } @@ -615,16 +617,16 @@ obj.pushKV("version", CLIENT_VERSION); obj.pushKV("subversion", userAgent(config)); obj.pushKV("protocolversion", PROTOCOL_VERSION); - if (g_connman) { + if (g_rpc_node->connman) { obj.pushKV("localservices", - strprintf("%016x", g_connman->GetLocalServices())); + strprintf("%016x", g_rpc_node->connman->GetLocalServices())); } obj.pushKV("localrelay", fRelayTxes); obj.pushKV("timeoffset", GetTimeOffset()); - if (g_connman) { - obj.pushKV("networkactive", g_connman->GetNetworkActive()); - obj.pushKV("connections", - int(g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL))); + if (g_rpc_node->connman) { + obj.pushKV("networkactive", g_rpc_node->connman->GetNetworkActive()); + obj.pushKV("connections", int(g_rpc_node->connman->GetNodeCount( + CConnman::CONNECTIONS_ALL))); } obj.pushKV("networks", GetNetworksInfo()); obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())); @@ -684,7 +686,7 @@ throw std::runtime_error(help.ToString()); } - if (!g_banman) { + if (!g_rpc_node->banman) { throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); } @@ -711,8 +713,8 @@ } if (strCommand == "add") { - if (isSubnet ? g_banman->IsBanned(subNet) - : g_banman->IsBanned(netAddr)) { + if (isSubnet ? g_rpc_node->banman->IsBanned(subNet) + : g_rpc_node->banman->IsBanned(netAddr)) { throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned"); } @@ -729,18 +731,21 @@ } if (isSubnet) { - g_banman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute); - if (g_connman) { - g_connman->DisconnectNode(subNet); + g_rpc_node->banman->Ban(subNet, BanReasonManuallyAdded, banTime, + absolute); + if (g_rpc_node->connman) { + g_rpc_node->connman->DisconnectNode(subNet); } } else { - g_banman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute); - if (g_connman) { - g_connman->DisconnectNode(netAddr); + g_rpc_node->banman->Ban(netAddr, BanReasonManuallyAdded, banTime, + absolute); + if (g_rpc_node->connman) { + g_rpc_node->connman->DisconnectNode(netAddr); } } } else if (strCommand == "remove") { - if (!(isSubnet ? g_banman->Unban(subNet) : g_banman->Unban(netAddr))) { + if (!(isSubnet ? g_rpc_node->banman->Unban(subNet) + : g_rpc_node->banman->Unban(netAddr))) { throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet " "was not previously banned."); @@ -763,13 +768,13 @@ .ToString()); } - if (!g_banman) { + if (!g_rpc_node->banman) { throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); } banmap_t banMap; - g_banman->GetBanned(banMap); + g_rpc_node->banman->GetBanned(banMap); UniValue bannedAddresses(UniValue::VARR); for (const auto &entry : banMap) { @@ -799,13 +804,13 @@ } .ToString()); } - if (!g_banman) { + if (!g_rpc_node->banman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } - g_banman->ClearBanned(); + g_rpc_node->banman->ClearBanned(); return NullUniValue; } @@ -826,15 +831,15 @@ .ToString()); } - if (!g_connman) { + if (!g_rpc_node->connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } - g_connman->SetNetworkActive(request.params[0].get_bool()); + g_rpc_node->connman->SetNetworkActive(request.params[0].get_bool()); - return g_connman->GetNetworkActive(); + return g_rpc_node->connman->GetNetworkActive(); } static UniValue getnodeaddresses(const Config &config, @@ -871,7 +876,7 @@ } .ToString()); } - if (!g_connman) { + if (!g_rpc_node->connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -886,7 +891,7 @@ } } // returns a shuffled list of CAddress - std::vector vAddr = g_connman->GetAddresses(); + std::vector vAddr = g_rpc_node->connman->GetAddresses(); UniValue ret(UniValue::VARR); int address_return_count = std::min(count, vAddr.size()); diff --git a/src/test/avalanche_tests.cpp b/src/test/avalanche_tests.cpp --- a/src/test/avalanche_tests.cpp +++ b/src/test/avalanche_tests.cpp @@ -956,7 +956,7 @@ std::thread schedulerThread(std::bind(&CScheduler::serviceQueue, &s)); { - AvalancheProcessor p(g_connman.get()); + AvalancheProcessor p(m_node.connman.get()); BOOST_CHECK(p.startEventLoop(s)); BOOST_CHECK_EQUAL(s.getQueueInfo(start, stop), 1); } diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include