Skip to content

Feature Request: Fully Deterministic produce_events #243

Open
@carlaKC

Description

@carlaKC

⚠ This will be a non-trivial refactor ⚠

Describe desired feature

SimLN can currently be run with a fixed seed for its random activity setting, but payments produced by the simulator will not be fully deterministic.

This is because we have a single DestinationGenerator which is used across many produce_events tasks*. We can hit the following sequence of events:

  • We have an RNG that produces values 1, 2, 3 then 4
  • We have two produce_events tasks A and B that will both sleep for 5 seconds in between payments**
  • Both A and B are competing for the same lock on our Arc<Mutex<DestinationGeneartor>>

First run:

  • A gets lock first: A gets value 1, B gets value 2
  • A gets lock first: A gets value 3, B gets value 4

Second run:

  • A gets lock first: A gets value 1, B gets value 2
  • B gets lock first: A gets value 4, B gets value 3

Across the two runs, the nodes get different destinations based on the order in which they acquire the lock. This averages out across multiple runs, but isn't properly deterministic. We should fix that.

* this was intentional, we don't want to have to store our lightning graph many times over
** the sleep time is random, so it's not that likely that they sleep for exactly the same time, but not impossible (especially if we start to speed up the clock)

Use case for feature

Fully deterministic runs are important for reproducible simulations.

Design Considerations

Part of this issue will be proposing a solution for this issue and discussing it here before opening up a PR, because it'll likely be a larger change to the codebase.

Incomplete thoughts that I have had about this are:

  1. Bite the memory bullet and copy the network graph for each node so that they have a distinct DestinationGenerator

This gets rid of the locking issue, as each will lock their own destination and always get the same fixed values.

  1. Have a single produce_events loop that deterministically queues events for each node

Rather than spinning up a task for each node to produce its own events, have one master task that's responsible for dispatching events for each of the nodes. This would look something like:

  • Get the next payment time for each node
  • Drop them in a sorted heap
  • Pull the next item off the heap, get the destination from the shared DestinationGenerator
  • Once dispatched, get the next payment time for the node and push it onto the heap
  1. There are probably better ways to do this, but my potato-brain hasn't thought of them.

Would you like to contribute code for this feature?

I'll collaborate on design + contribute review, but won't be able to champion it myself.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions