Skip to content

Commit 6614c65

Browse files
committed
Introduce interactive signing state flags and session persistence
This intoduces the INTERACTIVE_SIGNING, THEIR_TX_SIGNATURES_SENT, and OUR_TX_SIGNATURES_SENT funded state flags. A top-level state flag for INTERACTIVE_SIGNING was avoided so that this work is compatible with splicing as well as V2 channel establishment (dual-funding).
1 parent 2079148 commit 6614c65

File tree

3 files changed

+185
-15
lines changed

3 files changed

+185
-15
lines changed

lightning/src/ln/channel.rs

+69-12
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,12 @@ macro_rules! define_state_flags {
432432
is_remote_shutdown_sent, set_remote_shutdown_sent, clear_remote_shutdown_sent);
433433
define_state_flags!($flag_type, FundedStateFlags::LOCAL_SHUTDOWN_SENT,
434434
is_local_shutdown_sent, set_local_shutdown_sent, clear_local_shutdown_sent);
435+
define_state_flags!($flag_type, FundedStateFlags::INTERACTIVE_SIGNING,
436+
is_interactive_signing, set_interactive_signing, clear_interactive_signing);
437+
define_state_flags!($flag_type, FundedStateFlags::THEIR_TX_SIGNATURES_SENT,
438+
is_their_tx_signatures_sent, set_their_tx_signatures_sent, clear_their_tx_signatures_sent);
439+
define_state_flags!($flag_type, FundedStateFlags::OUR_TX_SIGNATURES_SENT,
440+
is_our_tx_signatures_sent, set_our_tx_signatures_sent, clear_our_tx_signatures_sent);
435441

436442
impl core::ops::BitOr<FundedStateFlags> for $flag_type {
437443
type Output = Self;
@@ -477,6 +483,9 @@ mod state_flags {
477483
pub const LOCAL_STFU_SENT: u32 = 1 << 15;
478484
pub const REMOTE_STFU_SENT: u32 = 1 << 16;
479485
pub const QUIESCENT: u32 = 1 << 17;
486+
pub const INTERACTIVE_SIGNING: u32 = 1 << 18;
487+
pub const OUR_TX_SIGNATURES_SENT: u32 = 1 << 19;
488+
pub const THEIR_TX_SIGNATURES_SENT: u32 = 1 << 20;
480489
}
481490

482491
define_state_flags!(
@@ -495,7 +504,16 @@ define_state_flags!(
495504
is_remote_shutdown_sent, set_remote_shutdown_sent, clear_remote_shutdown_sent),
496505
("Indicates we sent a `shutdown` message. At this point, we may not add any new HTLCs to \
497506
the channel.", LOCAL_SHUTDOWN_SENT, state_flags::LOCAL_SHUTDOWN_SENT,
498-
is_local_shutdown_sent, set_local_shutdown_sent, clear_local_shutdown_sent)
507+
is_local_shutdown_sent, set_local_shutdown_sent, clear_local_shutdown_sent),
508+
("Indicates we have an active interactive signing session for an interactive transaction",
509+
INTERACTIVE_SIGNING, state_flags::INTERACTIVE_SIGNING,
510+
is_interactive_signing, set_interactive_signing, clear_interactive_singing),
511+
("Indicates they sent us a `tx_signatures` message.",
512+
THEIR_TX_SIGNATURES_SENT, state_flags::THEIR_TX_SIGNATURES_SENT,
513+
is_their_tx_signatures_sent, set_their_tx_signatures_sent, clear_their_tx_signatures_sent),
514+
("Indicates we sent them a `tx_signatures` message.",
515+
OUR_TX_SIGNATURES_SENT, state_flags::OUR_TX_SIGNATURES_SENT,
516+
is_our_tx_signatures_sent, set_our_tx_signatures_sent, clear_our_tx_signatures_sent)
499517
]
500518
);
501519

@@ -566,7 +584,8 @@ enum ChannelState {
566584
NegotiatingFunding(NegotiatingFundingFlags),
567585
/// We have sent `funding_created` and are awaiting a `funding_signed` to advance to
568586
/// `AwaitingChannelReady`. Note that this is nonsense for an inbound channel as we immediately generate
569-
/// `funding_signed` upon receipt of `funding_created`, so simply skip this state.
587+
/// `funding_signed` upon receipt of `funding_created`, so simply skip this state. For dual-funded (V2)
588+
/// channels, this state is also skipped.
570589
FundingNegotiated,
571590
/// We've received/sent `funding_created` and `funding_signed` and are thus now waiting on the
572591
/// funding transaction to confirm.
@@ -683,6 +702,9 @@ impl ChannelState {
683702
impl_state_flag!(is_monitor_update_in_progress, set_monitor_update_in_progress, clear_monitor_update_in_progress, FUNDED_STATES);
684703
impl_state_flag!(is_local_shutdown_sent, set_local_shutdown_sent, clear_local_shutdown_sent, FUNDED_STATES);
685704
impl_state_flag!(is_remote_shutdown_sent, set_remote_shutdown_sent, clear_remote_shutdown_sent, FUNDED_STATES);
705+
impl_state_flag!(is_interactive_signing, set_interactive_signing, clear_interactive_signing, FUNDED_STATES);
706+
impl_state_flag!(is_our_tx_signatures_sent, set_our_tx_signatures_sent, clear_our_tx_signatures_sent, FUNDED_STATES);
707+
impl_state_flag!(is_their_tx_signatures_sent, set_their_tx_signatures_sent, clear_their_tx_signatures_sent, FUNDED_STATES);
686708
impl_state_flag!(is_our_channel_ready, set_our_channel_ready, clear_our_channel_ready, AwaitingChannelReady);
687709
impl_state_flag!(is_their_channel_ready, set_their_channel_ready, clear_their_channel_ready, AwaitingChannelReady);
688710
impl_state_flag!(is_waiting_for_batch, set_waiting_for_batch, clear_waiting_for_batch, AwaitingChannelReady);
@@ -2084,10 +2106,15 @@ trait InitialRemoteCommitmentReceiver<SP: Deref> where SP::Target: SignerProvide
20842106
context.channel_id = channel_id;
20852107

20862108
assert!(!context.channel_state.is_monitor_update_in_progress()); // We have not had any monitor(s) yet to fail update!
2087-
if context.is_batch_funding() {
2088-
context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::WAITING_FOR_BATCH);
2089-
} else {
2090-
context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
2109+
if !matches!(
2110+
context.channel_state,
2111+
ChannelState::AwaitingChannelReady(flags) if flags.is_set(FundedStateFlags::INTERACTIVE_SIGNING.into())
2112+
) {
2113+
if context.is_batch_funding() {
2114+
context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::WAITING_FOR_BATCH);
2115+
} else {
2116+
context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
2117+
}
20912118
}
20922119
if holder_commitment_point.advance(&context.holder_signer, &context.secp_ctx, logger).is_err() {
20932120
// We only fail to advance our commitment point/number if we're currently
@@ -2348,7 +2375,9 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
23482375
)));
23492376
};
23502377

2351-
self.context.channel_state = ChannelState::FundingNegotiated;
2378+
let mut channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
2379+
channel_state.set_interactive_signing();
2380+
self.context.channel_state = channel_state;
23522381

23532382
// Clear the interactive transaction constructor
23542383
self.interactive_tx_constructor.take();
@@ -4289,7 +4318,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
42894318
ChannelState::FundingNegotiated => f(),
42904319
ChannelState::AwaitingChannelReady(flags) =>
42914320
if flags.is_set(AwaitingChannelReadyFlags::WAITING_FOR_BATCH) ||
4292-
flags.is_set(FundedStateFlags::MONITOR_UPDATE_IN_PROGRESS.into())
4321+
flags.is_set(FundedStateFlags::MONITOR_UPDATE_IN_PROGRESS.into()) ||
4322+
(flags.is_set(FundedStateFlags::THEIR_TX_SIGNATURES_SENT.into()) && flags.is_set(FundedStateFlags::OUR_TX_SIGNATURES_SENT.into()))
42934323
{
42944324
f()
42954325
} else {
@@ -5440,7 +5470,7 @@ impl<SP: Deref> FundedChannel<SP> where
54405470
) -> Result<ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>, ChannelError>
54415471
where L::Target: Logger
54425472
{
5443-
if !matches!(self.context.channel_state, ChannelState::FundingNegotiated) {
5473+
if !matches!(self.context.channel_state, ChannelState::AwaitingChannelReady(_)) {
54445474
return Err(ChannelError::Close(
54455475
(
54465476
"Received initial commitment_signed before funding transaction constructed!".to_owned(),
@@ -5458,7 +5488,6 @@ impl<SP: Deref> FundedChannel<SP> where
54585488
log_info!(logger, "Received initial commitment_signed from peer for channel {}", &self.context.channel_id());
54595489

54605490
let need_channel_ready = self.check_get_channel_ready(0, logger).is_some();
5461-
self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
54625491
self.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
54635492

54645493
if let Some(tx_signatures) = self.interactive_tx_signing_session.as_mut().and_then(
@@ -6156,7 +6185,7 @@ impl<SP: Deref> FundedChannel<SP> where
61566185
pub fn tx_signatures<L: Deref>(&mut self, msg: &msgs::TxSignatures, logger: &L) -> Result<Option<msgs::TxSignatures>, ChannelError>
61576186
where L::Target: Logger
61586187
{
6159-
if !matches!(self.context.channel_state, ChannelState::AwaitingChannelReady(_)) {
6188+
if !matches!(self.context.channel_state, ChannelState::AwaitingChannelReady(flags) if flags.is_interactive_signing()) {
61606189
return Err(ChannelError::close("Received tx_signatures in strange state!".to_owned()));
61616190
}
61626191

@@ -6201,6 +6230,12 @@ impl<SP: Deref> FundedChannel<SP> where
62016230
self.interactive_tx_signing_session = None;
62026231
}
62036232

6233+
if holder_tx_signatures_opt.is_some() {
6234+
// We set our tx_signatures as sent even if we're waiting for initial monitor persist as
6235+
// we'll eventually send them after persist.
6236+
self.context.channel_state.set_our_tx_signatures_sent();
6237+
}
6238+
62046239
if holder_tx_signatures_opt.is_some() && self.is_awaiting_initial_mon_persist() {
62056240
log_debug!(logger, "Not sending tx_signatures: a monitor update is in progress. Setting monitor_pending_tx_signatures.");
62066241
self.context.monitor_pending_tx_signatures = holder_tx_signatures_opt;
@@ -10348,6 +10383,7 @@ impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider
1034810383
(49, self.context.local_initiated_shutdown, option), // Added in 0.0.122
1034910384
(51, is_manual_broadcast, option), // Added in 0.0.124
1035010385
(53, funding_tx_broadcast_safe_event_emitted, option), // Added in 0.0.124
10386+
(55, self.interactive_tx_signing_session, option) // Added in 0.2
1035110387
});
1035210388

1035310389
Ok(())
@@ -10636,6 +10672,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
1063610672
let mut next_holder_commitment_point_opt: Option<PublicKey> = None;
1063710673
let mut is_manual_broadcast = None;
1063810674

10675+
let mut interactive_tx_signing_session: Option<InteractiveTxSigningSession> = None;
10676+
1063910677
read_tlv_fields!(reader, {
1064010678
(0, announcement_sigs, option),
1064110679
(1, minimum_depth, option),
@@ -10671,6 +10709,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
1067110709
(49, local_initiated_shutdown, option),
1067210710
(51, is_manual_broadcast, option),
1067310711
(53, funding_tx_broadcast_safe_event_emitted, option),
10712+
(55, interactive_tx_signing_session, option),
1067410713
});
1067510714

1067610715
let (channel_keys_id, holder_signer) = if let Some(channel_keys_id) = channel_keys_id {
@@ -10800,6 +10839,24 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
1080010839
&channel_parameters.counterparty_parameters.as_ref()
1080110840
.expect("Persisted channel must have counterparty parameters").pubkeys.revocation_basepoint);
1080210841

10842+
let interactive_tx_signing_session = if matches!(
10843+
channel_state,
10844+
ChannelState::AwaitingChannelReady(flags) if flags.is_set(FundedStateFlags::INTERACTIVE_SIGNING.into())
10845+
) {
10846+
if let Some(mut signing_session) = interactive_tx_signing_session {
10847+
if let Some(ref funding_tx) = funding_transaction {
10848+
signing_session.update_from_funding_tx_after_read(funding_tx);
10849+
Some(signing_session)
10850+
} else {
10851+
None
10852+
}
10853+
} else {
10854+
None
10855+
}
10856+
} else {
10857+
None
10858+
};
10859+
1080310860
Ok(FundedChannel {
1080410861
funding: FundingScope {
1080510862
value_to_self_msat,
@@ -10932,7 +10989,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
1093210989

1093310990
is_holder_quiescence_initiator: None,
1093410991
},
10935-
interactive_tx_signing_session: None,
10992+
interactive_tx_signing_session,
1093610993
is_v2_established,
1093710994
holder_commitment_point,
1093810995
})

lightning/src/ln/interactivetxs.rs

+114-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// licenses.
99

1010
use crate::io_extras::sink;
11-
use crate::prelude::*;
11+
use crate::{io, prelude::*};
1212

1313
use bitcoin::absolute::LockTime as AbsoluteLockTime;
1414
use bitcoin::amount::Amount;
@@ -27,11 +27,13 @@ use crate::ln::msgs;
2727
use crate::ln::msgs::{SerialId, TxSignatures};
2828
use crate::ln::types::ChannelId;
2929
use crate::sign::{EntropySource, P2TR_KEY_PATH_WITNESS_WEIGHT, P2WPKH_WITNESS_WEIGHT};
30-
use crate::util::ser::TransactionU16LenLimited;
30+
use crate::util::ser::{Readable, TransactionU16LenLimited, Writeable, Writer};
3131

3232
use core::fmt::Display;
3333
use core::ops::Deref;
3434

35+
use super::msgs::DecodeError;
36+
3537
/// The number of received `tx_add_input` messages during a negotiation at which point the
3638
/// negotiation MUST be failed.
3739
const MAX_RECEIVED_TX_ADD_INPUT_COUNT: u16 = 4096;
@@ -431,6 +433,116 @@ impl InteractiveTxSigningSession {
431433
output: outputs.iter().cloned().map(|output| output.into_tx_out()).collect(),
432434
}
433435
}
436+
437+
pub fn update_from_funding_tx_after_read(&mut self, funding_tx: &Transaction) {
438+
self.unsigned_tx.inputs.iter_mut().zip(funding_tx.input.iter().cloned()).for_each(
439+
|(placeholder, real)| {
440+
*placeholder.txin_mut() = real;
441+
},
442+
);
443+
self.unsigned_tx.outputs.iter_mut().zip(funding_tx.output.iter().cloned()).for_each(
444+
|(placeholder, real)| {
445+
(*placeholder).output = OutputOwned::Single(real);
446+
},
447+
);
448+
}
449+
}
450+
451+
impl Writeable for InteractiveTxSigningSession {
452+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
453+
self.unsigned_tx.holder_is_initiator.write(writer)?;
454+
self.unsigned_tx.holder_sends_tx_signatures_first.write(writer)?;
455+
self.unsigned_tx
456+
.inputs
457+
.iter()
458+
.map(|input| input.serial_id())
459+
.collect::<Vec<_>>()
460+
.write(writer)?;
461+
self.unsigned_tx
462+
.outputs
463+
.iter()
464+
.map(|output| output.serial_id)
465+
.collect::<Vec<_>>()
466+
.write(writer)?;
467+
self.holder_tx_signatures.write(writer)?;
468+
self.counterparty_sent_tx_signatures.write(writer)?;
469+
self.has_received_commitment_signed.write(writer)?;
470+
Ok(())
471+
}
472+
}
473+
474+
impl Readable for InteractiveTxSigningSession {
475+
fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
476+
let holder_is_initiator: bool = Readable::read(reader)?;
477+
let holder_sends_tx_signatures_first: bool = Readable::read(reader)?;
478+
let inputs: Vec<SerialId> = Readable::read(reader)?;
479+
let outputs: Vec<SerialId> = Readable::read(reader)?;
480+
let holder_tx_signatures: Option<TxSignatures> = Readable::read(reader)?;
481+
let counterparty_sent_tx_signatures: bool = Readable::read(reader)?;
482+
let has_received_commitment_signed: bool = Readable::read(reader)?;
483+
484+
// We use an empty dummy `TxOut` for all `TxOut`s as they will be populated with their real
485+
// values from `funding_transaction` after reading.
486+
let dummy_txout = TxOut { value: Amount::default(), script_pubkey: ScriptBuf::new() };
487+
488+
Ok(InteractiveTxSigningSession {
489+
counterparty_sent_tx_signatures,
490+
holder_sends_tx_signatures_first,
491+
has_received_commitment_signed,
492+
holder_tx_signatures,
493+
unsigned_tx: ConstructedTransaction {
494+
holder_is_initiator,
495+
holder_sends_tx_signatures_first,
496+
inputs: inputs
497+
.into_iter()
498+
.map(|serial_id| {
499+
if is_serial_id_valid_for_counterparty(holder_is_initiator, serial_id) {
500+
InteractiveTxInput::Remote(LocalOrRemoteInput {
501+
serial_id,
502+
input: TxIn::default(),
503+
prev_output: dummy_txout.clone(),
504+
})
505+
} else {
506+
InteractiveTxInput::Local(
507+
// We use a dummy TxOut that will be populated from the funding_transaction after read.
508+
LocalOrRemoteInput {
509+
serial_id,
510+
input: TxIn::default(),
511+
prev_output: dummy_txout.clone(),
512+
},
513+
)
514+
}
515+
})
516+
.collect(),
517+
outputs: outputs
518+
.into_iter()
519+
.map(|serial_id| {
520+
let added_by = if is_serial_id_valid_for_counterparty(
521+
holder_is_initiator,
522+
serial_id,
523+
) {
524+
AddingRole::Remote
525+
} else {
526+
AddingRole::Local
527+
};
528+
InteractiveTxOutput {
529+
serial_id,
530+
added_by,
531+
// The ownership of the output is irrelevant at this point as the read would only happen
532+
// at `ChannelState::InteractiveSigning`, so we just use `Single` here.
533+
output: OutputOwned::Single(dummy_txout.clone()),
534+
}
535+
})
536+
.collect(),
537+
local_inputs_value_satoshis: 0,
538+
local_outputs_value_satoshis: 0,
539+
remote_inputs_value_satoshis: 0,
540+
remote_outputs_value_satoshis: 0,
541+
lock_time: AbsoluteLockTime::from_height(0)
542+
.expect("0 is a valid absolute locktime"),
543+
},
544+
})
545+
}
434546
}
435547

436548
#[derive(Debug)]

lightning/src/util/ser.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ use bitcoin::{consensus, Witness};
4343
use dnssec_prover::rr::Name;
4444

4545
use crate::chain::ClaimId;
46-
use crate::ln::msgs::DecodeError;
4746
#[cfg(taproot)]
4847
use crate::ln::msgs::PartialSignatureWithNonce;
48+
use crate::ln::msgs::{DecodeError, SerialId};
4949
use crate::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
5050
use core::time::Duration;
5151

@@ -1058,6 +1058,7 @@ impl_for_vec!(crate::ln::channelmanager::MonitorUpdateCompletionAction);
10581058
impl_for_vec!(crate::ln::channelmanager::PaymentClaimDetails);
10591059
impl_for_vec!(crate::ln::msgs::SocketAddress);
10601060
impl_for_vec!((A, B), A, B);
1061+
impl_for_vec!(SerialId);
10611062
impl_writeable_for_vec!(&crate::routing::router::BlindedTail);
10621063
impl_readable_for_vec!(crate::routing::router::BlindedTail);
10631064
impl_for_vec!(crate::routing::router::TrampolineHop);

0 commit comments

Comments
 (0)