-
Notifications
You must be signed in to change notification settings - Fork 159
Expand file tree
/
Copy pathstore.rs
More file actions
130 lines (115 loc) · 3.94 KB
/
Copy pathstore.rs
File metadata and controls
130 lines (115 loc) · 3.94 KB
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
// This file is Copyright its original authors, visible in version control history.
//
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
// accordance with one or both of these licenses.
use bitcoin::secp256k1::PublicKey;
use lightning::impl_writeable_tlv_based_enum;
use lightning::ln::types::ChannelId;
use crate::data_store::{StorableObject, StorableObjectId, StorableObjectUpdate};
use crate::hex_utils;
use crate::types::UserChannelId;
/// Persistent per-channel state tracked by LDK Node, keyed by [`UserChannelId`].
///
/// Durably stores channel flags at `ChannelPending` time so they remain accessible when the
/// channel closes, even after a restart or a [`ReplayEvent`]. The `Funded` variant is designed
/// to be extended with a `pending_splice` field in a future PR to support splice retry across
/// restarts and peer disconnects.
///
/// [`ReplayEvent`]: lightning::events::ReplayEvent
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum ChannelRecord {
/// State for a live channel whose funding transaction exists.
Funded {
user_channel_id: UserChannelId,
/// The node ID of the channel counterparty.
counterparty_node_id: PublicKey,
/// The channel's ID at the time the `ChannelPending` event fired.
channel_id: ChannelId,
/// Whether we opened the channel (outbound) or the counterparty did (inbound).
is_outbound: bool,
/// Whether the channel was publicly announced.
is_announced: bool,
},
}
impl_writeable_tlv_based_enum!(ChannelRecord,
(0, Funded) => {
(0, user_channel_id, required),
(2, counterparty_node_id, required),
(4, channel_id, required),
(6, is_outbound, required),
(8, is_announced, required),
},
);
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct ChannelRecordUpdate {
pub user_channel_id: UserChannelId,
}
impl StorableObjectUpdate<ChannelRecord> for ChannelRecordUpdate {
fn id(&self) -> UserChannelId {
self.user_channel_id
}
}
impl StorableObject for ChannelRecord {
type Id = UserChannelId;
type Update = ChannelRecordUpdate;
fn id(&self) -> UserChannelId {
match self {
ChannelRecord::Funded { user_channel_id, .. } => *user_channel_id,
}
}
fn update(&mut self, _update: Self::Update) -> bool {
// ChannelRecord fields are immutable once written in this version. Returning false
// makes insert_or_update a no-op when the record already exists, ensuring idempotency
// on ChannelPending replay.
false
}
fn to_update(&self) -> Self::Update {
ChannelRecordUpdate { user_channel_id: self.id() }
}
}
impl StorableObjectId for UserChannelId {
fn encode_to_hex_str(&self) -> String {
hex_utils::to_string(&self.0.to_be_bytes())
}
}
#[cfg(test)]
mod tests {
use lightning::ln::types::ChannelId;
use lightning::util::ser::{Readable, Writeable};
use super::*;
fn make_record(is_outbound: bool, is_announced: bool) -> ChannelRecord {
let user_channel_id = UserChannelId(42);
// A valid compressed public key: prefix 0x02 followed by 32 bytes.
let counterparty_node_id = PublicKey::from_slice(&[2u8; 33]).expect("valid pubkey");
let channel_id = ChannelId([3u8; 32]);
ChannelRecord::Funded {
user_channel_id,
counterparty_node_id,
channel_id,
is_outbound,
is_announced,
}
}
#[test]
fn channel_record_roundtrips() {
for (is_outbound, is_announced) in
[(true, false), (false, true), (true, true), (false, false)]
{
let record = make_record(is_outbound, is_announced);
let encoded = record.encode();
let decoded = ChannelRecord::read(&mut &encoded[..]).expect("decode succeeds");
assert_eq!(record, decoded);
assert_eq!(decoded.id(), UserChannelId(42));
assert!(matches!(
decoded,
ChannelRecord::Funded {
is_outbound: dec_out,
is_announced: dec_ann,
..
} if dec_out == is_outbound && dec_ann == is_announced
));
}
}
}