Skip to content

Commit

Permalink
Code refactor shutdown flow
Browse files Browse the repository at this point in the history
  • Loading branch information
chenyukang committed Feb 19, 2025
1 parent 051023f commit fff5391
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 157 deletions.
129 changes: 69 additions & 60 deletions src/fiber/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1354,62 +1354,69 @@ where
let transaction = state
.latest_commitment_transaction
.clone()
.expect("latest_commitment_transaction should exist when channel is in ChannelReady of ShuttingDown state");
.expect("latest_commitment_transaction should exist when channel is in ChannelReady of ShuttingDown state")
.into_view();

self.network
.send_message(NetworkActorMessage::new_event(
NetworkActorEvent::CommitmentTransactionPending(transaction, state.get_id()),
NetworkActorEvent::ClosingTransactionPending(
state.get_id(),
self.get_remote_peer_id(),
transaction,
true,
),
))
.expect(ASSUME_NETWORK_ACTOR_ALIVE);

state.update_state(ChannelState::ShuttingDown(
ShuttingDownFlags::WAITING_COMMITMENT_CONFIRMATION,
));
return Ok(());
}

let flags = match state.state {
ChannelState::ChannelReady() => {
debug!("Handling shutdown command in ChannelReady state");
ShuttingDownFlags::empty()
}
_ => {
debug!("Handling shutdown command in state {:?}", &state.state);
return Err(ProcessingChannelError::InvalidState(format!(
"Trying to send shutdown message while in invalid state {:?}",
&state.state
)));
}
};
} else {
let flags = match state.state {
ChannelState::ChannelReady() => {
debug!("Handling shutdown command in ChannelReady state");
ShuttingDownFlags::empty()
}
_ => {
debug!("Handling shutdown command in state {:?}", &state.state);
return Err(ProcessingChannelError::InvalidState(format!(
"Trying to send shutdown message while in invalid state {:?}",
&state.state
)));
}
};

state.check_shutdown_fee_rate(command.fee_rate, &command.close_script)?;
self.network
.send_message(NetworkActorMessage::new_command(
NetworkActorCommand::SendFiberMessage(FiberMessageWithPeerId::new(
self.get_remote_peer_id(),
FiberMessage::shutdown(Shutdown {
channel_id: state.get_id(),
close_script: command.close_script.clone(),
fee_rate: command.fee_rate,
}),
)),
))
.expect(ASSUME_NETWORK_ACTOR_ALIVE);
state.check_shutdown_fee_rate(command.fee_rate, &command.close_script)?;
self.network
.send_message(NetworkActorMessage::new_command(
NetworkActorCommand::SendFiberMessage(FiberMessageWithPeerId::new(
self.get_remote_peer_id(),
FiberMessage::shutdown(Shutdown {
channel_id: state.get_id(),
close_script: command.close_script.clone(),
fee_rate: command.fee_rate,
}),
)),
))
.expect(ASSUME_NETWORK_ACTOR_ALIVE);

let shutdown_info = ShutdownInfo {
close_script: command.close_script,
fee_rate: command.fee_rate.as_u64(),
signature: None,
};
state.local_shutdown_info = Some(shutdown_info);
state.update_state(ChannelState::ShuttingDown(
flags | ShuttingDownFlags::OUR_SHUTDOWN_SENT,
));
debug!(
"Channel state updated to {:?} after processing shutdown command",
&state.state
);
let shutdown_info = ShutdownInfo {
close_script: command.close_script,
fee_rate: command.fee_rate.as_u64(),
signature: None,
};
state.local_shutdown_info = Some(shutdown_info);
state.update_state(ChannelState::ShuttingDown(
flags | ShuttingDownFlags::OUR_SHUTDOWN_SENT,
));
debug!(
"Channel state updated to {:?} after processing shutdown command",
&state.state
);

state.maybe_transition_to_shutdown(&self.network)
state.maybe_transition_to_shutdown(&self.network)
}
}

pub async fn handle_update_command(
Expand Down Expand Up @@ -1932,26 +1939,28 @@ where
state.update_state(ChannelState::AwaitingChannelReady(flags));
state.maybe_channel_is_ready(&self.network).await;
}
ChannelEvent::CommitmentTransactionConfirmed => {
match state.state {
ChannelState::ShuttingDown(flags)
if flags.contains(ShuttingDownFlags::WAITING_COMMITMENT_CONFIRMATION) => {}
_ => {
return Err(ProcessingChannelError::InvalidState(format!(
"Expecting commitment transaction confirmed event in state ShuttingDown, but got state {:?}", &state.state)
));
}
};
state.update_state(ChannelState::Closed(CloseFlags::UNCOOPERATIVE));
debug!("Channel closed with uncooperative close");
}
ChannelEvent::CheckTlcRetryOperation => {
self.apply_retryable_tlc_operations(myself, state).await;
}
ChannelEvent::PeerDisconnected => {
myself.stop(Some("PeerDisconnected".to_string()));
}
ChannelEvent::ClosingTransactionConfirmed => {
ChannelEvent::ClosingTransactionConfirmed(force) => {
if force {
match state.state {
ChannelState::ShuttingDown(flags)
if flags
.contains(ShuttingDownFlags::WAITING_COMMITMENT_CONFIRMATION) => {}
_ => {
return Err(ProcessingChannelError::InvalidState(format!(
"Expecting commitment transaction confirmed event in state ShuttingDown, but got state {:?}", &state.state)
));
}
};
state.update_state(ChannelState::Closed(CloseFlags::UNCOOPERATIVE));
debug!("Channel closed with uncooperative close");
}

// Broadcast the channel update message which disables the channel.
if state.is_public() {
let update = state.generate_disabled_channel_update(&self.network).await;
Expand Down Expand Up @@ -3283,8 +3292,7 @@ pub struct ClosedChannel {}
pub enum ChannelEvent {
PeerDisconnected,
FundingTransactionConfirmed(H256, u32, u64),
CommitmentTransactionConfirmed,
ClosingTransactionConfirmed,
ClosingTransactionConfirmed(bool),
CheckTlcRetryOperation,
}

Expand Down Expand Up @@ -5424,6 +5432,7 @@ impl ChannelActorState {
self.get_id(),
self.get_remote_peer_id(),
tx,
false,
),
))
.expect(ASSUME_NETWORK_ACTOR_ALIVE);
Expand Down
119 changes: 22 additions & 97 deletions src/fiber/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,8 +615,8 @@ pub enum NetworkActorEvent {
),
/// A channel is ready to use.
ChannelReady(Hash256, PeerId, OutPoint),
/// A channel is already closed.
ClosingTransactionPending(Hash256, PeerId, TransactionView),
/// A channel is going to be closed, waiting the closing transaction to be broadcasted and confirmed.
ClosingTransactionPending(Hash256, PeerId, TransactionView, bool),

/// Both parties are now able to broadcast a valid funding transaction.
FundingTransactionPending(Transaction, OutPoint, Hash256),
Expand All @@ -628,17 +628,8 @@ pub enum NetworkActorEvent {
/// A funding transaction has failed.
FundingTransactionFailed(OutPoint),

/// Channel is going to be closed forcely, and the closing transaction is ready to be broadcasted.
CommitmentTransactionPending(Transaction, Hash256),

/// A commitment transaction is broacasted successfully.
CommitmentTransactionConfirmed(Hash256, Hash256),

/// A commitment transaction is failed to be broacasted.
CommitmentTransactionFailed(Hash256, Byte32),

/// A closing transaction has been confirmed.
ClosingTransactionConfirmed(PeerId, Hash256, Byte32),
ClosingTransactionConfirmed(PeerId, Hash256, Byte32, bool),

/// A closing transaction has failed (either because of invalid transaction or timeout)
ClosingTransactionFailed(PeerId, Hash256, Byte32),
Expand Down Expand Up @@ -901,33 +892,17 @@ where
.on_funding_transaction_confirmed(outpoint, block_hash, tx_index, timestamp)
.await;
}
NetworkActorEvent::CommitmentTransactionPending(transaction, channel_id) => {
state
.on_commitment_transaction_pending(transaction, channel_id)
.await;
}
NetworkActorEvent::CommitmentTransactionConfirmed(tx_hash, channel_id) => {
state
.on_commitment_transaction_confirmed(tx_hash, channel_id)
.await;
}
NetworkActorEvent::CommitmentTransactionFailed(tx_hash, channel_id) => {
error!(
"Commitment transaction failed for channel {:?}, tx hash: {:?}",
channel_id, tx_hash
);
}
NetworkActorEvent::FundingTransactionFailed(outpoint) => {
error!("Funding transaction failed: {:?}", outpoint);
}
NetworkActorEvent::ClosingTransactionPending(channel_id, peer_id, tx) => {
NetworkActorEvent::ClosingTransactionPending(channel_id, peer_id, tx, force) => {
state
.on_closing_transaction_pending(channel_id, peer_id.clone(), tx.clone())
.on_closing_transaction_pending(channel_id, peer_id.clone(), tx.clone(), force)
.await;
}
NetworkActorEvent::ClosingTransactionConfirmed(peer_id, channel_id, tx_hash) => {
NetworkActorEvent::ClosingTransactionConfirmed(peer_id, channel_id, tx_hash, force) => {
state
.on_closing_transaction_confirmed(&peer_id, &channel_id, tx_hash)
.on_closing_transaction_confirmed(&peer_id, &channel_id, tx_hash, force)
.await;
}
NetworkActorEvent::ClosingTransactionFailed(peer_id, tx_hash, channel_id) => {
Expand Down Expand Up @@ -2485,12 +2460,16 @@ where
let transaction = state
.latest_commitment_transaction
.clone()
.expect("latest_commitment_transaction should exist when channel is in ChannelReady of ShuttingDown state");
.expect("latest_commitment_transaction should exist when channel is in ChannelReady of ShuttingDown state")
.into_view();

self.network
.send_message(NetworkActorMessage::new_event(
NetworkActorEvent::CommitmentTransactionPending(
NetworkActorEvent::ClosingTransactionPending(
state.get_id(),
state.get_remote_peer_id(),
transaction,
channel_id,
true,
),
))
.expect(ASSUME_NETWORK_ACTOR_ALIVE);
Expand Down Expand Up @@ -2670,11 +2649,12 @@ where
channel_id: Hash256,
peer_id: PeerId,
transaction: TransactionView,
force: bool,
) {
let tx_hash: Byte32 = transaction.hash();
info!(
"Channel ({:?}) to peer {:?} is closed. Broadcasting closing transaction ({:?}) now.",
&channel_id, &peer_id, &tx_hash
"Channel ({:?}) to peer {:?} is closed {:?}. Broadcasting closing transaction ({:?}) now.",
&channel_id, &peer_id, &tx_hash, if force { "forcefully" } else { "cooperatively" }
);
let network: ActorRef<NetworkActorMessage> = self.network.clone();
self.broadcast_tx_with_callback(transaction, move |result| {
Expand All @@ -2688,7 +2668,9 @@ where
..
}) => {
info!("Cloisng transaction {:?} confirmed", &tx_hash);
NetworkActorEvent::ClosingTransactionConfirmed(peer_id, channel_id, tx_hash)
NetworkActorEvent::ClosingTransactionConfirmed(
peer_id, channel_id, tx_hash, force,
)
}
Ok(status) => {
error!(
Expand All @@ -2714,11 +2696,12 @@ where
peer_id: &PeerId,
channel_id: &Hash256,
tx_hash: Byte32,
force: bool,
) {
self.send_message_to_channel_actor(
*channel_id,
None,
ChannelActorMessage::Event(ChannelEvent::ClosingTransactionConfirmed),
ChannelActorMessage::Event(ChannelEvent::ClosingTransactionConfirmed(force)),
)
.await;
self.remove_channel(channel_id);
Expand Down Expand Up @@ -2877,54 +2860,6 @@ where
.await;
}

async fn on_commitment_transaction_pending(
&mut self,
transaction: Transaction,
channel_id: Hash256,
) {
let transaction = transaction.into_view();
let tx_hash: Byte32 = transaction.hash();
debug!(
"Commitment transaction for channel {:?} is now ready. Broadcast it {:?} now.",
&channel_id, &tx_hash
);

let network = self.network.clone();
self.broadcast_tx_with_callback(transaction, move |result| {
let message = match result {
Ok(TraceTxResponse {
status:
TxStatus {
status: Status::Committed,
..
},
..
}) => {
info!("Commitment transaction {:?} confirmed", tx_hash,);
NetworkActorEvent::CommitmentTransactionConfirmed(tx_hash.into(), channel_id)
}
Ok(status) => {
error!(
"Commitment transaction {:?} failed to be confirmed with final status {:?}",
&tx_hash, &status
);
NetworkActorEvent::CommitmentTransactionFailed(channel_id, tx_hash)
}
Err(err) => {
error!(
"Failed to trace commitment transaction {:?}: {:?}",
&tx_hash, &err
);
NetworkActorEvent::CommitmentTransactionFailed(channel_id, tx_hash)
}
};
network
.send_message(NetworkActorMessage::new_event(message))
.expect(ASSUME_NETWORK_MYSELF_ALIVE);
})
.await;
}

async fn on_funding_transaction_confirmed(
&mut self,
outpoint: OutPoint,
Expand Down Expand Up @@ -2953,16 +2888,6 @@ where
.await;
}

async fn on_commitment_transaction_confirmed(&mut self, tx_hash: Hash256, channel_id: Hash256) {
debug!("Commitment transaction is confirmed: {:?}", tx_hash);
self.send_message_to_channel_actor(
channel_id,
None,
ChannelActorMessage::Event(ChannelEvent::CommitmentTransactionConfirmed),
)
.await;
}

async fn send_message_to_channel_actor(
&mut self,
channel_id: Hash256,
Expand Down

0 comments on commit fff5391

Please sign in to comment.