Skip to content

Commit

Permalink
Batch funding for v1 channel establishments
Browse files Browse the repository at this point in the history
  • Loading branch information
wvanlint committed Aug 9, 2023
1 parent 6f58072 commit cc00689
Show file tree
Hide file tree
Showing 4 changed files with 370 additions and 38 deletions.
5 changes: 5 additions & 0 deletions lightning/src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ pub enum ClosureReason {
/// The counterparty requested a cooperative close of a channel that had not been funded yet.
/// The channel has been immediately closed.
CounterpartyCoopClosedUnfundedChannel,
/// Another channel in the same funding batch closed before the funding transaction
/// was ready to be broadcast.
FundingBatchClosure,
}

impl core::fmt::Display for ClosureReason {
Expand All @@ -188,6 +191,7 @@ impl core::fmt::Display for ClosureReason {
ClosureReason::DisconnectedPeer => f.write_str("the peer disconnected prior to the channel being funded"),
ClosureReason::OutdatedChannelManager => f.write_str("the ChannelManager read from disk was stale compared to ChannelMonitor(s)"),
ClosureReason::CounterpartyCoopClosedUnfundedChannel => f.write_str("the peer requested the unfunded channel be closed"),
ClosureReason::FundingBatchClosure => f.write_str("another channel in the same funding batch closed"),
}
}
}
Expand All @@ -202,6 +206,7 @@ impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
(10, DisconnectedPeer) => {},
(12, OutdatedChannelManager) => {},
(13, CounterpartyCoopClosedUnfundedChannel) => {},
(15, FundingBatchClosure) => {}
);

/// Intended destination of a failed HTLC as indicated in [`Event::HTLCHandlingFailed`].
Expand Down
36 changes: 27 additions & 9 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,10 @@ enum ChannelState {
/// We've successfully negotiated a closing_signed dance. At this point ChannelManager is about
/// to drop us, but we store this anyway.
ShutdownComplete = 4096,
/// Flag which is set on `FundingSent` to indicate this channel is funded in a batch and the
/// broadcasting of the funding transaction is being held until all channels in the batch
/// have received funding_signed and have their monitors persisted.
WaitingForBatch = 1 << 13,
}
const BOTH_SIDES_SHUTDOWN_MASK: u32 = ChannelState::LocalShutdownSent as u32 | ChannelState::RemoteShutdownSent as u32;
const MULTI_STATE_FLAGS: u32 = BOTH_SIDES_SHUTDOWN_MASK | ChannelState::PeerDisconnected as u32 | ChannelState::MonitorUpdateInProgress as u32;
Expand Down Expand Up @@ -1198,9 +1202,11 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
did_channel_update
}

/// Returns true if funding_created was sent/received.
/// Returns true if funding_signed was sent/received and the
/// funding transaction has been broadcast if necessary.
pub fn is_funding_initiated(&self) -> bool {
self.channel_state >= ChannelState::FundingSent as u32
self.channel_state >= ChannelState::FundingSent as u32 &&
self.channel_state & ChannelState::WaitingForBatch as u32 == 0
}

/// Transaction nomenclature is somewhat confusing here as there are many different cases - a
Expand Down Expand Up @@ -1940,7 +1946,8 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {

/// Returns transaction if there is pending funding transaction that is yet to broadcast
pub fn unbroadcasted_funding(&self) -> Option<Transaction> {
if self.channel_state & (ChannelState::FundingCreated as u32) != 0 {
if self.channel_state & ChannelState::FundingCreated as u32 != 0 ||
self.channel_state & ChannelState::WaitingForBatch as u32 != 0 {
self.funding_transaction.clone()
} else {
None
Expand Down Expand Up @@ -2487,7 +2494,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
/// Handles a funding_signed message from the remote end.
/// If this call is successful, broadcast the funding transaction (and not before!)
pub fn funding_signed<SP: Deref, L: Deref>(
&mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
&mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, is_batch_funding: bool, logger: &L
) -> Result<ChannelMonitor<Signer>, ChannelError>
where
SP::Target: SignerProvider<Signer = Signer>,
Expand Down Expand Up @@ -2557,7 +2564,11 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
channel_monitor.provide_latest_counterparty_commitment_tx(counterparty_initial_bitcoin_tx.txid, Vec::new(), self.context.cur_counterparty_commitment_transaction_number, self.context.counterparty_cur_commitment_point.unwrap(), logger);

assert_eq!(self.context.channel_state & (ChannelState::MonitorUpdateInProgress as u32), 0); // We have no had any monitor(s) yet to fail update!
self.context.channel_state = ChannelState::FundingSent as u32;
if is_batch_funding {
self.context.channel_state = ChannelState::FundingSent as u32 | ChannelState::WaitingForBatch as u32;
} else {
self.context.channel_state = ChannelState::FundingSent as u32;
}
self.context.cur_holder_commitment_transaction_number -= 1;
self.context.cur_counterparty_commitment_transaction_number -= 1;

Expand All @@ -2568,6 +2579,13 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
Ok(channel_monitor)
}

/// Updates the state of the channel to indicate that all channels in the batch
/// have received funding_signed and persisted their monitors.
/// The funding transaction is consequently allowed to be broadcast.
pub fn set_batch_ready(&mut self) {
self.context.channel_state &= !(ChannelState::WaitingForBatch as u32);
}

/// Handles a channel_ready message from our peer. If we've already sent our channel_ready
/// and the channel is now usable (and public), this may generate an announcement_signatures to
/// reply with.
Expand Down Expand Up @@ -3656,7 +3674,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
// (re-)broadcast the funding transaction as we may have declined to broadcast it when we
// first received the funding_signed.
let mut funding_broadcastable =
if self.context.is_outbound() && self.context.channel_state & !MULTI_STATE_FLAGS >= ChannelState::FundingSent as u32 {
if self.context.is_outbound() && self.context.channel_state & !MULTI_STATE_FLAGS >= ChannelState::FundingSent as u32 && self.context.channel_state & ChannelState::WaitingForBatch as u32 == 0 {
self.context.funding_transaction.take()
} else { None };
// That said, if the funding transaction is already confirmed (ie we're active with a
Expand Down Expand Up @@ -7642,7 +7660,7 @@ mod tests {
let (_, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap();

// Node B --> Node A: funding signed
let _ = node_a_chan.funding_signed(&funding_signed_msg, best_block, &&keys_provider, &&logger).unwrap();
let _ = node_a_chan.funding_signed(&funding_signed_msg, best_block, &&keys_provider, false, &&logger).unwrap();

// Put some inbound and outbound HTLCs in A's channel.
let htlc_amount_msat = 11_092_000; // put an amount below A's effective dust limit but above B's.
Expand Down Expand Up @@ -7769,7 +7787,7 @@ mod tests {
let (mut node_b_chan, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap();

// Node B --> Node A: funding signed
let _ = node_a_chan.funding_signed(&funding_signed_msg, best_block, &&keys_provider, &&logger).unwrap();
let _ = node_a_chan.funding_signed(&funding_signed_msg, best_block, &&keys_provider, false, &&logger).unwrap();

// Now disconnect the two nodes and check that the commitment point in
// Node B's channel_reestablish message is sane.
Expand Down Expand Up @@ -7957,7 +7975,7 @@ mod tests {
let (_, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap();

// Node B --> Node A: funding signed
let _ = node_a_chan.funding_signed(&funding_signed_msg, best_block, &&keys_provider, &&logger).unwrap();
let _ = node_a_chan.funding_signed(&funding_signed_msg, best_block, &&keys_provider, false, &&logger).unwrap();

// Make sure that receiving a channel update will update the Channel as expected.
let update = ChannelUpdate {
Expand Down
Loading

0 comments on commit cc00689

Please sign in to comment.