Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default to BOLT 4 tlv payload format onions #1414

Merged

Conversation

ViktorTigerstrom
Copy link
Contributor

@ViktorTigerstrom ViktorTigerstrom commented Apr 9, 2022

Closes #1393.

Default to creating BOLT 4 tlv payload format onions for nodes for which we haven't received any features through node announcements, and where no other features are known such as invoice features nor features in the init msg for nodes we
have channel(s) to.

If there is a more convenient way in our testing utils to create a network of nodes, where the nodes to not announce their features through NodeAnnouncements, instead of the test config function I created I'll of course change to that :)!

Happy to address any feedback!

@@ -1132,7 +1134,7 @@ where L::Target: Logger {
let features = if let Some(node_info) = $node.announcement_info.as_ref() {
&node_info.features
} else {
&empty_node_features
&variable_length_onion_optional_features
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just want to clarify that I couldn't manage to create a test scenario where changing this specific line created a different result in terms of which payload format we create. Though I think it makes sense to change this line.

@codecov-commenter
Copy link

codecov-commenter commented Apr 9, 2022

Codecov Report

Merging #1414 (697bda8) into main (711bcef) will increase coverage by 0.02%.
The diff coverage is 96.07%.

@@            Coverage Diff             @@
##             main    #1414      +/-   ##
==========================================
+ Coverage   90.82%   90.84%   +0.02%     
==========================================
  Files          73       74       +1     
  Lines       41266    41375     +109     
  Branches    41266    41375     +109     
==========================================
+ Hits        37480    37589     +109     
  Misses       3786     3786              
Impacted Files Coverage Δ
lightning/src/ln/functional_test_utils.rs 95.54% <ø> (ø)
lightning/src/routing/router.rs 92.58% <94.73%> (+0.08%) ⬆️
lightning/src/ln/onion_route_tests.rs 97.45% <96.20%> (-0.17%) ⬇️
lightning/src/routing/network_graph.rs 89.88% <100.00%> (+0.27%) ⬆️
lightning/src/ln/channelmanager.rs 84.66% <0.00%> (-0.29%) ⬇️
lightning-invoice/src/utils.rs 96.53% <0.00%> (-0.16%) ⬇️
lightning/src/ln/functional_tests.rs 97.04% <0.00%> (-0.02%) ⬇️
lightning/src/ln/mod.rs 95.00% <0.00%> (ø)
lightning/src/ln/inbound_payment.rs 93.49% <0.00%> (ø)
... and 2 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 711bcef...697bda8. Read the comment docs.

@ViktorTigerstrom
Copy link
Contributor Author

Cleaned up some documentation.

Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe this modifies the default for last-hop hints which do not appear in the network graph at all. This is the most common use for this. See the NodeFeatures::empty() call on L1317 in router.rs

@ViktorTigerstrom
Copy link
Contributor Author

I don't believe this modifies the default for last-hop hints which do not appear in the network graph at all. This is the most common use for this. See the NodeFeatures::empty() call on L1317 in router.rs

Ah thanks, I'll update with converge of that case as soon as I can!

Comment on lines 1104 to 1105
let mut variable_length_onion_optional_features = NodeFeatures::empty();
variable_length_onion_optional_features.set_variable_length_onion_optional();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let mut variable_length_onion_optional_features = NodeFeatures::empty();
variable_length_onion_optional_features.set_variable_length_onion_optional();
let mut onion_optional_features = NodeFeatures::empty();
onion_optional_features.set_variable_length_onion_optional();

I'm a super fan of the explicative variable name, but I think that here the variable is too long? Mabey onion_optional_features is better?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vincenzopalazzo True, thanks a lot for the feedback! I opted for onion_format_optional_features in the latest version I pushed, to find some middle ground without losing too much meaning. But I'll change to onion_optional_features if you think that's still too long :)

@@ -1132,7 +1134,7 @@ where L::Target: Logger {
let features = if let Some(node_info) = $node.announcement_info.as_ref() {
&node_info.features
} else {
&empty_node_features
&variable_length_onion_optional_features
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
&variable_length_onion_optional_features
&onion_optional_features

@@ -1330,7 +1332,7 @@ where L::Target: Logger {
if let Some(node_info) = node.announcement_info.as_ref() {
ordered_hops.last_mut().unwrap().1 = node_info.features.clone();
} else {
ordered_hops.last_mut().unwrap().1 = NodeFeatures::empty();
ordered_hops.last_mut().unwrap().1 = variable_length_onion_optional_features.clone();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ordered_hops.last_mut().unwrap().1 = variable_length_onion_optional_features.clone();
ordered_hops.last_mut().unwrap().1 = onion_optional_features.clone();

@jkczyz jkczyz self-requested a review April 12, 2022 17:42
Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically lgtm, need to review the tests still, can you squash the fixup commits?

@ViktorTigerstrom ViktorTigerstrom force-pushed the 2022-04-default-to-tlv-onions branch 2 times, most recently from b713196 to 18557ce Compare April 12, 2022 18:55
@ViktorTigerstrom
Copy link
Contributor Author

Fixed some documentation and updated the commit message. Sorry about that.

Copy link
Contributor

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Largely look good but still need to review the tests while you address the comments.

@@ -2958,7 +2964,7 @@ mod tests {
assert_eq!(route.paths[0][3].short_channel_id, last_hops[0].0[1].short_channel_id);
assert_eq!(route.paths[0][3].fee_msat, 100);
assert_eq!(route.paths[0][3].cltv_expiry_delta, 42);
assert_eq!(route.paths[0][3].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
assert_eq!(route.paths[0][3].node_features.le_flags(), &vec![0, 2]); // We dont pass flags in from invoices yet
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use default_onion_format_flags?

Comment on lines 1104 to 1105
let mut onion_format_optional_features = NodeFeatures::empty();
onion_format_optional_features.set_variable_length_onion_optional();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say use a method for this so it can be reused in the tests and name the variable default_node_features. No need to have the name talk about the feature itself. FWIW, I think we lose some meaning by dropping the "variable length" part of it, but we can avoid that by just using a generic name.

Comment on lines 1850 to 1852
fn default_onion_format_flags() -> Vec<u8> {
vec![0, 2]
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could drop this in favor of using the previously suggested method and calling le_flags on the result.

@ViktorTigerstrom
Copy link
Contributor Author

Thanks for the feedback @jkczyz! Addressed it in the latest commit.

I've also realized that I should maybe expand my test to include routing through an unannounced node that isn't the target node, to cover that case as well. I'll add that if you think that it's of value to cover that case in the tests.

///
/// Default features are:
/// * variable_length_onion_optional
fn default_node_features() -> NodeFeatures {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decided to also name this function to default_node_features, so that it possibly can be extended with more features in the future. I also considered if it would make more sense to add this as part of the NodeFeatures type itself, but figured that it probably belongs to the router context.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this refactoring :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to use some of our macros to simplify the tests (I commented with two specific ones, but similar changes apply in test_do_not_use_default_to_tlv_onions_if_other_features_not_supporting_them_exists as well. Otherwise LGTM.

Comment on lines 606 to 614
let scorer = test_utils::TestScorer::with_penalty(0);
let seed = [0u8; 32];
let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let read_only_network_graph = &network_graph.read_only();
let announced_route = get_route(
&origin_node.node.get_our_node_id(), &payment_params, read_only_network_graph,
Some(&origin_node.node.list_usable_channels().iter().collect::<Vec<_>>()),
1000000, TEST_FINAL_CLTV, origin_node.logger, &scorer, &random_seed_bytes).unwrap();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let scorer = test_utils::TestScorer::with_penalty(0);
let seed = [0u8; 32];
let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let read_only_network_graph = &network_graph.read_only();
let announced_route = get_route(
&origin_node.node.get_our_node_id(), &payment_params, read_only_network_graph,
Some(&origin_node.node.list_usable_channels().iter().collect::<Vec<_>>()),
1000000, TEST_FINAL_CLTV, origin_node.logger, &scorer, &random_seed_bytes).unwrap();
let (announced_route, _, _, _) = get_route_and_payment_hash!(origin_node, nodes[3], 1_000_000);

Comment on lines 644 to 648
let unannounced_chan_params = PaymentParameters::from_node_id(nodes[4].node.get_our_node_id()).with_route_hints(vec![last_hop]);
let unannounced_route = get_route(
&origin_node.node.get_our_node_id(), &unannounced_chan_params, read_only_network_graph,
Some(&origin_node.node.list_usable_channels().iter().collect::<Vec<_>>()),
10000, TEST_FINAL_CLTV, origin_node.logger, &scorer, &random_seed_bytes).unwrap();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let unannounced_chan_params = PaymentParameters::from_node_id(nodes[4].node.get_our_node_id()).with_route_hints(vec![last_hop]);
let unannounced_route = get_route(
&origin_node.node.get_our_node_id(), &unannounced_chan_params, read_only_network_graph,
Some(&origin_node.node.list_usable_channels().iter().collect::<Vec<_>>()),
10000, TEST_FINAL_CLTV, origin_node.logger, &scorer, &random_seed_bytes).unwrap();
let (unannounced_route, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[4], last_hop, 10_000, TEST_FINAL_CLTV);

@ViktorTigerstrom
Copy link
Contributor Author

ViktorTigerstrom commented Apr 13, 2022

Would be nice to use some of our macros to simplify the tests (I commented with two specific ones, but similar changes apply in test_do_not_use_default_to_tlv_onions_if_other_features_not_supporting_them_exists as well. Otherwise LGTM.

Hmmm the current version of the get_route_and_payment_hash macro specifies that the PaymentParameters should be constructed using InvoiceFeatures::known(), which will then be used when creating the route for the last hop.
So I had to modify the get_route_and_payment_hash macro in order to be able to use it. However I'm not really sure if my modifications simplified the tests or just complicated things more since the macro became more complicated to understand?

I therefore pushed the changes in a fixup commit, which I'll squash or drop depending on if you think the modifications are ok.

@TheBlueMatt
Copy link
Collaborator

Oops, right, good point. I do still prefer the fixup change here - less code duplication for stuff that we end up changing kinda often means way less painful changes later on.

let payment_params = $crate::routing::router::PaymentParameters::from_node_id($recv_node.node.get_our_node_id())
.with_features($crate::ln::features::InvoiceFeatures::known())
.with_route_hints($last_hops);
$crate::get_route_and_payment_hash!($send_node, $recv_node, payment_params, $recv_value, $cltv, true)
}};
($send_node: expr, $recv_node: expr, $payment_params: expr, $recv_value: expr, $cltv: expr, true /* with specified payment_params */) => {{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to just have this pattern (without the last true) and have uses of the previous pattern pass in the full PaymentParameters? I think there's only a few places in priv_short_conf_tests.rs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok sure, I'll fix that ASAP!

Default to creating tlv onions for nodes for which we haven't received
any features through node announcements or which aren't in the
`network_graph`, and where no other features are known such as invoice
features nor features in the init msg for nodes we have channels to.
@ViktorTigerstrom
Copy link
Contributor Author

ViktorTigerstrom commented Apr 14, 2022

Addressed the latest feedback and squashed the commits!

Note that I pushed the change of the get_route_and_payment_hash macro in a separate commit now as it isn't really related to the defaulting feature I've implemented, and I therefore wanted to avoid mixing the macro change with the feature's tests. Though I can of course squash them if you think that it's more appropriate!

Copy link
Contributor

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Just some nits on the tests.

// onions, as `nodes[0]` has no `NodeAnnouncementInfo` `features` for `node[3]`, and no `InvoiceFeatures`
// for the `payment_params`, which would otherwise have been used.
assert!(hops[2].node_features.supports_variable_length_onion());
// Note that we do not asset that `hops[0]` (the channel between `nodes[0]` and `nodes[1]`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/asset/assert

// for the `payment_params`, which would otherwise have been used.
assert!(hops[2].node_features.supports_variable_length_onion());
// Note that we do not asset that `hops[0]` (the channel between `nodes[0]` and `nodes[1]`)
// supports variable length onions, as the `InitFeatures` exchanged in the init message when
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "when"

/// purposes.
#[cfg(test)]
pub fn clear_nodes_announcement_info(&self) {
for node in self.nodes.write().unwrap().iter_mut(){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add space before brace

Comment on lines 667 to 675
// Tests that we do not default to creating tlv onions if any of these features exists when
// creating the specific hop in the route:
// 1. `InitFeatures` to the counterparty node exchanged with the init message to the node, which
// doesn't support variable length onions.
// 2. `NodeFeatures` in the `NodeAnnouncementInfo` of a node in sender node's the
// `network_graph`, which doesn't support variable length onions.
// 3. `InvoiceFeatures` specified by the receiving node, which doesn't support variable length
// onions, when no `NodeAnnouncementInfo` `features` exists for the receiver in the sender's
// `network_graph`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The language could be simplified here by moving the "doesn't support variable length onions" part out of each item and said once preceding the list.

// creating the specific hop in the route:
// 1. `InitFeatures` to the counterparty node exchanged with the init message to the node, which
// doesn't support variable length onions.
// 2. `NodeFeatures` in the `NodeAnnouncementInfo` of a node in sender node's the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drop trailing "the"

}

#[test]
fn test_do_not_use_default_to_tlv_onions_if_other_features_not_supporting_them_exists() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To name somewhat similar to the previous test, how about: test_do_not_default_to_onion_payload_tlv_format_when_unsupported

Copy link
Contributor

@vincenzopalazzo vincenzopalazzo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ViktorTigerstrom
Copy link
Contributor Author

Thanks for the feedback @jkczyz! Addressed and squashed it with the last commit :)

@jkczyz jkczyz merged commit e0b9b74 into lightningdevkit:main Apr 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

default to using new onion tlvs even without feature flags
5 participants