From 5cfe19ef02cc9746ba664aeaa90921691a75dcd6 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Fri, 15 Apr 2022 18:10:39 -0400 Subject: [PATCH] Enable wumbo channels to be created Also redefine MAX_FUNDING_SATOSHIS_NO_WUMBO to no longer be off-by-one. --- lightning/src/ln/channel.rs | 18 ++++++++++++------ lightning/src/ln/features.rs | 9 +++++++++ lightning/src/ln/functional_tests.rs | 28 +++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index d680095f..b172b8c5 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -736,8 +736,8 @@ pub const ANCHOR_OUTPUT_VALUE_SATOSHI: u64 = 330; /// Maximum `funding_satoshis` value according to the BOLT #2 specification, if /// `option_support_large_channel` (aka wumbo channels) is not supported. -/// It's 2^24. -pub const MAX_FUNDING_SATOSHIS_NO_WUMBO: u64 = 1 << 24; +/// It's 2^24 - 1. +pub const MAX_FUNDING_SATOSHIS_NO_WUMBO: u64 = (1 << 24) - 1; /// Total bitcoin supply in satoshis. pub const TOTAL_BITCOIN_SUPPLY_SATOSHIS: u64 = 21_000_000 * 1_0000_0000; @@ -854,8 +854,11 @@ impl Channel { let holder_signer = keys_provider.get_channel_signer(false, channel_value_satoshis); let pubkeys = holder_signer.pubkeys().clone(); - if channel_value_satoshis >= MAX_FUNDING_SATOSHIS_NO_WUMBO { - return Err(APIError::APIMisuseError{err: format!("funding_value must be smaller than {}, it was {}", MAX_FUNDING_SATOSHIS_NO_WUMBO, channel_value_satoshis)}); + if !their_features.supports_wumbo() && channel_value_satoshis > MAX_FUNDING_SATOSHIS_NO_WUMBO { + return Err(APIError::APIMisuseError{err: format!("funding_value must not exceed {}, it was {}", MAX_FUNDING_SATOSHIS_NO_WUMBO, channel_value_satoshis)}); + } + if channel_value_satoshis >= TOTAL_BITCOIN_SUPPLY_SATOSHIS { + return Err(APIError::APIMisuseError{err: format!("funding_value must be smaller than the total bitcoin supply, it was {}", channel_value_satoshis)}); } let channel_value_msat = channel_value_satoshis * 1000; if push_msat > channel_value_msat { @@ -1080,8 +1083,11 @@ impl Channel { } // Check sanity of message fields: - if msg.funding_satoshis >= MAX_FUNDING_SATOSHIS_NO_WUMBO { - return Err(ChannelError::Close(format!("Funding must be smaller than {}. It was {}", MAX_FUNDING_SATOSHIS_NO_WUMBO, msg.funding_satoshis))); + if msg.funding_satoshis > config.peer_channel_config_limits.max_funding_satoshis { + return Err(ChannelError::Close(format!("Per our config, funding must be at most {}. It was {}", config.peer_channel_config_limits.max_funding_satoshis, msg.funding_satoshis))); + } + if msg.funding_satoshis >= TOTAL_BITCOIN_SUPPLY_SATOSHIS { + return Err(ChannelError::Close(format!("Funding must be smaller than the total bitcoin supply. It was {}", msg.funding_satoshis))); } if msg.channel_reserve_satoshis > msg.funding_satoshis { return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must be not greater than funding_satoshis: {}", msg.channel_reserve_satoshis, msg.funding_satoshis))); diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs index 57d1d427..25808746 100644 --- a/lightning/src/ln/features.rs +++ b/lightning/src/ln/features.rs @@ -743,6 +743,15 @@ impl Features { self } } + +impl Features { + #[cfg(test)] + pub(crate) fn clear_wumbo(mut self) -> Self { + ::clear_bits(&mut self.flags); + self + } +} + macro_rules! impl_feature_len_prefixed_write { ($features: ident) => { impl Writeable for $features { diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index ef30c57e..3449bd94 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -58,9 +58,12 @@ use ln::chan_utils::CommitmentTransaction; #[test] fn test_insane_channel_opens() { // Stand up a network of 2 nodes + use ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS; + let mut cfg = UserConfig::default(); + cfg.peer_channel_config_limits.max_funding_satoshis = TOTAL_BITCOIN_SUPPLY_SATOSHIS + 1; let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); - let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(cfg)]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); // Instantiate channel parameters where we push the maximum msats given our @@ -92,11 +95,11 @@ fn test_insane_channel_opens() { } else { assert!(false); } }; - use ln::channel::MAX_FUNDING_SATOSHIS_NO_WUMBO; use ln::channelmanager::MAX_LOCAL_BREAKDOWN_TIMEOUT; // Test all mutations that would make the channel open message insane - insane_open_helper(format!("Funding must be smaller than {}. It was {}", MAX_FUNDING_SATOSHIS_NO_WUMBO, MAX_FUNDING_SATOSHIS_NO_WUMBO).as_str(), |mut msg| { msg.funding_satoshis = MAX_FUNDING_SATOSHIS_NO_WUMBO; msg }); + insane_open_helper(format!("Per our config, funding must be at most {}. It was {}", TOTAL_BITCOIN_SUPPLY_SATOSHIS + 1, TOTAL_BITCOIN_SUPPLY_SATOSHIS + 2).as_str(), |mut msg| { msg.funding_satoshis = TOTAL_BITCOIN_SUPPLY_SATOSHIS + 2; msg }); + insane_open_helper(format!("Funding must be smaller than the total bitcoin supply. It was {}", TOTAL_BITCOIN_SUPPLY_SATOSHIS).as_str(), |mut msg| { msg.funding_satoshis = TOTAL_BITCOIN_SUPPLY_SATOSHIS; msg }); insane_open_helper("Bogus channel_reserve_satoshis", |mut msg| { msg.channel_reserve_satoshis = msg.funding_satoshis + 1; msg }); @@ -113,6 +116,25 @@ fn test_insane_channel_opens() { insane_open_helper("max_accepted_htlcs was 484. It must not be larger than 483", |mut msg| { msg.max_accepted_htlcs = 484; msg }); } +#[test] +fn test_funding_exceeds_no_wumbo_limit() { + // Test that if a peer does not support wumbo channels, we'll refuse to open a wumbo channel to + // them. + use ln::channel::MAX_FUNDING_SATOSHIS_NO_WUMBO; + let chanmon_cfgs = create_chanmon_cfgs(2); + let mut node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + node_cfgs[1].features = InitFeatures::known().clear_wumbo(); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + + match nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), MAX_FUNDING_SATOSHIS_NO_WUMBO + 1, 0, 42, None) { + Err(APIError::APIMisuseError { err }) => { + assert_eq!(format!("funding_value must not exceed {}, it was {}", MAX_FUNDING_SATOSHIS_NO_WUMBO, MAX_FUNDING_SATOSHIS_NO_WUMBO + 1), err); + }, + _ => panic!() + } +} + fn do_test_counterparty_no_reserve(send_from_initiator: bool) { // A peer providing a channel_reserve_satoshis of 0 (or less than our dust limit) is insecure, // but only for them. Because some LSPs do it with some level of trust of the clients (for a -- 2.30.2