Skip to content

Torrent v2 5/8: V2 handshake, hash exchange and bounded transport - #235

Merged
linroid merged 1 commit into
torrent-v2-stack-04-recoveryfrom
torrent-v2-stack-05-protocol
Sep 20, 2026
Merged

linroid merged 1 commit into
torrent-v2-stack-04-recoveryfrom
torrent-v2-stack-05-protocol

Conversation

@linroid

@linroid linroid commented Sep 20, 2026 •

Copy link
Copy Markdown
Owner

Negotiates full-identity peer handshakes and authenticates bounded hash exchanges. Frame/request ownership, deadlines and explicit response handling constrain transport memory and malformed-peer behavior.

Part 5/8 of the consolidated stack for #162. Review and merge bottom-up. This PR targets torrent-v2-stack-04-recovery; its diff contains only this capability group.

Preservation and validation

Consolidates #186–#194. The consolidation snapshot matches original boundary 45e5b9ec exactly. Fresh CI then exposed a listener shutdown race: canceled accept() could escape as a socket exception. Foundation commit 2fdddd39 fixes cancellation classification and adds a deterministic regression test. This inherited fix and its test are the only file differences from that original boundary; all other contents are preserved. Original branches and discussions are retained.

Fresh CI runs on this replacement PR; historical checks and approvals are not transferred. The remaining production roadmap and release gates are still open.

Original PRs and frozen heads

PR Original head
#186 — Add bounded BEP 52 hash exchange wire messages c238102b
#187 — Authenticate peer hash proofs against trusted file roots 1403f581
#188 — Track and admit authenticated peer hash exchanges e18b978c
#189 — Connect admitted hash exchange to bounded peer transport bd9c0a87
#190 — Bound desktop bitfields by authenticated piece counts 3b1f9cfe
#191 — Negotiate full-identity v2 and hybrid peer routes c6f4ddf9
#192 — Retain v2 block requests until explicit peer responses 76cb3cc1
#193 — Admit outbound v2 peer frames before encoding and writing 7e7c32e5
#194 — Bound v2 block requests by file tails and response deadlines 45e5b9ec

Review carry-forward

These original discussions and their responses remain linked for review. Their unresolved status is preserved; consolidation does not imply reviewer approval.

Consolidated stack

  1. Torrent v2 1/8: Contracts, verification infrastructure and resource limits #231 — Contracts, verification infrastructure and resource limits
  2. Torrent v2 2/8: V2 identity, metainfo and Merkle integrity #232 — V2 identity, metainfo and Merkle integrity
  3. Torrent v2 3/8: V2 layout and verified storage #233 — V2 layout and verified storage
  4. Torrent v2 4/8: V2 catalog, checkpoints and crash recovery #234 — V2 catalog, checkpoints and crash recovery
  5. Torrent v2 5/8: V2 handshake, hash exchange and bounded transport #235 — V2 handshake, hash exchange and bounded transport
  6. Torrent v2 6/8: V2 scheduling and download execution #236 — V2 scheduling and download execution
  7. Torrent v2 7/8: Tracker lifecycle, editing and discovery privacy #237 — Tracker lifecycle, editing and discovery privacy
  8. Torrent v2 8/8: V2 engine lifecycle, rate controls and restart recovery #238 — V2 engine lifecycle, rate controls and restart recovery

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-20T07:46:09.558773Z e727802 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e727802a9f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

init {
require(root.size == 32)
require(baseLayer in 0..63 && proofLayers in 0..63 && baseLayer + proofLayers <= 63)
require(length in 2..512 && length and (length - 1) == 0)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept one-hash BEP 52 requests

BEP 52 permits length to be any positive power of two up to 512, including 1. A peer requesting a single remaining hash therefore causes PeerHashSelector construction to throw during decoding, closing an otherwise valid v2 connection; local scheduling also cannot issue such a request. Allow length == 1 (the existing hashCount calculation already handles that case).

Useful? React with 👍 / 👎.

Consolidates #186–#194, preserving source 45e5b9e.
Includes the foundation listener cancellation regression fix discovered by consolidation CI.
@github-actions

Copy link
Copy Markdown
Contributor

Test Results

  652 files    652 suites   4m 59s ⏱️
2 693 tests 2 693 ✅ 0 💤 0 ❌
3 567 runs  3 567 ✅ 0 💤 0 ❌

Results for commit 77e62d0.

@linroid
linroid added this pull request to stack #239 September 20, 2026 08:46
@linroid
linroid merged commit 3bedc3a into main Sep 20, 2026
10 checks passed
@linroid
linroid deleted the torrent-v2-stack-05-protocol branch September 20, 2026 11:01
linroid added a commit that referenced this pull request Sep 20, 2026
)

Four automated review findings from PRs #232, #235, #236 and #237 were left
unresolved when those branches were consolidated and merged.

Metadata cache (#237, P1): pending fetches were keyed by info hash alone, so a
TRACKER_ONLY caller arriving while a PUBLIC fetch was in flight joined that
operation and inherited discovery it had opted out of, along with its rejection
of private metadata. The privacy branch lives inside the fetch lambda, which
only runs for the caller that creates the deferred, so the guard could never
fire for the joining caller. Pending work is now keyed by hash and privacy.
Completed entries stay shared because the hash authenticates them.

Piece scheduler (#236): every HAVE frame rebuilt the peer's full availability
as a BooleanArray and made the scheduler copy and rescan it, so a peer sending
duplicate announcements forced repeated allocation and a full rarity scan per
message. HAVE now applies incrementally; only the one-time bitfield rebuilds.

Hash wire (#235): BEP 52 permits a request length of any positive power of two
up to 512, but length 1 was rejected during decoding, closing otherwise valid
v2 connections. The existing hashCount calculation already covers that case:
a lone base hash covers no proof layer, so uncles is proofLayers + 1, which
matches the invariant peerHashProofHeight enforces.

Metainfo (#232): an unconditional requireNotNull rejected documents that omit
"piece layers", which BEP 52 allows when no file exceeds the piece length. An
absent key now parses as an empty dictionary; validatePieceLayers still rejects
omission whenever the parsed files require external layers.

The symlink race reported on #233 is not addressed here. Closing it needs a
no-follow open plus handle-identity verification, which okio's commonMain
FileSystem does not expose; validateOwned still rejects symlinks, checks file
identity and revalidates after writing. The oversized-file finding on the same
PR was already fixed before merge and only left unresolved on GitHub.

Each fix carries a regression test. The two behavioural ones were confirmed to
fail without their fix: reverting the pending key to ignore privacy fails
restrictedCallersNeverJoinPendingPublicDiscovery, and removing the duplicate
guard fails announce_buildsAvailabilityIncrementallyAndIgnoresRepeatedIndexes.
Full suites pass on a forced rerun: 639 torrent and 203 core JVM tests, plus
the iOS simulator target compiling clean.
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.

1 participant