Prerequisites:
- 06-mining-pow
Сетевой протокол Bitcoin
Зачем это блокчейну?
Когда вы отправляете Bitcoin-транзакцию, ваш узел передаёт её соседям, те — своим соседям, и через секунды тысячи узлов по всему миру знают о ней. Как работает эта P2P-сеть? Как новый узел находит других? Как блок, найденный майнером в Исландии, за секунды оказывается у майнера в Токио?
Bitcoin — это не сервер и не «блокчейн в облаке». Это одноранговая (peer-to-peer) сеть из тысяч независимых узлов, каждый из которых хранит полную копию блокчейна и самостоятельно проверяет все правила.
# Подключитесь к регтест-узлу и посмотрите на пиров:
bitcoin-cli -regtest getpeerinfo
# Каждый пир -- это отдельный узел Bitcoin, с которым ваш узел обменивается данными
Обнаружение узлов (Peer Discovery)
Когда Bitcoin-узел запускается впервые, ему нужно найти других участников сети. Процесс:
1. DNS Seeds
Узел обращается к захардкоженным DNS-seed серверам:
seed.bitcoin.sipa.be
dnsseed.bluematt.me
seed.bitcoinstats.com
seed.btc.petertodd.net
...
DNS-запрос возвращает IP-адреса активных Bitcoin-узлов. Это начальная точка — дальше узел находит пиров самостоятельно.
2. Handshake (рукопожатие)
Новый узел Пир
|--- version ------------>| "Привет, я Bitcoin Core v30, regtest"
|<-- version -------------| "Привет, я Bitcoin Core v29, regtest"
|--- verack ------------->| "Подтверждаю"
|<-- verack --------------| "Подтверждаю"
| | Соединение установлено!
3. Обмен адресами (addr)
После подключения узлы обмениваются списками известных пиров через addr-сообщения. Каждый узел поддерживает базу данных адресов и периодически делится ими.
Результат: через несколько минут новый узел подключён к 8—10 исходящим (outbound) и может принимать до 125 входящих (inbound) соединений.
Распространение блоков
Когда майнер находит новый блок, он должен как можно быстрее доставить его всей сети. Задержка распространения = риск orphan-блоков.
Переключайте вкладки, чтобы увидеть три ключевых потока:
- Обнаружение узлов — как новый узел подключается к сети
- Распространение блока — inv -> getdata -> block
- Передача транзакции — inv -> getdata -> tx
Протокол распространения блока
Майнер Узел A Узел B
|--- inv (block_hash) ----->| |
| |--- inv (block_hash) ------->|
|<-- getdata (block_hash) --| |
|--- block (full_data) ---->| |
| |<-- getdata (block_hash) ----|
| |--- block (full_data) ------>|
- inv (inventory): «У меня есть блок с таким хешем»
- getdata: «Пришли мне этот блок»
- block: полные данные блока
Headers-first (Bitcoin Core 0.10+)
Современный Bitcoin Core использует оптимизацию headers-first:
- Сначала скачать заголовки (80 байт каждый) — дёшево
- Проверить цепочку заголовков (PoW, timestamp)
- Запросить полные блоки параллельно у нескольких пиров
Распространение транзакций
Транзакции распространяются по той же схеме inv -> getdata -> tx:
Кошелёк (SPV) Full Node Майнер
|--- inv (tx_hash) -------->| |
|<-- getdata (tx_hash) -----| |
|--- tx (full_data) ------->| |
| | Проверяет транзакцию |
| | Добавляет в мемпул |
| |--- inv (tx_hash) ---------->|
| | |
| |<-- getdata (tx_hash) -------|
| |--- tx (full_data) --------->|
| | Добавляет в мемпул
Каждый узел самостоятельно проверяет транзакцию перед ретрансляцией:
- Формат корректный?
- Входы существуют и не потрачены?
- Подписи валидны?
- Комиссия достаточна?
Если проверка не пройдена — транзакция отбрасывается и не ретранслируется.
Мемпул (Memory Pool)
Мемпул — это «зал ожидания» для неподтверждённых транзакций. Каждый узел поддерживает свой мемпул.
Как майнеры выбирают транзакции
Майнеры заполняют блок транзакциями из мемпула, приоритизируя по fee rate (комиссия за виртуальный байт):
fee_rate = fee / vbytes (сатоши/вБ)
Транзакции с большей fee rate включаются первыми. При заполненном мемпуле транзакции с низкой fee rate могут ждать часами или быть удалены.
RBF (Replace-by-Fee)
Если транзакция «застряла» в мемпуле (низкая комиссия), отправитель может создать замену с той же входной UTXO, но с более высокой комиссией. Узлы примут замену, если:
- Оригинал был помечен как replaceable (nSequence < 0xFFFFFFFF-1)
- Новая комиссия выше старой
CPFP (Child-Pays-for-Parent)
Получатель может «подтолкнуть» застрявшую транзакцию, создав дочернюю транзакцию, которая тратит выход застрявшей, с высокой комиссией. Майнеру выгодно включить обе транзакции — суммарная fee rate выше порога.
# Проверить мемпул на регтесте:
bitcoin-cli -regtest getmempoolinfo
# {
# "loaded": true,
# "size": 0, # количество транзакций
# "bytes": 0, # размер в байтах
# "usage": 64, # использование памяти
# "mempoolminfee": 0.00001000
# }
Initial Block Download (IBD)
Новый узел должен скачать и проверить все блоки с Genesis-блока (2009) до текущего. Это называется Initial Block Download.
Процесс
- Скачать заголовки — запросить цепочку заголовков у пиров (headers-first)
- Проверить заголовки — каждый заголовок: корректный PoW, правильный prev_hash, валидный timestamp
- Скачать блоки — параллельно у нескольких пиров (разные диапазоны высот)
- Проверить транзакции — каждая транзакция в каждом блоке проверяется полностью
- Построить UTXO set — после проверки всех блоков у узла есть актуальный набор неизрасходованных выходов
Время IBD
На 2025 год полная синхронизация занимает от нескольких часов до суток в зависимости от оборудования (CPU для проверки подписей, SSD для UTXO set, пропускная способность). Блокчейн Bitcoin занимает ~600 ГБ.
Формат сообщений
Каждое P2P-сообщение Bitcoin имеет структуру:
[Magic bytes: 4 байта] Идентификатор сети (mainnet/testnet/regtest)
[Command: 12 байт] Название команды (version, inv, block, tx, ...)
[Length: 4 байта] Длина payload
[Checksum: 4 байта] Первые 4 байта SHA-256d от payload
[Payload: N байт] Данные сообщения
| Сеть | Magic bytes |
|---|---|
| Mainnet | 0xf9beb4d9 |
| Testnet3 | 0x0b110907 |
| Regtest | 0xfabfb5da |
Magic bytes позволяют узлу сразу определить, к какой сети принадлежит соединение. Checksum обеспечивает целостность данных.
Современные улучшения
BIP 152: Compact Block Relay
Вместо отправки полного блока (~1-2 МБ) отправляется компактный блок — заголовок + укороченные ID транзакций. Поскольку принимающий узел уже имеет большинство транзакций в мемпуле, он восстанавливает блок локально. Уменьшает время распространения в ~10 раз.
BIP 324: Encrypted P2P (v2 transport)
Начиная с Bitcoin Core 26, P2P-соединения могут быть зашифрованы (Noise Protocol). Это защищает от:
- Перехвата трафика ISP
- Определения, какие транзакции отправляет конкретный узел
- Man-in-the-middle на уровне сети
Алгоритмический уровень
Подключитесь к регтест-узлу и исследуйте сеть:
# Информация о подключённых пирах:
bitcoin-cli -regtest getpeerinfo
# Каждый пир: addr, version, subver, pingtime, bytessent, bytesrecv
# Информация о мемпуле:
bitcoin-cli -regtest getmempoolinfo
# size, bytes, usage, mempoolminfee
# Информация о сети:
bitcoin-cli -regtest getnetworkinfo
# version, subversion, protocolversion, connections
Структура ответа getpeerinfo
[
{
"id": 0,
"addr": "127.0.0.1:18444",
"addrbind": "127.0.0.1:52348",
"network": "not_publicly_routable",
"services": "0000000000000409",
"version": 70016,
"subver": "/Satoshi:30.2.0/",
"inbound": false,
"bip152_hb_to": true,
"bytessent": 12345,
"bytesrecv": 67890,
"pingtime": 0.001
}
]
Практика
Запустите регтест-узел и исследуйте P2P-протокол:
# Запустите Docker-контейнер с Bitcoin Core
# docker compose -f labs/bitcoin/docker-compose.yml up -d
# Подключитесь и исследуйте:
bitcoin-cli -regtest getpeerinfo
bitcoin-cli -regtest getmempoolinfo
bitcoin-cli -regtest getnetworkinfo
Что дальше?
Мы изучили, как работает сеть Bitcoin — от обнаружения узлов до распространения блоков и транзакций. В следующих уроках перейдём к Lightning Network — протоколу второго уровня (Layer 2), который позволяет проводить тысячи транзакций в секунду без записи каждой из них в блокчейн.
Finished the lesson?
Mark it as complete to track your progress