diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py index 75cb6fad6e80c..f4438b655c1f5 100755 --- a/contrib/seeds/generate-seeds.py +++ b/contrib/seeds/generate-seeds.py @@ -40,6 +40,7 @@ class BIP155Network(Enum): TORV3 = 4 I2P = 5 CJDNS = 6 + HOSTNAME = 1993 def name_to_bip155(addr): '''Convert address string to BIP155 (networkID, addr) tuple.''' diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 05eb2738c516e..0ecd4b6c7f2ad 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -238,6 +238,7 @@ class CMainParams : public CChainParams { pchMessageStart[1] = 0x0c; pchMessageStart[2] = 0x6b; pchMessageStart[3] = 0xbd; + // magic numbers and ports here nDefaultPort = 9999; nDefaultPlatformP2PPort = 26656; nDefaultPlatformHTTPPort = 443; @@ -431,6 +432,7 @@ class CTestNetParams : public CChainParams { pchMessageStart[1] = 0xe2; pchMessageStart[2] = 0xca; pchMessageStart[3] = 0xff; + // more magic ports nDefaultPort = 19999; nDefaultPlatformP2PPort = 22000; nDefaultPlatformHTTPPort = 22001; @@ -603,6 +605,7 @@ class CDevNetParams : public CChainParams { pchMessageStart[1] = 0xca; pchMessageStart[2] = 0xff; pchMessageStart[3] = 0xce; + // more magic ports nDefaultPort = 19799; nDefaultPlatformP2PPort = 22100; nDefaultPlatformHTTPPort = 22101; @@ -851,6 +854,7 @@ class CRegTestParams : public CChainParams { pchMessageStart[1] = 0xc1; pchMessageStart[2] = 0xb7; pchMessageStart[3] = 0xdc; + // more magic ports nDefaultPort = 19899; nDefaultPlatformP2PPort = 22200; nDefaultPlatformHTTPPort = 22201; diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index 2a0bc7c9ef58b..bd2aafba46af9 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -1429,6 +1429,7 @@ static bool CheckService(const ProTx& proTx, TxValidationState& state) } static int mainnetDefaultPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort(); + // DON'T HARD CODE IT, DUH! if (Params().NetworkIDString() == CBaseChainParams::MAIN) { if (proTx.addr.GetPort() != mainnetDefaultPort) { return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-ipaddr-port"); diff --git a/src/evo/providertx.h b/src/evo/providertx.h index d7f8f259ffbab..b4b24256da1e5 100644 --- a/src/evo/providertx.h +++ b/src/evo/providertx.h @@ -22,6 +22,7 @@ class CBlockIndex; class CCoinsViewCache; class TxValidationState; +// CProRegTx is defined here class CProRegTx { public: diff --git a/src/netaddress.cpp b/src/netaddress.cpp index ac6afed471a55..8ae23de7c5aa6 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -36,6 +36,8 @@ CNetAddr::BIP155Network CNetAddr::GetBIP155Network() const return BIP155Network::I2P; case NET_CJDNS: return BIP155Network::CJDNS; + case NET_HOSTNAME: + return BIP155Network::HOSTNAME; case NET_INTERNAL: // should have been handled before calling this function case NET_UNROUTABLE: // m_net is never and should not be set to NET_UNROUTABLE case NET_MAX: // m_net is never and should not be set to NET_MAX @@ -88,6 +90,14 @@ bool CNetAddr::SetNetFromBIP155Network(uint8_t possible_bip155_net, size_t addre throw std::ios_base::failure( strprintf("BIP155 CJDNS address with length %u (should be %u)", address_size, ADDR_CJDNS_SIZE)); + case BIP155Network::HOSTNAME: + if (address_size == ADDR_HOSTNAME_SIZE) { + m_net = NET_HOSTNAME; + return true; + } + throw std::ios_base::failure( + strprintf("BIP155 HOSTNAME address with length %u (should be %u)", address_size, + ADDR_HOSTNAME_SIZE)); } // Don't throw on addresses with unknown network ids (maybe from the future). @@ -124,6 +134,9 @@ void CNetAddr::SetIP(const CNetAddr& ipIn) case NET_CJDNS: assert(ipIn.m_addr.size() == ADDR_CJDNS_SIZE); break; + case NET_HOSTNAME: + assert(ipIn.m_addr.size() <= ADDR_HOSTNAME_SIZE); + break; case NET_INTERNAL: assert(ipIn.m_addr.size() == ADDR_INTERNAL_SIZE); break; diff --git a/src/netaddress.h b/src/netaddress.h index b8001a4dd7327..8c41937cc424d 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -60,6 +60,9 @@ enum Network { /// CJDNS NET_CJDNS, + /// Hostname + NET_HOSTNAME, + /// A set of addresses that represent the hash of a string or FQDN. We use /// them in CAddrMan to keep track of which DNS seeds were used. NET_INTERNAL, @@ -105,6 +108,10 @@ static constexpr size_t ADDR_I2P_SIZE = 32; /// Size of CJDNS address (in bytes). static constexpr size_t ADDR_CJDNS_SIZE = 16; +/// Size of Hostname (in bytes). This is the maximum length of all labels and +/// dots as per RFC 1035 Size limits (Section 2.3.4.) +static constexpr size_t ADDR_HOSTNAME_SIZE = 255; + /// Size of "internal" (NET_INTERNAL) address (in bytes). static constexpr size_t ADDR_INTERNAL_SIZE = 10; @@ -114,6 +121,7 @@ static constexpr uint16_t I2P_SAM31_PORT{0}; /** * Network address. */ +// CNetAddr is defined here for IPv6 or IPv4 class CNetAddr { protected: @@ -164,8 +172,12 @@ class CNetAddr * @returns Whether the operation was successful. * @see CNetAddr::IsTor(), CNetAddr::IsI2P() */ + // Hmmm... looks like hostnames (DNS) *can* fit after all? bool SetSpecial(const std::string& addr); + // What might this look like?? + bool SetHostname(const std::string& addr); + bool IsBindAny() const; // INADDR_ANY equivalent bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor) @@ -187,6 +199,7 @@ class CNetAddr bool IsTor() const; bool IsI2P() const; bool IsCJDNS() const; + bool IsHostname() const; bool IsLocal() const; bool IsRoutable() const; bool IsInternal() const; @@ -282,6 +295,8 @@ class CNetAddr TORV3 = 4, I2P = 5, CJDNS = 6, + // add Hostname support here (and rename the enum?) + HOSTNAME = 1993, }; /** @@ -339,6 +354,7 @@ class CNetAddr case NET_ONION: case NET_I2P: case NET_CJDNS: + case NET_HOSTNAME: break; case NET_UNROUTABLE: case NET_MAX: @@ -518,6 +534,7 @@ class CSubNet }; /** A combination of a network address (CNetAddr) and a (TCP) port */ +// CService is defined here class CService : public CNetAddr { protected: diff --git a/src/netbase.cpp b/src/netbase.cpp index fc940b0501dac..ecb56ab93888a 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -90,6 +90,7 @@ enum Network ParseNetwork(const std::string& net_in) { if (net == "ipv4") return NET_IPV4; if (net == "ipv6") return NET_IPV6; if (net == "onion") return NET_ONION; + if (net == "hostname") return NET_HOSTNAME; if (net == "tor") { LogPrintf("Warning: net name 'tor' is deprecated and will be removed in the future. You should use 'onion' instead.\n"); return NET_ONION; @@ -109,6 +110,7 @@ std::string GetNetworkName(enum Network net) case NET_ONION: return "onion"; case NET_I2P: return "i2p"; case NET_CJDNS: return "cjdns"; + case NET_HOSTNAME: return "hostname"; case NET_INTERNAL: return "internal"; case NET_MAX: assert(false); } // no default case, so the compiler can warn about missing cases @@ -121,7 +123,7 @@ std::vector GetNetworkNames(bool append_unroutable) std::vector names; for (int n = 0; n < NET_MAX; ++n) { const enum Network network{static_cast(n)}; - if (network == NET_UNROUTABLE || network == NET_CJDNS || network == NET_INTERNAL) continue; + if (network == NET_UNROUTABLE || network == NET_HOSTNAME || network == NET_CJDNS || network == NET_INTERNAL) continue; names.emplace_back(GetNetworkName(network)); } if (append_unroutable) { diff --git a/src/rpc/evo.cpp b/src/rpc/evo.cpp index bd3ddaaf661e5..e919b558fe96d 100644 --- a/src/rpc/evo.cpp +++ b/src/rpc/evo.cpp @@ -67,14 +67,15 @@ static RPCArg GetRpcArg(const std::string& strParamName) "If not specified, payoutAddress is the one that is going to be used.\n" "The private key belonging to this address must be known in your wallet."} }, - {"ipAndPort", - {"ipAndPort", RPCArg::Type::STR, RPCArg::Optional::NO, - "IP and port in the form \"IP:PORT\". Must be unique on the network.\n" + // ip or hostname, and port + {"hostnameAndPort", + {"hostnameAndPort", RPCArg::Type::STR, RPCArg::Optional::NO, + "Host in the form \"HOSTNAME:PORT\". Must be unique on the network.\n" "Can be set to an empty string, which will require a ProUpServTx afterwards."} }, - {"ipAndPort_update", - {"ipAndPort", RPCArg::Type::STR, RPCArg::Optional::NO, - "IP and port in the form \"IP:PORT\". Must be unique on the network."} + {"hostnameAndPort_update", + {"hostnameAndPort", RPCArg::Type::STR, RPCArg::Optional::NO, + "Host in the form \"HOSTNAME:PORT\". Must be unique on the network."} }, {"operatorKey", {"operatorKey", RPCArg::Type::STR, RPCArg::Optional::NO, @@ -367,7 +368,7 @@ static void protx_register_fund_help(const JSONRPCRequest& request, bool legacy) + HELP_REQUIRING_PASSPHRASE, { GetRpcArg("collateralAddress"), - GetRpcArg("ipAndPort"), + GetRpcArg("hostnameAndPort"), GetRpcArg("ownerAddress"), legacy ? GetRpcArg("operatorPubKey_register_legacy") : GetRpcArg("operatorPubKey_register"), GetRpcArg("votingAddress_register"), @@ -402,7 +403,7 @@ static void protx_register_help(const JSONRPCRequest& request, bool legacy) { GetRpcArg("collateralHash"), GetRpcArg("collateralIndex"), - GetRpcArg("ipAndPort"), + GetRpcArg("hostnameAndPort"), GetRpcArg("ownerAddress"), legacy ? GetRpcArg("operatorPubKey_register_legacy") : GetRpcArg("operatorPubKey_register"), GetRpcArg("votingAddress_register"), @@ -436,7 +437,7 @@ static void protx_register_prepare_help(const JSONRPCRequest& request, bool lega { GetRpcArg("collateralHash"), GetRpcArg("collateralIndex"), - GetRpcArg("ipAndPort"), + GetRpcArg("hostnameAndPort"), GetRpcArg("ownerAddress"), legacy ? GetRpcArg("operatorPubKey_register_legacy") : GetRpcArg("operatorPubKey_register"), GetRpcArg("votingAddress_register"), @@ -489,7 +490,7 @@ static void protx_register_fund_evo_help(const JSONRPCRequest& request) HELP_REQUIRING_PASSPHRASE, { GetRpcArg("collateralAddress"), - GetRpcArg("ipAndPort"), + GetRpcArg("hostnameAndPort"), GetRpcArg("ownerAddress"), GetRpcArg("operatorPubKey_register"), GetRpcArg("votingAddress_register"), @@ -523,7 +524,7 @@ static void protx_register_evo_help(const JSONRPCRequest& request) { GetRpcArg("collateralHash"), GetRpcArg("collateralIndex"), - GetRpcArg("ipAndPort"), + GetRpcArg("hostnameAndPort"), GetRpcArg("ownerAddress"), GetRpcArg("operatorPubKey_register"), GetRpcArg("votingAddress_register"), @@ -556,7 +557,7 @@ static void protx_register_prepare_evo_help(const JSONRPCRequest& request) { GetRpcArg("collateralHash"), GetRpcArg("collateralIndex"), - GetRpcArg("ipAndPort"), + GetRpcArg("hostnameAndPort"), GetRpcArg("ownerAddress"), GetRpcArg("operatorPubKey_register"), GetRpcArg("votingAddress_register"), @@ -619,11 +620,12 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request, size_t paramIdx = 0; CMutableTransaction tx; - tx.nVersion = 3; + tx.nVersion = 3; // EVO SEND!! tx.nType = TRANSACTION_PROVIDER_REGISTER; const bool use_legacy = isV19active ? specific_legacy_bls_scheme : true; + // This is the type that packs the IP presently CProRegTx ptx; ptx.nType = mnType; @@ -654,8 +656,9 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request, wallet->LockCoin(ptx.collateralOutpoint); } + // paramIdx is now for hostnameAndPort if (request.params[paramIdx].get_str() != "") { - if (!Lookup(request.params[paramIdx].get_str().c_str(), ptx.addr, Params().GetDefaultPort(), false)) { + if (!Lookup(request.params[paramIdx].get_str().c_str(), ptx.addr, Params().GetDefaultPort(), g_dns_lookup)) { throw std::runtime_error(strprintf("invalid network address %s", request.params[paramIdx].get_str())); } } @@ -856,7 +859,7 @@ static void protx_update_service_help(const JSONRPCRequest& request) + HELP_REQUIRING_PASSPHRASE, { GetRpcArg("proTxHash"), - GetRpcArg("ipAndPort_update"), + GetRpcArg("hostnameAndPort_update"), GetRpcArg("operatorKey"), GetRpcArg("operatorPayoutAddress"), GetRpcArg("feeSourceAddress"), @@ -880,7 +883,7 @@ static void protx_update_service_evo_help(const JSONRPCRequest& request) HELP_REQUIRING_PASSPHRASE, { GetRpcArg("proTxHash"), - GetRpcArg("ipAndPort_update"), + GetRpcArg("hostnameAndPort_update"), GetRpcArg("operatorKey"), GetRpcArg("platformNodeID"), GetRpcArg("platformP2PPort"), diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index eb9b0af4d237a..41d7e65447421 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -87,7 +87,7 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) { { {RPCResult::Type::NUM, "id", "Peer index"}, - {RPCResult::Type::STR, "addr", "(host:port) The IP address and port of the peer"}, + {RPCResult::Type::STR, "addr", "(hostname:port) The Hostname (or IP address) and port of the peer"}, {RPCResult::Type::STR, "addrbind", "(ip:port) Bind address of the connection to the peer"}, {RPCResult::Type::STR, "addrlocal", "(ip:port) Local address as reported by the peer"}, {RPCResult::Type::STR, "network", "Network (" + Join(GetNetworkNames(/* append_unroutable */ true), ", ") + ")"}, @@ -461,7 +461,7 @@ static UniValue GetNetworksInfo() UniValue networks(UniValue::VARR); for (int n = 0; n < NET_MAX; ++n) { enum Network network = static_cast(n); - if (network == NET_UNROUTABLE || network == NET_CJDNS || network == NET_INTERNAL) continue; + if (network == NET_UNROUTABLE || network == NET_HOSTNAME || network == NET_CJDNS || network == NET_INTERNAL) continue; proxyType proxy; UniValue obj(UniValue::VOBJ); GetProxy(network, proxy); diff --git a/test/functional/feature_llmq_evo.py b/test/functional/feature_llmq_evo.py index 2c91db8f9c477..7e3b388a4558a 100755 --- a/test/functional/feature_llmq_evo.py +++ b/test/functional/feature_llmq_evo.py @@ -231,11 +231,11 @@ def test_evo_is_rejected_before_v19(self): break assert collateral_vout is not None - ipAndPort = '127.0.0.1:%d' % p2p_port(len(self.nodes)) + hostnameAndPort = 'localhost:%d' % p2p_port(len(self.nodes)) operatorReward = len(self.nodes) try: - self.nodes[0].protx('register_evo', collateral_txid, collateral_vout, ipAndPort, owner_address, bls['public'], voting_address, operatorReward, reward_address, funds_address, True) + self.nodes[0].protx('register_evo', collateral_txid, collateral_vout, hostnameAndPort, owner_address, bls['public'], voting_address, operatorReward, reward_address, funds_address, True) # this should never succeed assert False except: diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index e92a13da2e649..57e3c9d7f15b2 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -1223,21 +1223,21 @@ def dynamically_prepare_masternode(self, idx, node_p2p_port, evo=False, rnd=None break assert collateral_vout is not None - ipAndPort = '127.0.0.1:%d' % node_p2p_port + hostnameAndPort = 'localhost:%d' % node_p2p_port operatorReward = idx protx_result = None if evo: - protx_result = self.nodes[0].protx("register_evo", collateral_txid, collateral_vout, ipAndPort, owner_address, bls['public'], voting_address, operatorReward, reward_address, platform_node_id, platform_p2p_port, platform_http_port, funds_address, True) + protx_result = self.nodes[0].protx("register_evo", collateral_txid, collateral_vout, hostnameAndPort, owner_address, bls['public'], voting_address, operatorReward, reward_address, platform_node_id, platform_p2p_port, platform_http_port, funds_address, True) else: - protx_result = self.nodes[0].protx("register", collateral_txid, collateral_vout, ipAndPort, owner_address, bls['public'], voting_address, operatorReward, reward_address, funds_address, True) + protx_result = self.nodes[0].protx("register", collateral_txid, collateral_vout, hostnameAndPort, owner_address, bls['public'], voting_address, operatorReward, reward_address, funds_address, True) self.wait_for_instantlock(protx_result, self.nodes[0]) tip = self.nodes[0].generate(1)[0] self.sync_all(self.nodes) assert_equal(self.nodes[0].getrawtransaction(protx_result, 1, tip)['confirmations'], 1) - mn_info = MasternodeInfo(protx_result, owner_address, voting_address, reward_address, operatorReward, bls['public'], bls['secret'], collateral_address, collateral_txid, collateral_vout, ipAndPort, evo) + mn_info = MasternodeInfo(protx_result, owner_address, voting_address, reward_address, operatorReward, bls['public'], bls['secret'], collateral_address, collateral_txid, collateral_vout, hostnameAndPort, evo) self.mninfo.append(mn_info) mn_type_str = "EvoNode" if evo else "MN" @@ -1307,16 +1307,16 @@ def prepare_masternode(self, idx): votingAddr = ownerAddr port = p2p_port(len(self.nodes) + idx) - ipAndPort = '127.0.0.1:%d' % port + hostnameAndPort = 'localhost:%d' % port operatorReward = idx submit = (idx % 4) < 2 if register_fund: - protx_result = self.nodes[0].protx('register_fund', address, ipAndPort, ownerAddr, bls['public'], votingAddr, operatorReward, rewardsAddr, address, submit) + protx_result = self.nodes[0].protx('register_fund', address, hostnameAndPort, ownerAddr, bls['public'], votingAddr, operatorReward, rewardsAddr, address, submit) else: self.nodes[0].generate(1) - protx_result = self.nodes[0].protx('register', txid, collateral_vout, ipAndPort, ownerAddr, bls['public'], votingAddr, operatorReward, rewardsAddr, address, submit) + protx_result = self.nodes[0].protx('register', txid, collateral_vout, hostnameAndPort, ownerAddr, bls['public'], votingAddr, operatorReward, rewardsAddr, address, submit) if submit: proTxHash = protx_result @@ -1326,9 +1326,9 @@ def prepare_masternode(self, idx): if operatorReward > 0: self.nodes[0].generate(1) operatorPayoutAddress = self.nodes[0].getnewaddress() - self.nodes[0].protx('update_service', proTxHash, ipAndPort, bls['secret'], operatorPayoutAddress, address) + self.nodes[0].protx('update_service', proTxHash, hostnameAndPort, bls['secret'], operatorPayoutAddress, address) - self.mninfo.append(MasternodeInfo(proTxHash, ownerAddr, votingAddr, rewardsAddr, operatorReward, bls['public'], bls['secret'], address, txid, collateral_vout, ipAndPort, False)) + self.mninfo.append(MasternodeInfo(proTxHash, ownerAddr, votingAddr, rewardsAddr, operatorReward, bls['public'], bls['secret'], address, txid, collateral_vout, hostnameAndPort, False)) self.log.info("Prepared MN %d: collateral_txid=%s, collateral_vout=%d, protxHash=%s" % (idx, txid, collateral_vout, proTxHash))