Monad 的储备余额是什么:异步执行链为什么要预留一笔气体余量 图 1
Monad 的储备余额是什么:异步执行链为什么要预留一笔气体余量 · 图 1

Monad 把执行从共识的关键路径上摘了下来:节点先对交易的顺序达成一致,之后才去执行这些交易。执行必须在随后的 k 个区块内完成,官方文档当前把 k 写为三。好处是出块节奏不再被执行时间拖住,代价是一个新问题:共识给一个区块盖章时,手里只有往前数 k 个区块的执行状态。储备余额(Reserve Balance)机制就是为补上这个时间差而设计的。

滞后的账本会留下什么窟窿

官方文档给了一个直观例子:共识正在验证第四块,里面有一笔爱丽丝转给鲍勃一百个币的交易;可共识能看到的最新状态只到第一块,上面记着爱丽丝有余额一百一十个。单看这份旧账本,这笔交易余额充足,可以直接放行。但爱丽丝可能早在第二块里就把钱花掉了——共识还没执行到那一块,根本看不见。放任这种交易进块,就是一条零成本耗尽网络的拒绝服务攻击路径:用一笔旧余额反复开新版,让所有节点执行一堆注定失败的交易。

最朴素补救是静态检查:把第一块以来所有转账交易翻一遍,只要爱丽丝中间有任何花掉余额或气体的交易,就拒绝第四块。文档指出这条路线有两处失手。其一过严:爱丽丝可能在前两块里通过合约执行收到过进账,实际余额足够,仅凭静态流水拒绝会误伤正常用户。其二在 EIP-7702 下不安全:账户一旦把代码委托给合约,任何第三方提交的交易都可能从爱丽丝的账户里划钱,这些支出不出现在她自己的交易流水里,静态检查既看不到也拦不住。

两头各立一条规矩

机制示意图

储备余额的解法是把同一笔预留钱在共识与执行两侧各立一条规矩。执行侧:交易的支出被拆成气体花费与转账花费两部分,执行结束时(退款前),账户余额若从上方跌破预留线就该笔交易回滚——对普通发送者,允许因支付气体花费而低于预留线,对非发送者被扣款的情形则不得低于交易开始时余额与预留线中的较低值。共识侧:每个账户在途交易(进入不足 k 块的区块的交易)的气体花费共享一份预算,预算等于预留线与滞后状态余额中较低的一个;验证第 n 块时逐块核算这份预算,超支即判区块无效。

官方文档给这份预留线起的参数名是 user_reserve_balance,当前取值十枚 MON,并在页面上自注 k 个区块折合约一点二秒。文档同时承认基础规则太苛刻:账户永远不能花光余额,余额低于十枚的账户甚至发不出任何成功交易。

空仓例外与委托账户

于是文档补了一个空仓交易(emptying transaction)例外:发送者账户未处于委托状态、过去 k 块内没有发出过交易、也没有人替它提交过委托或解委托请求,那么这一笔允许直通,把余额花到底。换句话说,一个长期未动的小账户每 k 块能获得一次清空余额的机会。文档特意提醒,哪怕账户本来就没委托,只要 k 块内出现过解委托请求,这次也不再享受例外。

对已委托账户,规则只剩一条硬线:只有当一笔交易既扣减余额、又让最终余额跌破预留线时才回滚;余额增加或持平的交易不受影响。这也是为什么代付气体工作流里那种几乎不主动碰原生币的委托账户照常工作,而一旦有代码试图从一个余额六枚的委托账户里划走一枚,交易就会撞上回滚。

由此还会产生一个用户端容易困惑的现象:交易被成功收录进区块、收据却是失败回滚,而且气体照付。在异步执行的语境里这是储备预算机制的正常输出——共识按滞后账本判定这笔交易有钱付气体所以收了进来,执行追上来之后才发现它其实花的是已经不在的钱。

边界怎么看

储备余额不是资金托管,也不是最低存款要求,它是共识与执行之间的一份协同合同:约定执行侧永远守住这条线,共识侧才敢在看不到最新账本时先签收据。十枚 MON、k 等于三都属于文档标注的当前参数,协议迭代会调整,核对时以官方文档为准。评估异步执行链时值得问的三个问题是:滞后面板多宽、预留线多高、低余额账户有没有豁免通道——这三项共同决定了普通用户会在多大概率上碰到收录但回滚这类边缘体验。

风险提示:本文只解释机制,不构成任何投资建议;参数与状态以官方文档与链上数据为准。