Skip to content

Commit bc00072

Browse files
committed
add on_commitment_revocation
Signed-off-by: dzdidi <[email protected]>
1 parent 3db10b8 commit bc00072

File tree

3 files changed

+151
-9
lines changed

3 files changed

+151
-9
lines changed

teos-ldk-client/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ The client instance has the following methods:
1616
- `get_subscription_info <tower_id>`: gets the subscription information by querying the tower.
1717
- `get_appointment_receipt <tower_id> <locator>`: pulls a given appointment receipt from the local database.
1818
- `get_registration_receipt <tower_id>`: pulls the latest registration receipt from the local database.
19-
- `on_commitment_revocation <tx>`: sends appointments to the registered towers for every new commitment transaction.
19+
20+
The general usage idea
21+
- `on_commitment_revocation <wt_client, tx>`: sends appointments to the registered towers for every new commitment transaction.
2022

2123
# Configuration
2224

teos-ldk-client/src/lib.rs

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
use std::collections::{HashMap, HashSet};
22
use std::fmt;
3+
use std::sync::MutexGuard;
4+
use std::sync::{Arc, Mutex};
35

46
use serde::{Deserialize, Serialize};
57

68
use teos_common::appointment::{Appointment, Locator};
79
use teos_common::net::NetAddr;
810
use teos_common::receipts::AppointmentReceipt;
911
use teos_common::TowerId;
12+
use teos_common::{cryptography, errors};
13+
14+
use crate::convert::CommitmentRevocation;
15+
use crate::http::AddAppointmentError;
16+
use crate::net::http;
17+
use crate::wt_client::{RevocationData, WTClient};
1018

1119
pub mod convert;
1220
pub mod net;
@@ -280,6 +288,143 @@ impl MisbehaviorProof {
280288
}
281289
}
282290

291+
/// Sends an appointment to all registered towers for every new commitment transaction.
292+
///
293+
/// The appointment is built using the data provided by the backend (dispute txid and penalty transaction).
294+
pub async fn on_commitment_revocation(
295+
wt_client: Arc<Mutex<WTClient>>,
296+
commitment_revocation: CommitmentRevocation,
297+
) -> Result<(), Box<dyn std::error::Error>> {
298+
log::debug!(
299+
"New commitment revocation received for channel {}. Commit number {}",
300+
commitment_revocation.channel_id,
301+
commitment_revocation.commit_num
302+
);
303+
304+
// TODO: For now, to_self_delay is hardcoded to 42. Revisit and define it better / remove it when / if needed
305+
let locator = Locator::new(commitment_revocation.commitment_txid);
306+
let appointment = Appointment::new(
307+
locator,
308+
cryptography::encrypt(
309+
&commitment_revocation.penalty_tx,
310+
&commitment_revocation.commitment_txid,
311+
)
312+
.unwrap(),
313+
42,
314+
);
315+
let signature =
316+
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk).unwrap();
317+
318+
// Looks like we cannot iterate through towers given a locked state is not Send (due to the async call),
319+
// so we need to clone the bare minimum.
320+
let towers = wt_client
321+
.lock()
322+
.unwrap()
323+
.towers
324+
.iter()
325+
.map(|(id, info)| (*id, info.net_addr.clone(), info.status))
326+
.collect::<Vec<_>>();
327+
328+
for (tower_id, net_addr, status) in towers {
329+
if status.is_reachable() {
330+
match http::add_appointment(tower_id, &net_addr, &appointment, &signature).await {
331+
Ok((slots, receipt)) => {
332+
wt_client
333+
.lock()
334+
.unwrap()
335+
.add_appointment_receipt(tower_id, locator, slots, &receipt);
336+
log::debug!("Response verified and data stored in the database");
337+
}
338+
Err(e) => match e {
339+
AddAppointmentError::RequestError(e) => {
340+
if e.is_connection() {
341+
log::warn!(
342+
"{tower_id} cannot be reached. Adding {} to pending appointments",
343+
appointment.locator
344+
);
345+
let mut state = wt_client.lock().unwrap();
346+
state.set_tower_status(tower_id, TowerStatus::TemporaryUnreachable);
347+
state.add_pending_appointment(tower_id, &appointment);
348+
send_to_retrier(&state, tower_id, appointment.locator);
349+
}
350+
}
351+
AddAppointmentError::ApiError(e) => match e.error_code {
352+
errors::INVALID_SIGNATURE_OR_SUBSCRIPTION_ERROR => {
353+
log::warn!(
354+
"There is a subscription issue with {tower_id}. Adding {} to pending",
355+
appointment.locator
356+
);
357+
let mut state = wt_client.lock().unwrap();
358+
state.set_tower_status(tower_id, TowerStatus::SubscriptionError);
359+
state.add_pending_appointment(tower_id, &appointment);
360+
send_to_retrier(&state, tower_id, appointment.locator);
361+
}
362+
363+
_ => {
364+
log::warn!(
365+
"{tower_id} rejected the appointment. Error: {}, error_code: {}",
366+
e.error,
367+
e.error_code
368+
);
369+
wt_client
370+
.lock()
371+
.unwrap()
372+
.add_invalid_appointment(tower_id, &appointment);
373+
}
374+
},
375+
AddAppointmentError::SignatureError(proof) => {
376+
log::warn!("Cannot recover known tower_id from the appointment receipt. Flagging tower as misbehaving");
377+
wt_client
378+
.lock()
379+
.unwrap()
380+
.flag_misbehaving_tower(tower_id, proof)
381+
}
382+
},
383+
};
384+
} else if status.is_misbehaving() {
385+
log::warn!("{tower_id} is misbehaving. Not sending any further appointments",);
386+
} else {
387+
if status.is_subscription_error() {
388+
log::warn!(
389+
"There is a subscription issue with {tower_id}. Adding {} to pending",
390+
appointment.locator
391+
);
392+
} else {
393+
log::warn!(
394+
"{tower_id} is {status}. Adding {} to pending",
395+
appointment.locator,
396+
);
397+
}
398+
399+
let mut state = wt_client.lock().unwrap();
400+
state.add_pending_appointment(tower_id, &appointment);
401+
402+
if !status.is_unreachable() {
403+
send_to_retrier(&state, tower_id, appointment.locator);
404+
}
405+
}
406+
}
407+
408+
Ok(())
409+
}
410+
411+
/// Sends fresh data to a retrier as long as is does not exist, or it does and its running.
412+
fn send_to_retrier(state: &MutexGuard<WTClient>, tower_id: TowerId, locator: Locator) {
413+
if if let Some(status) = state.get_retrier_status(&tower_id) {
414+
// A retrier in the retriers map can only be running or idle
415+
status.is_running()
416+
} else {
417+
true
418+
} {
419+
state
420+
.unreachable_towers
421+
.send((tower_id, RevocationData::Fresh(locator)))
422+
.unwrap();
423+
} else {
424+
log::debug!("Not sending data to idle retrier ({tower_id}, {locator})")
425+
}
426+
}
427+
283428
#[cfg(test)]
284429
mod tests {
285430
use super::*;

teos-ldk-client/src/storage/encryption.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,12 @@ pub(crate) fn encrypt(
1616
message: &[u8],
1717
secret: &[u8],
1818
) -> Result<Vec<u8>, chacha20poly1305::aead::Error> {
19-
// Create nonce [0; 12]
2019
let nonce = Nonce::default();
21-
22-
// Hash the secret to create the encryption key
2320
let key_hash = sha256::Hash::hash(secret);
2421
let key = Key::from_slice(key_hash.as_byte_array());
2522

26-
// Create cipher instance
2723
let cipher = ChaCha20Poly1305::new(key);
28-
// Encrypt the message
24+
2925
cipher.encrypt(&nonce, message)
3026
}
3127

@@ -40,10 +36,9 @@ pub(crate) fn decrypt(
4036
encrypted_blob: &[u8],
4137
secret: &[u8],
4238
) -> Result<Vec<u8>, chacha20poly1305::aead::Error> {
43-
// Defaults is [0; 12]
4439
let nonce = Nonce::default();
45-
let k = sha256::Hash::hash(secret);
46-
let key = Key::from_slice(k.as_byte_array());
40+
let key_hash = sha256::Hash::hash(secret);
41+
let key = Key::from_slice(key_hash.as_byte_array());
4742

4843
let cypher = ChaCha20Poly1305::new(key);
4944

0 commit comments

Comments
 (0)