Skip to main content

fiber_types/
channel.rs

1//! Channel-related types: state flags, TLC status, channel state enum.
2
3use crate::crate_time::SystemTime;
4use crate::gen::fiber as molecule_fiber;
5use crate::invoice::HashAlgorithm;
6use crate::onion::PaymentOnionPacket;
7use crate::onion::TlcErrPacket;
8use crate::protocol::{ChannelAnnouncement, ChannelUpdate, EcdsaSignature};
9use crate::serde_utils::PartialSignatureAsBytes;
10use crate::serde_utils::PubNonceAsBytes;
11use crate::EntityHex;
12use crate::Hash256;
13use crate::Privkey;
14use crate::Pubkey;
15use bitflags::bitflags;
16use ckb_types::packed::Byte32 as MByte32;
17use ckb_types::packed::Script;
18use ckb_types::packed::Transaction;
19use ckb_types::prelude::{Pack, Unpack};
20use ckb_types::H256;
21use molecule::prelude::{Builder, Entity};
22use musig2::BinaryEncoding;
23use musig2::PartialSignature;
24use musig2::PubNonce;
25use musig2::{SecNonce, SecNonceBuilder};
26use serde::{Deserialize, Serialize};
27use serde_with::serde_as;
28use std::collections::{HashMap, VecDeque};
29use std::fmt::{Debug, Formatter};
30
31bitflags! {
32    #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
33    #[serde(transparent)]
34    pub struct ChannelFlags: u8 {
35        const PUBLIC = 1;
36        const ONE_WAY = 1 << 1;
37        const EXTERNAL_FUNDING = 1 << 2;
38    }
39
40    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
41    #[serde(transparent)]
42    pub struct ChannelUpdateChannelFlags: u32 {
43        const DISABLED = 1;
44    }
45
46    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
47    #[serde(transparent)]
48    pub struct ChannelUpdateMessageFlags: u32 {
49        const UPDATE_OF_NODE1 = 0;
50        const UPDATE_OF_NODE2 = 1;
51    }
52
53    #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
54    #[serde(transparent)]
55    pub struct NegotiatingFundingFlags: u32 {
56        const OUR_INIT_SENT = 1;
57        const THEIR_INIT_SENT = 1 << 1;
58        const INIT_SENT = NegotiatingFundingFlags::OUR_INIT_SENT.bits() | NegotiatingFundingFlags::THEIR_INIT_SENT.bits();
59        const AWAITING_EXTERNAL_FUNDING = 1 << 2;
60    }
61
62    #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
63    #[serde(transparent)]
64    pub struct CollaboratingFundingTxFlags: u32 {
65        const AWAITING_REMOTE_TX_COLLABORATION_MSG = 1;
66        const PREPARING_LOCAL_TX_COLLABORATION_MSG = 1 << 1;
67        const OUR_TX_COMPLETE_SENT = 1 << 2;
68        const THEIR_TX_COMPLETE_SENT = 1 << 3;
69        const COLLABORATION_COMPLETED = CollaboratingFundingTxFlags::OUR_TX_COMPLETE_SENT.bits() | CollaboratingFundingTxFlags::THEIR_TX_COMPLETE_SENT.bits();
70    }
71
72    #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
73    #[serde(transparent)]
74    pub struct SigningCommitmentFlags: u32 {
75        const OUR_COMMITMENT_SIGNED_SENT = 1;
76        const THEIR_COMMITMENT_SIGNED_SENT = 1 << 1;
77        const COMMITMENT_SIGNED_SENT = SigningCommitmentFlags::OUR_COMMITMENT_SIGNED_SENT.bits() | SigningCommitmentFlags::THEIR_COMMITMENT_SIGNED_SENT.bits();
78    }
79
80    #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
81    #[serde(transparent)]
82    pub struct AwaitingTxSignaturesFlags: u32 {
83        const OUR_TX_SIGNATURES_SENT = 1;
84        const THEIR_TX_SIGNATURES_SENT = 1 << 1;
85        const TX_SIGNATURES_SENT = AwaitingTxSignaturesFlags::OUR_TX_SIGNATURES_SENT.bits() | AwaitingTxSignaturesFlags::THEIR_TX_SIGNATURES_SENT.bits();
86    }
87
88    #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
89    #[serde(transparent)]
90    pub struct AwaitingChannelReadyFlags: u32 {
91        const OUR_CHANNEL_READY = 1;
92        const THEIR_CHANNEL_READY = 1 << 1;
93        const CHANNEL_READY = AwaitingChannelReadyFlags::OUR_CHANNEL_READY.bits() | AwaitingChannelReadyFlags::THEIR_CHANNEL_READY.bits();
94    }
95
96    #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
97    #[serde(transparent)]
98    pub struct ShuttingDownFlags: u32 {
99        const OUR_SHUTDOWN_SENT = 1;
100        const THEIR_SHUTDOWN_SENT = 1 << 1;
101        const AWAITING_PENDING_TLCS = ShuttingDownFlags::OUR_SHUTDOWN_SENT.bits() | ShuttingDownFlags::THEIR_SHUTDOWN_SENT.bits();
102        const DROPPING_PENDING = 1 << 2;
103        const WAITING_COMMITMENT_CONFIRMATION = 1 << 3;
104    }
105
106    #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
107    #[serde(transparent)]
108    pub struct CloseFlags: u32 {
109        const COOPERATIVE = 1;
110        const UNCOOPERATIVE_LOCAL = 1 << 1;
111        const ABANDONED = 1 << 2;
112        const FUNDING_ABORTED = 1 << 3;
113        const UNCOOPERATIVE_REMOTE = 1 << 4;
114        const WAITING_ONCHAIN_SETTLEMENT = 1 << 5;
115    }
116
117    #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
118    #[serde(transparent)]
119    pub struct AppliedFlags: u8 {
120        const ADD = 1;
121        const REMOVE = 1 << 1;
122    }
123}
124
125/// The id of a tlc, it can be either offered or received.
126#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Hash)]
127pub enum TLCId {
128    /// Offered tlc id
129    Offered(u64),
130    /// Received tlc id
131    Received(u64),
132}
133
134impl From<TLCId> for u64 {
135    fn from(id: TLCId) -> u64 {
136        match id {
137            TLCId::Offered(id) => id,
138            TLCId::Received(id) => id,
139        }
140    }
141}
142
143impl TLCId {
144    pub fn is_offered(&self) -> bool {
145        matches!(self, TLCId::Offered(_))
146    }
147
148    pub fn is_received(&self) -> bool {
149        !self.is_offered()
150    }
151
152    pub fn flip(&self) -> Self {
153        match self {
154            TLCId::Offered(id) => TLCId::Received(*id),
155            TLCId::Received(id) => TLCId::Offered(*id),
156        }
157    }
158
159    pub fn flip_mut(&mut self) {
160        *self = self.flip();
161    }
162}
163
164/// The status of an outbound tlc
165#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
166pub enum OutboundTlcStatus {
167    // Offered tlc created and sent to remote party
168    LocalAnnounced,
169    // Received ACK from remote party for this offered tlc
170    Committed,
171    // Remote party removed this tlc
172    RemoteRemoved,
173    // We received another RemoveTlc message from peer when we are waiting for the ack of the last one.
174    // So we need another ACK to confirm the removal.
175    RemoveWaitPrevAck,
176    // We have sent commitment signed to peer and waiting ACK for confirming this RemoveTlc
177    RemoveWaitAck,
178    // We have received the ACK for the RemoveTlc, it's safe to remove this tlc
179    RemoveAckConfirmed,
180}
181
182/// The status of an inbound tlc
183#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
184pub enum InboundTlcStatus {
185    // Received tlc from remote party, but not committed yet
186    RemoteAnnounced,
187    // We received another AddTlc peer message when we are waiting for the ack of the last one.
188    // So we need another ACK to confirm the addition.
189    AnnounceWaitPrevAck,
190    // We have sent commitment signed to peer and waiting ACK for confirming this AddTlc
191    AnnounceWaitAck,
192    // We have received ACK from peer and Committed this tlc
193    Committed,
194    // We have removed this tlc, but haven't received ACK from peer
195    LocalRemoved,
196    // We have received the ACK for the RemoveTlc, it's safe to remove this tlc
197    RemoveAckConfirmed,
198}
199
200/// The status of a tlc
201#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
202pub enum TlcStatus {
203    /// Outbound tlc
204    Outbound(OutboundTlcStatus),
205    /// Inbound tlc
206    Inbound(InboundTlcStatus),
207}
208
209impl TlcStatus {
210    pub fn as_outbound_status(&self) -> OutboundTlcStatus {
211        match self {
212            TlcStatus::Outbound(status) => status.clone(),
213            _ => {
214                unreachable!("unexpected status")
215            }
216        }
217    }
218
219    pub fn as_inbound_status(&self) -> InboundTlcStatus {
220        match self {
221            TlcStatus::Inbound(status) => status.clone(),
222            _ => {
223                unreachable!("unexpected status ")
224            }
225        }
226    }
227}
228
229/// The state of a channel.
230///
231/// Note: fiber-lib uses default serde (bincode-compatible), while fiber-json-types
232/// uses `#[serde(tag = "state_name", content = "state_flags")]` for JSON.
233/// This definition uses the default (bincode-compatible) representation.
234/// The JSON-specific tagged version is defined in fiber-json-types.
235#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
236pub enum ChannelState {
237    /// We are negotiating the parameters required for the channel prior to funding it.
238    /// For channels opened with external funding, this state is also used together with
239    /// `NegotiatingFundingFlags::AWAITING_EXTERNAL_FUNDING` to indicate that we are waiting
240    /// for the user to sign and submit the funding transaction externally.
241    NegotiatingFunding(NegotiatingFundingFlags),
242    /// We're collaborating with the other party on the funding transaction.
243    CollaboratingFundingTx(CollaboratingFundingTxFlags),
244    /// We have collaborated over the funding and are now waiting for CommitmentSigned messages.
245    SigningCommitment(SigningCommitmentFlags),
246    /// We've received and sent `commitment_signed` and are now waiting for both
247    /// party to collaborate on creating a valid funding transaction.
248    AwaitingTxSignatures(AwaitingTxSignaturesFlags),
249    /// We've received/sent `funding_created` and `funding_signed` and are thus now waiting on the
250    /// funding transaction to confirm.
251    AwaitingChannelReady(AwaitingChannelReadyFlags),
252    /// Both we and our counterparty consider the funding transaction confirmed and the channel is
253    /// now operational.
254    ChannelReady,
255    /// We've successfully negotiated a `closing_signed` dance.
256    ShuttingDown(ShuttingDownFlags),
257    /// This channel is closed.
258    Closed(CloseFlags),
259}
260
261impl ChannelState {
262    pub fn is_awaiting_external_funding(&self) -> bool {
263        matches!(
264            self,
265            ChannelState::NegotiatingFunding(flags)
266                if flags.contains(NegotiatingFundingFlags::AWAITING_EXTERNAL_FUNDING)
267        )
268    }
269
270    pub fn is_closed(&self) -> bool {
271        matches!(
272            self,
273            ChannelState::Closed(_)
274                | ChannelState::ShuttingDown(ShuttingDownFlags::WAITING_COMMITMENT_CONFIRMATION)
275        )
276    }
277
278    pub fn can_abort_funding(&self) -> bool {
279        match self {
280            ChannelState::NegotiatingFunding(_)
281            | ChannelState::CollaboratingFundingTx(_)
282            | ChannelState::SigningCommitment(_) => true,
283            ChannelState::AwaitingTxSignatures(flags)
284                if !flags.contains(AwaitingTxSignaturesFlags::OUR_TX_SIGNATURES_SENT) =>
285            {
286                true
287            }
288            _ => false,
289        }
290    }
291}
292
293impl ShuttingDownFlags {
294    pub fn is_ok_for_commitment_operation(&self) -> bool {
295        !self.contains(ShuttingDownFlags::DROPPING_PENDING)
296            && !self.contains(ShuttingDownFlags::WAITING_COMMITMENT_CONFIRMATION)
297    }
298}
299
300/// The initial commitment number for a channel.
301pub const INITIAL_COMMITMENT_NUMBER: u64 = 0;
302
303/// Tracks the local and remote commitment numbers.
304#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
305pub struct CommitmentNumbers {
306    pub local: u64,
307    pub remote: u64,
308}
309
310impl Default for CommitmentNumbers {
311    fn default() -> Self {
312        Self::new()
313    }
314}
315
316impl CommitmentNumbers {
317    pub fn new() -> Self {
318        Self {
319            local: INITIAL_COMMITMENT_NUMBER,
320            remote: INITIAL_COMMITMENT_NUMBER,
321        }
322    }
323
324    pub fn get_local(&self) -> u64 {
325        self.local
326    }
327
328    pub fn get_remote(&self) -> u64 {
329        self.remote
330    }
331
332    pub fn increment_local(&mut self) {
333        self.local += 1;
334    }
335
336    pub fn increment_remote(&mut self) {
337        self.remote += 1;
338    }
339}
340
341/// Channel constraints for TLC value and number limits.
342#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Default)]
343pub struct ChannelConstraints {
344    /// The maximum value that can be in pending TLCs.
345    pub max_tlc_value_in_flight: u128,
346    /// The maximum number of TLCs that can be accepted.
347    pub max_tlc_number_in_flight: u64,
348}
349
350impl ChannelConstraints {
351    pub fn new(max_tlc_value_in_flight: u128, max_tlc_number_in_flight: u64) -> Self {
352        Self {
353            max_tlc_value_in_flight,
354            max_tlc_number_in_flight,
355        }
356    }
357}
358
359/// TLC-related information for a channel.
360/// We can update this information through the channel update message.
361#[derive(Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
362pub struct ChannelTlcInfo {
363    /// The timestamp when the following information is updated.
364    pub timestamp: u64,
365
366    /// Whether this channel is enabled for TLC forwarding or not.
367    pub enabled: bool,
368
369    /// The fee rate for TLC transfers. We only have these values set when
370    /// this is a public channel. Both sides may set this value differently.
371    /// This is a fee that is paid by the sender of the TLC.
372    /// The detailed calculation for the fee of forwarding TLCs is
373    /// `fee = round_above(tlc_fee_proportional_millionths * tlc_value / 1,000,000)`.
374    pub tlc_fee_proportional_millionths: u128,
375
376    /// The expiry delta timestamp, in milliseconds, for the TLC.
377    pub tlc_expiry_delta: u64,
378
379    /// The minimal TLC value we can receive in relay TLC.
380    pub tlc_minimum_value: u128,
381}
382
383impl ChannelTlcInfo {
384    /// Create a new `ChannelTlcInfo` with the given parameters.
385    pub fn new(
386        tlc_minimum_value: u128,
387        tlc_expiry_delta: u64,
388        tlc_fee_proportional_millionths: u128,
389        timestamp: u64,
390    ) -> Self {
391        Self {
392            tlc_minimum_value,
393            tlc_expiry_delta,
394            tlc_fee_proportional_millionths,
395            enabled: true,
396            timestamp,
397        }
398    }
399}
400
401/// One counterparty's public keys which do not change over the life of a channel.
402#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
403pub struct ChannelBasePublicKeys {
404    /// The public key which is used to sign all commitment transactions, as it appears in the
405    /// on-chain channel lock-in 2-of-2 multisig output.
406    pub funding_pubkey: Pubkey,
407    /// The base point which is used (with derive_public_key) to derive a per-commitment public key
408    /// which is used to encumber HTLC-in-flight outputs.
409    pub tlc_base_key: Pubkey,
410}
411
412/// When we are forwarding a TLC, we need to know the previous TLC information.
413/// This struct keeps the information of the previous TLC.
414#[derive(Debug, Copy, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
415pub struct PrevTlcInfo {
416    pub prev_channel_id: Hash256,
417    /// The TLC is always a received TLC because we are forwarding it.
418    pub prev_tlc_id: u64,
419    pub forwarding_fee: u128,
420    pub shared_secret: Option<[u8; 32]>,
421}
422
423impl PrevTlcInfo {
424    pub fn new(prev_channel_id: Hash256, prev_tlc_id: u64, forwarding_fee: u128) -> Self {
425        Self {
426            prev_channel_id,
427            prev_tlc_id,
428            forwarding_fee,
429            shared_secret: None,
430        }
431    }
432
433    pub fn new_with_shared_secret(
434        prev_channel_id: Hash256,
435        prev_tlc_id: u64,
436        forwarding_fee: u128,
437        shared_secret: [u8; 32],
438    ) -> Self {
439        Self {
440            prev_channel_id,
441            prev_tlc_id,
442            forwarding_fee,
443            shared_secret: Some(shared_secret),
444        }
445    }
446}
447
448#[derive(Clone, Serialize, Deserialize, Eq, PartialEq)]
449pub struct TlcInfo {
450    pub status: TlcStatus,
451    pub tlc_id: TLCId,
452    pub amount: u128,
453    pub payment_hash: Hash256,
454    /// bolt04 total amount of the payment, must exist if payment secret is set
455    pub total_amount: Option<u128>,
456    /// bolt04 payment secret, only exists for last hop in multi-path payment
457    pub payment_secret: Option<Hash256>,
458    /// The attempt id associate with the tlc, only on outbound tlc
459    /// only exists for first hop in multi-path payment
460    pub attempt_id: Option<u64>,
461    pub expiry: u64,
462    pub hash_algorithm: HashAlgorithm,
463    // the onion packet for multi-hop payment
464    pub onion_packet: Option<PaymentOnionPacket>,
465    /// Shared secret used in forwarding.
466    ///
467    /// Save it to backward errors. Use all zeros when no shared secrets are available.
468    pub shared_secret: [u8; 32],
469    #[serde(default)]
470    pub is_trampoline_hop: bool,
471    pub created_at: CommitmentNumbers,
472    pub removed_reason: Option<RemoveTlcReason>,
473
474    /// Note: `forwarding_tlc` is used to track the tlc chain for a multi-tlc payment.
475    ///
476    /// For an outbound tlc, this field records the previous (upstream) tlc,
477    /// so we can walk backward when removing tlcs.
478    ///
479    /// For an inbound tlc, this field records the next (downstream) tlc,
480    /// so we can continue tracking the forwarding path.
481    ///
482    /// Example:
483    ///
484    ///   Node A ---------> Node B ------------> Node C ------------> Node D
485    ///   tlc_1  ---------> tlc_1(in) ---------> tlc_2(in) ---------> tlc_3
486    ///                     tlc_2(out)           tlc_3(out)
487    ///                forwarding_tlc        forwarding_tlc
488    ///
489    ///   forwarding_tlc relations:
490    ///
491    ///   - Node B:
492    ///     - inbound: tlc_1.forwarding_tlc = Some((channel_BC, tlc2_id))
493    ///     - outbound: tlc_2.forwarding_tlc = Some((channel_AB, tlc1_id))
494    ///
495    ///   - Node C:
496    ///     - inbound: tlc_2.forwarding_tlc = Some((channel_CD, tlc3_id))
497    ///     - outbound: tlc_3.forwarding_tlc = Some((channel_BC, tlc2_id))
498    ///
499    pub forwarding_tlc: Option<(Hash256, u64)>,
500    pub removed_confirmed_at: Option<u64>,
501    pub applied_flags: AppliedFlags,
502}
503
504use std::fmt;
505use std::time::Duration;
506
507impl fmt::Debug for TlcInfo {
508    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
509        f.debug_struct("TlcInfo")
510            .field("status", &self.status)
511            .field("tlc_id", &self.tlc_id)
512            .field("amount", &self.amount)
513            .field("payment_hash", &self.payment_hash)
514            .field("expiry", &self.expiry)
515            .field("created_at", &self.created_at)
516            .field("removed_reason", &self.removed_reason)
517            .field("applied_flags", &self.applied_flags)
518            .finish()
519    }
520}
521
522impl TlcInfo {
523    pub fn log(&self) -> String {
524        format!(
525            "id: {:?} status: {:?} amount: {:?} removed: {:?} hash: {:?} ",
526            &self.tlc_id, self.status, self.amount, self.removed_reason, self.payment_hash,
527        )
528    }
529
530    pub fn id(&self) -> u64 {
531        self.tlc_id.into()
532    }
533
534    pub fn is_offered(&self) -> bool {
535        self.tlc_id.is_offered()
536    }
537
538    pub fn is_received(&self) -> bool {
539        !self.is_offered()
540    }
541
542    pub fn get_commitment_numbers(&self) -> CommitmentNumbers {
543        self.created_at
544    }
545
546    pub fn flip_mut(&mut self) {
547        self.tlc_id.flip_mut();
548    }
549
550    pub fn outbound_status(&self) -> OutboundTlcStatus {
551        self.status.as_outbound_status()
552    }
553
554    pub fn inbound_status(&self) -> InboundTlcStatus {
555        self.status.as_inbound_status()
556    }
557
558    pub fn is_fail_remove_confirmed(&self) -> bool {
559        matches!(self.removed_reason, Some(RemoveTlcReason::RemoveTlcFail(_)))
560            && matches!(
561                self.status,
562                TlcStatus::Outbound(OutboundTlcStatus::RemoveAckConfirmed)
563                    | TlcStatus::Outbound(OutboundTlcStatus::RemoveWaitAck)
564                    | TlcStatus::Inbound(InboundTlcStatus::RemoveAckConfirmed)
565            )
566    }
567
568    /// Get the value for the field `htlc_type` in commitment lock witness.
569    /// - Lowest 1 bit: 0 if the tlc is offered by the remote party, 1 otherwise.
570    /// - High 7 bits:
571    ///     - 0: ckb hash
572    ///     - 1: sha256
573    pub fn get_htlc_type(&self) -> u8 {
574        let offered_flag = if self.is_offered() { 0u8 } else { 1u8 };
575        ((self.hash_algorithm as u8) << 1) + offered_flag
576    }
577}
578
579/// A collection of pending TLCs.
580#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Default)]
581pub struct PendingTlcs {
582    pub tlcs: Vec<TlcInfo>,
583    pub next_tlc_id: u64,
584}
585
586impl PendingTlcs {
587    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut TlcInfo> {
588        self.tlcs.iter_mut()
589    }
590
591    pub fn get_next_id(&self) -> u64 {
592        self.next_tlc_id
593    }
594
595    pub fn increment_next_id(&mut self) {
596        self.next_tlc_id += 1;
597    }
598
599    pub fn add_tlc(&mut self, tlc: TlcInfo) {
600        self.tlcs.push(tlc);
601    }
602}
603
604/// The state of all TLCs for a channel.
605#[derive(Default, Clone, Debug, Serialize, Deserialize)]
606pub struct TlcState {
607    pub offered_tlcs: PendingTlcs,
608    pub received_tlcs: PendingTlcs,
609    pub waiting_ack: bool,
610}
611
612impl TlcState {
613    pub fn info(&self) -> String {
614        format!(
615            "offer_tlcs: {:?} received_tlcs: {:?}",
616            self.offered_tlcs.tlcs.len(),
617            self.received_tlcs.tlcs.len(),
618        )
619    }
620
621    #[cfg(debug_assertions)]
622    pub fn debug(&self) {
623        let format_tlc_list = |tlcs: &[TlcInfo]| -> String {
624            if tlcs.is_empty() {
625                "    <none>".to_string()
626            } else {
627                tlcs.iter()
628                    .map(|tlc| format!("    {}", tlc.log()))
629                    .collect::<Vec<_>>()
630                    .join("\n")
631            }
632        };
633
634        let offered_str = format_tlc_list(&self.offered_tlcs.tlcs);
635        let received_str = format_tlc_list(&self.received_tlcs.tlcs);
636
637        if offered_str.contains("<none>") && received_str.contains("<none>") {
638            tracing::info!("TlcState: <none>");
639        } else {
640            tracing::info!(
641                "TlcState:\n  Offered:\n{}\n  Received:\n{}",
642                offered_str,
643                received_str
644            );
645        }
646    }
647
648    pub fn get_mut(&mut self, tlc_id: &TLCId) -> Option<&mut TlcInfo> {
649        self.offered_tlcs
650            .tlcs
651            .iter_mut()
652            .find(|tlc| tlc.tlc_id == *tlc_id)
653            .or_else(|| {
654                self.received_tlcs
655                    .tlcs
656                    .iter_mut()
657                    .find(|tlc| tlc.tlc_id == *tlc_id)
658            })
659    }
660
661    pub fn get(&self, tlc_id: &TLCId) -> Option<&TlcInfo> {
662        if tlc_id.is_offered() {
663            self.offered_tlcs
664                .tlcs
665                .iter()
666                .find(|tlc| tlc.tlc_id == *tlc_id)
667        } else {
668            self.received_tlcs
669                .tlcs
670                .iter()
671                .find(|tlc| tlc.tlc_id == *tlc_id)
672        }
673    }
674
675    pub fn get_committed_received_tlcs(&self) -> impl Iterator<Item = &TlcInfo> + '_ {
676        self.received_tlcs.tlcs.iter().filter(|tlc| {
677            debug_assert!(tlc.is_received());
678            matches!(tlc.inbound_status(), InboundTlcStatus::Committed)
679        })
680    }
681
682    pub fn get_expired_offered_tlcs(
683        &self,
684        expect_expiry: u64,
685    ) -> impl Iterator<Item = &TlcInfo> + '_ {
686        self.offered_tlcs.tlcs.iter().filter(move |tlc| {
687            tlc.outbound_status() != OutboundTlcStatus::LocalAnnounced
688                && tlc.removed_confirmed_at.is_none()
689                && tlc.expiry < expect_expiry
690        })
691    }
692
693    pub fn get_next_offering(&self) -> u64 {
694        self.offered_tlcs.get_next_id()
695    }
696
697    pub fn get_next_received(&self) -> u64 {
698        self.received_tlcs.get_next_id()
699    }
700
701    pub fn increment_offering(&mut self) {
702        self.offered_tlcs.increment_next_id();
703    }
704
705    pub fn increment_received(&mut self) {
706        self.received_tlcs.increment_next_id();
707    }
708
709    pub fn set_waiting_ack(&mut self, waiting_ack: bool) {
710        self.waiting_ack = waiting_ack;
711    }
712
713    pub fn all_tlcs(&self) -> impl Iterator<Item = &TlcInfo> + '_ {
714        self.offered_tlcs
715            .tlcs
716            .iter()
717            .chain(self.received_tlcs.tlcs.iter())
718    }
719
720    pub fn apply_remove_tlc(&mut self, tlc_id: TLCId) {
721        if tlc_id.is_offered() {
722            self.offered_tlcs.tlcs.retain(|tlc| tlc.tlc_id != tlc_id);
723        } else {
724            self.received_tlcs.tlcs.retain(|tlc| tlc.tlc_id != tlc_id);
725        }
726    }
727
728    pub fn add_offered_tlc(&mut self, tlc: TlcInfo) {
729        self.offered_tlcs.add_tlc(tlc);
730    }
731
732    pub fn add_received_tlc(&mut self, tlc: TlcInfo) {
733        self.received_tlcs.add_tlc(tlc);
734    }
735
736    pub fn set_received_tlc_removed(&mut self, tlc_id: u64, reason: RemoveTlcReason) -> Hash256 {
737        let tlc = self.get_mut(&TLCId::Received(tlc_id)).expect("get tlc");
738        assert_eq!(tlc.inbound_status(), InboundTlcStatus::Committed);
739        tlc.removed_reason = Some(reason);
740        tlc.status = TlcStatus::Inbound(InboundTlcStatus::LocalRemoved);
741        tlc.payment_hash
742    }
743
744    pub fn set_offered_tlc_removed(&mut self, tlc_id: u64, reason: RemoveTlcReason) -> Hash256 {
745        let tlc = self.get_mut(&TLCId::Offered(tlc_id)).expect("get tlc");
746        assert_eq!(tlc.outbound_status(), OutboundTlcStatus::Committed);
747        tlc.removed_reason = Some(reason);
748        tlc.status = TlcStatus::Outbound(OutboundTlcStatus::RemoteRemoved);
749        tlc.payment_hash
750    }
751
752    pub fn commitment_signed_tlcs(&self, for_remote: bool) -> impl Iterator<Item = &TlcInfo> + '_ {
753        self.offered_tlcs
754            .tlcs
755            .iter()
756            .filter(move |tlc| match tlc.outbound_status() {
757                OutboundTlcStatus::LocalAnnounced => for_remote,
758                OutboundTlcStatus::Committed => true,
759                OutboundTlcStatus::RemoteRemoved => for_remote,
760                OutboundTlcStatus::RemoveWaitPrevAck => for_remote,
761                OutboundTlcStatus::RemoveWaitAck => false,
762                OutboundTlcStatus::RemoveAckConfirmed => false,
763            })
764            .chain(
765                self.received_tlcs
766                    .tlcs
767                    .iter()
768                    .filter(move |tlc| match tlc.inbound_status() {
769                        InboundTlcStatus::RemoteAnnounced => !for_remote,
770                        InboundTlcStatus::AnnounceWaitPrevAck => !for_remote,
771                        InboundTlcStatus::AnnounceWaitAck => true,
772                        InboundTlcStatus::Committed => true,
773                        InboundTlcStatus::LocalRemoved => !for_remote,
774                        InboundTlcStatus::RemoveAckConfirmed => false,
775                    }),
776            )
777    }
778
779    pub fn update_for_commitment_signed(&mut self) -> bool {
780        for tlc in self.offered_tlcs.tlcs.iter_mut() {
781            if tlc.outbound_status() == OutboundTlcStatus::RemoteRemoved {
782                let status = if self.waiting_ack {
783                    OutboundTlcStatus::RemoveWaitPrevAck
784                } else {
785                    OutboundTlcStatus::RemoveWaitAck
786                };
787                tlc.status = TlcStatus::Outbound(status);
788            }
789        }
790        for tlc in self.received_tlcs.tlcs.iter_mut() {
791            if tlc.inbound_status() == InboundTlcStatus::RemoteAnnounced {
792                let status = if self.waiting_ack {
793                    InboundTlcStatus::AnnounceWaitPrevAck
794                } else {
795                    InboundTlcStatus::AnnounceWaitAck
796                };
797                tlc.status = TlcStatus::Inbound(status)
798            }
799        }
800        self.need_another_commitment_signed()
801    }
802
803    pub fn update_for_revoke_and_ack(&mut self, commitment_number: CommitmentNumbers) {
804        for tlc in self.offered_tlcs.tlcs.iter_mut() {
805            match tlc.outbound_status() {
806                OutboundTlcStatus::LocalAnnounced => {
807                    tlc.status = TlcStatus::Outbound(OutboundTlcStatus::Committed);
808                }
809                OutboundTlcStatus::RemoveWaitPrevAck => {
810                    tlc.status = TlcStatus::Outbound(OutboundTlcStatus::RemoveWaitAck);
811                }
812                OutboundTlcStatus::RemoveWaitAck => {
813                    tlc.status = TlcStatus::Outbound(OutboundTlcStatus::RemoveAckConfirmed);
814                    tlc.removed_confirmed_at = Some(commitment_number.get_local());
815                }
816                _ => {}
817            }
818        }
819
820        for tlc in self.received_tlcs.tlcs.iter_mut() {
821            match tlc.inbound_status() {
822                InboundTlcStatus::AnnounceWaitPrevAck => {
823                    tlc.status = TlcStatus::Inbound(InboundTlcStatus::AnnounceWaitAck);
824                }
825                InboundTlcStatus::AnnounceWaitAck => {
826                    tlc.status = TlcStatus::Inbound(InboundTlcStatus::Committed);
827                }
828                InboundTlcStatus::LocalRemoved => {
829                    tlc.status = TlcStatus::Inbound(InboundTlcStatus::RemoveAckConfirmed);
830                    tlc.removed_confirmed_at = Some(commitment_number.get_remote());
831                }
832                _ => {}
833            }
834        }
835    }
836
837    pub fn need_another_commitment_signed(&self) -> bool {
838        self.offered_tlcs.tlcs.iter().any(|tlc| {
839            let status = tlc.outbound_status();
840            matches!(
841                status,
842                OutboundTlcStatus::LocalAnnounced
843                    | OutboundTlcStatus::RemoteRemoved
844                    | OutboundTlcStatus::RemoveWaitPrevAck
845                    | OutboundTlcStatus::RemoveWaitAck
846            )
847        }) || self.received_tlcs.tlcs.iter().any(|tlc| {
848            let status = tlc.inbound_status();
849            matches!(
850                status,
851                InboundTlcStatus::RemoteAnnounced
852                    | InboundTlcStatus::AnnounceWaitPrevAck
853                    | InboundTlcStatus::AnnounceWaitAck
854            )
855        })
856    }
857}
858
859/// Command to add a new TLC to a channel.
860#[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
861pub struct AddTlcCommand {
862    pub amount: u128,
863    pub payment_hash: Hash256,
864    /// The attempt id associated with the TLC.
865    pub attempt_id: Option<u64>,
866    pub expiry: u64,
867    pub hash_algorithm: HashAlgorithm,
868    /// Onion packet for the next node.
869    pub onion_packet: Option<PaymentOnionPacket>,
870    /// Shared secret used in forwarding.
871    /// Save it for outbound (offered) TLC to backward errors.
872    /// Use all zeros when no shared secrets are available.
873    pub shared_secret: [u8; 32],
874    /// Whether this outbound TLC is the trampoline-boundary hop.
875    pub is_trampoline_hop: bool,
876    pub previous_tlc: Option<PrevTlcInfo>,
877}
878
879impl fmt::Debug for AddTlcCommand {
880    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
881        f.debug_struct("AddTlcCommand")
882            .field("amount", &self.amount)
883            .field("payment_hash", &self.payment_hash)
884            .field("attempt_id", &self.attempt_id)
885            .field("expiry", &self.expiry)
886            .field("hash_algorithm", &self.hash_algorithm)
887            .field("is_trampoline_hop", &self.is_trampoline_hop)
888            .field("previous_tlc", &self.previous_tlc)
889            .finish()
890    }
891}
892
893/// A retryable TLC operation that may need to be replayed after reconnection.
894#[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Debug, Hash)]
895pub enum RetryableTlcOperation {
896    RemoveTlc(TLCId, RemoveTlcReason),
897    AddTlc(AddTlcCommand),
898}
899
900/// Message to add a TLC to the channel.
901#[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
902pub struct AddTlc {
903    pub channel_id: Hash256,
904    pub tlc_id: u64,
905    pub amount: u128,
906    pub payment_hash: Hash256,
907    pub expiry: u64,
908    pub hash_algorithm: HashAlgorithm,
909    pub onion_packet: Option<PaymentOnionPacket>,
910}
911
912impl fmt::Debug for AddTlc {
913    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
914        f.debug_struct("AddTlc")
915            .field("channel_id", &self.channel_id)
916            .field("tlc_id", &self.tlc_id)
917            .field("amount", &self.amount)
918            .field("payment_hash", &self.payment_hash)
919            .field("expiry", &self.expiry)
920            .field("hash_algorithm", &self.hash_algorithm)
921            .finish()
922    }
923}
924
925impl From<AddTlc> for molecule_fiber::AddTlc {
926    fn from(add_tlc: AddTlc) -> Self {
927        molecule_fiber::AddTlc::new_builder()
928            .channel_id(add_tlc.channel_id.into())
929            .tlc_id(add_tlc.tlc_id.pack())
930            .amount(add_tlc.amount.pack())
931            .payment_hash(add_tlc.payment_hash.into())
932            .expiry(add_tlc.expiry.pack())
933            .hash_algorithm(molecule::prelude::Byte::new(add_tlc.hash_algorithm as u8))
934            .onion_packet(
935                add_tlc
936                    .onion_packet
937                    .map(|p| p.into_bytes())
938                    .unwrap_or_default()
939                    .pack(),
940            )
941            .build()
942    }
943}
944
945impl TryFrom<molecule_fiber::AddTlc> for AddTlc {
946    type Error = anyhow::Error;
947
948    fn try_from(add_tlc: molecule_fiber::AddTlc) -> Result<Self, Self::Error> {
949        let onion_packet_bytes: Vec<u8> = add_tlc.onion_packet().unpack();
950        let onion_packet =
951            (!onion_packet_bytes.is_empty()).then(|| PaymentOnionPacket::new(onion_packet_bytes));
952        Ok(AddTlc {
953            onion_packet,
954            channel_id: add_tlc.channel_id().into(),
955            tlc_id: add_tlc.tlc_id().unpack(),
956            amount: add_tlc.amount().unpack(),
957            payment_hash: add_tlc.payment_hash().into(),
958            expiry: add_tlc.expiry().unpack(),
959            hash_algorithm: add_tlc
960                .hash_algorithm()
961                .try_into()
962                .map_err(|e: crate::invoice::UnknownHashAlgorithmError| anyhow::anyhow!(e))?,
963        })
964    }
965}
966
967/// Message to remove a TLC from the channel.
968#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
969pub struct RemoveTlc {
970    pub channel_id: Hash256,
971    pub tlc_id: u64,
972    pub reason: RemoveTlcReason,
973}
974
975impl From<RemoveTlc> for molecule_fiber::RemoveTlc {
976    fn from(remove_tlc: RemoveTlc) -> Self {
977        molecule_fiber::RemoveTlc::new_builder()
978            .channel_id(remove_tlc.channel_id.into())
979            .tlc_id(remove_tlc.tlc_id.pack())
980            .reason(
981                molecule_fiber::RemoveTlcReason::new_builder()
982                    .set(remove_tlc.reason)
983                    .build(),
984            )
985            .build()
986    }
987}
988
989impl TryFrom<molecule_fiber::RemoveTlc> for RemoveTlc {
990    type Error = anyhow::Error;
991
992    fn try_from(remove_tlc: molecule_fiber::RemoveTlc) -> Result<Self, Self::Error> {
993        Ok(RemoveTlc {
994            channel_id: remove_tlc.channel_id().into(),
995            tlc_id: remove_tlc.tlc_id().unpack(),
996            reason: remove_tlc.reason().into(),
997        })
998    }
999}
1000
1001/// TLC update message to resend during channel reestablishment.
1002#[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Debug, Hash)]
1003pub enum TlcReplayUpdate {
1004    Add(AddTlc),
1005    Remove(RemoveTlc),
1006}
1007
1008/// Version for `CommitDiff` serialization compatibility.
1009pub const CURRENT_COMMIT_DIFF_VERSION: u8 = 2;
1010
1011fn default_commit_diff_version() -> u8 {
1012    CURRENT_COMMIT_DIFF_VERSION
1013}
1014
1015/// Optional template fields for `CommitmentSigned` replay.
1016#[serde_as]
1017#[derive(Clone, Debug, Serialize, Deserialize)]
1018pub struct CommitmentSignedTemplate {
1019    #[serde_as(as = "PubNonceAsBytes")]
1020    pub next_commitment_nonce: PubNonce,
1021    #[serde(default)]
1022    #[serde_as(as = "Option<PartialSignatureAsBytes>")]
1023    pub funding_tx_partial_signature: Option<PartialSignature>,
1024}
1025
1026/// Replay ordering hint when both revoke+commit are owed.
1027#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
1028pub enum ReplayOrderHint {
1029    RevokeThenCommit,
1030    CommitThenRevoke,
1031}
1032
1033/// Everything needed to resend a pending `CommitmentSigned` after reconnect.
1034#[serde_as]
1035#[derive(Clone, Debug, Serialize, Deserialize)]
1036pub struct CommitDiff {
1037    /// Structure version for backward/forward compatibility.
1038    #[serde(default = "default_commit_diff_version")]
1039    pub version: u8,
1040    /// Channel that owns this diff.
1041    #[serde(default)]
1042    pub channel_id: Hash256,
1043    /// Local/remote commitment numbers when this commitment was sent.
1044    #[serde(default)]
1045    pub local_commitment_number_at_send: u64,
1046    #[serde(default)]
1047    pub remote_commitment_number_at_send: u64,
1048    /// The commitment transaction (used for resign, not rebuilt).
1049    #[serde_as(as = "EntityHex")]
1050    pub commit_tx: Transaction,
1051    /// TLC updates included in this commitment (for resending).
1052    #[serde(default, alias = "tlc_updates")]
1053    pub replay_updates: Vec<TlcReplayUpdate>,
1054    /// Optional template fields for `CommitmentSigned` replay.
1055    #[serde(default)]
1056    pub commitment_signed_template: Option<CommitmentSignedTemplate>,
1057    /// Optional replay ordering hint when both revoke+commit are owed.
1058    #[serde(default)]
1059    pub replay_order_hint: Option<ReplayOrderHint>,
1060    /// Creation timestamp.
1061    #[serde(default, alias = "created_at")]
1062    pub created_at_ms: u64,
1063}
1064
1065/// Information about a channel shutdown.
1066#[serde_as]
1067#[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Debug)]
1068pub struct ShutdownInfo {
1069    #[serde_as(as = "EntityHex")]
1070    pub close_script: Script,
1071    pub fee_rate: u64,
1072    #[serde_as(as = "Option<PartialSignatureAsBytes>")]
1073    pub signature: Option<PartialSignature>,
1074}
1075
1076/// Message to revoke the previous commitment and acknowledge the new one.
1077#[serde_as]
1078#[derive(Debug, Clone, Serialize, Deserialize)]
1079pub struct RevokeAndAck {
1080    pub channel_id: Hash256,
1081    #[serde_as(as = "PartialSignatureAsBytes")]
1082    pub revocation_partial_signature: PartialSignature,
1083    pub next_per_commitment_point: Pubkey,
1084    #[serde_as(as = "PubNonceAsBytes")]
1085    pub next_revocation_nonce: PubNonce,
1086}
1087// This struct holds the channel information that are only relevant when the channel
1088// is public. The information includes signatures to the channel announcement message,
1089// our config for the channel that will be published to the network (via ChannelUpdate).
1090// For ChannelUpdate config, only information on our side are saved here because we have no
1091// control to the config on the counterparty side. And they will publish
1092// the config to the network via another ChannelUpdate message.
1093#[serde_as]
1094#[derive(Default, Clone, Debug, Serialize, Deserialize)]
1095pub struct PublicChannelInfo {
1096    /// Channel announcement signatures, may be empty for private channel.
1097    #[serde_as(as = "Option<(_, PartialSignatureAsBytes)>")]
1098    pub local_channel_announcement_signature: Option<(EcdsaSignature, PartialSignature)>,
1099    #[serde_as(as = "Option<(_, PartialSignatureAsBytes)>")]
1100    pub remote_channel_announcement_signature: Option<(EcdsaSignature, PartialSignature)>,
1101    #[serde_as(as = "Option<PubNonceAsBytes>")]
1102    pub remote_channel_announcement_nonce: Option<PubNonce>,
1103    pub channel_announcement: Option<ChannelAnnouncement>,
1104    pub channel_update: Option<ChannelUpdate>,
1105}
1106
1107impl PublicChannelInfo {
1108    pub fn new() -> Self {
1109        Default::default()
1110    }
1111}
1112
1113/// A simple implementation of a channel signer that keeps the private keys in memory.
1114///
1115/// This implementation performs no policy checks and is insufficient by itself as
1116/// a secure external signer.
1117#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
1118pub struct InMemorySigner {
1119    /// Holder secret key in the 2-of-2 multisig script of a channel.
1120    pub funding_key: Privkey,
1121    /// Holder HTLC secret key used in commitment transaction HTLC outputs.
1122    pub tlc_base_key: Privkey,
1123    /// SecNonce used to generate valid signature in musig.
1124    pub musig2_base_nonce: Privkey,
1125    /// Seed to derive above keys (per commitment).
1126    pub commitment_seed: [u8; 32],
1127}
1128
1129impl fmt::Debug for InMemorySigner {
1130    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1131        f.debug_struct("InMemorySigner")
1132            .field("funding_key", &"[REDACTED]")
1133            .field("tlc_base_key", &"[REDACTED]")
1134            .field("musig2_base_nonce", &"[REDACTED]")
1135            .field("commitment_seed", &"[REDACTED]")
1136            .finish()
1137    }
1138}
1139
1140/// Hash data with a salt using blake2b.
1141pub fn blake2b_hash_with_salt(data: &[u8], salt: &[u8]) -> [u8; 32] {
1142    let mut hasher = ckb_hash::new_blake2b();
1143    hasher.update(salt);
1144    hasher.update(data);
1145    let mut result = [0u8; 32];
1146    hasher.finalize(&mut result);
1147    result
1148}
1149
1150/// Compute a tweak value from a commitment point using blake2b.
1151pub fn get_tweak_by_commitment_point(commitment_point: &Pubkey) -> [u8; 32] {
1152    let mut hasher = ckb_hash::new_blake2b();
1153    hasher.update(&commitment_point.serialize());
1154    let mut result = [0u8; 32];
1155    hasher.finalize(&mut result);
1156    result
1157}
1158
1159/// Derive a private key by tweaking a secret with a commitment point.
1160pub fn derive_private_key(secret: &Privkey, commitment_point: &Pubkey) -> Privkey {
1161    secret.tweak(get_tweak_by_commitment_point(commitment_point))
1162}
1163
1164/// Derive a public key by tweaking a base key with a commitment point.
1165pub fn derive_public_key(base_key: &Pubkey, commitment_point: &Pubkey) -> Pubkey {
1166    base_key.tweak(get_tweak_by_commitment_point(commitment_point))
1167}
1168
1169/// Derive the TLC public key from a base key and commitment point.
1170pub fn derive_tlc_pubkey(base_key: &Pubkey, commitment_point: &Pubkey) -> Pubkey {
1171    derive_public_key(base_key, commitment_point)
1172}
1173
1174/// Derive the commitment secret for a given commitment number from a seed.
1175///
1176/// The commitment number should be in the range \[0, 2^48).
1177pub fn get_commitment_secret(commitment_seed: &[u8; 32], commitment_number: u64) -> [u8; 32] {
1178    let mut res: [u8; 32] = *commitment_seed;
1179    for i in 0..48 {
1180        let bitpos = 47 - i;
1181        if commitment_number & (1 << bitpos) == (1 << bitpos) {
1182            res[bitpos / 8] ^= 1 << (bitpos & 7);
1183            res = ckb_hash::blake2b_256(res);
1184        }
1185    }
1186    res
1187}
1188
1189/// Derive the commitment point (public key) for a given commitment number from a seed.
1190pub fn get_commitment_point(commitment_seed: &[u8; 32], commitment_number: u64) -> Pubkey {
1191    Privkey::from(&get_commitment_secret(commitment_seed, commitment_number)).pubkey()
1192}
1193
1194/// Context for musig2 nonce derivation.
1195pub enum Musig2Context {
1196    /// Commitment transaction context.
1197    Commitment,
1198    /// Revocation context.
1199    Revoke,
1200}
1201
1202impl std::fmt::Display for Musig2Context {
1203    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1204        let context_str = match self {
1205            Musig2Context::Commitment => "COMMITMENT",
1206            Musig2Context::Revoke => "REVOKE",
1207        };
1208        write!(f, "{}", context_str)
1209    }
1210}
1211
1212impl InMemorySigner {
1213    /// Generate an `InMemorySigner` from a seed.
1214    pub fn generate_from_seed(params: &[u8]) -> InMemorySigner {
1215        let seed = ckb_hash::blake2b_256(params);
1216
1217        let commitment_seed = {
1218            let mut hasher = ckb_hash::new_blake2b();
1219            hasher.update(&seed);
1220            hasher.update(&b"commitment seed"[..]);
1221            let mut result = [0u8; 32];
1222            hasher.finalize(&mut result);
1223            result
1224        };
1225
1226        let key_derive = |seed: &[u8], info: &[u8]| {
1227            let result = blake2b_hash_with_salt(seed, info);
1228            Privkey::from_slice(&result)
1229        };
1230
1231        let funding_key = key_derive(&seed, b"funding key");
1232        let tlc_base_key = key_derive(funding_key.as_ref(), b"HTLC base key");
1233        let musig2_base_nonce = key_derive(tlc_base_key.as_ref(), b"musig nocne");
1234
1235        InMemorySigner {
1236            funding_key,
1237            tlc_base_key,
1238            musig2_base_nonce,
1239            commitment_seed,
1240        }
1241    }
1242
1243    /// Get the base public keys for this signer.
1244    pub fn get_base_public_keys(&self) -> ChannelBasePublicKeys {
1245        ChannelBasePublicKeys {
1246            funding_pubkey: self.funding_key.pubkey(),
1247            tlc_base_key: self.tlc_base_key.pubkey(),
1248        }
1249    }
1250
1251    /// Returns the commitment point for the given commitment number.
1252    ///
1253    /// The commitment point is the public key derived from the commitment seed
1254    /// and the commitment number. It is used to derive the pubkeys used in
1255    /// TLC (htlc and revocation outputs).
1256    pub fn get_commitment_point(&self, commitment_number: u64) -> Pubkey {
1257        get_commitment_point(&self.commitment_seed, commitment_number)
1258    }
1259
1260    /// Returns the commitment secret for the given commitment number.
1261    pub fn get_commitment_secret(&self, commitment_number: u64) -> [u8; 32] {
1262        get_commitment_secret(&self.commitment_seed, commitment_number)
1263    }
1264
1265    /// Derive the TLC key for the given commitment number.
1266    pub fn derive_tlc_key(&self, new_commitment_number: u64) -> Privkey {
1267        let per_commitment_point = self.get_commitment_point(new_commitment_number);
1268        derive_private_key(&self.tlc_base_key, &per_commitment_point)
1269    }
1270
1271    /// Derive a musig2 nonce for the given commitment number and context.
1272    pub fn derive_musig2_nonce(&self, commitment_number: u64, context: Musig2Context) -> SecNonce {
1273        let commitment_point = self.get_commitment_point(commitment_number);
1274        let seckey = derive_private_key(&self.musig2_base_nonce, &commitment_point);
1275
1276        SecNonceBuilder::new(seckey.as_ref())
1277            .with_extra_input(&context.to_string())
1278            .build()
1279    }
1280}
1281
1282/// The status of a channel opening operation initiated by the local node.
1283#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
1284pub enum ChannelOpeningStatus {
1285    /// The `open_channel` RPC has been submitted and the `OpenChannel` message has been sent
1286    /// to the peer. We are waiting for the peer to respond with an `AcceptChannel` message.
1287    WaitingForPeer,
1288    /// The peer accepted the channel. We are now collaborating on the funding transaction.
1289    FundingTxBuilding,
1290    /// The funding transaction has been submitted to the chain and is awaiting confirmation.
1291    FundingTxBroadcasted,
1292    /// The funding transaction has been confirmed and the channel is fully open.
1293    ChannelReady,
1294    /// The channel opening failed. The `failure_detail` field contains the reason.
1295    Failed,
1296}
1297
1298/// A record that tracks a channel-opening attempt — either outbound (initiated by us)
1299/// or inbound (initiated by a remote peer and pending local acceptance).
1300///
1301/// Outbound records are created when `open_channel` is called.
1302/// Inbound records are created when an `OpenChannel` message is received from a peer.
1303#[serde_as]
1304#[derive(Clone, Debug, Serialize, Deserialize)]
1305pub struct ChannelOpenRecord {
1306    /// The channel ID. For outbound channels this is initially the temporary ID; it is
1307    /// updated to the final channel ID once the peer sends `AcceptChannel`. For inbound
1308    /// channels, the temp ID is replaced by the computed new ID when `accept_channel` is
1309    /// called.
1310    pub channel_id: Hash256,
1311    /// The remote peer public key.
1312    pub pubkey: Pubkey,
1313    /// Whether the local node is the accepting side (received the `OpenChannel` request).
1314    pub is_acceptor: bool,
1315    /// Current status of the opening process.
1316    pub status: ChannelOpeningStatus,
1317    /// The local node's funding amount for the channel.
1318    /// For outbound channels this is what the initiator contributes.
1319    /// For inbound channels this is set to the remote peer's funding amount.
1320    pub funding_amount: u128,
1321    /// Human-readable description of why the opening failed, set only when `status == Failed`.
1322    pub failure_detail: Option<String>,
1323    /// Timestamp (milliseconds since UNIX epoch) when the record was created.
1324    pub created_at: u64,
1325    /// Timestamp (milliseconds since UNIX epoch) of the last status update.
1326    pub last_updated_at: u64,
1327}
1328
1329impl ChannelOpenRecord {
1330    /// Create a new outbound record in the `WaitingForPeer` state.
1331    pub fn new(channel_id: Hash256, pubkey: Pubkey, funding_amount: u128) -> Self {
1332        let now = crate::now_timestamp_as_millis_u64();
1333        Self {
1334            channel_id,
1335            pubkey,
1336            is_acceptor: false,
1337            status: ChannelOpeningStatus::WaitingForPeer,
1338            funding_amount,
1339            failure_detail: None,
1340            created_at: now,
1341            last_updated_at: now,
1342        }
1343    }
1344
1345    /// Create a new inbound record in the `WaitingForPeer` state.
1346    /// Used when a remote peer's `OpenChannel` request is queued for local acceptance.
1347    pub fn new_inbound(channel_id: Hash256, pubkey: Pubkey, remote_funding_amount: u128) -> Self {
1348        let mut record = Self::new(channel_id, pubkey, remote_funding_amount);
1349        record.is_acceptor = true;
1350        record
1351    }
1352
1353    /// Transition to a new status.
1354    pub fn update_status(&mut self, status: ChannelOpeningStatus) {
1355        self.status = status;
1356        self.last_updated_at = crate::now_timestamp_as_millis_u64();
1357    }
1358
1359    /// Transition to `Failed` and record the reason.
1360    pub fn fail(&mut self, reason: String) {
1361        self.status = ChannelOpeningStatus::Failed;
1362        self.failure_detail = Some(reason);
1363        self.last_updated_at = crate::now_timestamp_as_millis_u64();
1364    }
1365}
1366
1367/// Store trait for persisting and querying outbound channel-opening records.
1368pub trait ChannelOpenRecordStore {
1369    /// Return all stored channel-opening records.
1370    fn get_channel_open_records(&self) -> Vec<ChannelOpenRecord>;
1371    /// Return the record for the given channel ID, if any.
1372    fn get_channel_open_record(&self, channel_id: &Hash256) -> Option<ChannelOpenRecord>;
1373    /// Persist (insert or overwrite) a channel-opening record.
1374    fn insert_channel_open_record(&self, record: ChannelOpenRecord);
1375    /// Delete the record for the given channel ID.
1376    fn delete_channel_open_record(&self, channel_id: &Hash256);
1377}
1378
1379/// A TLC that is pending notification for settlement.
1380#[derive(Clone, Serialize, Deserialize, Debug)]
1381pub struct PendingNotifySettleTlc {
1382    pub payment_hash: Hash256,
1383    pub tlc_id: u64,
1384    /// The expire time if the TLC should be held.
1385    pub hold_expire_at: Option<u64>,
1386}
1387
1388impl PendingNotifySettleTlc {
1389    /// Check if a PendingNotifySettleTlc should be held.
1390    pub fn pending_notify_should_hold(&self) -> bool {
1391        self.hold_expire_at.is_some()
1392    }
1393
1394    /// Get the remaining hold expiry duration for a PendingNotifySettleTlc.
1395    pub fn pending_notify_hold_expiry_duration(
1396        &self,
1397        now_millis_since_unix_epoch: u64,
1398    ) -> Duration {
1399        Duration::from_millis(
1400            self.hold_expire_at
1401                .unwrap_or_default()
1402                .saturating_sub(now_millis_since_unix_epoch),
1403        )
1404    }
1405}
1406
1407/// The core serializable state of a channel actor.
1408///
1409/// This struct contains all the persistable fields of a channel.
1410/// Runtime-only fields (like actor references) are managed separately in fiber-lib.
1411#[serde_as]
1412#[derive(Clone, Serialize, Deserialize)]
1413pub struct ChannelActorData {
1414    pub state: ChannelState,
1415    /// The data below are only relevant if the channel is public.
1416    pub public_channel_info: Option<PublicChannelInfo>,
1417
1418    pub local_tlc_info: ChannelTlcInfo,
1419    pub remote_tlc_info: Option<ChannelTlcInfo>,
1420
1421    /// The local public key used to establish p2p network connection.
1422    pub local_pubkey: Pubkey,
1423    /// The remote public key used to establish p2p network connection.
1424    pub remote_pubkey: Pubkey,
1425
1426    pub id: Hash256,
1427    #[serde_as(as = "Option<EntityHex>")]
1428    pub funding_tx: Option<Transaction>,
1429
1430    pub funding_tx_confirmed_at: Option<(H256, u32, u64)>,
1431
1432    #[serde_as(as = "Option<EntityHex>")]
1433    pub funding_udt_type_script: Option<Script>,
1434
1435    /// Is this channel initially inbound?
1436    /// An inbound channel is one where the counterparty is the funder of the channel.
1437    pub is_acceptor: bool,
1438
1439    /// Is this channel one-way?
1440    /// Combines with is_acceptor to determine if the channel able to send payment to the counterparty or not.
1441    pub is_one_way: bool,
1442
1443    /// The amount of CKB/UDT that we own in the channel.
1444    /// This value will only change after we have resolved a tlc.
1445    pub to_local_amount: u128,
1446    /// The amount of CKB/UDT that the remote owns in the channel.
1447    /// This value will only change after we have resolved a tlc.
1448    pub to_remote_amount: u128,
1449
1450    /// These two amounts used to keep the minimal ckb amount for the two parties.
1451    /// TLC operations will not affect these two amounts, only used to keep the commitment transactions
1452    /// to be valid, so that any party can close the channel at any time.
1453    pub local_reserved_ckb_amount: u64,
1454    pub remote_reserved_ckb_amount: u64,
1455
1456    /// The commitment fee rate is used to calculate the fee for the commitment transactions.
1457    /// The side who want to submit the commitment transaction will pay fee.
1458    pub commitment_fee_rate: u64,
1459
1460    /// The delay time for the commitment transaction, this value is set by the initiator of the channel.
1461    /// It must be a relative EpochNumberWithFraction in u64 format.
1462    pub commitment_delay_epoch: u64,
1463
1464    /// The fee rate used for funding transaction, the initiator may set it as `funding_fee_rate` option,
1465    /// if it's not set, DEFAULT_FEE_RATE will be used as default value, two sides will use the same fee rate.
1466    pub funding_fee_rate: u64,
1467
1468    /// Signer is used to sign the commitment transactions.
1469    pub signer: InMemorySigner,
1470
1471    /// Cached channel public keys for easier of access.
1472    pub local_channel_public_keys: ChannelBasePublicKeys,
1473
1474    /// Commitment numbers that are used to derive keys.
1475    /// This value is guaranteed to be 0 when channel is just created.
1476    pub commitment_numbers: CommitmentNumbers,
1477
1478    pub local_constraints: ChannelConstraints,
1479    pub remote_constraints: ChannelConstraints,
1480
1481    /// All the TLC related information.
1482    pub tlc_state: TlcState,
1483
1484    /// The retryable tlc operations that are waiting to be processed.
1485    pub retryable_tlc_operations: VecDeque<RetryableTlcOperation>,
1486    pub waiting_forward_tlc_tasks: HashMap<TLCId, [u8; 32]>,
1487
1488    /// The remote lock script for close channel, setup during the channel establishment.
1489    #[serde_as(as = "Option<EntityHex>")]
1490    pub remote_shutdown_script: Option<Script>,
1491    /// The local lock script for close channel.
1492    #[serde_as(as = "EntityHex")]
1493    pub local_shutdown_script: Script,
1494
1495    /// Basically the latest remote nonce sent by the peer with the CommitmentSigned message,
1496    /// but we will only update this field after we have sent a RevokeAndAck to the peer.
1497    #[serde_as(as = "Option<PubNonceAsBytes>")]
1498    pub last_committed_remote_nonce: Option<PubNonce>,
1499
1500    #[serde_as(as = "Option<PubNonceAsBytes>")]
1501    pub remote_revocation_nonce_for_verify: Option<PubNonce>,
1502    #[serde_as(as = "Option<PubNonceAsBytes>")]
1503    pub remote_revocation_nonce_for_send: Option<PubNonce>,
1504    #[serde_as(as = "Option<PubNonceAsBytes>")]
1505    pub remote_revocation_nonce_for_next: Option<PubNonce>,
1506
1507    /// The latest commitment transaction we're holding,
1508    /// it can be broadcasted to blockchain by us to force close the channel.
1509    #[serde_as(as = "Option<EntityHex>")]
1510    pub latest_commitment_transaction: Option<Transaction>,
1511
1512    /// All the commitment point that are sent from the counterparty.
1513    /// We need to save all these points to derive the keys for the commitment transactions.
1514    pub remote_commitment_points: Vec<(u64, Pubkey)>,
1515    pub remote_channel_public_keys: Option<ChannelBasePublicKeys>,
1516
1517    /// The shutdown info for both local and remote, setup by the shutdown command or message.
1518    pub local_shutdown_info: Option<ShutdownInfo>,
1519    pub remote_shutdown_info: Option<ShutdownInfo>,
1520
1521    /// Transaction hash of the shutdown transaction.
1522    /// The shutdown transaction can be COOPERATIVE or UNCOOPERATIVE.
1523    pub shutdown_transaction_hash: Option<H256>,
1524
1525    /// A flag to indicate whether the channel is reestablishing,
1526    /// we won't process any messages until the channel is reestablished.
1527    pub reestablishing: bool,
1528    pub last_revoke_ack_msg: Option<RevokeAndAck>,
1529
1530    pub created_at: SystemTime,
1531
1532    /// TLC updates sent to peer since the last local CommitmentSigned.
1533    /// This preserves send order for reestablish replay.
1534    #[serde(default)]
1535    pub pending_replay_updates: Vec<TlcReplayUpdate>,
1536
1537    /// Tracks whether the last outbound sync message was RevokeAndAck.
1538    #[serde(default)]
1539    pub last_was_revoke: bool,
1540}
1541
1542fn partial_signature_to_molecule(partial_signature: PartialSignature) -> MByte32 {
1543    MByte32::from_slice(partial_signature.serialize().as_ref()).expect("[Byte; 32] from [u8; 32]")
1544}
1545
1546fn pub_nonce_to_molecule(pub_nonce: PubNonce) -> molecule_fiber::PubNonce {
1547    molecule_fiber::PubNonce::from_slice(pub_nonce.to_bytes().as_ref())
1548        .expect("PubNonce from 66 bytes")
1549}
1550
1551impl From<PubNonce> for molecule_fiber::PubNonce {
1552    fn from(value: PubNonce) -> Self {
1553        molecule_fiber::PubNonce::from_slice(value.to_bytes().as_ref())
1554            .expect("valid pubnonce serialized to 66 bytes")
1555    }
1556}
1557
1558impl TryFrom<molecule_fiber::PubNonce> for PubNonce {
1559    type Error = musig2::errors::DecodeError<PubNonce>;
1560
1561    fn try_from(value: molecule_fiber::PubNonce) -> Result<Self, Self::Error> {
1562        PubNonce::from_bytes(value.as_slice())
1563    }
1564}
1565
1566impl From<RevokeAndAck> for molecule_fiber::RevokeAndAck {
1567    fn from(revoke_and_ack: RevokeAndAck) -> Self {
1568        molecule_fiber::RevokeAndAck::new_builder()
1569            .channel_id(revoke_and_ack.channel_id.into())
1570            .revocation_partial_signature(partial_signature_to_molecule(
1571                revoke_and_ack.revocation_partial_signature,
1572            ))
1573            .next_per_commitment_point(revoke_and_ack.next_per_commitment_point.into())
1574            .next_revocation_nonce(pub_nonce_to_molecule(revoke_and_ack.next_revocation_nonce))
1575            .build()
1576    }
1577}
1578
1579impl TryFrom<molecule_fiber::RevokeAndAck> for RevokeAndAck {
1580    type Error = anyhow::Error;
1581
1582    fn try_from(revoke_and_ack: molecule_fiber::RevokeAndAck) -> Result<Self, Self::Error> {
1583        Ok(RevokeAndAck {
1584            channel_id: revoke_and_ack.channel_id().into(),
1585            revocation_partial_signature: PartialSignature::from_slice(
1586                revoke_and_ack.revocation_partial_signature().as_slice(),
1587            )
1588            .map_err(|e| anyhow::anyhow!(e))?,
1589            next_per_commitment_point: revoke_and_ack
1590                .next_per_commitment_point()
1591                .try_into()
1592                .map_err(|e: secp256k1::Error| anyhow::anyhow!(e))?,
1593            next_revocation_nonce: PubNonce::from_bytes(
1594                revoke_and_ack.next_revocation_nonce().as_slice(),
1595            )
1596            .map_err(|e| anyhow::anyhow!("{}", e))?,
1597        })
1598    }
1599}
1600
1601/// The fulfillment of a TLC removal.
1602#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
1603pub struct RemoveTlcFulfill {
1604    pub payment_preimage: Hash256,
1605}
1606
1607/// The reason for removing a TLC.
1608#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
1609pub enum RemoveTlcReason {
1610    RemoveTlcFulfill(RemoveTlcFulfill),
1611    RemoveTlcFail(TlcErrPacket),
1612}
1613
1614impl Debug for RemoveTlcReason {
1615    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1616        match self {
1617            RemoveTlcReason::RemoveTlcFulfill(_fulfill) => {
1618                write!(f, "RemoveTlcFulfill")
1619            }
1620            RemoveTlcReason::RemoveTlcFail(_fail) => {
1621                write!(f, "RemoveTlcFail")
1622            }
1623        }
1624    }
1625}
1626
1627impl RemoveTlcReason {
1628    /// Intermediate node backwards the error to the previous hop using the shared secret
1629    /// used in forwarding the onion packet.
1630    pub fn backward(self, shared_secret: &[u8; 32]) -> Self {
1631        match self {
1632            RemoveTlcReason::RemoveTlcFulfill(remove_tlc_fulfill) => {
1633                RemoveTlcReason::RemoveTlcFulfill(remove_tlc_fulfill)
1634            }
1635            RemoveTlcReason::RemoveTlcFail(remove_tlc_fail) => {
1636                RemoveTlcReason::RemoveTlcFail(remove_tlc_fail.backward(shared_secret))
1637            }
1638        }
1639    }
1640}
1641
1642impl From<RemoveTlcReason> for molecule_fiber::RemoveTlcReasonUnion {
1643    fn from(remove_tlc_reason: RemoveTlcReason) -> Self {
1644        match remove_tlc_reason {
1645            RemoveTlcReason::RemoveTlcFulfill(remove_tlc_fulfill) => {
1646                molecule_fiber::RemoveTlcReasonUnion::RemoveTlcFulfill(remove_tlc_fulfill.into())
1647            }
1648            RemoveTlcReason::RemoveTlcFail(remove_tlc_fail) => {
1649                molecule_fiber::RemoveTlcReasonUnion::TlcErrPacket(remove_tlc_fail.into())
1650            }
1651        }
1652    }
1653}
1654
1655impl From<RemoveTlcReason> for molecule_fiber::RemoveTlcReason {
1656    fn from(remove_tlc_reason: RemoveTlcReason) -> Self {
1657        molecule_fiber::RemoveTlcReason::new_builder()
1658            .set(remove_tlc_reason)
1659            .build()
1660    }
1661}
1662
1663impl From<molecule_fiber::RemoveTlcReason> for RemoveTlcReason {
1664    fn from(remove_tlc_reason: molecule_fiber::RemoveTlcReason) -> Self {
1665        match remove_tlc_reason.to_enum() {
1666            molecule_fiber::RemoveTlcReasonUnion::RemoveTlcFulfill(remove_tlc_fulfill) => {
1667                RemoveTlcReason::RemoveTlcFulfill(remove_tlc_fulfill.into())
1668            }
1669            molecule_fiber::RemoveTlcReasonUnion::TlcErrPacket(remove_tlc_fail) => {
1670                RemoveTlcReason::RemoveTlcFail(remove_tlc_fail.into())
1671            }
1672        }
1673    }
1674}
1675
1676impl From<RemoveTlcFulfill> for molecule_fiber::RemoveTlcFulfill {
1677    fn from(remove_tlc_fulfill: RemoveTlcFulfill) -> Self {
1678        molecule_fiber::RemoveTlcFulfill::new_builder()
1679            .payment_preimage(remove_tlc_fulfill.payment_preimage.into())
1680            .build()
1681    }
1682}
1683
1684impl From<molecule_fiber::RemoveTlcFulfill> for RemoveTlcFulfill {
1685    fn from(remove_tlc_fulfill: molecule_fiber::RemoveTlcFulfill) -> Self {
1686        RemoveTlcFulfill {
1687            payment_preimage: remove_tlc_fulfill.payment_preimage().into(),
1688        }
1689    }
1690}
1691
1692/// The channel update info with a single direction of channel.
1693///
1694/// This is a pure data struct used by both the internal graph representation
1695/// and the RPC JSON response types.
1696#[serde_as]
1697#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
1698pub struct ChannelUpdateInfo {
1699    /// The timestamp is the time when the channel update was received by the node.
1700    #[serde_as(as = "crate::U64Hex")]
1701    pub timestamp: u64,
1702    /// Whether the channel can be currently used for payments (in this one direction).
1703    pub enabled: bool,
1704    /// The exact amount of balance that we can send to the other party via the channel.
1705    #[serde_as(as = "Option<crate::U128Hex>")]
1706    pub outbound_liquidity: Option<u128>,
1707    /// The difference in htlc expiry values that you must have when routing through this channel (in milliseconds).
1708    #[serde_as(as = "crate::U64Hex")]
1709    pub tlc_expiry_delta: u64,
1710    /// The minimum value, which must be relayed to the next hop via the channel
1711    #[serde_as(as = "crate::U128Hex")]
1712    pub tlc_minimum_value: u128,
1713    /// The forwarding fee rate for the channel.
1714    #[serde_as(as = "crate::U64Hex")]
1715    pub fee_rate: u64,
1716}
1717
1718impl From<&ChannelTlcInfo> for ChannelUpdateInfo {
1719    fn from(info: &ChannelTlcInfo) -> Self {
1720        Self {
1721            timestamp: info.timestamp,
1722            enabled: info.enabled,
1723            outbound_liquidity: None,
1724            tlc_expiry_delta: info.tlc_expiry_delta,
1725            tlc_minimum_value: info.tlc_minimum_value,
1726            fee_rate: info.tlc_fee_proportional_millionths as u64,
1727        }
1728    }
1729}
1730
1731impl From<ChannelTlcInfo> for ChannelUpdateInfo {
1732    fn from(info: ChannelTlcInfo) -> Self {
1733        Self::from(&info)
1734    }
1735}
1736
1737impl From<crate::protocol::ChannelUpdate> for ChannelUpdateInfo {
1738    fn from(update: crate::protocol::ChannelUpdate) -> Self {
1739        Self::from(&update)
1740    }
1741}
1742
1743impl From<&crate::protocol::ChannelUpdate> for ChannelUpdateInfo {
1744    fn from(update: &crate::protocol::ChannelUpdate) -> Self {
1745        Self {
1746            timestamp: update.timestamp,
1747            enabled: !update.is_disabled(),
1748            outbound_liquidity: None,
1749            tlc_expiry_delta: update.tlc_expiry_delta,
1750            tlc_minimum_value: update.tlc_minimum_value,
1751            fee_rate: update.tlc_fee_proportional_millionths as u64,
1752        }
1753    }
1754}