Skip to content

Commit 6205466

Browse files
committed
rpc: "addpeeraddress tried" return error on failure
When trying to add an address to the IP address manager tried table, it's first added to the new table and then moved to the tried table. Previously, adding a conflicting address to the address manager's tried table with test-only `addpeeraddress tried=true` RPC would return `{ "success": true }`. However, the address would not be added to the tried table, but would remain in the new table. This caused, e.g., issue 28964. This is fixed by returning `{ "success": false, "error": "failed-adding-to-tried" }` for failed tried table additions. Since the address remaining in the new table can't be removed (the address manager interface does not support removing addresses at the moment and adding this seems to be a bigger effort), an error message is returned. This indicates to a user why the RPC failed and allows accounting for the extra address in the new table. Also: To check the number of addresses in each addrman table, the addrman checks were re-run and the log output of this check was asserted. Ideally, logs shouldn't be used as an interface in automated tests. To avoid asserting the logs, use the getaddrmaninfo and getrawaddrman RPCs (which weren't implemented when the test was added). Removing the "getnodeaddress" calls would also remove the addrman checks from the test, which could reduce the test coverage. To avoid this, these are kept.
1 parent 9f2609d commit 6205466

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
lines changed

src/rpc/net.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,7 @@ static RPCHelpMan getnodeaddresses()
951951
static RPCHelpMan addpeeraddress()
952952
{
953953
return RPCHelpMan{"addpeeraddress",
954-
"\nAdd the address of a potential peer to the address manager. This RPC is for testing only.\n",
954+
"Add the address of a potential peer to an address manager table. This RPC is for testing only.",
955955
{
956956
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address of the peer"},
957957
{"port", RPCArg::Type::NUM, RPCArg::Optional::NO, "The port of the peer"},
@@ -960,7 +960,8 @@ static RPCHelpMan addpeeraddress()
960960
RPCResult{
961961
RPCResult::Type::OBJ, "", "",
962962
{
963-
{RPCResult::Type::BOOL, "success", "whether the peer address was successfully added to the address manager"},
963+
{RPCResult::Type::BOOL, "success", "whether the peer address was successfully added to the address manager table"},
964+
{RPCResult::Type::STR, "error", /*optional=*/true, "error description, if the address could not be added"},
964965
},
965966
},
966967
RPCExamples{
@@ -989,8 +990,13 @@ static RPCHelpMan addpeeraddress()
989990
success = true;
990991
if (tried) {
991992
// Attempt to move the address to the tried addresses table.
992-
addrman.Good(address);
993+
if (!addrman.Good(address)) {
994+
success = false;
995+
obj.pushKV("error", "failed-adding-to-tried");
996+
}
993997
}
998+
} else {
999+
obj.pushKV("error", "failed-adding-to-new");
9941000
}
9951001
}
9961002

test/functional/rpc_net.py

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -340,26 +340,52 @@ def test_addpeeraddress(self):
340340
assert_raises_rpc_error(-1, "JSON integer out of range", self.nodes[0].addpeeraddress, address="1.2.3.4", port=-1)
341341
assert_raises_rpc_error(-1, "JSON integer out of range", self.nodes[0].addpeeraddress, address="1.2.3.4", port=65536)
342342

343+
self.log.debug("Test that adding a valid address to the new table succeeds")
344+
assert_equal(node.addpeeraddress(address="1.0.0.0", tried=False, port=8333), {"success": True})
345+
addrman = node.getrawaddrman()
346+
assert_equal(len(addrman["tried"]), 0)
347+
new_table = list(addrman["new"].values())
348+
assert_equal(len(new_table), 1)
349+
assert_equal(new_table[0]["address"], "1.0.0.0")
350+
assert_equal(new_table[0]["port"], 8333)
351+
352+
self.log.debug("Test that adding an already-present new address to the new and tried tables fails")
353+
for value in [True, False]:
354+
assert_equal(node.addpeeraddress(address="1.0.0.0", tried=value, port=8333), {"success": False, "error": "failed-adding-to-new"})
355+
assert_equal(len(node.getnodeaddresses(count=0)), 1)
356+
343357
self.log.debug("Test that adding a valid address to the tried table succeeds")
344358
self.addr_time = int(time.time())
345359
node.setmocktime(self.addr_time)
346360
assert_equal(node.addpeeraddress(address="1.2.3.4", tried=True, port=8333), {"success": True})
347-
with node.assert_debug_log(expected_msgs=["CheckAddrman: new 0, tried 1, total 1 started"]):
348-
addrs = node.getnodeaddresses(count=0) # getnodeaddresses re-runs the addrman checks
349-
assert_equal(len(addrs), 1)
350-
assert_equal(addrs[0]["address"], "1.2.3.4")
351-
assert_equal(addrs[0]["port"], 8333)
361+
addrman = node.getrawaddrman()
362+
assert_equal(len(addrman["new"]), 1)
363+
tried_table = list(addrman["tried"].values())
364+
assert_equal(len(tried_table), 1)
365+
assert_equal(tried_table[0]["address"], "1.2.3.4")
366+
assert_equal(tried_table[0]["port"], 8333)
367+
node.getnodeaddresses(count=0) # getnodeaddresses re-runs the addrman checks
352368

353369
self.log.debug("Test that adding an already-present tried address to the new and tried tables fails")
354370
for value in [True, False]:
355-
assert_equal(node.addpeeraddress(address="1.2.3.4", tried=value, port=8333), {"success": False})
356-
assert_equal(len(node.getnodeaddresses(count=0)), 1)
357-
358-
self.log.debug("Test that adding a second address, this time to the new table, succeeds")
371+
assert_equal(node.addpeeraddress(address="1.2.3.4", tried=value, port=8333), {"success": False, "error": "failed-adding-to-new"})
372+
assert_equal(len(node.getnodeaddresses(count=0)), 2)
373+
374+
self.log.debug("Test that adding an address, which collides with the address in tried table, fails")
375+
colliding_address = "1.2.5.45" # grinded address that produces a tried-table collision
376+
assert_equal(node.addpeeraddress(address=colliding_address, tried=True, port=8333), {"success": False, "error": "failed-adding-to-tried"})
377+
# When adding an address to the tried table, it's first added to the new table.
378+
# As we fail to move it to the tried table, it remains in the new table.
379+
addrman_info = node.getaddrmaninfo()
380+
assert_equal(addrman_info["all_networks"]["tried"], 1)
381+
assert_equal(addrman_info["all_networks"]["new"], 2)
382+
383+
self.log.debug("Test that adding an another address to the new table succeeds")
359384
assert_equal(node.addpeeraddress(address="2.0.0.0", port=8333), {"success": True})
360-
with node.assert_debug_log(expected_msgs=["CheckAddrman: new 1, tried 1, total 2 started"]):
361-
addrs = node.getnodeaddresses(count=0) # getnodeaddresses re-runs the addrman checks
362-
assert_equal(len(addrs), 2)
385+
addrman_info = node.getaddrmaninfo()
386+
assert_equal(addrman_info["all_networks"]["tried"], 1)
387+
assert_equal(addrman_info["all_networks"]["new"], 3)
388+
node.getnodeaddresses(count=0) # getnodeaddresses re-runs the addrman checks
363389

364390
def test_sendmsgtopeer(self):
365391
node = self.nodes[0]

0 commit comments

Comments
 (0)