Skip to content

Add draft ZIP: Version 2 Zcash P2P Network Protocol - #1344

Open
arya2 wants to merge 18 commits into
mainfrom
agent/zip-204-quic-transport
Open

Add draft ZIP: Version 2 Zcash P2P Network Protocol#1344
arya2 wants to merge 18 commits into
mainfrom
agent/zip-204-quic-transport

Conversation

@arya2

@arya2 arya2 commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

A successor to the protocol specified in ZIP 204, replacing the Bitcoin-inherited TCP message-passing architecture with a transport-neutral stream layer realized by QUIC, anticipating a Nym mixnet transport used in parallel (QUIC for latency-critical relay and sync, Nym for anonymity-critical traffic such as transaction origination).

Adds zips/draft-arya-jvff-p2p-quic-transport.rst (new draft ZIP, 1714 lines).

@arya2
arya2 requested a review from ValarDragon August 4, 2026 20:11
Comment thread zips/draft-arya-jvff-p2p-quic-transport.md Outdated
The QUIC transport uses QUIC version 1 [^rfc9000] over UDP, secured with
TLS 1.3 [^rfc8446] as specified by RFC 9001 [^rfc9001].

- A node MUST NOT use 0-RTT (early data). Requests carried in 0-RTT data are

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What SHOULD/MUST you do if your peer tries to use 0-RTT? Suggestion: MUST drop the connection.

Comment thread zips/draft-arya-jvff-p2p-quic-transport.md
Comment thread zips/draft-arya-jvff-p2p-quic-transport.md Outdated

@arya2 arya2 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This draft should also include a Tor profile

Comment thread zips/draft-arya-jvff-p2p-quic-transport.md Outdated
| Size | Field | Description |
|--------|-----------|-----------------------------------------------------------------------------------------------------------------|
| varies | `count` | Number of entries (CompactSize). |
| varies | `entries` | `count` entries, each a 1-byte requested format (`0x00` full block, `0x01` compact block) followed by a 32-byte block hash. |

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

we don't need to decide between full or compact blocks here, always return full blocks, add coinbase transaction and transaction ids to getheaders response instead

Comment on lines +1019 to +1021
Requests references to the contents of the peer's transaction memory pool;
the requester may then fetch transactions of interest with `get-tx`. A node
MAY decline to serve `get-mempool` by resetting its sending direction of the

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Unclear if this is meant to be a snapshot or a subscription, but it should be a subscription

Comment on lines +1080 to +1085
### Address Announcements

Stream type: `0x12`

Each record payload on an address announcement stream is a single network
address record (see [Network Address Record](#networkaddressrecord)).

@arya2 arya2 Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This may pose a address book takeover risk (look at IP segmentation)

mechanisms.


## Misbehavior and Banning

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This needs to be re-written, it can be more concise in describing the concept and more verbose in explaining how it should work.

| Size | Field | Description |
|--------|-------------|--------------------------------------------------------------------------|
| varies | `count` | Number of address records (CompactSize). |
| varies | `addresses` | `count` network address records (see [Network Address Record](#networkaddressrecord)). |

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

add information about peer services to the response format

@arya2 arya2 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Look into:

  • Random linear network code
  • Raptor code
  • Solana Shreds + Flashblocks
  • DAG sync

Comment thread zips/draft-arya-jvff-p2p-quic-transport.md Outdated
Comment on lines +411 to +415
| varies | `network` | Network identifier string (CompactSize-prefixed; see below). |
| varies | `initial_max_data` | Initial connection-level flow control credit in bytes (CompactSize). |
| varies | `initial_max_stream_data` | Initial per-stream flow control credit in bytes (CompactSize). |
| varies | `initial_max_streams_bidi` | Initial limit on the peer's concurrent bidirectional streams (CompactSize). |
| varies | `initial_max_streams_uni` | Initial limit on the peer's concurrent unidirectional streams (CompactSize). |

@daira daira Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

General comments about length leakage attacks — that is, attacks that infer information about plaintext from encrypted packet sizes.

QUIC

QUIC doesn't pad application data by default. It has PADDING frames which are one-byte frames (QUIC uses a prefix-free lengthless frame encoding) that can be used to extend any packet to a fixed length. However, an application would need to use that mechanism explicitly. If it doesn't, then it leaks the total length of the variable-length integer encodings. If it does, then any bandwidth benefit of using variable-length encodings is lost.

So what I would suggest is to look at all of the small application message types (requests without any attached data), and make all of those message formats a fixed length, so that they become indistinguishable once encrypted. For compatibility with Tor, that length should be at most the Tor cell body length, i.e. ≤ 509 bytes. The easiest way to do this is to use fixed-length integer encodings — that way the number of padding bytes is fixed for each message type, and there will be no way to misimplement it so that it leaks length information for those types but still interoperates. Optionally you could allow several small messages to be encoded within a larger fixed-size cell, but I'm not sure that's worth the hassle.

Note that this doesn't address information leakage from the lengths of larger messages; you could add padding for those but I'm not sure it would help as much.

Tor

Tor pads application data to the cell body length of 509 bytes. So the leakage in that case is granular, and would only be visible to an adversary if several messages are concatenated to a size that either fits or does not fit in a cell body. In any case, what I suggested above would be harmless for Tor and could reduce that remaining leakage.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

daira
daira previously approved these changes Aug 12, 2026

@daira daira left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Consider whether to address the short-message length leakage issue. Otherwise ACK.

Comment thread zips/draft-arya-jvff-p2p-quic-transport.md Outdated
arya2 and others added 11 commits August 12, 2026 16:34
A successor to the protocol specified in ZIP 204, replacing the
Bitcoin-inherited TCP message-passing architecture with a
transport-neutral stream layer realized by QUIC, anticipating a Nym
mixnet transport used in parallel (QUIC for latency-critical relay
and sync, Nym for anonymity-critical traffic such as transaction
origination).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Convert draft-arya-jvff-p2p-quic-transport from reStructuredText to
MultiMarkdown, and improve the specification:

- Define a stream "refuse" operation so rejecting unidirectional streams
  is expressible (a receiver cannot reset a peer's stream).
- Exempt compact block announcements with valid headers from misbehavior
  penalties, since high-bandwidth mode permits relay before full
  validation.
- Permit header announcements regardless of the announce preference, and
  fall back to them when a compact block exceeds the record size limit.
- Bound compact block transaction counts (ids_count + prefilled_count
  <= 65,536, matching the prefill index space).
- Specify get-headers behavior for empty and unmatched locators, and
  allow empty responses.
- Define "connection error", reserve stream type ranges, and make
  malformed requests/responses and unknown result values explicit
  PROTOCOL_ERRORs.
- Allow the responder to send its init record immediately, and
  responders to serve requests before the requester's FIN.
- Require accepting both certificate encodings and key types; note the
  linkability cost of connection migration.
- Restrict get-addr requests to outbound connections, matching the
  answering rule.
- Prefer persisted addresses over DNS seeding in peer discovery; note
  that address self-discovery is out of scope.
- Ignore and preserve unrecognized service bits.
- Add a Security and Privacy Considerations section and a dual-stack
  transition paragraph to Deployment.
- Add a Serialized Blocks section: the protocol spec deliberately leaves
  whole-block encoding to the P2P protocol, and the previously cited
  "Section 7.6: Block Encoding" (#blockencoding) never existed in any
  spec release.
- Update protocol spec citations to Version 2026.8.0 [NU6.3], including
  the renumbered Section 7.6: Block Header Encoding and Consensus.
- Add requester/responder terminology and clarify the legacy protocol
  version number.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Frame the protocol over an arbitrary transport providing a secure
  channel and peer/network identification, per review discussion.
- Add a Tor transport: v3 onion services, in-band network preamble,
  and a QUIC-modeled stream framing layer over the Tor bytestream.
- 0-RTT: responders MUST NOT accept early data; attempted use MUST
  close the connection.
- Clarify that a retried request starts a new stream whose first byte
  is again the stream type.
- Deduplicate protocol version tables and assignment procedure against
  ZIP 204; state that protocol versions share the legacy numbering
  space.
- get-blocks always returns full blocks; get-headers optionally
  carries each block's coinbase transaction and full transaction IDs
  (tx_ids=1), replacing requestable compact blocks in low-bandwidth
  relay.
- Make get-mempool a subscription (snapshot plus ongoing updates).
- Add Address Book Management: IP-range bucketing, source-group
  segmentation, and overlay-address caution against address book
  takeover.
- Rewrite Misbehavior and Banning: concise concept, detailed
  mechanics, and ban semantics per transport.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C36xn69yRXtupScMCYarca
Moves the wire-level get-hashes primitive (best-chain block hashes at
a requested height stride) into the protocol ZIP, supporting the
checkpoint-based synchronization strategies recommended by the
companion block chain synchronization draft. Headers-first becomes the
baseline (rather than only) synchronization method.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C36xn69yRXtupScMCYarca
Adds normative rules and security considerations for synchronization:
headers-first (eager header/PoW validation, headers as scheduling
inputs only, cross-peer chain comparison, no penalties for divergent
views) and checkpointed synchronization (validated advancement,
untrusted-input handling, reorganization margin, headers-first
fallback), with trusted commitments defined but their scheme left
local to the node. Concrete strategies remain in the companion block
chain synchronization draft.

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

Extends the review pattern of citing ZIP 204 by section: DNS seed
lists, connection limits, block download parameters, trickling/mempool
policy, address relay reference values, ban thresholds, and ZIP 201
peer preference are now references instead of copies. The addrv2
record encoding collapses to a ZIP 155 citation, keeping only the
per-transport port interpretation and reachability notes. Also removes
internal duplication (Motivation vs Changes list, the transport
complementarity story, ZIP 239 relay rule stated four times, Network
Upgrade Peer Management vs Epoch Enforcement) and trims rationale
prose from normative sections. Net -239 lines with no normative wire
format removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C36xn69yRXtupScMCYarca
- Add a bottom-up roadmap paragraph at the top of the Specification.
- Promote synchronization (headers-first, checkpointed rules, download
  parameters) out of Block Relay into its own top-level section, so
  block propagation and chain synchronization are separate concerns.
- Link the stream types table entries to their sections, making it an
  index.
- Add short non-normative example flows: connection establishment, and
  block relay in high- and low-bandwidth modes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C36xn69yRXtupScMCYarca
Each entry now carries span metadata alongside the block hash: a
quantized size (unit ceil(MAX_BLOCK_SIZE/255) = 7,844 bytes, matching
the deployed Zebra known-hash asset hint format), transaction count,
and note-commitment count, aggregated over the stride-long span ending
at the entry. Stride 1 gives per-block values; checkpoint-spaced
strides give per-chunk totals for byte- and cost-balanced download
scheduling. Hints are deterministic functions of the identified
blocks, so post-download mismatches are provable and penalized.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C36xn69yRXtupScMCYarca
Brings in the security-review fixes, misbehavior-attribution hardening,
and deduplication pass applied on agent/checkpointed-sync-zip, so this
PR reflects the current text of the draft.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per review: state directly that a peer attempting 0-RTT MUST have its
connection closed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drops the 7,844-byte size-value unit in favor of plain byte counts.
The unit existed to compress checkpoint data distributed through
crates.io, which is not a constraint on the P2P protocol, and tying
the encoding to the maximum block size was a forward-compatibility
footgun for a future block size change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
arya2 and others added 5 commits August 12, 2026 16:34
Per review: stride is unneeded. Each entry now describes a single
block (hash, size, txs, notes); a requester needing coarser
granularity aggregates the per-block values itself.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per review: make explicit that each address record carries last-known
service flags, how a responder populates them, and that they are an
unauthenticated selection hint until confirmed by the peer's own init
record.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per review: requests whose fields are position-fixed (get-hashes,
get-block-range, get-tree-roots, get-object) now use fixed-length
integer encodings instead of CompactSize, so each request type has a
single wire length below the Tor cell body size and its encrypted size
reveals at most the stream type. Adds a Length Leakage discussion to
the security considerations covering QUIC PADDING, Tor cell
granularity, and the remaining leakage from list-carrying requests and
responses.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Node implementers SHOULD carry mempool transaction propagation and
address book queries over a mixnet transport once available, and over
Tor in the interim.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@arya2
arya2 force-pushed the agent/zip-204-quic-transport branch from c4ab11e to 155d838 Compare August 12, 2026 20:34
@arya2

arya2 commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator Author

@daira I think this is ready to merge as a first draft

Verified against a trusted commitment, cumulative txouts values give
each block's bit offsets within the spentness-hint bitmap of the sync
draft, letting a synchronizing node check the bitmap's length before
downloading bodies and letting parallel work units index the bitmap
without processing the blocks below them.

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is still a CompactSize.

@arya2 arya2 Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Updated to be fixed length in 65ec4f7.

oxarbitrage added a commit to oxarbitrage/zcash-p2p-spec that referenced this pull request Aug 23, 2026
…eams

Phase 1 of the TLA+ model of the draft "Version 2 Zcash P2P Network
Protocol" (zcash/zips#1344, pinned at a3f4fa2a), which cites this repo as
its formal model. Lives in v2/; the legacy ZIP-204 model is unchanged.

- v2/streams.tla: one FIFO per stream instead of one inbox per connection,
  so QUIC's "streams are mutually independent" is modeled as free reordering
  across streams; FIN is a queue sentinel, RESET_STREAM/STOP_SENDING are
  flags that can overtake data; slots are reused once both sides close.
- v2/records.tla: init and header-announcement records.
- v2/protocol.tla: connection setup, init handshake with min-version
  negotiation and OBSOLETE, block announcement streams with the
  one-per-type rule and sender-initiated replacement. Two switches select
  the receiver's reading of the draft: StrictSingleton, RefusePreHandshake.

Finding: under the literal reading of "Announcement Streams", a sender that
finishes or resets its announcement stream and opens the replacement the
draft allows is disconnected with PROTOCOL_ERROR whenever the receiver
consumes the replacement's type byte before the old stream's FIN or reset.
protocol_strict.cfg reproduces it as a 12-state violation of
NoHonestProtocolError; protocol.cfg / protocol_refuse.cfg /
protocol_obsolete.cfg verify completely under the tolerant reading.
Zebra's draft implementation applies the strict check on receive.

CI runs the four 2-peer configs (strict as a must-fail) and a bounded
3-peer symmetry run; the PDF workflow now also covers sync_scheduler.tla
and the v2 modules. Write-up in documents/v2-modeling.md, proposed draft
wording in documents/v2-spec-feedback.md.

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.

3 participants