Introducing Bitcoin nodes' boostrap process and its protocol
Introduction

During my undergraduate internship in the KAIST NetS&P lab, I needed to find out how Bitcoin nodes communicate when joining a distributed network for the first time. Specifically, I wanted to understand what information is exchanged between nodes and known hosts or seed nodes during this initial connection. To investigate this, I utilized Wireshark to capture packets and analyze the communication process. And find out that the handshake required for Bitcoin nodes involves a streamlined set of messages, as detailed above.
The commands and protocols exchanged during this process are critical for establishing reliable connections and data sharing. For a more in-depth understanding, I’ve referenced various Bitcoin Protocol and BEP official documentation throughout this exploration.
Bitcoin protocol
Messages
Bitcoin nodes communicate with Bitcoin protocol which follows the protocol documentation like below (which is built on top on TCP)
Messages which are bitcoin protocol have common structures like the table below +) Almost all integers are encoded in little endian. Only IP or port number are encoded big endian. All field sizes are numbers of bytes
| Field Size | Description | Data type | Comments |
|---|---|---|---|
| 4 | magic | uint32_t | for REGTEST: 0xDAB5BFFA |
| 12 | command | char[12] | NULL padded |
| 4 | length | uint32_t | Length of payload bytes |
| 4 | checksum | uint32_t | First 4 bytes of sha256(sha256(payload)) |
| ? | payload | uchar[] | Actual data |
version
Advertise its version
wtxiderelay
- Send prior to
verack - For only protocol both
70016or higher
Payload
Empty payload for this command
sendaddrv2
BIP155
Prefer to receive addrv2 than addr
- Must send as response to
version - and send prior to
verack
verack
sent reply to version
getaddr
asking information about active peers
sendcmpct
- Payload length is 9
- For only protocol both
70014or higher
Payload (9bytes) = 1byte (boolean) + 8bytes
Example Payload: 0 2 0 0 0 0 0 0
If first and second bytes are
1 and 1→ new blocks bycmpctblock(BIP130)0 and *→ new blocks byinvandheaders(BIP130)* and not 1→ not received any message
ping
confirm TCP/IP connection is valid with random nonce
pong
response to ping with nonce from ping
getheaders
requests the peer for headers message
Example Payload.
- version:
70016 - hash_count:
1 - block_locator_hashes:
[GENESIS_BLOCK_HASH]In other words, starting hash - hash_stop:
0In other words, stop_hash. When it is set to zero, get as many blocks as possible (Max. 2000)
So, for getheaders message, it requests the opposite nodes to send block hashes starting from block_locator_hashes until hash_stop.
Payload
| Field Size | Description | Data type | Comments |
|---|---|---|---|
| 4 | version | uint32_t | the protocol version |
| 1+ | hash count | var_int | number of block locator hash entries |
| 32+ | block locator hashes | char[32] | block locator object |
| 32 | hash_stop | char[32] | hash of the last desired block header |
feefilter
Instruct peers not to send invs for transactions with fees below specific value.
→ due to limited memepool
- For only protocol both
70013or higher
headers
returns block header response to getheaders message.
sendheaders
prefer to receive headers message than inv
- For only protocol both
70012or higher