mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-03-14 07:06:42 +01:00
Merge pull request #3596 from joostjager/inbound-channel-config-override
Allow to override config defaults for inbound channels on a per-channel basis
This commit is contained in:
commit
cdc8e2130d
8 changed files with 253 additions and 55 deletions
|
@ -809,6 +809,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out, anchors: bool) {
|
|||
temporary_channel_id,
|
||||
counterparty_node_id,
|
||||
user_channel_id,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
|
|
|
@ -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<SignerOp>) {
|
|||
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)
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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;
|
||||
|
@ -1902,7 +1902,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),
|
||||
|
@ -7755,8 +7755,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<ChannelConfigOverrides>) -> 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
|
||||
|
@ -7777,15 +7777,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<ChannelConfigOverrides>) -> 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<ChannelConfigOverrides>
|
||||
) -> 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);
|
||||
|
||||
|
@ -7815,7 +7823,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);
|
||||
|
@ -7835,7 +7843,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(
|
||||
|
@ -14657,9 +14665,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::*;
|
||||
|
@ -14667,7 +14675,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]
|
||||
|
@ -15480,7 +15488,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);
|
||||
|
||||
|
@ -15511,7 +15519,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);
|
||||
|
||||
|
@ -15702,7 +15710,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"),
|
||||
}
|
||||
|
@ -15720,7 +15728,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!(),
|
||||
|
@ -15736,7 +15744,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"),
|
||||
}
|
||||
|
@ -15819,6 +15827,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<ChannelConfigOverrides>) -> 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();
|
||||
|
@ -15855,10 +15890,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]
|
||||
|
@ -15943,10 +15978,12 @@ mod tests {
|
|||
let new_fee = user_config.channel_config.forwarding_fee_proportional_millionths + 100;
|
||||
nodes[0].node.update_partial_channel_config(&channel.counterparty.node_id, &[channel.channel_id], &ChannelConfigUpdate {
|
||||
forwarding_fee_proportional_millionths: Some(new_fee),
|
||||
accept_underpaying_htlcs: Some(true),
|
||||
..Default::default()
|
||||
}).unwrap();
|
||||
assert_eq!(nodes[0].node.list_channels()[0].config.unwrap().cltv_expiry_delta, new_cltv_expiry_delta);
|
||||
assert_eq!(nodes[0].node.list_channels()[0].config.unwrap().forwarding_fee_proportional_millionths, new_fee);
|
||||
assert_eq!(nodes[0].node.list_channels()[0].config.unwrap().accept_underpaying_htlcs, true);
|
||||
let events = nodes[0].node.get_and_clear_pending_msg_events();
|
||||
assert_eq!(events.len(), 1);
|
||||
match &events[0] {
|
||||
|
|
|
@ -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;
|
||||
|
@ -1327,7 +1327,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"),
|
||||
};
|
||||
|
@ -1395,7 +1395,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"),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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"),
|
||||
};
|
||||
|
|
|
@ -601,6 +601,9 @@ impl ChannelConfig {
|
|||
{
|
||||
self.force_close_avoidance_max_fee_satoshis = force_close_avoidance_max_fee_satoshis;
|
||||
}
|
||||
if let Some(accept_underpaying_htlcs) = update.accept_underpaying_htlcs {
|
||||
self.accept_underpaying_htlcs = accept_underpaying_htlcs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -674,14 +677,30 @@ impl crate::util::ser::Readable for ChannelConfig {
|
|||
}
|
||||
|
||||
/// A parallel struct to [`ChannelConfig`] to define partial updates.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Default)]
|
||||
pub struct ChannelConfigUpdate {
|
||||
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound over the channel. See
|
||||
/// [`ChannelConfig::forwarding_fee_proportional_millionths`].
|
||||
pub forwarding_fee_proportional_millionths: Option<u32>,
|
||||
|
||||
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel. See
|
||||
/// [`ChannelConfig::forwarding_fee_base_msat`].
|
||||
pub forwarding_fee_base_msat: Option<u32>,
|
||||
|
||||
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over the channel this
|
||||
/// config applies to. See [`ChannelConfig::cltv_expiry_delta`].
|
||||
pub cltv_expiry_delta: Option<u16>,
|
||||
|
||||
/// The total exposure we are willing to allow to dust HTLCs. See [`ChannelConfig::max_dust_htlc_exposure`].
|
||||
pub max_dust_htlc_exposure_msat: Option<MaxDustHTLCExposure>,
|
||||
|
||||
/// The additional fee we're willing to pay to avoid waiting for the counterparty's `to_self_delay` to reclaim
|
||||
/// funds. See [`ChannelConfig::force_close_avoidance_max_fee_satoshis`].
|
||||
pub force_close_avoidance_max_fee_satoshis: Option<u64>,
|
||||
|
||||
/// If set, allows this channel's counterparty to skim an additional fee off this node's inbound HTLCs. See
|
||||
/// [`ChannelConfig::accept_underpaying_htlcs`].
|
||||
pub accept_underpaying_htlcs: Option<bool>,
|
||||
}
|
||||
|
||||
impl From<ChannelConfig> for ChannelConfigUpdate {
|
||||
|
@ -696,6 +715,7 @@ impl From<ChannelConfig> for ChannelConfigUpdate {
|
|||
force_close_avoidance_max_fee_satoshis: Some(
|
||||
config.force_close_avoidance_max_fee_satoshis,
|
||||
),
|
||||
accept_underpaying_htlcs: Some(config.accept_underpaying_htlcs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -893,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<ChannelHandshakeConfigUpdate>,
|
||||
|
||||
/// Overrides for channel update parameters.
|
||||
pub update_overrides: Option<ChannelConfigUpdate>,
|
||||
}
|
||||
|
||||
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<u8>,
|
||||
|
||||
/// Overrides the smallest value HTLC we will accept to process. See [`ChannelHandshakeConfig::our_htlc_minimum_msat`].
|
||||
pub htlc_minimum_msat: Option<u64>,
|
||||
|
||||
/// Overrides confirmations we will wait for before considering the channel locked in. See
|
||||
/// [`ChannelHandshakeConfig::minimum_depth`].
|
||||
pub minimum_depth: Option<u32>,
|
||||
|
||||
/// 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<u16>,
|
||||
|
||||
/// 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<u16>,
|
||||
|
||||
/// 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<u32>,
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue