Reading Bitcoin's network traffic
A historical Wireshark trace connects the ledger to the network. We reconstruct the 24-byte V1 envelope, verify an empty-payload checksum, follow block requests and expand a one-transaction block. The final step separates TCP framing, message parsing, block validation and chain selection—and explains what changes with V2 encrypted transport.
A Bitcoin block does not travel alone. It is serialized, wrapped in a protocol message, written into a connection's byte stream and split into packets by the network stack. A packet analyzer rebuilds those layers so that we can read them.
That layered view is useful well beyond Bitcoin. Many protocol mistakes come from treating a packet as a message, a checksum as authentication, or a message received from a peer as data already validated by the application.
In the previous part, we examined a block stored on disk. Here we use historical Wireshark captures of Bitcoin's V1 transport. The captures contain old blocks exchanged by a later node: a block's timestamp is not the capture time. We will preserve that distinction and avoid treating separate screenshots as if they were one continuous transaction.

Original Wireshark session with Bitcoin messages visible in the packet list. Open full-size original.
5.1 Establish a connection before exchanging blocks
A node first needs another peer's address. It may obtain candidates from its saved peer database, other peers or bootstrap mechanisms such as DNS seeds. Discovery supplies places to connect; it does not grant those machines authority over the ledger.
For the V1 exchange considered here, the peers establish a TCP connection and exchange version messages containing protocol and service information. They acknowledge the exchange with verack. Other negotiation messages can appear around this process depending on the supported protocol features.
The messages do not authenticate a human identity or certify that the other peer is honest. A handshake establishes a usable protocol conversation. We still check what the peer sends.
A node can also hold many simultaneous connections. In a packet list, two consecutive Bitcoin rows may belong to different remote machines. Before inferring a conversation, filter by connection or TCP stream and inspect direction, requested identifiers and response contents. The P2P guide describes the distinction between discovering peers, establishing connections and downloading blocks.
5.2 Decode the V1 message envelope
A V1 message has a 24-byte header followed by a payload whose length the header declares. The same envelope carries commands with very different bodies: verack has an empty payload, while block contains a serialized block.
On mainnet, the magic is f9 be b4 d9. The command is ASCII; the payload length is a little-endian 32-bit integer. The checksum consists of the first four bytes of double SHA-256 of the payload.
The checksum detects accidental damage or a mismatch in message assembly. It is not a signature or a message-authentication code: an adversary who changes the payload can recompute it. Likewise, recognizing the magic does not establish that a block is valid. These are parsing and transport checks, not consensus decisions.
The magic is the same four-byte sequence we saw in the historical disk record, but the surrounding structures differ. A disk record has magic, size and serialized block. A V1 network message additionally has a command and checksum. Neither wrapper belongs in the block's proof-of-work hash.

Original capture highlighting mainnet magic in the V1 envelope. Open full-size original.
5.3 Check a complete verack message
The captured verack message fits entirely in its 24-byte header:
f9 be b4 d9
76 65 72 61 63 6b 00 00 00 00 00 00
00 00 00 00
5d f6 e0 e2The six nonzero command bytes spell verack. Six zero bytes complete the command field. The next four zero bytes encode a payload length of zero. The checksum is not zero, because the hash of an empty byte string is not an empty result.
We can verify the entire example without a node or a packet analyzer:
from hashlib import sha256
from struct import unpack
def hash256(data):
return sha256(sha256(data).digest()).digest()
message = bytes.fromhex("""
f9beb4d9
76657261636b000000000000
00000000
5df6e0e2
""")
magic, command, size, checksum = unpack("<4s12sI4s", message[:24])
payload = message[24:]
assert len(message) == 24
assert magic == bytes.fromhex("f9beb4d9")
assert command == b"verack" + bytes(6)
assert size == len(payload) == 0
assert checksum == hash256(payload)[:4] == bytes.fromhex("5df6e0e2")This check has a deliberately narrow scope. It validates the bytes of this known message. A stream parser additionally needs buffering, length limits and a way to handle incomplete or malformed messages safely. It must not assume that a single socket read returns exactly one envelope.

Original verack capture. The command, zero payload length and empty-payload checksum can be compared with the bytes above. Open full-size original.
5.4 Find the block inside its response
Another capture shows a block response with a payload length of 216 bytes, encoded as d8 00 00 00. The V1 command field is the five bytes of block followed by seven zero bytes. The displayed payload checksum is 29 d9 15 04.
Inside the payload, the analyzer expands an 80-byte header, a transaction count of one, and a transaction. That gives a useful accounting check:
With its network header, the application message occupies 240 bytes. Those totals do not include Ethernet, IP or TCP headers.

Original block response, with the V1 envelope and block header expanded. The neighboring getdata row belongs to another peer; adjacency alone does not establish a request/response pair. Open full-size original.
The header in this response reports an early-2009 block. It is not the July 2011 block decoded in the previous article. A separate expanded-transaction capture also has a different block header. We can use these views to understand the same format without joining their bytes into a fictitious single block.
In that expanded transaction, the previous transaction hash is all zeroes and the output index is ffffffff. Those two fields identify a coinbase input. The eight-byte script is 04ffff001d025d07; the sole output is 5,000,000,000 satoshis, exactly 50 BTC, with a 67-byte pay-to-public-key script.
It would be wrong to describe this as an ordinary payment spending a previous user's transaction. The null outpoint is decisive. It would also be wrong to infer the total fees from the 50 BTC claim alone: a miner can leave some reward unclaimed. Parsing the record establishes what was claimed, while checking the full block establishes what was permitted.

Original expanded transaction capture. Its null outpoint identifies a coinbase input and its output claims 50 BTC. This screenshot shows a different block header from the preceding capture. Open full-size original.
5.5 Read the stream, not just the packet list
The capture's bitcoin display filter is convenient for finding decoded V1 messages. It does not mean that every TCP segment in the conversation contains a separately decodable Bitcoin command. An analyzer may show the protocol only on the frame where enough data becomes available for reassembly.
TCP transports an ordered stream. One application message can span several segments; several messages can also share a segment. Retransmissions, capture loss and out-of-order arrival further complicate the visible packet list. The 240-byte message above was shown as reassembled data, not as a requirement that the sender transmit one 240-byte packet.
A disciplined reading goes through the layers in order:
- Identify the connection and message direction.
- Reassemble the stream and check the declared message boundaries.
- Decode the command, payload length and checksum.
- Parse the payload according to that command's format.
- Apply the relevant validation rules and, for a block, compare its place in the known chain.
For a getdata request, inspect the inventory type and object hash. A block response should match the requested object in that conversation. The screenshot's preceding getdata row is addressed to another peer, so mere adjacency does not establish that it caused the selected response. The protocol reference specifies the message fields; the capture still needs careful interpretation.
5.6 What changes with encrypted transport
These diagrams describe historical, cleartext V1 transport. Bitcoin also has a V2 encrypted transport specified by BIP 324. A passive observer of a V2 connection does not see the same readable command fields and payload bytes, so applying an old V1 dissector or filtering for decoded V1 commands cannot reveal the same conversation.
Transport encryption protects a connection's traffic under its stated design. It does not encrypt the public blockchain, hide every network-level fact or remove the need to validate transactions. It also does not, by itself, give a peer a certified real-world identity. The ledger and the transport solve different problems.
This returns us to the design principle behind DCoin. Peer discovery finds a source. A connection carries bytes. An envelope separates messages. A checksum checks their payload. A transaction's spending conditions authorize a state change. Consensus chooses among valid histories. Understanding a blockchain becomes much easier when each of these mechanisms is allowed to make exactly its own claim—and no larger one.