[net] Add addpeeraddress RPC method

Allows addresses to be added to Address Manager for testing.
This commit is contained in:
John Newbery 2020-07-23 18:10:35 +01:00
parent ae8051bbd8
commit 37a480e0cd
5 changed files with 66 additions and 22 deletions

View file

@ -2523,9 +2523,9 @@ void CConnman::MarkAddressGood(const CAddress& addr)
addrman.Good(addr);
}
void CConnman::AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty)
bool CConnman::AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty)
{
addrman.Add(vAddr, addrFrom, nTimePenalty);
return addrman.Add(vAddr, addrFrom, nTimePenalty);
}
std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pct)

View file

@ -250,7 +250,7 @@ public:
// Addrman functions
void SetServices(const CService &addr, ServiceFlags nServices);
void MarkAddressGood(const CAddress& addr);
void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
bool AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct);
/**
* Cache is used to minimize topology leaks, so it should

View file

@ -173,6 +173,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "createwallet", 4, "avoid_reuse"},
{ "createwallet", 5, "descriptors"},
{ "getnodeaddresses", 0, "count"},
{ "addpeeraddress", 1, "port"},
{ "stop", 0, "wait" },
};
// clang-format on

View file

@ -773,6 +773,54 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request)
return ret;
}
static UniValue addpeeraddress(const JSONRPCRequest& request)
{
RPCHelpMan{"addpeeraddress",
"\nAdd the address of a potential peer to the address manager. This RPC is for testing only.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address of the peer"},
{"port", RPCArg::Type::NUM, RPCArg::Optional::NO, "The port of the peer"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::BOOL, "success", "whether the peer address was successfully added to the address manager"},
},
},
RPCExamples{
HelpExampleCli("addpeeraddress", "\"1.2.3.4\" 8333")
+ HelpExampleRpc("addpeeraddress", "\"1.2.3.4\", 8333")
},
}.Check(request);
NodeContext& node = EnsureNodeContext(request.context);
if (!node.connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
UniValue obj(UniValue::VOBJ);
std::string addr_string = request.params[0].get_str();
uint16_t port = request.params[1].get_int();
CNetAddr net_addr;
if (!LookupHost(addr_string, net_addr, false)) {
obj.pushKV("success", false);
return obj;
}
CAddress address = CAddress({net_addr, port}, ServiceFlags(NODE_NETWORK|NODE_WITNESS));
address.nTime = GetAdjustedTime();
// The source address is set equal to the address. This is equivalent to the peer
// announcing itself.
if (!node.connman->AddNewAddresses({address}, address)) {
obj.pushKV("success", false);
return obj;
}
obj.pushKV("success", true);
return obj;
}
void RegisterNetRPCCommands(CRPCTable &t)
{
// clang-format off
@ -792,6 +840,7 @@ static const CRPCCommand commands[] =
{ "network", "clearbanned", &clearbanned, {} },
{ "network", "setnetworkactive", &setnetworkactive, {"state"} },
{ "network", "getnodeaddresses", &getnodeaddresses, {"count"} },
{ "hidden", "addpeeraddress", &addpeeraddress, {"address", "port"} },
};
// clang-format on

View file

@ -22,8 +22,6 @@ from test_framework.util import (
from test_framework.mininode import P2PInterface
import test_framework.messages
from test_framework.messages import (
CAddress,
msg_addr,
NODE_NETWORK,
NODE_WITNESS,
)
@ -154,29 +152,25 @@ class NetTest(BitcoinTestFramework):
def _test_getnodeaddresses(self):
self.nodes[0].add_p2p_connection(P2PInterface())
# send some addresses to the node via the p2p message addr
msg = msg_addr()
# Add some addresses to the Address Manager over RPC. Due to the way
# bucket and bucket position are calculated, some of these addresses
# will collide.
imported_addrs = []
for i in range(256):
a = "123.123.123.{}".format(i)
for i in range(10000):
first_octet = i >> 8
second_octet = i % 256
a = "{}.{}.1.1".format(first_octet, second_octet)
imported_addrs.append(a)
addr = CAddress()
addr.time = 100000000
addr.nServices = NODE_NETWORK | NODE_WITNESS
addr.ip = a
addr.port = 8333
msg.addrs.append(addr)
self.nodes[0].p2p.send_and_ping(msg)
self.nodes[0].addpeeraddress(a, 8333)
# Obtain addresses via rpc call and check they were ones sent in before.
#
# All addresses added above are in the same netgroup and so are assigned
# to the same bucket. Maximum possible addresses in addrman is therefore
# 64, although actual number will usually be slightly less due to
# BucketPosition collisions.
# Maximum possible addresses in addrman is 10000, although actual
# number will usually be less due to bucket and bucket position
# collisions.
node_addresses = self.nodes[0].getnodeaddresses(0)
assert_greater_than(len(node_addresses), 50)
assert_greater_than(65, len(node_addresses))
assert_greater_than(len(node_addresses), 5000)
assert_greater_than(10000, len(node_addresses))
for a in node_addresses:
assert_greater_than(a["time"], 1527811200) # 1st June 2018
assert_equal(a["services"], NODE_NETWORK | NODE_WITNESS)