diff --git a/src/net.cpp b/src/net.cpp index 0f49b8ad5a..ba3f303a73 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -429,7 +429,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo std::vector resolved; if (Lookup(pszDest, resolved, default_port, fNameLookup && !HaveNameProxy(), 256) && !resolved.empty()) { const CService rnd{resolved[GetRand(resolved.size())]}; - addrConnect = CAddress{MaybeFlipIPv6toCJDNS(rnd), NODE_NONE}; + addrConnect = CAddress{MaybeFlipIPv6toCJDNS(rnd), addrConnect.nServices}; if (!addrConnect.IsValid()) { LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s\n", addrConnect.ToString(), pszDest); return nullptr; @@ -2146,7 +2146,7 @@ std::vector CConnman::GetAddedNodeInfo() const { std::vector ret; - std::list lAddresses(0); + std::list> lAddresses(0); { LOCK(m_added_nodes_mutex); ret.reserve(m_added_nodes.size()); @@ -2170,9 +2170,13 @@ std::vector CConnman::GetAddedNodeInfo() const } } - for (const std::string& strAddNode : lAddresses) { + std::string strAddNode; + bool use_p2p_v2; + + for (auto addr : lAddresses) { + std::tie(strAddNode, use_p2p_v2) = addr; CService service(LookupNumeric(strAddNode, Params().GetDefaultPort(strAddNode))); - AddedNodeInfo addedNode{strAddNode, CService(), false, false}; + AddedNodeInfo addedNode{strAddNode, CService(), false, false, use_p2p_v2}; if (service.IsValid()) { // strAddNode is an IP:port auto it = mapConnected.find(service); @@ -2180,6 +2184,7 @@ std::vector CConnman::GetAddedNodeInfo() const addedNode.resolvedAddress = service; addedNode.fConnected = true; addedNode.fInbound = it->second; + addedNode.use_p2p_v2 = use_p2p_v2; } } else { // strAddNode is a name @@ -2188,6 +2193,7 @@ std::vector CConnman::GetAddedNodeInfo() const addedNode.resolvedAddress = it->second.second; addedNode.fConnected = true; addedNode.fInbound = it->second.first; + addedNode.use_p2p_v2 = use_p2p_v2; } } ret.emplace_back(std::move(addedNode)); @@ -2213,6 +2219,11 @@ void CConnman::ThreadOpenAddedConnections() } tried = true; CAddress addr(CService(), NODE_NONE); + + if (info.use_p2p_v2) { + addr.nServices = ServiceFlags(addr.nServices | NODE_P2P_V2); + } + OpenNetworkConnection(addr, false, &grant, info.strAddedNode.c_str(), ConnectionType::MANUAL); if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) return; @@ -2789,22 +2800,22 @@ std::vector CConnman::GetAddresses(CNode& requestor, size_t max_addres return cache_entry.m_addrs_response_cache; } -bool CConnman::AddNode(const std::string& strNode) +bool CConnman::AddNode(const std::string& strNode, const bool use_p2p_v2) { LOCK(m_added_nodes_mutex); - for (const std::string& it : m_added_nodes) { - if (strNode == it) return false; + for (auto it : m_added_nodes) { + if (strNode == it.first) return false; } - m_added_nodes.push_back(strNode); + m_added_nodes.push_back(std::make_pair(strNode, use_p2p_v2)); return true; } bool CConnman::RemoveAddedNode(const std::string& strNode) { LOCK(m_added_nodes_mutex); - for(std::vector::iterator it = m_added_nodes.begin(); it != m_added_nodes.end(); ++it) { - if (strNode == *it) { + for(auto it = m_added_nodes.begin(); it != m_added_nodes.end(); ++it) { + if (strNode == it->first) { m_added_nodes.erase(it); return true; } @@ -2977,7 +2988,8 @@ ServiceFlags CConnman::GetLocalServices() const unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion) - : m_connected{GetTime()}, + : nServices(addrIn.nServices), + m_connected(GetTimeSeconds()), addr(addrIn), addrBind(addrBindIn), m_addr_name{addrNameIn.empty() ? addr.ToStringIPPort() : addrNameIn}, diff --git a/src/net.h b/src/net.h index 9623a630e7..9c0e3db90a 100644 --- a/src/net.h +++ b/src/net.h @@ -34,6 +34,7 @@ #include #include #include +#include #include class AddrMan; @@ -92,6 +93,7 @@ struct AddedNodeInfo CService resolvedAddress; bool fConnected; bool fInbound; + bool use_p2p_v2; }; class CNodeStats; @@ -792,7 +794,10 @@ class CConnman vWhitelistedRange = connOptions.vWhitelistedRange; { LOCK(m_added_nodes_mutex); - m_added_nodes = connOptions.m_added_nodes; + + for (const std::string& strAddedNode: connOptions.m_added_nodes) { + m_added_nodes.push_back(std::make_pair(strAddedNode, false)); + } } m_onion_binds = connOptions.onion_binds; } @@ -876,7 +881,7 @@ class CConnman // Count the number of block-relay-only peers we have over our limit. int GetExtraBlockRelayCount() const; - bool AddNode(const std::string& node); + bool AddNode(const std::string& node, const bool use_p2p_v2); bool RemoveAddedNode(const std::string& node); std::vector GetAddedNodeInfo() const; @@ -1099,7 +1104,10 @@ class CConnman AddrMan& addrman; std::deque m_addr_fetches GUARDED_BY(m_addr_fetches_mutex); Mutex m_addr_fetches_mutex; - std::vector m_added_nodes GUARDED_BY(m_added_nodes_mutex); + + // connection string and whether to use v2 p2p + std::vector> m_added_nodes GUARDED_BY(m_added_nodes_mutex); + mutable Mutex m_added_nodes_mutex; std::vector m_nodes GUARDED_BY(m_nodes_mutex); std::list m_nodes_disconnected; diff --git a/src/protocol.cpp b/src/protocol.cpp index 7506c81815..d2652b07f4 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -196,6 +196,7 @@ static std::string serviceFlagToStr(size_t bit) case NODE_WITNESS: return "WITNESS"; case NODE_COMPACT_FILTERS: return "COMPACT_FILTERS"; case NODE_NETWORK_LIMITED: return "NETWORK_LIMITED"; + case NODE_P2P_V2: return "P2P_V2"; // Not using default, so we get warned when a case is missing } diff --git a/src/protocol.h b/src/protocol.h index 2149e45993..81689e4994 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -290,6 +290,9 @@ enum ServiceFlags : uint64_t { // See BIP159 for details on how this is implemented. NODE_NETWORK_LIMITED = (1 << 10), + // NODE_P2P_V2 means the node supports BIP324 transport + NODE_P2P_V2 = (1 << 11), + // Bits 24-31 are reserved for temporary experiments. Just pick a bit that // isn't getting used, or one not being used much, and notify the // bitcoin-development mailing list. Remember that service bits are just diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index a171972da3..afdeb65b8b 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -201,6 +201,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "addpeeraddress", 1, "port"}, { "addpeeraddress", 2, "tried"}, { "stop", 0, "wait" }, + { "addnode", 2, "p2p_v2" }, }; // clang-format on diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 557b1296a6..c018720cd9 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -276,11 +276,12 @@ static RPCHelpMan addnode() { {"node", RPCArg::Type::STR, RPCArg::Optional::NO, "The node (see getpeerinfo for nodes)"}, {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once"}, + {"p2p_v2", RPCArg::Type::BOOL, RPCArg::Default{false}, "Peer supports BIP324 v2 transport protocol"}, }, RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{ - HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\"") - + HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"") + HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\" true") + + HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\" true") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -296,17 +297,21 @@ static RPCHelpMan addnode() CConnman& connman = EnsureConnman(node); std::string strNode = request.params[0].get_str(); + bool use_p2p_v2 = !request.params[2].isNull() && request.params[2].get_bool(); if (strCommand == "onetry") { CAddress addr; + if (use_p2p_v2) { + addr.nServices = ServiceFlags(addr.nServices | NODE_P2P_V2); + } connman.OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), ConnectionType::MANUAL); return NullUniValue; } if (strCommand == "add") { - if (!connman.AddNode(strNode)) { + if (!connman.AddNode(strNode, use_p2p_v2)) { throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added"); } } diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp index f87b6f1503..8382f966af 100644 --- a/src/test/fuzz/connman.cpp +++ b/src/test/fuzz/connman.cpp @@ -45,7 +45,7 @@ FUZZ_TARGET_INIT(connman, initialize_connman) random_string = fuzzed_data_provider.ConsumeRandomLengthString(64); }, [&] { - connman.AddNode(random_string); + connman.AddNode(random_string, fuzzed_data_provider.ConsumeBool()); }, [&] { connman.CheckIncomingNonce(fuzzed_data_provider.ConsumeIntegral());