Skip to content

Simulating countermeasures against jamming attacks in the Lightning Network

License

Notifications You must be signed in to change notification settings

s-tikhomirov/ln-jamming-simulator

Repository files navigation

Lightning Network Jamming Simulator

A simulator for Lightning Network payments with unconditional fees, aimed at preventing jamming attacks.

See paper: Unjamming Lightning: A Systematic Approach.

Quick start

Requires NetworkX and NumPy. Tests require pytest.

How to run it:

$ python run.py --num_runs_per_simulation=10 --duration=300 --scenario=virtual --log_level=info --num_jamming_batches=5

See run.py -help for details.

Architecture

The general architecture is as follows.

The Simulator executes a simulation Scenario. A Scenario describes the network topology along with the properties of honest and malicious payments. The goal of a simulation is to estimate the revenue of certain nodes with and without an attack. The results are written as JSON and CSV files into /results (filenames include the current timestamp).

First, we prepare a Scenario. This involves the following:

  • parse a snapshot from /snapshots;
  • specify the honest and malicious senders and receivers, and, optionally, the target node;
  • specify the list of nodes that payments must go through (optionally).

Running the Scenario involves running two simulations: with and without jamming. A simulation implies, first, creating a Schedule, and then executing it. A Schedule consists of timestamped Events, where each event represents an honest payment or a jam. During execution, the simulator pops the next Event from the Schedule and executes it, until the schedule is empty.

To execute an Event, the simulator does the following:

  • find a suitable route from the sender to the receiver for the amount required (implemented in Router);
  • create a Payment for the current event and the selected route;
  • send the Payment along the route (make up to a specified number of attempts if necessary).

Sending a Payment along the route involves these stages, until the payment fails or reaches the receiver:

  • extract the next node from the Payment;
  • pick a suitable Channel in the Hop towards the next node;
  • store a new Htlc in the HTLC queue of the chosen channel in the direction needed (ChannelDirection);
  • if there are no free slots in this ChannelDirection, try resolving the oldest HTLC from the queue;
  • if even the HTLC with the lowest resolution time can't yet be resolved (i.e., the channel is jammed), fail the payment.

For more implementation details, see classes.md and simulation.md.

An example of JSON output:

{
    "params": {
        "scenario": "wheel",
        "num_target_node_pairs": 8,
        "duration": 30,
        "num_runs_per_simulation": 10,
        "success_base_fee": 1,
        "success_fee_rate": 5e-06,
        "no_balance_failures": false,
        "default_num_slots_per_channel_in_direction": 483,
        "max_num_attempts_per_route_honest": 10,
        "max_num_attempts_per_route_jamming": 493,
        "dust_limit": 354,
        "honest_payments_per_second": 10,
        "min_processing_delay": 1,
        "expected_extra_processing_delay": 3,
        "jam_delay": 7
    },
    "simulations": {
        "honest": [
            {
                "upfront_base_coeff": 0,
                "upfront_rate_coeff": 0,
                "stats": {
                    "num_sent": 3.2,
                    "num_failed": 0.4,
                    "num_reached_receiver": 2.8
                },
                "revenues": {
                    "Alice": -1.3611165,
                    "Hub": 3.0027425,
                    "Bob": -0.5166645,
                    "Charlie": -0.3822195,
                    "Dave": -0.742742,
                    "JammerSender": 0,
                    "JammerReceiver": 0
                }
            }
        ],
        "jamming": [
            {
                "upfront_base_coeff": 0,
                "upfront_rate_coeff": 0,
                "stats": {
                    "num_sent": 2471.9,
                    "num_failed": 2471.9,
                    "num_reached_receiver": 2425
                },
                "revenues": {
                    "Alice": 0.0,
                    "Hub": 0.0,
                    "Bob": 0.0,
                    "Charlie": 0.0,
                    "Dave": 0.0,
                    "JammerSender": 0.0,
                    "JammerReceiver": 0.0
                }
            }
        ]
    }
}

The numbers in stats are not necessarily integers, as they are averaged across multiple simulation runs. The revenues for the jamming case in the example above are all zero, because jams fail and don't pay success-case fees. For upfront_base_coeff > 0 or upfront_rate_coeff > 0, that would not be the case.

The coefficients upfront_base_coeff and upfront_rate_coeff indicate what the unconditional fee parameters are in proportion to the default success-case parameters. If the success-case fee is 1 satoshi plus 5 parts per million, upfront_base_coeff is 2, and upfront_rate_coeff is 3, then the unconditional fee would be 2 satoshi plus 15 parts per million. (The numbers are picked just for the sake of an example; in real simulations, upfront fees are much lower.)

About

Simulating countermeasures against jamming attacks in the Lightning Network

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages