比特币作为一套去中心化的开源协议,其升级不能依靠某个单一机构拍板决策。社区借鉴 IETF 的 RFC 机制,设计了 BIP(Bitcoin Improvement Proposal) 流程。本节解析 BIP 的分类与生命周期,深入隔离见证(SegWit)的技术本质、交易可锻性修复,以及 Weight 单位的区块容量新定义。
4.5.1 BIP 流程与分类体系
BIP 既是技术文档,也是政治协商工具——任何涉及共识规则、网络协议或应用程序接口的重大变更,都必须以 BIP 的形式公开讨论。
BIP 的编号分类
BIP 按性质分为三个类别,编号本身并无优先级:
| 类别 | 说明 | 典型示例 |
|---|---|---|
| Standards Track(标准类) | 直接影响共识规则、P2P 网络协议或交互标准,要求全节点兼容实现 | BIP-141(SegWit 激活规则)、BIP-143(签名验证规则) |
| Informational(信息类) | 提供技术说明、设计原理或最佳实践,不强制实现 | BIP-32(分层确定性钱包设计原理) |
| Process(流程类) | 描述比特币开发的工作流程、角色分工、BIP 的元流程 | BIP-2(BIP 自身治理流程) |
BIP 生命周期
stateDiagram-v2
[*] --> 草案Draft
草案Draft --> 已接受Accepted: 分配编号进入社区评议
已接受Accepted --> 最终Final: 已实现并广泛部署
已接受Accepted --> 活跃Active: 流程类持续有效
草案Draft --> 推迟Deferred: 长期无进展
已接受Accepted --> 废除Withdrawn: 提案人撤回
最终Final --> 过时Superseded: 被后续BIP替代
每份 BIP 必须包含:动机(Motivation)、规范(Specification)、兼容性分析、参考实现(Reference Implementation)。
BIP-141 / 143 / 144:里程碑级组合
隔离见证(SegWit)并非单一 BIP,而是一套协调部署的提案组合:
- BIP-141:定义 SegWit 的共识层激活规则、版本位信号逻辑和新的区块 commitment 结构。
- BIP-143:定义 v0 Witness Program 的签名验证方式,引入更高效的 sighash 计算。
- BIP-144:扩展 P2P 协议消息格式,允许节点在兼容旧节点的同时传递含 witness 的交易与区块。
BIP-9:版本位(Version Bits)软分叉部署机制
在 SegWit 之前,软分叉通常采用固定区块高度激活(如 BIP-34、BIP-66),存在风险:若矿工未提前升级,升级高度到达时可能产生孤块链分裂。BIP-9 引入版本位信号:矿工在区块版本号的 32 位字段中设置特定位,表示已就绪支持某提案。当连续一个难度调整周期(2016 个区块,约 2 周)中信号比例超过阈值,该提案进入锁定(Locked-in)状态,再经过一个周期后自动激活(Active)。
4.5.2 隔离见证(SegWit)的技术本质
核心设计动机
传统比特币交易中,签名数据(scriptSig)与交易金额、输入输出等核心数据被混在同一结构中,导致三个相互关联的问题:
- 交易可锻性(Transaction Malleability):签名数据的微调会改变交易哈希(txid),破坏依赖 txid 的链下协议。
- 协议升级困难:签名验证逻辑与交易结构紧耦合,扩展新脚本类型需涉及全局共识规则。
- 区块容量瓶颈:签名占交易体积的约 60%,但旧规则对"交易数据"与"签名数据"一视同仁,无法灵活定价。
隔离见证的本质是结构重组:将签名数据从交易体中剥离,移入一个独立的 witness(见证)字段。
graph LR
subgraph 传统交易结构
tx_in1["输入1:txid + vout + scriptSig(签名)"]
tx_out1["输出1:金额 + scriptPubKey"]
end
subgraph SegWit 交易结构
sw_in1["输入1:txid + vout +(空脚本)"]
sw_out1["输出1:金额 + scriptPubKey(witness program)"]
w1["Witness:签名 + 公钥"]
end
style tx_in1 fill:#fdd
style w1 fill:#dfd
两种交易 ID 的区分
SegWit 引入两套哈希标识,解决可锻性的同时保持向后兼容:
| 标识符 | 覆盖范围 | 用途 |
|---|---|---|
| txid | 交易的非 witness 部分(传统字段) | 旧节点可见,用于链上 txid 索引、区块内的 Merkle 树 |
| wtxid | 完整交易(含 witness 数据) | 新节点间同步完整交易,用于 witness 的 Merkle 树根校验 |
用公式精确描述:
其中 dSHA256 表示双重 SHA-256 运算:。
这意味着:即使攻击者修改了 witness 中的签名字节,txid 仍然保持不变,而 wtxid 会变化。依赖 txid 的链下合约因此获得稳定性。
向后兼容机制
旧节点只解析到传统交易字段时会看到:输入的 scriptSig 为空,输出的 scriptPubKey 是 OP_0 + 20 字节。从旧节点的视角,这笔交易满足"脚本执行成功",因此会被视为有效并进入区块。然而旧节点不能验证 witness 签名的真伪——这在 SegWit 激活后的软分叉规则下不是问题,因为一旦绝大多数算力已升级,包含无效 witness 的区块会被新节点拒绝,进而在最长链竞争中落败。
graph TD
A[旧全节点<br/>不识别 witness] -->|看到 P2WPKH 输出| B[认为 anyone-can-spend]
D[新全节点<br/>识别 witness] -->|要求完整 witness| E[验证签名真伪]
D -->|见证验证失败| F[拒绝区块交易]
E -->|最长链共识| G[无效交易无法被包含进有效链]
B -.-> G
这就是软分叉的精髓:旧规则的有效集与新规则的有效集保持前向兼容——新规则是旧规则的子集收紧。
4.5.3 交易可锻性(Transaction Malleability)漏洞
交易可锻性的核心:攻击者可以修改签名数据(保持交易语义不变),却改变交易的 txid。
在传统交易中,scriptSig = 签名 + 公钥。txid 是对包含 scriptSig 的整个序列化交易做双重哈希。由于签名存在多种合法 DER 编码变体(如 r/s 的前导零、SIGHASH 标志的编码差异),攻击者可以:
- 截获一笔真实交易
- 找到一个合法的替代签名编码,使脚本验证仍通过
- 广播这个新编码的版本——txid 变了,但支付的语义完全没变
这对依赖 txid 的链下协议(如闪电网络的交易委托)是毁灭性的:链下协议锁定的是某个具体 txid,攻击者却广播了不同的 txid,导致链上结算与链下状态脱节。
4.5.4 TypeScript 从零实现:SegWit Weight 计算与区块容量
SegWit 引入 Weight(权重)单位重新定义区块大小:
其中:
base_size= 不含 witness 的序列化字节数total_size= 含 witness 的完整字节数- 权重上限 4,000,000(此前为 1,000,000 字节)
/**
* SegWit Weight 与区块容量计算
* 纯 TypeScript 从零实现,无外部依赖
*/
/** 计算单笔交易的 weight 与 vsize */
function computeWeight(
baseBytes: number, // 不含 witness 的序列化字节数
witnessBytes: number // witness 字节数
): { weight: number; vsize: number } {
const totalBytes = baseBytes + witnessBytes;
// SegWit 规则:weight = base*3 + total
const weight = baseBytes * 3 + totalBytes;
// vsize = ceil(weight / 4)
const vsize = Math.ceil(weight / 4);
return { weight, vsize };
}
// ---- 演示 ----
// 典型 P2WPKH 交易(1 输入 2 输出):
// base ~138 字节(不含签名),witness ~72+33=105 字节
const demo = computeWeight(138, 105);
console.log("P2WPKH 交易:");
console.log(` weight = {demo.vsize}`);
// 传统 P2PKH 交易:签名在 scriptSig,base 本身就含签名
const legacy = computeWeight(250, 0);
console.log("传统 P2PKH 交易:");
console.log(` weight = {legacy.vsize}`);
// 理论满 weight 区块(4,000,000)
const blockBase = 1_000_000;
const blockWitness = 4_000_000 - blockBase * 3;
const block = txWeight(blockBase, blockWitness);
console.log("理论满 weight 区块:");
console.log(` total weight = ${block}, 符合 4M 上限`);
/** SegWit weight 计算(完整版) */
function txWeight(baseSize: number, totalSize: number): number {
return baseSize * 3 + totalSize;
}运行结果:
P2WPKH 交易:
weight = 657, vsize = 165
传统 P2PKH 交易:
weight = 1000, vsize = 250
理论满 weight 区块:
total weight = 4000000, 符合 4M 上限可以看到:同样的 1 输入 2 输出,P2WPKH(签名移入 witness)的 weight(657)显著低于传统 P2PKH(1000)——因为 witness 数据按 1 倍计重而非 4 倍。这正是 SegWit 在不改变 1MB 基础区块限制(权重上限 4M)的前提下,让实际可容纳交易数提升约 1.7 倍的原因。
本节要点
- BIP 是比特币升级的标准化流程,分为 Standards / Informational / Process 三类,生命周期包含草案到最终的多阶段评审。
- BIP-9 版本位机制让软分叉通过矿工信号而非固定高度激活,降低了孤块分裂风险。
- SegWit 通过将签名移入独立 witness 字段,用 txid/wtxid 双 ID 修复交易可锻性,并以软分叉方式向后兼容旧节点。
- Weight 单位重新定义了区块容量(4M weight ≈ 1M base + 3M witness),签名数据被赋予更低的价格。
- 软分叉 = 新规则是旧规则的子集收紧,旧节点仍认可新规则产生的区块。
评论
0评论加载中…