ddk_manager/channel/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
//! # Module containing structures and methods for working with DLC channels.

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

use crate::{ChannelId, ContractId};

use self::{
    accepted_channel::AcceptedChannel, offered_channel::OfferedChannel,
    signed_channel::SignedChannel,
};

pub mod accepted_channel;
pub mod offered_channel;
pub mod party_points;
pub mod ser;
pub mod signed_channel;
mod utils;

/// Enumeration containing the possible state a DLC channel can be in.
#[derive(Clone)]
#[allow(clippy::large_enum_variant)]
pub enum Channel {
    /// A channel that has been offered.
    Offered(OfferedChannel),
    /// A channel that has been accepted.
    Accepted(AcceptedChannel),
    /// A channel whose fund outputs have been signed by the offer party.
    Signed(SignedChannel),
    /// A channel that failed when validating an
    /// [`ddk_messages::channel::AcceptChannel`] message.
    FailedAccept(FailedAccept),
    /// A channel that failed when validating an
    /// [`ddk_messages::channel::SignChannel`] message.
    FailedSign(FailedSign),
    /// A [`OfferedChannel`] that got rejected by the counterparty.
    Cancelled(OfferedChannel),
    /// 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),
}

impl std::fmt::Debug for Channel {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let state = match self {
            Channel::Offered(_) => "offered",
            Channel::Accepted(_) => "accepted",
            Channel::Signed(_) => "signed",
            Channel::FailedAccept(_) => "failed accept",
            Channel::FailedSign(_) => "failed sign",
            Channel::Cancelled(_) => "cancelled",
            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()
    }
}

impl Channel {
    /// Returns the public key of the counter party's node.
    pub fn get_counter_party_id(&self) -> PublicKey {
        match self {
            Channel::Offered(o) => o.counter_party,
            Channel::Accepted(a) => a.counter_party,
            Channel::Signed(s) => s.counter_party,
            Channel::FailedAccept(f) => f.counter_party,
            Channel::FailedSign(f) => f.counter_party,
            Channel::Cancelled(o) => o.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,
        }
    }
}

/// A channel that failed when validating an
/// [`ddk_messages::channel::AcceptChannel`] message.
#[derive(Clone)]
pub struct FailedAccept {
    /// The [`secp256k1_zkp::PublicKey`] of the counter party.
    pub counter_party: PublicKey,
    /// The temporary [`crate::ChannelId`] of the channel.
    pub temporary_channel_id: ChannelId,
    /// An message describing the error encountered while validating the
    /// [`ddk_messages::channel::AcceptChannel`] message.
    pub error_message: String,
    /// The [`ddk_messages::channel::AcceptChannel`] that was received.
    pub accept_message: AcceptChannel,
}

/// A channel that failed when validating an
/// [`ddk_messages::channel::SignChannel`] message.
#[derive(Clone)]
pub struct FailedSign {
    /// The [`secp256k1_zkp::PublicKey`] of the counter party.
    pub counter_party: PublicKey,
    /// The [`crate::ChannelId`] of the channel.
    pub channel_id: ChannelId,
    /// An message describing the error encountered while validating the
    /// [`ddk_messages::channel::SignChannel`] message.
    pub error_message: String,
    /// The [`ddk_messages::channel::SignChannel`] that was received.
    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 {
        match self {
            Channel::Offered(o) => o.temporary_channel_id,
            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!(),
        }
    }

    /// Returns the [`crate::ChannelId`] for the channel.
    pub fn get_id(&self) -> ChannelId {
        match self {
            Channel::Offered(o) => o.temporary_channel_id,
            Channel::Accepted(a) => a.channel_id,
            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,
            Channel::Cancelled(c) => c.temporary_channel_id,
        }
    }

    /// Returns the contract id associated with the channel if in a state where a contract is set.
    pub fn get_contract_id(&self) -> Option<ContractId> {
        match self {
            Channel::Offered(o) => Some(o.offered_contract_id),
            Channel::Accepted(a) => Some(a.accepted_contract_id),
            Channel::Signed(s) => s.get_contract_id(),
            Channel::FailedAccept(_) => None,
            Channel::FailedSign(_) => None,
            _ => None,
        }
    }
}

/// Generate a temporary contract id for a DLC based on the channel id and the update index of the DLC channel.
pub fn generate_temporary_contract_id(
    channel_id: ChannelId,
    channel_update_idx: u64,
) -> ContractId {
    let mut data = Vec::with_capacity(65);
    data.extend_from_slice(&channel_id);
    data.extend_from_slice(&channel_update_idx.to_be_bytes());
    bitcoin::hashes::sha256::Hash::hash(&data).to_byte_array()
}