Skip to content

Commit 1156efb

Browse files
authored
Merge pull request #3637 from dunxen/2025-02-interactivesigningstate
Introduce interactive signing state flags for funded states.
2 parents 63a5e03 + b5ac8e8 commit 1156efb

File tree

8 files changed

+396
-124
lines changed

8 files changed

+396
-124
lines changed

fuzz/src/full_stack.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,7 @@ fn two_peer_forwarding_seed() -> Vec<u8> {
10341034
// our network key
10351035
ext_from_hex("0100000000000000000000000000000000000000000000000000000000000000", &mut test);
10361036
// config
1037-
ext_from_hex("0000000000900000000000000000640001000000000001ffff0000000000000000ffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff000000ffffffff00ffff1a000400010000020400000000040200000a08ffffffffffffffff0001000000", &mut test);
1037+
ext_from_hex("0000000000900000000000000000640001000000000001ffff0000000000000000ffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff000000ffffffff00ffff1a000400010000020400000000040200000a08ffffffffffffffff000100000000", &mut test);
10381038

10391039
// new outbound connection with id 0
10401040
ext_from_hex("00", &mut test);
@@ -1550,7 +1550,7 @@ fn gossip_exchange_seed() -> Vec<u8> {
15501550
// our network key
15511551
ext_from_hex("0100000000000000000000000000000000000000000000000000000000000000", &mut test);
15521552
// config
1553-
ext_from_hex("0000000000900000000000000000640001000000000001ffff0000000000000000ffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff000000ffffffff00ffff1a000400010000020400000000040200000a08ffffffffffffffff0001000000", &mut test);
1553+
ext_from_hex("0000000000900000000000000000640001000000000001ffff0000000000000000ffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff000000ffffffff00ffff1a000400010000020400000000040200000a08ffffffffffffffff000100000000", &mut test);
15541554

15551555
// new outbound connection with id 0
15561556
ext_from_hex("00", &mut test);

lightning/src/ln/channel.rs

Lines changed: 251 additions & 90 deletions
Large diffs are not rendered by default.

lightning/src/ln/channelmanager.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3253,7 +3253,7 @@ macro_rules! handle_monitor_update_completion {
32533253
&mut $peer_state.pending_msg_events, $chan, updates.raa,
32543254
updates.commitment_update, updates.order, updates.accepted_htlcs, updates.pending_update_adds,
32553255
updates.funding_broadcastable, updates.channel_ready,
3256-
updates.announcement_sigs, updates.tx_signatures);
3256+
updates.announcement_sigs, updates.tx_signatures, None);
32573257
if let Some(upd) = channel_update {
32583258
$peer_state.pending_msg_events.push(upd);
32593259
}
@@ -7665,10 +7665,10 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
76657665
pending_forwards: Vec<(PendingHTLCInfo, u64)>, pending_update_adds: Vec<msgs::UpdateAddHTLC>,
76667666
funding_broadcastable: Option<Transaction>,
76677667
channel_ready: Option<msgs::ChannelReady>, announcement_sigs: Option<msgs::AnnouncementSignatures>,
7668-
tx_signatures: Option<msgs::TxSignatures>
7668+
tx_signatures: Option<msgs::TxSignatures>, tx_abort: Option<msgs::TxAbort>,
76697669
) -> (Option<(u64, Option<PublicKey>, OutPoint, ChannelId, u128, Vec<(PendingHTLCInfo, u64)>)>, Option<(u64, Vec<msgs::UpdateAddHTLC>)>) {
76707670
let logger = WithChannelContext::from(&self.logger, &channel.context, None);
7671-
log_trace!(logger, "Handling channel resumption for channel {} with {} RAA, {} commitment update, {} pending forwards, {} pending update_add_htlcs, {}broadcasting funding, {} channel ready, {} announcement, {} tx_signatures",
7671+
log_trace!(logger, "Handling channel resumption for channel {} with {} RAA, {} commitment update, {} pending forwards, {} pending update_add_htlcs, {}broadcasting funding, {} channel ready, {} announcement, {} tx_signatures, {} tx_abort",
76727672
&channel.context.channel_id(),
76737673
if raa.is_some() { "an" } else { "no" },
76747674
if commitment_update.is_some() { "a" } else { "no" },
@@ -7677,6 +7677,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
76777677
if channel_ready.is_some() { "sending" } else { "without" },
76787678
if announcement_sigs.is_some() { "sending" } else { "without" },
76797679
if tx_signatures.is_some() { "sending" } else { "without" },
7680+
if tx_abort.is_some() { "sending" } else { "without" },
76807681
);
76817682

76827683
let counterparty_node_id = channel.context.get_counterparty_node_id();
@@ -7710,6 +7711,12 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
77107711
msg,
77117712
});
77127713
}
7714+
if let Some(msg) = tx_abort {
7715+
pending_msg_events.push(MessageSendEvent::SendTxAbort {
7716+
node_id: counterparty_node_id,
7717+
msg,
7718+
});
7719+
}
77137720

77147721
macro_rules! handle_cs { () => {
77157722
if let Some(update) = commitment_update {
@@ -8583,14 +8590,14 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
85838590
match chan_entry.get_mut().as_funded_mut() {
85848591
Some(chan) => {
85858592
let logger = WithChannelContext::from(&self.logger, &chan.context, None);
8586-
let tx_signatures_opt = try_channel_entry!(self, peer_state, chan.tx_signatures(msg, &&logger), chan_entry);
8593+
let (funding_tx_opt, tx_signatures_opt) = try_channel_entry!(self, peer_state, chan.tx_signatures(msg, &&logger), chan_entry);
85878594
if let Some(tx_signatures) = tx_signatures_opt {
85888595
peer_state.pending_msg_events.push(MessageSendEvent::SendTxSignatures {
85898596
node_id: *counterparty_node_id,
85908597
msg: tx_signatures,
85918598
});
85928599
}
8593-
if let Some(ref funding_tx) = chan.context.unbroadcasted_funding(&chan.funding) {
8600+
if let Some(ref funding_tx) = funding_tx_opt {
85948601
self.tx_broadcaster.broadcast_transactions(&[funding_tx]);
85958602
{
85968603
let mut pending_events = self.pending_events.lock().unwrap();
@@ -9491,7 +9498,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
94919498
let need_lnd_workaround = chan.context.workaround_lnd_bug_4006.take();
94929499
let (htlc_forwards, decode_update_add_htlcs) = self.handle_channel_resumption(
94939500
&mut peer_state.pending_msg_events, chan, responses.raa, responses.commitment_update, responses.order,
9494-
Vec::new(), Vec::new(), None, responses.channel_ready, responses.announcement_sigs, None);
9501+
Vec::new(), Vec::new(), None, responses.channel_ready, responses.announcement_sigs,
9502+
responses.tx_signatures, responses.tx_abort);
94959503
debug_assert!(htlc_forwards.is_none());
94969504
debug_assert!(decode_update_add_htlcs.is_none());
94979505
if let Some(upd) = channel_update {
@@ -12006,6 +12014,12 @@ where
1200612014
}
1200712015

1200812016
fn handle_open_channel_v2(&self, counterparty_node_id: PublicKey, msg: &msgs::OpenChannelV2) {
12017+
if !self.init_features().supports_dual_fund() {
12018+
let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
12019+
"Dual-funded channels not supported".to_owned(),
12020+
msg.common_fields.temporary_channel_id.clone())), counterparty_node_id);
12021+
return;
12022+
}
1200912023
// Note that we never need to persist the updated ChannelManager for an inbound
1201012024
// open_channel message - pre-funded channels are never written so there should be no
1201112025
// change to the contents.
@@ -12926,7 +12940,9 @@ pub fn provided_init_features(config: &UserConfig) -> InitFeatures {
1292612940
if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx {
1292712941
features.set_anchors_zero_fee_htlc_tx_optional();
1292812942
}
12929-
features.set_dual_fund_optional();
12943+
if config.enable_dual_funded_channels {
12944+
features.set_dual_fund_optional();
12945+
}
1293012946
// Only signal quiescence support in tests for now, as we don't yet support any
1293112947
// quiescent-dependent protocols (e.g., splicing).
1293212948
#[cfg(any(test, fuzzing))]

lightning/src/ln/dual_funding_tests.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ struct V2ChannelEstablishmentTestSession {
3939
fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession) {
4040
let chanmon_cfgs = create_chanmon_cfgs(2);
4141
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
42-
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
42+
let mut node_1_user_config = test_default_channel_config();
43+
node_1_user_config.enable_dual_funded_channels = true;
44+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(node_1_user_config)]);
4345
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
4446
let logger_a = test_utils::TestLogger::with_id("node a".to_owned());
4547

@@ -206,13 +208,6 @@ fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession)
206208
assert!(events.is_empty());
207209
nodes[1].chain_monitor.complete_sole_pending_chan_update(&channel_id);
208210

209-
let events = nodes[1].node.get_and_clear_pending_events();
210-
assert_eq!(events.len(), 1);
211-
match events[0] {
212-
Event::ChannelPending { channel_id: chan_id, .. } => assert_eq!(chan_id, channel_id),
213-
_ => panic!("Unexpected event"),
214-
};
215-
216211
let tx_signatures_msg = get_event_msg!(
217212
nodes[1],
218213
MessageSendEvent::SendTxSignatures,
@@ -234,6 +229,13 @@ fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession)
234229
},
235230
);
236231

232+
let events = nodes[1].node.get_and_clear_pending_events();
233+
assert_eq!(events.len(), 1);
234+
match events[0] {
235+
Event::ChannelPending { channel_id: chan_id, .. } => assert_eq!(chan_id, channel_id),
236+
_ => panic!("Unexpected event"),
237+
};
238+
237239
// For an inbound channel V2 channel the transaction should be broadcast once receiving a
238240
// tx_signature and applying local tx_signatures:
239241
let broadcasted_txs = nodes[1].tx_broadcaster.txn_broadcast();

lightning/src/ln/interactivetxs.rs

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,18 @@ pub(crate) struct ConstructedTransaction {
189189
holder_sends_tx_signatures_first: bool,
190190
}
191191

192+
impl_writeable_tlv_based!(ConstructedTransaction, {
193+
(1, holder_is_initiator, required),
194+
(3, inputs, required),
195+
(5, outputs, required),
196+
(7, local_inputs_value_satoshis, required),
197+
(9, local_outputs_value_satoshis, required),
198+
(11, remote_inputs_value_satoshis, required),
199+
(13, remote_outputs_value_satoshis, required),
200+
(15, lock_time, required),
201+
(17, holder_sends_tx_signatures_first, required),
202+
});
203+
192204
impl ConstructedTransaction {
193205
fn new(context: NegotiationContext) -> Self {
194206
let local_inputs_value_satoshis = context
@@ -309,25 +321,32 @@ impl ConstructedTransaction {
309321
/// https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#sharing-funding-signatures-tx_signatures
310322
#[derive(Debug, Clone, PartialEq)]
311323
pub(crate) struct InteractiveTxSigningSession {
312-
pub unsigned_tx: ConstructedTransaction,
324+
unsigned_tx: ConstructedTransaction,
313325
holder_sends_tx_signatures_first: bool,
314-
received_commitment_signed: bool,
326+
has_received_commitment_signed: bool,
315327
holder_tx_signatures: Option<TxSignatures>,
316-
counterparty_sent_tx_signatures: bool,
317328
}
318329

319330
impl InteractiveTxSigningSession {
320-
pub fn received_commitment_signed(&mut self) -> Option<TxSignatures> {
321-
self.received_commitment_signed = true;
322-
if self.holder_sends_tx_signatures_first {
323-
self.holder_tx_signatures.clone()
324-
} else {
325-
None
326-
}
331+
pub fn unsigned_tx(&self) -> &ConstructedTransaction {
332+
&self.unsigned_tx
333+
}
334+
335+
pub fn holder_sends_tx_signatures_first(&self) -> bool {
336+
self.holder_sends_tx_signatures_first
337+
}
338+
339+
pub fn has_received_commitment_signed(&self) -> bool {
340+
self.has_received_commitment_signed
341+
}
342+
343+
pub fn holder_tx_signatures(&self) -> &Option<TxSignatures> {
344+
&self.holder_tx_signatures
327345
}
328346

329-
pub fn get_tx_signatures(&self) -> Option<TxSignatures> {
330-
if self.received_commitment_signed {
347+
pub fn received_commitment_signed(&mut self) -> Option<TxSignatures> {
348+
self.has_received_commitment_signed = true;
349+
if self.holder_sends_tx_signatures_first {
331350
self.holder_tx_signatures.clone()
332351
} else {
333352
None
@@ -352,7 +371,6 @@ impl InteractiveTxSigningSession {
352371
return Err(());
353372
}
354373
self.unsigned_tx.add_remote_witnesses(tx_signatures.witnesses.clone());
355-
self.counterparty_sent_tx_signatures = true;
356374

357375
let holder_tx_signatures = if !self.holder_sends_tx_signatures_first {
358376
self.holder_tx_signatures.clone()
@@ -433,6 +451,13 @@ impl InteractiveTxSigningSession {
433451
}
434452
}
435453

454+
impl_writeable_tlv_based!(InteractiveTxSigningSession, {
455+
(1, unsigned_tx, required),
456+
(3, holder_sends_tx_signatures_first, required),
457+
(5, has_received_commitment_signed, required),
458+
(7, holder_tx_signatures, required),
459+
});
460+
436461
#[derive(Debug)]
437462
struct NegotiationContext {
438463
holder_node_id: PublicKey,
@@ -1008,9 +1033,8 @@ macro_rules! define_state_transitions {
10081033
let signing_session = InteractiveTxSigningSession {
10091034
holder_sends_tx_signatures_first: tx.holder_sends_tx_signatures_first,
10101035
unsigned_tx: tx,
1011-
received_commitment_signed: false,
1036+
has_received_commitment_signed: false,
10121037
holder_tx_signatures: None,
1013-
counterparty_sent_tx_signatures: false,
10141038
};
10151039
Ok(NegotiationComplete(signing_session))
10161040
}
@@ -1157,6 +1181,11 @@ enum AddingRole {
11571181
Remote,
11581182
}
11591183

1184+
impl_writeable_tlv_based_enum!(AddingRole,
1185+
(1, Local) => {},
1186+
(3, Remote) => {},
1187+
);
1188+
11601189
/// Represents an input -- local or remote (both have the same fields)
11611190
#[derive(Clone, Debug, Eq, PartialEq)]
11621191
pub struct LocalOrRemoteInput {
@@ -1165,19 +1194,35 @@ pub struct LocalOrRemoteInput {
11651194
prev_output: TxOut,
11661195
}
11671196

1197+
impl_writeable_tlv_based!(LocalOrRemoteInput, {
1198+
(1, serial_id, required),
1199+
(3, input, required),
1200+
(5, prev_output, required),
1201+
});
1202+
11681203
#[derive(Clone, Debug, Eq, PartialEq)]
11691204
pub(crate) enum InteractiveTxInput {
11701205
Local(LocalOrRemoteInput),
11711206
Remote(LocalOrRemoteInput),
11721207
// TODO(splicing) SharedInput should be added
11731208
}
11741209

1210+
impl_writeable_tlv_based_enum!(InteractiveTxInput,
1211+
{1, Local} => (),
1212+
{3, Remote} => (),
1213+
);
1214+
11751215
#[derive(Clone, Debug, Eq, PartialEq)]
11761216
pub(super) struct SharedOwnedOutput {
11771217
tx_out: TxOut,
11781218
local_owned: u64,
11791219
}
11801220

1221+
impl_writeable_tlv_based!(SharedOwnedOutput, {
1222+
(1, tx_out, required),
1223+
(3, local_owned, required),
1224+
});
1225+
11811226
impl SharedOwnedOutput {
11821227
pub fn new(tx_out: TxOut, local_owned: u64) -> SharedOwnedOutput {
11831228
debug_assert!(
@@ -1205,6 +1250,11 @@ pub(super) enum OutputOwned {
12051250
Shared(SharedOwnedOutput),
12061251
}
12071252

1253+
impl_writeable_tlv_based_enum!(OutputOwned,
1254+
{1, Single} => (),
1255+
{3, Shared} => (),
1256+
);
1257+
12081258
impl OutputOwned {
12091259
pub fn tx_out(&self) -> &TxOut {
12101260
match self {
@@ -1259,6 +1309,12 @@ pub(crate) struct InteractiveTxOutput {
12591309
output: OutputOwned,
12601310
}
12611311

1312+
impl_writeable_tlv_based!(InteractiveTxOutput, {
1313+
(1, serial_id, required),
1314+
(3, added_by, required),
1315+
(5, output, required),
1316+
});
1317+
12621318
impl InteractiveTxOutput {
12631319
pub fn tx_out(&self) -> &TxOut {
12641320
self.output.tx_out()

lightning/src/ln/msgs.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,18 @@ pub struct ChannelReestablish {
866866
/// The sender's per-commitment point for their current commitment transaction
867867
pub my_current_per_commitment_point: PublicKey,
868868
/// The next funding transaction ID
869+
///
870+
/// Allows peers to finalize the signing steps of an interactive transaction construction, or
871+
/// safely abort that transaction if it was not signed by one of the peers, who has thus already
872+
/// removed it from its state.
873+
///
874+
/// If we've sent `commtiment_signed` for an interactively constructed transaction
875+
/// during a signing session, but have not received `tx_signatures` we MUST set `next_funding_txid`
876+
/// to the txid of that interactive transaction, else we MUST NOT set it.
877+
///
878+
/// See the spec for further details on this:
879+
/// * `channel_reestablish`-sending node: https:///github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L2466-L2470
880+
/// * `channel_reestablish`-receiving node: https:///github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L2520-L2531
869881
pub next_funding_txid: Option<Txid>,
870882
}
871883

lightning/src/util/config.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,10 @@ pub struct UserConfig {
880880
/// [`ChannelManager::send_payment_for_bolt12_invoice`]: crate::ln::channelmanager::ChannelManager::send_payment_for_bolt12_invoice
881881
/// [`ChannelManager::abandon_payment`]: crate::ln::channelmanager::ChannelManager::abandon_payment
882882
pub manually_handle_bolt12_invoices: bool,
883+
/// If this is set to `true`, dual-funded channels will be enabled.
884+
///
885+
/// Default value: `false`
886+
pub enable_dual_funded_channels: bool,
883887
}
884888

885889
impl Default for UserConfig {
@@ -893,6 +897,7 @@ impl Default for UserConfig {
893897
manually_accept_inbound_channels: false,
894898
accept_intercept_htlcs: false,
895899
manually_handle_bolt12_invoices: false,
900+
enable_dual_funded_channels: false,
896901
}
897902
}
898903
}
@@ -912,6 +917,7 @@ impl Readable for UserConfig {
912917
manually_accept_inbound_channels: Readable::read(reader)?,
913918
accept_intercept_htlcs: Readable::read(reader)?,
914919
manually_handle_bolt12_invoices: Readable::read(reader)?,
920+
enable_dual_funded_channels: Readable::read(reader)?,
915921
})
916922
}
917923
}

0 commit comments

Comments
 (0)