智能合约语言里一个函数调用另一个函数,在字节码层面有两种实现路线。一条是纯跳转:保存现场、跳到目标函数入口、回来时再恢复现场,全靠编译器手工搬栈和内存。另一条是正经地用 CALL 指令调用自己:目标地址填本合约地址,让虚拟机正规地开一个执行帧。第二条路干净得多——上下文天然隔离、返回状态干净、静态分析工具看得懂、追踪器能还原调用树,还能缓解嵌套调用对栈深度的消耗。唯一的拦路虎是钱:调用一个地址要先付七百 Gas 的加载费,哪怕那个地址就是自己。EIP-1380 的全文主张浓缩成一句话:当目标地址等于调用者地址时,四类调用指令的价格从 700 降到 40。
七百从哪来,四十又从哪来
七百这个数的出处是 2016 年那次针对冷调用攻击的重定价:把调用费抬高,是为了补偿节点从磁盘加载陌生合约代码的真实开销。提案作者顺着这套逻辑做了个算术——七百与更早的四十之间那六百六十,恰好可以理解为”从磁盘读代码”的部分;而自己调自己时代码已在内存,该付的只剩开执行帧的四十。于是降价不是讨价还价,是把同一套定价公式诚实地应用到被遗漏的场景。
受益的是什么人
直接受益的不是手写合约的散户,而是编译器与语言设计者。Solidity 一类语言长期在内部函数上用跳转,就是因为走调用太贵;一旦价格放行,语言运行时可以更放心地用调用帧实现纯函数,换来上下文隔离——函数之间不再共享可能被污染的内存残留,跨函数内存别名这类老大难缺陷在源头消失。附带的好处链同样具体:反汇编器与链上浏览器能画出真实调用图,审计工具不再把”一大坨扁平字节”当分析对象;静态分析少一大类误报;深层递归的合约离栈深上限更远,因为每个帧只带本层局部量而不是全部历史的现场拷贝。值得注意的是受益主体是编译器这一事实:协议为一种更好的编译策略降价,而不是为某类应用降价,这让它的影响面既深又安静。
风险账本
向后兼容一节写得干脆:老合约只会”变便宜”,不会行为改变。作者提醒了一课历史:EIP-150 那次涨价让依赖固定Gas数值的合约吃过教训,但方向相反的改动冲击更小——依赖费用不变的合约在降费世界里最多多拿到优惠,不会多付钱。真正需要评估的风险藏在另一侧——如果语言全面转向调用式内部函数,每帧开销虽然只有四十,帧数量却在增加,某些极端代码形态的总成本未必单调下降;这属于编译器要精算的工程问题,不是协议层面的阻塞点。
现状与边界
提案停在 Stagnant(停滞),以 EIP 官网当前标签为准。此后 EOF 系列提案走了另一条路:给虚拟机加正规子程序指令,从机制上而非价格上解决同一需求。两条路线殊途同归地证明:内部函数调用的表达问题,协议社区迟早要接招。
快速问答
问:调用自己会扣自己的余额吗? 答:不会。不带金额的调用只建立执行帧,转账只在显式携带价值时发生。 问:四十Gas依据哪份先例? 答:依据重定价前的老调用费——提案把七百拆成”六百六十的读盘加四十的开帧”,四十正是历史价里开帧的那部分。 问:编译器现在怎么绕开这个成本? 答:用跳转加手工现场管理,代价是语言实现复杂、分析工具看不见调用结构。
一条判断线
评估任何”给某操作降价”的提案,先还原它的定价公式:这一笔费用买的是什么资源,场景里这种资源真实消耗了吗?公式对不上的收费,降价就是纠错。
风险提示:本文仅为虚拟机机制科普,不构成任何投资建议。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。