Skip to content

fix: keep SDS causalHistory wire-compatible with pre-SDS-R nodes#86

Merged
Ivansete-status merged 3 commits into
release/v0.4from
v4-wire-compat
Jul 10, 2026
Merged

fix: keep SDS causalHistory wire-compatible with pre-SDS-R nodes#86
Ivansete-status merged 3 commits into
release/v0.4from
v4-wire-compat

Conversation

@Ivansete-status

Copy link
Copy Markdown
Collaborator

Problem

On the v0.4 line, causalHistory (protobuf field 3) is encoded as a repeated embedded HistoryEntry submessage. Pre-SDS-R nodes — v0.2.x, and the release/v0.3 line that status-go ships today — read field 3 as a repeated string of message IDs. Same field number and wire type, so decoding doesn't error; it silently misparses: the old node reads the submessage framing bytes as the ID string, so its causal-history/dependency IDs are garbage that never match real messages. The message is buffered as an unmet dependency and never delivered (0 MESSAGES_NEW).

This is the same regression already fixed on release/v0.3 (nim-sds v0.3.1); this PR ports the fix to the v0.4 / declarative-codec line so v0.4 releases can interoperate with the v0.2.x/v0.3.x nodes live on the network.

Fix (additive, matches release/v0.3)

  • field 3 → repeated string/bytes of message IDs (read correctly by every SDS version)
  • per-entry SDS-R metadata (senderId, retrievalHint) → new additive field 8 (repeated HistoryEntry, keyed by message ID), which older nodes skip as an unknown field
  • field 7 (message senderId) and field 13 (repairRequest) unchanged

New nodes join field 3 + field 8 by message ID; messages from pre-SDS-R nodes carry no field 8 and decode to bare-ID entries.

Field alignment with release/v0.3: both lines now carry the causal-history IDs in field 3 and the rich metadata in field 8 (same HistoryEntry sub-shape {1: id, 2: hint, 3: senderId}), so v0.3.x ↔ v0.4.x interoperate. (Note: nim-sds v0.3.1 currently carries hints in field 7; a companion v0.3.2 moves them to field 8 to match this PR.)

Verification

  • existing suite green (test_reliability incl. SDS-R repair: 67/67)
  • new test_wire_compat.nim: old-decoder-reads-new (the exact break), new round-trip incl. senderId, and new-decodes-legacy — all pass.

🤖 Generated with Claude Code

Ivansete-status and others added 2 commits July 8, 2026 23:41
The declarative codec (nim-protobuf-serialization) encoded causalHistory
(field 3) as a repeated embedded HistoryEntry. Pre-SDS-R nodes (v0.2.x /
v0.3.x, and the release/v0.3 line status-go ships today) read field 3 as a
repeated string of message IDs, so they misparse the embedded submessage
bytes as an ID string, corrupt dependency tracking, and silently never
deliver the message (buffered as an unmet dependency).

Make the SDS-R metadata additive instead, matching release/v0.3:
- field 3 stays a repeated string/bytes of message IDs (read by every SDS
  version);
- the per-entry senderId/retrievalHint move to a new additive field 8
  (repeated HistoryEntry keyed by message ID), which older nodes skip;
- field 7 (message senderId) and field 13 (repairRequest) are unchanged.

New nodes join field 3 + field 8 by message ID; messages from pre-SDS-R
nodes carry no field 8 and decode to bare-ID entries. Adds
test_wire_compat.nim (old-decode-of-new, new round-trip incl. senderId,
new-decode-of-legacy).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The macos-latest runner rotated its Xcode images (16.2 is gone; only 26.x
is available), so the pinned 'xcode-version: 16.2' failed with "Could not
find Xcode version that satisfied version spec". Track 'latest-stable' so
the iOS build follows the runner instead of a version that gets removed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@fcecin fcecin left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@NagyZoltanPeter NagyZoltanPeter left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

The retrieval-hint provider (the Go binding's C.CBytes) allocates the
returned hint with malloc and hands us ownership. onRetrievalHint freed it
with Nim's deallocShared, corrupting Nim's shared-heap allocator and
crashing with a SIGSEGV in deallocBigChunk/avltree.del once wrapOutgoingMessage
starts invoking the provider per causal-history entry. Free it with libc
free instead.

Reproduced end-to-end via the C ABI on the release/v0.3 line (malloc-based
provider + 500 wraps): buggy build segfaults (exit 139), fixed build
completes with ~4900 provider calls.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Ivansete-status
Ivansete-status merged commit 01fdcfc into release/v0.4 Jul 10, 2026
18 checks passed
@Ivansete-status
Ivansete-status deleted the v4-wire-compat branch July 10, 2026 09:25
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.

3 participants