Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ interface Node {
[Throws=NodeError]
UserChannelId open_announced_channel(PublicKey node_id, SocketAddress address, u64 channel_amount_sats, u64? push_to_counterparty_msat, ChannelConfig? channel_config);
[Throws=NodeError]
void splice_in([ByRef]UserChannelId user_channel_id, PublicKey counterparty_node_id, u64 splice_amount_sats);
[Throws=NodeError]
void splice_out([ByRef]UserChannelId user_channel_id, PublicKey counterparty_node_id, Address address, u64 splice_amount_sats);
[Throws=NodeError]
void close_channel([ByRef]UserChannelId user_channel_id, PublicKey counterparty_node_id);
[Throws=NodeError]
void force_close_channel([ByRef]UserChannelId user_channel_id, PublicKey counterparty_node_id, string? reason);
Expand Down Expand Up @@ -280,6 +284,7 @@ enum NodeError {
"ProbeSendingFailed",
"ChannelCreationFailed",
"ChannelClosingFailed",
"ChannelSplicingFailed",
"ChannelConfigUpdateFailed",
"PersistenceFailed",
"FeerateEstimationUpdateFailed",
Expand Down Expand Up @@ -382,8 +387,10 @@ interface Event {
PaymentForwarded(ChannelId prev_channel_id, ChannelId next_channel_id, UserChannelId?
prev_user_channel_id, UserChannelId? next_user_channel_id, PublicKey? prev_node_id, PublicKey? next_node_id, u64? total_fee_earned_msat, u64? skimmed_fee_msat, boolean claim_from_onchain_tx, u64? outbound_amount_forwarded_msat);
ChannelPending(ChannelId channel_id, UserChannelId user_channel_id, ChannelId former_temporary_channel_id, PublicKey counterparty_node_id, OutPoint funding_txo);
ChannelReady(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id);
ChannelReady(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id, OutPoint? funding_txo);
ChannelClosed(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id, ClosureReason? reason);
SplicePending(ChannelId channel_id, UserChannelId user_channel_id, PublicKey counterparty_node_id, OutPoint new_funding_txo);
SpliceFailed(ChannelId channel_id, UserChannelId user_channel_id, PublicKey counterparty_node_id, OutPoint? abandoned_funding_txo);
};

enum PaymentFailureReason {
Expand Down
1 change: 1 addition & 0 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1718,6 +1718,7 @@ fn build_with_store_internal(
wallet,
chain_source,
tx_broadcaster,
fee_estimator,
event_queue,
channel_manager,
chain_monitor,
Expand Down
14 changes: 13 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ pub const WALLET_KEYS_SEED_LEN: usize = 64;
/// | `probing_liquidity_limit_multiplier` | 3 |
/// | `log_level` | Debug |
/// | `anchor_channels_config` | Some(..) |
/// | `route_parameters` | None |
/// | `route_parameters` | None |
/// | `reject_inbound_splices` | true |
///
/// See [`AnchorChannelsConfig`] and [`RouteParametersConfig`] for more information regarding their
/// respective default values.
Expand Down Expand Up @@ -178,6 +179,15 @@ pub struct Config {
/// **Note:** If unset, default parameters will be used, and you will be able to override the
/// parameters on a per-payment basis in the corresponding method calls.
pub route_parameters: Option<RouteParametersConfig>,
/// If this is set to `true`, then inbound channel splice requests will be rejected. This
/// ensures backwards compatibility is not broken with LDK Node v0.6 or prior while a splice is
/// pending.
///
/// Outbound channel splice requests (via [`Node`] methods, an opt-in API) are still allowed as
/// users should be aware of the backwards compatibility risk prior to using the functionality.
///
/// [`Node`]: crate::Node
pub reject_inbound_splices: bool,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, contrary to the docs here and in LDK, this flag is necessary to still support downgrades, i.e., forwards, not backwards compatibility (we might want to fix this/make this more clear in the LDK docs).

However, we currently don't support downgrades in LDK Node anyways, so here we can just omit this flag.

}

impl Default for Config {
Expand All @@ -192,6 +202,7 @@ impl Default for Config {
anchor_channels_config: Some(AnchorChannelsConfig::default()),
route_parameters: None,
node_alias: None,
reject_inbound_splices: true,
}
}
}
Expand Down Expand Up @@ -319,6 +330,7 @@ pub(crate) fn default_user_config(config: &Config) -> UserConfig {
user_config.manually_accept_inbound_channels = true;
user_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx =
config.anchor_channels_config.is_some();
user_config.reject_inbound_splices = config.reject_inbound_splices;

if may_announce_channel(config).is_err() {
user_config.accept_forwards_to_priv_channels = false;
Expand Down
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub enum Error {
ChannelCreationFailed,
/// A channel could not be closed.
ChannelClosingFailed,
/// A channel could not be spliced.
ChannelSplicingFailed,
/// A channel configuration could not be updated.
ChannelConfigUpdateFailed,
/// Persistence failed.
Expand Down Expand Up @@ -145,6 +147,7 @@ impl fmt::Display for Error {
Self::ProbeSendingFailed => write!(f, "Failed to send the given payment probe."),
Self::ChannelCreationFailed => write!(f, "Failed to create channel."),
Self::ChannelClosingFailed => write!(f, "Failed to close channel."),
Self::ChannelSplicingFailed => write!(f, "Failed to splice channel."),
Self::ChannelConfigUpdateFailed => write!(f, "Failed to update channel config."),
Self::PersistenceFailed => write!(f, "Failed to persist data."),
Self::FeerateEstimationUpdateFailed => {
Expand Down
186 changes: 167 additions & 19 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ pub enum Event {
funding_txo: OutPoint,
},
/// A channel is ready to be used.
///
/// This event is emitted when:
/// - A new channel has been established and is ready for use
/// - An existing channel has been spliced and is ready with the new funding output
ChannelReady {
/// The `channel_id` of the channel.
channel_id: ChannelId,
Expand All @@ -208,6 +212,14 @@ pub enum Event {
///
/// This will be `None` for events serialized by LDK Node v0.1.0 and prior.
counterparty_node_id: Option<PublicKey>,
/// The outpoint of the channel's funding transaction.
///
/// This represents the channel's current funding output, which may change when the
/// channel is spliced. For spliced channels, this will contain the new funding output
/// from the confirmed splice transaction.
///
/// This will be `None` for events serialized by LDK Node v0.6.0 and prior.
funding_txo: Option<OutPoint>,
},
/// A channel has been closed.
ChannelClosed {
Expand All @@ -222,6 +234,28 @@ pub enum Event {
/// This will be `None` for events serialized by LDK Node v0.2.1 and prior.
reason: Option<ClosureReason>,
},
/// A channel splice is pending confirmation on-chain.
SplicePending {
/// The `channel_id` of the channel.
channel_id: ChannelId,
/// The `user_channel_id` of the channel.
user_channel_id: UserChannelId,
/// The `node_id` of the channel counterparty.
counterparty_node_id: PublicKey,
/// The outpoint of the channel's splice funding transaction.
new_funding_txo: OutPoint,
},
/// A channel splice has failed.
SpliceFailed {
/// The `channel_id` of the channel.
channel_id: ChannelId,
/// The `user_channel_id` of the channel.
user_channel_id: UserChannelId,
/// The `node_id` of the channel counterparty.
counterparty_node_id: PublicKey,
/// The outpoint of the channel's splice funding transaction.
abandoned_funding_txo: Option<OutPoint>,
},
}

impl_writeable_tlv_based_enum!(Event,
Expand All @@ -246,6 +280,7 @@ impl_writeable_tlv_based_enum!(Event,
(0, channel_id, required),
(1, counterparty_node_id, option),
(2, user_channel_id, required),
(3, funding_txo, option),
},
(4, ChannelPending) => {
(0, channel_id, required),
Expand Down Expand Up @@ -278,7 +313,19 @@ impl_writeable_tlv_based_enum!(Event,
(10, skimmed_fee_msat, option),
(12, claim_from_onchain_tx, required),
(14, outbound_amount_forwarded_msat, option),
}
},
(8, SplicePending) => {
(1, channel_id, required),
(3, counterparty_node_id, required),
(5, user_channel_id, required),
(7, new_funding_txo, required),
},
(9, SpliceFailed) => {
(1, channel_id, required),
(3, counterparty_node_id, required),
(5, user_channel_id, required),
(7, abandoned_funding_txo, option),
},
);

pub struct EventQueue<L: Deref>
Expand Down Expand Up @@ -1381,14 +1428,28 @@ where
}
},
LdkEvent::ChannelReady {
channel_id, user_channel_id, counterparty_node_id, ..
channel_id,
user_channel_id,
counterparty_node_id,
funding_txo,
..
} => {
log_info!(
self.logger,
"Channel {} with counterparty {} ready to be used.",
channel_id,
counterparty_node_id,
);
if let Some(funding_txo) = funding_txo {
log_info!(
self.logger,
"Channel {} with counterparty {} ready to be used with funding_txo {}",
channel_id,
counterparty_node_id,
funding_txo,
);
} else {
log_info!(
self.logger,
"Channel {} with counterparty {} ready to be used",
channel_id,
counterparty_node_id,
);
}

if let Some(liquidity_source) = self.liquidity_source.as_ref() {
liquidity_source
Expand All @@ -1400,6 +1461,7 @@ where
channel_id,
user_channel_id: UserChannelId(user_channel_id),
counterparty_node_id: Some(counterparty_node_id),
funding_txo,
};
match self.event_queue.add_event(event) {
Ok(_) => {},
Expand Down Expand Up @@ -1598,20 +1660,104 @@ where
}
}
},
LdkEvent::FundingTransactionReadyForSigning { .. } => {
debug_assert!(false, "We currently don't support interactive-tx, so this event should never be emitted.");
},
LdkEvent::SplicePending { .. } => {
debug_assert!(
false,
"We currently don't support splicing, so this event should never be emitted."
LdkEvent::FundingTransactionReadyForSigning {
channel_id,
counterparty_node_id,
unsigned_transaction,
..
} => {
let partially_signed_tx =
self.wallet.sign_owned_inputs(unsigned_transaction).map_err(|()| {
log_error!(self.logger, "Failed signing funding transaction");
ReplayEvent()
})?;

self.channel_manager
.funding_transaction_signed(
&channel_id,
&counterparty_node_id,
partially_signed_tx,
)
.map_err(|e| {
log_error!(self.logger, "Failed signing funding transaction: {:?}", e);
ReplayEvent()
})?;

log_info!(
self.logger,
"Signed funding transaction for channel {} with counterparty {}",
channel_id,
counterparty_node_id
);
},
LdkEvent::SpliceFailed { .. } => {
debug_assert!(
false,
"We currently don't support splicing, so this event should never be emitted."
LdkEvent::SplicePending {
channel_id,
user_channel_id,
counterparty_node_id,
new_funding_txo,
..
} => {
log_info!(
self.logger,
"Channel {} with counterparty {} pending splice with funding_txo {}",
channel_id,
counterparty_node_id,
new_funding_txo,
);

let event = Event::SplicePending {
channel_id,
user_channel_id: UserChannelId(user_channel_id),
counterparty_node_id,
new_funding_txo,
};

match self.event_queue.add_event(event) {
Ok(_) => {},
Err(e) => {
log_error!(self.logger, "Failed to push to event queue: {}", e);
return Err(ReplayEvent());
},
};
},
LdkEvent::SpliceFailed {
channel_id,
user_channel_id,
counterparty_node_id,
abandoned_funding_txo,
..
} => {
if let Some(funding_txo) = abandoned_funding_txo {
log_info!(
self.logger,
"Channel {} with counterparty {} failed splice with funding_txo {}",
channel_id,
counterparty_node_id,
funding_txo,
);
} else {
log_info!(
self.logger,
"Channel {} with counterparty {} failed splice",
channel_id,
counterparty_node_id,
);
}

let event = Event::SpliceFailed {
channel_id,
user_channel_id: UserChannelId(user_channel_id),
counterparty_node_id,
abandoned_funding_txo,
};

match self.event_queue.add_event(event) {
Ok(_) => {},
Err(e) => {
log_error!(self.logger, "Failed to push to event queue: {}", e);
return Err(ReplayEvent());
},
};
},
}
Ok(())
Expand All @@ -1638,6 +1784,7 @@ mod tests {
channel_id: ChannelId([23u8; 32]),
user_channel_id: UserChannelId(2323),
counterparty_node_id: None,
funding_txo: None,
};
event_queue.add_event(expected_event.clone()).unwrap();

Expand Down Expand Up @@ -1675,6 +1822,7 @@ mod tests {
channel_id: ChannelId([23u8; 32]),
user_channel_id: UserChannelId(2323),
counterparty_node_id: None,
funding_txo: None,
};

// Check `next_event_async` won't return if the queue is empty and always rather timeout.
Expand Down
Loading