Skip to content

Commit fef946c

Browse files
author
Antoine Riard
committed
Add checks that amt_to_forward and outgoing_cltv_value are within
acceptable ranges add log_route macro
1 parent 0f24a67 commit fef946c

File tree

3 files changed

+42
-15
lines changed

3 files changed

+42
-15
lines changed

src/ln/channelmanager.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,7 +1625,18 @@ impl ChannelMessageHandler for ChannelManager {
16251625
hmac: next_hop_data.hmac.clone(),
16261626
};
16271627

1628-
//TODO: Check amt_to_forward and outgoing_cltv_value are within acceptable ranges!
1628+
let channel_state = self.channel_state.lock().unwrap();
1629+
let chan = channel_state.by_id.get(&msg.channel_id).unwrap();
1630+
let fee = chan.get_our_fee_base_msat(&*self.fee_estimator) + (next_hop_data.data.amt_to_forward * self.fee_proportional_millionths as u64 / 1000000) as u32;
1631+
if (msg.amount_msat - fee as u64) < next_hop_data.data.amt_to_forward {
1632+
log_debug!(self, "HTLC {} incorrect amount: in {} out {} fee required {}", msg.htlc_id, msg.amount_msat, next_hop_data.data.amt_to_forward, fee);
1633+
//TODO: give back a "channel_update" in failure onion packet ?
1634+
return_err!("Prior hop has deviated from specified parameters", 0x1000 | 12, &[0;0]);
1635+
}
1636+
if (msg.cltv_expiry - CLTV_EXPIRY_DELTA as u32) < next_hop_data.data.outgoing_cltv_value {
1637+
log_debug!(self, "HTLC {} incorrect CLTV: in {} out {} delta required {}", msg.htlc_id, msg.cltv_expiry, next_hop_data.data.outgoing_cltv_value, CLTV_EXPIRY_DELTA);
1638+
return_err!("Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta", 0x1000 | 13, &[0;0]);
1639+
}
16291640

16301641
PendingForwardHTLCInfo {
16311642
onion_packet: Some(outgoing_packet),
@@ -2595,7 +2606,6 @@ mod tests {
25952606
for (node, hop) in expected_route.iter().zip(route.hops.iter()) {
25962607
assert_eq!(hop.pubkey, node.node.get_our_node_id());
25972608
}
2598-
25992609
send_along_route(origin_node, route, expected_route, recv_value)
26002610
}
26012611

@@ -2804,15 +2814,15 @@ mod tests {
28042814
pubkey: nodes[2].node.get_our_node_id(),
28052815
short_channel_id: chan_3.0.contents.short_channel_id,
28062816
fee_msat: 0,
2807-
cltv_expiry_delta: chan_2.1.contents.cltv_expiry_delta as u32
2817+
cltv_expiry_delta: chan_2.0.contents.cltv_expiry_delta as u32
28082818
});
28092819
hops.push(RouteHop {
28102820
pubkey: nodes[1].node.get_our_node_id(),
28112821
short_channel_id: chan_2.0.contents.short_channel_id,
28122822
fee_msat: 1000000,
28132823
cltv_expiry_delta: TEST_FINAL_CLTV,
28142824
});
2815-
hops[1].fee_msat = chan_2.1.contents.fee_base_msat as u64 + chan_2.1.contents.fee_proportional_millionths as u64 * hops[2].fee_msat as u64 / 1000000;
2825+
hops[1].fee_msat = chan_2.0.contents.fee_base_msat as u64 + chan_2.0.contents.fee_proportional_millionths as u64 * hops[2].fee_msat as u64 / 1000000;
28162826
hops[0].fee_msat = chan_3.1.contents.fee_base_msat as u64 + chan_3.1.contents.fee_proportional_millionths as u64 * hops[1].fee_msat as u64 / 1000000;
28172827
let payment_hash_2 = send_along_route(&nodes[1], Route { hops }, &vec!(&nodes[3], &nodes[2], &nodes[1])[..], 1000000).1;
28182828

src/ln/router.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -258,29 +258,29 @@ impl RoutingMessageHandler for Router {
258258
None => return Err(HandleError{err: "Couldn't find channel for update", action: Some(ErrorAction::IgnoreError)}),
259259
Some(channel) => {
260260
macro_rules! maybe_update_channel_info {
261-
( $target: expr) => {
262-
if $target.last_update >= msg.contents.timestamp {
261+
( $first_side: expr, $other_side: expr) => {
262+
if $first_side.last_update >= msg.contents.timestamp {
263263
return Err(HandleError{err: "Update older than last processed update", action: Some(ErrorAction::IgnoreError)});
264264
}
265-
chan_was_enabled = $target.enabled;
266-
$target.last_update = msg.contents.timestamp;
267-
$target.enabled = chan_enabled;
268-
$target.cltv_expiry_delta = msg.contents.cltv_expiry_delta;
269-
$target.htlc_minimum_msat = msg.contents.htlc_minimum_msat;
270-
$target.fee_base_msat = msg.contents.fee_base_msat;
271-
$target.fee_proportional_millionths = msg.contents.fee_proportional_millionths;
265+
chan_was_enabled = $first_side.enabled;
266+
$first_side.last_update = msg.contents.timestamp;
267+
$first_side.enabled = chan_enabled;
268+
$other_side.cltv_expiry_delta = msg.contents.cltv_expiry_delta;
269+
$other_side.htlc_minimum_msat = msg.contents.htlc_minimum_msat;
270+
$other_side.fee_base_msat = msg.contents.fee_base_msat;
271+
$other_side.fee_proportional_millionths = msg.contents.fee_proportional_millionths;
272272
}
273273
}
274274

275275
let msg_hash = Message::from_slice(&Sha256dHash::from_data(&msg.contents.encode()[..])[..]).unwrap();
276276
if msg.contents.flags & 1 == 1 {
277277
dest_node_id = channel.one_to_two.src_node_id.clone();
278278
secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.signature, &channel.two_to_one.src_node_id);
279-
maybe_update_channel_info!(channel.two_to_one);
279+
maybe_update_channel_info!(channel.two_to_one, channel.one_to_two);
280280
} else {
281281
dest_node_id = channel.two_to_one.src_node_id.clone();
282282
secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.signature, &channel.one_to_two.src_node_id);
283-
maybe_update_channel_info!(channel.one_to_two);
283+
maybe_update_channel_info!(channel.one_to_two, channel.two_to_one);
284284
}
285285
}
286286
}

src/util/macro_logger.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use chain::transaction::OutPoint;
33
use bitcoin::util::hash::Sha256dHash;
44
use secp256k1::key::PublicKey;
55

6+
use ln::router::Route;
7+
68
use std;
79

810
pub(crate) struct DebugPubKey<'a>(pub &'a PublicKey);
@@ -50,6 +52,21 @@ macro_rules! log_funding_channel_id {
5052
}
5153
}
5254

55+
pub(crate) struct DebugRoute<'a>(pub &'a Route);
56+
impl<'a> std::fmt::Display for DebugRoute<'a> {
57+
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
58+
for (i,h) in self.0.hops.iter().enumerate() {
59+
write!(f, "Hop {}\n pubkey {}\n short_channel_id {}\n fee_msat {}\n cltv_expiry_delta {}\n\n", i, log_pubkey!(h.pubkey), h.short_channel_id, h.fee_msat, h.cltv_expiry_delta)?;
60+
}
61+
Ok(())
62+
}
63+
}
64+
macro_rules! log_route {
65+
($obj: expr) => {
66+
::util::macro_logger::DebugRoute(&$obj)
67+
}
68+
}
69+
5370
macro_rules! log_internal {
5471
($self: ident, $lvl:expr, $($arg:tt)+) => (
5572
&$self.logger.log(&Record::new($lvl, format_args!($($arg)+), module_path!(), file!(), line!()));

0 commit comments

Comments
 (0)