Skip to content

Bulk synchronization: v2 protocol primitives and Block Chain Synchronization ZIP - #1346

Open
arya2 wants to merge 14 commits into
agent/zip-204-quic-transportfrom
agent/checkpointed-sync-zip
Open

Bulk synchronization: v2 protocol primitives and Block Chain Synchronization ZIP#1346
arya2 wants to merge 14 commits into
agent/zip-204-quic-transportfrom
agent/checkpointed-sync-zip

Conversation

@arya2

@arya2 arya2 commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Recommends how nodes synchronize over the version 2 P2P protocol. The v2 protocol draft (#1344) now defines the primitives (get-headers/get-blocks/get-hashes) and the normative synchronization rules for both headers-first and checkpointed synchronization; this ZIP recommends concrete strategies satisfying those rules:

  • Headers-first synchronization (the baseline full-validation method).
  • Checkpointed synchronization: verify checkpoint-spaced get-hashes responses against a local trusted commitment (e.g. compiled-in hash chunk hashes), fetch stride-1 hashes as download handles, and hash-chain each downloaded range to its verified checkpoints.

Plus strategy selection and peer-diversity recommendations, degrading gracefully to headers-first when get-hashes is unavailable.

Stacked on #1344, which it references.

🤖 Generated with Claude Code

https://claude.ai/code/session_01C36xn69yRXtupScMCYarca

@arya2
arya2 force-pushed the agent/checkpointed-sync-zip branch 3 times, most recently from 8c07e78 to a867274 Compare August 6, 2026 22:09
@arya2 arya2 changed the title Add draft ZIP: Block Chain Synchronization Bulk synchronization: v2 protocol primitives and Block Chain Synchronization ZIP Aug 6, 2026
@arya2
arya2 force-pushed the agent/checkpointed-sync-zip branch from ae76452 to 62c49e7 Compare August 17, 2026 20:12
@arya2
arya2 force-pushed the agent/checkpointed-sync-zip branch from c593c65 to 0d723b9 Compare August 17, 2026 22:23
arya2 and others added 14 commits August 17, 2026 18:23
Recommends how nodes synchronize over the version 2 P2P protocol,
which defines the primitives (get-headers/get-blocks/get-hashes) and
the normative synchronization rules. This ZIP recommends two concrete
strategies satisfying those rules:

- Headers-first synchronization (the baseline full-validation method).
- Checkpointed synchronization: verify checkpoint-spaced get-hashes
  responses against a local trusted commitment (e.g. compiled-in hash
  chunk hashes), fetch stride-1 hashes as download handles, and
  hash-chain each downloaded range to its verified checkpoints.

Plus strategy selection and peer-diversity recommendations, with
graceful degradation to headers-first when get-hashes is unavailable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C36xn69yRXtupScMCYarca
Research-driven redesign removing the legacy-protocol assumptions the
IBD design was built around:

v2 P2P ZIP:
- get-block-range (0x07): anchored, descending block streaming — every
  block verified on arrival against a committed anchor; resumable
  truncation; kills per-hash download handles and request round trips.
- get-tree-roots (0x08): per-block note commitment tree roots +
  history-tree leaf data + auth data roots, verified against header
  commitments (ZIP 221/244) — eliminates the ~70%-of-commit-CPU tree
  recomputation with zero added trust.
- get-object (0x09): ranged fetch of content-addressed sync artifacts
  (known-hash chunks, snapshot pieces) with SHA-256 verification.
- Service flags: NODE_TREE_ROOTS, NODE_SYNC_ARTIFACTS,
  NODE_NETWORK_LIMITED (≥2,304 recent blocks) with advertisement rules
  for snapshot-synced and pruned nodes.
- Bulk transfer performance guidance (BDP-sized flow control windows,
  paced congestion control, UDP offload, per-connection core bound).
- Scope ZIP 204 download parameters to headers-first; bulk transfer is
  byte-budgeted per the sync ZIP.

Sync ZIP:
- Checkpointed synchronization rebuilt on verified known-hash chunk
  artifacts + byte-sized get-block-range work units.
- Verified Tree Roots strategy (header-commitment verification
  procedure, one-block-lag history tree rebuild).
- Snapshot Synchronization: manifest + pieces, chain-verifiable tree
  components, assumeutxo-model trust for uncommitted state, background
  backfill, service flag transitions.
- Download Scheduling: 16-64 MiB units, EWMA per-peer budgets, 4-8
  peer concurrency, byte-bounded lookahead, dual stall detection,
  end-game duplication, exact blame.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C36xn69yRXtupScMCYarca
- get-block-range: add a max_bytes request bound (cap 64 MiB) so work
  units are sized in bytes, not blocks — count alone was meaningless
  across eras whose block sizes differ by three orders of magnitude,
  and byte truncation self-chunks spans even without size metadata.
  Make the header-to-body binding (transaction merkle root) an
  explicit on-arrival check.
- Sync ZIP: new Spentness Hints strategy adapted from SwiftSync:
  salted-aggregate, lookup-free, order-independent state construction.
  Transparent outputs use a 1-bit-per-output hint artifact; nullifier
  sets need no hint (snapshot sets serve as the hint during backfill,
  proving set equality and distinctness); value pools come from
  commutative sums. Hint-verified backfill discharges the trust in the
  snapshot's uncommitted components. Wrong hints fail sync; they can
  never cause acceptance of incorrect state. No new wire messages —
  hints are content-addressed artifacts over get-object.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C36xn69yRXtupScMCYarca
…tacks

Adversarial review of the misbehavior rules found places where penalties
prescribed for security could be turned against honest nodes. Fixes:

- Scope the wrong-reference-type penalty to senders that hold the
  transaction (announcements, get-mempool records); wrong-typed get-tx
  requests get a not-found result and MUST NOT be penalized, since a
  requester can have derived the type from another peer's data.
- get-object: penalize a content-hash failure only when one peer
  delivered every byte; forbid penalizing multi-peer assemblies and
  specify re-fetch-whole-from-one-peer to isolate the liar. Make
  overdelivery a FLOOD connection error.
- Constrain the open-ended validation-failure penalty to provable,
  context-free invalidity, with explicit exemptions: expiry races, local
  policy, missing/moved state, content of requested objects, and
  transactions served under the block-reconstruction obligation.
- Anchor get-tree-roots requests with a final_hash field so entries
  describe requester-identified blocks; divergent responders refuse with
  REFUSED instead of eating a 100-point penalty for honest disagreement.
- Key misbehavior scores by address with persistence, so deferred
  penalties (span hints, tree roots) survive reconnection whitewashing.
- Add a governing principle: no penalty unless the violation is provable
  independent of local chain view, mempool, clock, and policy.
- Specify handling for nonconforming announcement records, get-block-range
  overdelivery, and oversized get-headers/get-addr responses; extend the
  pre-validation exemption to substituted header announcements and served
  transactions; clarify whitelist scope and ban address granularity.
- Sync draft: align exact-blame and security-claim wording with the
  attribution rules; anchor tree-root requests at authenticated hashes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fourteen verified findings from a security review of the two draft ZIPs.

Verification correctness:

- Tree-root verification used hashFinalSaplingRoot as the Sapling root
  "between Sapling and NU5", but ZIP 221 repurposes that field from
  Heartwood. Split the procedure at Heartwood and state that comparing a
  Sapling root against that field above Heartwood would penalize every
  honest responder.
- Roots that no header commits to (Ironwood at every height, and the
  highest entry of each response, which reconstruction has not yet
  reached) were adopted unverified; they are now never adopted. Align the
  pre-activation sentinel with the p2p ZIP's 32 zero bytes.
- get-block-range's arrival checks do not bind v5 authorizing data, so
  "accepts no unverified bytes" was false from NU5. Correct the claim,
  bound block size, and require the auth-data check before a block is
  stored, served, or used to regenerate artifacts.

Snapshot trust:

- Hint-verified backfill did not discharge what it claimed: the
  transparent aggregate hashed outpoints only, and the Sprout tree and
  value pool balances were checked by nothing. Reconcile whole UTXO
  entries, recompute the Sprout tree and pool balances, and scope the
  discharge claim to what is actually compared.
- Require the trusted commitment to reach H+1, since the chain history
  tree at H is committed by the following block's header.

Spentness hints:

- Specify the construction (keyed BLAKE2b-256, 32-byte CSPRNG salt,
  per-aggregate personalization, 256-bit modular accumulator). A
  non-PRF or a machine-word accumulator defeats the "failure, not
  fraud" guarantee.
- Scope order-independence to the state construction: ZIP 209's
  per-block non-negative pool balance rule and the maturity rules are
  not functions of the terminal totals. Require checked arithmetic for
  value sums.

Bounds and allocation:

- Bound the Tor preamble's network string and flow-control fields, which
  are parsed before every existing limit; make the handshake timeout run
  from transport establishment so it covers them.
- Bound get-object's offset and specify the evaluation order, so the
  natural min(offset+length, size) clamp cannot underflow into a huge
  read; reject a size below the bytes already received.
- Bound compact-block ids_count and prefilled_count individually as well
  as their sum, and bound prefilled indexes by the block's own
  transaction count rather than by 65535.
- Bound get-headers ids_count, which the record payload limit does not
  reach because ids is a fixed-width array.
- Add a protocol-wide rule against allocating from a declared count.

Attribution and amplification:

- Require get-blocks and get-tx responses to match the request; give
  both a responder byte budget, since count limits do not bound bytes.
- Restrict the span-metadata penalty to hash-determined fields:
  span_size is not fixed by a block's hash, so a padding attacker could
  make the penalty fall on the honest hint-serving peer.
- Add misbehavior rows for auth-data and artifact-hash failures.
- Validate the addrv2 time field, the freshness signal peer selection
  ranks on, which was attacker-suppliable and unclamped.

Also: rate-limit get-mempool and gate it on relay; align the
reorganization margin across both documents; de-duplicate two colliding
"Example (non-normative)" anchors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace restated definitions with references to their canonical homes:
- ZIP 204 owns CompactSize/strings/integers, default ports, service-flag
  bit numbering and reserved bits, and TX_EXPIRING_SOON_THRESHOLD
- BIP 152 owns the short-ID algorithm and prefilled index encoding;
  only the Zcash-specific substitutions remain
- The v2 protocol draft owns get-block-range delivery/resumption rules,
  the service-flag advertisement rule (and 2,304 constant), the
  get-object per-request maximum, and the trusted-commitment/artifact/
  anchor definitions the sync draft previously restated
- The misbehavior table is now the single registry of penalty points;
  inline sites cross-reference it
- Drop repeated intra-document statements (self-connection nonce,
  init-field immutability, failure-not-fraud, re-anchoring mechanics)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Pad the example nullifier-pool personalization string to the mandated
  16 bytes.
- 'Header field at offset 4' read as a byte offset; say 'fourth header
  field'.
- The false-zero probability of 2^-32 describes a 32-bit accumulator,
  not any machine word.
- The v2 protocol has no named 'resumption rule'; describe the
  get-block-range truncation behavior instead.
- Drop get-tx from the imported terminology; nothing in this ZIP
  concerns transaction relay.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The compiled-in commitment is only the expected hashes of the list's
chunks over fixed height ranges; the full known-hash list is obtained
verifiably from the P2P network with get-hashes, with get-object
artifacts, bundling, and mirrors as alternative sources of the same
bytes rather than the primary path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Spentness hints become per-range hint chunks bound by the same trusted
  commitment as the known-hash list, verified against pinned per-range
  hashes; entry-chunk hashes stay stable as coverage extends, hint-chunk
  hashes change with the terminal height.
- Confine hints to the reach of the trusted commitment, dropping the
  per-spent-output creation-height/coinbase-flag artifact extension that
  only the above-commitment mode needed.
- Drop the nullifier distinctness checks: double-reveal below the final
  checkpoint is excluded by the commitment, and the aggregate's multiset
  equality transfers distinctness to the snapshot set.
- Stop carrying the transparent pool balance in the snapshot (it is the
  sum of the UTXO set's amounts) and drop its backfill comparison, which
  the whole-entry UTXO check already implies; the shielded pool balances
  remain in the manifest, needed for ZIP 209 enforcement above H.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…unks

Per-range hint hashes bought no stability: extending the commitment's
coverage changes every hint hash anyway, since the bits are relative to
the final checkpoint height. Bind all hints up to the final checkpoint
under a single SHA-256 hash, fetched and verified whole, and keep the
per-range hashes for the entry chunks alone, whose hashes never change
as coverage extends.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The node needs them — the transparent pool balance included — as the
starting point for the pool-balance consensus rules when it validates
above H, so they stay in the manifest and in the backfill
reconciliation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reflects zebra/docs/design-swiftsync-hints.md decisions:

- Normative table of aggregates, item encodings (36-byte outpoint,
  32-byte nullifier), and 16-byte personalization strings, replacing
  the examples.
- Verify the hint bitmap upfront — hash, and bit count against the
  entry chunks' txouts metadata (added to get-hashes in the v2 draft) —
  before any body download; recovery keeps the verified known-hash list
  and header chain and re-downloads bodies without hints.
- Genesis-anchored sync drops the nullifier aggregates entirely:
  inserts are sequential writes, and double-reveal is excluded by the
  commitment.
- Older commitments stay valid for their shorter span.
- Optional frontier artifacts at the final checkpoint, verified against
  header-authenticated roots (Ironwood excepted), so verified tree
  roots can hand off to full validation without replaying leaves.
- Deployment: purely in-band distribution is possible given
  NODE_SYNC_ARTIFACTS seeders; bundling and mirrors become MAY.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The commitment's pinned hash, updated by each release that updates the
checkpoints, is the whole verification story: the bitmap stands or
falls with the commitment itself, exactly as the checkpoint hashes do,
and is auditable the same way, being a deterministic function of the
chain. Remove the salt, the keyed-hash aggregates, the personalization
table, and every zero-check; the snapshot backfill reconciliation
becomes a direct whole-entry comparison of the reconstructed and
snapshot sets, and backfill proceeds without transparent hints (the
bits are relative to the final checkpoint, not H).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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