Skip to content

Commit

Permalink
Handle ClosingSigned
Browse files Browse the repository at this point in the history
  • Loading branch information
contrun committed May 8, 2024
1 parent 9395926 commit 4a0877b
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 4 deletions.
80 changes: 78 additions & 2 deletions src/ckb/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,8 @@ pub struct ChannelActorState {
// The commitment point that is going to be used in the following commitment transaction.
pub counterparty_commitment_point: Option<Pubkey>,
pub counterparty_channel_parameters: Option<ChannelParametersOneParty>,
pub holder_shutdown_signature: Option<PartialSignature>,
pub counterparty_shutdown_signature: Option<PartialSignature>,
}

#[derive(PartialEq, Eq, Clone, Debug)]
Expand Down Expand Up @@ -962,7 +964,7 @@ bitflags! {
/// we and they have sent `shutdown` messages and all HTLCs are resolved.
const THEIR_CLOSING_SIGNED = 1 << 3;
/// Indicates all pending HTLCs are resolved, and this channel will be dropped.
const DROPPING_PENDING = ShuttingDownFlags::AWAITING_PENDING_TLCS.bits() | 1 << 2;
const DROPPING_PENDING = ShuttingDownFlags::AWAITING_PENDING_TLCS.bits() | ShuttingDownFlags::OUR_CLOSING_SIGNED.bits() | ShuttingDownFlags::THEIR_CLOSING_SIGNED.bits();
}
}

Expand Down Expand Up @@ -994,6 +996,8 @@ pub enum ChannelState {
/// We've successfully negotiated a `closing_signed` dance. At this point, the `ChannelManager`
/// is about to drop us, but we store this anyway.
ShuttingDown(ShuttingDownFlags),
/// This channel is closed.
Closed,
}

fn new_channel_id_from_seed(seed: &[u8]) -> Hash256 {
Expand Down Expand Up @@ -1096,6 +1100,8 @@ impl ChannelActorState {
counterparty_nonce: Some(counterparty_nonce),
counterparty_commitment_point: Some(counterparty_commitment_point),
counterparty_initial_commitment_point: Some(counterparty_prev_commitment_point),
holder_shutdown_signature: None,
counterparty_shutdown_signature: None,
}
}

Expand Down Expand Up @@ -1135,6 +1141,8 @@ impl ChannelActorState {
counterparty_initial_commitment_point: None,
holder_shutdown_script: None,
counterparty_shutdown_script: None,
holder_shutdown_signature: None,
counterparty_shutdown_signature: None,
}
}
}
Expand Down Expand Up @@ -1199,7 +1207,6 @@ impl ChannelActorState {
.funding_tx
.as_ref()
.expect("Funding transaction is present");
dbg!(&tx);
// By convention, the funding tx output for the channel is the first output.
tx.output_pts_iter()
.next()
Expand Down Expand Up @@ -1526,6 +1533,74 @@ impl ChannelActorState {

Ok(())
}
PCNMessage::ClosingSigned(closing) => {
let flags = match self.state {
ChannelState::ShuttingDown(flags)
if flags.contains(ShuttingDownFlags::AWAITING_PENDING_TLCS) =>
{
flags
}
_ => {
return Err(ProcessingChannelError::InvalidState(format!(
"received ClosingSigned message, but we're not ready for ClosingSigned, state is currently {:?}",
self.state
)));
}
};
let ClosingSigned {
partial_signature,
channel_id,
fee: _,
} = closing;

if channel_id != self.get_id() {
return Err(ProcessingChannelError::InvalidParameter(
"Channel id mismatch".to_string(),
));
}

let verify_ctx = Musig2VerifyContext::from(&*self);
let tx = self.build_shutdown_tx(
self.get_holder_shutdown_script(),
self.get_counterparty_shutdown_script(),
);
let message = tx.hash();
verify_ctx.verify(partial_signature, message.as_slice())?;
debug!("Successfully verified ClosingSigned message");
self.counterparty_shutdown_signature = Some(partial_signature);

let flags = flags | ShuttingDownFlags::THEIR_CLOSING_SIGNED;
self.state = ChannelState::ShuttingDown(flags);
if flags.contains(ShuttingDownFlags::DROPPING_PENDING) {
self.state = ChannelState::Closed;
let partial_signatures = if self.should_holder_send_tx_signatures_first() {
[
self.holder_shutdown_signature.unwrap(),
self.counterparty_shutdown_signature.unwrap(),
]
} else {
[
self.counterparty_shutdown_signature.unwrap(),
self.holder_shutdown_signature.unwrap(),
]
};
let tx =
aggregate_partial_signatures_for_tx(tx, verify_ctx, partial_signatures)
.expect("The validity of the signatures verified");

network
.send_message(NetworkActorMessage::new_event(
NetworkActorEvent::ChannelClosed(
self.get_id(),
self.peer_id.clone(),
tx,
),
))
.expect("network actor alive");
}
Ok(())
}

_ => {
warn!("Received unsupported message: {:?}", &message);
Ok(())
Expand Down Expand Up @@ -1561,6 +1636,7 @@ impl ChannelActorState {
))
.expect("network actor alive");

self.holder_shutdown_signature = Some(signature);
network
.send_message(NetworkActorMessage::new_event(
NetworkActorEvent::ChannelShutdown(self.get_id(), self.peer_id.clone()),
Expand Down
20 changes: 19 additions & 1 deletion src/ckb/network.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use ckb_types::core::TransactionView;
use ckb_types::packed::{OutPoint, Transaction};
use log::{debug, error, info, warn};
use ractor::{async_trait as rasync_trait, Actor, ActorCell, ActorProcessingErr, ActorRef};
Expand Down Expand Up @@ -96,6 +97,7 @@ pub enum NetworkServiceEvent {
ChannelPendingToBeAccepted(PeerId, Hash256),
ChannelReady(PeerId, Hash256),
ChannelShutDown(PeerId, Hash256),
ChannelClosed(PeerId, Hash256, TransactionView),
}

/// Events that can be sent to the network actor. Except for NetworkServiceEvent,
Expand All @@ -115,8 +117,10 @@ pub enum NetworkActorEvent {
ChannelAccepted(Hash256, Hash256),
/// A channel is ready to use.
ChannelReady(Hash256, PeerId),
/// A channel is ready to use.
/// A channel is being shutting down.
ChannelShutdown(Hash256, PeerId),
/// A channel is already closed.
ChannelClosed(Hash256, PeerId, TransactionView),

/// Both parties are now able to broadcast a valid funding transaction.
FundingTransactionPending(Transaction, OutPoint, Hash256),
Expand Down Expand Up @@ -650,6 +654,20 @@ impl Actor for NetworkActor {
))
.expect("myself alive");
}
NetworkActorEvent::ChannelClosed(channel_id, peer_id, tx) => {
info!(
"Channel ({:?}) to peer {:?} is already closed. Closing transaction {:?} can be broacasted now.",
channel_id, peer_id, tx
);
// Notify outside observers.
myself
.send_message(NetworkActorMessage::new_event(
NetworkActorEvent::NetworkServiceEvent(
NetworkServiceEvent::ChannelClosed(peer_id, channel_id, tx),
),
))
.expect("myself alive");
}
NetworkActorEvent::PeerMessage(peer_id, session, message) => {
self.handle_peer_message(state, peer_id, session, message)
.await?
Expand Down
2 changes: 1 addition & 1 deletion src/ckb/serde_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ where

String::deserialize(deserializer)
.and_then(|string| {
if &string[..2].to_lowercase() != "0x" {
if string.len() < 2 || &string[..2].to_lowercase() != "0x" {
return Err(Error::custom("hex string should start with 0x"));
};
hex::decode(&string[2..])
Expand Down
1 change: 1 addition & 0 deletions src/ckb/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,7 @@ impl TryFrom<molecule_pcn::Shutdown> for Shutdown {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClosingSigned {
pub channel_id: Hash256,
// TODO: fee is actually not used for now.
pub fee: u64,
pub partial_signature: PartialSignature,
}
Expand Down

0 comments on commit 4a0877b

Please sign in to comment.