Skip to content

multi: Small Determinism Fixups#308

Merged
carlaKC merged 4 commits into
bitcoin-dev-project:mainfrom
carlaKC:determinism-fixups
Jun 24, 2026
Merged

multi: Small Determinism Fixups#308
carlaKC merged 4 commits into
bitcoin-dev-project:mainfrom
carlaKC:determinism-fixups

Conversation

@carlaKC

@carlaKC carlaKC commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

A few low hanging fruit for improving determinism courtesy of claude.

carlaKC and others added 4 commits June 23, 2026 14:26
The payment event heap previously ordered events by execution time alone.
When two events are scheduled for the same instant, the BinaryHeap pop order
was unspecified, making otherwise-seeded runs non-reproducible.

Break ties on the source node's public key. The heap holds at most one event
per source at a time, so (execution_time, source) is a total order, and Eq is
made consistent with the new Ord.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two select! loops still polled their branches in tokio's default random order:
the payment-failure result send in produce_simulation_results, and the
interceptor-result drain in the SimNode HTLC forwarding path. Random branch
selection is a source of run-to-run non-determinism.

Make both biased so their poll order is fixed. Branch order is unchanged, so
behaviour is identical save for the now-deterministic ordering. The shutdown
listener already sits first in the failure-send loop, matching the
shutdown-first convention used elsewhere.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
send_payment stamped each Payment's dispatch_time with SystemTime::now(),
bypassing the simulation clock. Under discrete-event simulation the wall clock
does not advance with virtual time, so this both broke virtual-time timestamps
and made results non-reproducible.

Stamp the dispatch time from the simulation clock once the inter-payment wait
has elapsed, and thread it into send_payment as an argument.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The latency interceptor sampled its forwarding delay from rand::thread_rng(),
an unseeded global RNG. That made HTLC latencies non-reproducible even when the
simulation was given a fixed seed.

Hold a seedable StdRng on the interceptor (behind a mutex, since it is shared
across concurrent HTLCs) and seed it from the new_poisson constructor. The CLI
threads its fixed seed through when building the interceptor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@carlaKC carlaKC requested a review from elnosh June 24, 2026 14:04
@carlaKC carlaKC merged commit 941839e into bitcoin-dev-project:main Jun 24, 2026
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