把区块哈希装进一个合约:EIP-210 的 2017 年蓝图 图 1
把区块哈希装进一个合约:EIP-210 的 2017 年蓝图 · 图 1

EVM 里有条性格别扭的指令:BLOCKHASH。合约问它’第 N 块哈希是什么’,它只肯回答距离当前块不到 256 块的问题,再早的一律回零。而且这个读数既不在状态树里、也不在区块链上单独存一份,得靠每个客户端各自维护一套历史哈希缓存和回溯逻辑。EIP-210 在 2017 年 2 月 10 日给这团别扭画了张改造图:起草人 Vitalik Buterin,状态 Stagnant(停滞)。方案是把区块哈希写进状态——在地址 0xf0(十进制 240)放一段特设代码,让哈希查询变成一次普通合约调用。

蓝图怎么运转

提案的机制分两半。写的一半:从激活块起,每个区块在处理任何交易之前,先由系统发起一次内置调用——发起者是保留地址(二的一百六十次方减二那个特殊账户),目标是 0xf0 合约,数据字段装着上一个块的哈希。合约收到后把值存进存储:哈希落在哪个槽位由区块号决定——区块号写成二百五十六进制,商决定页、余数决定页内位置,每块至多做几次存储写入,页与页之间靠’本块只写余数为零那一格’的规则自然接力。读的一半:BLOCKHASH 指令本身改成对同一合约发起一次调用(不是交易),合约沿同样的二百五十六进制路径回查;超过二百五十六层间接跳转还找不到,说明超出维护窗口,返回零。配套的价格调整写明 Gas 从二十提到八百,承认合约代码路径比底层数组贵。

为什么要这么折腾

提案的动机页给了两层理由。工程层:哈希查询从此不再是’隐含状态’——技术上算状态、却不进状态树的灰区数据,改写成普通存储后,协议定义变干净,四种客户端各写各的回溯逻辑也消失了。结构层:这页更妙。按这个布局,区块 N 不仅记着 N-1 的哈希,还隔页指着 N 减去二百五十六、六万五千五百三十六……的哈希,链条之间多出大量’跨越很远的直连边’。轻客户端同步时不必再顺着一格一格往回走两百多级台阶,跳跃指针让初始同步的下载量大幅下降——这是提案里唯一带远期收益的一笔。

和今天的方案差在哪

这个蓝图没有上线:它原本挂在君士坦丁堡窗口,最终停在草稿。想同一件事的人没散场:2025 年 5 月的 Pectra 升级用 EIP-2935 把最近一段历史区块哈希放进了状态里的保留系统账户;想把 BLOCKHASH 指令本身改成直读这段状态的 EIP-7709 则仍未定稿——蓝图的核心动作以拆分的方式部分兑现了。对比两份图纸,路线分野清楚:210 用一段现场编写的合约代码充当索引器,读写都走 CALL 的开销;2935 把同样的数据直接规定为状态里的保留账户字段,机器认格式,不认代码。210 的聪明在合约化——逻辑可见、规则可议;它的落选也在合约化——为验证一段写死注入的代码承担永久维护义务,不如一纸格式规定来得省心。

一条直觉账

旧世界里,历史哈希不在状态树里,每个客户端要在自己的数据库角落维护一段应答缓存,查得越远要求节点留的数据越厚,而窗口外的答案一律是零——这解释了一个常见困惑:为什么智能合约做’远期抽签’或’历史锚定’不能靠 BLOCKHASH,只能依赖链下喂数或专门预言机。210 许诺的世界把窗口拉到理论无限,靠的是页式索引的摊销:每块几次存储写,换来全历史可读。今天 2935 兑现的正是这个思路的收敛版——历史哈希进了状态、每块多存一份哈希,只是保留窗口取固定长度而非全历史。

蓝图的另一半遗产

值得多说一句的是那个轻客户端伏笔。跨距离直连边的思路本身活了下来:后来几年围绕轻客户端同步的多种设计——从批量哈希承诺到信标链的同步委员会——解决的都是同一个瓶颈:新节点如何在不下载全历史的前提下,用可验证的跳跃指针证明’我接上的这条链确实从创世走来’。EIP-210 的分页索引是这个问题最早的显式解之一,它提醒读者:一条指令的重构,有时是替十年后的架构问题先占一个坑。

快速问答

问:BLOCKHASH 现在的 256 块限制还在吗? 答:可回答的窗口语义保留了很长的岁月,各阶段改动集中在’答案从哪来’:从客户端内存挪向状态,正是要绕开 210 未竟的那一步。

问:0xf0 现在住着谁? 答:仍是无人地址。以太坊为将来预留低位地址的先例不少,蓝图作废后地址原地保留,谁也没再动用。

风险提示:本文为协议机制科普,不构成任何投资建议;提案机制与状态以 EIP 仓库当期文本为准。