Arbitrum 的三套时钟:block.number、天文数字 gas 上限与没有交易就没有块 图 1
Arbitrum 的三套时钟:block.number、天文数字 gas 上限与没有交易就没有块 · 图 1

同一条链上,区块号其实有两套账:链自己的编号,和智能合约里 block.number 返回的数字。在 Arbitrum 上这两套账几乎对不上号,而且合约看到的那个值指向的是一层祖先链的块。再叠上两个现象——每个块显示的巨额 gas 上限,以及没有交易就没有块——一条 L2 的时间语义与主网有系统性的偏差。Arbitrum 官方文档把这三件事合并在一页里讲清楚。

block.number 返回的不是本链块号

官方文档写明:在 Arbitrum 智能合约里读 block.number,得到的值是序列器收到这笔交易时所在的第一条非 Arbitrum 祖先链的块号,而且只是接近、未必精确。对以太坊上的 Arbitrum 二层,或者架在 Arbitrum 上的三层链,那个值是以太坊的块号;对结算到其他链的链,则是那条父链的块号。链自己的块号从创世零号起严格递增,与以太坊的编号完全脱钩。两个编号之间是多对一关系:一个以太坊块里可以装进多个 Arbitrum 块,但一个 Arbitrum 块不可能跨两个以太坊块存在。

由此得出的时间纪律很直白:任何合约对块号与时间戳做的假设,在以小时计的长期尺度上大体可靠,在分钟尺度上不可靠——这条建议本来就同样适用于以太坊本身,到了 L2 上只是更严格。需要一层历史区块哈希时,EIP-2935 引入的历史存储合约在 Arbitrum 上也可以用来读过去的二层块哈希,行为与主网同一地址的合约同形。

上千兆的天文数字与三千二百万的真实上限

说明图

用浏览器看 Arbitrum 的块,gas 上限常显示为一个约一千万亿的天文数字。官方文档解释了这个假象的来源:一个块的 gas 上限被定义为块内所有交易 gas 上限之和,而每笔交易的配额里还要计入在父链发布数据的花费,为容纳父链成本波动,协议给每个块指派了一个人为的大数。执行层面真正有效的配额被压在三千二百万以内。换句话说,查询到的巨大上限是二维计费(执行费加数据费)在单一字段上的投影,实际执行成本远低于面值。需要精确核算时,官方推荐用 NodeInterface 的气体估算组件把两维费用拆开算。

没有交易就没有块

Arbitrum 的出块完全由使用量驱动:ArbOS 与序列器共同决定块从哪里切开,而块的产生取决于有没有交易进来。活跃的链上块大致稳定产出,冷清的链上块会零星出现。这对依赖固定出块间隔的逻辑意味着,块号差不等于时间差,空转时段的块号不会前进。把事件排序、定时任务或倒计时写进合约前,先想清楚你的假设建立在哪个时钟上——是链自身稀疏的块号,还是每块携带的时间戳,还是背后以太坊那约十二秒一格的稳定心跳。三者只有在长期尺度上才大致同步。

对合约写作者的落地清单

把上面的规则翻译成可执行的检查:凡是用 block.number 做倒计时的合约,在 L2 上应改为用 block.timestamp 与显式时钟源;凡是用块号差做速率限制的逻辑,先问清楚块号差在冷清时段会不会干脆不增长;凡是从 RPC 读最新块再推断费用的代码,要接受该块可能诞生于几十秒前的事实,序列器软确认与以太坊收录之间存在时间差。对跨链复用的合约库,这些假设往往埋在最底层的工具函数里,做一次全文检索比逐行审更快。另一个实用技巧是用 NodeInterface 的气体估算组件替代朴素的 eth_estimateGas,它把执行维度和父链数据维度分开返回,预算更接近真实扣款。

风险提示:本文为技术机制说明,不构成投资建议;参数与实现可能随升级变化,请以官方文档为准。