布隆过滤器的两张体检单:36000 字节、50 个哈希与 520 字节元素
早期轻钱包向节点递交一张布隆过滤器,“我只关心命中这张网的交易”。这张网本身是有规格上限的:网眼尺寸、网线粗细、每根针的长度,v31.0 源码里各有一行常量管着。超限的过滤器不会被”修剪”,而是直接把递交它的对端记上一笔。
两条硬线在哪定义
common/bloom.h 里有两个常量:MAX_BLOOM_FILTER_SIZE 为 36000 字节,MAX_HASH_FUNCS 为 50。前者限死过滤器位图本体的体积,后者限死哈希函数个数——两个维度一起决定这张网的误报率与内存占用。构造器还会做一件容易被忽视的事:按期望元素数与期望误报率算出理想尺寸后,用这两条上限封顶,哈希函数个数同样封顶。也就是说钱包自己算出”要 70 个哈希函数”时,实际落地的仍是 50。
节点侧的验收在 net_processing.cpp 处理 filterload 消息的位置:反序列化出过滤器后先跑 IsWithinSizeConstraints(字节数不超 36000、哈希数不超 50),不合格就 Misbehaving,理由字符串是 too-large bloom filter,并断开该连接。在 v31.0 的实现里,一次记账即把该对端标记为不鼓励(m_should_discourage),后续进入静默劝退流程——没有旧版本”攒满 100 分再踢”的中间态。
第三张体检单在 filteradd 上
往已有过滤器里追加元素走 filteradd 消息,单根”针”也有长度限制:追加的数据超过 MAX_SCRIPT_ELEMENT_SIZE(script/script.h 定义,520 字节)直接判坏消息,记 bad filteradd message;追加时节点发现这台对端根本没装过滤器,同样记账。520 这个数字不是过滤器专属,它就是脚本数据对象的通用上限,布隆消息沿用了同一尺度。
对今天的你意味着什么
布隆收款是前隔离见证时代的轻客户端方案,现代钱包更多转向紧凑区块过滤器,但它远没有退场:老牌桌面钱包、一些交易所后端、审计与取证脚本仍在用它。理解三条线的实际用处有四个场景。其一,钱包往过滤器里塞的公钥哈希、脚本哈希、输出点数量失控时,位图会先撞 36000 字节天花板,此时老式客户端的行为是拉高误报率硬撑——你会收到大量不相关的交易,这是误报不是丢币。其二,自建观察节点若不带 NODE_BLOOM 服务位,收到 filterload 会直接断开(同一段代码前半截检查的就是服务位),这解释了为什么关掉布隆中继的节点配老钱包会”连上就掉”。其三,误报率参数不是隐私参数:节点只看到你的过滤器,看不到你”真正想要什么”,但过滤器本身会泄露你监控过哪些哈希。其四,别把追加元素当无底洞,超过 520 字节的整段脚本不是合法的针,只能塞其哈希。
一张自查卡
遇到”老钱包连自建节点不稳定”的报修,可以按四步走:第一步确认节点仍在提供布隆服务位,近年不少发行配置默认不再开;第二步看日志里有没有 too-large bloom filter 或 bad filteradd message 字样,有则问题在钱包塞的过滤器规格,无则继续排查;第三步观察掉线是否发生在提交过滤器之后——时点吻合基本可以断定是过滤器体积或元素长度越线;第四步换用紧凑过滤器类后端做对照实验,两套通道并行观察一周期再下结论。
最后记住一个换算直觉:36000 字节的位图能容纳的”针”,在可接受的误报率下大约对应几千个元素量级。钱包每多用一个地址、每多订阅一段脚本,都在往这张网里加针——网越密,误报越多,节点为你转发的无关交易也越多。布隆收款的成本从来不是免费的,只是把筛选的账单从流量挪到了误报上。
风险提示:涉及收款方案迁移(布隆转过滤器索引、换钱包后端)时,请先用小额度资金演练核对;本文不构成投资建议。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。