Skip to content

Commit d3819c0

Browse files
committed
added user_id as an option parameter to getappointments cli command
Signed-off-by: aruokhai <[email protected]> removed todo Signed-off-by: aruokhai <[email protected]>
1 parent 818f756 commit d3819c0

File tree

8 files changed

+112
-27
lines changed

8 files changed

+112
-27
lines changed

teos/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
22
tonic_build::configure()
33
.extern_path(".common.teos.v2", "::teos-common::protos")
44
.type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]")
5-
.field_attribute("user_id", "#[serde(with = \"hex::serde\")]")
5+
.field_attribute("GetUserRequest.user_id", "#[serde(with = \"hex::serde\")]")
66
.field_attribute("tower_id", "#[serde(with = \"hex::serde\")]")
77
.field_attribute(
88
"user_ids",

teos/proto/teos/v2/appointment.proto

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ package teos.v2;
44
import "common/teos/v2/appointment.proto";
55

66
message GetAppointmentsRequest {
7-
// Request the information of appointments with specific locator.
7+
// Request the information of appointments with specific locator and user_id (optional) .
88

99
bytes locator = 1;
10+
optional bytes user_id = 2;
1011
}
1112

1213
message GetAppointmentsResponse {

teos/src/api/internal.rs

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use std::sync::{Arc, Condvar, Mutex};
22
use tonic::{Code, Request, Response, Status};
33
use triggered::Trigger;
44

5-
use crate::extended_appointment::UUID;
65
use crate::protos as msgs;
76
use crate::protos::private_tower_services_server::PrivateTowerServices;
87
use crate::protos::public_tower_services_server::PublicTowerServices;
@@ -280,27 +279,40 @@ impl PrivateTowerServices for Arc<InternalAPI> {
280279
.map_or("an unknown address".to_owned(), |a| a.to_string())
281280
);
282281

283-
let mut matching_appointments = vec![];
284-
let locator = Locator::from_slice(&request.into_inner().locator).map_err(|_| {
282+
let req_data = request.into_inner();
283+
let locator = Locator::from_slice(&req_data.locator).map_err(|_| {
285284
Status::new(
286285
Code::InvalidArgument,
287286
"The provided locator does not match the expected format (16-byte hexadecimal string)",
288287
)
289288
})?;
290-
291-
for (_, appointment) in self
289+
let mut user_id = None;
290+
if let Some(user_id_slice) = req_data.user_id {
291+
let parsed_user_id = UserId::from_slice(&user_id_slice).map_err(|_| {
292+
Status::new(
293+
Code::InvalidArgument,
294+
"The Provided user_id does not match expected format (33-byte hex string)",
295+
)
296+
})?;
297+
user_id = Some(parsed_user_id)
298+
}
299+
let appointments: Vec<(UserId, Appointment)> = self
292300
.watcher
293-
.get_watcher_appointments_with_locator(locator)
301+
.get_watcher_appointments_with_locator(locator, user_id)
302+
.into_values()
303+
.map(|appointment| (appointment.user_id, appointment.inner))
304+
.collect();
305+
306+
307+
308+
let mut matching_appointments: Vec<common_msgs::AppointmentData> = appointments
294309
.into_iter()
295-
{
296-
matching_appointments.push(common_msgs::AppointmentData {
310+
.map(|(_, appointment)| common_msgs::AppointmentData {
297311
appointment_data: Some(
298-
common_msgs::appointment_data::AppointmentData::Appointment(
299-
appointment.inner.into(),
300-
),
312+
common_msgs::appointment_data::AppointmentData::Appointment(appointment.into()),
301313
),
302314
})
303-
}
315+
.collect();
304316

305317
for (_, tracker) in self
306318
.watcher
@@ -390,7 +402,6 @@ impl PrivateTowerServices for Arc<InternalAPI> {
390402
Some((info, locators)) => Ok(Response::new(msgs::GetUserResponse {
391403
available_slots: info.available_slots,
392404
subscription_expiry: info.subscription_expiry,
393-
// TODO: Should make `get_appointments` queryable using the (user_id, locator) pair for consistency.
394405
appointments: locators
395406
.into_iter()
396407
.map(|locator| locator.to_vec())
@@ -511,14 +522,18 @@ mod tests_private_api {
511522

512523
let locator = Locator::new(get_random_tx().txid()).to_vec();
513524
let response = internal_api
514-
.get_appointments(Request::new(msgs::GetAppointmentsRequest { locator }))
525+
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
526+
locator,
527+
user_id: None,
528+
}))
515529
.await
516530
.unwrap()
517531
.into_inner();
518532

519533
assert!(matches!(response, msgs::GetAppointmentsResponse { .. }));
520534
}
521535

536+
522537
#[tokio::test]
523538
async fn test_get_appointments_watcher() {
524539
let (internal_api, _s) = create_api().await;
@@ -548,6 +563,7 @@ mod tests_private_api {
548563
let response = internal_api
549564
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
550565
locator: locator.to_vec(),
566+
user_id: None,
551567
}))
552568
.await
553569
.unwrap()
@@ -599,6 +615,7 @@ mod tests_private_api {
599615
let response = internal_api
600616
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
601617
locator: locator.to_vec(),
618+
user_id: None,
602619
}))
603620
.await
604621
.unwrap()
@@ -747,7 +764,10 @@ mod tests_private_api {
747764

748765
assert_eq!(response.available_slots, SLOTS - 1);
749766
assert_eq!(response.subscription_expiry, START_HEIGHT as u32 + DURATION);
750-
assert_eq!(response.appointments, Vec::from([appointment.inner.locator.to_vec()]));
767+
assert_eq!(
768+
response.appointments,
769+
Vec::from([appointment.inner.locator.to_vec()])
770+
);
751771
}
752772

753773
#[tokio::test]

teos/src/cli.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,21 @@ async fn main() {
7575
println!("{}", pretty_json(&appointments.into_inner()).unwrap());
7676
}
7777
Command::GetAppointments(appointments_data) => {
78+
let mut user_id = None;
79+
if let Some(i) = &appointments_data.user_id {
80+
match UserId::from_str(i.as_str()) {
81+
Ok(parsed_user_id) => {
82+
user_id = Some(parsed_user_id.to_vec());
83+
}
84+
Err(err) => handle_error(err),
85+
}
86+
}
7887
match Locator::from_hex(&appointments_data.locator) {
7988
Ok(locator) => {
8089
match client
8190
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
8291
locator: locator.to_vec(),
92+
user_id,
8393
}))
8494
.await
8595
{

teos/src/cli_config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub struct GetUserData {
3131
pub struct GetAppointmentsData {
3232
/// The locator of the appointments (16-byte hexadecimal string).
3333
pub locator: String,
34+
/// The user identifier (33-byte compressed public key).
35+
pub user_id: Option<String>,
3436
}
3537

3638
/// Holds all the command line options and commands.

teos/src/dbm.rs

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ impl DBM {
331331
pub(crate) fn load_appointments(
332332
&self,
333333
locator: Option<Locator>,
334+
user_id: Option<UserId>,
334335
) -> HashMap<UUID, ExtendedAppointment> {
335336
let mut appointments = HashMap::new();
336337

@@ -339,12 +340,20 @@ impl DBM {
339340
FROM appointments as a LEFT JOIN trackers as t ON a.UUID=t.UUID WHERE t.UUID IS NULL".to_string();
340341
// If a locator was passed, filter based on it.
341342
if locator.is_some() {
342-
sql.push_str(" AND a.locator=(?)");
343+
sql.push_str(" AND a.locator=(?1)");
344+
if user_id.is_some() {
345+
sql.push_str(" AND a.user_id=(?2)");
346+
}
343347
}
344348
let mut stmt = self.connection.prepare(&sql).unwrap();
345349

346350
let mut rows = if let Some(locator) = locator {
347-
stmt.query([locator.to_vec()]).unwrap()
351+
if let Some(user_id) = user_id {
352+
stmt.query([locator.to_vec(), user_id.to_vec()]).unwrap()
353+
} else {
354+
stmt.query([locator.to_vec()]).unwrap()
355+
356+
}
348357
} else {
349358
stmt.query([]).unwrap()
350359
};
@@ -1106,7 +1115,7 @@ mod tests {
11061115
appointments.insert(uuid, appointment);
11071116
}
11081117

1109-
assert_eq!(dbm.load_appointments(None), appointments);
1118+
assert_eq!(dbm.load_appointments(None, None), appointments);
11101119

11111120
// If an appointment has an associated tracker, it should not be loaded since it is seen
11121121
// as a triggered appointment
@@ -1122,7 +1131,7 @@ mod tests {
11221131
dbm.store_tracker(uuid, &tracker).unwrap();
11231132

11241133
// We should get all the appointments back except from the triggered one
1125-
assert_eq!(dbm.load_appointments(None), appointments);
1134+
assert_eq!(dbm.load_appointments(None, None), appointments);
11261135
}
11271136

11281137
#[test]
@@ -1157,7 +1166,7 @@ mod tests {
11571166
}
11581167

11591168
// Validate that no other appointments than the ones with our locator are returned.
1160-
assert_eq!(dbm.load_appointments(Some(locator)), appointments);
1169+
assert_eq!(dbm.load_appointments(Some(locator), None), appointments);
11611170

11621171
// If an appointment has an associated tracker, it should not be loaded since it is seen
11631172
// as a triggered appointment
@@ -1175,7 +1184,49 @@ mod tests {
11751184
dbm.store_tracker(uuid, &tracker).unwrap();
11761185

11771186
// We should get all the appointments matching our locator back except from the triggered one
1178-
assert_eq!(dbm.load_appointments(Some(locator)), appointments);
1187+
assert_eq!(dbm.load_appointments(Some(locator), None), appointments);
1188+
}
1189+
1190+
#[test]
1191+
fn test_load_appointments_with_locator_and_user_id() {
1192+
let dbm = DBM::in_memory().unwrap();
1193+
1194+
// create two appointment maps for two userId
1195+
let mut user_id1_appointments = HashMap::new();
1196+
let mut user_id2_appointments = HashMap::new();
1197+
1198+
let dispute_tx = get_random_tx();
1199+
let dispute_txid = dispute_tx.txid();
1200+
let locator = Locator::new(dispute_txid);
1201+
1202+
// generate two user ids
1203+
let user_id1 = get_random_user_id();
1204+
let user_id2 = get_random_user_id();
1205+
1206+
let user = UserInfo::new(
1207+
AVAILABLE_SLOTS,
1208+
SUBSCRIPTION_START,
1209+
SUBSCRIPTION_EXPIRY,
1210+
);
1211+
dbm.store_user(user_id1, &user).unwrap();
1212+
dbm.store_user(user_id2, &user).unwrap();
1213+
1214+
let (uuid, appointment) = generate_dummy_appointment_with_user(user_id1, Some(&dispute_txid));
1215+
dbm.store_appointment(uuid, &appointment).unwrap();
1216+
// Store the appointment for the first user_id made using our dispute tx.
1217+
user_id1_appointments.insert(uuid, appointment);
1218+
1219+
let (uuid, appointment) = generate_dummy_appointment_with_user(user_id2, Some(&dispute_txid));
1220+
dbm.store_appointment(uuid, &appointment).unwrap();
1221+
// Store the appointment for the second user_id made using our dispute tx.
1222+
user_id2_appointments.insert(uuid, appointment);
1223+
1224+
// Validate that the first user_id appointment map matches the fetched appointments.
1225+
assert_eq!(dbm.load_appointments(Some(locator), Some(user_id1)), user_id1_appointments);
1226+
1227+
// Validate that the second user_id appointment map matches the fetched appointments.
1228+
assert_eq!(dbm.load_appointments(Some(locator), Some(user_id2)), user_id2_appointments);
1229+
11791230
}
11801231

11811232
#[test]
@@ -1259,7 +1310,7 @@ mod tests {
12591310
i as usize
12601311
);
12611312
// Check appointment data was deleted and users properly updated
1262-
assert_eq!(rest, dbm.load_appointments(None).keys().cloned().collect());
1313+
assert_eq!(rest, dbm.load_appointments(None, None).keys().cloned().collect());
12631314
assert_eq!(
12641315
dbm.load_user(user_id).unwrap().available_slots,
12651316
user.available_slots

teos/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ async fn main() {
182182
);
183183
let mut derefed = bitcoin_cli.deref();
184184
// Load last known block from DB if found. Poll it from Bitcoind otherwise.
185-
let last_known_block = dbm.lock().unwrap().load_last_known_block();
185+
let last_known_block = None;
186186
let tip = if let Some(block_hash) = last_known_block {
187187
let mut last_known_header = derefed
188188
.get_header(&block_hash, None)

teos/src/watcher.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,15 +420,16 @@ impl Watcher {
420420

421421
/// Gets all the appointments stored in the [Watcher] (from the database).
422422
pub(crate) fn get_all_watcher_appointments(&self) -> HashMap<UUID, ExtendedAppointment> {
423-
self.dbm.lock().unwrap().load_appointments(None)
423+
self.dbm.lock().unwrap().load_appointments(None, None)
424424
}
425425

426426
/// Gets all the appointments matching a specific locator from the [Watcher] (from the database).
427427
pub(crate) fn get_watcher_appointments_with_locator(
428428
&self,
429429
locator: Locator,
430+
user_id: Option<UserId>,
430431
) -> HashMap<UUID, ExtendedAppointment> {
431-
self.dbm.lock().unwrap().load_appointments(Some(locator))
432+
self.dbm.lock().unwrap().load_appointments(Some(locator), user_id)
432433
}
433434

434435
/// Gets all the trackers stored in the [Responder] (from the database).

0 commit comments

Comments
 (0)