Complete BEP 6 Fast Extension: send Allowed Fast Set + record received#1052
Open
guangtoutong wants to merge 1 commit into
Open
Complete BEP 6 Fast Extension: send Allowed Fast Set + record received#1052guangtoutong wants to merge 1 commit into
guangtoutong wants to merge 1 commit into
Conversation
Closes anacrolix#235. Adds the missing pieces of BEP 6 Fast Extension. Before this change two behaviours were broken: 1. AllowedFast received from peers was logged but never recorded into the peerAllowedFast bitmap, so every downstream check (requesting.go, shouldRequestWithoutBias, peer.go, torrent.go) read an empty set and the feature was effectively a no-op on the receive side. 2. We never sent AllowedFast to remote peers. Peers that support Fast Extension expect a small set of allowed-fast pieces after handshake so they can request data while choked; without it the cold-start penalty is one full choke cycle. This change: internal/fast/fast.go Implements the BEP 6 generator: SHA1-based pseudorandom indices seeded with the /24-masked peer IP and the v1 info hash. Pure function so peers can independently re-derive and verify. Returns nil for IPv6 (the spec defines the algorithm for IPv4 only) and for zero k / zero piece count. peerconn.go - Fixes the receive path: case pp.AllowedFast now records the piece into peerAllowedFast so downstream bitmap reads work. - Adds (*PeerConn).sendAllowedFastSet, called from sendInitialMessages when fastEnabled() and torrent metadata are available. Skips when peer has no IPv4 or when only the v2 info hash is known (algorithm requires v1 hash). - Bumps the "allowed fasts sent" expvar counter, mirroring the existing "allowed fasts received". client.go sendInitialMessages calls pc.sendAllowedFastSet() after the Have-all/Have-none/Bitfield decision, before Port (DHT). internal/fast/fast_test.go - Verifies output against BEP 6's canonical example (ip=80.4.4.200, infohash=0xAA*20, numPieces=1313, k=7 -> [1059, 431, 808, 1217, 287, 376, 1188]). - Determinism, /24 subnet stability, IPv6 nil, uniqueness in collision-prone configurations, edge cases (k=0, numPieces=0). Algorithm reference: cenkalti/rain (suggested by @anacrolix in anacrolix#235). All existing tests pass. New tests included.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #235.
Completes BEP 6 Fast Extension by adding the two missing pieces:
1. Bug fix: received
AllowedFastwas a no-opBefore this change,
case pp.AllowedFastinpeerconn.mainReadLooplogged the message but never wrote topeerAllowedFast. Every downstream check (requesting.go,shouldRequestWithoutBias,peer.go:peerAllowedFast.Iterate,torrent.go:1548) read an empty bitmap, so honoring a peer's allowed-fast set was effectively disabled.2. New: send our Allowed Fast Set
When
fastEnabled()and torrent metadata are available, we now compute the BEP 6 allowed-fast set for the remote peer and send oneAllowedFastmessage per piece after the Have-all/Have-none/Bitfield decision insendInitialMessages. Peers can request these pieces while choked, removing the cold-start penalty.Algorithm
internal/fast/fast.go— SHA1-based pseudorandom indices seeded with the /24-masked peer IP and v1 info hash. Pure function so peers can independently re-derive and verify. Returns nil for IPv6 (BEP 6 defines the algorithm for IPv4 only). Reference: cenkalti/rain/internal/fast (as suggested in #235).Tests
internal/fast/fast_test.go:[1059, 431, 808, 1217, 287, 376, 1188]✅All existing tests pass.
storage/possumfails locally on Windows due to a missing nativelibpossumlibrary — unrelated to this change.Files
internal/fast/fast.go— new packageinternal/fast/fast_test.go— new testspeerconn.go— fix receive path, addsendAllowedFastSetclient.go— invokesendAllowedFastSetafter Have-all/Have-none/Bitfieldcc @cenkalti (parts of the algorithm are based on rain's implementation).