Skip to content

Commit 89b9a42

Browse files
committed
Add tests for defaulting to creating tlv onions
1 parent 76fa6cf commit 89b9a42

File tree

2 files changed

+154
-1
lines changed

2 files changed

+154
-1
lines changed

lightning/src/ln/onion_route_tests.rs

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use ln::channelmanager::{HTLCForwardInfo, CLTV_FAR_FAR_AWAY, MIN_CLTV_EXPIRY_DEL
1818
use ln::onion_utils;
1919
use routing::network_graph::{NetworkUpdate, RoutingFees};
2020
use routing::router::{get_route, PaymentParameters, Route, RouteHint, RouteHintHop};
21-
use ln::features::{InitFeatures, InvoiceFeatures};
21+
use ln::features::{InitFeatures, InvoiceFeatures, NodeFeatures};
2222
use ln::msgs;
2323
use ln::msgs::{ChannelMessageHandler, ChannelUpdate, OptionalField};
2424
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider};
@@ -34,6 +34,7 @@ use bitcoin::hashes::sha256::Hash as Sha256;
3434
use bitcoin::secp256k1;
3535
use bitcoin::secp256k1::Secp256k1;
3636
use bitcoin::secp256k1::key::{PublicKey, SecretKey};
37+
use bitcoin::network::constants::Network;
3738

3839
use io;
3940
use prelude::*;
@@ -577,6 +578,149 @@ fn test_onion_failure() {
577578
}, true, Some(23), None, None);
578579
}
579580

581+
#[test]
582+
fn test_default_to_onion_payload_tlv_format() {
583+
// Tests that we default to creating tlv format onion payloads in the scenario that we have no
584+
// `NodeAnnouncementInfo` `features` for a node in the `network_graph` when creating a route,
585+
// and no other known `features` for the node.
586+
let chanmon_cfgs = create_chanmon_cfgs(4);
587+
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
588+
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
589+
let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs);
590+
591+
create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
592+
create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
593+
create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known());
594+
595+
let payment_params = PaymentParameters::from_node_id(nodes[3].node.get_our_node_id());
596+
let origin_node = &nodes[0];
597+
let network_graph = origin_node.network_graph;
598+
599+
// Clears all the `NodeAnnouncementInfo` for all nodes of `nodes[0]`'s `network_graph`, so that
600+
// their `features` aren't used when creating the `route`.
601+
network_graph.clear_nodes_announcement_info();
602+
603+
let scorer = test_utils::TestScorer::with_penalty(0);
604+
let seed = [0u8; 32];
605+
let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
606+
let random_seed_bytes = keys_manager.get_secure_random_bytes();
607+
let route = get_route(
608+
&origin_node.node.get_our_node_id(), &payment_params, &network_graph.read_only(),
609+
Some(&origin_node.node.list_usable_channels().iter().collect::<Vec<_>>()),
610+
1000000, TEST_FINAL_CLTV, origin_node.logger, &scorer, &random_seed_bytes).unwrap();
611+
612+
let hops = &route.paths[0];
613+
// Assert that the hop between `nodes[1]` and `nodes[2]` defaults to supporting variable length
614+
// onions, as `nodes[0]` has no `NodeAnnouncementInfo` `features` for `node[2]`
615+
assert!(hops[1].node_features.supports_variable_length_onion());
616+
// Assert that the hop between `nodes[2]` and `nodes[3]` defaults to supporting variable length
617+
// onions, as `nodes[0]` has no `NodeAnnouncementInfo` `features` for `node[3]`, and no `InvoiceFeatures`
618+
// for the `payment_params`, which would otherwise have been used.
619+
assert!(hops[2].node_features.supports_variable_length_onion());
620+
// Note that we do not asset that `hops[0]` (the channel between `nodes[0]` and `nodes[1]`)
621+
// supports variable length onions, as the `InitFeatures` exchanged while opening the channel
622+
// will be used when creating the route. We therefore do not default to supporting variable
623+
// length onions for that hop, as the `InitFeatures` in this case are `InitFeatures::known()`.
624+
625+
let cur_height = nodes[0].best_block_info().1 + 1;
626+
let (onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 40000, &None, cur_height, &None).unwrap();
627+
628+
for onion_payload in onion_payloads.iter() {
629+
match onion_payload.format {
630+
msgs::OnionHopDataFormat::Legacy {..} => {
631+
panic!("Generated a `msgs::OnionHopDataFormat::Legacy` payload, even though that shouldn't have happend.");
632+
}
633+
_ => {}
634+
}
635+
}
636+
}
637+
638+
#[test]
639+
fn test_do_not_use_default_to_tlv_onions_if_other_features_not_supporting_them_exists() {
640+
// Tests that we do not default to creating tlv onions if any of these features exists when
641+
// creating the specific hop in the route:
642+
// 1. `InitFeatures` to the counterparty node exchanged when creating a channel to the node,
643+
// which doesn't support variable length onions.
644+
// 2. `NodeFeatures` in the `NodeAnnouncementInfo` of a node in sender node's the
645+
// `network_graph`, which doesn't support variable length onions.
646+
// 3. `InvoiceFeatures` specified by the receiving node, which doesn't support variable length
647+
// onions, when no `NodeAnnouncementInfo` `features` exists for the receiver in the sender's
648+
// `network_graph`.
649+
let chanmon_cfgs = create_chanmon_cfgs(4);
650+
let mut node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
651+
652+
// Set `node[1]` config to `InitFeatures::empty()` which return `false` for
653+
// `supports_variable_length_onion()`
654+
let mut node_1_cfg = &mut node_cfgs[1];
655+
node_1_cfg.features = InitFeatures::empty();
656+
657+
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
658+
let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs);
659+
660+
create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
661+
create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
662+
create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::known(), InitFeatures::known());
663+
664+
let payment_params = PaymentParameters::from_node_id(nodes[3].node.get_our_node_id())
665+
.with_features(InvoiceFeatures::empty());
666+
let origin_node = &nodes[0];
667+
let network_graph = origin_node.network_graph;
668+
network_graph.clear_nodes_announcement_info();
669+
let scorer = test_utils::TestScorer::with_penalty(0);
670+
let seed = [0u8; 32];
671+
let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
672+
let random_seed_bytes = keys_manager.get_secure_random_bytes();
673+
674+
// Set `NodeAnnouncementInfo` `features` which do not support variable length onions for
675+
// `nodes[2]` in `nodes[0]`'s `network_graph`.
676+
let nodes_2_unsigned_node_announcement = msgs::UnsignedNodeAnnouncement {
677+
features: NodeFeatures::empty(),
678+
timestamp: 20090103,
679+
node_id: nodes[2].node.get_our_node_id(),
680+
rgb: [32; 3],
681+
alias: [16;32],
682+
addresses: Vec::new(),
683+
excess_address_data: Vec::new(),
684+
excess_data: Vec::new(),
685+
};
686+
let _res = network_graph.update_node_from_unsigned_announcement(&nodes_2_unsigned_node_announcement);
687+
688+
let route = get_route(
689+
&origin_node.node.get_our_node_id(), &payment_params, &network_graph.read_only(),
690+
Some(&origin_node.node.list_usable_channels().iter().collect::<Vec<_>>()),
691+
1000000, TEST_FINAL_CLTV, origin_node.logger, &scorer, &random_seed_bytes).unwrap();
692+
693+
let hops = &route.paths[0];
694+
695+
// Assert that the hop between `nodes[0]` and `nodes[1]` doesn't support variable length
696+
// onions, as as the `InitFeatures` exchanged (`InitFeatures::empty()`) while opening the
697+
// channel is used when creating the `route` and that we therefore do not default to supporting
698+
// variable length onions. Despite `nodes[0]` having no `NodeAnnouncementInfo` `features` for
699+
// `node[1]`.
700+
assert!(!hops[0].node_features.supports_variable_length_onion());
701+
// Assert that the hop between `nodes[1]` and `nodes[2]` uses the `features` from
702+
// `nodes_2_unsigned_node_announcement` that doesn't support supporting variable length
703+
// onions.
704+
assert!(!hops[1].node_features.supports_variable_length_onion());
705+
// Assert that the hop between `nodes[2]` and `nodes[3]` uses the `InvoiceFeatures` set to the
706+
// `payment_params`, that doesn't support variable length onions. We therefore do not end up
707+
// defaulting to supporting variable length onions, despite `nodes[0]` having no
708+
// `NodeAnnouncementInfo` `features` for `node[3]`.
709+
assert!(!hops[2].node_features.supports_variable_length_onion());
710+
711+
let cur_height = nodes[0].best_block_info().1 + 1;
712+
let (onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 40000, &None, cur_height, &None).unwrap();
713+
714+
for onion_payload in onion_payloads.iter() {
715+
match onion_payload.format {
716+
msgs::OnionHopDataFormat::Legacy {..} => {}
717+
_ => {
718+
panic!("Should have only have generated `msgs::OnionHopDataFormat::Legacy` payloads");
719+
}
720+
}
721+
}
722+
}
723+
580724
macro_rules! get_phantom_route {
581725
($nodes: expr, $amt: expr, $channel: expr) => {{
582726
let secp_ctx = Secp256k1::new();

lightning/src/routing/network_graph.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,15 @@ impl NetworkGraph {
10331033
}
10341034
}
10351035

1036+
/// Clears the `NodeAnnouncementInfo` field for all nodes in the `NetworkGraph` for testing
1037+
/// purposes.
1038+
#[cfg(test)]
1039+
pub fn clear_nodes_announcement_info(&self) {
1040+
for node in self.nodes.write().unwrap().iter_mut(){
1041+
node.1.announcement_info = None;
1042+
}
1043+
}
1044+
10361045
/// For an already known node (from channel announcements), update its stored properties from a
10371046
/// given node announcement.
10381047
///

0 commit comments

Comments
 (0)