paritytech / paritytech/web3-storage

`CommitmentCollection::agreeing_providers` conflates root-agreement with checkpoint signers

Open
#332 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
12
Forks
3
Avg merge
2d 2h
Merged PRs (30d)
33

Description

Introduced by Illia's comment in #318

Summary

CommitmentCollection exposes two fields that read like the same set but no longer are:

  • signatures - the providers whose signature actually goes into the on-chain checkpoint call
  • agreeing_providers - every provider that reported the majority MMR root, including those whose signature was dropped by payload grouping

Until payload grouping was introduced (modal_payload_group, clients/storage/src/checkpoint.rs:1177-1201), signatures was derived 1:1 from the agreeing set, so the two were always the same providers and every consumer could read either one interchangeably. That invariant is now gone, but the field name, the type, and the consumers were not updated - the only thing distinguishing the two sets is a doc comment.

Why the sets can diverge

Same root does not imply same committed range. Providers can agree on mmr_root while disagreeing on (start_seq, leaf_count), and the pallet verifies every submitted signature against a single encoded (bucket_id, commitment, nonce) payload - so only one payload group can be submitted. collect_commitments groups by root first, then picks the modal payload group within it, and drops the rest (with a tracing::warn!).

Worked example - providers A, B, C, D all report the same mmr_root; A, B, C report (start_seq=0, leaf_count=100), D reports (0, 120):

agreeing_providers = [A, B, C, D]        // everyone who matched the root
signatures         = [(A,..), (B,..), (C,..)]  // what's actually in the checkpoint

D is in the first list but not the second. D carries no on-chain liability for that snapshot, yet reads as having backed it.

Impact

submit_checkpoint gets this right - it thresholds on signatures.len() and derives signers from signatures (checkpoint.rs:1433-1447). The happy path is correct.

The problem is the public struct: CommitmentCollection is re-exported from storage_client, so persistence, health tracking, monitoring, dashboards, and any external consumer that reads agreeing_providers as "who backed this checkpoint" is silently wrong.

There is already one such consumer in-tree. analyze_conflicts (checkpoint.rs:1590-1662) computes both its consensus decision and its reported count from agreeing_providers:

let majority_percentage =
    collection.agreeing_providers.len() as f64 / total_providers as f64 * 100.0;

let resolution = if majority_percentage >= self.config.consensus_threshold_percent as f64 {
    ConflictResolution::ProceedWithMajority

With the default 51% threshold and four providers - A, B on root R payload P1; C on root R payload P2; D on root R':

value
agreeing_providers [A, B, C] (3)
signatures [A, B] (2)
disagreeing_providers [(D, R')] (1)
total_providers 4, required = ceil(4 * 0.51) = 3
submit_checkpoint InsufficientConsensus { agreeing: 2, required: 3 } - correct
analyze_conflicts ProceedWithMajority, majority_count: 3 - wrong

So collect_commitments_with_conflicts hands the caller a recommendation to proceed on a collection that cannot meet the submission threshold, and a majority_count that overstates coverage by the number of dropped providers. majority_count is also what gets serialized into PersistedConflict (clients/storage/src/checkpoint_persistence.rs:299), so the overcount outlives the process.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in clients/storage/src/checkpoint.rs, especially collect_commitments, analyze_conflicts, and submit_checkpoint, then inspect the CommitmentCollection definition and clients/storage/src/checkpoint_persistence.rs:299. Trace how agreeing_providers and signatures are used; done means conflict analysis and persisted majority_count reflect providers whose signatures can actually be submitted and do not recommend proceeding below the submission threshold.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
distributed-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.