Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow force closing in any state #128

Merged
merged 2 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ members = [
]

[patch.crates-io]
lightning = { git = "https://github.com/p2pderivatives/rust-lightning/", rev = "1e5b2a42" }
lightning-net-tokio = { git = "https://github.com/p2pderivatives/rust-lightning/", rev = "1e5b2a42" }
lightning-persister = { git = "https://github.com/p2pderivatives/rust-lightning/", rev = "1e5b2a42" }
lightning = { git = "https://github.com/p2pderivatives/rust-lightning/", rev = "26db9546" }
lightning-net-tokio = { git = "https://github.com/p2pderivatives/rust-lightning/", rev = "26db9546" }
lightning-persister = { git = "https://github.com/p2pderivatives/rust-lightning/", rev = "26db9546" }
88 changes: 86 additions & 2 deletions dlc-manager/src/channel/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! # Module containing structures and methods for working with DLC channels.

use bitcoin::hashes::Hash;
use bitcoin::{hashes::Hash, Transaction, Txid};
use dlc_messages::channel::{AcceptChannel, SignChannel};
use secp256k1_zkp::PublicKey;

Expand All @@ -27,6 +27,24 @@ pub enum Channel {
Accepted(AcceptedChannel),
/// A channel whose fund outputs have been signed by the offer party.
Signed(SignedChannel),
/// A [`Channel`] is in `Closing` state when the local party
/// has broadcast a buffer transaction and is waiting to finalize the
/// closing of the channel by broadcasting a CET.
Closing(ClosingChannel),
/// A [`Channel`] is in `Closed` state when it was force closed by
/// the local party.
Closed(ClosedChannel),
/// A [`Channel`] is in `CounterClosed` state when it was force
/// closed by the counter party.
CounterClosed(ClosedChannel),
/// A [`Channel`] is in `ClosedPunished` state when the local
/// party broadcast a punishment transaction in response to the counter
/// party broadcasting a settle or buffer transaction for a revoked channel
/// state.
ClosedPunished(ClosedPunishedChannel),
/// A [`SignedChannel`] is in `CollaborativelyClosed` state when it was
/// collaboratively closed.
CollaborativelyClosed(ClosedChannel),
/// A channel that failed when validating an
/// [`dlc_messages::channel::AcceptChannel`] message.
FailedAccept(FailedAccept),
Expand All @@ -43,8 +61,13 @@ impl std::fmt::Debug for Channel {
Channel::Signed(_) => "signed",
Channel::FailedAccept(_) => "failed accept",
Channel::FailedSign(_) => "failed sign",
Channel::Closing(_) => "closing",
Channel::Closed(_) => "closed",
Channel::CounterClosed(_) => "counter closed",
Channel::ClosedPunished(_) => "closed punished",
Channel::CollaborativelyClosed(_) => "collaboratively closed",
};
f.debug_struct("Contract").field("state", &state).finish()
f.debug_struct("Channel").field("state", &state).finish()
}
}

Expand All @@ -57,6 +80,11 @@ impl Channel {
Channel::Signed(s) => s.counter_party,
Channel::FailedAccept(f) => f.counter_party,
Channel::FailedSign(f) => f.counter_party,
Channel::Closing(c) => c.counter_party,
Channel::Closed(c) | Channel::CounterClosed(c) | Channel::CollaborativelyClosed(c) => {
c.counter_party
}
Channel::ClosedPunished(c) => c.counter_party,
}
}
}
Expand Down Expand Up @@ -91,6 +119,52 @@ pub struct FailedSign {
pub sign_message: SignChannel,
}

#[derive(Clone)]
/// A channel is closing when its buffer transaction was broadcast or detected on chain.
pub struct ClosingChannel {
/// The [`secp256k1_zkp::PublicKey`] of the counter party.
pub counter_party: PublicKey,
/// The temporary [`crate::ChannelId`] of the channel.
pub temporary_channel_id: ChannelId,
/// The [`crate::ChannelId`] for the channel.
pub channel_id: ChannelId,
/// The previous state the channel was before being closed, if that state was the `Signed` one,
/// otherwise is `None`.
pub rollback_state: Option<SignedChannel>,
/// The buffer transaction that was broadcast.
pub buffer_transaction: Transaction,
/// The [`crate::ContractId`] of the contract that was used to close
/// the channel.
pub contract_id: ContractId,
/// Whether the local party initiated the closing of the channel.
pub is_closer: bool,
}

#[derive(Clone)]
/// A channel is closed when its buffer transaction has been spent.
pub struct ClosedChannel {
/// The [`secp256k1_zkp::PublicKey`] of the counter party.
pub counter_party: PublicKey,
/// The temporary [`crate::ChannelId`] of the channel.
pub temporary_channel_id: ChannelId,
/// The [`crate::ChannelId`] for the channel.
pub channel_id: ChannelId,
}

#[derive(Clone)]
/// A channel is closed punished when the counter party broadcast a revoked transaction triggering
/// the broadcast of a punishment transaction by the local party.
pub struct ClosedPunishedChannel {
/// The [`secp256k1_zkp::PublicKey`] of the counter party.
pub counter_party: PublicKey,
/// The temporary [`crate::ChannelId`] of the channel.
pub temporary_channel_id: ChannelId,
/// The [`crate::ChannelId`] for the channel.
pub channel_id: ChannelId,
/// The transaction id of the punishment transaction that was broadcast.
pub punish_txid: Txid,
}

impl Channel {
/// Returns the temporary [`crate::ChannelId`] for the channel.
pub fn get_temporary_id(&self) -> ChannelId {
Expand All @@ -99,6 +173,10 @@ impl Channel {
Channel::Accepted(a) => a.temporary_channel_id,
Channel::Signed(s) => s.temporary_channel_id,
Channel::FailedAccept(f) => f.temporary_channel_id,
Channel::Closed(c) | Channel::CounterClosed(c) | Channel::CollaborativelyClosed(c) => {
c.temporary_channel_id
}
Channel::ClosedPunished(c) => c.temporary_channel_id,
_ => unimplemented!(),
}
}
Expand All @@ -111,6 +189,11 @@ impl Channel {
Channel::Signed(s) => s.channel_id,
Channel::FailedAccept(f) => f.temporary_channel_id,
Channel::FailedSign(f) => f.channel_id,
Channel::Closing(c) => c.channel_id,
Channel::Closed(c) | Channel::CounterClosed(c) | Channel::CollaborativelyClosed(c) => {
c.channel_id
}
Channel::ClosedPunished(c) => c.channel_id,
}
}

Expand All @@ -122,6 +205,7 @@ impl Channel {
Channel::Signed(s) => s.get_contract_id(),
Channel::FailedAccept(_) => None,
Channel::FailedSign(_) => None,
_ => None,
}
}
}
Expand Down
22 changes: 17 additions & 5 deletions dlc-manager/src/channel/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::accepted_channel::AcceptedChannel;
use super::offered_channel::OfferedChannel;
use super::party_points::PartyBasePoints;
use super::signed_channel::{SignedChannel, SignedChannelState};
use super::{FailedAccept, FailedSign};
use super::{ClosedChannel, ClosedPunishedChannel, ClosingChannel, FailedAccept, FailedSign};

use dlc_messages::ser_impls::{
read_ecdsa_adaptor_signature, read_string, write_ecdsa_adaptor_signature, write_string,
Expand Down Expand Up @@ -60,12 +60,24 @@ impl_dlc_writeable_enum!(
(6, RenewOffered, {(offered_contract_id, writeable), (counter_payout, writeable), (is_offer, writeable), (offer_next_per_update_point, writeable), (timeout, writeable)}),
(7, RenewAccepted, {(contract_id, writeable), (offer_per_update_point, writeable), (accept_per_update_point, writeable), (buffer_transaction, writeable), (buffer_script_pubkey, writeable), (timeout, writeable), (own_payout, writeable)}),
(8, RenewConfirmed, {(contract_id, writeable), (offer_per_update_point, writeable), (accept_per_update_point, writeable), (buffer_transaction, writeable), (buffer_script_pubkey, writeable), (offer_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (timeout, writeable), (own_payout, writeable), (total_collateral, writeable)}),
(15, RenewFinalized, {(contract_id, writeable), (offer_per_update_point, writeable), (accept_per_update_point, writeable), (buffer_transaction, writeable), (buffer_script_pubkey, writeable), (offer_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (accept_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (timeout, writeable), (own_payout, writeable), (total_collateral, writeable)}),
(9, Closing, {(buffer_transaction, writeable), (contract_id, writeable), (is_initiator, writeable)}),
(10, ClosedPunished, { (punishment_txid, writeable) }),
(9, RenewFinalized, {(contract_id, writeable), (offer_per_update_point, writeable), (accept_per_update_point, writeable), (buffer_transaction, writeable), (buffer_script_pubkey, writeable), (offer_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (accept_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (timeout, writeable), (own_payout, writeable), (total_collateral, writeable)}),
(10, Closing, {(buffer_transaction, writeable), (contract_id, writeable), (is_initiator, writeable)}),
(11, CollaborativeCloseOffered, { (counter_payout, writeable), (offer_signature, writeable), (close_tx, writeable), (timeout, writeable) })
;;(12, Closed), (13, CounterClosed), (14, CollaborativelyClosed)
;;
);

impl_dlc_writeable!(FailedAccept, {(temporary_channel_id, writeable), (error_message, {cb_writeable, write_string, read_string}), (accept_message, writeable), (counter_party, writeable)});
impl_dlc_writeable!(FailedSign, {(channel_id, writeable), (error_message, {cb_writeable, write_string, read_string}), (sign_message, writeable), (counter_party, writeable)});

impl_dlc_writeable!(ClosingChannel, {
(channel_id, writeable),
(counter_party, writeable),
(temporary_channel_id, writeable),
(rollback_state, option),
(buffer_transaction, writeable),
(contract_id, writeable),
(is_closer, writeable)

});
impl_dlc_writeable!(ClosedChannel, {(channel_id, writeable), (counter_party, writeable), (temporary_channel_id, writeable)});
impl_dlc_writeable!(ClosedPunishedChannel, {(channel_id, writeable), (counter_party, writeable), (temporary_channel_id, writeable), (punish_txid, writeable)});
19 changes: 1 addition & 18 deletions dlc-manager/src/channel/signed_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! transaction inputs. This module contains the model for a signed channel,
//! the possible states in which it can be as well as methods to work with it.

use bitcoin::{Script, Transaction, Txid};
use bitcoin::{Script, Transaction};
use dlc::PartyParams;
use lightning::ln::chan_utils::CounterpartyCommitmentSecrets;
use secp256k1_zkp::{ecdsa::Signature, EcdsaAdaptorSignature, PublicKey};
Expand Down Expand Up @@ -300,20 +300,6 @@ typed_enum!(
/// Whether the local party initiated the closing of the channel.
is_initiator: bool,
},
/// A [`SignedChannel`] is in `Closed` state when it was force closed by
/// the local party.
Closed,
/// A [`SignedChannel`] is in `CounterClosed` state when it was force
/// closed by the counter party.
CounterClosed,
/// A [`SignedChannel`] is in `ClosedPublished` state when the local
/// party broadcast a punishment transaction in response to the counter
/// party broadcasting a settle or buffer transaction for a revoked channel
/// state.
ClosedPunished {
/// The transaction id of the punishment transaction that was broadcast.
punishment_txid: Txid,
},
/// A [`SignedChannel`] is in `CollaborativeCloseOffered` state when the local party
/// has sent a [`dlc_messages::channel::CollaborativeCloseOffer`] message.
CollaborativeCloseOffered {
Expand All @@ -327,9 +313,6 @@ typed_enum!(
/// unresponsive and the channel will be forced closed.
timeout: u64,
},
/// A [`SignedChannel`] is in `CollaborativelyClosed` state when it was
/// collaboratively closed.
CollaborativelyClosed,
},
/// Enum automatically generated associating a number to each signed channel
/// state.
Expand Down
54 changes: 38 additions & 16 deletions dlc-manager/src/channel_updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{
offered_channel::OfferedChannel,
party_points::PartyBasePoints,
signed_channel::{SignedChannel, SignedChannelState},
Channel, ClosedChannel,
},
contract::{
accepted_contract::AcceptedContract, contract_info::ContractInfo,
Expand Down Expand Up @@ -2265,9 +2266,9 @@ where
/// closing transaction and returning it.
pub fn accept_collaborative_close_offer<C: Signing, S: Deref>(
secp: &Secp256k1<C>,
signed_channel: &mut SignedChannel,
signed_channel: &SignedChannel,
signer: &S,
) -> Result<Transaction, Error>
) -> Result<(Transaction, Channel), Error>
where
S::Target: Signer,
{
Expand Down Expand Up @@ -2295,8 +2296,12 @@ where
)?;

// TODO(tibo): should only transition to close after confirmation.
signed_channel.state = SignedChannelState::CollaborativelyClosed;
Ok(close_tx)
let channel = Channel::CollaborativelyClosed(ClosedChannel {
counter_party: signed_channel.counter_party,
temporary_channel_id: signed_channel.temporary_channel_id,
channel_id: signed_channel.channel_id,
});
Ok((close_tx, channel))
}

fn get_settle_tx_and_adaptor_sig(
Expand Down Expand Up @@ -2528,13 +2533,14 @@ where
/// Extract the CET and computes the signature for it, and marks the channel as closed.
pub fn finalize_unilateral_close_settled_channel<S: Deref>(
secp: &Secp256k1<All>,
signed_channel: &mut SignedChannel,
signed_channel: &SignedChannel,
confirmed_contract: &SignedContract,
contract_info: &ContractInfo,
attestations: &[(usize, OracleAttestation)],
adaptor_info: &AdaptorInfo,
signer: &S,
) -> Result<Transaction, Error>
is_initiator: bool,
) -> Result<(Transaction, Channel), Error>
where
S::Target: Signer,
{
Expand Down Expand Up @@ -2618,10 +2624,18 @@ where
&adaptor_sigs[range_info.adaptor_index],
&oracle_sigs,
)?;
let closed_channel = ClosedChannel {
counter_party: signed_channel.counter_party,
temporary_channel_id: signed_channel.temporary_channel_id,
channel_id: signed_channel.channel_id,
};
let channel = if is_initiator {
Channel::Closed(closed_channel)
} else {
Channel::CounterClosed(closed_channel)
};

signed_channel.state = SignedChannelState::Closed;

Ok(cet)
Ok((cet, channel))
}

/// Sign the settlement transaction and update the state of the channel.
Expand All @@ -2630,7 +2644,7 @@ pub fn close_settled_channel<S: Deref>(
signed_channel: &mut SignedChannel,
signer: &S,
is_initiator: bool,
) -> Result<Transaction, Error>
) -> Result<(Transaction, Channel), Error>
where
S::Target: Signer,
{
Expand All @@ -2639,11 +2653,11 @@ where

pub(crate) fn close_settled_channel_internal<S: Deref>(
secp: &Secp256k1<All>,
signed_channel: &mut SignedChannel,
signed_channel: &SignedChannel,
signer: &S,
sub_channel: Option<(SubChannel, &ClosingSubChannel)>,
is_initiator: bool,
) -> Result<Transaction, Error>
) -> Result<(Transaction, Channel), Error>
where
S::Target: Signer,
{
Expand Down Expand Up @@ -2744,10 +2758,18 @@ where
)?;
}

signed_channel.state = if is_initiator {
SignedChannelState::Closed
let channel = if is_initiator {
Channel::Closed(ClosedChannel {
counter_party: signed_channel.counter_party,
temporary_channel_id: signed_channel.temporary_channel_id,
channel_id: signed_channel.channel_id,
})
} else {
SignedChannelState::CounterClosed
Channel::CounterClosed(ClosedChannel {
counter_party: signed_channel.counter_party,
temporary_channel_id: signed_channel.temporary_channel_id,
channel_id: signed_channel.channel_id,
})
};
Ok(settle_tx)
Ok((settle_tx, channel))
}
Loading
Loading