]> git.bitcoin.ninja Git - rust-lightning/blob - lightning/src/ln/channel_id.rs
Adapt intro node process_pending_htlcs test for non-intro nodes
[rust-lightning] / lightning / src / ln / channel_id.rs
1 // This file is Copyright its original authors, visible in version control
2 // history.
3 //
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
8 // licenses.
9
10 //! ChannelId definition.
11
12 use crate::chain::transaction::OutPoint;
13 use crate::io;
14 use crate::ln::msgs::DecodeError;
15 use crate::sign::EntropySource;
16 use crate::util::ser::{Readable, Writeable, Writer};
17 use super::channel_keys::RevocationBasepoint;
18
19 use bitcoin::hashes::{
20         Hash as _,
21         HashEngine as _,
22         sha256::Hash as Sha256,
23 };
24 use core::fmt;
25 use core::ops::Deref;
26
27 /// A unique 32-byte identifier for a channel.
28 /// Depending on how the ID is generated, several varieties are distinguished
29 /// (but all are stored as 32 bytes):
30 ///   _v1_ and _temporary_.
31 /// A _v1_ channel ID is generated based on funding tx outpoint (txid & index).
32 /// A _temporary_ ID is generated randomly.
33 /// (Later revocation-point-based _v2_ is a possibility.)
34 /// The variety (context) is not stored, it is relevant only at creation.
35 ///
36 /// This is not exported to bindings users as we just use [u8; 32] directly.
37 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
38 pub struct ChannelId(pub [u8; 32]);
39
40 impl ChannelId {
41         /// Create _v1_ channel ID based on a funding TX ID and output index
42         pub fn v1_from_funding_txid(txid: &[u8; 32], output_index: u16) -> Self {
43                 let mut res = [0; 32];
44                 res[..].copy_from_slice(&txid[..]);
45                 res[30] ^= ((output_index >> 8) & 0xff) as u8;
46                 res[31] ^= ((output_index >> 0) & 0xff) as u8;
47                 Self(res)
48         }
49
50         /// Create _v1_ channel ID from a funding tx outpoint
51         pub fn v1_from_funding_outpoint(outpoint: OutPoint) -> Self {
52                 Self::v1_from_funding_txid(outpoint.txid.as_byte_array(), outpoint.index)
53         }
54
55         /// Create a _temporary_ channel ID randomly, based on an entropy source.
56         pub fn temporary_from_entropy_source<ES: Deref>(entropy_source: &ES) -> Self
57         where ES::Target: EntropySource {
58                 Self(entropy_source.get_secure_random_bytes())
59         }
60
61         /// Generic constructor; create a new channel ID from the provided data.
62         /// Use a more specific `*_from_*` constructor when possible.
63         pub fn from_bytes(data: [u8; 32]) -> Self {
64                 Self(data)
65         }
66
67         /// Create a channel ID consisting of all-zeros data (e.g. when uninitialized or a placeholder).
68         pub fn new_zero() -> Self {
69                 Self([0; 32])
70         }
71
72         /// Check whether ID is consisting of all zeros (uninitialized)
73         pub fn is_zero(&self) -> bool {
74                 self.0[..] == [0; 32]
75         }
76
77         /// Create _v2_ channel ID by concatenating the holder revocation basepoint with the counterparty
78         /// revocation basepoint and hashing the result. The basepoints will be concatenated in increasing
79         /// sorted order.
80         pub fn v2_from_revocation_basepoints(
81                 ours: &RevocationBasepoint,
82                 theirs: &RevocationBasepoint,
83         ) -> Self {
84                 let ours = ours.0.serialize();
85                 let theirs = theirs.0.serialize();
86                 let (lesser, greater) = if ours < theirs {
87                         (ours, theirs)
88                 } else {
89                         (theirs, ours)
90                 };
91                 let mut engine = Sha256::engine();
92                 engine.input(&lesser[..]);
93                 engine.input(&greater[..]);
94                 Self(Sha256::from_engine(engine).to_byte_array())
95         }
96
97         /// Create temporary _v2_ channel ID by concatenating a zeroed out basepoint with the holder
98         /// revocation basepoint and hashing the result.
99         pub fn temporary_v2_from_revocation_basepoint(our_revocation_basepoint: &RevocationBasepoint) -> Self {
100                 Self(Sha256::hash(&[[0u8; 33], our_revocation_basepoint.0.serialize()].concat()).to_byte_array())
101         }
102 }
103
104 impl Writeable for ChannelId {
105         fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
106                 self.0.write(w)
107         }
108 }
109
110 impl Readable for ChannelId {
111         fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
112                 let buf: [u8; 32] = Readable::read(r)?;
113                 Ok(ChannelId(buf))
114         }
115 }
116
117 impl fmt::Display for ChannelId {
118         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119                 crate::util::logger::DebugBytes(&self.0).fmt(f)
120         }
121 }
122
123 #[cfg(test)]
124 mod tests {
125         use bitcoin::hashes::{
126                 Hash as _,
127                 HashEngine as _,
128                 hex::FromHex as _,
129                 sha256::Hash as Sha256,
130         };
131         use bitcoin::secp256k1::PublicKey;
132         use hex::DisplayHex;
133
134         use crate::ln::ChannelId;
135         use crate::ln::channel_keys::RevocationBasepoint;
136         use crate::util::ser::{Readable, Writeable};
137         use crate::util::test_utils;
138         use crate::prelude::*;
139         use crate::io;
140
141         #[test]
142         fn test_channel_id_v1_from_funding_txid() {
143                 let channel_id = ChannelId::v1_from_funding_txid(&[2; 32], 1);
144                 assert_eq!(channel_id.0.as_hex().to_string(), "0202020202020202020202020202020202020202020202020202020202020203");
145         }
146
147         #[test]
148         fn test_channel_id_new_from_data() {
149                 let data: [u8; 32] = [2; 32];
150                 let channel_id = ChannelId::from_bytes(data.clone());
151                 assert_eq!(channel_id.0, data);
152         }
153
154         #[test]
155         fn test_channel_id_equals() {
156                 let channel_id11 = ChannelId::v1_from_funding_txid(&[2; 32], 2);
157                 let channel_id12 = ChannelId::v1_from_funding_txid(&[2; 32], 2);
158                 let channel_id21 = ChannelId::v1_from_funding_txid(&[2; 32], 42);
159                 assert_eq!(channel_id11, channel_id12);
160                 assert_ne!(channel_id11, channel_id21);
161         }
162
163         #[test]
164         fn test_channel_id_write_read() {
165                 let data: [u8; 32] = [2; 32];
166                 let channel_id = ChannelId::from_bytes(data.clone());
167
168                 let mut w = test_utils::TestVecWriter(Vec::new());
169                 channel_id.write(&mut w).unwrap();
170
171                 let channel_id_2 = ChannelId::read(&mut io::Cursor::new(&w.0)).unwrap();
172                 assert_eq!(channel_id_2, channel_id);
173                 assert_eq!(channel_id_2.0, data);
174         }
175
176         #[test]
177         fn test_channel_id_display() {
178                 let channel_id = ChannelId::v1_from_funding_txid(&[2; 32], 1);
179                 assert_eq!(format!("{}", &channel_id), "0202020202020202020202020202020202020202020202020202020202020203");
180         }
181
182         #[test]
183         fn test_channel_id_v2_from_basepoints() {
184                 // Ours greater than theirs
185                 let ours = RevocationBasepoint(PublicKey::from_slice(&<Vec<u8>>::from_hex("0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c").unwrap()[..]).unwrap());
186                 let theirs = RevocationBasepoint(PublicKey::from_slice(&<Vec<u8>>::from_hex("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()[..]).unwrap());
187
188                 let mut engine = Sha256::engine();
189                 engine.input(&theirs.0.serialize());
190                 engine.input(&ours.0.serialize());
191                 let expected_id = ChannelId(Sha256::from_engine(engine).to_byte_array());
192
193                 assert_eq!(ChannelId::v2_from_revocation_basepoints(&ours, &theirs), expected_id);
194
195                 // Theirs greater than ours
196                 let ours = RevocationBasepoint(PublicKey::from_slice(&<Vec<u8>>::from_hex("027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007").unwrap()[..]).unwrap());
197                 let theirs = RevocationBasepoint(PublicKey::from_slice(&<Vec<u8>>::from_hex("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()[..]).unwrap());
198
199                 let mut engine = Sha256::engine();
200                 engine.input(&ours.0.serialize());
201                 engine.input(&theirs.0.serialize());
202                 let expected_id = ChannelId(Sha256::from_engine(engine).to_byte_array());
203
204                 assert_eq!(ChannelId::v2_from_revocation_basepoints(&ours, &theirs), expected_id);
205         }
206 }