Skip to content

slow jam attack impl - #114

Merged
elnosh merged 1 commit into
carlaKC:masterfrom
elnosh:slow-jam-attack
Oct 8, 2025
Merged

slow jam attack impl#114
elnosh merged 1 commit into
carlaKC:masterfrom
elnosh:slow-jam-attack

Conversation

@elnosh

@elnosh elnosh commented Sep 18, 2025

Copy link
Copy Markdown
Collaborator

No description provided.

Comment thread ln-resource-mgr/src/lib.rs Outdated

@carlaKC carlaKC left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Looking good! I think we just need to tighten up validation a bit and then this will be good to go.

In a follow up, I think that it would be interesting to re-use this logic to do slot jamming (rather than the liquidity jamming that we have here) - it'll probably end up cheaper (reputation for ~200 above-dust htlcs should be cheaper than the full liquidity of the channel).

{
fn setup_for_network(&self) -> Result<NetworkSetup, BoxError> {
// Validate that attacker receiver has channel with target.
self.target_channels

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I think that we should add some stricter checks here, just so that we can be sure that everything is happening as expected:

  • channel_to_jam is in target_channels
  • attacker_sender has a channel with the node that owns channel_to_jam
  • The sanity_check_node has a channel with channel_to_jam node
  • The honest receiver_pubkey has a channel with target

Specifically the last one, because this is how we check we've succeeded with a test payment. If we don't have a target -- receiver_pubkey channel, we'll still get a failed payment and think that we succeeded but actually it was just a bad route.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

will add for these 2

  • channel_to_jam is in target_channels
  • The honest receiver_pubkey has a channel with target

for

  • attacker_sender has a channel with the node that owns channel_to_jam
  • The sanity_check_node has a channel with channel_to_jam node

would be hard to make those checks here since we don't have a list of all the channels (only the target channels) but I think that for

attacker_sender has a channel with the node that owns channel_to_jam

is implicitly checked if build_reputation succeeds. If attacker_sender didn't have a channel with the target's peer then build_reputation would fail and subsequently cause the attack to return an error.

The sanity_check_node has a channel with channel_to_jam node

This could be checked by making a test payment before the attack and check that it succeeds. Then if payment over same route over channel_to_jam fails then it means the channel is jammed (it could've failed for liquidity reasons but can also check for reason in results file and verify that it failed because of no resources)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

would be hard to make those checks here since we don't have a list of all the channels

We can use self.network_graph.read_only().channels() and then just check that the channel_to_jam's node_one / node_two are the attacker_sender and channel_to_jam pubkeys.

We could probably use the LDK graph for the target_channels as well, but we need them so much that it's worth keeping a list of them around IMO.

is implicitly checked if build_reputation succeeds.
This could be checked by making a test payment before the attack and check that it succeeds.

We can implicitly check some of these while running the simulation, but I think we should aim to fail-fast if we're spun up with a topology that we don't like (rather than pass validation of the network, then fail to run the simulation). Should be do-able with the LDK network graph? Even if it's just checking the pubkeys as suggested above.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I completely blanked out on fact that I had the network_graph 🤦‍♂️
Added checks for these two:

  • attacker_sender has a channel with the node that owns channel_to_jam
  • The sanity_check_node has a channel with channel_to_jam node

Comment thread ln-simln-jamming/src/attacks/slow_jam.rs Outdated
Comment thread ln-simln-jamming/src/attacks/slow_jam.rs Outdated
Comment thread ln-simln-jamming/src/parsing.rs Outdated
@elnosh

elnosh commented Oct 3, 2025

Copy link
Copy Markdown
Collaborator Author

addressed comments in fixup

@elnosh
elnosh requested a review from carlaKC October 3, 2025 15:10

@carlaKC carlaKC left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Really close, just some last validation gripes please 🙏

Comment thread ln-simln-jamming/src/attacks/slow_jam.rs
self.honest_sender.0
))?;

let check_payment = async |expect_succeed: bool| -> Result<(), BoxError> {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I don't think we gain all that much making this a closure, could be implemented on attack instead?

Don't have strong feelings here, so take it or leave it!

{
fn setup_for_network(&self) -> Result<NetworkSetup, BoxError> {
// Validate that attacker receiver has channel with target.
self.target_channels

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

would be hard to make those checks here since we don't have a list of all the channels

We can use self.network_graph.read_only().channels() and then just check that the channel_to_jam's node_one / node_two are the attacker_sender and channel_to_jam pubkeys.

We could probably use the LDK graph for the target_channels as well, but we need them so much that it's worth keeping a list of them around IMO.

is implicitly checked if build_reputation succeeds.
This could be checked by making a test payment before the attack and check that it succeeds.

We can implicitly check some of these while running the simulation, but I think we should aim to fail-fast if we're spun up with a topology that we don't like (rather than pass validation of the network, then fail to run the simulation). Should be do-able with the LDK network graph? Even if it's just checking the pubkeys as suggested above.

@carlaKC carlaKC left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

LGTM!

Just one nit, feel free to ignore or add on squash. Feel free to go ahead with merge once squashed 🥇

let mut attacker_channel_present = false;
let mut honest_sender_present = false;
for channel in peer_channels {
if let Some(channel_info) = graph.channel(*channel) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

nit: should we fail if the channel we got from graph.node.channels isn't present here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I would think there is something very wrong in LDK if we got it in the list of a node's channels but not in this channel call. But I don't mind adding.

@elnosh
elnosh merged commit 4b6a3fc into carlaKC:master Oct 8, 2025
2 checks passed
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.

2 participants