Multi-leader jitter#6289
Conversation
In rounds with index >= 1, honest clients now wait a deterministic delay derived from `hash(owner, round) mod round_duration` before re-proposing. The owner with the lowest priority hash proposes immediately. This is a gentle-clients convention to break the per-round collision loop when several clients keep proposing in multi-leader mode; it is not enforced by the protocol. Also extends `round_timeout` to cover all multi-leader rounds with the same formula used for single-leader rounds, since the jitter relies on a configured round duration. The new behavior is gated by `Options::multi_leader_jitter` (true in production, false in `test_default`) so the existing test suite is unaffected.
The new `--disable-multi-leader-jitter` flag lets users opt out of the deterministic per-owner delay that spreads out concurrent multi-leader proposals. Default is enabled, matching the behavior of the chain listener loop in production binaries.
deuszx
left a comment
There was a problem hiding this comment.
Consider adding support to linera web client. Other than that – LGTM
Adds `disableMultiLeaderJitter` to `InitializeOptions` and a matching `LINERA_DISABLE_MULTI_LEADER_JITTER` URL search param, alongside the existing `LINERA_LOG` and `LINERA_PROFILING` overrides. The value set at `initialize` time is stored globally and applied to every `Client::new` in the session.
It's only used internally by `multi_leader_proposal_delay`.
|
This exposes a problem with how we handle |
Retrying an `execute_block` call after a `WaitForTimeout` could pick up the pending proposal that was the user's own previous attempt and return `Conflict` for it. Compare the committed block's operations and authenticated owner against the request instead of using strict block equality (or unconditionally returning `Conflict` for leftover pendings).
| fn classify_committed( | ||
| &self, | ||
| certificate: ConfirmedBlockCertificate, | ||
| operations: &[Operation], |
There was a problem hiding this comment.
@afck This is great. It seems like we're progressing towards a model where we have a number of parallel queues (say operations, bundles, events) feeding new transactions inside blocks and we could start tracking the fate of user operations with callbacks (and support cancelation while in the queue).
It seems very reasonable to index operations by (AuthenticatedOwner, Bytes) by the way (and maybe other data that I'm forgetting that can plausibly affect execution). We could decide that applications are responsible for
- refined tracking of user operations with additional metadata inside the bytes, if needed.
- not depending on transient data like block height (or leaky global state after Implement the execution of the streams, messages and operations in persistent instances over the block. #6032)
Backport of the client-side parts of #6289 ## Motivation If there are conflicting proposals in the first multi-leader round that probably means that several clients are trying to make a proposal at the same time. When they see the conflict, they would currently propose immediately in the next round, and likely cause a conflict again. Sometimes retried proposals are considered "conflicts", even though they match what the user was attempting to do. ## Proposal - Clients randomly delay re-proposing in multi-leader rounds to reduce the chance of conflicting again. Disabled with `--disable-multi-leader-jitter` (or `LINERA_DISABLE_MULTI_LEADER_JITTER` in the web client). - Better distinguish `Committed` vs. `Conflict` outcomes. ## Test Plan A unit test was added for the delay computation. ## Release Plan - Release SDK. ## Links - PR to `main`: #6289 - [reviewer checklist](https://github.com/linera-io/linera-protocol/blob/main/CONTRIBUTING.md#reviewer-checklist)
## 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)
Motivation
If there are conflicting proposals in the first multi-leader round that probably means that several clients are trying to make a proposal at the same time. When they see the conflict, they would currently propose immediately in the next round, and likely cause a conflict again.
Proposal
Wait for a random amount of time instead.
This can be disabled with a CLI option.
Test Plan
A unit test was added for the delay computation. (Happy to add a higher-level case to
client_testsif necessary.)Release Plan
Links