Support (de)serializing Path::blinded_tails in Routes
authorValentine Wallace <vwallace@protonmail.com>
Sun, 9 Apr 2023 19:47:47 +0000 (15:47 -0400)
committerValentine Wallace <vwallace@protonmail.com>
Fri, 21 Apr 2023 19:35:07 +0000 (15:35 -0400)
lightning/src/routing/router.rs
lightning/src/util/ser.rs
lightning/src/util/test_utils.rs

index 0a2cb9081f922ee84ef4d9cd29851191b3ae0c6f..28ca2c4bfc700d2509cfa00539472546e154797f 100644 (file)
@@ -358,14 +358,25 @@ impl Writeable for Route {
        fn write<W: crate::util::ser::Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
                write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
                (self.paths.len() as u64).write(writer)?;
+               let mut blinded_tails = Vec::new();
                for path in self.paths.iter() {
                        (path.hops.len() as u8).write(writer)?;
-                       for hop in path.hops.iter() {
+                       for (idx, hop) in path.hops.iter().enumerate() {
                                hop.write(writer)?;
+                               if let Some(blinded_tail) = &path.blinded_tail {
+                                       if blinded_tails.is_empty() {
+                                               blinded_tails = Vec::with_capacity(path.hops.len());
+                                               for _ in 0..idx {
+                                                       blinded_tails.push(None);
+                                               }
+                                       }
+                                       blinded_tails.push(Some(blinded_tail));
+                               } else if !blinded_tails.is_empty() { blinded_tails.push(None); }
                        }
                }
                write_tlv_fields!(writer, {
                        (1, self.payment_params, option),
+                       (2, blinded_tails, optional_vec),
                });
                Ok(())
        }
@@ -389,10 +400,17 @@ impl Readable for Route {
                                cmp::min(min_final_cltv_expiry_delta, hops.last().unwrap().cltv_expiry_delta);
                        paths.push(Path { hops, blinded_tail: None });
                }
-               let mut payment_params = None;
-               read_tlv_fields!(reader, {
+               _init_and_read_tlv_fields!(reader, {
                        (1, payment_params, (option: ReadableArgs, min_final_cltv_expiry_delta)),
+                       (2, blinded_tails, optional_vec),
                });
+               let blinded_tails = blinded_tails.unwrap_or(Vec::new());
+               if blinded_tails.len() != 0 {
+                       if blinded_tails.len() != paths.len() { return Err(DecodeError::InvalidValue) }
+                       for (mut path, blinded_tail_opt) in paths.iter_mut().zip(blinded_tails.into_iter()) {
+                               path.blinded_tail = blinded_tail_opt;
+                       }
+               }
                Ok(Route { paths, payment_params })
        }
 }
@@ -2245,10 +2263,11 @@ fn build_route_from_hops_internal<L: Deref>(
 
 #[cfg(test)]
 mod tests {
+       use crate::blinded_path::{BlindedHop, BlindedPath};
        use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, EffectiveCapacity};
        use crate::routing::utxo::UtxoResult;
        use crate::routing::router::{get_route, build_route_from_hops_internal, add_random_cltv_offset, default_node_features,
-               Path, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees,
+               BlindedTail, Path, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees,
                DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, MAX_PATH_LENGTH_ESTIMATE};
        use crate::routing::scoring::{ChannelUsage, FixedPenaltyScorer, Score, ProbabilisticScorer, ProbabilisticScoringParameters};
        use crate::routing::test_utils::{add_channel, add_or_update_node, build_graph, build_line_graph, id_to_feature_flags, get_nodes, update_channel};
@@ -2260,8 +2279,9 @@ mod tests {
        use crate::util::config::UserConfig;
        use crate::util::test_utils as ln_test_utils;
        use crate::util::chacha20::ChaCha20;
+       use crate::util::ser::{Readable, Writeable};
        #[cfg(c_bindings)]
-       use crate::util::ser::{Writeable, Writer};
+       use crate::util::ser::Writer;
 
        use bitcoin::hashes::Hash;
        use bitcoin::network::constants::Network;
@@ -2275,6 +2295,7 @@ mod tests {
        use bitcoin::secp256k1::{PublicKey,SecretKey};
        use bitcoin::secp256k1::Secp256k1;
 
+       use crate::io::Cursor;
        use crate::prelude::*;
        use crate::sync::Arc;
 
@@ -5745,6 +5766,68 @@ mod tests {
                let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes);
                assert!(route.is_ok());
        }
+
+       #[test]
+       fn blinded_route_ser() {
+               let blinded_path_1 = BlindedPath {
+                       introduction_node_id: ln_test_utils::pubkey(42),
+                       blinding_point: ln_test_utils::pubkey(43),
+                       blinded_hops: vec![
+                               BlindedHop { blinded_node_id: ln_test_utils::pubkey(44), encrypted_payload: Vec::new() },
+                               BlindedHop { blinded_node_id: ln_test_utils::pubkey(45), encrypted_payload: Vec::new() }
+                       ],
+               };
+               let blinded_path_2 = BlindedPath {
+                       introduction_node_id: ln_test_utils::pubkey(46),
+                       blinding_point: ln_test_utils::pubkey(47),
+                       blinded_hops: vec![
+                               BlindedHop { blinded_node_id: ln_test_utils::pubkey(48), encrypted_payload: Vec::new() },
+                               BlindedHop { blinded_node_id: ln_test_utils::pubkey(49), encrypted_payload: Vec::new() }
+                       ],
+               };
+               // (De)serialize a Route with 1 blinded path out of two total paths.
+               let mut route = Route { paths: vec![Path {
+                       hops: vec![RouteHop {
+                               pubkey: ln_test_utils::pubkey(50),
+                               node_features: NodeFeatures::empty(),
+                               short_channel_id: 42,
+                               channel_features: ChannelFeatures::empty(),
+                               fee_msat: 100,
+                               cltv_expiry_delta: 0,
+                       }],
+                       blinded_tail: Some(BlindedTail {
+                               hops: blinded_path_1.blinded_hops,
+                               blinding_point: blinded_path_1.blinding_point,
+                               excess_final_cltv_expiry_delta: 40,
+                               final_value_msat: 100,
+                       })}, Path {
+                       hops: vec![RouteHop {
+                               pubkey: ln_test_utils::pubkey(51),
+                               node_features: NodeFeatures::empty(),
+                               short_channel_id: 43,
+                               channel_features: ChannelFeatures::empty(),
+                               fee_msat: 100,
+                               cltv_expiry_delta: 0,
+                       }], blinded_tail: None }],
+                       payment_params: None,
+               };
+               let encoded_route = route.encode();
+               let decoded_route: Route = Readable::read(&mut Cursor::new(&encoded_route[..])).unwrap();
+               assert_eq!(decoded_route.paths[0].blinded_tail, route.paths[0].blinded_tail);
+               assert_eq!(decoded_route.paths[1].blinded_tail, route.paths[1].blinded_tail);
+
+               // (De)serialize a Route with two paths, each containing a blinded tail.
+               route.paths[1].blinded_tail = Some(BlindedTail {
+                       hops: blinded_path_2.blinded_hops,
+                       blinding_point: blinded_path_2.blinding_point,
+                       excess_final_cltv_expiry_delta: 41,
+                       final_value_msat: 101,
+               });
+               let encoded_route = route.encode();
+               let decoded_route: Route = Readable::read(&mut Cursor::new(&encoded_route[..])).unwrap();
+               assert_eq!(decoded_route.paths[0].blinded_tail, route.paths[0].blinded_tail);
+               assert_eq!(decoded_route.paths[1].blinded_tail, route.paths[1].blinded_tail);
+       }
 }
 
 #[cfg(all(test, not(feature = "no-std")))]
index 566c74752d7dbd34ea3f65a185bf874e97c4cb23..77ee33c4fa099de78ef6bac9f7c1cfd210586f73 100644 (file)
@@ -814,6 +814,8 @@ impl Readable for Vec<u8> {
 impl_for_vec!(ecdsa::Signature);
 impl_for_vec!(crate::ln::channelmanager::MonitorUpdateCompletionAction);
 impl_for_vec!((A, B), A, B);
+impl_writeable_for_vec!(&crate::routing::router::BlindedTail);
+impl_readable_for_vec!(crate::routing::router::BlindedTail);
 
 impl Writeable for Script {
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
index e39e894f5e7961c0df1eec33568d72cd6fcb76ec..531c2dad0f3207843079c097bbe51687e5c82098 100644 (file)
@@ -60,6 +60,15 @@ use crate::chain::keysinterface::{InMemorySigner, Recipient, EntropySource, Node
 use std::time::{SystemTime, UNIX_EPOCH};
 use bitcoin::Sequence;
 
+pub fn pubkey(byte: u8) -> PublicKey {
+       let secp_ctx = Secp256k1::new();
+       PublicKey::from_secret_key(&secp_ctx, &privkey(byte))
+}
+
+pub fn privkey(byte: u8) -> SecretKey {
+       SecretKey::from_slice(&[byte; 32]).unwrap()
+}
+
 pub struct TestVecWriter(pub Vec<u8>);
 impl Writer for TestVecWriter {
        fn write_all(&mut self, buf: &[u8]) -> Result<(), io::Error> {