From 02861dde01ce08d783fb72db6e71af2b2ac225c8 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Wed, 12 Feb 2025 11:28:13 +0100 Subject: [PATCH] Allow config defaults override for inbound channels This commit introduces a config override struct parameter to the accept_inbound_channel methods. With manual channel acceptance enabled, users can modify the default configuration as needed. --- fuzz/src/chanmon_consistency.rs | 1 + lightning/src/ln/async_signer_tests.rs | 4 +- lightning/src/ln/chanmon_update_fail_tests.rs | 8 +- lightning/src/ln/channelmanager.rs | 73 +++++++++---- lightning/src/ln/functional_test_utils.rs | 6 +- lightning/src/ln/functional_tests.rs | 101 ++++++++++++++---- lightning/src/ln/priv_short_conf_tests.rs | 10 +- lightning/src/util/config.rs | 81 ++++++++++++++ 8 files changed, 230 insertions(+), 54 deletions(-) diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 54c9a7e481b..90f5fed30b3 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -809,6 +809,7 @@ pub fn do_test(data: &[u8], underlying_out: Out, anchors: bool) { temporary_channel_id, counterparty_node_id, user_channel_id, + None, ) .unwrap(); } else { diff --git a/lightning/src/ln/async_signer_tests.rs b/lightning/src/ln/async_signer_tests.rs index 4a857d191a9..0cd78738e9b 100644 --- a/lightning/src/ln/async_signer_tests.rs +++ b/lightning/src/ln/async_signer_tests.rs @@ -74,7 +74,7 @@ fn do_test_open_channel(zero_conf: bool) { match &events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf( - temporary_channel_id, &nodes[0].node.get_our_node_id(), 0) + temporary_channel_id, &nodes[0].node.get_our_node_id(), 0, None) .expect("Unable to accept inbound zero-conf channel"); }, ev => panic!("Expected OpenChannelRequest, not {:?}", ev) @@ -319,7 +319,7 @@ fn do_test_funding_signed_0conf(signer_ops: Vec) { match &events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf( - temporary_channel_id, &nodes[0].node.get_our_node_id(), 0) + temporary_channel_id, &nodes[0].node.get_our_node_id(), 0, None) .expect("Unable to accept inbound zero-conf channel"); }, ev => panic!("Expected OpenChannelRequest, not {:?}", ev) diff --git a/lightning/src/ln/chanmon_update_fail_tests.rs b/lightning/src/ln/chanmon_update_fail_tests.rs index 48e02ffcfe5..497f724a243 100644 --- a/lightning/src/ln/chanmon_update_fail_tests.rs +++ b/lightning/src/ln/chanmon_update_fail_tests.rs @@ -2775,9 +2775,9 @@ fn do_test_outbound_reload_without_init_mon(use_0conf: bool) { match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { if use_0conf { - nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0).unwrap(); + nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0, None).unwrap(); } else { - nodes[1].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0).unwrap(); + nodes[1].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0, None).unwrap(); } }, _ => panic!("Unexpected event"), @@ -2866,9 +2866,9 @@ fn do_test_inbound_reload_without_init_mon(use_0conf: bool, lock_commitment: boo match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { if use_0conf { - nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0).unwrap(); + nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0, None).unwrap(); } else { - nodes[1].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0).unwrap(); + nodes[1].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0, None).unwrap(); } }, _ => panic!("Unexpected event"), diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 5bbcb2897ec..17db983a768 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -80,7 +80,7 @@ use crate::onion_message::messenger::{Destination, MessageRouter, Responder, Res use crate::onion_message::offers::{OffersMessage, OffersMessageHandler}; use crate::sign::{EntropySource, NodeSigner, Recipient, SignerProvider}; use crate::sign::ecdsa::EcdsaChannelSigner; -use crate::util::config::{UserConfig, ChannelConfig, ChannelConfigUpdate}; +use crate::util::config::{ChannelConfig, ChannelConfigUpdate, ChannelConfigOverrides, UserConfig}; use crate::util::wakers::{Future, Notifier}; use crate::util::scid_utils::fake_scid; use crate::util::string::UntrustedString; @@ -1900,7 +1900,7 @@ where /// /// let user_channel_id = 43; /// match channel_manager.accept_inbound_channel( -/// &temporary_channel_id, &counterparty_node_id, user_channel_id +/// &temporary_channel_id, &counterparty_node_id, user_channel_id, None /// ) { /// Ok(()) => println!("Accepting channel {}", temporary_channel_id), /// Err(e) => println!("Error accepting channel {}: {:?}", temporary_channel_id, e), @@ -7722,8 +7722,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ /// /// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest /// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id - pub fn accept_inbound_channel(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> { - self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, false, user_channel_id) + pub fn accept_inbound_channel(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128, config_overrides: Option) -> Result<(), APIError> { + self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, false, user_channel_id, config_overrides) } /// Accepts a request to open a channel after a [`events::Event::OpenChannelRequest`], treating @@ -7744,15 +7744,23 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ /// /// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest /// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id - pub fn accept_inbound_channel_from_trusted_peer_0conf(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> { - self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, true, user_channel_id) + pub fn accept_inbound_channel_from_trusted_peer_0conf(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128, config_overrides: Option) -> Result<(), APIError> { + self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, true, user_channel_id, config_overrides) } /// TODO(dual_funding): Allow contributions, pass intended amount and inputs fn do_accept_inbound_channel( &self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, accept_0conf: bool, - user_channel_id: u128, + user_channel_id: u128, config_overrides: Option ) -> Result<(), APIError> { + + let mut config = self.default_configuration.clone(); + + // Apply configuration overrides. + if let Some(overrides) = config_overrides { + config.apply(&overrides); + }; + let logger = WithContext::from(&self.logger, Some(*counterparty_node_id), Some(*temporary_channel_id), None); let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); @@ -7782,7 +7790,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ InboundV1Channel::new( &self.fee_estimator, &self.entropy_source, &self.signer_provider, *counterparty_node_id, &self.channel_type_features(), &peer_state.latest_features, &open_channel_msg, - user_channel_id, &self.default_configuration, best_block_height, &self.logger, accept_0conf + user_channel_id, &config, best_block_height, &self.logger, accept_0conf ).map_err(|err| MsgHandleErrInternal::from_chan_no_close(err, *temporary_channel_id) ).map(|mut channel| { let logger = WithChannelContext::from(&self.logger, &channel.context, None); @@ -7802,7 +7810,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ self.get_our_node_id(), *counterparty_node_id, &self.channel_type_features(), &peer_state.latest_features, &open_channel_msg, - user_channel_id, &self.default_configuration, best_block_height, + user_channel_id, &config, best_block_height, &self.logger, ).map_err(|_| MsgHandleErrInternal::from_chan_no_close( ChannelError::Close( @@ -14540,9 +14548,9 @@ mod tests { use crate::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, ClosureReason}; use crate::ln::types::ChannelId; use crate::types::payment::{PaymentPreimage, PaymentHash, PaymentSecret}; - use crate::ln::channelmanager::{create_recv_pending_htlc_info, HTLCForwardInfo, inbound_payment, PaymentId, RecipientOnionFields, InterceptId}; + use crate::ln::channelmanager::{create_recv_pending_htlc_info, inbound_payment, ChannelConfigOverrides, HTLCForwardInfo, InterceptId, PaymentId, RecipientOnionFields}; use crate::ln::functional_test_utils::*; - use crate::ln::msgs::{self, ErrorAction}; + use crate::ln::msgs::{self, AcceptChannel, ErrorAction}; use crate::ln::msgs::ChannelMessageHandler; use crate::ln::outbound_payment::Retry; use crate::prelude::*; @@ -14550,7 +14558,7 @@ mod tests { use crate::util::errors::APIError; use crate::util::ser::Writeable; use crate::util::test_utils; - use crate::util::config::{ChannelConfig, ChannelConfigUpdate}; + use crate::util::config::{ChannelConfig, ChannelConfigUpdate, ChannelHandshakeConfigUpdate}; use crate::sign::EntropySource; #[test] @@ -15299,7 +15307,7 @@ mod tests { // Test the API functions. check_not_connected_to_peer_error(nodes[0].node.create_channel(unkown_public_key, 1_000_000, 500_000_000, 42, None, None), unkown_public_key); - check_unkown_peer_error(nodes[0].node.accept_inbound_channel(&channel_id, &unkown_public_key, 42), unkown_public_key); + check_unkown_peer_error(nodes[0].node.accept_inbound_channel(&channel_id, &unkown_public_key, 42, None), unkown_public_key); check_unkown_peer_error(nodes[0].node.close_channel(&channel_id, &unkown_public_key), unkown_public_key); @@ -15330,7 +15338,7 @@ mod tests { let error_message = "Channel force-closed"; // Test the API functions. - check_api_misuse_error(nodes[0].node.accept_inbound_channel(&channel_id, &counterparty_node_id, 42)); + check_api_misuse_error(nodes[0].node.accept_inbound_channel(&channel_id, &counterparty_node_id, 42, None)); check_channel_unavailable_error(nodes[0].node.close_channel(&channel_id, &counterparty_node_id), channel_id, counterparty_node_id); @@ -15521,7 +15529,7 @@ mod tests { let events = nodes[1].node.get_and_clear_pending_events(); match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { - nodes[1].node.accept_inbound_channel(&temporary_channel_id, &random_pk, 23).unwrap(); + nodes[1].node.accept_inbound_channel(&temporary_channel_id, &random_pk, 23, None).unwrap(); } _ => panic!("Unexpected event"), } @@ -15539,7 +15547,7 @@ mod tests { let events = nodes[1].node.get_and_clear_pending_events(); match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { - match nodes[1].node.accept_inbound_channel(&temporary_channel_id, &last_random_pk, 23) { + match nodes[1].node.accept_inbound_channel(&temporary_channel_id, &last_random_pk, 23, None) { Err(APIError::APIMisuseError { err }) => assert_eq!(err, "Too many peers with unfunded channels, refusing to accept new ones"), _ => panic!(), @@ -15555,7 +15563,7 @@ mod tests { let events = nodes[1].node.get_and_clear_pending_events(); match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { - nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &last_random_pk, 23).unwrap(); + nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &last_random_pk, 23, None).unwrap(); } _ => panic!("Unexpected event"), } @@ -15635,6 +15643,33 @@ mod tests { #[test] fn test_inbound_anchors_manual_acceptance() { + test_inbound_anchors_manual_acceptance_with_override(None); + } + + #[test] + fn test_inbound_anchors_manual_acceptance_overridden() { + let overrides = ChannelConfigOverrides { + handshake_overrides: Some(ChannelHandshakeConfigUpdate { + max_inbound_htlc_value_in_flight_percent_of_channel: Some(5), + htlc_minimum_msat: Some(1000), + minimum_depth: Some(2), + to_self_delay: Some(200), + max_accepted_htlcs: Some(5), + channel_reserve_proportional_millionths: Some(20000), + }), + update_overrides: None, + }; + + let accept_message = test_inbound_anchors_manual_acceptance_with_override(Some(overrides)); + assert_eq!(accept_message.common_fields.max_htlc_value_in_flight_msat, 5_000_000); + assert_eq!(accept_message.common_fields.htlc_minimum_msat, 1_000); + assert_eq!(accept_message.common_fields.minimum_depth, 2); + assert_eq!(accept_message.common_fields.to_self_delay, 200); + assert_eq!(accept_message.common_fields.max_accepted_htlcs, 5); + assert_eq!(accept_message.channel_reserve_satoshis, 2_000); + } + + fn test_inbound_anchors_manual_acceptance_with_override(config_overrides: Option) -> AcceptChannel { // Tests that we properly limit inbound channels when we have the manual-channel-acceptance // flag set and (sometimes) accept channels as 0conf. let mut anchors_cfg = test_default_channel_config(); @@ -15671,10 +15706,10 @@ mod tests { let events = nodes[2].node.get_and_clear_pending_events(); match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => - nodes[2].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 23).unwrap(), + nodes[2].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 23, config_overrides).unwrap(), _ => panic!("Unexpected event"), } - get_event_msg!(nodes[2], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()); + get_event_msg!(nodes[2], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()) } #[test] diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index e77a3e72e6f..2382e8c09c7 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -27,7 +27,7 @@ use crate::onion_message::messenger::OnionMessenger; use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate}; use crate::routing::router::{self, PaymentParameters, Route, RouteParameters}; use crate::sign::{EntropySource, RandomBytes}; -use crate::util::config::{UserConfig, MaxDustHTLCExposure}; +use crate::util::config::{MaxDustHTLCExposure, UserConfig}; #[cfg(test)] use crate::util::logger::Logger; use crate::util::scid_utils; @@ -1321,7 +1321,7 @@ pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, r assert_eq!(events.len(), 1); match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { - receiver.node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &initiator.node.get_our_node_id(), 0).unwrap(); + receiver.node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &initiator.node.get_our_node_id(), 0, None).unwrap(); }, _ => panic!("Unexpected event"), }; @@ -1389,7 +1389,7 @@ pub fn exchange_open_accept_chan<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: assert_eq!(events.len(), 1); match &events[0] { Event::OpenChannelRequest { temporary_channel_id, counterparty_node_id, .. } => - node_b.node.accept_inbound_channel(temporary_channel_id, counterparty_node_id, 42).unwrap(), + node_b.node.accept_inbound_channel(temporary_channel_id, counterparty_node_id, 42, None).unwrap(), _ => panic!("Unexpected event"), }; } diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 66e21d64d54..7c9d10d1c4c 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -22,7 +22,7 @@ use crate::events::bump_transaction::WalletSource; use crate::events::{Event, FundingInfo, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, ClosureReason, HTLCDestination, PaymentFailureReason}; use crate::ln::types::ChannelId; use crate::types::payment::{PaymentPreimage, PaymentSecret, PaymentHash}; -use crate::ln::channel::{CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT, get_holder_selected_channel_reserve_satoshis, OutboundV1Channel, InboundV1Channel, COINBASE_MATURITY, Channel}; +use crate::ln::channel::{get_holder_selected_channel_reserve_satoshis, Channel, InboundV1Channel, OutboundV1Channel, COINBASE_MATURITY, CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT}; use crate::ln::channelmanager::{self, PaymentId, RAACommitmentOrder, RecipientOnionFields, BREAKDOWN_TIMEOUT, ENABLE_GOSSIP_TICKS, DISABLE_GOSSIP_TICKS, MIN_CLTV_EXPIRY_DELTA}; use crate::ln::channel::{DISCONNECT_PEER_AWAITING_RESPONSE_TICKS, ChannelError}; use crate::ln::{chan_utils, onion_utils}; @@ -30,14 +30,14 @@ use crate::ln::chan_utils::{commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_ use crate::routing::gossip::{NetworkGraph, NetworkUpdate}; use crate::routing::router::{Path, PaymentParameters, Route, RouteHop, get_route, RouteParameters}; use crate::types::features::{ChannelFeatures, ChannelTypeFeatures, NodeFeatures}; -use crate::ln::msgs; +use crate::ln::msgs::{self, AcceptChannel}; use crate::ln::msgs::{ChannelMessageHandler, RoutingMessageHandler, ErrorAction}; use crate::util::test_channel_signer::TestChannelSigner; use crate::util::test_utils::{self, TestLogger, WatchtowerPersister}; use crate::util::errors::APIError; use crate::util::ser::{Writeable, ReadableArgs}; use crate::util::string::UntrustedString; -use crate::util::config::{UserConfig, MaxDustHTLCExposure}; +use crate::util::config::{ChannelConfigOverrides, ChannelHandshakeConfigUpdate, ChannelConfigUpdate, MaxDustHTLCExposure, UserConfig}; use bitcoin::hash_types::BlockHash; use bitcoin::locktime::absolute::LockTime; @@ -8408,12 +8408,14 @@ fn test_channel_update_has_correct_htlc_maximum_msat() { fn test_manually_accept_inbound_channel_request() { let mut manually_accept_conf = UserConfig::default(); manually_accept_conf.manually_accept_inbound_channels = true; + manually_accept_conf.channel_handshake_config.minimum_depth = 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, Some(manually_accept_conf.clone())]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); - let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, Some(manually_accept_conf)).unwrap(); + nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None, Some(manually_accept_conf)).unwrap(); let res = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()); nodes[1].node.handle_open_channel(nodes[0].node.get_our_node_id(), &res); @@ -8422,10 +8424,28 @@ fn test_manually_accept_inbound_channel_request() { // accepting the inbound channel request. assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty()); + let config_overrides = ChannelConfigOverrides { + handshake_overrides: Some(ChannelHandshakeConfigUpdate { + max_inbound_htlc_value_in_flight_percent_of_channel: None, + htlc_minimum_msat: None, + minimum_depth: None, + to_self_delay: None, + max_accepted_htlcs: Some(3), + channel_reserve_proportional_millionths: None, + }), + update_overrides: Some(ChannelConfigUpdate { + forwarding_fee_proportional_millionths: None, + forwarding_fee_base_msat: Some(555), + cltv_expiry_delta: None, + max_dust_htlc_exposure_msat: None, + force_close_avoidance_max_fee_satoshis: None, + accept_underpaying_htlcs: None, + }), + }; let events = nodes[1].node.get_and_clear_pending_events(); match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { - nodes[1].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 23).unwrap(); + nodes[1].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 23, Some(config_overrides)).unwrap(); } _ => panic!("Unexpected event"), } @@ -8433,25 +8453,65 @@ fn test_manually_accept_inbound_channel_request() { let accept_msg_ev = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(accept_msg_ev.len(), 1); + let ref accept_channel: AcceptChannel; match accept_msg_ev[0] { - MessageSendEvent::SendAcceptChannel { ref node_id, .. } => { + MessageSendEvent::SendAcceptChannel { ref node_id, ref msg } => { assert_eq!(*node_id, nodes[0].node.get_our_node_id()); + + // Assert overriden handshake parameter. + assert_eq!(msg.common_fields.max_accepted_htlcs, 3); + + accept_channel = msg; } _ => panic!("Unexpected event"), } - let error_message = "Channel force-closed"; - nodes[1].node.force_close_broadcasting_latest_txn(&temp_channel_id, &nodes[0].node.get_our_node_id(), error_message.to_string()).unwrap(); - let close_msg_ev = nodes[1].node.get_and_clear_pending_msg_events(); - assert_eq!(close_msg_ev.len(), 1); + // Continue channel opening process until channel update messages are sent. + nodes[0].node.handle_accept_channel(nodes[1].node.get_our_node_id(), &accept_channel); + let (temporary_channel_id, tx, funding_outpoint) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 100_000, 42); + nodes[0].node.unsafe_manual_funding_transaction_generated(temporary_channel_id, nodes[1].node.get_our_node_id(), funding_outpoint).unwrap(); + check_added_monitors!(nodes[0], 0); - let events = nodes[1].node.get_and_clear_pending_events(); - match events[0] { - Event::ChannelClosed { user_channel_id, .. } => { - assert_eq!(user_channel_id, 23); - } + let funding_created = get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id()); + nodes[1].node.handle_funding_created(nodes[0].node.get_our_node_id(), &funding_created); + check_added_monitors!(nodes[1], 1); + expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id()); + + let funding_signed = get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id()); + nodes[0].node.handle_funding_signed(nodes[1].node.get_our_node_id(), &funding_signed); + check_added_monitors!(nodes[0], 1); + let events = &nodes[0].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 2); + match &events[0] { + crate::events::Event::FundingTxBroadcastSafe { funding_txo, .. } => { + assert_eq!(funding_txo.txid, funding_outpoint.txid); + assert_eq!(funding_txo.vout, funding_outpoint.index.into()); + }, _ => panic!("Unexpected event"), - } + }; + match &events[1] { + crate::events::Event::ChannelPending { counterparty_node_id, .. } => { + assert_eq!(*&nodes[1].node.get_our_node_id(), *counterparty_node_id); + }, + _ => panic!("Unexpected event"), + }; + + mine_transaction(&nodes[0], &tx); + mine_transaction(&nodes[1], &tx); + + let as_channel_ready = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReady, nodes[0].node.get_our_node_id()); + nodes[1].node.handle_channel_ready(nodes[0].node.get_our_node_id(), &as_channel_ready); + let as_channel_ready = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReady, nodes[1].node.get_our_node_id()); + nodes[0].node.handle_channel_ready(nodes[1].node.get_our_node_id(), &as_channel_ready); + + expect_channel_ready_event(&nodes[0], &nodes[1].node.get_our_node_id()); + expect_channel_ready_event(&nodes[1], &nodes[0].node.get_our_node_id()); + + // Assert that the overriden base fee surfaces in the channel update. + let channel_update = get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[0].node.get_our_node_id()); + assert_eq!(channel_update.contents.fee_base_msat, 555); + + get_event_msg!(nodes[0], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id()); } #[test] @@ -8515,8 +8575,8 @@ fn test_can_not_accept_inbound_channel_twice() { let events = nodes[1].node.get_and_clear_pending_events(); match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { - nodes[1].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0).unwrap(); - let api_res = nodes[1].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0); + nodes[1].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0, None).unwrap(); + let api_res = nodes[1].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0, None); match api_res { Err(APIError::APIMisuseError { err }) => { assert_eq!(err, "No such channel awaiting to be accepted."); @@ -8548,7 +8608,7 @@ fn test_can_not_accept_unknown_inbound_channel() { let nodes = create_network(2, &node_cfg, &node_chanmgr); let unknown_channel_id = ChannelId::new_zero(); - let api_res = nodes[0].node.accept_inbound_channel(&unknown_channel_id, &nodes[1].node.get_our_node_id(), 0); + let api_res = nodes[0].node.accept_inbound_channel(&unknown_channel_id, &nodes[1].node.get_our_node_id(), 0, None); match api_res { Err(APIError::APIMisuseError { err }) => { assert_eq!(err, "No such channel awaiting to be accepted."); @@ -11557,7 +11617,7 @@ fn test_accept_inbound_channel_errors_queued() { let events = nodes[1].node.get_and_clear_pending_events(); match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { - match nodes[1].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 23) { + match nodes[1].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 23, None) { Err(APIError::ChannelUnavailable { err: _ }) => (), _ => panic!(), } @@ -11667,4 +11727,3 @@ fn test_funding_signed_event() { nodes[0].node.get_and_clear_pending_msg_events(); nodes[1].node.get_and_clear_pending_msg_events(); } - diff --git a/lightning/src/ln/priv_short_conf_tests.rs b/lightning/src/ln/priv_short_conf_tests.rs index f2525e63d4c..97d3c68f9f6 100644 --- a/lightning/src/ln/priv_short_conf_tests.rs +++ b/lightning/src/ln/priv_short_conf_tests.rs @@ -20,7 +20,7 @@ use crate::types::features::ChannelTypeFeatures; use crate::ln::msgs; use crate::ln::types::ChannelId; use crate::ln::msgs::{ChannelMessageHandler, RoutingMessageHandler, ErrorAction}; -use crate::util::config::{UserConfig, MaxDustHTLCExposure}; +use crate::util::config::{MaxDustHTLCExposure, UserConfig}; use crate::util::ser::Writeable; use crate::prelude::*; @@ -591,7 +591,7 @@ fn test_0conf_channel_with_async_monitor() { assert_eq!(events.len(), 1); match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { - nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0).unwrap(); + nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0, None).unwrap(); }, _ => panic!("Unexpected event"), }; @@ -919,7 +919,7 @@ fn test_zero_conf_accept_reject() { Event::OpenChannelRequest { temporary_channel_id, .. } => { // Assert we fail to accept via the non-0conf method assert!(nodes[1].node.accept_inbound_channel(&temporary_channel_id, - &nodes[0].node.get_our_node_id(), 0).is_err()); + &nodes[0].node.get_our_node_id(), 0, None).is_err()); }, _ => panic!(), } @@ -948,7 +948,7 @@ fn test_zero_conf_accept_reject() { Event::OpenChannelRequest { temporary_channel_id, .. } => { // Assert we can accept via the 0conf method assert!(nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf( - &temporary_channel_id, &nodes[0].node.get_our_node_id(), 0).is_ok()); + &temporary_channel_id, &nodes[0].node.get_our_node_id(), 0, None).is_ok()); }, _ => panic!(), } @@ -983,7 +983,7 @@ fn test_connect_before_funding() { assert_eq!(events.len(), 1); match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { - nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0).unwrap(); + nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0, None).unwrap(); }, _ => panic!("Unexpected event"), }; diff --git a/lightning/src/util/config.rs b/lightning/src/util/config.rs index e497b27e67c..ef35df1a0b1 100644 --- a/lightning/src/util/config.rs +++ b/lightning/src/util/config.rs @@ -913,3 +913,84 @@ impl Readable for UserConfig { }) } } + +/// Config structure for overriding channel parameters. +#[derive(Default)] +pub struct ChannelConfigOverrides { + /// Overrides for channel handshake parameters. + pub handshake_overrides: Option, + + /// Overrides for channel update parameters. + pub update_overrides: Option, +} + +impl UserConfig { + /// Applies given channel config overrides to the user config. + pub fn apply(&mut self, config: &ChannelConfigOverrides) { + if let Some(handshake_overrides) = &config.handshake_overrides { + self.channel_handshake_config.apply(&handshake_overrides); + } + + if let Some(update_overrides) = &config.update_overrides { + self.channel_config.apply(&update_overrides); + } + } +} + +/// Config structure for overriding channel handshake parameters. +#[derive(Default)] +pub struct ChannelHandshakeConfigUpdate { + /// Overrides the percentage of the channel value we will cap the total value of outstanding inbound HTLCs to. See + /// [`ChannelHandshakeConfig::max_inbound_htlc_value_in_flight_percent_of_channel`]. + pub max_inbound_htlc_value_in_flight_percent_of_channel: Option, + + /// Overrides the smallest value HTLC we will accept to process. See [`ChannelHandshakeConfig::our_htlc_minimum_msat`]. + pub htlc_minimum_msat: Option, + + /// Overrides confirmations we will wait for before considering the channel locked in. See + /// [`ChannelHandshakeConfig::minimum_depth`]. + pub minimum_depth: Option, + + /// Overrides the number of blocks we require our counterparty to wait to claim their money. See + /// [`ChannelHandshakeConfig::our_to_self_delay`]. + pub to_self_delay: Option, + + /// The maximum number of HTLCs in-flight from our counterparty towards us at the same time. See + /// [`ChannelHandshakeConfig::our_max_accepted_htlcs`]. + pub max_accepted_htlcs: Option, + + /// The Proportion of the channel value to configure as counterparty's channel reserve. See + /// [`ChannelHandshakeConfig::their_channel_reserve_proportional_millionths`]. + pub channel_reserve_proportional_millionths: Option, +} + +impl ChannelHandshakeConfig { + /// Applies the provided handshake config update. + pub fn apply(&mut self, config: &ChannelHandshakeConfigUpdate) { + if let Some(max_in_flight_percent) = + config.max_inbound_htlc_value_in_flight_percent_of_channel + { + self.max_inbound_htlc_value_in_flight_percent_of_channel = max_in_flight_percent; + } + + if let Some(htlc_minimum_msat) = config.htlc_minimum_msat { + self.our_htlc_minimum_msat = htlc_minimum_msat; + } + + if let Some(minimum_depth) = config.minimum_depth { + self.minimum_depth = minimum_depth; + } + + if let Some(to_self_delay) = config.to_self_delay { + self.our_to_self_delay = to_self_delay; + } + + if let Some(max_accepted_htlcs) = config.max_accepted_htlcs { + self.our_max_accepted_htlcs = max_accepted_htlcs; + } + + if let Some(channel_reserve) = config.channel_reserve_proportional_millionths { + self.their_channel_reserve_proportional_millionths = channel_reserve; + } + } +}