進階
Sendheaders Message
了解 P2P 協議中的 sendheaders 消息,啟用區塊頭直接推送模式。
6 分鐘
Sendheaders(BIP-130)是比特幣 P2P 協議中用於請求區塊頭直接推送的消息。 啟用後,對等節點會使用 headers 消息而非 inv 來通告新區塊,減少延遲。
Sendheaders 概述
Sendheaders 的目的:
傳統模式(使用 inv):
┌─────────┐ inv(block) ┌─────────┐
│ Node A │ ──────────────→ │ Node B │
│ │ getheaders │ │
│ │ ←────────────── │ │
│ │ headers │ │
│ │ ──────────────→ │ │
└─────────┘ └─────────┘
需要 3 次消息往返
Sendheaders 模式:
┌─────────┐ headers ┌─────────┐
│ Node A │ ──────────────→ │ Node B │
└─────────┘ └─────────┘
只需 1 次消息
優勢:
1. 減少往返延遲
2. 更快的區塊傳播
3. 簡化通訊流程 消息格式
Sendheaders 消息格式:
┌─────────────────────────────────────────┐
│ (empty payload - 0 bytes) │
└─────────────────────────────────────────┘
完整 P2P 消息:
┌──────────────────────────────────────────────┐
│ magic (4 bytes) │
│ command: "sendheaders" (12 bytes, padded) │
│ length: 0 (4 bytes) │
│ checksum: 0x5df6e0e2 (4 bytes) │
│ payload: (empty) │
└──────────────────────────────────────────────┘
發送時機:
- 版本握手完成後
- 通常在 verack 之後立即發送
- 只需發送一次
// 非常簡單的消息,只是一個標誌 協議行為
Sendheaders 後的行為變化:
發送 sendheaders 前:
- 新區塊通過 inv 通告
- 接收方需要請求 headers
- 傳統的請求-回應模式
發送 sendheaders 後:
- 新區塊直接發送 headers
- 無需額外請求
- 接收方驗證後請求區塊體
發送方邏輯:
class Peer:
prefer_headers = False
def on_sendheaders(self):
self.prefer_headers = True
def announce_block(self, block):
if self.prefer_headers:
# 直接發送 header
self.send_headers([block.header])
else:
# 傳統方式
self.send_inv(block.hash)
// 雙向獨立:A 發送 sendheaders 只影響 A 收到的通告 Headers 通告
使用 headers 通告新區塊:
單個區塊通告:
┌─────────────────────────────────────────┐
│ count: 1 │
│ headers: │
│ block_header (80 bytes) │
│ txn_count: 0 │
└─────────────────────────────────────────┘
多個區塊(追趕):
┌─────────────────────────────────────────┐
│ count: 8 │
│ headers: │
│ block_header_1 (80 bytes) │
│ txn_count: 0 │
│ block_header_2 (80 bytes) │
│ txn_count: 0 │
│ ... │
└─────────────────────────────────────────┘
規則:
- 最多發送 8 個連續 headers
- 如果超過 8 個,回退到 inv 模式
- 確保不會發送過長的消息
何時回退到 inv:
if blocks_to_announce > 8:
send_inv(blocks)
else:
send_headers(blocks) 接收方處理
處理 headers 通告:
def process_headers_announcement(headers):
for header in headers:
# 驗證 header
if not validate_header(header):
misbehaving(peer)
return
# 檢查是否已有
if have_block(header.hash):
continue
# 檢查父區塊
if not have_block(header.prev_hash):
# 缺少父區塊,需要同步
send_getheaders(locator)
return
# 接受 header
add_header(header)
# 請求區塊體
for header in headers:
if want_block(header.hash):
request_block(header.hash)
注意事項:
- 驗證 PoW
- 檢查時間戳
- 確保連接到已知鏈 BIP-130 規範
BIP-130 詳細規範:
引入版本:
- 協議版本 70012+
- Bitcoin Core 0.12.0+
行為定義:
1. 發送 sendheaders 表示偏好 headers 通告
2. 接收方應記住此偏好
3. 新區塊使用 headers 而非 inv 通告
4. 最多 8 個連續 headers
5. 超過則使用 inv
與 sendcmpct 的關係:
- sendheaders: 使用 headers 通告
- sendcmpct (high bandwidth): 直接發送 cmpctblock
- 兩者可以共存
優先級:
if sendcmpct_high_bandwidth:
send_cmpctblock()
elif sendheaders:
send_headers()
else:
send_inv() 調試與監控
# 監控 sendheaders 狀態
# Bitcoin Core 不直接暴露 sendheaders 狀態
# 但可以通過日誌觀察
# 日誌設置
# bitcoin.conf
debug=net
# 日誌輸出:
# "Sending sendheaders to peer=5"
# "peer=3 prefers headers announcements"
# "Announcing block via headers to peer=5"
# 觀察區塊通告方式
# 如果看到 "sending headers" 而非 "sending inv"
# 說明 sendheaders 已啟用
# 檢查節點是否支持
bitcoin-cli getpeerinfo | jq '.[] | {
id: .id,
version: .version,
subver: .subver
}'
# version >= 70012 支持 sendheaders 實現細節
Bitcoin Core 中的實現:
// 發送 sendheaders
void PeerManager::SendSendHeaders(CNode& node) {
if (node.GetCommonVersion() >= SENDHEADERS_VERSION) {
connman.PushMessage(&node,
CNetMsgMaker(node.GetCommonVersion())
.Make(NetMsgType::SENDHEADERS));
}
}
// 處理收到的 sendheaders
void PeerManager::ProcessSendHeaders(CNode& node) {
node.fPreferHeaders = true;
}
// 通告新區塊
void PeerManager::AnnounceBlock(const CBlockIndex* pindex) {
for (auto& node : connman.GetNodes()) {
if (node.fPreferHeaders) {
// 收集要發送的 headers
std::vector<CBlockHeader> vHeaders;
// ... 收集連續的 headers ...
if (vHeaders.size() <= MAX_HEADERS_ANNOUNCE) {
// 使用 headers 通告
connman.PushMessage(&node,
CNetMsgMaker(node.GetCommonVersion())
.Make(NetMsgType::HEADERS, vHeaders));
} else {
// 太多了,使用 inv
AnnounceBlockViaInv(node, pindex);
}
} else {
AnnounceBlockViaInv(node, pindex);
}
}
}
const int SENDHEADERS_VERSION = 70012;
const size_t MAX_HEADERS_ANNOUNCE = 8; 相關概念
- Headers Message:區塊頭消息
- Getheaders:區塊頭請求
- Compact Blocks:緊湊區塊
- Inv Message:庫存通告
- Headers-First Sync:頭部優先同步
已複製連結