Block Locator
A block locator is a data structure with a sparse list of block hashes that helps Bitcoin nodes efficiently synchronize their chain state.
Key Takeaways
- A block locator is a compact list of block hashes that a Bitcoin node sends to a peer so they can find the most recent block both nodes share, known as the fork point.
- The list uses exponential spacing: the first 10 hashes are consecutive, then the step size doubles for each subsequent entry (2nd, 4th, 8th, 16th block back), always ending with the genesis block. This keeps the locator to roughly 30 to 40 hashes regardless of chain height.
- Block locators are carried inside the
getheadersandgetblocksP2P messages, making them the starting point for headers-first sync and chain synchronization between nodes.
What Is a Block Locator?
A block locator is a data structure used in Bitcoin's peer-to-peer protocol to help two nodes quickly identify where their copies of the blockchain diverge. When a node wants to synchronize with a peer, it cannot simply ask "send me everything after block X" because it does not know which blocks the peer has. The two nodes might share the same chain, or they might have diverged at some point due to a chain reorganization or simply being at different heights.
Instead of sending its entire chain (which would be enormous), the node constructs a block locator: a short, strategically chosen list of block hashes that gives the peer enough information to figure out the most recent ancestor they share. From that common point, the peer can respond with the headers or blocks the requesting node is missing.
In Bitcoin Core, the block locator is represented by the CBlockLocator class. It consists of a protocol version number and a vector of block hashes ordered from newest to oldest. The structure is defined in the chain header files and used throughout the networking code whenever a node needs to request chain data from a peer.
How It Works
The key insight behind the block locator is that most chain divergences are short. Two well-connected nodes typically agree on recent history and only differ by a few blocks at the tip. Long-range forks are extremely rare. The locator exploits this by providing dense coverage of recent blocks (where forks are likely) and sparse coverage of older blocks (where forks are unlikely).
Building the Locator
Bitcoin Core builds a block locator using the following algorithm:
- Start at the node's current chain tip and add its hash to the list
- Walk backward through the chain, adding each block's hash. For the first 10 entries, add every consecutive block
- After 10 entries, double the step size with each subsequent hash: skip 2, then 4, then 8, then 16 blocks, and so on
- Always include the genesis block hash as the final entry
The result is an ordered list that looks something like this for a node at block height 870,000:
Block 870,000 (tip)
Block 869,999 (tip - 1)
Block 869,998 (tip - 2)
...
Block 869,991 (tip - 9) ← first 10 are consecutive
Block 869,989 (tip - 11) ← step = 2
Block 869,985 (tip - 15) ← step = 4
Block 869,977 (tip - 23) ← step = 8
Block 869,961 (tip - 39) ← step = 16
Block 869,929 (tip - 71) ← step = 32
Block 869,865 (tip - 135) ← step = 64
...
Block 0 (genesis) ← always includedLogarithmic Efficiency
Because the step size doubles after the first 10 entries, the total number of hashes grows logarithmically with chain height. For a chain of height h, the locator contains approximately 10 + log2(h) entries. At a chain height of 870,000, this works out to roughly 10 + 20 = 30 hashes. Even if Bitcoin ran for centuries and reached a chain height of billions, a locator would still contain fewer than 50 hashes.
Each hash is 32 bytes, so the entire locator fits within roughly 1 to 1.5 KB of data: a trivially small message that can pinpoint any divergence point in a chain containing hundreds of thousands of blocks.
Finding the Fork Point
When a peer receives a block locator (inside a getheaders or getblocks message), it processes it as follows:
- Iterate through the locator hashes from newest to oldest
- For each hash, check whether it exists in the peer's own chain
- The first matching hash is the most recent common ancestor (fork point)
- Respond with headers or block inventory starting from the block after that fork point
If none of the locator hashes match (an unlikely case meaning the chains share nothing in common except genesis), the peer responds starting from block 1. The genesis block hash at the end of every locator guarantees that at least one match is always found.
Locator Precision
The exponential spacing means the locator might not identify the exact fork point on the first round trip. For example, if two chains diverged 500 blocks back, the locator's nearest hash might be at 512 blocks back due to the exponential step. The peer would respond with headers starting from that point, and the requesting node can then send a more precise locator if needed. In practice, the getheaders response of up to 2,000 headers per message covers any gap introduced by the sparse tail of the locator.
Use in P2P Messages
Block locators appear in two key P2P protocol messages:
getheaders
The getheaders message is the primary mechanism for headers-first synchronization. A node sends its block locator along with a stop hash (or a zero hash to request the maximum batch). The peer responds with a headers message containing up to 2,000 block headers starting from the fork point.
getheaders message format:
┌──────────────────────────┐
│ version (uint32) │
│ hash_count (varint) │
│ block_locator_hashes │
│ [32 bytes × count] │
│ hash_stop (32 bytes) │
└──────────────────────────┘The node repeats getheaders requests, updating the locator each time with the latest received header, until the peer has no more headers to send. This iterative process downloads the entire header chain before any full blocks are fetched: a key part of initial block download.
getblocks
The older getblocks message uses the same locator format but triggers a different response: the peer replies with an inv (inventory) message listing block hashes rather than full headers. This was the original synchronization mechanism before headers-first sync was introduced. Modern nodes prefer getheaders because downloading headers first lets a node validate the chain's proof-of-work before committing to full block downloads.
Why It Matters
Without block locators, nodes would face a difficult choice during synchronization: send their entire chain of hashes (wasteful) or guess a common block and risk being wrong (fragile). The locator solves this elegantly by compressing the chain into a logarithmic-sized summary that handles both common cases (recent forks of a few blocks) and rare cases (deep reorganizations) efficiently.
This mechanism is especially critical during initial block download, where a new node must synchronize hundreds of thousands of blocks from peers. The locator ensures the node can find where to start downloading efficiently, even when connecting to peers that may be on slightly different chain tips. For a deeper look at how Bitcoin nodes discover and communicate with each other, see the Bitcoin P2P network topology research article.
Layer-2 protocols like Lightning and Spark rely on the underlying Bitcoin node's ability to stay synchronized with the network. The block locator is a small but essential part of the infrastructure that keeps Bitcoin nodes in consensus about the current state of the chain.
Code Example
The following pseudocode illustrates how Bitcoin Core constructs a block locator. The actual implementation lives in the chain module and uses skip pointers for performance, but the core logic is straightforward:
function buildBlockLocator(tip):
hashes = []
step = 1
height = tip.height
while height >= 0:
hashes.append(getBlockHash(height))
// After the first 10 entries, double the step
if hashes.length > 10:
step = step * 2
height = height - step
// Always end with the genesis block
if hashes[hashes.length - 1] != GENESIS_HASH:
hashes.append(GENESIS_HASH)
return hashesAnd the peer's processing logic:
function processLocator(locatorHashes, stopHash):
forkPoint = null
for hash in locatorHashes:
if myChain.contains(hash):
forkPoint = myChain.getBlock(hash)
break
if forkPoint == null:
forkPoint = genesisBlock
// Return up to 2,000 headers after the fork point
headers = []
current = forkPoint.next
while current != null and headers.length < 2000:
headers.append(current.header)
if current.hash == stopHash:
break
current = current.next
return headersRisks and Considerations
No Protocol-Level Size Limit
Bitcoin's original protocol specification does not impose an explicit maximum on the number of hashes in a block locator. In practice, the exponential spacing algorithm in Bitcoin Core produces at most about 42 hashes (given a 32-bit block height limit and a doubling exponent after 10 entries). However, a malicious node could theoretically send a locator with thousands of hashes, consuming processing time on the receiving node. Proposals on the Bitcoin development mailing list have suggested capping locator size at 64 entries to formalize this practical limit.
Eclipse Attack Considerations
If an attacker controls all of a node's peer connections (an eclipse attack), they could respond to locator requests with a fabricated chain. The node would sync headers from the attacker and potentially follow a malicious fork. This is why Bitcoin Core validates chain work during headers-first sync: the node only follows the chain with the most cumulative proof-of-work, making it expensive for an attacker to produce a convincing fake chain.
Locator Accuracy vs. Chain Depth
The exponential spacing trades precision for compactness. For forks deeper than about 10 blocks, the locator will not pinpoint the exact divergence block on the first attempt. The requesting node may receive some redundant headers it already has. This overhead is minimal in practice: the first round trip narrows the gap to within a factor of two, and subsequent exchanges can refine further. For the vast majority of real-world synchronization scenarios, a single locator round trip is sufficient.
This glossary entry is for informational purposes only and does not constitute financial or investment advice. Always do your own research before using any protocol or technology.