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

Trampoline Payload Construction Method #3386

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

arik-so
Copy link
Contributor

@arik-so arik-so commented Oct 28, 2024

Introduce a method for constructing Trampoline payloads.

This will allow the non-Trampoline method to be modified to generate a Trampoline onion and finish its own regular payload construction.

Builds on top of #3333.

lightning/src/routing/router.rs Outdated Show resolved Hide resolved
lightning/src/routing/router.rs Outdated Show resolved Hide resolved
@@ -454,6 +454,9 @@ impl_writeable_tlv_based!(BlindedTail, {
pub struct Path {
/// The list of unblinded hops in this [`Path`]. Must be at least length one.
pub hops: Vec<RouteHop>,
/// The list of unblinded Trampoline hops. If present, must be at least one.
/// The public key of the first Trampoline hop must match the public key of the last regular hop.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't see why this needs to be true. Can we just have each trampoline hop be next hops starting after the last unblinded node.

@@ -454,6 +454,9 @@ impl_writeable_tlv_based!(BlindedTail, {
pub struct Path {
/// The list of unblinded hops in this [`Path`]. Must be at least length one.
pub hops: Vec<RouteHop>,
/// The list of unblinded Trampoline hops. If present, must be at least one.
/// The public key of the first Trampoline hop must match the public key of the last regular hop.
pub trampoline_hops: Vec<TrampolineHop>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Seems weird to add this to the public API in a PR that doesn't use it. Can you go ahead and wire up build_trampoline_onion_payloads to build the valid onion in the same PR?

@arik-so arik-so force-pushed the arik/trampoline/payload-construction branch 2 times, most recently from 7cad33e to 856ce97 Compare November 19, 2024 23:04
@arik-so arik-so force-pushed the arik/trampoline/payload-construction branch from 856ce97 to 5ea3ada Compare November 21, 2024 17:15
Copy link

codecov bot commented Nov 21, 2024

Codecov Report

Attention: Patch coverage is 27.39130% with 167 lines in your changes missing coverage. Please review.

Project coverage is 89.98%. Comparing base (726dd5c) to head (35a3693).
Report is 8 commits behind head on main.

Files with missing lines Patch % Lines
lightning/src/ln/onion_utils.rs 9.94% 161 Missing and 2 partials ⚠️
lightning/src/events/mod.rs 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3386      +/-   ##
==========================================
+ Coverage   89.69%   89.98%   +0.29%     
==========================================
  Files         130      130              
  Lines      107335   109705    +2370     
  Branches   107335   109705    +2370     
==========================================
+ Hits        96273    98721    +2448     
+ Misses       8660     8657       -3     
+ Partials     2402     2327      -75     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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.

Ah I guess my previous comments still need to be addressed.

@@ -404,13 +404,16 @@ pub struct BlindedTail {
pub excess_final_cltv_expiry_delta: u32,
/// The total amount paid on this [`Path`], excluding the fees.
pub final_value_msat: u64,
/// Used for determining the type of Trampoline path to construct
pub final_hop_supports_trampoline: bool
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we instead consider storing a *Features of some form?

lightning/src/routing/router.rs Outdated Show resolved Hide resolved
@arik-so arik-so force-pushed the arik/trampoline/payload-construction branch from 5ea3ada to af1818b Compare December 5, 2024 01:19
@arik-so arik-so mentioned this pull request Dec 5, 2024
29 tasks
@arik-so arik-so force-pushed the arik/trampoline/payload-construction branch 4 times, most recently from ee68783 to 4dd0fea Compare December 9, 2024 05:31
Ok((res, value_msat, cltv))
}

fn build_trampoline_onion_payloads_callback<'a, H, B, F>(
Copy link
Contributor

@valentinewallace valentinewallace Dec 10, 2024

Choose a reason for hiding this comment

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

Is there a way to DRY this with build_onion_payloads_callback, via implementing a trait on OutboundTrampolinePayload and OutboundOnionPayload that the common method is parameterized by? Kinda like what we do for decode_next_hop and how it works for both onion message and onion payment packets.

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'm not sure the payloads_callback is super DRYable, because all the response types that are being pushed vary strongly between RouteHop and TrampolineHop, but I think I was able to at least DRY up the onion_keys callback.

@arik-so arik-so force-pushed the arik/trampoline/payload-construction branch 3 times, most recently from 67100ce to dc679c0 Compare December 11, 2024 07:23
@arik-so arik-so force-pushed the arik/trampoline/payload-construction branch from dc679c0 to 7477b1a Compare December 12, 2024 17:14
@@ -1940,7 +1940,7 @@ impl MaybeReadable for Event {
payment_hash,
payment_failed_permanently,
failure,
path: Path { hops: path.unwrap(), blinded_tail },
path: Path { hops: path.unwrap(), trampoline_hops: vec![], blinded_tail },
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we'll want to serialize these hops in the event(s) eventually so may be easy to just do it in this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

true, will add serialization

onion_payloads.push(OutboundOnionPayload::TrampolineEntrypoint {
amt_to_forward: outer_total_msat,
outgoing_cltv_value: outer_starting_htlc_offset,
multipath_trampoline_data: None,
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this be set to something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh yes, good catch, thank you

cur_value_msat += final_value_msat;
callback(
PayloadCallbackAction::PushBack,
msgs::OutboundTrampolinePayload::BlindedReceive {
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like in https://github.com/lightning/bolts/blob/fa0594ac2af3531d734f1d707a146d6e13679451/bolt04/trampoline-payment-onion-test.json there can be final trampoline hops that are unblinded, but that doesn't look supported in the code atm. Are we explicitly only supporting trampoline to blinded paths?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yup, we deliberately are. We originally supported non-blinded destinations but decided not to.

let trampoline_onion_keys = construct_trampoline_onion_keys(&Secp256k1::new(), &trampoline_hops, &trampoline_session_key).unwrap();
let trampoline_onion_packet = construct_trampoline_onion_packet(trampoline_payloads, trampoline_onion_keys, [0u8; 32], &associated_data, None).unwrap();
let trampoline_onion_packet_hex = trampoline_onion_packet.encode().to_lower_hex_string();
assert_eq!(trampoline_onion_packet_hex, "0002bc59a9abc893d75a8d4f56a6572f9a3507323a8de22abe0496ea8d37da166a8b4bba0e560f1a9deb602bfd98fe9167141d0b61d669df90c0149096d505b85d3d02806e6c12caeb308b878b6bc7f1b15839c038a6443cd3bec3a94c2293165375555f6d7720862b525930f41fddcc02260d197abd93fb58e60835fd97d9dc14e7979c12f59df08517b02e3e4d50e1817de4271df66d522c4e9675df71c635c4176a8381bc22b342ff4e9031cede87f74cc039fca74aa0a3786bc1db2e158a9a520ecb99667ef9a6bbfaf5f0e06f81c27ca48134ba2103229145937c5dc7b8ecc5201d6aeb592e78faa3c05d3a035df77628f0be9b1af3ef7d386dd5cc87b20778f47ebd40dbfcf12b9071c5d7112ab84c3e0c5c14867e684d09a18bc93ac47d73b7343e3403ef6e3b70366835988920e7d772c3719d3596e53c29c4017cb6938421a557ce81b4bb26701c25bf622d4c69f1359dc85857a375c5c74987a4d3152f66987001c68a50c4bf9e0b1dab4ad1a64b0535319bbf6c4fbe4f9c50cb65f5ef887bfb91b0a57c0f86ba3d91cbeea1607fb0c12c6c75d03bbb0d3a3019c40597027f5eebca23083e50ec79d41b1152131853525bf3fc13fb0be62c2e3ce733f59671eee5c4064863fb92ae74be9ca68b9c716f9519fd268478ee27d91d466b0de51404de3226b74217d28250ead9d2c95411e0230570f547d4cc7c1d589791623131aa73965dccc5aa17ec12b442215ce5d346df664d799190df5dd04a13");
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 generate and check the overall payment onion from the test vector as well as the inner trampoline onion?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure, I can extend that

@arik-so arik-so force-pushed the arik/trampoline/payload-construction branch from 7477b1a to ba71d6e Compare December 13, 2024 10:34
let outer_session_key = SecretKey::from_slice(&<Vec<u8>>::from_hex("4f777e8dac16e6dfe333066d9efb014f7a51d11762ff76eca4d3a95ada99ba3e").unwrap()).unwrap();
let outer_onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &outer_hops, &outer_session_key).unwrap();
let outer_onion_prng_seed = onion_utils::gen_pad_from_shared_secret(&outer_session_key.secret_bytes());
let outer_onion_packet = onion_utils::construct_onion_packet(outer_payloads, outer_onion_keys, outer_onion_prng_seed, &associated_data).unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use create_payment_onion instead? I think we don't currently have coverage of that method when trampoline hops are present and generally better to use the public API when testing

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, I think I have some ideas for how to do it precisely enough for it to match the test vectors. Not entirely sure yet if it will work, but I'll see what I can do

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 pushed changes addressing the other comments, but this one will take a little while

@@ -1584,6 +1584,7 @@ impl Writeable for Event {
(9, None::<RouteParameters>, option), // retry in LDK versions prior to 0.0.115
(11, payment_id, option),
(13, failure, required),
(15, path.trampoline_hops, required_vec),
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: use optional_vec so we don't write it when it's empty

@@ -2085,7 +2088,7 @@ impl MaybeReadable for Event {
Ok(Some(Event::PaymentPathSuccessful {
payment_id: payment_id.0.unwrap(),
payment_hash,
path: Path { hops: path, blinded_tail },
path: Path { hops: path, trampoline_hops: vec![], blinded_tail },
Copy link
Contributor

Choose a reason for hiding this comment

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

Needs ser for this event too

@arik-so arik-so force-pushed the arik/trampoline/payload-construction branch from ba71d6e to b934379 Compare December 13, 2024 22:03
@arik-so arik-so force-pushed the arik/trampoline/payload-construction branch from b934379 to 6569246 Compare December 13, 2024 22:54
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.

3 participants