From 0c1b4c17b4a1ca7ba4887eec51e6ffedd0018405 Mon Sep 17 00:00:00 2001 From: Sergi Delgado Segura Date: Sat, 12 Nov 2022 14:33:34 -0300 Subject: [PATCH] Adds addresses to gettowerinfo --- teos-common/src/lib.rs | 1 + teos-common/src/net.rs | 39 ++++++++++++++++ teos/build.rs | 4 ++ teos/proto/teos/v2/tower_services.proto | 13 +++++- teos/src/api/internal.rs | 9 ++++ teos/src/api/mod.rs | 1 + teos/src/api/serde.rs | 62 +++++++++++++++++++++++++ teos/src/main.rs | 54 ++++++++++++++------- teos/src/test_utils.rs | 2 + 9 files changed, 166 insertions(+), 19 deletions(-) create mode 100644 teos-common/src/net.rs create mode 100644 teos/src/api/serde.rs diff --git a/teos-common/src/lib.rs b/teos-common/src/lib.rs index a4d5cc5..b355e5b 100644 --- a/teos-common/src/lib.rs +++ b/teos-common/src/lib.rs @@ -13,6 +13,7 @@ pub mod constants; pub mod cryptography; pub mod dbm; pub mod errors; +pub mod net; pub mod receipts; pub mod ser; pub mod test_utils; diff --git a/teos-common/src/net.rs b/teos-common/src/net.rs new file mode 100644 index 0000000..e0497a7 --- /dev/null +++ b/teos-common/src/net.rs @@ -0,0 +1,39 @@ +use std::fmt; + +/// Represents all types of teos network addresses +pub enum AddressType { + IpV4 = 0, + TorV3 = 1, +} + +impl From for AddressType { + fn from(x: i32) -> Self { + match x { + 0 => AddressType::IpV4, + 1 => AddressType::TorV3, + x => panic!("Unknown address type {}", x), + } + } +} + +impl std::str::FromStr for AddressType { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "ipv4" => Ok(AddressType::IpV4), + "torv3" => Ok(AddressType::TorV3), + _ => Err(format!("Unknown type: {}", s)), + } + } +} + +impl fmt::Display for AddressType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match self { + AddressType::IpV4 => "ipv4", + AddressType::TorV3 => "torv3", + }; + write!(f, "{}", s) + } +} diff --git a/teos/build.rs b/teos/build.rs index 0bd1477..aa9031f 100644 --- a/teos/build.rs +++ b/teos/build.rs @@ -12,6 +12,10 @@ fn main() -> Result<(), Box> { "GetUserResponse.appointments", "#[serde(serialize_with = \"teos_common::ser::serde_vec_bytes::serialize\")]", ) + .field_attribute( + "NetworkAddress.address_type", + "#[serde(rename = \"type\", with = \"crate::api::serde::serde_address_type\")]", + ) .compile( &[ "proto/teos/v2/appointment.proto", diff --git a/teos/proto/teos/v2/tower_services.proto b/teos/proto/teos/v2/tower_services.proto index 944e2d2..92fa881 100644 --- a/teos/proto/teos/v2/tower_services.proto +++ b/teos/proto/teos/v2/tower_services.proto @@ -7,15 +7,26 @@ import "common/teos/v2/appointment.proto"; import "common/teos/v2/user.proto"; import "google/protobuf/empty.proto"; +message NetworkAddress { + // Tower public API endpoint. + enum AddressType { + IpV4 = 0; + TorV3 = 1; + } + AddressType address_type = 1; + string address = 2; + uint32 port = 3; + +} message GetTowerInfoResponse { // Response with information about the tower. - bytes tower_id = 1; uint32 n_registered_users = 2; uint32 n_watcher_appointments = 3; uint32 n_responder_trackers = 4; bool bitcoind_reachable = 5; + repeated NetworkAddress addresses = 6; } service PublicTowerServices { diff --git a/teos/src/api/internal.rs b/teos/src/api/internal.rs index e79c427..bcfe5b1 100644 --- a/teos/src/api/internal.rs +++ b/teos/src/api/internal.rs @@ -21,6 +21,8 @@ use teos_common::UserId; pub struct InternalAPI { /// A [Watcher] instance. watcher: Arc, + /// A list of public API endpoints. + addresses: Vec, /// A flag that indicates wether bitcoind is reachable or not. bitcoind_reachable: Arc<(Mutex, Condvar)>, /// A signal indicating the tower is shuting down. @@ -31,16 +33,22 @@ impl InternalAPI { /// Creates a new [InternalAPI] instance. pub fn new( watcher: Arc, + addresses: Vec, bitcoind_reachable: Arc<(Mutex, Condvar)>, shutdown_trigger: Trigger, ) -> Self { Self { watcher, + addresses, bitcoind_reachable, shutdown_trigger, } } + pub fn get_addresses(&self) -> &Vec { + &self.addresses + } + /// Checks whether bitcoind is reachable. fn check_service_unavailable(&self) -> Result<(), Status> { if *self.bitcoind_reachable.0.lock().unwrap() { @@ -305,6 +313,7 @@ impl PrivateTowerServices for Arc { ) -> Result, Status> { Ok(Response::new(msgs::GetTowerInfoResponse { tower_id: self.watcher.tower_id.to_vec(), + addresses: self.get_addresses().clone(), n_registered_users: self.watcher.get_registered_users_count() as u32, n_watcher_appointments: self.watcher.get_appointments_count() as u32, n_responder_trackers: self.watcher.get_trackers_count() as u32, diff --git a/teos/src/api/mod.rs b/teos/src/api/mod.rs index 281e208..e901b04 100644 --- a/teos/src/api/mod.rs +++ b/teos/src/api/mod.rs @@ -1,3 +1,4 @@ pub mod http; pub mod internal; +pub mod serde; pub mod tor; diff --git a/teos/src/api/serde.rs b/teos/src/api/serde.rs new file mode 100644 index 0000000..d8c2183 --- /dev/null +++ b/teos/src/api/serde.rs @@ -0,0 +1,62 @@ +use crate::protos as msgs; + +use teos_common::net::AddressType; + +impl msgs::NetworkAddress { + pub fn from_ipv4(address: String, port: u16) -> Self { + Self { + address_type: AddressType::IpV4 as i32, + address, + port: port as u32, + } + } + + pub fn from_torv3(address: String, port: u16) -> Self { + Self { + address_type: AddressType::TorV3 as i32, + address, + port: port as u32, + } + } +} + +pub mod serde_address_type { + use serde::de::{self, Deserializer}; + use serde::Serializer; + use std::str::FromStr; + + use super::AddressType; + + pub fn serialize(status: &i32, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&AddressType::from(*status).to_string()) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct StatusVisitor; + + impl<'de> de::Visitor<'de> for StatusVisitor { + type Value = i32; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a string containing the address type") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + let status = AddressType::from_str(v) + .map_err(|_| E::custom("given address type is unknown"))?; + Ok(status as i32) + } + } + + deserializer.deserialize_any(StatusVisitor) + } +} diff --git a/teos/src/main.rs b/teos/src/main.rs index 7fdd158..1986310 100644 --- a/teos/src/main.rs +++ b/teos/src/main.rs @@ -19,13 +19,14 @@ use lightning_block_sync::poll::{ use lightning_block_sync::{BlockSource, SpvClient, UnboundedCache}; use teos::api::internal::InternalAPI; -use teos::api::{http, tor}; +use teos::api::{http, tor::TorAPI}; use teos::bitcoin_cli::BitcoindClient; use teos::carrier::Carrier; use teos::chain_monitor::ChainMonitor; use teos::config::{self, Config, Opt}; use teos::dbm::DBM; use teos::gatekeeper::Gatekeeper; +use teos::protos as msgs; use teos::protos::private_tower_services_server::PrivateTowerServicesServer; use teos::protos::public_tower_services_server::PublicTowerServicesServer; use teos::responder::Responder; @@ -273,8 +274,36 @@ async fn main() { log::info!("Bootstrap completed. Turning on interfaces"); // Build interfaces + let http_api_addr = format!("{}:{}", conf.api_bind, conf.api_port) + .parse() + .unwrap(); + let mut addresses = vec![msgs::NetworkAddress::from_ipv4( + conf.api_bind.clone(), + conf.api_port, + )]; + + // Create Tor endpoint if required + let tor_api = if conf.tor_support { + let tor_api = TorAPI::new( + http_api_addr, + conf.onion_hidden_service_port, + conf.tor_control_port, + path_network, + ) + .await; + addresses.push(msgs::NetworkAddress::from_torv3( + tor_api.get_onion_address(), + conf.api_port, + )); + + Some(tor_api) + } else { + None + }; + let rpc_api = Arc::new(InternalAPI::new( watcher, + addresses, bitcoind_reachable.clone(), shutdown_trigger, )); @@ -290,9 +319,6 @@ async fn main() { "http://{}:{}", conf.internal_api_bind, conf.internal_api_port ); - let http_api_addr = format!("{}:{}", conf.api_bind, conf.api_port) - .parse() - .unwrap(); // Generate mtls certificates to data directory so the admin can securely connect // to the server to perform administrative tasks. @@ -336,21 +362,13 @@ async fn main() { // Add Tor Onion Service for public API let mut tor_task = Option::None; let (tor_service_ready, ready_signal_tor) = triggered::trigger(); - if conf.tor_support { + if let Some(tor_api) = tor_api { log::info!("Starting up Tor hidden service"); - let tor_control_port = conf.tor_control_port; - let onion_port = conf.onion_hidden_service_port; tor_task = Some(task::spawn(async move { - if let Err(e) = tor::expose_onion_service( - tor_control_port, - http_api_addr, - onion_port, - path_network, - tor_service_ready, - shutdown_signal_tor, - ) - .await + if let Err(e) = tor_api + .expose_onion_service(tor_service_ready, shutdown_signal_tor) + .await { eprintln!("Cannot connect to the Tor backend: {}", e); std::process::exit(1); @@ -367,8 +385,8 @@ async fn main() { http_api_task.await.unwrap(); private_api_task.await.unwrap(); public_api_task.await.unwrap(); - if conf.tor_support { - tor_task.unwrap().await.unwrap(); + if let Some(tor_task) = tor_task { + tor_task.await.unwrap(); } log::info!("Shutting down tower"); diff --git a/teos/src/test_utils.rs b/teos/src/test_utils.rs index f8cdf7a..b7959fd 100644 --- a/teos/src/test_utils.rs +++ b/teos/src/test_utils.rs @@ -45,6 +45,7 @@ use crate::carrier::Carrier; use crate::dbm::DBM; use crate::extended_appointment::{ExtendedAppointment, UUID}; use crate::gatekeeper::{Gatekeeper, UserInfo}; +use crate::protos as msgs; use crate::responder::{ConfirmationStatus, Responder, TransactionTracker}; use crate::rpc_errors; use crate::watcher::{Breach, Watcher}; @@ -496,6 +497,7 @@ pub(crate) async fn create_api_with_config( ( Arc::new(InternalAPI::new( Arc::new(watcher), + vec![msgs::NetworkAddress::from_ipv4("address".to_string(), 21)], bitcoind_reachable, shutdown_trigger, )),