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:

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:

  1. Unrequested: The block is needed, but no peer has been asked for it.
  2. Pending / Requested: A request message has been sent to a peer, and the client is awaiting the response. The client logs the timestamp and peer ID to handle timeouts.
  3. 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: