From 02fbe3ae0bd91cbab2828cb7aa46f6493c82f026 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Sun, 9 Aug 2020 21:49:31 +0200 Subject: [PATCH 1/5] net: add nLastBlockTime/TXTime to CNodeStats, CNode::copyStats --- src/net.cpp | 2 ++ src/net.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/net.cpp b/src/net.cpp index 6c1980735c4..883e57bdf00 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -530,6 +530,8 @@ void CNode::copyStats(CNodeStats &stats, const std::vector &m_asmap) } X(nLastSend); X(nLastRecv); + X(nLastTXTime); + X(nLastBlockTime); X(nTimeConnected); X(nTimeOffset); stats.addrName = GetAddrName(); diff --git a/src/net.h b/src/net.h index 7a8abb401d4..c72eada3ff4 100644 --- a/src/net.h +++ b/src/net.h @@ -619,6 +619,8 @@ public: bool fRelayTxes; int64_t nLastSend; int64_t nLastRecv; + int64_t nLastTXTime; + int64_t nLastBlockTime; int64_t nTimeConnected; int64_t nTimeOffset; std::string addrName; From 8a560a7d57cbd9f473d6a3782893a0e2243c55bd Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Sat, 15 Aug 2020 11:07:02 +0200 Subject: [PATCH 2/5] rpc: expose nLastBlockTime/TXTime as getpeerinfo last_block/transaction --- src/rpc/net.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 9bd7c15992e..e9343b3348a 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -100,6 +100,8 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) {RPCResult::Type::BOOL, "relaytxes", "Whether peer has asked us to relay transactions to it"}, {RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"}, {RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"}, + {RPCResult::Type::NUM_TIME, "last_transaction", "The " + UNIX_EPOCH_TIME + " of the last valid transaction received from this peer"}, + {RPCResult::Type::NUM_TIME, "last_block", "The " + UNIX_EPOCH_TIME + " of the last block received from this peer"}, {RPCResult::Type::NUM, "bytessent", "The total bytes sent"}, {RPCResult::Type::NUM, "bytesrecv", "The total bytes received"}, {RPCResult::Type::NUM_TIME, "conntime", "The " + UNIX_EPOCH_TIME + " of the connection"}, @@ -169,6 +171,8 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) obj.pushKV("relaytxes", stats.fRelayTxes); obj.pushKV("lastsend", stats.nLastSend); obj.pushKV("lastrecv", stats.nLastRecv); + obj.pushKV("last_transaction", stats.nLastTXTime); + obj.pushKV("last_block", stats.nLastBlockTime); obj.pushKV("bytessent", stats.nSendBytes); obj.pushKV("bytesrecv", stats.nRecvBytes); obj.pushKV("conntime", stats.nTimeConnected); From 21c57bacda766a4f56ee75a2872f5d0f94e3901e Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Sat, 15 Aug 2020 09:01:21 +0200 Subject: [PATCH 3/5] test: getpeerinfo last_block and last_transaction tests --- test/functional/rpc_net.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index 192b60e5d24..1729ddc210f 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -8,9 +8,12 @@ Tests correspond to code in rpc/net.cpp. """ from decimal import Decimal +from itertools import product +import time from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( + assert_approx, assert_equal, assert_greater_than_or_equal, assert_greater_than, @@ -48,17 +51,17 @@ class NetTest(BitcoinTestFramework): self.supports_cli = False def run_test(self): - self.log.info('Get out of IBD for the minfeefilter test') - self.nodes[0].generate(1) + self.log.info('Get out of IBD for the minfeefilter and getpeerinfo tests') + self.nodes[0].generate(101) self.log.info('Connect nodes both way') connect_nodes(self.nodes[0], 1) connect_nodes(self.nodes[1], 0) self._test_connection_count() + self._test_getpeerinfo() self._test_getnettotals() self._test_getnetworkinfo() self._test_getaddednodeinfo() - self._test_getpeerinfo() self.test_service_flags() self._test_getnodeaddresses() @@ -140,7 +143,18 @@ class NetTest(BitcoinTestFramework): assert_raises_rpc_error(-24, "Node has not been added", self.nodes[0].getaddednodeinfo, '1.1.1.1') def _test_getpeerinfo(self): + # Create a few getpeerinfo last_block/last_transaction values. + if self.is_wallet_compiled(): + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) + self.nodes[1].generate(1) + self.sync_all() + time_now = int(time.time()) peer_info = [x.getpeerinfo() for x in self.nodes] + # Verify last_block and last_transaction keys/values. + for node, peer, field in product(range(self.num_nodes), range(2), ['last_block', 'last_transaction']): + assert field in peer_info[node][peer].keys() + if peer_info[node][peer][field] != 0: + assert_approx(peer_info[node][peer][field], time_now, vspan=60) # check both sides of bidirectional connection between nodes # the address bound to on one side will be the source address for the other node assert_equal(peer_info[0][0]['addrbind'], peer_info[1][0]['addr']) From cfef5a2c98b9563392a4a258fedb8bdc869c9749 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Sat, 15 Aug 2020 09:15:19 +0200 Subject: [PATCH 4/5] test: rpc_net.py logging and test naming improvements --- test/functional/rpc_net.py | 39 ++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index 1729ddc210f..9b8e585b492 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -51,25 +51,27 @@ class NetTest(BitcoinTestFramework): self.supports_cli = False def run_test(self): - self.log.info('Get out of IBD for the minfeefilter and getpeerinfo tests') + # Get out of IBD for the minfeefilter and getpeerinfo tests. self.nodes[0].generate(101) - self.log.info('Connect nodes both way') + # Connect nodes both ways. connect_nodes(self.nodes[0], 1) connect_nodes(self.nodes[1], 0) - self._test_connection_count() - self._test_getpeerinfo() - self._test_getnettotals() - self._test_getnetworkinfo() - self._test_getaddednodeinfo() + self.test_connection_count() + self.test_getpeerinfo() + self.test_getnettotals() + self.test_getnetworkinfo() + self.test_getaddednodeinfo() self.test_service_flags() - self._test_getnodeaddresses() + self.test_getnodeaddresses() - def _test_connection_count(self): - # connect_nodes connects each node to the other + def test_connection_count(self): + self.log.info("Test getconnectioncount") + # After using `connect_nodes` to connect nodes 0 and 1 to each other. assert_equal(self.nodes[0].getconnectioncount(), 2) - def _test_getnettotals(self): + def test_getnettotals(self): + self.log.info("Test getnettotals") # getnettotals totalbytesrecv and totalbytessent should be # consistent with getpeerinfo. Since the RPC calls are not atomic, # and messages might have been recvd or sent between RPC calls, call @@ -99,7 +101,8 @@ class NetTest(BitcoinTestFramework): assert_greater_than_or_equal(after['bytesrecv_per_msg'].get('pong', 0), before['bytesrecv_per_msg'].get('pong', 0) + 32) assert_greater_than_or_equal(after['bytessent_per_msg'].get('ping', 0), before['bytessent_per_msg'].get('ping', 0) + 32) - def _test_getnetworkinfo(self): + def test_getnetworkinfo(self): + self.log.info("Test getnetworkinfo") assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True) assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2) @@ -111,7 +114,7 @@ class NetTest(BitcoinTestFramework): with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: true\n']): self.nodes[0].setnetworkactive(state=True) - self.log.info('Connect nodes both way') + # Connect nodes both ways. connect_nodes(self.nodes[0], 1) connect_nodes(self.nodes[1], 0) @@ -123,7 +126,8 @@ class NetTest(BitcoinTestFramework): for info in network_info: assert_net_servicesnames(int(info["localservices"], 0x10), info["localservicesnames"]) - def _test_getaddednodeinfo(self): + def test_getaddednodeinfo(self): + self.log.info("Test getaddednodeinfo") assert_equal(self.nodes[0].getaddednodeinfo(), []) # add a node (node2) to node0 ip_port = "127.0.0.1:{}".format(p2p_port(2)) @@ -142,7 +146,8 @@ class NetTest(BitcoinTestFramework): # check that a non-existent node returns an error assert_raises_rpc_error(-24, "Node has not been added", self.nodes[0].getaddednodeinfo, '1.1.1.1') - def _test_getpeerinfo(self): + def test_getpeerinfo(self): + self.log.info("Test getpeerinfo") # Create a few getpeerinfo last_block/last_transaction values. if self.is_wallet_compiled(): self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) @@ -166,11 +171,13 @@ class NetTest(BitcoinTestFramework): assert_net_servicesnames(int(info[0]["services"], 0x10), info[0]["servicesnames"]) def test_service_flags(self): + self.log.info("Test service flags") self.nodes[0].add_p2p_connection(P2PInterface(), services=(1 << 4) | (1 << 63)) assert_equal(['UNKNOWN[2^4]', 'UNKNOWN[2^63]'], self.nodes[0].getpeerinfo()[-1]['servicesnames']) self.nodes[0].disconnect_p2ps() - def _test_getnodeaddresses(self): + def test_getnodeaddresses(self): + self.log.info("Test getnodeaddresses") self.nodes[0].add_p2p_connection(P2PInterface()) # Add some addresses to the Address Manager over RPC. Due to the way From 5da96210fc2fda9fbd79531f42f91262fd7a9257 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Sat, 15 Aug 2020 15:26:33 +0200 Subject: [PATCH 5/5] doc: release note for getpeerinfo last_block/last_transaction --- doc/release-notes-19731.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 doc/release-notes-19731.md diff --git a/doc/release-notes-19731.md b/doc/release-notes-19731.md new file mode 100644 index 00000000000..abe38e06af6 --- /dev/null +++ b/doc/release-notes-19731.md @@ -0,0 +1,6 @@ +Updated RPCs +------------ + +- The `getpeerinfo` RPC now has additional `last_block` and `last_transaction` + fields that return the UNIX epoch time of the last block and the last valid + transaction received from each peer. (#19731)