//! ChannelId definition.
+use crate::chain::transaction::OutPoint;
+use crate::io;
use crate::ln::msgs::DecodeError;
use crate::sign::EntropySource;
use crate::util::ser::{Readable, Writeable, Writer};
+use super::channel_keys::RevocationBasepoint;
-use bitcoin::hashes::hex::ToHex;
-
-use crate::io;
-use crate::prelude::*;
+use bitcoin::hashes::{
+ Hash as _,
+ HashEngine as _,
+ sha256::Hash as Sha256,
+};
use core::fmt;
use core::ops::Deref;
/// A unique 32-byte identifier for a channel.
-/// Depending on how the ID is generated, several varieties are distinguished (but all are stored as 32 bytes): _v1_ and _temporary_.
+/// Depending on how the ID is generated, several varieties are distinguished
+/// (but all are stored as 32 bytes):
+/// _v1_ and _temporary_.
/// A _v1_ channel ID is generated based on funding tx outpoint (txid & index).
/// A _temporary_ ID is generated randomly.
/// (Later revocation-point-based _v2_ is a possibility.)
Self(res)
}
+ /// Create _v1_ channel ID from a funding tx outpoint
+ pub fn v1_from_funding_outpoint(outpoint: OutPoint) -> Self {
+ Self::v1_from_funding_txid(outpoint.txid.as_byte_array(), outpoint.index)
+ }
+
/// Create a _temporary_ channel ID randomly, based on an entropy source.
pub fn temporary_from_entropy_source<ES: Deref>(entropy_source: &ES) -> Self
where ES::Target: EntropySource {
pub fn is_zero(&self) -> bool {
self.0[..] == [0; 32]
}
+
+ /// Create _v2_ channel ID by concatenating the holder revocation basepoint with the counterparty
+ /// revocation basepoint and hashing the result. The basepoints will be concatenated in increasing
+ /// sorted order.
+ pub fn v2_from_revocation_basepoints(
+ ours: &RevocationBasepoint,
+ theirs: &RevocationBasepoint,
+ ) -> Self {
+ let ours = ours.0.serialize();
+ let theirs = theirs.0.serialize();
+ let (lesser, greater) = if ours < theirs {
+ (ours, theirs)
+ } else {
+ (theirs, ours)
+ };
+ let mut engine = Sha256::engine();
+ engine.input(&lesser[..]);
+ engine.input(&greater[..]);
+ Self(Sha256::from_engine(engine).to_byte_array())
+ }
+
+ /// Create temporary _v2_ channel ID by concatenating a zeroed out basepoint with the holder
+ /// revocation basepoint and hashing the result.
+ pub fn temporary_v2_from_revocation_basepoint(our_revocation_basepoint: &RevocationBasepoint) -> Self {
+ Self(Sha256::hash(&[[0u8; 33], our_revocation_basepoint.0.serialize()].concat()).to_byte_array())
+ }
}
impl Writeable for ChannelId {
}
}
-impl ToHex for ChannelId {
- fn to_hex(&self) -> String {
- self.0.to_hex()
- }
-}
-
impl fmt::Display for ChannelId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
crate::util::logger::DebugBytes(&self.0).fmt(f)
#[cfg(test)]
mod tests {
+ use bitcoin::hashes::{
+ Hash as _,
+ HashEngine as _,
+ hex::FromHex as _,
+ sha256::Hash as Sha256,
+ };
+ use bitcoin::secp256k1::PublicKey;
+ use hex::DisplayHex;
+
use crate::ln::ChannelId;
+ use crate::ln::channel_keys::RevocationBasepoint;
use crate::util::ser::{Readable, Writeable};
use crate::util::test_utils;
- use bitcoin::hashes::hex::ToHex;
use crate::prelude::*;
use crate::io;
#[test]
fn test_channel_id_v1_from_funding_txid() {
let channel_id = ChannelId::v1_from_funding_txid(&[2; 32], 1);
- assert_eq!(channel_id.to_hex(), "0202020202020202020202020202020202020202020202020202020202020203");
+ assert_eq!(channel_id.0.as_hex().to_string(), "0202020202020202020202020202020202020202020202020202020202020203");
}
#[test]
let channel_id = ChannelId::v1_from_funding_txid(&[2; 32], 1);
assert_eq!(format!("{}", &channel_id), "0202020202020202020202020202020202020202020202020202020202020203");
}
+
+ #[test]
+ fn test_channel_id_v2_from_basepoints() {
+ // Ours greater than theirs
+ let ours = RevocationBasepoint(PublicKey::from_slice(&<Vec<u8>>::from_hex("0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c").unwrap()[..]).unwrap());
+ let theirs = RevocationBasepoint(PublicKey::from_slice(&<Vec<u8>>::from_hex("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()[..]).unwrap());
+
+ let mut engine = Sha256::engine();
+ engine.input(&theirs.0.serialize());
+ engine.input(&ours.0.serialize());
+ let expected_id = ChannelId(Sha256::from_engine(engine).to_byte_array());
+
+ assert_eq!(ChannelId::v2_from_revocation_basepoints(&ours, &theirs), expected_id);
+
+ // Theirs greater than ours
+ let ours = RevocationBasepoint(PublicKey::from_slice(&<Vec<u8>>::from_hex("027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007").unwrap()[..]).unwrap());
+ let theirs = RevocationBasepoint(PublicKey::from_slice(&<Vec<u8>>::from_hex("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()[..]).unwrap());
+
+ let mut engine = Sha256::engine();
+ engine.input(&ours.0.serialize());
+ engine.input(&theirs.0.serialize());
+ let expected_id = ChannelId(Sha256::from_engine(engine).to_byte_array());
+
+ assert_eq!(ChannelId::v2_from_revocation_basepoints(&ours, &theirs), expected_id);
+ }
}