Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions crates/floresta-node/src/json_rpc/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
use std::collections::BTreeMap;

use corepc_types::v26::AddrManInfoNetwork;
use corepc_types::v30::AddedNode;
use corepc_types::v30::AddedNodeAddress;
use corepc_types::v30::GetAddedNodeInfo;
use corepc_types::v30::GetAddrManInfo;
use corepc_types::v30::GetNetworkInfo;
use corepc_types::v30::GetNetworkInfoNetwork;
Expand All @@ -15,6 +18,7 @@ use floresta_wire::address_man::NetworkStats;
use floresta_wire::address_man::ReachableNetworks;
use floresta_wire::bitcoin_socket_addr::BitcoinSocketAddr;
use floresta_wire::bitcoin_socket_addr::SystemResolver;
use floresta_wire::node_interface::AddedNodeInfo;
use floresta_wire::node_interface::NetworkMethods;
use floresta_wire::node_interface::PeerInfo;
use serde_json::Value;
Expand Down Expand Up @@ -167,6 +171,44 @@ impl<Blockchain: RpcChain> RpcImpl<Blockchain> {
Ok(GetAddrManInfo(map))
}

pub(crate) async fn get_added_node_info(
&self,
node: Option<String>,
) -> Result<GetAddedNodeInfo> {
let node = node
.map(|str| BitcoinSocketAddr::parse_address(&str, Some(self.network), SystemResolver))
.transpose()?;

let node_request = self
.node
.get_added_node_info(node)
.await
.map_err(|e| JsonRpcError::Node(e.to_string()))?;

let mut ret: Vec<AddedNode> = vec![];

for AddedNodeInfo {
addednode,
connected,
addresses,
} in node_request
{
let mut cpc_addresses: Vec<AddedNodeAddress> = vec![];

for floresta_wire::node_interface::AddedNodeAddress { address, connected } in addresses

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for floresta_wire::node_interface::AddedNodeAddress { address, connected } in addresses
AddedNodeAddress

Can't this function use combinators?

{
cpc_addresses.push(AddedNodeAddress { address, connected });
}
ret.push(AddedNode {
added_node: addednode,
connected,
addresses: cpc_addresses,
});
}

Ok(GetAddedNodeInfo(ret))
}

pub(crate) async fn get_network_info(&self) -> Result<GetNetworkInfo> {
// Floresta does not listen for inbound connections, so every peer is outbound.
let connections_in = 0;
Expand Down
9 changes: 9 additions & 0 deletions crates/floresta-node/src/json_rpc/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,15 @@ async fn handle_json_rpc_request(
state.clone().find_tx_out(txid, vout, script, height).await
}

"getaddednodeinfo" => {
let node = try_into_optional(get_at(&params, 0, "node"))?;

state
.get_added_node_info(node)
.await
.map(|v| serde_json::to_value(v).expect(SERIALIZATION_EXPECT_MSG))
}

"getblock" => {
let hash = get_at(&params, 0, "block_hash")?;
let verbosity = get_with_default(&params, 1, "verbosity", 1)?;
Expand Down
41 changes: 41 additions & 0 deletions crates/floresta-wire/src/p2p_wire/node/peer_man.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ use crate::node_context::NodeContext;
use crate::node_context::PeerId;
use crate::node_handle::NodeResponse;
use crate::node_handle::UserRequest;
use crate::node_interface::AddedNodeAddress;
use crate::node_interface::AddedNodeInfo;
use crate::node_interface::PeerInfo;
use crate::p2p_wire::error::WireError;
use crate::p2p_wire::peer::PeerMessages;
Expand Down Expand Up @@ -849,6 +851,45 @@ where
})
}

pub(crate) fn handle_get_added_node_info(
&self,
node: Option<BitcoinSocketAddr>,
) -> Vec<AddedNodeInfo> {
self.added_peers
.iter()
.filter_map(|added| {
// If a node filter is specified, skip entries that don't match
if let Some(filter) = &node {
if &added.address != filter {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if &added.address != filter {
if added.address != *filter {

return None;
}
}

let connected = self.peers.values().any(|peer| {
peer.address.as_bitcoin_socket_addr() == &added.address

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
peer.address.as_bitcoin_socket_addr() == &added.address
*peer.address.as_bitcoin_socket_addr() == added.address

&& peer.state == PeerStatus::Ready
});

let addr_str = added.address.to_string();

let addresses = if connected {
vec![AddedNodeAddress {
address: addr_str.clone(),
connected: "outbound".to_string(),
}]
} else {
vec![]
};

Some(AddedNodeInfo {
addednode: addr_str,
connected,
addresses,
})
})
.collect()
}

// === ADDNODE ===

/// Handles addnode-RPC `Add` requests, adding a new peer to the `added_peers` list. This means
Expand Down
6 changes: 6 additions & 0 deletions crates/floresta-wire/src/p2p_wire/node/user_req.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ where
return;
}

UserRequest::GetAddedNodeInfo(node) => {
let info = self.handle_get_added_node_info(node);
try_and_log!(responder.send(NodeResponse::GetAddedNodeInfo(info)));
return;
}

UserRequest::SendTransaction(transaction) => {
let txid = transaction.compute_txid();
let mut mempool = self.mempool.lock().await;
Expand Down
18 changes: 18 additions & 0 deletions crates/floresta-wire/src/p2p_wire/node_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use super::UtreexoNodeConfig;
use super::node::NodeNotification;
use crate::address_man::ConnectionStats;
use crate::bitcoin_socket_addr::BitcoinSocketAddr;
use crate::node_interface::AddedNodeInfo;
use crate::node_interface::ChainMethods;
use crate::node_interface::MempoolMethods;
use crate::node_interface::NetworkMethods;
Expand Down Expand Up @@ -93,6 +94,9 @@ pub enum UserRequest {

/// Return address manager statistics.
GetAddrManInfo,

/// Request for data regarding added nodes possibly filter by a provided one
GetAddedNodeInfo(Option<BitcoinSocketAddr>),
}

#[derive(Debug)]
Expand Down Expand Up @@ -139,6 +143,9 @@ pub enum NodeResponse {

/// Address manager statistics.
GetAddrManInfo(ConnectionStats),

/// Request for data regarding added nodes possibly filter by a provided one
GetAddedNodeInfo(Vec<AddedNodeInfo>),
}

#[derive(Debug)]
Expand Down Expand Up @@ -271,6 +278,17 @@ impl NetworkMethods for NodeHandle {
extract_variant!(Ping, val)
}

async fn get_added_node_info(
&self,
node: Option<BitcoinSocketAddr>,
) -> Result<Vec<AddedNodeInfo>, Self::Error> {
let val = self
.send_request(UserRequest::GetAddedNodeInfo(node))
.await?;

extract_variant!(GetAddedNodeInfo, val)
}

async fn get_addrman_info(&self) -> Result<ConnectionStats, Self::Error> {
let val = self.send_request(UserRequest::GetAddrManInfo).await?;

Expand Down
33 changes: 33 additions & 0 deletions crates/floresta-wire/src/p2p_wire/node_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,33 @@ pub enum UserRequest {

/// Return address manager statistics.
GetAddrManInfo,

/// Return information about manually added nodes, optionally filtered by address.
GetAddedNodeInfo(Option<BitcoinSocketAddr>),
}

#[derive(Debug, Clone, Serialize)]
/// Information about a manually added node (via `addnode`).
pub struct AddedNodeInfo {
/// The address of the added node in "ip:port" format.
pub addednode: String,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BitcoinSocketAddr here


/// Whether we are currently connected to this node.
pub connected: bool,

/// Connection details. Only populated when `connected` is true.
#[serde(skip_serializing_if = "Vec::is_empty")]
pub addresses: Vec<AddedNodeAddress>,
}

#[derive(Debug, Clone, Serialize)]
/// Address information for a connected added node.
pub struct AddedNodeAddress {
/// The peer address in "ip:port" format.
pub address: String,

/// The connection direction: "outbound" (Floresta does not accept inbound).
pub connected: String,
}

#[derive(Debug, Clone, Serialize)]
Expand Down Expand Up @@ -213,6 +240,12 @@ pub trait NetworkMethods {
/// about a single peer.
fn get_peer_info(&self) -> impl Future<Output = Result<Vec<PeerInfo>, Self::Error>>;

/// Information about all manually added nodes possibly filtering by a given one.
fn get_added_node_info(
&self,
node: Option<BitcoinSocketAddr>,
) -> impl Future<Output = Result<Vec<AddedNodeInfo>, Self::Error>>;

/// Returns the number of peers currently connected to the node
fn get_connection_count(&self) -> impl Future<Output = Result<usize, Self::Error>>;

Expand Down
44 changes: 44 additions & 0 deletions doc/rpc/getaddednodeinfo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# `getaddednodeinfo`

Return information about nodes that were manually added.

## Usage

### Synopsis

```text
floresta-cli getaddednodeinfo [node]
```

### Examples

```bash
floresta-cli getaddednodeinfo
floresta-cli getaddednodeinfo 192.168.0.1:8333
```

## Arguments

- `node` - (string, optional) If provided, return information only about this added node. The value should be an IP address or `ip:port`. If only an IP is given, port 8333 is assumed.

## Returns

### Ok Response

A JSON array of objects, one per added node:

- `addednode` - (string) The address of the node in `ip:port` format
- `connected` - (boolean) Whether the node is currently connected
- `addresses` - (array, only when connected) Connection details:
- `address` - (string) The peer address in `ip:port` format
- `connected` - (string) The connection direction (`"outbound"`)

### Error Response

- `Node` - Failed to retrieve added node information
- `InvalidAddress` - The provided node address could not be parsed

## Notes

- Only manually nodes added will appear here; peers discovered automatically are not included.
- Floresta does not accept inbound connections yet, so the `connected` field in the `addresses` array is always `"outbound"`.