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.
This commit is contained in:
Sergi Delgado Segura 2022-04-05 11:52:54 -04:00
parent 65f0709f78
commit c777dd69d4
18 changed files with 396 additions and 335 deletions

View file

@ -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"

23
teos-common/build.rs Normal file
View file

@ -0,0 +1,23 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
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(())
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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<Appointment> 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,
}
}
}

View file

@ -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;

40
teos-common/src/ser.rs Normal file
View file

@ -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<S>(status: &i32, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&AppointmentStatus::from(*status).to_string())
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<i32, D::Error>
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<E>(self, v: &str) -> Result<Self::Value, E>
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)
}
}

View file

@ -1,18 +1,9 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
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<dyn std::error::Error>> {
"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(())

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 {

View file

@ -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;
}

View file

@ -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<T: serde::Serialize>(
}
async fn register(
req: msgs::RegisterRequest,
req: common_msgs::RegisterRequest,
addr: Option<std::net::SocketAddr>,
mut grpc_conn: PublicTowerServicesClient<Channel>,
) -> std::result::Result<impl Reply, Rejection> {
@ -150,7 +150,7 @@ async fn register(
}
async fn add_appointment(
req: msgs::AddAppointmentRequest,
req: common_msgs::AddAppointmentRequest,
addr: Option<std::net::SocketAddr>,
mut grpc_conn: PublicTowerServicesClient<Channel>,
) -> std::result::Result<impl Reply, Rejection> {
@ -182,7 +182,7 @@ async fn add_appointment(
}
async fn get_appointment(
req: msgs::GetAppointmentRequest,
req: common_msgs::GetAppointmentRequest,
addr: Option<std::net::SocketAddr>,
mut grpc_conn: PublicTowerServicesClient<Channel>,
) -> std::result::Result<impl Reply, Rejection> {
@ -210,7 +210,7 @@ async fn get_appointment(
}
async fn get_subscription_info(
req: msgs::GetSubscriptionInfoRequest,
req: common_msgs::GetSubscriptionInfoRequest,
addr: Option<std::net::SocketAddr>,
mut grpc_conn: PublicTowerServicesClient<Channel>,
) -> std::result::Result<impl Reply, Rejection> {
@ -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::<msgs::RegisterRequest, msgs::RegisterResponse>(
"/register",
msgs::RegisterRequest {
user_id: get_random_user_id().serialize(),
},
server_addr,
)
.await;
assert!(matches!(response, Ok(msgs::RegisterResponse { .. })));
let response =
request_to_api::<common_msgs::RegisterRequest, common_msgs::RegisterResponse>(
"/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::<msgs::RegisterRequest, msgs::RegisterResponse>(
request_to_api::<common_msgs::RegisterRequest, common_msgs::RegisterResponse>(
"/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::<msgs::RegisterRequest, msgs::RegisterResponse>(
request_to_api::<common_msgs::RegisterRequest, common_msgs::RegisterResponse>(
"/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::<msgs::AddAppointmentRequest, msgs::AddAppointmentResponse>(
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::<msgs::RegisterRequest, msgs::RegisterResponse>(
request_to_api::<common_msgs::RegisterRequest, common_msgs::RegisterResponse>(
"/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::<msgs::RegisterRequest, msgs::RegisterResponse>(
request_to_api::<common_msgs::RegisterRequest, common_msgs::RegisterResponse>(
"/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::<msgs::AddAppointmentRequest, msgs::AddAppointmentResponse>(
request_to_api::<common_msgs::AddAppointmentRequest, common_msgs::AddAppointmentResponse>(
"/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::<msgs::GetAppointmentRequest, msgs::GetAppointmentResponse>(
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::<msgs::RegisterRequest, msgs::RegisterResponse>(
request_to_api::<common_msgs::RegisterRequest, common_msgs::RegisterResponse>(
"/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::<msgs::RegisterRequest, msgs::RegisterResponse>(
request_to_api::<common_msgs::RegisterRequest, common_msgs::RegisterResponse>(
"/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::<msgs::GetSubscriptionInfoRequest, msgs::GetSubscriptionInfoResponse>(
"/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(),
})),

View file

@ -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<InternalAPI> {
/// Register endpoint. Part of the public API. Internally calls [Watcher::register].
async fn register(
&self,
request: Request<msgs::RegisterRequest>,
) -> Result<Response<msgs::RegisterResponse>, Status> {
request: Request<common_msgs::RegisterRequest>,
) -> Result<Response<common_msgs::RegisterResponse>, Status> {
self.check_service_unavailable()?;
let req_data = request.into_inner();
@ -74,7 +75,7 @@ impl PublicTowerServices for Arc<InternalAPI> {
})?;
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<InternalAPI> {
/// Add appointment endpoint. Part of the public API. Internally calls [Watcher::add_appointment].
async fn add_appointment(
&self,
request: Request<msgs::AddAppointmentRequest>,
) -> Result<Response<msgs::AddAppointmentResponse>, Status> {
request: Request<common_msgs::AddAppointmentRequest>,
) -> Result<Response<common_msgs::AddAppointmentResponse>, 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<InternalAPI> {
.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<InternalAPI> {
/// Get appointment endpoint. Part of the public API. Internally calls [Watcher::get_appointment].
async fn get_appointment(
&self,
request: Request<msgs::GetAppointmentRequest>,
) -> Result<Response<msgs::GetAppointmentResponse>, Status> {
request: Request<common_msgs::GetAppointmentRequest>,
) -> Result<Response<common_msgs::GetAppointmentResponse>, 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<InternalAPI> {
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<InternalAPI> {
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<InternalAPI> {
/// Get subscription info endpoint. Part of the public API. Internally calls [Watcher::get_subscription_info].
async fn get_subscription_info(
&self,
request: Request<msgs::GetSubscriptionInfoRequest>,
) -> Result<Response<msgs::GetSubscriptionInfoResponse>, Status> {
request: Request<common_msgs::GetSubscriptionInfoRequest>,
) -> Result<Response<common_msgs::GetSubscriptionInfoResponse>, Status> {
self.check_service_unavailable()?;
let (subscription_info, locators) = self
.watcher
@ -206,7 +209,7 @@ impl PublicTowerServices for Arc<InternalAPI> {
),
})?;
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<InternalAPI> {
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<InternalAPI> {
.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<InternalAPI> {
.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

View file

@ -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<S>(status: &i32, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&AppointmentStatus::from(*status).to_string())
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<i32, D::Error>
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<E>(self, v: &str) -> Result<Self::Value, E>
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)
}
}

View file

@ -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<Appointment> 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).

View file

@ -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<TransactionTracker> for msgs::Tracker {
impl From<TransactionTracker> 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),