use crate::ln::inbound_payment;
use crate::ln::types::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret};
use crate::ln::channel::{self, Channel, ChannelPhase, ChannelContext, ChannelError, ChannelUpdateStatus, ShutdownResult, UnfundedChannelContext, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel, WithChannelContext};
-use crate::ln::channel_state::{ChannelCounterparty, ChannelDetails, ChannelShutdownState, CounterpartyForwardingInfo};
+use crate::ln::channel_state::ChannelDetails;
use crate::ln::features::{Bolt12InvoiceFeatures, ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
#[cfg(any(feature = "_test_utils", test))]
use crate::ln::features::Bolt11InvoiceFeatures;
/// #
/// # fn example<T: AChannelManager>(channel_manager: T) {
/// # let channel_manager = channel_manager.get_cm();
+/// # let error_message = "Channel force-closed";
/// channel_manager.process_pending_events(&|event| match event {
/// Event::OpenChannelRequest { temporary_channel_id, counterparty_node_id, .. } => {
/// if !is_trusted(counterparty_node_id) {
/// match channel_manager.force_close_without_broadcasting_txn(
-/// &temporary_channel_id, &counterparty_node_id
+/// &temporary_channel_id, &counterparty_node_id, error_message.to_string()
/// ) {
/// Ok(()) => println!("Rejecting channel {}", temporary_channel_id),
/// Err(e) => println!("Error rejecting channel {}: {:?}", temporary_channel_id, e),
/// #
/// # fn example<T: AChannelManager>(channel_manager: T) -> Result<(), Bolt12SemanticError> {
/// # let channel_manager = channel_manager.get_cm();
+/// # let absolute_expiry = None;
/// let offer = channel_manager
-/// .create_offer_builder()?
+/// .create_offer_builder(absolute_expiry)?
/// # ;
/// # // Needed for compiling for c_bindings
/// # let builder: lightning::offers::offer::OfferBuilder<_, _> = offer.into();
/// many peers we reject new (inbound) connections.
const MAX_NO_CHANNEL_PEERS: usize = 250;
+/// The maximum expiration from the current time where an [`Offer`] or [`Refund`] is considered
+/// short-lived, while anything with a greater expiration is considered long-lived.
+///
+/// Using [`ChannelManager::create_offer_builder`] or [`ChannelManager::create_refund_builder`],
+/// will included a [`BlindedPath`] created using:
+/// - [`MessageRouter::create_compact_blinded_paths`] when short-lived, and
+/// - [`MessageRouter::create_blinded_paths`] when long-lived.
+///
+/// Using compact [`BlindedPath`]s may provide better privacy as the [`MessageRouter`] could select
+/// more hops. However, since they use short channel ids instead of pubkeys, they are more likely to
+/// become invalid over time as channels are closed. Thus, they are only suitable for short-term use.
+pub const MAX_SHORT_LIVED_RELATIVE_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24);
+
/// Used by [`ChannelManager::list_recent_payments`] to express the status of recent payments.
/// These include payments that have yet to find a successful path, or have unresolved HTLCs.
#[derive(Debug, PartialEq)]
Ok(counterparty_node_id)
}
- fn force_close_sending_error(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey, broadcast: bool) -> Result<(), APIError> {
+ fn force_close_sending_error(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey, broadcast: bool, error_message: String)
+ -> Result<(), APIError> {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
+ log_debug!(self.logger,
+ "Force-closing channel, The error message sent to the peer : {}", error_message);
match self.force_close_channel_with_peer(channel_id, counterparty_node_id, None, broadcast) {
Ok(counterparty_node_id) => {
let per_peer_state = self.per_peer_state.read().unwrap();
peer_state.pending_msg_events.push(
events::MessageSendEvent::HandleError {
node_id: counterparty_node_id,
- action: msgs::ErrorAction::DisconnectPeer {
- msg: Some(msgs::ErrorMessage { channel_id: *channel_id, data: "Channel force-closed".to_owned() })
+ action: msgs::ErrorAction::SendErrorMessage {
+ msg: msgs::ErrorMessage { channel_id: *channel_id, data: error_message }
},
}
);
}
}
- /// Force closes a channel, immediately broadcasting the latest local transaction(s) and
- /// rejecting new HTLCs on the given channel. Fails if `channel_id` is unknown to
- /// the manager, or if the `counterparty_node_id` isn't the counterparty of the corresponding
- /// channel.
- pub fn force_close_broadcasting_latest_txn(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey)
+ /// Force closes a channel, immediately broadcasting the latest local transaction(s),
+ /// rejecting new HTLCs.
+ ///
+ /// The provided `error_message` is sent to connected peers for closing
+ /// channels and should be a human-readable description of what went wrong.
+ ///
+ /// Fails if `channel_id` is unknown to the manager, or if the `counterparty_node_id`
+ /// isn't the counterparty of the corresponding channel.
+ pub fn force_close_broadcasting_latest_txn(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey, error_message: String)
-> Result<(), APIError> {
- self.force_close_sending_error(channel_id, counterparty_node_id, true)
+ self.force_close_sending_error(channel_id, counterparty_node_id, true, error_message)
}
/// Force closes a channel, rejecting new HTLCs on the given channel but skips broadcasting
- /// the latest local transaction(s). Fails if `channel_id` is unknown to the manager, or if the
- /// `counterparty_node_id` isn't the counterparty of the corresponding channel.
+ /// the latest local transaction(s).
+ ///
+ /// The provided `error_message` is sent to connected peers for closing channels and should
+ /// be a human-readable description of what went wrong.
///
+ /// Fails if `channel_id` is unknown to the manager, or if the
+ /// `counterparty_node_id` isn't the counterparty of the corresponding channel.
/// You can always broadcast the latest local transaction(s) via
/// [`ChannelMonitor::broadcast_latest_holder_commitment_txn`].
- pub fn force_close_without_broadcasting_txn(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey)
+ pub fn force_close_without_broadcasting_txn(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey, error_message: String)
-> Result<(), APIError> {
- self.force_close_sending_error(channel_id, counterparty_node_id, false)
+ self.force_close_sending_error(channel_id, counterparty_node_id, false, error_message)
}
/// Force close all channels, immediately broadcasting the latest local commitment transaction
/// for each to the chain and rejecting new HTLCs on each.
- pub fn force_close_all_channels_broadcasting_latest_txn(&self) {
+ ///
+ /// The provided `error_message` is sent to connected peers for closing channels and should
+ /// be a human-readable description of what went wrong.
+ pub fn force_close_all_channels_broadcasting_latest_txn(&self, error_message: String) {
for chan in self.list_channels() {
- let _ = self.force_close_broadcasting_latest_txn(&chan.channel_id, &chan.counterparty.node_id);
+ let _ = self.force_close_broadcasting_latest_txn(&chan.channel_id, &chan.counterparty.node_id, error_message.clone());
}
}
/// Force close all channels rejecting new HTLCs on each but without broadcasting the latest
/// local transaction(s).
- pub fn force_close_all_channels_without_broadcasting_txn(&self) {
+ ///
+ /// The provided `error_message` is sent to connected peers for closing channels and
+ /// should be a human-readable description of what went wrong.
+ pub fn force_close_all_channels_without_broadcasting_txn(&self, error_message: String) {
for chan in self.list_channels() {
- let _ = self.force_close_without_broadcasting_txn(&chan.channel_id, &chan.counterparty.node_id);
+ let _ = self.force_close_without_broadcasting_txn(&chan.channel_id, &chan.counterparty.node_id, error_message.clone());
}
}
macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
/// Creates an [`OfferBuilder`] such that the [`Offer`] it builds is recognized by the
- /// [`ChannelManager`] when handling [`InvoiceRequest`] messages for the offer. The offer will
- /// not have an expiration unless otherwise set on the builder.
+ /// [`ChannelManager`] when handling [`InvoiceRequest`] messages for the offer. The offer's
+ /// expiration will be `absolute_expiry` if `Some`, otherwise it will not expire.
///
/// # Privacy
///
- /// Uses [`MessageRouter::create_blinded_paths`] to construct a [`BlindedPath`] for the offer.
- /// However, if one is not found, uses a one-hop [`BlindedPath`] with
- /// [`ChannelManager::get_our_node_id`] as the introduction node instead. In the latter case,
- /// the node must be announced, otherwise, there is no way to find a path to the introduction in
- /// order to send the [`InvoiceRequest`].
+ /// Uses [`MessageRouter`] to construct a [`BlindedPath`] for the offer based on the given
+ /// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
+ /// privacy implications as well as those of the parameterized [`Router`], which implements
+ /// [`MessageRouter`].
///
/// Also, uses a derived signing pubkey in the offer for recipient privacy.
///
///
/// [`Offer`]: crate::offers::offer::Offer
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
- pub fn create_offer_builder(&$self) -> Result<$builder, Bolt12SemanticError> {
+ pub fn create_offer_builder(
+ &$self, absolute_expiry: Option<Duration>
+ ) -> Result<$builder, Bolt12SemanticError> {
let node_id = $self.get_our_node_id();
let expanded_key = &$self.inbound_payment_key;
let entropy = &*$self.entropy_source;
let secp_ctx = &$self.secp_ctx;
- let path = $self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
+ let path = $self.create_blinded_path_using_absolute_expiry(absolute_expiry)
+ .map_err(|_| Bolt12SemanticError::MissingPaths)?;
let builder = OfferBuilder::deriving_signing_pubkey(
node_id, expanded_key, entropy, secp_ctx
)
.chain_hash($self.chain_hash)
.path(path);
+ let builder = match absolute_expiry {
+ None => builder,
+ Some(absolute_expiry) => builder.absolute_expiry(absolute_expiry),
+ };
+
Ok(builder.into())
}
} }
///
/// # Privacy
///
- /// Uses [`MessageRouter::create_blinded_paths`] to construct a [`BlindedPath`] for the refund.
- /// However, if one is not found, uses a one-hop [`BlindedPath`] with
- /// [`ChannelManager::get_our_node_id`] as the introduction node instead. In the latter case,
- /// the node must be announced, otherwise, there is no way to find a path to the introduction in
- /// order to send the [`Bolt12Invoice`].
+ /// Uses [`MessageRouter`] to construct a [`BlindedPath`] for the refund based on the given
+ /// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
+ /// privacy implications as well as those of the parameterized [`Router`], which implements
+ /// [`MessageRouter`].
///
/// Also, uses a derived payer id in the refund for payer privacy.
///
let entropy = &*$self.entropy_source;
let secp_ctx = &$self.secp_ctx;
- let path = $self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
+ let path = $self.create_blinded_path_using_absolute_expiry(Some(absolute_expiry))
+ .map_err(|_| Bolt12SemanticError::MissingPaths)?;
let builder = RefundBuilder::deriving_payer_id(
node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
)?
///
/// # Privacy
///
- /// Uses a one-hop [`BlindedPath`] for the reply path with [`ChannelManager::get_our_node_id`]
- /// as the introduction node and a derived payer id for payer privacy. As such, currently, the
- /// node must be announced. Otherwise, there is no way to find a path to the introduction node
- /// in order to send the [`Bolt12Invoice`].
+ /// For payer privacy, uses a derived payer id and uses [`MessageRouter::create_blinded_paths`]
+ /// to construct a [`BlindedPath`] for the reply path. For further privacy implications, see the
+ /// docs of the parameterized [`Router`], which implements [`MessageRouter`].
///
/// # Limitations
///
inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key)
}
+ /// Creates a blinded path by delegating to [`MessageRouter`] based on the path's intended
+ /// lifetime.
+ ///
+ /// Whether or not the path is compact depends on whether the path is short-lived or long-lived,
+ /// respectively, based on the given `absolute_expiry` as seconds since the Unix epoch. See
+ /// [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`].
+ fn create_blinded_path_using_absolute_expiry(
+ &self, absolute_expiry: Option<Duration>
+ ) -> Result<BlindedPath, ()> {
+ let now = self.duration_since_epoch();
+ let max_short_lived_absolute_expiry = now.saturating_add(MAX_SHORT_LIVED_RELATIVE_EXPIRY);
+
+ if absolute_expiry.unwrap_or(Duration::MAX) <= max_short_lived_absolute_expiry {
+ self.create_compact_blinded_path()
+ } else {
+ self.create_blinded_path()
+ }
+ }
+
+ pub(super) fn duration_since_epoch(&self) -> Duration {
+ #[cfg(not(feature = "std"))]
+ let now = Duration::from_secs(
+ self.highest_seen_timestamp.load(Ordering::Acquire) as u64
+ );
+ #[cfg(feature = "std")]
+ let now = std::time::SystemTime::now()
+ .duration_since(std::time::SystemTime::UNIX_EPOCH)
+ .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
+
+ now
+ }
+
/// Creates a blinded path by delegating to [`MessageRouter::create_blinded_paths`].
///
/// Errors if the `MessageRouter` errors or returns an empty `Vec`.
let peers = self.per_peer_state.read().unwrap()
.iter()
.map(|(node_id, peer_state)| (node_id, peer_state.lock().unwrap()))
+ .filter(|(_, peer)| peer.is_connected)
+ .filter(|(_, peer)| peer.latest_features.supports_onion_messages())
+ .map(|(node_id, _)| *node_id)
+ .collect::<Vec<_>>();
+
+ self.router
+ .create_blinded_paths(recipient, peers, secp_ctx)
+ .and_then(|paths| paths.into_iter().next().ok_or(()))
+ }
+
+ /// Creates a blinded path by delegating to [`MessageRouter::create_compact_blinded_paths`].
+ ///
+ /// Errors if the `MessageRouter` errors or returns an empty `Vec`.
+ fn create_compact_blinded_path(&self) -> Result<BlindedPath, ()> {
+ let recipient = self.get_our_node_id();
+ let secp_ctx = &self.secp_ctx;
+
+ let peers = self.per_peer_state.read().unwrap()
+ .iter()
+ .map(|(node_id, peer_state)| (node_id, peer_state.lock().unwrap()))
+ .filter(|(_, peer)| peer.is_connected)
.filter(|(_, peer)| peer.latest_features.supports_onion_messages())
.map(|(node_id, peer)| ForwardNode {
node_id: *node_id,
.collect::<Vec<_>>();
self.router
- .create_blinded_paths(recipient, peers, secp_ctx)
+ .create_compact_blinded_paths(recipient, peers, secp_ctx)
.and_then(|paths| paths.into_iter().next().ok_or(()))
}
const SERIALIZATION_VERSION: u8 = 1;
const MIN_SERIALIZATION_VERSION: u8 = 1;
-impl_writeable_tlv_based!(CounterpartyForwardingInfo, {
- (2, fee_base_msat, required),
- (4, fee_proportional_millionths, required),
- (6, cltv_expiry_delta, required),
-});
-
-impl_writeable_tlv_based!(ChannelCounterparty, {
- (2, node_id, required),
- (4, features, required),
- (6, unspendable_punishment_reserve, required),
- (8, forwarding_info, option),
- (9, outbound_htlc_minimum_msat, option),
- (11, outbound_htlc_maximum_msat, option),
-});
-
-impl Writeable for ChannelDetails {
- fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
- // `user_channel_id` used to be a single u64 value. In order to remain backwards compatible with
- // versions prior to 0.0.113, the u128 is serialized as two separate u64 values.
- let user_channel_id_low = self.user_channel_id as u64;
- let user_channel_id_high_opt = Some((self.user_channel_id >> 64) as u64);
- write_tlv_fields!(writer, {
- (1, self.inbound_scid_alias, option),
- (2, self.channel_id, required),
- (3, self.channel_type, option),
- (4, self.counterparty, required),
- (5, self.outbound_scid_alias, option),
- (6, self.funding_txo, option),
- (7, self.config, option),
- (8, self.short_channel_id, option),
- (9, self.confirmations, option),
- (10, self.channel_value_satoshis, required),
- (12, self.unspendable_punishment_reserve, option),
- (14, user_channel_id_low, required),
- (16, self.balance_msat, required),
- (18, self.outbound_capacity_msat, required),
- (19, self.next_outbound_htlc_limit_msat, required),
- (20, self.inbound_capacity_msat, required),
- (21, self.next_outbound_htlc_minimum_msat, required),
- (22, self.confirmations_required, option),
- (24, self.force_close_spend_delay, option),
- (26, self.is_outbound, required),
- (28, self.is_channel_ready, required),
- (30, self.is_usable, required),
- (32, self.is_public, required),
- (33, self.inbound_htlc_minimum_msat, option),
- (35, self.inbound_htlc_maximum_msat, option),
- (37, user_channel_id_high_opt, option),
- (39, self.feerate_sat_per_1000_weight, option),
- (41, self.channel_shutdown_state, option),
- (43, self.pending_inbound_htlcs, optional_vec),
- (45, self.pending_outbound_htlcs, optional_vec),
- });
- Ok(())
- }
-}
-
-impl Readable for ChannelDetails {
- fn read<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
- _init_and_read_len_prefixed_tlv_fields!(reader, {
- (1, inbound_scid_alias, option),
- (2, channel_id, required),
- (3, channel_type, option),
- (4, counterparty, required),
- (5, outbound_scid_alias, option),
- (6, funding_txo, option),
- (7, config, option),
- (8, short_channel_id, option),
- (9, confirmations, option),
- (10, channel_value_satoshis, required),
- (12, unspendable_punishment_reserve, option),
- (14, user_channel_id_low, required),
- (16, balance_msat, required),
- (18, outbound_capacity_msat, required),
- // Note that by the time we get past the required read above, outbound_capacity_msat will be
- // filled in, so we can safely unwrap it here.
- (19, next_outbound_htlc_limit_msat, (default_value, outbound_capacity_msat.0.unwrap() as u64)),
- (20, inbound_capacity_msat, required),
- (21, next_outbound_htlc_minimum_msat, (default_value, 0)),
- (22, confirmations_required, option),
- (24, force_close_spend_delay, option),
- (26, is_outbound, required),
- (28, is_channel_ready, required),
- (30, is_usable, required),
- (32, is_public, required),
- (33, inbound_htlc_minimum_msat, option),
- (35, inbound_htlc_maximum_msat, option),
- (37, user_channel_id_high_opt, option),
- (39, feerate_sat_per_1000_weight, option),
- (41, channel_shutdown_state, option),
- (43, pending_inbound_htlcs, optional_vec),
- (45, pending_outbound_htlcs, optional_vec),
- });
-
- // `user_channel_id` used to be a single u64 value. In order to remain backwards compatible with
- // versions prior to 0.0.113, the u128 is serialized as two separate u64 values.
- let user_channel_id_low: u64 = user_channel_id_low.0.unwrap();
- let user_channel_id = user_channel_id_low as u128 +
- ((user_channel_id_high_opt.unwrap_or(0 as u64) as u128) << 64);
-
- Ok(Self {
- inbound_scid_alias,
- channel_id: channel_id.0.unwrap(),
- channel_type,
- counterparty: counterparty.0.unwrap(),
- outbound_scid_alias,
- funding_txo,
- config,
- short_channel_id,
- channel_value_satoshis: channel_value_satoshis.0.unwrap(),
- unspendable_punishment_reserve,
- user_channel_id,
- balance_msat: balance_msat.0.unwrap(),
- outbound_capacity_msat: outbound_capacity_msat.0.unwrap(),
- next_outbound_htlc_limit_msat: next_outbound_htlc_limit_msat.0.unwrap(),
- next_outbound_htlc_minimum_msat: next_outbound_htlc_minimum_msat.0.unwrap(),
- inbound_capacity_msat: inbound_capacity_msat.0.unwrap(),
- confirmations_required,
- confirmations,
- force_close_spend_delay,
- is_outbound: is_outbound.0.unwrap(),
- is_channel_ready: is_channel_ready.0.unwrap(),
- is_usable: is_usable.0.unwrap(),
- is_public: is_public.0.unwrap(),
- inbound_htlc_minimum_msat,
- inbound_htlc_maximum_msat,
- feerate_sat_per_1000_weight,
- channel_shutdown_state,
- pending_inbound_htlcs: pending_inbound_htlcs.unwrap_or(Vec::new()),
- pending_outbound_htlcs: pending_outbound_htlcs.unwrap_or(Vec::new()),
- })
- }
-}
-
impl_writeable_tlv_based!(PhantomRouteHints, {
(2, channels, required_vec),
(4, phantom_scid, required),
}
}
-impl_writeable_tlv_based_enum!(ChannelShutdownState,
- (0, NotShuttingDown) => {},
- (2, ShutdownInitiated) => {},
- (4, ResolvingHTLCs) => {},
- (6, NegotiatingClosingFee) => {},
- (8, ShutdownComplete) => {}, ;
-);
-
/// Arguments for the creation of a ChannelManager that are not deserialized.
///
/// At a high-level, the process for deserializing a ChannelManager and resuming normal operation
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
-
- nodes[0].node.force_close_broadcasting_latest_txn(&chan.2, &nodes[1].node.get_our_node_id()).unwrap();
+ let error_message = "Channel force-closed";
+ nodes[0].node.force_close_broadcasting_latest_txn(&chan.2, &nodes[1].node.get_our_node_id(), error_message.to_string()).unwrap();
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
check_closed_event!(nodes[0], 1, ClosureReason::HolderForceClosed, [nodes[1].node.get_our_node_id()], 100000);
let channel_id = ChannelId::from_bytes([4; 32]);
let unkown_public_key = PublicKey::from_secret_key(&Secp256k1::signing_only(), &SecretKey::from_slice(&[42; 32]).unwrap());
let intercept_id = InterceptId([0; 32]);
+ let error_message = "Channel force-closed";
// 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.close_channel(&channel_id, &unkown_public_key), unkown_public_key);
- check_unkown_peer_error(nodes[0].node.force_close_broadcasting_latest_txn(&channel_id, &unkown_public_key), unkown_public_key);
+ check_unkown_peer_error(nodes[0].node.force_close_broadcasting_latest_txn(&channel_id, &unkown_public_key, error_message.to_string()), unkown_public_key);
- check_unkown_peer_error(nodes[0].node.force_close_without_broadcasting_txn(&channel_id, &unkown_public_key), unkown_public_key);
+ check_unkown_peer_error(nodes[0].node.force_close_without_broadcasting_txn(&channel_id, &unkown_public_key, error_message.to_string()), unkown_public_key);
check_unkown_peer_error(nodes[0].node.forward_intercepted_htlc(intercept_id, &channel_id, unkown_public_key, 1_000_000), unkown_public_key);
// Dummy values
let channel_id = ChannelId::from_bytes([4; 32]);
+ 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_channel_unavailable_error(nodes[0].node.close_channel(&channel_id, &counterparty_node_id), channel_id, counterparty_node_id);
- check_channel_unavailable_error(nodes[0].node.force_close_broadcasting_latest_txn(&channel_id, &counterparty_node_id), channel_id, counterparty_node_id);
+ check_channel_unavailable_error(nodes[0].node.force_close_broadcasting_latest_txn(&channel_id, &counterparty_node_id, error_message.to_string()), channel_id, counterparty_node_id);
- check_channel_unavailable_error(nodes[0].node.force_close_without_broadcasting_txn(&channel_id, &counterparty_node_id), channel_id, counterparty_node_id);
+ check_channel_unavailable_error(nodes[0].node.force_close_without_broadcasting_txn(&channel_id, &counterparty_node_id, error_message.to_string()), channel_id, counterparty_node_id);
check_channel_unavailable_error(nodes[0].node.forward_intercepted_htlc(InterceptId([0; 32]), &channel_id, counterparty_node_id, 1_000_000), channel_id, counterparty_node_id);
anchors_config.manually_accept_inbound_channels = true;
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(anchors_config.clone()), Some(anchors_config.clone())]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+ let error_message = "Channel force-closed";
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 0, None, None).unwrap();
let open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
let events = nodes[1].node.get_and_clear_pending_events();
match events[0] {
Event::OpenChannelRequest { temporary_channel_id, .. } => {
- nodes[1].node.force_close_broadcasting_latest_txn(&temporary_channel_id, &nodes[0].node.get_our_node_id()).unwrap();
+ nodes[1].node.force_close_broadcasting_latest_txn(&temporary_channel_id, &nodes[0].node.get_our_node_id(), error_message.to_string()).unwrap();
}
_ => panic!("Unexpected event"),
}
let user_config = test_default_channel_config();
let node_chanmgr = create_node_chanmgrs(2, &node_cfg, &[Some(user_config), Some(user_config)]);
let nodes = create_network(2, &node_cfg, &node_chanmgr);
+ let error_message = "Channel force-closed";
// Open a channel, immediately disconnect each other, and broadcast Alice's latest state.
let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1);
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
- nodes[0].node.force_close_broadcasting_latest_txn(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
+ nodes[0].node.force_close_broadcasting_latest_txn(&chan_id, &nodes[1].node.get_our_node_id(), error_message.to_string()).unwrap();
check_closed_broadcast(&nodes[0], 1, true);
check_added_monitors(&nodes[0], 1);
check_closed_event!(nodes[0], 1, ClosureReason::HolderForceClosed, [nodes[1].node.get_our_node_id()], 100000);