Skip to content

Commit

Permalink
plugin: Add macro to shortcut the hook flow
Browse files Browse the repository at this point in the history
Adds a macro that allows us to replace `unwrap`s in order to prevent
panics. The macro shortcuts further execution and returns from the
htlc_accepted_hook.

Signed-off-by: Peter Neuroth <[email protected]>
  • Loading branch information
nepet committed Nov 25, 2024
1 parent 09fc51f commit 9b66b16
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 32 deletions.
66 changes: 36 additions & 30 deletions libs/gl-plugin/src/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,27 +54,35 @@ struct HtlcAcceptedResponse {
const TLV_FORWARD_AMT: u64 = 2;
const TLV_PAYMENT_SECRET: u64 = 8;

/// A macro to break out of the current hook flow and return a `continue`
/// signal to core-lightning. This is to be used when we don't know how to
/// handle a given payload or as a shortcut in case we could identify that the
/// incoming htlc is not part of a LSP jit channel opening.
macro_rules! unwrap_or_continue {
($res:expr) => {
match $res {
Ok(x) => x,
Err(e) => {
log::debug!("Lsp-plugin continue, reason: {}", e.to_string());
return Ok(serde_json::to_value(HtlcAcceptedResponse {
result: "continue".to_string(),
..Default::default()
})
.expect("Could not serialize json value"));
}
}
};
}

pub async fn on_htlc_accepted(plugin: Plugin, v: Value) -> Result<Value, anyhow::Error> {
let req: HtlcAcceptedRequest = serde_json::from_value(v).unwrap();
let req: HtlcAcceptedRequest = unwrap_or_continue!(serde_json::from_value(v));
log::debug!("Decoded {:?}", &req);

let htlc_amt = req.htlc.amount_msat;
let onion_amt = match req.onion.forward_msat {
Some(a) => a,
None => {
// An onion payload without an `amt_to_forward` is unorthodox and
// can not be processed by this plugin. Skip it.
log::debug!(
"lsp-plugin: got an onion payload={} without an amt forward_msat.",
req.onion.payload
);
return Ok(serde_json::to_value(HtlcAcceptedResponse {
result: "continue".to_string(),
..Default::default()
})
.unwrap());
}
};
let onion_amt = unwrap_or_continue!(req.onion.forward_msat.ok_or(format!(
"payload={} is missing forward_msat",
&req.onion.payload
)));

let res = if htlc_amt.msat() < onion_amt.msat() {
log::info!(
Expand All @@ -85,7 +93,10 @@ pub async fn on_htlc_accepted(plugin: Plugin, v: Value) -> Result<Value, anyhow:

let mut payload = req.onion.payload.clone();
payload.set_tu64(TLV_FORWARD_AMT, htlc_amt.msat());
let payment_secret = payload.get(TLV_PAYMENT_SECRET).unwrap();
let payment_secret = unwrap_or_continue!(payload.get(TLV_PAYMENT_SECRET).ok_or(format!(
"payload={} is missing payment_secret",
&payload.to_string()
)));

let mut rpc = cln_rpc::ClnRpc::new(plugin.configuration().rpc_file).await?;
let res: cln_rpc::model::responses::ListinvoicesResponse = rpc
Expand All @@ -99,19 +110,14 @@ pub async fn on_htlc_accepted(plugin: Plugin, v: Value) -> Result<Value, anyhow:
limit: None,
})
.await?;
if res.invoices.len() != 1 {
log::warn!(
"No invoice matching incoming HTLC payment_hash={} found, continuing",
hex::encode(&req.htlc.payment_hash)
);
return Ok(serde_json::to_value(HtlcAcceptedResponse {
result: "continue".to_string(),
..Default::default()
})
.unwrap());
}

let total_msat = res.invoices.iter().next().unwrap().amount_msat.unwrap();
let invoice = unwrap_or_continue!(res.invoices.first().ok_or(format!(
"no invoice matching incoming HTLC payment_hash={} found",
hex::encode(&req.htlc.payment_hash),
)));
let total_msat = unwrap_or_continue!(invoice
.amount_msat
.ok_or("invoice has no total amount msat"));

let mut ps = bytes::BytesMut::new();
ps.put(&payment_secret.value[0..32]);
Expand Down
4 changes: 2 additions & 2 deletions libs/gl-testing/tests/test_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ def test_lsp_jit_fee(clients, node_factory, bitcoind):
We test multiple parts and overpay slightly to verify that even
that works out ok.
We also check that we can handle unorthodox onion payloads that
We also check that we can handle unorthodox onion payloads that
don't carry fields that we expect.
"""
Expand Down Expand Up @@ -384,7 +384,7 @@ def test_lsp_jit_fee(clients, node_factory, bitcoind):

# The htlc should be passed on to the next consumer.
c.find_node().process.wait_for_log(
r"lsp-plugin: got an onion payload=.* without an amt forward_msat.",
r"Lsp-plugin continue, reason: payload=.* is missing forward_msat",
timeout=10,
)

Expand Down

0 comments on commit 9b66b16

Please sign in to comment.