一条区块链网络由成千上万个独立节点组成,它们运行的软件版本各不相同。如何让这些异构节点相互识别能力、协商共同支持的协议版本,并在不分裂网络的前提下完成升级,是长期可演化性的核心议题。
6.7.1 版本握手:version/verack 与 Hello
当两个节点建立 TCP 连接后,第一件事是协议握手——不是传输区块,而是交换"我是谁、我能做什么"。
比特币的 version/verack 握手
发起方(Outbound)先发送 version 消息,接收方回复 verack,随后发起方也回复 verack。两次交叉的 version/verack 构成握手完成:
sequenceDiagram
participant A as 节点A(发起方)
participant B as 节点B(接收方)
A->>B: TCP 连接建立
A->>B: version (v=70015, services=13, height=876543)
B->>A: verack
Note over A,B: A 开始监听 B 的消息
B->>A: version (v=70015, services=13, height=876510)
A->>B: verack
Note over A,B: 双向握手完成
A->>B: getaddr / addr 交换对等地址
version 消息核心字段:
| 字段 | 类型 | 说明 |
|---|---|---|
version | int32 | 协议版本号(当前主流 70016) |
services | uint64 | 服务位掩码 |
timestamp | int64 | Unix 时间戳(用于时间同步) |
addr_recv | net_addr | 对方网络地址 |
addr_from | net_addr | 自身网络地址 |
nonce | uint64 | 64 位随机数(防止自连接循环) |
start_height | int32 | 本地区块高度 |
relay | bool | 是否接收交易广播 |
以太坊的 Hello + Status 握手
以太坊采用更现代的两消息设计:
Hello:协议版本、客户端标识、监听端口、Capabilities列表(如eth/68,snap/1);Status:创世哈希、最新区块头哈希、区块总难度(TD)。
随后通过 Ping/Pong 心跳维持连接活性。
6.7.2 服务位与能力协商
比特币的 services 字段是一个位掩码(bitmask),每个比特位代表一项能力:
| 位值 | 名称 | 说明 |
|---|---|---|
| 1 | NODE_NETWORK | 可提供完整区块链数据 |
| 2 | NODE_BLOOM | 支持 Bloom Filter 查询 |
| 4 | NODE_WITNESS | 支持 SegWit 隔离见证 |
| 64 | NODE_COMPACT_FILTERS | 支持 Golomb 编码过滤器 |
| 1024 | NODE_NETWORK_LIMITED | 仅提供近期区块数据(pruned 节点) |
能力协商通过按位与完成:
ts
// version-handshake-sim.ts
// 纯内置:模拟版本/服务位握手与服务发现
const NODE_NONE = 0;
const NODE_NETWORK = 1 << 0;
const NODE_BLOOM = 1 << 1;
const NODE_WITNESS = 1 << 2;
const NODE_COMPACT_FILTERS = 1 << 6;
function hasService(services: number, flag: number): boolean {
return (services & flag) === flag;
}
function intersectServices(a: number, b: number): string[] {
const shared = a & b;
const names: Record<number, string> = {
[NODE_NETWORK]: 'NETWORK',
[NODE_BLOOM]: 'BLOOM',
[NODE_WITNESS]: 'WITNESS',
[NODE_COMPACT_FILTERS]: 'COMPACT_FILTERS',
};
return Object.entries(names)
.filter(([flag]) => hasService(shared, Number(flag)))
.map(([, name]) => name);
}
// 两节点握手
const nodeA = NODE_NETWORK | NODE_WITNESS; // 可完整提供 + 支持 SegWit
const nodeB = NODE_NETWORK | NODE_BLOOM | NODE_WITNESS | NODE_COMPACT_FILTERS;
console.log('共享能力:', intersectServices(nodeA, nodeB));
// 输出: [ 'NETWORK', 'WITNESS' ]
// B 的 BLOOM 和 COMPACT_FILTERS 不被 A 支持6.7.3 BIP-9 VersionBits:软分叉信号协商
软分叉激活需要全网节点达成"是否支持"的共识。BIP-9 引入 VersionBits——使用区块头 nVersion 字段的未使用比特位作为能力信令信道。
| 状态 | 说明 |
|---|---|
| Defined | 提案被分配一个 VersionBit 位置,等待信号起始 |
| Started | 信号窗口开始,矿工在该位设为 1 表示支持 |
| Locked In | 在窗口期内达到 95% 信号率,该升级被锁定激活 |
| Active | 达到锁定高度 + 延迟后,规则正式生效 |
| Failed | 信号窗口结束,未达 95%,提案竞争失败 |
graph LR
A[Defined] -->|信号窗口| B[Started]
B -->|≥95% 信号率| C[Locked In]
B -->|窗口结束<br><95%| F[Failed]
C -->|延迟激活| D[Active]
style C fill:#ccffcc
style F fill:#ffcccc
6.7.4 向后兼容与协议演化的哲学
核心原则:软分叉必须保持向后兼容。旧节点可以继续运行,只是无法验证新规则的额外数据。
比特币的协议演化策略是极度保守:一次升级从 BIP 提案到激活可能需要数年时间。以太坊的演化速度更快,通过硬分叉(如 The Merge、Dencun)引入激进改进。
两种哲学的对比:
| 特性 | 比特币(保守) | 以太坊(积极) |
|---|---|---|
| 升级周期 | 数年/次 | 数月/次 |
| 兼容性 | 软分叉为主,向后兼容 | 硬分叉为主,所有节点必须升级 |
| 争议处理 | 社区辩论 + 算力信号 | 核心开发者驱动 + 社区公投 |
| 代表升级 | SegWit (4年) | The Merge, Dencun |
关键认知:协议版本协商与升级机制回答的是"如何让去中心化系统持续进化而不崩溃"。版本握手是一个微共识过程——在发起任何数据交换前,两个节点必须先就"我们能共享什么"达成一致。BIP-9 的 VersionBits 将这种微共识扩展为全网升级的协调工具。
← 6.6 轻客户端与全节点 | 前往 → ch06-summary
评论
0评论加载中…