术语表 /开发者参考
MSG_WITNESS_BLOCK
- MSG_WITNESS_BLOCK 是什么?
- 见证区块清单类型是支持隔离见证的节点以扩展序列化格式请求区块的方式,区块附带所有签名,而不是将其剥离。
规定于 BIP-144。
两个节点可以持有同一个区块,却对它有多少字节意见不一。MSG_WITNESS_BLOCK 的代码为0x40000002,是在普通区块请求上加了见证位,自隔离见证于2017年8月24日在区块481,824激活以来就一直存在。如果您运行自己的节点,这就是用来获取签名的请求,您的设备需要这些签名才会信任这条链。
运作方式
Bitcoin Core 保留了同一个区块的两种写出方式,并根据请求方的不同在两者之间做出选择。
见证标志是单个高位0x40000000。把它加到区块清单类型(即2)上,就得到0x40000002。BIP144 同时引入了这个标志和服务位 NODE_WITNESS(值为8),节点在其 version 消息中通告该服务位,表示自己可以提供更完整的数据。该标志只会出现在 getdata 请求中。区块通告以普通区块清单的形式传播,因为通告只是一个哈希,而无论哪种方式,哈希都相同。
最后这一点正是两种序列化格式得以并存的原因。区块头所承诺的默克尔根由 txid 构建而成,而 txid 是在去除见证数据的交易上计算出来的。剥离所有签名后,该区块的哈希仍是同一个32字节的标识符。见证数据则另行承诺,位于 coinbase 交易的某个输出中,该输出的脚本长度至少为38字节,以四字节标签0xaa21a9ed 开头,后接32字节的见证默克尔根。
两者的差别体现在大小上。区块的上限是4,000,000权重单位,按剥离后大小的三倍加上完整大小来计算,这使得装满见证数据的区块在网络传输中可接近4 MB。区块774,628于2023年2月1日被挖出,大小约为3.96 MB,几乎全部是位于见证空间的一份铭文。把这条权重公式倒推回去,如此大的区块在剥离后的形式中几乎所剩无几。请求旧版序列化格式的旧节点只会收到骨架,拿不到任何有效载荷,这正是此类节点被视为无法验证当前区块的原因。
在哪里会遇到它
无需阅读任何源代码,有两个地方可以看到 MSG_WITNESS_BLOCK:节点自身的日志和它的对等节点统计信息。
以 net 调试类别启动 bitcoind,在整个初始区块下载期间都会看到 getdata 行不断滚动,每一行都带有见证标志,因为现代节点只从支持见证数据的对等节点获取区块。getpeerinfo RPC 按消息类型分别列出发送和接收的字节数,因此很容易观察到区块流量在同步过程中占据主导。Bitcoin Core 23.0增加了 getblockfrompeer,它向指定的某个对等节点按哈希请求某个特定区块,取回的是见证形式的区块。
修剪节点使情况更为复杂。启用修剪的节点(允许的最小设置为550 MiB)会通告 NODE_NETWORK_LIMITED,只提供最近的288个区块,大约相当于两天的历史数据。如果向其请求更早的区块,则不会返回任何内容。
对购买和持有比特币的人来说,含义很直接。自行验证区块链,就意味着下载每一个签名并逐一检查。向服务器查询的手机钱包从不发送此请求,从不接触见证数据,屏幕上显示的余额只能听信他人的说法。
MSG_WITNESS_BLOCK vs MSG_BLOCK
MSG_BLOCK 请求的是去除签名的同一个区块,如今属于旧版请求。两种类型都以相同的哈希指定区块,并且都以 block 消息作答。区别在于每笔交易内部是否包含标记字节、标志字节和见证栈。对于近期的区块,请求 MSG_BLOCK 的节点连其中的一笔隔离见证支出都无法验证,因此 Bitcoin Core 只把这种形式留给从未通告 NODE_WITNESS 的对等节点。