ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

EIP-2327 BEGINDATA 操作码解析:用 0xb6 标记合约数据区,重塑 EVM 的 JUMPDEST 分析与静态分析生态

EIP-2327 BEGINDATA 操作码解析:用 0xb6 标记合约数据区,重塑 EVM 的 JUMPDEST 分析与静态分析生态 EIP-2327 BEGINDATA 操作码解析用 0xb6 标记合约数据区重塑 EVM 的 JUMPDEST 分析与静态分析生态【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs导读EIP-2327 是 Ethereum Improvement Proposals 仓库中一项处于 Stagnant停滞状态的 Core 类标准提案它提议为 EVM 引入一个全新的操作码BEGINDATA字节码0xb6用于声明合约字节码的剩余部分均为数据、不可执行。本文以 EIPS/eip-2327.md 为骨架完整还原该提案的动机、规范、设计取舍与测试用例并结合仓库中 EIPS/eip-615.md、EIPS/eip-3541.md 等相关 EIP 进行纵深解读。读完本文你将理解 EVM 解释器如何计算合法JUMPDEST集合、为什么数据区会污染静态分析以及BEGINDATA如何为跳转表jumptable、EOF 演进和跨链代码校验铺路。一、提案概览在合约字节码中划出只读数据区1.1 核心主张BEGINDATA是一个零参数操作码语义非常简洁引入新操作码BEGINDATA它指示合约的剩余字节应被视为数据而非合约代码且不可被执行。提案同时给出了三个硬性规定见 EIPS/eip-2327.md 的 Specification 小节规则语义JUMPDEST 分析提前终止在计算合约合法JUMPDEST时一旦遇到第一个BEGINDATA即停止分析跳转保护任何跳转到大于等于第一个BEGINDATA位置的代码位置都会触发BAD_JUMP_DESTINATION异常执行语义若在执行期间遇到BEGINDATA其语义等价于STOP消耗0 gas此外BEGINDATA之后的数据区依然可以通过CODECOPY与EXTCODECOPY读取且不影响CODESIZE与EXTCODESIZE——也就是说它只改变可执行性边界不改变可读性边界。1.2 提案元信息EIP 编号2327标题BEGINDATA opcode作者Martin Lundfall (MrChico)类型Standards Track / Core状态Stagnant停滞创建日期2019-10-28二、动机被误当代码的数据区与静态分析的困境2.1 智能合约普遍把数据塞进字节码提案的 Abstract 明确指出在合约字节码中直接内联存储数据是一种非常常见的做法典型场景包括构造函数参数constructor arguments部署时拼接在 initcode 之后常量变量constant variablesSolidity 编译后以立即数形式嵌入代码编译器元数据compiler metadataSolidity 生成的 CBOR 元数据块通常位于代码末尾init 阶段中的运行时合约contract runtime创建合约时由 initcode 返回的 runtime code。这些数据与正常指令字节混排在一起而目前的 EVM 解释器在分析代码时无法区分二者——它仍然会对数据区中的每一个字节做JUMPDEST扫描即逐字节判定0x5b是否为合法跳转目标。2.2 数据区带来的三大问题静态分析工具的噩梦分析器必须对数据中的0x5b进行额外判定而实际上这些字节永远不该成为跳转目标反汇编器与区块浏览器的误显示数据区的随机字节会被解释为一堆INVALID操作码导致链上浏览器的反汇编视图一团乱码性能的边际损失JUMPDEST分析需要遍历到代码末尾若提前在BEGINDATA处停止可以省去对数据区的无意义遍历。2.3 跨链代码校验与可扩展性提案的 Motivation 还提到了一个关键的可扩展性场景其他链在链上评估来自以太坊的交易时如果验证代码是否符合某种模式例如 Optimism 项目的做法就不必对数据区做完整的 jumpdest 分析——因为BEGINDATA已经明确告知数据不会被执行因而不必符合该模式。这直接降低了跨链验证的计算成本。三、设计溯源从 EIP-615 的跳转表到独立提案3.1BEGINDATA的老家EIP-615BEGINDATA并非 EIP-2327 的首创。Motivation 明确指出它最早出现在Subroutines and Static Jumps for the EVM即 EIPS/eip-615.md中用于确定合约字节码中**跳转表jumptable**的位置。在 EIPS/eip-615.md 的指令对照表中BEGINDATA对应 Wasm 的tables、x86 的JMP指令族所依赖的跳转表数据区其数据结构定义为BEGINDATA指定从该指令之后到字节码末尾的所有字节都是数据且是不可达代码。EIP-615 为相关指令族分配的字节码如下注意0xb6正是BEGINDATA0xb0 JUMPTO 0xb1 JUMPIF 0xb2 JUMPV 0xb3 JUMPSUB 0xb4 JUMPSUBV 0xb5 BEGINSUB 0xb6 BEGINDATA 0xb7 RETURNSUB 0xb8 PUTLOCAL 0xb9 GETLOCALEIP-615 中JUMPV/JUMPSUBV的跳转向量正是存储于BEGINDATA之后的内联数据JUMPV跳转到向量中的某个JUMPDEST偏移量。向量以 MSB-first、二进制补码、两字节正整数的形式内联存储在 BEGINDATA 字节码之后的jump_targets偏移处。EIP-2327 之所以把BEGINDATA单独拎出来成文是因为它自身就具有独立价值——将数据排除在JUMPDEST分析之外即使 EIP-615 的整套子程序机制不落地这个单点改进依然成立。3.2 字节码0xb6的选择Rationale 说明选择0xb6是为了与 EIPS/eip-615.md 保持对齐避免未来两套提案同时落地时产生字节冲突。这一选择也体现出 EIP 生态中预留字节的谨慎态度——类似地EIPS/eip-3541.md 为了给 EVM Object FormatEOF预留魔法字节直接禁止了以0xEF开头的新合约部署。四、规范细节执行语义与数据可读性4.1 JUMPDEST 分析提前终止EVM 解释器在加载合约时会预先扫描所有0x5bJUMPDEST字节建立合法跳转目标集合。EIP-2327 的规范要求在计算合约合法JUMPDEST的过程中一旦遇到第一个BEGINDATA就停止分析。换言之跳转到等于或大于第一个BEGINDATA位置的任何代码位置都会产生BAD_JUMP_DESTINATION错误。这意味着即便数据区中的某个字节恰好是0x5b它也不会被登记为合法跳转目标——从根源上杜绝了跳进数据区的可能。这与 EIP-615 的验证器伪代码中的处理完全一致其validate_jumps与validate_subroutine两个遍历函数在遇到BEGINDATA时都会break见 EIPS/eip-615.md 附录 A。4.2 执行时语义等价 STOP0 gas若程序计数器PC在执行过程中推进到了BEGINDATA解释器将其视同STOP处理且不消耗任何 gas。Rationale 坦诚地指出这一选择有些武断——备选方案是让执行以 out-of-gas 错误中止。最终选择STOP语义实际上是给数据区一个安静的结束被跳越执行、碰到即停不引发异常退出。4.3 数据区的可读性不受影响规范特意强调了数据区的只读可访问性BEGINDATA之后的字节仍可通过CODECOPY读取自身代码与EXTCODECOPY读取他人代码访问BEGINDATA不改变CODESIZE与EXTCODESIZE的返回值。也就是说BEGINDATA只影响什么可以被执行/跳转完全不影响什么可以被读取。数据区依然是合约的合法数据源——这正是构造函数参数、常量与元数据得以内联存储的前提。五、设计取舍Rationale小结设计决策理由字节码选0xb6与 EIP-615 指令编码对齐见 EIPS/eip-615.md 的 Costs Codes 小节遇到BEGINDATA即 STOP相对温和的终止方式备选方案out-of-gas 中止被放弃作者承认该选择带有一定任意性六、向后兼容性分析现有合约会受影响吗6.1 基本结论提案的 Backwards Compatibility 小节给出的判断是除非现有合约的行为依赖未使用unused操作码否则本提案不会改变任何现有合约。由于合约从一开始就在字节码中嵌入数据从某种意义上说所有合约都使用了未使用的操作码——但只有满足下述条件的合约才会受硬分叉影响数据被组织为执行时可被跳过、且被跳越的形态即数据字节在正常执行路径上会被JUMP/JUMPI越过使得0x5b等字节有机会成为跳转目标。6.2 Solidity 从未生成过此类代码提案明确指出Solidity 编译器从未生成过这种代码结构。因此实际受影响面极小但仍需评估其他方式创建的合约手写汇编、其他编译器产物等是否可能存在这种结构。这与 EIPS/eip-3541.md 的论证思路一脉相承——后者在禁止0xEF开头字节前先对链上约 1808 万个合约做了实证分析确认没有现存合约以0xEF开头。七、测试用例Test Cases虽然提案的 Implementation 仍为 Not yet截至文档状态无参考实现但已给出两组明确的行为级测试用例跳转至数据区失败用例构造一个合约使其跳转到目标X——X的 pc 值高于BEGINDATA操作码位置且X处的字节恰好是0x5b。预期结果该跳转以BAD_JUMP_DESTINATION错误失败。此用例直接验证数据区中的0x5b不被登记为合法跳转目标这一核心规范。执行触达数据区用例构造一个合约使其在执行过程中遇到BEGINDATA操作码。预期结果合约停止执行当前调用帧stop executing the current call frame即STOP语义生效。这两组用例恰好覆盖了规范中静态跳转分析与运行时执行两条路径可作为未来客户端测试套件如 go-ethereum 的 core/vm 测试的基础参考。八、生态影响为后续提案铺路Motivation 在结尾列出了BEGINDATA落地后可能催生的三个方向禁用未使用操作码如 EIP-1712 相关讨论 所提议的一旦数据区被明确标记就可以安全地限制某些未使用操作码的使用跳转表jumptableEIPS/eip-615.md 中的JUMPV/JUMPSUBV依赖BEGINDATA之后的内联跳转向量禁止部署存在栈使用违规的合约静态验证器可以依托数据区明确这一前提对控制流与栈帧做更严格的线性时间校验。从仓库整体演进看这一思路与后来的 EOFEVM Object Format方向高度一致EIPS/eip-3541.md 通过预留0xEF魔法字节为格式化代码铺路而BEGINDATA则是在无头格式下用单个操作码解决同类问题——两者共同反映了以太坊对字节码结构化、可验证化的持续追求。同时EIPS/eip-170.md 中关于合约代码上限MAX_CODE_SIZE与代码预读取开销的讨论也从侧面印证了减少对数据区做无谓分析在性能上的价值。九、现状与阅读建议EIP-2327 当前状态为Stagnant停滞尚未被纳入任何硬分叉。但它作为一项思路清晰、语义克制的 Core 提案至今仍被后续研究者反复引用其数据与代码分离的思想在 EOF、跨链代码验证等话题中持续产生影响力。如果你关注以下方向本提案值得精读EVM 的JUMPDEST分析与静态安全分析如 Mythril、Securify 类工具的底层假设合约字节码的链上验证与跨链可移植性EIP-615 子程序/跳转表提案及其衍生设计。延伸阅读仓库内相对路径提案正文EIPS/eip-2327.md跳转表与子程序的原始提案BEGINDATA起源EIPS/eip-615.mdEOF 魔法字节预留0xEFEIPS/eip-3541.md合约代码大小上限MAX_CODE_SIZEEIPS/eip-170.md注本文所有事实均以当前仓库中的 EIP 文档为准EIP-2327 的 Implementation 小节原文为 Not yet请勿将其理解为已有生产实现。若需在自己的客户端或分析工具中实验BEGINDATA语义请以上述测试用例为基准自行实现并验证。【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表