Skip to content

Fix multi-leader jitter target receding instead of anchoring to round start#6484

Closed
ma2bd wants to merge 1 commit into
mainfrom
ma2bd/forward-port-jitter-anchor-fix
Closed

Fix multi-leader jitter target receding instead of anchoring to round start#6484
ma2bd wants to merge 1 commit into
mainfrom
ma2bd/forward-port-jitter-anchor-fix

Conversation

@ma2bd

@ma2bd ma2bd commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Motivation

Forward-port of #6431 (which targeted testnet_conway) to main. The bug it fixes exists on main too.

This is an experimental alternative solution to a full revert as in #6455

On 2026-05-29 several PM market chains froze: each was stuck in a multi-leader round, never committing a block, which crash-looped the workers via the idle-chain liveness probe. Disabling multi-leader jitter on the workers recovered them, pinpointing the jitter path.

Root cause is in multi_leader_jitter_target (linera-core/src/client/chain_client/mod.rs) added by #6338. It anchors the proposal delay to the current time whenever the round start cannot be derived from a round timeout:

  • ChainOwnership::round_timeout(round) returns None for every multi-leader round except the last (linera-base/src/ownership.rs). The affected chains run multi_leader_rounds = 1000, so this is essentially every round.
  • It also falls back to now when proposing in a round different from the manager's current round (the conflict-bump case).

With the anchor at now, propose_at = now + delay is recomputed on every call. On a busy chain process_inbox runs constantly — each inbox notification interrupts the wait and re-evaluates — so the target recedes by delay every time and the non-preferred sole proposer never reaches it. round_for_new_proposal returns WaitForTimeout forever, the worker never proposes, and the chain wedges.

Proposal

When the round start cannot be derived from a timeout, anchor to the time the round was first observed (remembered per round in a new in-memory jitter_round_anchor field) instead of now. Then propose_at is a fixed point the clock catches up to: the worker waits out the jitter delay once and proposes. The round_timeout − duration derivation is unchanged where it already worked (single-leader rounds, final multi-leader round).

The pure timing logic is extracted into a free multi_leader_jitter_target function (the method becomes a thin adapter reading the clock + anchor) so it can be unit-tested.

Backward compatible: this changes only local proposal timing — no wire format, consensus rule, or persisted state changes. Mixed-version clients/validators interoperate.

Test Plan

  • New regression test multi_leader_jitter_target_is_anchored_not_receding: in a non-final multi-leader round, the target stays fixed as the clock advances, and the owner proposes once the clock reaches it.
  • cargo clippy -p linera-core --all-targets clean; cargo +nightly fmt --check clean.

Release Plan

  • Nothing to do / These changes follow the usual release cycle.

Links

@ma2bd ma2bd marked this pull request as draft June 11, 2026 17:32
@ma2bd ma2bd closed this Jun 15, 2026
pull Bot pushed a commit to Spencerx/linera-protocol that referenced this pull request Jun 18, 2026
## Motivation

`main` still runs multi-leader jitter (linera-io#6289, plus the default bump in
linera-io#6359). On `testnet_conway` the jitter variant (linera-io#6338) was reverted in
linera-io#6433 ("We found several issues in the PR") following the 2026-05-29
PM-market incident. This brings `main` in line by backing the feature
out here too.

**Alternatively we could try to fix things with linera-io#6484**

## Proposal

`git revert` of linera-io#6289 ("Multi-leader jitter"). Because `main`'s jitter
is a different commit than the one reverted on `testnet_conway` (linera-io#6338
was the testnet variant), this is a fresh revert rather than a
cherry-pick of linera-io#6433.

Scope is jitter only:
- Removes `multi_leader_jitter_target` (chain client),
`multi_leader_proposal_delay` (ownership), and the
`--multi-leader-jitter` client option.
- **Keeps** the `multi_leader_rounds` default change (linera-io#6359, 2 → 5) —
unrelated to jitter.

One conflict in `chain_client/mod.rs` (the seam where linera-io#6289 inserted the
jitter fn before `clear_pending_proposal`) was resolved by keeping
`main`'s current `clear_pending_proposal` definition.

## Test Plan

- `cargo build` / `cargo check` clean on `linera-base`, `linera-core`,
`linera-client`.
- `cargo clippy --all-targets` clean (no dangling references to removed
jitter symbols anywhere in the tree).
- `cargo test -p linera-base ownership` green.
- CI.

## Release Plan

- These changes follow the usual release cycle. (`testnet_conway`
already reverted the equivalent change.)

## Links

- Reverts: linera-io#6289
- Mirrors the `testnet_conway` revert: linera-io#6433 (which reverted the testnet
variant linera-io#6338)
- [reviewer
checklist](https://github.com/linera-io/linera-protocol/blob/main/CONTRIBUTING.md#reviewer-checklist)
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.

1 participant