Skip to content

Commit 5247e8c

Browse files
committed
lsp_plugin: add hook helper to the client
We nearly always want to return `{"result":"continue"}` in case that something went wrong. This commits adds two helper macros that help us to cleanly return from a hook while logging necessary information. Signed-off-by: Peter Neuroth <[email protected]>
1 parent 055a2e7 commit 5247e8c

File tree

1 file changed

+100
-50
lines changed

1 file changed

+100
-50
lines changed

plugins/lsps-plugin/src/client.rs

Lines changed: 100 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -496,21 +496,27 @@ async fn on_invoice_payment(
496496
p: cln_plugin::Plugin<State>,
497497
v: serde_json::Value,
498498
) -> Result<serde_json::Value, anyhow::Error> {
499-
let req: InvoicePaymentRequest = serde_json::from_value(v).context("invalid hook request")?;
500-
let preimage = <[u8; 32]>::from_hex(&req.payment.preimage).context("invalid preimage hex")?;
499+
let req: InvoicePaymentRequest = ok_or_continue!(
500+
serde_json::from_value(v).context("failed to deserialize htlc_accepted request JSON")
501+
);
502+
let preimage = ok_or_continue!(
503+
<[u8; 32]>::from_hex(&req.payment.preimage).context("invalid preimage hex")
504+
);
501505
let hash = payment_hash(&preimage);
502506

503507
// Delete DS-entries.
504508
let dir = p.configuration().lightning_dir;
505509
let rpc_path = Path::new(&dir).join(&p.configuration().rpc_file);
506-
let mut cln_client = cln_rpc::ClnRpc::new(rpc_path.clone()).await?;
507-
cln_client
510+
let mut cln_client = ok_or_continue!(cln_rpc::ClnRpc::new(rpc_path.clone())
511+
.await
512+
.context("failed to connect to core-lightning"));
513+
ok_or_continue!(cln_client
508514
.call_typed(&DeldatastoreRequest {
509515
key: vec!["lsps".to_string(), "invoice".to_string(), hash.to_string()],
510516
generation: None,
511517
})
512518
.await
513-
.ok();
519+
.context("failed to delete datastore record"));
514520

515521
Ok(serde_json::json!({"result": "continue"}))
516522
}
@@ -519,23 +525,20 @@ async fn on_htlc_accepted(
519525
p: cln_plugin::Plugin<State>,
520526
v: serde_json::Value,
521527
) -> Result<serde_json::Value, anyhow::Error> {
522-
let req: HtlcAcceptedRequest = serde_json::from_value(v)?;
528+
let req: HtlcAcceptedRequest = ok_or_continue!(
529+
serde_json::from_value(v).context("failed to deserialize htlc_accepted request JSON")
530+
);
523531

524532
let htlc_amt = req.htlc.amount_msat;
525-
let onion_amt = match req.onion.forward_msat {
526-
Some(a) => a,
527-
None => {
528-
debug!("onion is missing forward_msat, continue");
529-
let value = serde_json::to_value(HtlcAcceptedResponse::continue_(None, None, None))?;
530-
return Ok(value);
531-
}
532-
};
533+
let onion_amt = some_or_continue!(
534+
req.onion.forward_msat,
535+
"missing forward_msat in onion, continue"
536+
);
533537

534-
let Some(payment_data) = req.onion.payload.get(TLV_PAYMENT_SECRET) else {
535-
debug!("payment is a forward, continue");
536-
let value = serde_json::to_value(HtlcAcceptedResponse::continue_(None, None, None))?;
537-
return Ok(value);
538-
};
538+
let payment_data = some_or_continue!(
539+
req.onion.payload.get(TLV_PAYMENT_SECRET),
540+
"htlc is a forward, continue"
541+
);
539542

540543
let extra_fee_msat = req
541544
.htlc
@@ -551,31 +554,31 @@ async fn on_htlc_accepted(
551554
// Check that the htlc belongs to a jit-channel request.
552555
let dir = p.configuration().lightning_dir;
553556
let rpc_path = Path::new(&dir).join(&p.configuration().rpc_file);
554-
let mut cln_client = cln_rpc::ClnRpc::new(rpc_path.clone()).await?;
555-
let lsp_data = cln_client
557+
let mut cln_client = ok_or_continue!(cln_rpc::ClnRpc::new(rpc_path.clone())
558+
.await
559+
.context("failed to connect to core-lightning"));
560+
561+
let lsp_data = ok_or_continue!(cln_client
556562
.call_typed(&ListdatastoreRequest {
557563
key: Some(vec![
558564
"lsps".to_string(),
559565
"invoice".to_string(),
560566
hex::encode(&req.htlc.payment_hash),
561567
]),
562568
})
563-
.await?;
569+
.await
570+
.context("failed to fetch datastore record"));
564571

565-
if lsp_data.datastore.first().is_none() {
566-
// Not an LSP payment, just continue
567-
debug!("payment is a not a jit-channel-opening, continue");
568-
let value = serde_json::to_value(HtlcAcceptedResponse::continue_(None, None, None))?;
569-
return Ok(value);
570-
};
572+
// If we don't know about this payment it's not an LSP payment, continue.
573+
some_or_continue!(lsp_data.datastore.first());
571574

572575
debug!(
573576
"incoming jit-channel htlc with htlc_amt={} and onion_amt={}",
574577
htlc_amt.msat(),
575578
onion_amt.msat()
576579
);
577580

578-
let inv_res = cln_client
581+
let inv_res = ok_or_continue!(cln_client
579582
.call_typed(&ListinvoicesRequest {
580583
index: None,
581584
invstring: None,
@@ -585,16 +588,14 @@ async fn on_htlc_accepted(
585588
payment_hash: Some(hex::encode(&req.htlc.payment_hash)),
586589
start: None,
587590
})
588-
.await?;
591+
.await
592+
.context("failed to get invoice"));
589593

590-
let Some(invoice) = inv_res.invoices.first() else {
591-
debug!(
592-
"no invoice found for jit-channel opening with payment_hash={}",
593-
hex::encode(&req.htlc.payment_hash)
594-
);
595-
let value = serde_json::to_value(HtlcAcceptedResponse::continue_(None, None, None))?;
596-
return Ok(value);
597-
};
594+
let invoice = some_or_continue!(
595+
inv_res.invoices.first(),
596+
"no invoice found for jit-channel-opening with payment_hash={}",
597+
hex::encode(&req.htlc.payment_hash)
598+
);
598599

599600
let total_amt = match invoice.amount_msat {
600601
Some(a) => {
@@ -620,14 +621,9 @@ async fn on_htlc_accepted(
620621
ps.extend_from_slice(&payment_data[0..32]);
621622
ps.extend(encode_tu64(total_amt));
622623
payload.insert(TLV_PAYMENT_SECRET, ps);
623-
let payload_bytes = match payload.to_bytes() {
624-
Ok(b) => b,
625-
Err(e) => {
626-
warn!("can't encode payload to bytes {}", e);
627-
let value = serde_json::to_value(HtlcAcceptedResponse::continue_(None, None, None))?;
628-
return Ok(value);
629-
}
630-
};
624+
let payload_bytes = ok_or_continue!(payload
625+
.to_bytes()
626+
.context("failed to encode payload as bytes"));
631627

632628
info!(
633629
"Amended onion payload with forward_amt={} and total_msat={}",
@@ -652,11 +648,16 @@ async fn on_openchannel(
652648
id: String,
653649
}
654650

655-
let req: Request = serde_json::from_value(v.get("openchannel").unwrap().clone())
656-
.context("Failed to parse request JSON")?;
651+
let req: Request = ok_or_continue!(serde_json::from_value(
652+
v.get("openchannel").unwrap().clone()
653+
)
654+
.context("failed to deserialize open_channel request JSON"));
655+
657656
let dir = p.configuration().lightning_dir;
658657
let rpc_path = Path::new(&dir).join(&p.configuration().rpc_file);
659-
let mut cln_client = cln_rpc::ClnRpc::new(rpc_path.clone()).await?;
658+
let mut cln_client = ok_or_continue!(cln_rpc::ClnRpc::new(rpc_path.clone())
659+
.await
660+
.context("failed to connect to core-lightning"));
660661

661662
let ds_req = ListdatastoreRequest {
662663
key: Some(vec![
@@ -665,7 +666,11 @@ async fn on_openchannel(
665666
req.id.clone(),
666667
]),
667668
};
668-
let ds_res = cln_client.call_typed(&ds_req).await?;
669+
let ds_res = ok_or_continue!(cln_client
670+
.call_typed(&ds_req)
671+
.await
672+
.context("failed to get datastore record"));
673+
669674
if let Some(_rec) = ds_res.datastore.iter().next() {
670675
info!("Allowing zero-conf channel from LSP {}", &req.id);
671676
let ds_req = DeldatastoreRequest {
@@ -791,6 +796,51 @@ pub fn payment_hash(preimage: &[u8]) -> sha256::Hash {
791796
sha256::Hash::hash(preimage)
792797
}
793798

799+
fn continue_ok() -> Result<serde_json::Value, anyhow::Error> {
800+
Ok(serde_json::json!({"result": "continue"}))
801+
}
802+
803+
#[macro_export]
804+
macro_rules! some_or_continue {
805+
($expr:expr) => {
806+
match $expr {
807+
Some(v) => v,
808+
None => return continue_ok(),
809+
}
810+
};
811+
($expr:expr, $($log:tt)+) => {
812+
match $expr {
813+
Some(v) => v,
814+
None => {
815+
debug!($($log)+);
816+
return continue_ok();
817+
},
818+
}
819+
};
820+
}
821+
822+
#[macro_export]
823+
macro_rules! ok_or_continue {
824+
($expr:expr) => {
825+
match $expr {
826+
Ok(v) => v,
827+
Err(e) => {
828+
debug!("{:#}", e);
829+
return continue_ok();
830+
}
831+
}
832+
};
833+
($expr:expr, $($log:tt)+) => {
834+
match $expr {
835+
Ok(v) => v,
836+
Err(e) => {
837+
debug!("{}: {:#}",format_args!($($log)+), e);
838+
return continue_ok();
839+
}
840+
}
841+
};
842+
}
843+
794844
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
795845
struct LspsBuyJitChannelResponse {
796846
bolt11: String,

0 commit comments

Comments
 (0)