From c777dd69d46fcc501082003cfc056bb029eddaaa Mon Sep 17 00:00:00 2001 From: Sergi Delgado Segura Date: Tue, 5 Apr 2022 11:52:54 -0400 Subject: [PATCH] Splits protos in main and common Some functionality can be reused by clients, like the API requests/responses, so splitting the protos will reduce the boilerplate when building them. --- teos-common/Cargo.toml | 8 +- teos-common/build.rs | 23 +++ .../proto/common/teos/v2/appointment.proto | 75 ++++++++++ teos-common/proto/common/teos/v2/user.proto | 31 ++++ teos-common/src/appointment.rs | 12 ++ teos-common/src/lib.rs | 5 + teos-common/src/ser.rs | 40 ++++++ teos/build.rs | 23 +-- teos/proto/teos/appointment.proto | 93 ------------ teos/proto/teos/user.proto | 51 ------- teos/proto/teos/v2/appointment.proto | 22 +++ teos/proto/teos/{ => v2}/tower_services.proto | 11 +- teos/proto/teos/v2/user.proto | 22 +++ teos/src/api/http.rs | 125 +++++++++-------- teos/src/api/internal.rs | 132 ++++++++++-------- teos/src/api/mod.rs | 41 ------ teos/src/extended_appointment.rs | 11 -- teos/src/responder.rs | 6 +- 18 files changed, 396 insertions(+), 335 deletions(-) create mode 100644 teos-common/build.rs create mode 100644 teos-common/proto/common/teos/v2/appointment.proto create mode 100644 teos-common/proto/common/teos/v2/user.proto create mode 100644 teos-common/src/ser.rs delete mode 100644 teos/proto/teos/appointment.proto delete mode 100644 teos/proto/teos/user.proto create mode 100644 teos/proto/teos/v2/appointment.proto rename teos/proto/teos/{ => v2}/tower_services.proto (65%) create mode 100644 teos/proto/teos/v2/user.proto diff --git a/teos-common/Cargo.toml b/teos-common/Cargo.toml index 40f0796..885113f 100644 --- a/teos-common/Cargo.toml +++ b/teos-common/Cargo.toml @@ -8,7 +8,10 @@ edition = "2018" [dependencies] # General -hex = "0.4.3" +hex = { version = "0.4.3", features = [ "serde" ] } +prost = "0.9" +serde = "1.0.130" +tonic = "0.6" # Crypto rand = "0.8.4" @@ -17,3 +20,6 @@ chacha20poly1305 = "0.8.0" # Bitcoin and Lightning bitcoin = "0.27" lightning = "0.0.105" + +[build-dependencies] +tonic-build = "0.6" \ No newline at end of file diff --git a/teos-common/build.rs b/teos-common/build.rs new file mode 100644 index 0000000..c132feb --- /dev/null +++ b/teos-common/build.rs @@ -0,0 +1,23 @@ +fn main() -> Result<(), Box> { + tonic_build::configure() + .type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]") + .type_attribute("AppointmentData.appointment_data", "#[serde(untagged)]") + .field_attribute("AppointmentData.appointment_data", "#[serde(flatten)]") + .field_attribute("appointment_data", "#[serde(rename = \"appointment\")]") + .field_attribute("user_id", "#[serde(with = \"hex::serde\")]") + .field_attribute("locator", "#[serde(with = \"hex::serde\")]") + .field_attribute("encrypted_blob", "#[serde(with = \"hex::serde\")]") + .field_attribute( + "GetAppointmentResponse.status", + "#[serde(with = \"crate::ser::serde_status\")]", + ) + .compile( + &[ + "proto/common/teos/v2/appointment.proto", + "proto/common/teos/v2/user.proto", + ], + &["proto/common/teos/v2"], + )?; + + Ok(()) +} diff --git a/teos-common/proto/common/teos/v2/appointment.proto b/teos-common/proto/common/teos/v2/appointment.proto new file mode 100644 index 0000000..3eb9d1e --- /dev/null +++ b/teos-common/proto/common/teos/v2/appointment.proto @@ -0,0 +1,75 @@ +syntax = "proto3"; +package common.teos.v2; + +message Appointment { + /* + Contains the basic information about an appointment (Watcher) and it's used for messages like + AddAppointmentRequest or encapsulated inside AppointmentData for GetAppointmentResponse + */ + + bytes locator = 1; + bytes encrypted_blob = 2; + uint32 to_self_delay = 3; + + } + + message Tracker { + // It's the equivalent of an appointment message from data held by the Responder. + + bytes dispute_txid = 1; + bytes penalty_txid = 2; + bytes penalty_rawtx = 3; + } + + message AppointmentData { + /* + Encapsulates the data for a GetAppointmentResponse, given it can be an appointment (data is on the Watcher) or a + tracker (data is on the Responder). + */ + + oneof appointment_data { + Appointment appointment = 1; + Tracker tracker = 2; + } + } + + message AddAppointmentRequest { + // Request to add an appointment to the backend, contains the appointment data and the user signature. + + Appointment appointment = 1; + string signature = 2; + } + + message AddAppointmentResponse { + /* + Response to an AddAppointmentRequest, contains the locator to identify the added appointment, the tower signature, + the block at which the tower has started (or will start) watching for the appointment, and the updated subscription + information. + */ + + bytes locator = 1; + uint32 start_block = 2; + string signature = 3; + uint32 available_slots = 4; + uint32 subscription_expiry = 5; + } + + message GetAppointmentRequest { + // Request to get information about an appointment. Contains the appointment locator and a signature by the user. + + bytes locator = 1; + string signature = 2; + } + + message GetAppointmentResponse { + // Response to a GetAppointmentRequest. Contains the appointment data encapsulated in an AppointmentData message. + + AppointmentData appointment_data = 1; + enum AppointmentStatus { + NOT_FOUND = 0; + BEING_WATCHED = 1; + DISPUTE_RESPONDED = 2; + + } + AppointmentStatus status = 2; + } \ No newline at end of file diff --git a/teos-common/proto/common/teos/v2/user.proto b/teos-common/proto/common/teos/v2/user.proto new file mode 100644 index 0000000..83be03d --- /dev/null +++ b/teos-common/proto/common/teos/v2/user.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; +package common.teos.v2; + +message RegisterRequest { + // Requests a user registration with the tower. Contains the user id in the form of a compressed ECDSA public key. + + bytes user_id = 1; + } + + message RegisterResponse { + // Response to a RegisterRequest, contains the registration information alongside the tower signature of the agreement. + + bytes user_id = 1; + uint32 available_slots = 2; + uint32 subscription_expiry = 3; + string subscription_signature = 4; + } + + message GetSubscriptionInfoRequest { + // Request to get a specific user's subscription info. + + string signature = 1; +} + +message GetSubscriptionInfoResponse { + // Response with the information the tower has about a specific user + + uint32 available_slots = 1; + uint32 subscription_expiry = 2; + repeated bytes locators = 3; +} \ No newline at end of file diff --git a/teos-common/src/appointment.rs b/teos-common/src/appointment.rs index b22f925..b688a01 100644 --- a/teos-common/src/appointment.rs +++ b/teos-common/src/appointment.rs @@ -6,6 +6,8 @@ use std::{convert::TryInto, fmt}; use bitcoin::Txid; +use crate::protos as msgs; + pub const LOCATOR_LEN: usize = 16; /// User identifier for appointments. @@ -125,3 +127,13 @@ impl Appointment { result } } + +impl From for msgs::Appointment { + fn from(a: Appointment) -> Self { + Self { + locator: a.locator.serialize(), + encrypted_blob: a.encrypted_blob.clone(), + to_self_delay: a.to_self_delay, + } + } +} diff --git a/teos-common/src/lib.rs b/teos-common/src/lib.rs index b0e58d7..5782994 100644 --- a/teos-common/src/lib.rs +++ b/teos-common/src/lib.rs @@ -2,11 +2,16 @@ //! //! Functionality shared between users and towers. +pub mod protos { + tonic::include_proto!("common.teos.v2"); +} + pub mod appointment; pub mod constants; pub mod cryptography; pub mod errors; pub mod receipts; +pub mod ser; use std::fmt; diff --git a/teos-common/src/ser.rs b/teos-common/src/ser.rs new file mode 100644 index 0000000..eb3941f --- /dev/null +++ b/teos-common/src/ser.rs @@ -0,0 +1,40 @@ +pub mod serde_status { + use serde::de::{self, Deserializer}; + use serde::ser::Serializer; + use std::str::FromStr; + + use crate::appointment::AppointmentStatus; + + pub fn serialize(status: &i32, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&AppointmentStatus::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 status") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + let status = AppointmentStatus::from_str(v) + .map_err(|_| E::custom("given status is unknown"))?; + Ok(status as i32) + } + } + + deserializer.deserialize_any(StatusVisitor) + } +} diff --git a/teos/build.rs b/teos/build.rs index 0e5cc8f..56482d4 100644 --- a/teos/build.rs +++ b/teos/build.rs @@ -1,18 +1,9 @@ fn main() -> Result<(), Box> { tonic_build::configure() + .extern_path(".common.teos.v2", "::teos-common::protos") .type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]") - .type_attribute("AppointmentData.appointment_data", "#[serde(untagged)]") - .field_attribute("AppointmentData.appointment_data", "#[serde(flatten)]") - .field_attribute("appointment_data", "#[serde(rename = \"appointment\")]") .field_attribute("user_id", "#[serde(with = \"hex::serde\")]") .field_attribute("tower_id", "#[serde(with = \"hex::serde\")]") - .field_attribute("locator", "#[serde(with = \"hex::serde\")]") - .field_attribute("encrypted_blob", "#[serde(with = \"hex::serde\")]") - .field_attribute("tx", "#[serde(with = \"hex::serde\")]") - .field_attribute( - "locators", - "#[serde(serialize_with = \"crate::api::http::serialize_vec_bytes\")]", - ) .field_attribute( "user_ids", "#[serde(serialize_with = \"crate::api::http::serialize_vec_bytes\")]", @@ -21,17 +12,13 @@ fn main() -> Result<(), Box> { "GetUserResponse.appointments", "#[serde(serialize_with = \"crate::api::http::serialize_vec_bytes\")]", ) - .field_attribute( - "GetAppointmentResponse.status", - "#[serde(with = \"crate::api::serde_status\")]", - ) .compile( &[ - "proto/teos/appointment.proto", - "proto/teos/tower_services.proto", - "proto/teos/user.proto", + "proto/teos/v2/appointment.proto", + "proto/teos/v2/tower_services.proto", + "proto/teos/v2/user.proto", ], - &["proto/teos"], + &["proto/teos/v2", "../teos-common/proto/"], )?; Ok(()) diff --git a/teos/proto/teos/appointment.proto b/teos/proto/teos/appointment.proto deleted file mode 100644 index b0b1639..0000000 --- a/teos/proto/teos/appointment.proto +++ /dev/null @@ -1,93 +0,0 @@ -syntax = "proto3"; -package teos.v2; - -message Appointment { - /* - Contains the basic information about an appointment (Watcher) and it's used for messages like - AddAppointmentRequest or encapsulated inside AppointmentData for GetAppointmentResponse - */ - - bytes locator = 1; - bytes encrypted_blob = 2; - uint32 to_self_delay = 3; - -} - -message Tracker { - // It's the equivalent of an appointment message from data held by the Responder. - - bytes dispute_txid = 1; - bytes penalty_txid = 2; - bytes penalty_rawtx = 3; -} - -message AppointmentData { - /* - Encapsulates the data for a GetAppointmentResponse, given it can be an appointment (data is on the Watcher) or a - tracker (data is on the Responder). - */ - - oneof appointment_data { - Appointment appointment = 1; - Tracker tracker = 2; - } -} - -message AddAppointmentRequest { - // Request to add an appointment to the backend, contains the appointment data and the user signature. - - Appointment appointment = 1; - string signature = 2; -} - -message AddAppointmentResponse { - /* - Response to an AddAppointmentRequest, contains the locator to identify the added appointment, the tower signature, - the block at which the tower has started (or will start) watching for the appointment, and the updated subscription - information. - */ - - bytes locator = 1; - uint32 start_block = 2; - string signature = 3; - uint32 available_slots = 4; - uint32 subscription_expiry = 5; -} - -message GetAppointmentRequest { - // Request to get information about an appointment. Contains the appointment locator and a signature by the user. - - bytes locator = 1; - string signature = 2; -} - -message GetAppointmentResponse { - // Response to a GetAppointmentRequest. Contains the appointment data encapsulated in an AppointmentData message. - - AppointmentData appointment_data = 1; - enum AppointmentStatus { - NOT_FOUND = 0; - BEING_WATCHED = 1; - DISPUTE_RESPONDED = 2; - - } - AppointmentStatus status = 2; -} - -message GetAppointmentsRequest { - // Request the information of appointments with specific locator. - - bytes locator = 1; -} - -message GetAppointmentsResponse { - // Response with the information of all appointments with a specific locator. - - repeated AppointmentData appointments = 1; -} - -message GetAllAppointmentsResponse { - // Response with data about all the appointments in the tower. - - repeated AppointmentData appointments = 1; -} \ No newline at end of file diff --git a/teos/proto/teos/user.proto b/teos/proto/teos/user.proto deleted file mode 100644 index 5cef3e2..0000000 --- a/teos/proto/teos/user.proto +++ /dev/null @@ -1,51 +0,0 @@ -syntax = "proto3"; -package teos.v2; - -message RegisterRequest { - // Requests a user registration with the tower. Contains the user id in the form of a compressed ECDSA public key. - - bytes user_id = 1; -} - -message RegisterResponse { - // Response to a RegisterRequest, contains the registration information alongside the tower signature of the agreement. - - bytes user_id = 1; - uint32 available_slots = 2; - uint32 subscription_expiry = 3; - string subscription_signature = 4; -} - -message GetUserRequest { - // Request to get information about a specific user. Contains the user id. - - bytes user_id = 1; -} - -message GetUserResponse { - // Response with the information the tower has about a specific user - - uint32 available_slots = 1; - uint32 subscription_expiry = 2; - repeated bytes appointments = 3; -} - -message GetUsersResponse { - // Response with information about all the users registered with the tower. Contains a list of user ids. - - repeated bytes user_ids = 1; -} - -message GetSubscriptionInfoRequest { - // Request to get a specific user's subscription info. - - string signature = 1; -} - -message GetSubscriptionInfoResponse { - // Response with the information the tower has about a specific user - - uint32 available_slots = 1; - uint32 subscription_expiry = 2; - repeated bytes locators = 3; -} \ No newline at end of file diff --git a/teos/proto/teos/v2/appointment.proto b/teos/proto/teos/v2/appointment.proto new file mode 100644 index 0000000..67c6679 --- /dev/null +++ b/teos/proto/teos/v2/appointment.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; +package teos.v2; + +import "common/teos/v2/appointment.proto"; + +message GetAppointmentsRequest { + // Request the information of appointments with specific locator. + + bytes locator = 1; +} + +message GetAppointmentsResponse { + // Response with the information of all appointments with a specific locator. + + repeated common.teos.v2.AppointmentData appointments = 1; +} + +message GetAllAppointmentsResponse { + // Response with data about all the appointments in the tower. + + repeated common.teos.v2.AppointmentData appointments = 1; +} \ No newline at end of file diff --git a/teos/proto/teos/tower_services.proto b/teos/proto/teos/v2/tower_services.proto similarity index 65% rename from teos/proto/teos/tower_services.proto rename to teos/proto/teos/v2/tower_services.proto index 8a12181..944e2d2 100644 --- a/teos/proto/teos/tower_services.proto +++ b/teos/proto/teos/v2/tower_services.proto @@ -3,8 +3,11 @@ package teos.v2; import "appointment.proto"; import "user.proto"; +import "common/teos/v2/appointment.proto"; +import "common/teos/v2/user.proto"; import "google/protobuf/empty.proto"; + message GetTowerInfoResponse { // Response with information about the tower. @@ -18,10 +21,10 @@ message GetTowerInfoResponse { service PublicTowerServices { // Public tower services, only reachable from the public API. - rpc register(RegisterRequest) returns (RegisterResponse) {} - rpc add_appointment(AddAppointmentRequest) returns (AddAppointmentResponse) {} - rpc get_appointment(GetAppointmentRequest) returns (GetAppointmentResponse) {} - rpc get_subscription_info(GetSubscriptionInfoRequest) returns (GetSubscriptionInfoResponse) {} + rpc register(common.teos.v2.RegisterRequest) returns (common.teos.v2.RegisterResponse) {} + rpc add_appointment(common.teos.v2.AddAppointmentRequest) returns (common.teos.v2.AddAppointmentResponse) {} + rpc get_appointment(common.teos.v2.GetAppointmentRequest) returns (common.teos.v2.GetAppointmentResponse) {} + rpc get_subscription_info(common.teos.v2.GetSubscriptionInfoRequest) returns (common.teos.v2.GetSubscriptionInfoResponse) {} } service PrivateTowerServices { diff --git a/teos/proto/teos/v2/user.proto b/teos/proto/teos/v2/user.proto new file mode 100644 index 0000000..36e2a3f --- /dev/null +++ b/teos/proto/teos/v2/user.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; +package teos.v2; + +message GetUserRequest { + // Request to get information about a specific user. Contains the user id. + + bytes user_id = 1; +} + +message GetUserResponse { + // Response with the information the tower has about a specific user + + uint32 available_slots = 1; + uint32 subscription_expiry = 2; + repeated bytes appointments = 3; +} + +message GetUsersResponse { + // Response with information about all the users registered with the tower. Contains a list of user ids. + + repeated bytes user_ids = 1; +} \ No newline at end of file diff --git a/teos/src/api/http.rs b/teos/src/api/http.rs index 60ec315..af1b5c4 100644 --- a/teos/src/api/http.rs +++ b/teos/src/api/http.rs @@ -7,9 +7,9 @@ use triggered::Listener; use warp::{http::StatusCode, reject, reply, Filter, Rejection, Reply}; use teos_common::appointment::LOCATOR_LEN; +use teos_common::protos as common_msgs; use teos_common::{errors, USER_ID_LEN}; -use crate::protos as msgs; use crate::protos::public_tower_services_client::PublicTowerServicesClient; // TODO: Limit the body length for /add_appointment should not be needed, since slots are consumed proportionally to it. @@ -124,7 +124,7 @@ fn parse_grpc_response( } async fn register( - req: msgs::RegisterRequest, + req: common_msgs::RegisterRequest, addr: Option, mut grpc_conn: PublicTowerServicesClient, ) -> std::result::Result { @@ -150,7 +150,7 @@ async fn register( } async fn add_appointment( - req: msgs::AddAppointmentRequest, + req: common_msgs::AddAppointmentRequest, addr: Option, mut grpc_conn: PublicTowerServicesClient, ) -> std::result::Result { @@ -182,7 +182,7 @@ async fn add_appointment( } async fn get_appointment( - req: msgs::GetAppointmentRequest, + req: common_msgs::GetAppointmentRequest, addr: Option, mut grpc_conn: PublicTowerServicesClient, ) -> std::result::Result { @@ -210,7 +210,7 @@ async fn get_appointment( } async fn get_subscription_info( - req: msgs::GetSubscriptionInfoRequest, + req: common_msgs::GetSubscriptionInfoRequest, addr: Option, mut grpc_conn: PublicTowerServicesClient, ) -> std::result::Result { @@ -637,15 +637,16 @@ mod tests_methods { #[tokio::test] async fn test_register() { let server_addr = run_tower_in_background().await; - let response = request_to_api::( - "/register", - msgs::RegisterRequest { - user_id: get_random_user_id().serialize(), - }, - server_addr, - ) - .await; - assert!(matches!(response, Ok(msgs::RegisterResponse { .. }))); + let response = + request_to_api::( + "/register", + common_msgs::RegisterRequest { + user_id: get_random_user_id().serialize(), + }, + server_addr, + ) + .await; + assert!(matches!(response, Ok(common_msgs::RegisterResponse { .. }))); } #[tokio::test] @@ -655,9 +656,9 @@ mod tests_methods { let user_id = get_random_user_id(); // Register once, this should go trough and set slots to the limit - request_to_api::( + request_to_api::( "/register", - msgs::RegisterRequest { + common_msgs::RegisterRequest { user_id: user_id.serialize(), }, server_addr, @@ -669,7 +670,7 @@ mod tests_methods { assert_eq!( check_api_error( "/register", - RequestBody::Json(serde_json::json!(msgs::RegisterRequest { + RequestBody::Json(serde_json::json!(common_msgs::RegisterRequest { user_id: user_id.serialize(), })), server_addr, @@ -697,7 +698,7 @@ mod tests_methods { assert_eq!( check_api_error( "/register", - RequestBody::Json(serde_json::json!(msgs::RegisterRequest { + RequestBody::Json(serde_json::json!(common_msgs::RegisterRequest { user_id: user_id.serialize(), })), server_addr, @@ -719,9 +720,9 @@ mod tests_methods { // Register first let (user_sk, user_pk) = cryptography::get_random_keypair(); - request_to_api::( + request_to_api::( "/register", - msgs::RegisterRequest { + common_msgs::RegisterRequest { user_id: user_pk.serialize().to_vec(), }, server_addr, @@ -733,9 +734,12 @@ mod tests_methods { let appointment = generate_dummy_appointment(None).inner; let signature = cryptography::sign(&appointment.serialize(), &user_sk).unwrap(); - let response = request_to_api::( + let response = request_to_api::< + common_msgs::AddAppointmentRequest, + common_msgs::AddAppointmentResponse, + >( "/add_appointment", - msgs::AddAppointmentRequest { + common_msgs::AddAppointmentRequest { appointment: Some(appointment.into()), signature, }, @@ -743,7 +747,10 @@ mod tests_methods { ) .await; - assert!(matches!(response, Ok(msgs::AddAppointmentResponse { .. }))); + assert!(matches!( + response, + Ok(common_msgs::AddAppointmentResponse { .. }) + )); } #[tokio::test] @@ -756,7 +763,7 @@ mod tests_methods { assert_eq!( check_api_error( "/add_appointment", - RequestBody::Json(serde_json::json!(msgs::AddAppointmentRequest { + RequestBody::Json(serde_json::json!(common_msgs::AddAppointmentRequest { appointment: Some(appointment.into()), signature, })), @@ -781,9 +788,9 @@ mod tests_methods { // Register let (user_sk, user_pk) = cryptography::get_random_keypair(); - request_to_api::( + request_to_api::( "/register", - msgs::RegisterRequest { + common_msgs::RegisterRequest { user_id: user_pk.serialize().to_vec(), }, server_addr, @@ -802,7 +809,7 @@ mod tests_methods { assert_eq!( check_api_error( "/add_appointment", - RequestBody::Json(serde_json::json!(msgs::AddAppointmentRequest { + RequestBody::Json(serde_json::json!(common_msgs::AddAppointmentRequest { appointment: Some(appointment.into()), signature, })), @@ -832,7 +839,7 @@ mod tests_methods { assert_eq!( check_api_error( "/add_appointment", - RequestBody::Json(serde_json::json!(msgs::AddAppointmentRequest { + RequestBody::Json(serde_json::json!(common_msgs::AddAppointmentRequest { appointment: Some(appointment.into()), signature, })), @@ -855,9 +862,9 @@ mod tests_methods { // Register first let (user_sk, user_pk) = cryptography::get_random_keypair(); - request_to_api::( + request_to_api::( "/register", - msgs::RegisterRequest { + common_msgs::RegisterRequest { user_id: user_pk.serialize().to_vec(), }, server_addr, @@ -869,9 +876,9 @@ mod tests_methods { let appointment = generate_dummy_appointment(None).inner; let signature = cryptography::sign(&appointment.serialize(), &user_sk).unwrap(); - request_to_api::( + request_to_api::( "/add_appointment", - msgs::AddAppointmentRequest { + common_msgs::AddAppointmentRequest { appointment: Some(appointment.clone().into()), signature, }, @@ -881,9 +888,12 @@ mod tests_methods { .unwrap(); // Get it back - let response = request_to_api::( + let response = request_to_api::< + common_msgs::GetAppointmentRequest, + common_msgs::GetAppointmentResponse, + >( "/get_appointment", - msgs::GetAppointmentRequest { + common_msgs::GetAppointmentRequest { locator: appointment.locator.serialize(), signature: cryptography::sign( format!("get appointment {}", appointment.locator).as_bytes(), @@ -895,7 +905,10 @@ mod tests_methods { ) .await; - assert!(matches!(response, Ok(msgs::GetAppointmentResponse { .. }))); + assert!(matches!( + response, + Ok(common_msgs::GetAppointmentResponse { .. }) + )); } #[tokio::test] @@ -910,7 +923,7 @@ mod tests_methods { assert_eq!( check_api_error( "/get_appointment", - RequestBody::Json(serde_json::json!(msgs::GetAppointmentRequest { + RequestBody::Json(serde_json::json!(common_msgs::GetAppointmentRequest { locator: appointment.locator.serialize(), signature: cryptography::sign( format!("get appointment {}", appointment.locator).as_bytes(), @@ -937,9 +950,9 @@ mod tests_methods { // Register first let (user_sk, user_pk) = cryptography::get_random_keypair(); - request_to_api::( + request_to_api::( "/register", - msgs::RegisterRequest { + common_msgs::RegisterRequest { user_id: user_pk.serialize().to_vec(), }, server_addr, @@ -953,7 +966,7 @@ mod tests_methods { assert_eq!( check_api_error( "/get_appointment", - RequestBody::Json(serde_json::json!(msgs::GetAppointmentRequest { + RequestBody::Json(serde_json::json!(common_msgs::GetAppointmentRequest { locator: appointment.locator.serialize(), signature: cryptography::sign( format!("get appointment {}", appointment.locator).as_bytes(), @@ -988,7 +1001,7 @@ mod tests_methods { assert_eq!( check_api_error( "/get_appointment", - RequestBody::Json(serde_json::json!(msgs::GetAppointmentRequest { + RequestBody::Json(serde_json::json!(common_msgs::GetAppointmentRequest { locator: appointment.locator.serialize(), signature: cryptography::sign( format!("get appointment {}", appointment.locator).as_bytes(), @@ -1015,9 +1028,9 @@ mod tests_methods { // Register first let (user_sk, user_pk) = cryptography::get_random_keypair(); - request_to_api::( + request_to_api::( "/register", - msgs::RegisterRequest { + common_msgs::RegisterRequest { user_id: user_pk.serialize().to_vec(), }, server_addr, @@ -1026,20 +1039,22 @@ mod tests_methods { .unwrap(); // Get the subscription info - let response = - request_to_api::( - "/get_subscription_info", - msgs::GetSubscriptionInfoRequest { - signature: cryptography::sign("get subscription info".as_bytes(), &user_sk) - .unwrap(), - }, - server_addr, - ) - .await; + let response = request_to_api::< + common_msgs::GetSubscriptionInfoRequest, + common_msgs::GetSubscriptionInfoResponse, + >( + "/get_subscription_info", + common_msgs::GetSubscriptionInfoRequest { + signature: cryptography::sign("get subscription info".as_bytes(), &user_sk) + .unwrap(), + }, + server_addr, + ) + .await; assert!(matches!( response, - Ok(msgs::GetSubscriptionInfoResponse { .. }) + Ok(common_msgs::GetSubscriptionInfoResponse { .. }) )); } @@ -1053,7 +1068,7 @@ mod tests_methods { assert_eq!( check_api_error( "/get_subscription_info", - RequestBody::Json(serde_json::json!(msgs::GetSubscriptionInfoRequest { + RequestBody::Json(serde_json::json!(common_msgs::GetSubscriptionInfoRequest { signature: cryptography::sign("get subscription info".as_bytes(), &user_sk) .unwrap(), })), @@ -1081,7 +1096,7 @@ mod tests_methods { assert_eq!( check_api_error( "/get_subscription_info", - RequestBody::Json(serde_json::json!(msgs::GetSubscriptionInfoRequest { + RequestBody::Json(serde_json::json!(common_msgs::GetSubscriptionInfoRequest { signature: cryptography::sign("get subscription info".as_bytes(), &user_sk) .unwrap(), })), diff --git a/teos/src/api/internal.rs b/teos/src/api/internal.rs index a27a732..c4b1baa 100644 --- a/teos/src/api/internal.rs +++ b/teos/src/api/internal.rs @@ -12,6 +12,7 @@ use crate::watcher::{ }; use teos_common::appointment::{Appointment, AppointmentStatus, Locator}; +use teos_common::protos as common_msgs; use teos_common::UserId; /// Internal API of the tower. @@ -61,8 +62,8 @@ impl PublicTowerServices for Arc { /// Register endpoint. Part of the public API. Internally calls [Watcher::register]. async fn register( &self, - request: Request, - ) -> Result, Status> { + request: Request, + ) -> Result, Status> { self.check_service_unavailable()?; let req_data = request.into_inner(); @@ -74,7 +75,7 @@ impl PublicTowerServices for Arc { })?; match self.watcher.register(user_id) { - Ok(receipt) => Ok(Response::new(msgs::RegisterResponse { + Ok(receipt) => Ok(Response::new(common_msgs::RegisterResponse { user_id: req_data.user_id, available_slots: receipt.available_slots(), subscription_expiry: receipt.subscription_expiry(), @@ -90,8 +91,8 @@ impl PublicTowerServices for Arc { /// Add appointment endpoint. Part of the public API. Internally calls [Watcher::add_appointment]. async fn add_appointment( &self, - request: Request, - ) -> Result, Status> { + request: Request, + ) -> Result, Status> { self.check_service_unavailable()?; let req_data = request.into_inner(); let app_data = req_data.appointment.unwrap(); @@ -108,7 +109,7 @@ impl PublicTowerServices for Arc { .add_appointment(appointment, req_data.signature) { Ok((receipt, available_slots, subscription_expiry)) => { - Ok(Response::new(msgs::AddAppointmentResponse { + Ok(Response::new(common_msgs::AddAppointmentResponse { locator: locator.serialize(), start_block: receipt.start_block(), signature: receipt.signature().unwrap(), @@ -137,8 +138,8 @@ impl PublicTowerServices for Arc { /// Get appointment endpoint. Part of the public API. Internally calls [Watcher::get_appointment]. async fn get_appointment( &self, - request: Request, - ) -> Result, Status> { + request: Request, + ) -> Result, Status> { self.check_service_unavailable()?; let req_data = request.into_inner(); let locator = Locator::deserialize(&req_data.locator).unwrap(); @@ -147,9 +148,9 @@ impl PublicTowerServices for Arc { Ok(info) => { let (appointment_data, status) = match info { AppointmentInfo::Appointment(appointment) => ( - msgs::AppointmentData { + common_msgs::AppointmentData { appointment_data: Some( - msgs::appointment_data::AppointmentData::Appointment( + common_msgs::appointment_data::AppointmentData::Appointment( appointment.into(), ), ), @@ -157,15 +158,17 @@ impl PublicTowerServices for Arc { AppointmentStatus::BeingWatched, ), AppointmentInfo::Tracker(tracker) => ( - msgs::AppointmentData { + common_msgs::AppointmentData { appointment_data: Some( - msgs::appointment_data::AppointmentData::Tracker(tracker.into()), + common_msgs::appointment_data::AppointmentData::Tracker( + tracker.into(), + ), ), }, AppointmentStatus::DisputeResponded, ), }; - Ok(Response::new(msgs::GetAppointmentResponse { + Ok(Response::new(common_msgs::GetAppointmentResponse { appointment_data: Some(appointment_data), status: status as i32, })) @@ -189,8 +192,8 @@ impl PublicTowerServices for Arc { /// Get subscription info endpoint. Part of the public API. Internally calls [Watcher::get_subscription_info]. async fn get_subscription_info( &self, - request: Request, - ) -> Result, Status> { + request: Request, + ) -> Result, Status> { self.check_service_unavailable()?; let (subscription_info, locators) = self .watcher @@ -206,7 +209,7 @@ impl PublicTowerServices for Arc { ), })?; - Ok(Response::new(msgs::GetSubscriptionInfoResponse { + Ok(Response::new(common_msgs::GetSubscriptionInfoResponse { available_slots: subscription_info.available_slots, subscription_expiry: subscription_info.subscription_expiry, locators: locators.iter().map(|x| x.serialize()).collect(), @@ -226,16 +229,18 @@ impl PrivateTowerServices for Arc { let mut all_appointments = Vec::new(); for (_, appointment) in self.watcher.get_all_watcher_appointments().into_iter() { - all_appointments.push(msgs::AppointmentData { - appointment_data: Some(msgs::appointment_data::AppointmentData::Appointment( - appointment.inner.into(), - )), + all_appointments.push(common_msgs::AppointmentData { + appointment_data: Some( + common_msgs::appointment_data::AppointmentData::Appointment( + appointment.inner.into(), + ), + ), }) } for (_, tracker) in self.watcher.get_all_responder_trackers().into_iter() { - all_appointments.push(msgs::AppointmentData { - appointment_data: Some(msgs::appointment_data::AppointmentData::Tracker( + all_appointments.push(common_msgs::AppointmentData { + appointment_data: Some(common_msgs::appointment_data::AppointmentData::Tracker( tracker.into(), )), }) @@ -265,10 +270,12 @@ impl PrivateTowerServices for Arc { .get_watcher_appointments_with_locator(locator) .into_iter() { - matching_appointments.push(msgs::AppointmentData { - appointment_data: Some(msgs::appointment_data::AppointmentData::Appointment( - appointment.inner.into(), - )), + matching_appointments.push(common_msgs::AppointmentData { + appointment_data: Some( + common_msgs::appointment_data::AppointmentData::Appointment( + appointment.inner.into(), + ), + ), }) } @@ -277,8 +284,8 @@ impl PrivateTowerServices for Arc { .get_responder_trackers_with_locator(locator) .into_iter() { - matching_appointments.push(msgs::AppointmentData { - appointment_data: Some(msgs::appointment_data::AppointmentData::Tracker( + matching_appointments.push(common_msgs::AppointmentData { + appointment_data: Some(common_msgs::appointment_data::AppointmentData::Tracker( tracker.into(), )), }) @@ -419,7 +426,7 @@ mod tests_private_api { assert_eq!(response.appointments.len(), 1); assert!(matches!( response.appointments[0].appointment_data, - Some(msgs::appointment_data::AppointmentData::Appointment { .. }) + Some(common_msgs::appointment_data::AppointmentData::Appointment { .. }) )); } @@ -441,7 +448,7 @@ mod tests_private_api { assert_eq!(response.appointments.len(), 1); assert!(matches!( response.appointments[0].appointment_data, - Some(msgs::appointment_data::AppointmentData::Tracker { .. }) + Some(common_msgs::appointment_data::AppointmentData::Tracker { .. }) )); } @@ -498,8 +505,8 @@ mod tests_private_api { for app_data in response.appointments { assert!(matches!( app_data.appointment_data, - Some(msgs::appointment_data::AppointmentData::Appointment( - msgs::Appointment { + Some(common_msgs::appointment_data::AppointmentData::Appointment( + common_msgs::Appointment { locator: ref app_loc, .. } @@ -549,8 +556,8 @@ mod tests_private_api { for app_data in response.appointments { assert!(matches!( app_data.appointment_data, - Some(msgs::appointment_data::AppointmentData::Tracker( - msgs::Tracker { + Some(common_msgs::appointment_data::AppointmentData::Tracker( + common_msgs::Tracker { ref dispute_txid, .. } @@ -743,14 +750,14 @@ mod tests_public_api { // Registering (even multiple times) should work for _ in 0..2 { let response = internal_api - .register(Request::new(msgs::RegisterRequest { + .register(Request::new(common_msgs::RegisterRequest { user_id: UserId(user_pk).serialize(), })) .await .unwrap() .into_inner(); - assert!(matches!(response, msgs::RegisterResponse { .. })) + assert!(matches!(response, common_msgs::RegisterResponse { .. })) } } @@ -773,7 +780,7 @@ mod tests_public_api { for user_id in user_ids { match internal_api - .register(Request::new(msgs::RegisterRequest { user_id })) + .register(Request::new(common_msgs::RegisterRequest { user_id })) .await { Err(status) => { @@ -794,7 +801,7 @@ mod tests_public_api { // First registration should go trough internal_api - .register(Request::new(msgs::RegisterRequest { + .register(Request::new(common_msgs::RegisterRequest { user_id: user_id.clone(), })) .await @@ -802,7 +809,7 @@ mod tests_public_api { // Trying to add more slots (re-register) must fail match internal_api - .register(Request::new(msgs::RegisterRequest { user_id })) + .register(Request::new(common_msgs::RegisterRequest { user_id })) .await { Err(status) => { @@ -822,7 +829,7 @@ mod tests_public_api { let user_id = UserId(user_pk).serialize(); match internal_api - .register(Request::new(msgs::RegisterRequest { user_id })) + .register(Request::new(common_msgs::RegisterRequest { user_id })) .await { Err(status) => { @@ -845,7 +852,7 @@ mod tests_public_api { let user_signature = cryptography::sign(&appointment.serialize(), &user_sk).unwrap(); let response = internal_api - .add_appointment(Request::new(msgs::AddAppointmentRequest { + .add_appointment(Request::new(common_msgs::AddAppointmentRequest { appointment: Some(appointment.clone().into()), signature: user_signature.clone(), })) @@ -853,7 +860,10 @@ mod tests_public_api { .unwrap() .into_inner(); - assert!(matches!(response, msgs::AddAppointmentResponse { .. })); + assert!(matches!( + response, + common_msgs::AddAppointmentResponse { .. } + )); } #[tokio::test] @@ -867,7 +877,7 @@ mod tests_public_api { let user_signature = cryptography::sign(&appointment.serialize(), &user_sk).unwrap(); match internal_api - .add_appointment(Request::new(msgs::AddAppointmentRequest { + .add_appointment(Request::new(common_msgs::AddAppointmentRequest { appointment: Some(appointment.clone().into()), signature: user_signature.clone(), })) @@ -896,7 +906,7 @@ mod tests_public_api { let user_signature = cryptography::sign(&appointment.serialize(), &user_sk).unwrap(); match internal_api - .add_appointment(Request::new(msgs::AddAppointmentRequest { + .add_appointment(Request::new(common_msgs::AddAppointmentRequest { appointment: Some(appointment.clone().into()), signature: user_signature.clone(), })) @@ -925,7 +935,7 @@ mod tests_public_api { let user_signature = cryptography::sign(&appointment.serialize(), &user_sk).unwrap(); match internal_api - .add_appointment(Request::new(msgs::AddAppointmentRequest { + .add_appointment(Request::new(common_msgs::AddAppointmentRequest { appointment: Some(appointment.clone().into()), signature: user_signature.clone(), })) @@ -954,7 +964,7 @@ mod tests_public_api { .add_random_tracker_to_responder(UUID::new(appointment.locator, user_id)); match internal_api - .add_appointment(Request::new(msgs::AddAppointmentRequest { + .add_appointment(Request::new(common_msgs::AddAppointmentRequest { appointment: Some(appointment.clone().into()), signature: user_signature.clone(), })) @@ -980,7 +990,7 @@ mod tests_public_api { let user_signature = cryptography::sign(&appointment.serialize(), &user_sk).unwrap(); match internal_api - .add_appointment(Request::new(msgs::AddAppointmentRequest { + .add_appointment(Request::new(common_msgs::AddAppointmentRequest { appointment: Some(appointment.clone().into()), signature: user_signature.clone(), })) @@ -1013,7 +1023,7 @@ mod tests_public_api { // Get the appointment through the API let message = format!("get appointment {}", appointment.locator); let response = internal_api - .get_appointment(Request::new(msgs::GetAppointmentRequest { + .get_appointment(Request::new(common_msgs::GetAppointmentRequest { locator: appointment.locator.serialize(), signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(), })) @@ -1021,7 +1031,10 @@ mod tests_public_api { .unwrap() .into_inner(); - assert!(matches!(response, msgs::GetAppointmentResponse { .. })) + assert!(matches!( + response, + common_msgs::GetAppointmentResponse { .. } + )) } #[tokio::test] @@ -1038,7 +1051,7 @@ mod tests_public_api { // Try to get the appointment through the API let message = format!("get appointment {}", appointment.locator); match internal_api - .get_appointment(Request::new(msgs::GetAppointmentRequest { + .get_appointment(Request::new(common_msgs::GetAppointmentRequest { locator: appointment.locator.serialize(), signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(), })) @@ -1065,7 +1078,7 @@ mod tests_public_api { let message = format!("get appointment {}", appointment.locator); match internal_api - .get_appointment(Request::new(msgs::GetAppointmentRequest { + .get_appointment(Request::new(common_msgs::GetAppointmentRequest { locator: appointment.locator.serialize(), signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(), })) @@ -1093,7 +1106,7 @@ mod tests_public_api { // Try to get the appointment through the API let message = format!("get appointment {}", appointment.locator); match internal_api - .get_appointment(Request::new(msgs::GetAppointmentRequest { + .get_appointment(Request::new(common_msgs::GetAppointmentRequest { locator: appointment.locator.serialize(), signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(), })) @@ -1116,7 +1129,7 @@ mod tests_public_api { let appointment = generate_dummy_appointment(None).inner; let message = format!("get appointment {}", appointment.locator); match internal_api - .get_appointment(Request::new(msgs::GetAppointmentRequest { + .get_appointment(Request::new(common_msgs::GetAppointmentRequest { locator: appointment.locator.serialize(), signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(), })) @@ -1141,14 +1154,17 @@ mod tests_public_api { // Get the subscription info though the API let message = "get subscription info".to_string(); let response = internal_api - .get_subscription_info(Request::new(msgs::GetSubscriptionInfoRequest { + .get_subscription_info(Request::new(common_msgs::GetSubscriptionInfoRequest { signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(), })) .await .unwrap() .into_inner(); - assert!(matches!(response, msgs::GetSubscriptionInfoResponse { .. })) + assert!(matches!( + response, + common_msgs::GetSubscriptionInfoResponse { .. } + )) } #[tokio::test] @@ -1161,7 +1177,7 @@ mod tests_public_api { // Try to get the subscription info though the API let message = "get subscription info".to_string(); match internal_api - .get_subscription_info(Request::new(msgs::GetSubscriptionInfoRequest { + .get_subscription_info(Request::new(common_msgs::GetSubscriptionInfoRequest { signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(), })) .await @@ -1185,7 +1201,7 @@ mod tests_public_api { // Try to get the subscription info though the API let message = "get subscription info".to_string(); match internal_api - .get_subscription_info(Request::new(msgs::GetSubscriptionInfoRequest { + .get_subscription_info(Request::new(common_msgs::GetSubscriptionInfoRequest { signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(), })) .await @@ -1206,7 +1222,7 @@ mod tests_public_api { let (user_sk, _) = get_random_keypair(); let message = "get subscription info".to_string(); match internal_api - .get_subscription_info(Request::new(msgs::GetSubscriptionInfoRequest { + .get_subscription_info(Request::new(common_msgs::GetSubscriptionInfoRequest { signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(), })) .await diff --git a/teos/src/api/mod.rs b/teos/src/api/mod.rs index bfeaf40..281e208 100644 --- a/teos/src/api/mod.rs +++ b/teos/src/api/mod.rs @@ -1,44 +1,3 @@ pub mod http; pub mod internal; pub mod tor; - -pub mod serde_status { - use serde::de::{self, Deserializer}; - use serde::ser::Serializer; - use std::str::FromStr; - - use teos_common::appointment::AppointmentStatus; - - pub fn serialize(status: &i32, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&AppointmentStatus::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 status") - } - - fn visit_str(self, v: &str) -> Result - where - E: de::Error, - { - let status = AppointmentStatus::from_str(v) - .map_err(|_| E::custom("given status is unknown"))?; - Ok(status as i32) - } - } - - deserializer.deserialize_any(StatusVisitor) - } -} diff --git a/teos/src/extended_appointment.rs b/teos/src/extended_appointment.rs index 0eeca5a..85749cc 100644 --- a/teos/src/extended_appointment.rs +++ b/teos/src/extended_appointment.rs @@ -6,7 +6,6 @@ use std::fmt; use bitcoin::hashes::{ripemd160, Hash}; -use crate::protos as msgs; use teos_common::appointment::{Appointment, Locator}; use teos_common::UserId; @@ -113,16 +112,6 @@ impl ExtendedAppointment { } } -impl From for msgs::Appointment { - fn from(a: Appointment) -> Self { - Self { - locator: a.locator.serialize(), - encrypted_blob: a.encrypted_blob.clone(), - to_self_delay: a.to_self_delay, - } - } -} - /// Computes the number of slots an appointment takes from a user subscription. /// /// This is based on the [encrypted_blob](Appointment::encrypted_blob) size and the slot size that was defined by the [Gatekeeper](crate::gatekeeper::Gatekeeper). diff --git a/teos/src/responder.rs b/teos/src/responder.rs index f19db7a..ad958d7 100644 --- a/teos/src/responder.rs +++ b/teos/src/responder.rs @@ -9,13 +9,13 @@ use bitcoin::{BlockHeader, Transaction, Txid}; use lightning::chain; use teos_common::constants; +use teos_common::protos as common_msgs; use teos_common::UserId; use crate::carrier::Carrier; use crate::dbm::DBM; use crate::extended_appointment::UUID; use crate::gatekeeper::{Gatekeeper, UserInfo}; -use crate::protos as msgs; use crate::watcher::Breach; /// Number of missed confirmations to wait before rebroadcasting a transaction. @@ -108,9 +108,9 @@ impl TransactionTracker { } } -impl From for msgs::Tracker { +impl From for common_msgs::Tracker { fn from(t: TransactionTracker) -> Self { - msgs::Tracker { + common_msgs::Tracker { dispute_txid: t.dispute_tx.txid().to_vec(), penalty_txid: t.penalty_tx.txid().to_vec(), penalty_rawtx: consensus::serialize(&t.penalty_tx),