From 21cb8db1b6256335952c4664430287f10f5ee522 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Fri, 16 Apr 2021 16:17:11 -0400 Subject: [PATCH] invoice: swap RouteHop for RouteHint To prevent naming conflicts in bindings --- lightning-invoice/Cargo.toml | 1 + lightning-invoice/src/de.rs | 60 +++++++++++------- lightning-invoice/src/lib.rs | 109 +++++++++++++++++--------------- lightning-invoice/src/ser.rs | 12 ++-- lightning/src/routing/router.rs | 2 +- 5 files changed, 105 insertions(+), 79 deletions(-) diff --git a/lightning-invoice/Cargo.toml b/lightning-invoice/Cargo.toml index 47bf9d74..758578ca 100644 --- a/lightning-invoice/Cargo.toml +++ b/lightning-invoice/Cargo.toml @@ -10,6 +10,7 @@ readme = "README.md" [dependencies] bech32 = "0.7" +lightning = { version = "0.0.13", path = "../lightning" } secp256k1 = { version = "0.20", features = ["recovery"] } num-traits = "0.2.8" bitcoin_hashes = "0.9.4" diff --git a/lightning-invoice/src/de.rs b/lightning-invoice/src/de.rs index d6cb9207..df92cacd 100644 --- a/lightning-invoice/src/de.rs +++ b/lightning-invoice/src/de.rs @@ -10,6 +10,8 @@ use bech32::{u5, FromBase32}; use bitcoin_hashes::Hash; use bitcoin_hashes::sha256; +use lightning::routing::network_graph::RoutingFees; +use lightning::routing::router::RouteHint; use num_traits::{CheckedAdd, CheckedMul}; @@ -353,7 +355,7 @@ impl FromBase32 for Signature { } } -fn parse_int_be(digits: &[U], base: T) -> Option +pub(crate) fn parse_int_be(digits: &[U], base: T) -> Option where T: CheckedAdd + CheckedMul + From + Default, U: Into + Copy { @@ -575,7 +577,7 @@ impl FromBase32 for Route { return Err(ParseError::UnexpectedEndOfTaggedFields); } - let mut route_hops = Vec::::new(); + let mut route_hops = Vec::::new(); let mut bytes = bytes.as_slice(); while !bytes.is_empty() { @@ -585,12 +587,16 @@ impl FromBase32 for Route { let mut channel_id: [u8; 8] = Default::default(); channel_id.copy_from_slice(&hop_bytes[33..41]); - let hop = RouteHop { - pubkey: PublicKey::from_slice(&hop_bytes[0..33])?, - short_channel_id: channel_id, - fee_base_msat: parse_int_be(&hop_bytes[41..45], 256).expect("slice too big?"), - fee_proportional_millionths: parse_int_be(&hop_bytes[45..49], 256).expect("slice too big?"), - cltv_expiry_delta: parse_int_be(&hop_bytes[49..51], 256).expect("slice too big?") + let hop = RouteHint { + src_node_id: PublicKey::from_slice(&hop_bytes[0..33])?, + short_channel_id: parse_int_be(&channel_id, 256).expect("short chan ID slice too big?"), + fees: RoutingFees { + base_msat: parse_int_be(&hop_bytes[41..45], 256).expect("slice too big?"), + proportional_millionths: parse_int_be(&hop_bytes[45..49], 256).expect("slice too big?"), + }, + cltv_expiry_delta: parse_int_be(&hop_bytes[49..51], 256).expect("slice too big?"), + htlc_minimum_msat: None, + htlc_maximum_msat: None, }; route_hops.push(hop); @@ -931,41 +937,51 @@ mod test { #[test] fn test_parse_route() { - use RouteHop; + use lightning::routing::network_graph::RoutingFees; + use lightning::routing::router::RouteHint; use ::Route; use bech32::FromBase32; + use de::parse_int_be; let input = from_bech32( "q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqa\ fqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzq".as_bytes() ); - let mut expected = Vec::::new(); - expected.push(RouteHop { - pubkey: PublicKey::from_slice( + let mut expected = Vec::::new(); + expected.push(RouteHint { + src_node_id: PublicKey::from_slice( &[ 0x02u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c, 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3, 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55 ][..] ).unwrap(), - short_channel_id: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], - fee_base_msat: 1, - fee_proportional_millionths: 20, - cltv_expiry_delta: 3 + short_channel_id: parse_int_be(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], 256).expect("short chan ID slice too big?"), + fees: RoutingFees { + base_msat: 1, + proportional_millionths: 20, + }, + cltv_expiry_delta: 3, + htlc_minimum_msat: None, + htlc_maximum_msat: None }); - expected.push(RouteHop { - pubkey: PublicKey::from_slice( + expected.push(RouteHint { + src_node_id: PublicKey::from_slice( &[ 0x03u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c, 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3, 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55 ][..] ).unwrap(), - short_channel_id: [0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a], - fee_base_msat: 2, - fee_proportional_millionths: 30, - cltv_expiry_delta: 4 + short_channel_id: parse_int_be(&[0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a], 256).expect("short chan ID slice too big?"), + fees: RoutingFees { + base_msat: 2, + proportional_millionths: 30, + }, + cltv_expiry_delta: 4, + htlc_minimum_msat: None, + htlc_maximum_msat: None }); assert_eq!(Route::from_base32(&input), Ok(Route(expected))); diff --git a/lightning-invoice/src/lib.rs b/lightning-invoice/src/lib.rs index e9ca442f..8820274c 100644 --- a/lightning-invoice/src/lib.rs +++ b/lightning-invoice/src/lib.rs @@ -17,12 +17,16 @@ extern crate bech32; extern crate bitcoin_hashes; +extern crate lightning; extern crate num_traits; extern crate secp256k1; use bech32::u5; use bitcoin_hashes::Hash; use bitcoin_hashes::sha256; +#[cfg(any(doc, test))] +use lightning::routing::network_graph::RoutingFees; +use lightning::routing::router::RouteHint; use secp256k1::key::PublicKey; use secp256k1::{Message, Secp256k1}; @@ -383,26 +387,7 @@ pub struct Signature(pub RecoverableSignature); /// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops) /// #[derive(Eq, PartialEq, Debug, Clone)] -pub struct Route(Vec); - -/// Node on a private route -#[derive(Eq, PartialEq, Debug, Clone)] -pub struct RouteHop { - /// Node's public key - pub pubkey: PublicKey, - - /// Which channel of this node we would be using - pub short_channel_id: [u8; 8], - - /// Fee charged by this node per transaction - pub fee_base_msat: u32, - - /// Fee charged by this node proportional to the amount routed - pub fee_proportional_millionths: u32, - - /// Delta substracted by this node from incoming cltv_expiry value - pub cltv_expiry_delta: u16, -} +pub struct Route(Vec); /// Tag constants as specified in BOLT11 #[allow(missing_docs)] @@ -499,7 +484,7 @@ impl InvoiceBuilder { } /// Adds a private route. - pub fn route(mut self, route: Vec) -> Self { + pub fn route(mut self, route: Vec) -> Self { match Route::new(route) { Ok(r) => self.tagged_fields.push(TaggedField::Route(r)), Err(e) => self.error = Some(e), @@ -1159,7 +1144,7 @@ impl ExpiryTime { impl Route { /// Create a new (partial) route from a list of hops - pub fn new(hops: Vec) -> Result { + pub fn new(hops: Vec) -> Result { if hops.len() <= 12 { Ok(Route(hops)) } else { @@ -1168,21 +1153,21 @@ impl Route { } /// Returrn the underlying vector of hops - pub fn into_inner(self) -> Vec { + pub fn into_inner(self) -> Vec { self.0 } } -impl Into> for Route { - fn into(self) -> Vec { +impl Into> for Route { + fn into(self) -> Vec { self.into_inner() } } impl Deref for Route { - type Target = Vec; + type Target = Vec; - fn deref(&self) -> &Vec { + fn deref(&self) -> &Vec { &self.0 } } @@ -1458,18 +1443,22 @@ mod test { .build_raw(); assert_eq!(long_desc_res, Err(CreationError::DescriptionTooLong)); - let route_hop = RouteHop { - pubkey: PublicKey::from_slice( + let route_hop = RouteHint { + src_node_id: PublicKey::from_slice( &[ 0x03, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c, 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3, 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55 ][..] ).unwrap(), - short_channel_id: [0; 8], - fee_base_msat: 0, - fee_proportional_millionths: 0, + short_channel_id: 0, + fees: RoutingFees { + base_msat: 0, + proportional_millionths: 0, + }, cltv_expiry_delta: 0, + htlc_minimum_msat: None, + htlc_maximum_msat: None, }; let too_long_route = vec![route_hop; 13]; let long_route_res = builder.clone() @@ -1505,36 +1494,52 @@ mod test { let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key); let route_1 = vec![ - RouteHop { - pubkey: public_key.clone(), - short_channel_id: [123; 8], - fee_base_msat: 2, - fee_proportional_millionths: 1, + RouteHint { + src_node_id: public_key.clone(), + short_channel_id: de::parse_int_be(&[123; 8], 256).expect("short chan ID slice too big?"), + fees: RoutingFees { + base_msat: 2, + proportional_millionths: 1, + }, cltv_expiry_delta: 145, + htlc_minimum_msat: None, + htlc_maximum_msat: None, }, - RouteHop { - pubkey: public_key.clone(), - short_channel_id: [42; 8], - fee_base_msat: 3, - fee_proportional_millionths: 2, + RouteHint { + src_node_id: public_key.clone(), + short_channel_id: de::parse_int_be(&[42; 8], 256).expect("short chan ID slice too big?"), + fees: RoutingFees { + base_msat: 3, + proportional_millionths: 2, + }, cltv_expiry_delta: 146, + htlc_minimum_msat: None, + htlc_maximum_msat: None, } ]; let route_2 = vec![ - RouteHop { - pubkey: public_key.clone(), - short_channel_id: [0; 8], - fee_base_msat: 4, - fee_proportional_millionths: 3, + RouteHint { + src_node_id: public_key.clone(), + short_channel_id: 0, + fees: RoutingFees { + base_msat: 4, + proportional_millionths: 3, + }, cltv_expiry_delta: 147, + htlc_minimum_msat: None, + htlc_maximum_msat: None, }, - RouteHop { - pubkey: public_key.clone(), - short_channel_id: [1; 8], - fee_base_msat: 5, - fee_proportional_millionths: 4, + RouteHint { + src_node_id: public_key.clone(), + short_channel_id: de::parse_int_be(&[1; 8], 256).expect("short chan ID slice too big?"), + fees: RoutingFees { + base_msat: 5, + proportional_millionths: 4, + }, cltv_expiry_delta: 148, + htlc_minimum_msat: None, + htlc_maximum_msat: None, } ]; diff --git a/lightning-invoice/src/ser.rs b/lightning-invoice/src/ser.rs index 2b4332f8..68fbfcf1 100644 --- a/lightning-invoice/src/ser.rs +++ b/lightning-invoice/src/ser.rs @@ -370,17 +370,21 @@ impl ToBase32 for Route { let mut converter = BytesToBase32::new(writer); for hop in self.iter() { - converter.append(&hop.pubkey.serialize()[..])?; - converter.append(&hop.short_channel_id[..])?; + converter.append(&hop.src_node_id.serialize()[..])?; + let short_channel_id = try_stretch( + encode_int_be_base256(hop.short_channel_id), + 8 + ).expect("sizeof(u64) == 8"); + converter.append(&short_channel_id)?; let fee_base_msat = try_stretch( - encode_int_be_base256(hop.fee_base_msat), + encode_int_be_base256(hop.fees.base_msat), 4 ).expect("sizeof(u32) == 4"); converter.append(&fee_base_msat)?; let fee_proportional_millionths = try_stretch( - encode_int_be_base256(hop.fee_proportional_millionths), + encode_int_be_base256(hop.fees.proportional_millionths), 4 ).expect("sizeof(u32) == 4"); converter.append(&fee_proportional_millionths)?; diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 0ad307cd..20028d21 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -117,7 +117,7 @@ impl Readable for Route { } /// A channel descriptor which provides a last-hop route to get_route -#[derive(Clone)] +#[derive(Eq, PartialEq, Debug, Clone)] pub struct RouteHint { /// The node_id of the non-target end of the route pub src_node_id: PublicKey, -- 2.30.2