协议演进 / BIP/比特币改进提案 / BIP-157
BIP-157
全节点为每个区块生成确定性紧凑过滤器供轻客户端下载比对,命中才下载整块,取代把过滤器交给全节点的 BIP-37 模式。本 BIP 目前处于已部署状态。
一、档案卡
| 编号 | BIP-157 |
|---|---|
| 标题 | Client Side Block Filtering |
| 作者 | Olaoluwa Osuntokun <[email protected]>, Alex Akselrod <[email protected]>, Jim Posen <[email protected]> |
| 指定日期 | 2017-05-24 |
| 层级 | Peer Services(对等服务) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已部署) |
| 依赖文档 | Requires: BIP-158 |
| 阅读版 | https://bips.dev/157 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki |
二、放在哪一族
轻客户端协议一族,是对 BIP-37 的反向重构。BIP-37 的模式是:轻客户端把自己的布隆过滤器发给全节点,全节点替它挑出匹配的交易。BIP-157 把方向倒过来:过滤器由全节点按块确定性生成、向所有人公开供应,筛选工作回到客户端自己手里做。
它与 BIP-158 是一对搭档,且依赖关系写进了文件头:BIP-157 定义协议流程(怎么索取、怎么验证过滤器),并 Requires BIP-158;BIP-158 定义过滤器本身的结构(装什么数据、怎么编码压缩)。只有 BIP-157 而没有具体的过滤器类型,协议是空的;原文因此把最初的过滤器类型放在 BIP-158 中单独定义。
原文在批评 BIP-37 的节点 DoS 问题时还引用了 BIP-111(NODE_BLOOM 服务位)所记录的背景,可一并参照。
三、它要解决什么
轻客户端的诉求是:不下载、不验证全部数据,也能读到与自己相关的链上交易,并尽量少信任对等节点、少耗带宽与存储。它的做法通常是先同步全部区块头、验工作量证明、跟随最长工作量证明链,再只取与自己有关的数据。
当时通行的轻客户端协议 BIP-37,原文列了三类已知的毛病:
- 隐私近乎为零:客户端要把盯着的地址、未花费输出等信息编成布隆过滤器交给全节点。原文引用的研究结论是,多数现成实现给钱包与应用的隐私保护实际上“virtually zero”——过滤器在隐私与误报率之间无论怎么调参,都要向对端交出大量信息;
- 安全可被蒙骗:恶意全节点可以干脆漏掉关键数据而极少被发现。对闪电网络客户端这类必须对某些链上事件及时作出反应的应用,这种遗漏不可接受;
- 全节点被反噬:用心构造的布隆过滤器能让诚实全节点付出可观的 I/O 与 CPU 代价,构成对全节点的拒绝服务向量,反过来让节点运营者不愿再支持该协议。
新协议的解法是把关系反过来(见第二节):全节点生成确定性过滤器,客户端下载过滤器后在本地比对,命中才下载整块。确定性带来三个好处:过滤器只需构造一次并存盘,供应成本低,消除了 BIP-37 式的不对称消耗;客户端能自行校验过滤器的正确性,比检查“对方有没有漏发”容易得多;整块可以从任意来源下载,没有任何单个对端能掌握客户端到底关心什么,隐私更好。
四、规则本身
4.1 过滤器类型与服务位
为兼顾可扩展性与体积,协议允许多种过滤器类型:类型决定过滤器里装哪些区块数据、以及构造与查询的方法,每种类型以一个字节的代码标识。全节点为每个区块、为每种自己支持的类型各生成一个过滤器,并可用服务位宣告自己支持哪些类型。最初的类型由 BIP-158 定义,并分配了一个服务位来宣告对它的支持。
4.2 过滤器头:一条可以自查的承诺链
设计借用了区块头的“headers-first”思路。如同区块头以默克尔承诺绑定块内交易,原文定义过滤器头(filter header)来承诺区块过滤器,且每个过滤器头还承诺前一个过滤器头:
- 某个过滤器的规范哈希,是其序列化字节的双重 SHA256;
- 过滤器头是 32 字节,等于“过滤器哈希拼接前一个过滤器头”再作双重 SHA256;
- 创世块所用的“前一个过滤器头”定义为 32 字节全零。
客户端可以先把整条链的过滤器头下载并核对,再下载过滤器本体。若多个对等节点给出的过滤器头链不一致,客户端能定位到最初分叉的那一个块,下载该整块、自行算出正确过滤器,从而判定哪个对端在作恶或出错。原文结论是:只要至少有一个诚实对端,轻客户端就能识别出正确的区块过滤器。
4.3 新增的六条消息
协议新增三对请求/应答消息(字段从简转述,细节以原文为准):
getcfilters/cfilter:按过滤器类型、起始高度与截止区块哈希,索取一段区块的过滤器本体;一段的跨度必须严格小于 1,000 个块,应答逐块按高度顺序各发一条cfilter;getcfheaders/cfheaders:索取一段区块的可验证过滤器头,跨度必须严格小于 2,000 个块;应答不直接罗列每个过滤器头,而是给一个前置过滤器头加一串过滤器哈希,客户端据此自行推导出整串过滤器头,并能校验它们之间的绑定关系;getcfcheckpt/cfcheckpt:索取按固定间隔抽样的过滤器头检查点——即高度为 1,000 的正倍数的那些块的过滤器头。客户端可借检查点把整条链切成若干段,从不同对端并行下载并逐段核对。
共同纪律:对端未宣告支持所请求的过滤器类型时不应发送这类请求;收到不支持的类型的请求可以不回应;请求中的截止哈希必须是接收方已知的链上区块,未知则不应回应。
4.4 全节点如何运作
支持本 BIP 的全节点应把过滤器当作区块链的一份附加索引:每接入一个新块,就为所有支持的类型生成过滤器并持久化保存;启动时若发现缺失,应从创世块到链尖重建索引。检查点过滤器头应常驻内存,以免 getcfcheckpt 请求引发大量随机磁盘读取。
关键纪律:节点不应在收到请求时才临时现算过滤器。从大块现算小过滤器的不对称消耗,正是 BIP-37 式 DoS 的翻版,本协议明确要避免。节点在生成并保存某块的全部过滤器后,可以裁剪该块的原始数据。
4.5 轻客户端如何运作
原文给客户端的推荐流程是:
- 先用标准 headers-first 方式从对端同步完整的区块头链,并断开链上工作量明显落后的对端;
- 再下载并核对所需全部过滤器头——可先用
getcfcheckpt取每 1,000 块一个的检查点,再分段并行取头并与检查点核对;除非连的是受信对端,否则应连接多个支持该类型的出站对端以对冲收到错误头的风险; - 若不同对端给出的过滤器头冲突,按 4.2 的办法定位第一处分歧、下载整块重算,并封禁发错头的一方;
- 过滤器头全部核实且无冲突后,再逐块下载过滤器本体,逐一校验其与对应过滤器头的绑定关系,发错过滤器的对端同样应被封禁;至少应持久保存最近 100 个块已核实的过滤器头(或自选的终局深度),以便重启后与新对端给出的头比对;
- 真正需要整块时,应从随机选出的出站对端下载(甚至可以是 不支持本 BIP 的对端),以减少因交易关联分析造成的隐私损失。
原文 Rationale 还记下了一个被放弃的替代方案:让区块本身在共识层包含对过滤器的承诺,轻客户端便可凭区块头直接验真——代价是要动全网共识规则;本 BIP 选择只在 P2P 层解决,全节点生成过滤器属于自愿的附加服务。
五、谁必须动
普通持币人(轻钱包用户):不必手工操作,但受益方式变了:钱包不再把自己的关注对象编成过滤器交出去,而是把每块的过滤器拿回来自己筛。
钱包与轻客户端开发者:本 BIP 的主要实现方:同步并核对过滤器头链、多对端交叉验证、冲突时下块重算并封禁作恶对端、本地比对过滤器、命中后随机选源下载整块。
全节点:自愿选择是否支持:预先生成并持久化各类型过滤器、按新消息供应过滤器与过滤器头,并遵守“不临时现算”的纪律。不支持的节点照常运行,只是不能为这类轻客户端服务。
共识层:完全不动。过滤器与过滤器头都不进区块、不进共识;它们是全节点在链外维护的索引与承诺。
六、现在算不算数,以及一个常见误读
状态为 Deployed(已部署)。按 BIP 体系的用法,这表示该轻客户端协议已被实际部署进运行中的实现,与 BIP-158 的过滤器格式成对使用。需要留意它的定位:这是一种可供钱包选用的同步模式,不是每个节点都必须提供的服务——全节点是否生成过滤器是自愿的,轻客户端能否用得上,取决于它连到的对端是否支持。
常见误读:
“用了 BIP-157,轻客户端就是把验证工作外包给全节点,必须信任它发的过滤器。”
不对,这正是它与 BIP-37 的根本区别。过滤器是确定性的:任何人对同一个区块都会算出同一个过滤器。客户端先拿到互相绑定的过滤器头链,又能从多个对端交叉比对;一旦有分歧,下载整块亲手重算即可当场判定谁在说谎,并把对方封禁。原文给出的保证是——只要至少连着一个诚实对端,客户端就能识别出正确的过滤器。信任被换成了可核查,而不是被简单地转移。
七、延伸
- 阅读版:https://bips.dev/157
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki
- 相关:BIP-158 紧凑区块过滤器(本篇所依赖)、BIP-37 连接布隆过滤、BIP-111 NODE_BLOOM 服务位
- 仓库总目录:https://github.com/bitcoin/bips
