Skip to content

feat: chunks convergence - #5557

Merged
sbackend123 merged 18 commits into
feat/pullsync-chunk-sumfrom
feat/pullsync-soc-convergence
Aug 13, 2026
Merged

feat: chunks convergence#5557
sbackend123 merged 18 commits into
feat/pullsync-chunk-sumfrom
feat/pullsync-soc-convergence

Conversation

@sbackend123

@sbackend123 sbackend123 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Checklist

  • I have read the coding guide.
  • My change requires a documentation update, and I have done it.
  • I have added tests to cover my changes.
  • I have filled out the description and linked the related issues.

Description

This PR makes neighborhoods converge on one chunk when several valid conflicting CAC/SOC variants race through push/pull sync. Nodes no longer keep “whatever arrived first”: the reserve applies conflict rules, rejects "losers", and re-announces winners so peers that already synced past the old entry still see the resolution.

Conflicts:
Same batch + stamp index, newer timestamp -> Newer wins (any chunk type)
Same batch + stamp index + timestamp, different addresses -> Lexicographically lower address wins
Same SOC address + identical stamp, different wrapped payloads -> Lexicographically lower wrapped CAC wins

Additionally PR implements refactoring on Put method. Motivation: Put method had grown into a single, multi-screen function that mixed every write / overwrite / conflict path in one place, including behavior that branched on chunk type (CAC vs SOC). That made the control flow hard to reason about and easy to get wrong when adding a new case.

Open API Spec Version Changes (if applicable)

Motivation and Context (Optional)

Related Issue (Optional)

Screenshots (if appropriate):

AI Disclosure

  • This PR contains code that has been generated by an LLM.
  • I have reviewed the AI generated code thoroughly.
  • I possess the technical expertise to responsibly review the code generated in this PR.

martinconic and others added 15 commits July 20, 2026 22:46
Two valid single owner chunks can share an address, batch and stamp while
wrapping different content. The stamp signs the chunk address, so both carry
an identical stamp and produce an identical stamp hash. The content-blind
existence check at the top of reserve.Put therefore treated the second chunk
as already stored and dropped it, leaving each node holding whichever chunk
reached it first. Neighborhoods never converged, and the reserve sampler
computed different commitments from the same address.

Make the check content-aware via the pullsync sum, and settle the divergence
here rather than in the protocol: the chunk wrapping the lower CAC address
wins. The rule depends only on the two payloads, so every node reaches the
same answer regardless of arrival order.

On a win the chunk is replaced in place, reusing the stamp index and stamp
entries, which are identical for both. The bin ID is bumped so peers that
already synced past the old one are offered the replacement. The reserve size
is unchanged: one chunk goes in, one comes out.

Pullsync treats a lost tie-break as an expected outcome rather than a sync
error, since the node already holds the chunk the neighborhood converges on.

Divergent chunks under different batches are not covered: they occupy
different stamp indices, so no tie-break fires.
Two valid single owner chunks can share an address, batch and stamp while
wrapping different content. The stamp signs the chunk address, so both carry
an identical stamp and produce an identical stamp hash. The content-blind
existence check at the top of reserve.Put therefore treated the second chunk
as already stored and dropped it, leaving each node holding whichever chunk
reached it first. Neighborhoods never converged, and the reserve sampler
computed different commitments from the same address.

Make the check content-aware via the pullsync sum, and settle the divergence
here rather than in the protocol: the chunk wrapping the lower CAC address
wins. The rule depends only on the two payloads, so every node reaches the
same answer regardless of arrival order.

On a win the chunk is replaced in place, reusing the stamp index and stamp
entries, which are identical for both. The bin ID is bumped so peers that
already synced past the old one are offered the replacement. The reserve size
is unchanged: one chunk goes in, one comes out.

Pullsync treats a lost tie-break as an expected outcome rather than a sync
error, since the node already holds the chunk the neighborhood converges on.

Divergent chunks under different batches are not covered: they occupy
different stamp indices, so no tie-break fires.
…nto feat/pullsync-soc-convergence

# Conflicts:
#	pkg/storage/storage_test.go
#	pkg/storer/internal/reserve/reserve.go
#	pkg/storer/internal/reserve/reserve_test.go
…SWIP-101)

Different nodes receive the same chunks in different orders, so for any
set of conflicting chunks every arrival order must leave the reserve in
the same final state; an order-dependent outcome means neighborhoods
that can never agree. The harness drives conflict sets through every
permutation against a fresh reserve and compares canonical state
fingerprints (bin IDs excluded: they are order-dependent by design),
asserting the sum index invariants on every run as a side effect.

Converging on this branch: the equal-timestamp CAC tie-break, the
identical-stamp divergent SOC resolution and timestamp ordering.

Five constellations are order-dependent, all falling through the same
gap: at equal stamp timestamps the tie-break fires only for a content
addressed incoming chunk with a different address, and every other case
drops into an unconditional replace. These are marked unresolved in the
case table: they log the divergence without failing the suite, and
setting RESERVE_STRICT_CONVERGENCE=1 turns them into failures, which
gives the reserve.Put refactor a concrete target. A case marked
unresolved that starts converging fails loudly so the marker is removed
and the table stays honest.

Testing methodology and findings are documented alongside the refactor
notes for reuse.
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Akrem Chabchoub <121046693+akrem-chabchoub@users.noreply.github.com>
Co-authored-by: Not Darko <93942788+darkobas2@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Ljubiša Gačević <35105035+gacevicljubisa@users.noreply.github.com>
Co-authored-by: Janoš Guljaš <janos@users.noreply.github.com>
Co-authored-by: acud <12988138+acud@users.noreply.github.com>
Co-authored-by: sbackend <sofia.sakharova@ethswarm.org>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…nto feat/pullsync-soc-convergence

# Conflicts:
#	pkg/storer/internal/reserve/reserve.go
@sbackend123 sbackend123 changed the title feat: pullsync soc convergence feat: chunks convergence Aug 11, 2026
@sbackend123
sbackend123 marked this pull request as ready for review August 13, 2026 10:34
@sbackend123
sbackend123 merged commit 1fcfef4 into feat/pullsync-chunk-sum Aug 13, 2026
12 of 13 checks passed
@sbackend123
sbackend123 deleted the feat/pullsync-soc-convergence branch August 13, 2026 10:34
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