How BitTorrent Tracks Blocks in Incomplete Pieces
In the BitTorrent protocol, files are divided into pieces, which are further broken down into standard 16 KiB transmission blocks for peer-to-peer exchange. Because the main torrent metadata only verifies full pieces via cryptographic hashes, clients must internally track the individual 16 KiB blocks of active, incomplete pieces. This article explains the internal data structures, bitmask tracking methods, and buffer management clients use to monitor these sub-piece chunks from request to disk verification.
The Distinction Between Pieces and Blocks
The BitTorrent metainfo file (.torrent) defines a
torrent by “pieces,” typically ranging from 256 KiB to several megabytes
in size. Each piece has a corresponding SHA-1 or SHA-256 hash. However,
transmitting an entire piece in a single network packet is inefficient.
To facilitate smooth transmission and pipelining, clients break pieces
down into “blocks” (also called chunks), with 16 KiB (16,384 bytes)
being the universally accepted standard size.
While the global piece availability of a client is advertised to
peers using a piece-level bitfield message, individual 16
KiB block tracking is strictly managed locally within the client’s
memory.
In-Memory Piece State Structures
When a client decides to download a piece, it initializes a dedicated
in-memory data structure for that specific piece. This structure, often
referred to as a PieceState or
ActivePieceContext, contains all the metadata required to
track incoming data:
- Piece Index: The zero-based index of the piece within the torrent.
- Total Blocks: The total number of 16 KiB blocks in the piece (the final piece of a file may have fewer blocks).
- Blocks Received Counter: An integer tracking how many blocks have arrived.
- Block Status Mask: A small local bitmask or boolean array.
- Data Buffer: A contiguous block of allocated memory sized to hold the entire piece.
Sub-Piece Bitmasks and Offset Mapping
The primary mechanism for tracking which specific 16 KiB blocks have been received is a local bitfield (or bitmask) dedicated to that active piece.
Because standard pieces contain a fixed number of 16 KiB blocks, each
block corresponds to a discrete index: * Block 0: Offset 0
bytes (Bit 0) * Block 1: Offset 16,384 bytes (Bit 1) *
Block 2: Offset 32,768 bytes (Bit 2) * Block n:
Offset n * 16,384 bytes (Bit n)
When a peer sends a piece network message containing the
piece index, byte offset, and raw data payload, the client calculates
the block index:
\[\text{Block Index} = \frac{\text{Byte Offset}}{16384}\]
The client copies the 16 KiB payload into the memory buffer at the
exact byte offset and flips the corresponding bit in the local bitmask
from 0 to 1. It also increments the blocks
received counter.
Request States and Duplicate Prevention
Advanced BitTorrent clients (such as libtorrent-rasterbar, qBittorrent, and Transmission) track sub-piece blocks with more granularity than just “present” or “missing.” Each block within an active piece often exists in one of several states:
- Unrequested: The block is needed, but no peer has been asked for it.
- Pending / Requested: A
requestmessage has been sent to a peer, and the client is awaiting the response. The client logs the timestamp and peer ID to handle timeouts. - Received: The block has been written to the piece buffer.
Tracking these states prevents the client from redundantly requesting the same 16 KiB block from multiple peers under normal conditions, while allowing the client to re-request blocks if a peer disconnects or fails to respond before a timeout.
Completion and Verification
Once the “blocks received” counter matches the total block count for
the piece (meaning all bits in the local block bitmask are set to
1), the piece is complete.
The client passes the contiguous piece buffer through a cryptographic hashing function (SHA-1 or SHA-256) and compares the output to the expected hash in the metadata:
- If the hash matches: The piece is written to disk,
the client’s global torrent-level bitfield is updated to mark the entire
piece as complete,
havemessages are sent to connected peers, and the sub-piece memory structure is deallocated. - If the hash fails: A data corruption or malicious
block occurred. Because individual 16 KiB blocks lack individual
cryptographic hashes in standard BitTorrent v1, the entire piece buffer
is marked invalid, all block bits are reset to
0, and the blocks are re-requested from different peers.