From 054862f212ac5e8c7911fae7a0b64f565e3f9b7b Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Tue, 20 May 2025 11:55:58 +0100 Subject: [PATCH] Add model for getnodeaddresses GetNodeAddresses returns an Address. Create a bitcoin::Address model for it and modify the test to use it. Implement for v18 to v21. In v22 the return changes, label v22 to v28 as TODO. --- integration_test/tests/network.rs | 7 ++++--- types/src/model/mod.rs | 4 +++- types/src/model/network.rs | 24 +++++++++++++++++++++++- types/src/v18/mod.rs | 2 +- types/src/v18/network/into.rs | 28 ++++++++++++++++++++++++++++ types/src/v18/network/mod.rs | 2 ++ types/src/v19/mod.rs | 2 +- types/src/v20/mod.rs | 2 +- types/src/v21/mod.rs | 2 +- types/src/v22/mod.rs | 2 +- types/src/v23/mod.rs | 2 +- types/src/v24/mod.rs | 2 +- types/src/v25/mod.rs | 2 +- types/src/v26/mod.rs | 2 +- types/src/v27/mod.rs | 2 +- types/src/v28/mod.rs | 2 +- verify/src/method/v18.rs | 2 +- verify/src/method/v19.rs | 2 +- verify/src/method/v20.rs | 2 +- verify/src/method/v21.rs | 2 +- verify/src/method/v22.rs | 2 +- verify/src/method/v23.rs | 2 +- verify/src/method/v24.rs | 2 +- verify/src/method/v25.rs | 2 +- verify/src/method/v26.rs | 2 +- verify/src/method/v27.rs | 2 +- verify/src/method/v28.rs | 2 +- 27 files changed, 82 insertions(+), 27 deletions(-) create mode 100644 types/src/v18/network/into.rs diff --git a/integration_test/tests/network.rs b/integration_test/tests/network.rs index 30d92100..e9db7c26 100644 --- a/integration_test/tests/network.rs +++ b/integration_test/tests/network.rs @@ -37,10 +37,11 @@ fn network__get_network_info__modelled() { fn network__get_node_addresses() { let node = Node::with_wallet(Wallet::None, &[]); let json: GetNodeAddresses = node.client.get_node_addresses().expect("getnodeaddresses"); - assert!(json.0.len() <= 2500); - if let Some(addr) = json.0.first() { + let res: Result = json.into_model(); + let model = res.expect("GetNodeAddresses into model"); + assert!(model.0.len() <= 2500); + if let Some(addr) = model.0.first() { assert!(addr.port > 0); - assert!(!addr.address.is_empty()); assert!(addr.time > 1231006505); } } diff --git a/types/src/model/mod.rs b/types/src/model/mod.rs index 6ef32b59..5ce33610 100644 --- a/types/src/model/mod.rs +++ b/types/src/model/mod.rs @@ -34,7 +34,9 @@ pub use self::{ BlockTemplateTransaction, GetBlockTemplate, GetPrioritisedTransactions, PrioritisedTransaction, }, - network::{GetNetworkInfo, GetNetworkInfoAddress, GetNetworkInfoNetwork}, + network::{ + GetNetworkInfo, GetNetworkInfoAddress, GetNetworkInfoNetwork, GetNodeAddresses, NodeAddress, + }, raw_transactions::{ AnalyzePsbt, AnalyzePsbtInput, AnalyzePsbtInputMissing, CombinePsbt, CombineRawTransaction, ConvertToPsbt, CreatePsbt, CreateRawTransaction, DecodePsbt, DecodeRawTransaction, diff --git a/types/src/model/network.rs b/types/src/model/network.rs index 77cdd995..c3197a65 100644 --- a/types/src/model/network.rs +++ b/types/src/model/network.rs @@ -5,7 +5,8 @@ //! These structs model the types returned by the JSON-RPC API but have concrete types //! and are not specific to a specific version of Bitcoin Core. -use bitcoin::FeeRate; +use bitcoin::address::NetworkUnchecked; +use bitcoin::{Address, FeeRate}; use serde::{Deserialize, Serialize}; /// Models the result of JSON-RPC method `getnetworkinfo`. @@ -64,3 +65,24 @@ pub struct GetNetworkInfoAddress { /// Relative score. pub score: u32, } + +/// Result of JSON-RPC method `getnodeaddresses`. +/// +/// > getnodeaddresses ( count ) +/// > +/// > Return known addresses which can potentially be used to find new nodes in the network. +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct GetNodeAddresses(pub Vec); + +/// An item from the list returned by the JSON-RPC method `getnodeaddresses`. +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct NodeAddress { + /// Timestamp in seconds since epoch (Jan 1 1970 GMT) when the node was last seen. + pub time: u64, + /// The services offered. + pub services: u64, + /// The address of the node. + pub address: Address, + /// The port of the node. + pub port: u16, +} diff --git a/types/src/v18/mod.rs b/types/src/v18/mod.rs index e8e65cdc..473b4af6 100644 --- a/types/src/v18/mod.rs +++ b/types/src/v18/mod.rs @@ -103,7 +103,7 @@ //! | getconnectioncount | returns numeric | | //! | getnettotals | version | | //! | getnetworkinfo | version + model | | -//! | getnodeaddresses | version | | +//! | getnodeaddresses | version + model | | //! | getpeerinfo | version | | //! | listbanned | returns string | | //! | ping | returns nothing | | diff --git a/types/src/v18/network/into.rs b/types/src/v18/network/into.rs new file mode 100644 index 00000000..a91ef35f --- /dev/null +++ b/types/src/v18/network/into.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: CC0-1.0 + +use bitcoin::address::NetworkUnchecked; +use bitcoin::{address, Address}; + +use super::{GetNodeAddresses, NodeAddress}; +use crate::model; + +impl GetNodeAddresses { + /// Converts version specific type to a version nonspecific, more strongly typed type. + pub fn into_model(self) -> Result { + let nodes = self.0.into_iter().map(|n| n.into_model()).collect::>()?; + Ok(model::GetNodeAddresses(nodes)) + } +} + +impl NodeAddress { + /// Converts version specific type to a version nonspecific, more strongly typed type. + pub fn into_model(self) -> Result { + let address = self.address.parse::>()?; + Ok(model::NodeAddress { + time: self.time, + services: self.services, + address, + port: self.port, + }) + } +} diff --git a/types/src/v18/network/mod.rs b/types/src/v18/network/mod.rs index e42c7ac8..63792aa0 100644 --- a/types/src/v18/network/mod.rs +++ b/types/src/v18/network/mod.rs @@ -4,6 +4,8 @@ //! //! Types for methods found under the `== Network ==` section of the API docs. +mod into; + use serde::{Deserialize, Serialize}; /// Result of JSON-RPC method `getnodeaddresses`. diff --git a/types/src/v19/mod.rs b/types/src/v19/mod.rs index a2575db3..8484967e 100644 --- a/types/src/v19/mod.rs +++ b/types/src/v19/mod.rs @@ -103,7 +103,7 @@ //! | getconnectioncount | returns numeric | | //! | getnettotals | version | | //! | getnetworkinfo | version + model | | -//! | getnodeaddresses | version | | +//! | getnodeaddresses | version + model | | //! | getpeerinfo | version | | //! | listbanned | returns string | | //! | ping | returns nothing | | diff --git a/types/src/v20/mod.rs b/types/src/v20/mod.rs index 9a4bf72f..41b72644 100644 --- a/types/src/v20/mod.rs +++ b/types/src/v20/mod.rs @@ -104,7 +104,7 @@ //! | getconnectioncount | returns numeric | | //! | getnettotals | version | | //! | getnetworkinfo | version + model | | -//! | getnodeaddresses | version | | +//! | getnodeaddresses | version + model | | //! | getpeerinfo | version | | //! | listbanned | returns string | | //! | ping | returns nothing | | diff --git a/types/src/v21/mod.rs b/types/src/v21/mod.rs index 5ff3e581..5be779b9 100644 --- a/types/src/v21/mod.rs +++ b/types/src/v21/mod.rs @@ -105,7 +105,7 @@ //! | getconnectioncount | returns numeric | | //! | getnettotals | version | | //! | getnetworkinfo | version + model | | -//! | getnodeaddresses | version | | +//! | getnodeaddresses | version + model | | //! | getpeerinfo | version | | //! | listbanned | returns string | | //! | ping | returns nothing | | diff --git a/types/src/v22/mod.rs b/types/src/v22/mod.rs index 03d1223f..2305a723 100644 --- a/types/src/v22/mod.rs +++ b/types/src/v22/mod.rs @@ -105,7 +105,7 @@ //! | getconnectioncount | returns numeric | | //! | getnettotals | version | | //! | getnetworkinfo | version + model | | -//! | getnodeaddresses | version | | +//! | getnodeaddresses | version + model | TODO | //! | getpeerinfo | version | | //! | listbanned | returns string | | //! | ping | returns nothing | | diff --git a/types/src/v23/mod.rs b/types/src/v23/mod.rs index ebea75e2..636567ae 100644 --- a/types/src/v23/mod.rs +++ b/types/src/v23/mod.rs @@ -96,7 +96,7 @@ //! | getconnectioncount | returns numeric | | //! | getnettotals | version | | //! | getnetworkinfo | version + model | | -//! | getnodeaddresses | version | | +//! | getnodeaddresses | version + model | TODO | //! | getpeerinfo | version | | //! | listbanned | returns string | | //! | ping | returns nothing | | diff --git a/types/src/v24/mod.rs b/types/src/v24/mod.rs index 79f76e5d..d242f7de 100644 --- a/types/src/v24/mod.rs +++ b/types/src/v24/mod.rs @@ -97,7 +97,7 @@ //! | getconnectioncount | returns numeric | | //! | getnettotals | version | | //! | getnetworkinfo | version + model | | -//! | getnodeaddresses | version | | +//! | getnodeaddresses | version + model | TODO || //! | getpeerinfo | version | | //! | listbanned | returns string | | //! | ping | returns nothing | | diff --git a/types/src/v25/mod.rs b/types/src/v25/mod.rs index f17b6889..77db62ae 100644 --- a/types/src/v25/mod.rs +++ b/types/src/v25/mod.rs @@ -98,7 +98,7 @@ //! | getconnectioncount | returns numeric | | //! | getnettotals | version | | //! | getnetworkinfo | version + model | | -//! | getnodeaddresses | version | | +//! | getnodeaddresses | version + model | TODO | //! | getpeerinfo | version | | //! | listbanned | returns string | | //! | ping | returns nothing | | diff --git a/types/src/v26/mod.rs b/types/src/v26/mod.rs index b73d19bb..6d0a12da 100644 --- a/types/src/v26/mod.rs +++ b/types/src/v26/mod.rs @@ -104,7 +104,7 @@ //! | getconnectioncount | returns numeric | | //! | getnettotals | version | | //! | getnetworkinfo | version + model | | -//! | getnodeaddresses | version | | +//! | getnodeaddresses | version + model | TODO | //! | getpeerinfo | version | | //! | listbanned | returns string | | //! | ping | returns nothing | | diff --git a/types/src/v27/mod.rs b/types/src/v27/mod.rs index 6535e76b..f46370cf 100644 --- a/types/src/v27/mod.rs +++ b/types/src/v27/mod.rs @@ -104,7 +104,7 @@ //! | getconnectioncount | returns numeric | | //! | getnettotals | version | | //! | getnetworkinfo | version + model | | -//! | getnodeaddresses | version | | +//! | getnodeaddresses | version + model | TODO | //! | getpeerinfo | version | | //! | listbanned | returns string | | //! | ping | returns nothing | | diff --git a/types/src/v28/mod.rs b/types/src/v28/mod.rs index fd21c3dc..4985d79d 100644 --- a/types/src/v28/mod.rs +++ b/types/src/v28/mod.rs @@ -104,7 +104,7 @@ //! | getconnectioncount | returns numeric | | //! | getnettotals | version | | //! | getnetworkinfo | version + model | | -//! | getnodeaddresses | version | | +//! | getnodeaddresses | version + model | TODO | //! | getpeerinfo | version | | //! | listbanned | returns string | | //! | ping | returns nothing | | diff --git a/verify/src/method/v18.rs b/verify/src/method/v18.rs index ed2b0c07..f2a641d6 100644 --- a/verify/src/method/v18.rs +++ b/verify/src/method/v18.rs @@ -60,7 +60,7 @@ pub const METHODS: &[Method] = &[ Method::new_numeric("getconnectioncount", "get_connection_count"), Method::new_no_model("getnettotals", "GetNetTotals", "get_net_totals"), Method::new_modelled("getnetworkinfo", "GetNetworkInfo", "get_network_info"), - Method::new_no_model("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), + Method::new_modelled("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), Method::new_no_model("getpeerinfo", "GetPeerInfo", "get_peer_info"), Method::new_string("listbanned", "list_banned"), // v17 docs seem wrong, says no return. Method::new_nothing("ping", "ping"), diff --git a/verify/src/method/v19.rs b/verify/src/method/v19.rs index 31d5ead9..8a277c06 100644 --- a/verify/src/method/v19.rs +++ b/verify/src/method/v19.rs @@ -60,7 +60,7 @@ pub const METHODS: &[Method] = &[ Method::new_numeric("getconnectioncount", "get_connection_count"), Method::new_no_model("getnettotals", "GetNetTotals", "get_net_totals"), Method::new_modelled("getnetworkinfo", "GetNetworkInfo", "get_network_info"), - Method::new_no_model("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), + Method::new_modelled("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), Method::new_no_model("getpeerinfo", "GetPeerInfo", "get_peer_info"), Method::new_string("listbanned", "list_banned"), // v17 docs seem wrong, says no return. Method::new_nothing("ping", "ping"), diff --git a/verify/src/method/v20.rs b/verify/src/method/v20.rs index 68f67770..76a3ceec 100644 --- a/verify/src/method/v20.rs +++ b/verify/src/method/v20.rs @@ -61,7 +61,7 @@ pub const METHODS: &[Method] = &[ Method::new_numeric("getconnectioncount", "get_connection_count"), Method::new_no_model("getnettotals", "GetNetTotals", "get_net_totals"), Method::new_modelled("getnetworkinfo", "GetNetworkInfo", "get_network_info"), - Method::new_no_model("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), + Method::new_modelled("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), Method::new_no_model("getpeerinfo", "GetPeerInfo", "get_peer_info"), Method::new_string("listbanned", "list_banned"), // v17 docs seem wrong, says no return. Method::new_nothing("ping", "ping"), diff --git a/verify/src/method/v21.rs b/verify/src/method/v21.rs index 24528fe8..466cb529 100644 --- a/verify/src/method/v21.rs +++ b/verify/src/method/v21.rs @@ -62,7 +62,7 @@ pub const METHODS: &[Method] = &[ Method::new_numeric("getconnectioncount", "get_connection_count"), Method::new_no_model("getnettotals", "GetNetTotals", "get_net_totals"), Method::new_modelled("getnetworkinfo", "GetNetworkInfo", "get_network_info"), - Method::new_no_model("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), + Method::new_modelled("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), Method::new_no_model("getpeerinfo", "GetPeerInfo", "get_peer_info"), Method::new_string("listbanned", "list_banned"), // v17 docs seem wrong, says no return. Method::new_nothing("ping", "ping"), diff --git a/verify/src/method/v22.rs b/verify/src/method/v22.rs index 9ba8999d..16031a2e 100644 --- a/verify/src/method/v22.rs +++ b/verify/src/method/v22.rs @@ -62,7 +62,7 @@ pub const METHODS: &[Method] = &[ Method::new_numeric("getconnectioncount", "get_connection_count"), Method::new_no_model("getnettotals", "GetNetTotals", "get_net_totals"), Method::new_modelled("getnetworkinfo", "GetNetworkInfo", "get_network_info"), - Method::new_no_model("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), + Method::new_modelled("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), Method::new_no_model("getpeerinfo", "GetPeerInfo", "get_peer_info"), Method::new_string("listbanned", "list_banned"), // v17 docs seem wrong, says no return. Method::new_nothing("ping", "ping"), diff --git a/verify/src/method/v23.rs b/verify/src/method/v23.rs index 4f9b23a3..d4078988 100644 --- a/verify/src/method/v23.rs +++ b/verify/src/method/v23.rs @@ -60,7 +60,7 @@ pub const METHODS: &[Method] = &[ Method::new_numeric("getconnectioncount", "get_connection_count"), Method::new_no_model("getnettotals", "GetNetTotals", "get_net_totals"), Method::new_modelled("getnetworkinfo", "GetNetworkInfo", "get_network_info"), - Method::new_no_model("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), + Method::new_modelled("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), Method::new_no_model("getpeerinfo", "GetPeerInfo", "get_peer_info"), Method::new_string("listbanned", "list_banned"), // v17 docs seem wrong, says no return. Method::new_nothing("ping", "ping"), diff --git a/verify/src/method/v24.rs b/verify/src/method/v24.rs index e6dc3a4c..3f1a880e 100644 --- a/verify/src/method/v24.rs +++ b/verify/src/method/v24.rs @@ -61,7 +61,7 @@ pub const METHODS: &[Method] = &[ Method::new_numeric("getconnectioncount", "get_connection_count"), Method::new_no_model("getnettotals", "GetNetTotals", "get_net_totals"), Method::new_modelled("getnetworkinfo", "GetNetworkInfo", "get_network_info"), - Method::new_no_model("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), + Method::new_modelled("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), Method::new_no_model("getpeerinfo", "GetPeerInfo", "get_peer_info"), Method::new_string("listbanned", "list_banned"), // v17 docs seem wrong, says no return. Method::new_nothing("ping", "ping"), diff --git a/verify/src/method/v25.rs b/verify/src/method/v25.rs index 8bcbd0b0..7eda7417 100644 --- a/verify/src/method/v25.rs +++ b/verify/src/method/v25.rs @@ -62,7 +62,7 @@ pub const METHODS: &[Method] = &[ Method::new_numeric("getconnectioncount", "get_connection_count"), Method::new_no_model("getnettotals", "GetNetTotals", "get_net_totals"), Method::new_modelled("getnetworkinfo", "GetNetworkInfo", "get_network_info"), - Method::new_no_model("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), + Method::new_modelled("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), Method::new_no_model("getpeerinfo", "GetPeerInfo", "get_peer_info"), Method::new_string("listbanned", "list_banned"), // v17 docs seem wrong, says no return. Method::new_nothing("ping", "ping"), diff --git a/verify/src/method/v26.rs b/verify/src/method/v26.rs index f7d6ea1d..1b7cdd5f 100644 --- a/verify/src/method/v26.rs +++ b/verify/src/method/v26.rs @@ -68,7 +68,7 @@ pub const METHODS: &[Method] = &[ Method::new_numeric("getconnectioncount", "get_connection_count"), Method::new_no_model("getnettotals", "GetNetTotals", "get_net_totals"), Method::new_modelled("getnetworkinfo", "GetNetworkInfo", "get_network_info"), - Method::new_no_model("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), + Method::new_modelled("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), Method::new_no_model("getpeerinfo", "GetPeerInfo", "get_peer_info"), Method::new_string("listbanned", "list_banned"), // v17 docs seem wrong, says no return. Method::new_nothing("ping", "ping"), diff --git a/verify/src/method/v27.rs b/verify/src/method/v27.rs index d4fe3205..0cad5b20 100644 --- a/verify/src/method/v27.rs +++ b/verify/src/method/v27.rs @@ -70,7 +70,7 @@ pub const METHODS: &[Method] = &[ Method::new_numeric("getconnectioncount", "get_connection_count"), Method::new_no_model("getnettotals", "GetNetTotals", "get_net_totals"), Method::new_modelled("getnetworkinfo", "GetNetworkInfo", "get_network_info"), - Method::new_no_model("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), + Method::new_modelled("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), Method::new_no_model("getpeerinfo", "GetPeerInfo", "get_peer_info"), Method::new_string("listbanned", "list_banned"), // v17 docs seem wrong, says no return. Method::new_nothing("ping", "ping"), diff --git a/verify/src/method/v28.rs b/verify/src/method/v28.rs index 6470fee3..621466dd 100644 --- a/verify/src/method/v28.rs +++ b/verify/src/method/v28.rs @@ -70,7 +70,7 @@ pub const METHODS: &[Method] = &[ Method::new_numeric("getconnectioncount", "get_connection_count"), Method::new_no_model("getnettotals", "GetNetTotals", "get_net_totals"), Method::new_modelled("getnetworkinfo", "GetNetworkInfo", "get_network_info"), - Method::new_no_model("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), + Method::new_modelled("getnodeaddresses", "GetNodeAddresses", "get_node_addresses"), Method::new_no_model("getpeerinfo", "GetPeerInfo", "get_peer_info"), Method::new_string("listbanned", "list_banned"), // v17 docs seem wrong, says no return. Method::new_nothing("ping", "ping"),