Skip to content

Commit d6b1825

Browse files
authored
Merge pull request #513 from ariard/2020-02-fix-zero-msat-htlc
BOLT2: Check we don't send and accept 0-msat HTLC
2 parents d27e9e1 + dd9c476 commit d6b1825

File tree

4 files changed

+84
-8
lines changed

4 files changed

+84
-8
lines changed

lightning/src/ln/channel.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -433,10 +433,6 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
433433
cmp::max(at_open_background_feerate * B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT / 1000, 546) //TODO
434434
}
435435

436-
fn derive_our_htlc_minimum_msat(_at_open_channel_feerate_per_kw: u64) -> u64 {
437-
1000 // TODO
438-
}
439-
440436
// Constructors:
441437
pub fn new_outbound<K: Deref, F: Deref>(fee_estimator: &F, keys_provider: &K, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_id: u64, logger: Arc<Logger>, config: &UserConfig) -> Result<Channel<ChanSigner>, APIError>
442438
where K::Target: KeysInterface<ChanKeySigner = ChanSigner>,
@@ -519,7 +515,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
519515
their_max_htlc_value_in_flight_msat: 0,
520516
their_channel_reserve_satoshis: 0,
521517
their_htlc_minimum_msat: 0,
522-
our_htlc_minimum_msat: Channel::<ChanSigner>::derive_our_htlc_minimum_msat(feerate),
518+
our_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat },
523519
their_to_self_delay: 0,
524520
our_to_self_delay: config.own_channel_config.our_to_self_delay,
525521
their_max_accepted_htlcs: 0,
@@ -744,7 +740,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
744740
their_max_htlc_value_in_flight_msat: cmp::min(msg.max_htlc_value_in_flight_msat, msg.funding_satoshis * 1000),
745741
their_channel_reserve_satoshis: msg.channel_reserve_satoshis,
746742
their_htlc_minimum_msat: msg.htlc_minimum_msat,
747-
our_htlc_minimum_msat: Channel::<ChanSigner>::derive_our_htlc_minimum_msat(msg.feerate_per_kw as u64),
743+
our_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat },
748744
their_to_self_delay: msg.to_self_delay,
749745
our_to_self_delay: config.own_channel_config.our_to_self_delay,
750746
their_max_accepted_htlcs: msg.max_accepted_htlcs,
@@ -1656,6 +1652,9 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
16561652
if msg.amount_msat > self.channel_value_satoshis * 1000 {
16571653
return Err(ChannelError::Close("Remote side tried to send more than the total value of the channel"));
16581654
}
1655+
if msg.amount_msat == 0 {
1656+
return Err(ChannelError::Close("Remote side tried to send a 0-msat HTLC"));
1657+
}
16591658
if msg.amount_msat < self.our_htlc_minimum_msat {
16601659
return Err(ChannelError::Close("Remote side tried to send less than our minimum HTLC value"));
16611660
}
@@ -3493,6 +3492,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
34933492
if amount_msat > self.channel_value_satoshis * 1000 {
34943493
return Err(ChannelError::Ignore("Cannot send more than the total value of the channel"));
34953494
}
3495+
3496+
if amount_msat == 0 {
3497+
return Err(ChannelError::Ignore("Cannot send 0-msat HTLC"));
3498+
}
3499+
34963500
if amount_msat < self.their_htlc_minimum_msat {
34973501
return Err(ChannelError::Ignore("Cannot send less than their minimum HTLC value"));
34983502
}

lightning/src/ln/functional_test_utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,7 @@ pub fn create_node_chanmgrs<'a, 'b>(node_count: usize, cfgs: &'a Vec<NodeCfg<'b>
10051005
let mut default_config = UserConfig::default();
10061006
default_config.channel_options.announced_channel = true;
10071007
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
1008+
default_config.own_channel_config.our_htlc_minimum_msat = 1000; // sanitization being done by the sender, to exerce receiver logic we need to lift of limit
10081009
let node = ChannelManager::new(Network::Testnet, cfgs[i].fee_estimator, &cfgs[i].chan_monitor, cfgs[i].tx_broadcaster, cfgs[i].logger.clone(), &cfgs[i].keys_manager, if node_config[i].is_some() { node_config[i].clone().unwrap() } else { default_config }, 0).unwrap();
10091010
chanmgrs.push(node);
10101011
}

lightning/src/ln/functional_tests.rs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5486,7 +5486,6 @@ fn bolt2_open_channel_sending_node_checks_part2() {
54865486

54875487
#[test]
54885488
fn test_update_add_htlc_bolt2_sender_value_below_minimum_msat() {
5489-
//BOLT2 Requirement: MUST offer amount_msat greater than 0.
54905489
//BOLT2 Requirement: MUST NOT offer amount_msat below the receiving node's htlc_minimum_msat (same validation check catches both of these)
54915490
let chanmon_cfgs = create_chanmon_cfgs(2);
54925491
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
@@ -5496,7 +5495,7 @@ fn test_update_add_htlc_bolt2_sender_value_below_minimum_msat() {
54965495
let mut route = nodes[0].router.get_route(&nodes[1].node.get_our_node_id(), None, &[], 100000, TEST_FINAL_CLTV).unwrap();
54975496
let (_, our_payment_hash) = get_payment_preimage_hash!(nodes[0]);
54985497

5499-
route.hops[0].fee_msat = 0;
5498+
route.hops[0].fee_msat = 100;
55005499

55015500
let err = nodes[0].node.send_payment(route, our_payment_hash);
55025501

@@ -5509,6 +5508,51 @@ fn test_update_add_htlc_bolt2_sender_value_below_minimum_msat() {
55095508
nodes[0].logger.assert_log("lightning::ln::channelmanager".to_string(), "Cannot send less than their minimum HTLC value".to_string(), 1);
55105509
}
55115510

5511+
#[test]
5512+
fn test_update_add_htlc_bolt2_sender_zero_value_msat() {
5513+
//BOLT2 Requirement: MUST offer amount_msat greater than 0.
5514+
let chanmon_cfgs = create_chanmon_cfgs(2);
5515+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
5516+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
5517+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
5518+
let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::supported(), InitFeatures::supported());
5519+
let mut route = nodes[0].router.get_route(&nodes[1].node.get_our_node_id(), None, &[], 100000, TEST_FINAL_CLTV).unwrap();
5520+
let (_, our_payment_hash) = get_payment_preimage_hash!(nodes[0]);
5521+
5522+
route.hops[0].fee_msat = 0;
5523+
5524+
let err = nodes[0].node.send_payment(route, our_payment_hash);
5525+
5526+
if let Err(APIError::ChannelUnavailable{err}) = err {
5527+
assert_eq!(err, "Cannot send 0-msat HTLC");
5528+
} else {
5529+
assert!(false);
5530+
}
5531+
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
5532+
nodes[0].logger.assert_log("lightning::ln::channelmanager".to_string(), "Cannot send 0-msat HTLC".to_string(), 1);
5533+
}
5534+
5535+
#[test]
5536+
fn test_update_add_htlc_bolt2_receiver_zero_value_msat() {
5537+
//BOLT2 Requirement: MUST offer amount_msat greater than 0.
5538+
let chanmon_cfgs = create_chanmon_cfgs(2);
5539+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
5540+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
5541+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
5542+
let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::supported(), InitFeatures::supported());
5543+
let route = nodes[0].router.get_route(&nodes[1].node.get_our_node_id(), None, &[], 100000, TEST_FINAL_CLTV).unwrap();
5544+
let (_, our_payment_hash) = get_payment_preimage_hash!(nodes[0]);
5545+
5546+
nodes[0].node.send_payment(route, our_payment_hash);
5547+
check_added_monitors!(nodes[0], 1);
5548+
let mut updates = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
5549+
updates.update_add_htlcs[0].amount_msat = 0;
5550+
5551+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &updates.update_add_htlcs[0]);
5552+
nodes[1].logger.assert_log("lightning::ln::channelmanager".to_string(), "Remote side tried to send a 0-msat HTLC".to_string(), 1);
5553+
check_closed_broadcast!(nodes[1], true).unwrap();
5554+
}
5555+
55125556
#[test]
55135557
fn test_update_add_htlc_bolt2_sender_cltv_expiry_too_high() {
55145558
//BOLT 2 Requirement: MUST set cltv_expiry less than 500000000.
@@ -7271,3 +7315,21 @@ fn test_override_channel_config() {
72717315
assert_eq!(res.channel_flags, 0);
72727316
assert_eq!(res.to_self_delay, 200);
72737317
}
7318+
7319+
#[test]
7320+
fn test_override_0msat_htlc_minimum() {
7321+
let mut zero_config = UserConfig::default();
7322+
zero_config.own_channel_config.our_htlc_minimum_msat = 0;
7323+
let chanmon_cfgs = create_chanmon_cfgs(2);
7324+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
7325+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(zero_config.clone())]);
7326+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
7327+
7328+
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 16_000_000, 12_000_000, 42, Some(zero_config)).unwrap();
7329+
let res = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
7330+
assert_eq!(res.htlc_minimum_msat, 1);
7331+
7332+
nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::supported(), &res);
7333+
let res = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
7334+
assert_eq!(res.htlc_minimum_msat, 1);
7335+
}

lightning/src/util/config.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,22 @@ pub struct ChannelHandshakeConfig {
5151
/// Default value: BREAKDOWN_TIMEOUT (currently 144), we enforce it as a minimum at channel
5252
/// opening so you can tweak config to ask for more security, not less.
5353
pub our_to_self_delay: u16,
54+
/// Set to the smallest value HTLC we will accept to process.
55+
///
56+
/// This value is sent to our counterparty on channel-open and we close the channel any time
57+
/// our counterparty misbehaves by sending us an HTLC with a value smaller than this.
58+
///
59+
/// Default value: 1. If the value is less than 1, it is ignored and set to 1, as is required
60+
/// by the protocol.
61+
pub our_htlc_minimum_msat: u64,
5462
}
5563

5664
impl Default for ChannelHandshakeConfig {
5765
fn default() -> ChannelHandshakeConfig {
5866
ChannelHandshakeConfig {
5967
minimum_depth: 6,
6068
our_to_self_delay: BREAKDOWN_TIMEOUT,
69+
our_htlc_minimum_msat: 1,
6170
}
6271
}
6372
}

0 commit comments

Comments
 (0)