这是一个非常经典的区块链后端开发面试题,考察的是你对 以太坊数据结构 和 RPC 通信成本 的深度理解。
看不懂这个答案,通常是因为不了解 “为什么 eth_getLogs 慢” 以及 “Bloom Filter(布隆过滤器)是个什么神奇东西”。
我用大白话和生活中的例子给你拆解一下。
1. 为什么“笨办法”行不通?
场景
你需要监听 1万个 合约地址的事件(Event)。 区块链每 12 秒产生一个新的区块。
笨办法(直接轮询)
每当新区块出来,你都向节点(Node)发送请求:
“哎,节点兄弟,帮我查查这个新块里,有没有关于这 1 万个地址的日志?”
问题在哪里?
- RPC 请求爆炸:如果你一个一个查,要发 1 万次请求。如果你合并成一个大请求,参数会巨长。
- 节点磁盘 IO 爆炸:
eth_getLogs是一个很“重”的操作。节点收到请求后,必须去它的数据库(LevelDB/RocksDB)里翻阅日志索引。即使这个块里没有任何你关心的交易,节点也得去硬盘里确认一遍“确实没有”。 - 结果:当你要监听的合约变多时,节点会被读废,响应变慢,甚至拒绝服务。
2. 什么是 Bloom Filter(布隆过滤器)?
在不谈技术细节的情况下,你只需要记住它的核心特性:
它像是一个极其压缩的信息指纹。
- 特点 1:如果布隆过滤器说“不存在”,那就绝对不存在。 (100% 准确)
- 特点 2:如果布隆过滤器说“存在”,那“可能存在”,也可能不存在。 (存在误判率)
- 特点 3:体积极小,检查速度极快。
举个生活例子
你在管理一个有 1000 个房间的酒店(区块链),你要找“张三”(你关注的合约)。
- 笨办法 (
eth_getLogs):你挨个敲 1000 个房间的门,问“张三在吗?”。这累死人。 - 布隆过滤器 (
LogsBloom):酒店大堂门口有个公告板。- 规则:如果你姓“张”,就在第 1 行打个勾;如果你名字是两个字,就在第 2 行打个勾。
- 现在你要找“张三”。你先看公告板:
- 情况 A:第 1 行没有勾。结论:张三绝对不在里面。(因为如果在,他肯定会打勾)。-> 直接走人,不用敲门了。
- 情况 B:第 1 行有勾,第 2 行也有勾。结论:张三“可能”在里面。(但也可能是“张四”、“李三”或者“王麻子”碰巧打的勾)。-> 这时候你再去敲门确认。
3. 以太坊是怎么利用这个特性的?
在以太坊中,每个区块头(Block Header) 都有一个字段叫 logsBloom(大小只有 256 字节)。
这个 logsBloom 就是那个“公告板”。它把这个区块里所有交易产生的所有日志的:
- 合约地址 (Address)
- 事件主题 (Topic)
都映射(Hash)进去了。
4. 优化后的流程(话术里的逻辑)
现在你手握 1 万个合约地址,新区块来了:
-
Step 1:只下载“区块头”(轻量级)
- 你只调用
eth_getBlockByNumber(..., false)。这个数据非常小,不用查交易详情,节点返回飞快。 - 你拿到了这个块的
logsBloom(公告板)。
- 你只调用
-
Step 2:在本地算一下(CPU 计算,不耗网络)
- 你自己写代码,把你关注的 1 万个地址,去跟这个
logsBloom比对。 - 判断逻辑:这个块里有没有可能包含我的合约地址?
- 你自己写代码,把你关注的 1 万个地址,去跟这个
-
Step 3:决策
- 结果是“不可能”(绝大多数情况):
- 这 1 万个合约在这个块里都没动静。
- 动作:直接忽略这个块。省下了去请求
eth_getLogs的巨大开销。
- 结果是“可能”(少数情况):
- 布隆过滤器显示命中(可能是真的命中了,也可能是误判)。
- 动作:这时候才发起
eth_getLogs去查详情。就算查回来发现是空的(误判),也无所谓,因为这种次数很少。
- 结果是“不可能”(绝大多数情况):
总结(如何回答面试官)
你可以这样重新整理思路回答,会显得更清晰:
- 痛点:直接轮询
eth_getLogs对节点 IO 压力太大,尤其是监听数万个合约时,大部分区块其实都没有相关交易,查询是无效的浪费。 - 原理:以太坊区块头包含一个
logsBloom字段,这是一个 256 字节的布隆过滤器,它聚合了该区块所有日志的地址和 Topic。 - 方案:
- 我先拉取区块头(轻量请求)。
- 在本地内存中,用我关注的合约地址列表去匹配这个 Bloom Filter。
- 利用布隆过滤器**“说没有就绝对没有”**的特性,我可以安全地跳过 90% 以上无关的区块,完全不需要发起
eth_getLogs请求。 - 只有当 Bloom Filter 提示“可能存在”时,我才去请求完整的日志详情。
- 收益:将大量的网络 IO 和数据库读取(Rpc调用),转化为了本地极快的 CPU 位运算,性能提升非常明显。