Skip to content

Conversation

joostjager
Copy link
Contributor

@joostjager joostjager commented Sep 10, 2025

Adds functionality for LSPs to hold onion messages for their clients until they come back online.

Depends on lightningdevkit/rust-lightning#4046

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Sep 10, 2025

👋 Thanks for assigning @tnull as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@joostjager joostjager changed the base branch from main to develop September 10, 2025 12:01
@joostjager joostjager requested a review from tnull September 10, 2025 12:12
@joostjager joostjager force-pushed the onion-mailbox branch 2 times, most recently from 8612c01 to d9545a8 Compare September 11, 2025 14:30
@joostjager joostjager self-assigned this Sep 11, 2025
@joostjager joostjager force-pushed the onion-mailbox branch 2 times, most recently from 9818d0c to 89d74d5 Compare September 12, 2025 07:27
src/lib.rs Outdated
}

#[allow(missing_docs)]
pub fn om_mailbox_is_empty(&self) -> bool {
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 wanted to expose this to the integration test, but not sure how to do it without introducing an extra cfg flag

Copy link
Collaborator

Choose a reason for hiding this comment

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

Well, that's why they are integration / black box tests, they test the public API. Would be good to drop this method. If you want to test internal functionality, you'd need to write a unit test.

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 don't think it is so binary, but I understand your pov. As far as I know, there isn't really another way to detect that the onion message is intercepted and waiting. Would you want to use a (blind) sleep instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Using sleep 3s now.

@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @tnull! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 2nd Reminder

Hey @tnull! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Copy link
Collaborator

@tnull tnull left a comment

Choose a reason for hiding this comment

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

This needs a rebase now.

@joostjager joostjager force-pushed the onion-mailbox branch 2 times, most recently from 8192f71 to a971ee4 Compare September 16, 2025 07:32
@joostjager
Copy link
Contributor Author

Rebased after merge of #621

@joostjager
Copy link
Contributor Author

Updated to latest version of lightningdevkit/rust-lightning#4046

src/event.rs Outdated
LdkEvent::OnionMessageIntercepted { .. } => {
debug_assert!(false, "We currently don't support onion message interception, so this event should never be emitted.");
LdkEvent::OnionMessageIntercepted { peer_node_id, message } => {
self.om_mailbox.onion_message_intercepted(peer_node_id, message);
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 still log an error and do nothing here if !config.async_payment_services_enabled?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added trace log

src/builder.rs Outdated
},
};

let om_mailbox = Arc::new(OnionMessageMailbox::new());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we make this an Option that will only be set if async_payment_services_enabled?

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 am not a fan of this type of optionality as there resources involved with an empty onion mailbox are negligible. But made the change.

src/lib.rs Outdated
}

#[allow(missing_docs)]
pub fn om_mailbox_is_empty(&self) -> bool {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Well, that's why they are integration / black box tests, they test the public API. Would be good to drop this method. If you want to test internal functionality, you'd need to write a unit test.

}

impl OnionMessageMailbox {
const MAX_MESSAGES_PER_PEER: usize = 100;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm, these 100/100 values seems relatively restrictive and still results in ~300 MB of OM data in memory, AFAIU.

Maybe it would be worth to at least go for a 30/300 ratio, so that we allow for more potential peers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Any of those constant can be right or wrong, no strong opinion about it. Changed.

let peer_to_remove = map
.iter()
.max_by_key(|(_, queue)| queue.len())
.map(|(peer, _)| peer.clone())
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think PublicKey is Copy.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed. Made it *peer

const MAX_PEERS: usize = 100;

pub fn new() -> Self {
Self { map: Mutex::new(HashMap::new()) }
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would it make sense to pre-alloc some capacity from the start to avoid constant reallocations?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As this is triggered by a network message, this seems to be a negligible optimization?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added MAX_PEERS capacity.

@joostjager joostjager force-pushed the onion-mailbox branch 2 times, most recently from cfc9387 to 39fe521 Compare September 17, 2025 12:36
Copy link
Collaborator

@tnull tnull left a comment

Choose a reason for hiding this comment

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

This needs yet another rebase now

This introduces an in-memory mailbox to hold onion messages until the
receiver comes online. This is required for async payment
`held_htlc_available` messages.

The mailbox is bounded by a maximum number of peers and a maximum
number of messages per peer.
@joostjager
Copy link
Contributor Author

Rebased

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

3 participants