同步节点如何拿到访问列表:EIP-8159给eth协议加两种新消息 图 1
同步节点如何拿到访问列表:EIP-8159给eth协议加两种新消息 · 图 1

一个被忽略的同步瓶颈

以太坊的执行层正在把”区块里碰过哪些状态”显式记录下来。EIP-7928 提出的区块级访问列表(Block Access List,简称 BAL)把整个区块执行时读写的地址、存储槽、余额、随机数和代码变化全部列成一张表。有了这张表,节点可以做三件事:并行预读磁盘、并行执行交易、甚至不解码交易内容直接应用状态更新。但一个新节点在同步历史区块时,这张表从哪来?如果只能靠自己重新执行一遍每个区块,那前面说的加速全都落空。EIP-8159(2026年2月起草,本文撰写时处于 Review 状态)回答的就是这个问题:给 eth 协议(对应版本号 eth/71)加两种新消息,让 BAL 像区块体和收据一样可以按哈希向对等节点索取。

区块头多出一个哈希字段

要让 BAL 可验证,先得让它被承诺。EIP-8159 在区块头中 requests-hash 之后追加一个 block-access-list-hash 字段,内容是 keccak256(rlp.encode(block-access-list))。规则很干脆:该提案激活之后的区块必须携带这个字段,之前的区块必须没有。节点拿到一份 BAL,算哈希、对比区块头,就能确定对等节点没有偷工减料。

BAL 本身的编码

BAL 是一串按地址字典序排列的账户变更条目,每个条目里分五类清单:存储变化(按槽排序,槽内按发生顺序)、纯读取的存储槽、余额变化、随机数变化和代码变化。每条变化都带一个 block-access-index 数字,标明它发生在区块的哪个位置:0 表示执行前的系统合约调用,1 到 n 对应 n 笔交易,n+1 表示执行后的系统调用与提款。这个索引正是并行执行的关键线索——两个账户的变更若落在互不重叠的交易区间,就可以同时处理。

两种新消息怎么工作

请求方发送 GetBlockAccessLists(消息代码 0x12),带一个请求编号和一串区块哈希;应答方回 BlockAccessLists(0x13),按同样顺序给出对应的 BAL,取不到的位置用 RLP 空串 0x80 占位。BAL 只在提案激活后的区块、且在对等节点的保留期内可得,请求历史更久的区块返回空是正常现象,不是对手节点作恶。单条消息能请求多少份 BAL 由实现自行设定上限。

快速问答

问:这会不会让所有节点都得存全量 BAL? 答:不会。提案明确 BAL 只在保留期内提供,保留期规则由它所依赖的 EIP-7928 定义,节点可以只保留一段时间窗口。

问:为什么要单独发消息,而不是把 BAL 塞进区块体? 答:提案的取舍是——BAL 体积不小,塞进区块体会加重每条传播路径的负担;单独按需请求,只在同步这类确实需要的场景付费。

一条判断线

看这类 p2p 协议扩展,抓三个问题就够:数据被什么哈希承诺、向谁请求、取不到时如何区分”没有”和”作弊”。EIP-8159 三样都给了明确答案,这也是它进入 Review 阶段的原因。

一次同步的完整旅程

把新节点从创世附近一直追到链头的过程拆解开,就能看清这个提案省了什么。今天的同步节点拿到一个区块体,要顺序做完以下动作才算认识这个区块:把每笔交易的发送方地址、碰过的每个存储槽全部在执行中撞出来,撞上冷数据就发起一次磁盘查找。区块级访问列表把这份”碰过什么”的清单提前摊开,节点于是可以先并发发起所有磁盘读取,再并行执行交易,甚至对不涉及本地账户变更的部分直接应用状态增量而不必逐笔重放。EIP-8159 补的正是最后一环:清单得能随区块一起从网络里取到。一次典型的请求是同步节点发出若干区块哈希,收回应答,逐份算哈希比对区块头,通过就入库并立刻用在新块处理上。取不到时节点退回旧路径,功能不受影响,只是慢。

它和收据中继的区别

有人会问:收据和日志不也是”区块处理结果”吗,为什么不能顺路带上 BAL?区别在于消费者。收据服务于钱包和索引器的历史查询,体积小、格式稳定、被无数工具解析;BAL 服务于执行层自身的加速,随状态模型演进可能反复变动格式。把它做成独立消息、由区块头哈希承诺,就允许它在不改动区块体结构的前提下独立演进——这也是提案不把 BAL 塞进区块体的核心理由。

风险提示:本文为协议提案的科普介绍,EIP-8159 截至撰写时未在主网激活,具体规则以提案原文和最终客户端实现为准;协议演进存在变数,不构成任何投资或技术选型建议。