Skip to content

Commit c3b0dd2

Browse files
Support (de)serializing Path::blinded_tails in Routes
1 parent f6c2ee1 commit c3b0dd2

File tree

3 files changed

+99
-5
lines changed

3 files changed

+99
-5
lines changed

lightning/src/routing/router.rs

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -358,14 +358,25 @@ impl Writeable for Route {
358358
fn write<W: crate::util::ser::Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
359359
write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
360360
(self.paths.len() as u64).write(writer)?;
361+
let mut blinded_tails = Vec::new();
361362
for path in self.paths.iter() {
362363
(path.hops.len() as u8).write(writer)?;
363-
for hop in path.hops.iter() {
364+
for (idx, hop) in path.hops.iter().enumerate() {
364365
hop.write(writer)?;
366+
if let Some(blinded_tail) = &path.blinded_tail {
367+
if blinded_tails.is_empty() {
368+
blinded_tails = Vec::with_capacity(path.hops.len());
369+
for _ in 0..idx {
370+
blinded_tails.push(None);
371+
}
372+
}
373+
blinded_tails.push(Some(blinded_tail));
374+
} else if !blinded_tails.is_empty() { blinded_tails.push(None); }
365375
}
366376
}
367377
write_tlv_fields!(writer, {
368378
(1, self.payment_params, option),
379+
(2, blinded_tails, optional_vec),
369380
});
370381
Ok(())
371382
}
@@ -389,10 +400,17 @@ impl Readable for Route {
389400
cmp::min(min_final_cltv_expiry_delta, hops.last().unwrap().cltv_expiry_delta);
390401
paths.push(Path { hops, blinded_tail: None });
391402
}
392-
let mut payment_params = None;
393-
read_tlv_fields!(reader, {
403+
_init_and_read_tlv_fields!(reader, {
394404
(1, payment_params, (option: ReadableArgs, min_final_cltv_expiry_delta)),
405+
(2, blinded_tails, optional_vec),
395406
});
407+
let blinded_tails = blinded_tails.unwrap_or(Vec::new());
408+
if blinded_tails.len() != 0 {
409+
if blinded_tails.len() != paths.len() { return Err(DecodeError::InvalidValue) }
410+
for (mut path, blinded_tail_opt) in paths.iter_mut().zip(blinded_tails.into_iter()) {
411+
path.blinded_tail = blinded_tail_opt;
412+
}
413+
}
396414
Ok(Route { paths, payment_params })
397415
}
398416
}
@@ -2245,10 +2263,11 @@ fn build_route_from_hops_internal<L: Deref>(
22452263

22462264
#[cfg(test)]
22472265
mod tests {
2266+
use crate::blinded_path::{BlindedHop, BlindedPath};
22482267
use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, EffectiveCapacity};
22492268
use crate::routing::utxo::UtxoResult;
22502269
use crate::routing::router::{get_route, build_route_from_hops_internal, add_random_cltv_offset, default_node_features,
2251-
Path, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees,
2270+
BlindedTail, Path, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees,
22522271
DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, MAX_PATH_LENGTH_ESTIMATE};
22532272
use crate::routing::scoring::{ChannelUsage, FixedPenaltyScorer, Score, ProbabilisticScorer, ProbabilisticScoringParameters};
22542273
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 {
22602279
use crate::util::config::UserConfig;
22612280
use crate::util::test_utils as ln_test_utils;
22622281
use crate::util::chacha20::ChaCha20;
2282+
use crate::util::ser::{Readable, Writeable};
22632283
#[cfg(c_bindings)]
2264-
use crate::util::ser::{Writeable, Writer};
2284+
use crate::util::ser::Writer;
22652285

22662286
use bitcoin::hashes::Hash;
22672287
use bitcoin::network::constants::Network;
@@ -2275,6 +2295,7 @@ mod tests {
22752295
use bitcoin::secp256k1::{PublicKey,SecretKey};
22762296
use bitcoin::secp256k1::Secp256k1;
22772297

2298+
use crate::io::Cursor;
22782299
use crate::prelude::*;
22792300
use crate::sync::Arc;
22802301

@@ -5745,6 +5766,68 @@ mod tests {
57455766
let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes);
57465767
assert!(route.is_ok());
57475768
}
5769+
5770+
#[test]
5771+
fn blinded_route_ser() {
5772+
let blinded_path_1 = BlindedPath {
5773+
introduction_node_id: ln_test_utils::pubkey(42),
5774+
blinding_point: ln_test_utils::pubkey(43),
5775+
blinded_hops: vec![
5776+
BlindedHop { blinded_node_id: ln_test_utils::pubkey(44), encrypted_payload: Vec::new() },
5777+
BlindedHop { blinded_node_id: ln_test_utils::pubkey(45), encrypted_payload: Vec::new() }
5778+
],
5779+
};
5780+
let blinded_path_2 = BlindedPath {
5781+
introduction_node_id: ln_test_utils::pubkey(46),
5782+
blinding_point: ln_test_utils::pubkey(47),
5783+
blinded_hops: vec![
5784+
BlindedHop { blinded_node_id: ln_test_utils::pubkey(48), encrypted_payload: Vec::new() },
5785+
BlindedHop { blinded_node_id: ln_test_utils::pubkey(49), encrypted_payload: Vec::new() }
5786+
],
5787+
};
5788+
// (De)serialize a Route with 1 blinded path out of two total paths.
5789+
let mut route = Route { paths: vec![Path {
5790+
hops: vec![RouteHop {
5791+
pubkey: ln_test_utils::pubkey(50),
5792+
node_features: NodeFeatures::empty(),
5793+
short_channel_id: 42,
5794+
channel_features: ChannelFeatures::empty(),
5795+
fee_msat: 100,
5796+
cltv_expiry_delta: 0,
5797+
}],
5798+
blinded_tail: Some(BlindedTail {
5799+
hops: blinded_path_1.blinded_hops,
5800+
blinding_point: blinded_path_1.blinding_point,
5801+
excess_final_cltv_expiry_delta: 40,
5802+
final_value_msat: 100,
5803+
})}, Path {
5804+
hops: vec![RouteHop {
5805+
pubkey: ln_test_utils::pubkey(51),
5806+
node_features: NodeFeatures::empty(),
5807+
short_channel_id: 43,
5808+
channel_features: ChannelFeatures::empty(),
5809+
fee_msat: 100,
5810+
cltv_expiry_delta: 0,
5811+
}], blinded_tail: None }],
5812+
payment_params: None,
5813+
};
5814+
let encoded_route = route.encode();
5815+
let decoded_route: Route = Readable::read(&mut Cursor::new(&encoded_route[..])).unwrap();
5816+
assert_eq!(decoded_route.paths[0].blinded_tail, route.paths[0].blinded_tail);
5817+
assert_eq!(decoded_route.paths[1].blinded_tail, route.paths[1].blinded_tail);
5818+
5819+
// (De)serialize a Route with two paths, each containing a blinded tail.
5820+
route.paths[1].blinded_tail = Some(BlindedTail {
5821+
hops: blinded_path_2.blinded_hops,
5822+
blinding_point: blinded_path_2.blinding_point,
5823+
excess_final_cltv_expiry_delta: 41,
5824+
final_value_msat: 101,
5825+
});
5826+
let encoded_route = route.encode();
5827+
let decoded_route: Route = Readable::read(&mut Cursor::new(&encoded_route[..])).unwrap();
5828+
assert_eq!(decoded_route.paths[0].blinded_tail, route.paths[0].blinded_tail);
5829+
assert_eq!(decoded_route.paths[1].blinded_tail, route.paths[1].blinded_tail);
5830+
}
57485831
}
57495832

57505833
#[cfg(all(test, not(feature = "no-std")))]

lightning/src/util/ser.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,8 @@ impl Readable for Vec<u8> {
814814
impl_for_vec!(ecdsa::Signature);
815815
impl_for_vec!(crate::ln::channelmanager::MonitorUpdateCompletionAction);
816816
impl_for_vec!((A, B), A, B);
817+
impl_writeable_for_vec!(&crate::routing::router::BlindedTail);
818+
impl_readable_for_vec!(crate::routing::router::BlindedTail);
817819

818820
impl Writeable for Script {
819821
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {

lightning/src/util/test_utils.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ use crate::chain::keysinterface::{InMemorySigner, Recipient, EntropySource, Node
6060
use std::time::{SystemTime, UNIX_EPOCH};
6161
use bitcoin::Sequence;
6262

63+
pub fn pubkey(byte: u8) -> PublicKey {
64+
let secp_ctx = Secp256k1::new();
65+
PublicKey::from_secret_key(&secp_ctx, &privkey(byte))
66+
}
67+
68+
pub fn privkey(byte: u8) -> SecretKey {
69+
SecretKey::from_slice(&[byte; 32]).unwrap()
70+
}
71+
6372
pub struct TestVecWriter(pub Vec<u8>);
6473
impl Writer for TestVecWriter {
6574
fn write_all(&mut self, buf: &[u8]) -> Result<(), io::Error> {

0 commit comments

Comments
 (0)