合约怎么知道当前区块的基础费:BASEFEE 指令(EIP-3198) 图 1
合约怎么知道当前区块的基础费:BASEFEE 指令(EIP-3198) · 图 1

一个参数从「只有钱包看得见」到「合约也看得见」

EIP-1559 让每个区块有了一个由协议自动计算的「基础费」(base fee):区块拥挤它就上调,冷清它就下调,每块按不超过 12.5% 的幅度缓步移动。在这个数字存在的头一年里,它只出现在交易验证逻辑和 RPC 返回值里——钱包能读,合约读不到。合约想知道 Gas 多少钱,只能靠用户传入参数或翻某本预言机喂价,两者都有被人操纵的时间差。

EIP-3198 补上了这块拼图:新增一条 BASEFEE 指令(字节码 0x48),执行时直接把当前区块的基础费压上栈顶。提案由 Vitalik Buterin 等人参与撰写,随 2021 年 8 月的伦敦升级与 EIP-1559 同日在主网激活——两条本就是配套工程:一条定义基础费,一条让程序能查询它。

合约怎么知道当前区块的基础费:BASEFEE 指令(EIP-3198) 图 2
合约怎么知道当前区块的基础费:BASEFEE 指令(EIP-3198) · 图 2

合约拿这个数字能做什么

拍卖类协议是提案里点名的用例。有些机制要求「按 Gas 成本向参与者报销」,如果报销标准由用户申报,就会被报高价薅羊毛;让合约自己读 BASEFEE,报销额与真实费用自动挂钩,中间商没有伪造空间。

另一类是「贵的时候少动、便宜的时候多动」的节奏器:批量结算、清算触发、链上游戏的状态刷新,都可以写成基础费低于某阈值才执行,把不紧急的操作推到深夜 Gas 谷时。还有一类是反身性检查:协议可以用 BASEFEE 估计「攻击者此刻操作的成本」,成本过低时提高奖励门槛,让攻击在经济上不划算。

精度边界:它只是「本块」的一个数

BASEFEE 的读数粒度只有当前区块,这是很多设计翻车的地方。第一,它是块级的平均值,不反映你这笔交易实际支付的总成本——优先费、Blob 费、执行 Gas 用量都另算。第二,智能账户或批处理合约里,同一笔交易内部不同调用看到的是同一个块级数字,它不会告诉你在本块里的排队位置。第三,基础费的调节有界(伦敦升级起,单块变动不超过 12.5%),这个数字既是特性也是限制:它让费用像潮水而不是闪电,但也意味着「读到的数」在下一块仍大体成立——反过来说,指望它做秒级价格信号是误用。

和相邻数字的分工

把三个数字摆在一起最不容易混:BASEFEE 是协议在本块强制烧掉的那部分单价,由规则自动算;优先费(tip)是用户之间竞价给验证者的部分,由市场实时定;eth_gasPrice / eth_maxPriorityFeePerGas 这类 RPC 值是节点根据你的内存池情况给出的估算建议。合约内做决策用 BASEFEE,发交易前估价用 RPC,两者的时间尺度和可信来源不同。

一次调用的完整旅程

把 BASEFEE 放进一次真实的智能账户操作里走一遍:某自动定投合约被触发,代码第一步执行 BASEFEE 拿到本块基础费,第二步和预设上限比较——超出就改走「延后一批」的分支,没超出就继续。整条逻辑没有向任何外部请求价格,也没有信任用户传入的参数,账本重放时每个节点都会算出同一个数字,结果完全确定。这就是指令读数与预言机喂价的本质差异:前者是全节点一致的状态函数,后者依赖签发者的时间戳与签名。对追求「任何节点重放必得同一结果」的协议来说,这种确定性本身就是安全属性的一部分。

快速问答

问:L2 上的合约读 BASEFEE 读到的是什么? 答:多数 Rollup 的预置费用机制不同——有的把 L2 基础费做成类似语义,有的直接读常量或 L1 派生的映射值,各家实现不一样。把「以太坊主网的行为」直接套到某条二层之前,先查那条链的费用文档,这比假设兼容更可靠。

问:BASEFEE 会进交易签名吗? 答:它只是执行期的读数,不改变交易字段。EIP-1559 类型的交易签名里写的是你对基础费的上限承诺,而不是对未来值的预测——BASEFEE 指令改变的是合约的感知能力,不是费用规则本身。

风险提示

本文是协议机制科普,不构成投资建议。费用规则与参数随升级变化,涉及成本敏感的智能合约请以当期客户端实现与官方文档为准。