ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深入解析 EIP-1702:以太坊通用账户版本化方案(Generalized Account Versioning Scheme)

深入解析 EIP-1702:以太坊通用账户版本化方案(Generalized Account Versioning Scheme) 深入解析 EIP-1702以太坊通用账户版本化方案Generalized Account Versioning Scheme【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPsEIP-1702Generalized Account Versioning Scheme通用账户版本化方案由 Wei Tangsorpaas于 2017 年 12 月提出是一份 Standards Track / Core 类别的以太坊改进提案。其核心思想是在账户状态中引入version字段让同一个区块内可以同时执行多个版本的虚拟机VM从而在保持存量合约行为完全不变的前提下以软化的方式引入破坏性 EVM 变更并为未来接入链上 WebAssemblyeWASM虚拟机铺平道路。阅读本文后你将理解账户版本化的数据结构设计、执行与部署规则、验证阶段机制、附加字段解析策略以及它如何在后续 EIP如 EIP-615、EIP-1930中被作为依赖引用并与 EOFEIP-3540等演进方案形成对比。背景与动机为什么需要账户版本化以太坊主网自上线以来经历过多次硬分叉。每次硬分叉都会修改 EVM 语义或引入新特性而这些修改是全局生效的——一旦分叉完成所有合约包括多年前部署、依赖旧语义的合约都会在新规则下执行。这在以下场景中成为问题想要实现破坏性的 EVM 改进例如废弃某条操作码、改变语义但又必须保证存量合约行为不受影响想要在同一链上并行部署 eWASM 等全新 VM与旧 EVM 合约共存并清晰定义交互边界想在部署时对代码做一次性校验如 EIP-615 的子例程静态校验但旧合约字节码并不满足新校验规则。EIP-1702 的解决思路是按账户记录版本通过允许为不同时间创建的合约执行不同版本的虚拟机破坏性特性可以安全落地而旧合约仍按原样工作。这正是该提案标题中Generalized通用的含义——它是一种通用的版本化基础设施而非针对某一具体 VM 特性。需要说明的是该规范并不适用于所有硬分叉。EIP-1702 原文特别指出历史上存在因网络攻击而发起的紧急硬分叉emergency hard fork。如果攻击只能对特定合约执行一次那么本方案依然适用但如果攻击是全局性的直接进行普通紧急硬分叉仍是更好的选择。这一边界条件提醒我们账户版本化解决的是平滑演进问题而非紧急止损问题。核心设计账户状态中的version字段世界状态 Trie 中的账户重定义EIP-1702 将存储在世界状态 Trieworld state trie中的账户状态重新定义为5 个字段字段说明nonce账户交易计数balance账户余额storageRoot存储 Trie 根codeHash合约代码哈希version新增256 位标量scalar标识账户/代码所属 VM 版本新增的version字段是一个 256 位标量其类型定义沿用以太坊黄皮书Yellow Paper中的 scalar 概念——它与nonce、balance同类型等价于一个不含前导零、最大长度为 32 字节的 RLP 变长字节数组。RLP 编码规则按版本决定字段数量version字段的引入直接影响了账户的 RLP 序列化形态当version为0时账户按前 4 项nonce、balance、storageRoot、codeHash进行 RLP 编码——与现有账户编码完全一致当version非零时账户按5 项进行 RLP 编码。这一设计保证了版本化方案对存量账户的完全向后兼容所有已存在的账户版本为 0其 RLP 表示与分叉前逐字节相同节点无需重写任何历史状态。此外账户版本还可以可选地定义附加的账户状态 RLP 字段其含义由version字段决定。具体解析策略在附加字段解析策略一节中定义这为未来 EIP例如新增账户字段的提案预留了扩展空间。合约执行规则codes version决定执行语义EIP-1702 定义了一条关键的执行规则从状态中获取账户代码时必须同时获取其关联的version字段。该版本被称为codes version代码版本账户代码始终在其所属的 codes version 对应的 VM 中执行。这一规则有两个重要推论调用帧的版本随合约走对于DELEGATECALL和CALLCODE这类借用目标合约代码但保持当前调用上下文的操作码执行调用帧execution call frame的版本与委托方/接收方合约delegating/receiving contract的版本一致。也就是说当旧版本合约通过DELEGATECALL调用新版本合约的代码时新代码会以旧版本 VM 的语义执行——版本判定始终取决于代码属于谁而非调用发起者是谁。版本只与账户绑定与调用路径无关无论通过何种方式普通CALL、STATICCALL、交易调用一个合约只要代码的version相同执行语义就相同。合约部署规则合约家族的版本一致性EIP-1702 引入了合约家族family of contracts的概念来统一部署版本每个合约都有一个部署方式要么通过合约创建交易contract creation transaction要么由另一个合约通过CREATE/CREATE2创建如果将部署方式视为合约的parent父节点那么所有合约会构成一棵家族树其root根总是合约创建交易一个合约家族的所有成员始终具有相同的version。具体到操作码层面这意味着CREATE0xf0和CREATE20xf5总是部署与当前codes version相同的合约即使待部署的代码为空empty code该规则依然成立CREATE/CREATE2使用当前的codes version执行 init code初始化代码并部署该版本的合约。EIP-1014Skinny CREATE2状态为 Final定义了CREATE2的地址推导公式keccak256(0xff address salt keccak256(init_code))[12:]详见 EIPS/eip-1014.mdEIP-1702 的部署规则与该地址推导机制正交版本跟随创建者地址仍由公式决定。验证Validation阶段部署前的门禁EIP-1702 为合约部署无论是通过CREATE/CREATE2操作码还是通过合约创建交易新增了一个称为validation验证的步骤当version为0时验证阶段不做任何事总是成功——这保证了对存量部署流程的零影响未来的 VM 版本可以定义额外的验证规则部署代码必须通过验证才能上链如果验证失败部署不会继续并返回 out-of-gasgas 耗尽。验证阶段的价值在于它允许新 VM 版本在部署时对字节码做一次性静态校验例如 EIP-615 提议的子例程合法性检查、跳转目标检查而无需在每次执行时重复分析。这与后文将提到的 EOF 格式EIP-3540的部署时一次性验证理念一脉相承但实现路径不同——EIP-1702 的版本信息在账户中而 EOF 的版本信息在代码前缀中。合约创建交易LATEST_VERSION的锚点对于顶层部署路径——合约创建交易——EIP-1702 定义在硬分叉中定义LATEST_VERSION为当前支持的最新 VM 版本合约创建交易总是在LATEST_VERSION中执行即其codes version为LATEST_VERSION并部署LATEST_VERSION的合约在执行合约创建交易之前先对合约创建代码运行validation若未通过返回 out-of-gas。结合合约家族规则这一设计实现了版本传播的闭环版本只由合约创建交易指定锚定为LATEST_VERSION随后通过CREATE/CREATE2沿家族树自然继承。在基础层base layer中链上不存在显式指定版本的通道版本完全由创建路径决定这大大简化了实现复杂度。预编译合约与外部拥有地址预编译合约precompiled contracts和外部拥有地址externally-owned addresses, EOA没有version字段如果一条消息调用交易或CALL/CALLCODE/STATICCALL/DELEGATECALL触及一个新的外部拥有地址或一个尚不存在的预编译合约地址该账户总是以version字段为0被创建。这条规则保证了版本字段不会污染非合约账户也避免了对地址创建逻辑的额外成本。附加账户状态 RLP 字段的解析策略EIP-1702 预见到未来可能需要为账户关联更多信息当时已有一些 EIP 在讨论新增账户状态 RLP 字段因此明确定义了附加字段的解析策略检查 RLP 列表长度若为4则账户版本设为0不解析任何附加字段若 RLP 列表长度大于4则将位置4从0开始计数的标量设为账户版本查询该版本的规范获取其定义的附加字段数量N若 RLP 列表长度不等于5 N返回解析错误parse error将 RLP 位置5至4 N按该版本规范定义的附加字段含义进行解析。这一策略使得账户状态可以随版本演进而携带额外信息同时保持严格的结构校验避免字段数量不匹配导致的歧义。扩展44-VERTXN 与 45-VEROPEIP-1702 的 Specification 部分定义了基础账户版本化层base account versioning layer它本身已可用于处理大多数 EVM 改进。在此基础上提案还给出了两个可独立部署的扩展规范原文仅作文档用途启用 EIP-1702 时除非同时包含扩展规范否则不应启用这些扩展44-VERTXN针对合约创建交易的账户版本化扩展——允许合约创建交易显式指定目标版本而非固定为LATEST_VERSION45-VEROP针对CREATE与CREATE2的账户版本化扩展——允许部署操作码显式指定子合约版本。这两个扩展是支持多个最新 VM 并行运行例如 EVM 与 WebAssembly 同时作为最新 VM所必需的。在基础层中版本只能沿创建路径继承无法在同一硬分叉中同时接纳两个最新VM而通过 44-VERTXN / 45-VEROP创建交易和创建操作码可以显式选择版本从而打破单一LATEST_VERSION的限制。使用模板其他 EIP 如何接入账户版本化EIP-1702 定义了其他 EIP 使用该规范的方式。账户版本化通常直接应用于一个硬分叉 meta EIP硬分叉中的 EIP 按 VM 类型如 EVM 与 eWASM分组每组定义以下元信息Version一个非零、小于2^256的标量唯一标识该版本不要求连续编号Parent version新特性所基于的父版本父版本为0时表示基座为 legacy VM传统 EVM。注意一旦定义了非0的版本legacy VM 的特性集必须被冻结当定义一个全新 VM如 eWASM时parent version 不适用Features该版本上启用的所有附加特性。如果 meta EIP 还包含提供附加账户状态 RLP 字段的 EIP则额外定义Account fields截至该 meta EIP 为止的全部账户字段不含基础 5 字段nonce、balance、storageRoot、codeHash、version。如果某 EIP 只修改账户字段、不修改 VM 执行逻辑则建议额外指定一个执行逻辑与上一版本相同、仅账户字段不同的版本——这样可以将纯数据结构的变更与执行语义的变更解耦。原理Rationale与备选方案为什么选择账户内嵌版本字段EIP-1702 通过账户状态中的新 RLP 项实现版本化其关键设计是让合约家族始终持有相同版本。由此版本只需由合约创建交易提供锚定为LATEST_VERSION后续沿家族树自动继承任何版本的代码格式都不受限制因为版本在执行时由账户决定而非由代码内容决定若未来要同时支持多个最新 VM如 EVM 与 WebAssembly 并行再通过 44-VERTXN 和 45-VEROP 扩展实现。备选方案对比原文讨论了另外两条实现路径前缀式版本化26-VER 与 40-UNUSED账户版本完全由其代码头部前缀决定。缺点在于仅靠 26-VER 无法证明任何代码是合法的——因为当前 VM 允许把代码当数据code-as-data处理40-UNUSED 通过保留前缀字节解决该问题但代价是潜在的向后不兼容。EIP-1891独立合约存储版本将版本字段写入一个独立合约而非账户 RLP 状态。同样能达到目的且可能降低代码复杂度但每次代码执行都需要额外的 Trie 遍历影响性能。EIP-1702 的账户内嵌方案则避免了上述两者的缺陷不依赖代码内容无 code-as-data 问题、无额外 Trie 遍历版本随账户读取一起获得。向后兼容性EIP-1702 声明其完全向后兼容版本为0的账户编码与分叉前逐字节一致version为0时验证阶段为空操作存量合约的执行路径完全不变。这是该方案最核心的工程承诺——硬分叉升级不改变任何现有合约的可观察行为。讨论性能与 WebAssembly 展望性能影响在性能方面当时几乎所有全节点实现都使用配置参数config parameters来决定采用哪个 VM 版本切换 VM 版本本质上只是更换一组配置参数、改变一个指针的操作。因此本方案对性能的影响几乎为零nearly zero——版本随账户读取附带获得没有额外的存储查找或状态访问。WebAssembly 共存该方案对链上 WebAssembly VM 的部署同样有意义WASM 合约与 EVM 合约可以共存于同一条链其执行边界与交互模型由上述规则清晰定义——每个合约按自身版本执行DELEGATECALL/CALLCODE时版本随代码走创建时版本沿家族继承。在仓库中的关联与后续演进EIP-1702 虽然状态为Stagnant按 EIPS/eip-1.md 的定义即提案进入 Draft/Review/Last Call 后超过 6 个月未活跃被移入的状态作者或编辑器可将其复活回 Draft但它在以太坊核心协议讨论中留下了清晰的印记本仓库中即可找到多处关联证据EIP-615Static CALL variant of SUBROUTINE在其 Dependencies 一节中明确将 EIP-1702 列为依赖This proposal needs a versioning scheme to allow for its bytecode (and eventually eWasm bytecode) to be deployed with existing bytecode on the same blockchain.该提案需要版本化方案以允许其字节码——最终包括 eWasm 字节码——与现有字节码在同一区块链上共存并在第 319 行重申需要类似 EIP-1702 的版本化方案见 EIPS/eip-615.md。这印证了 EIP-1702 作为版本化基础设施的设计定位。EIP-1930CALL with strict gas semantics在讨论选项 a新增 3 个严格 gas 语义的操作码变体时指出该方案能避免旧合约受影响但代价是引入新操作码而有了 EIP-1702就可以让旧操作码过时render the old opcode obsolete见 EIPS/eip-1930.md——说明版本化方案可以作为废弃旧操作码的替代机制。EIP-2378EIPs Eligible for Inclusion的规格表中EIP-1702 被列为ELIGIBLE有资格纳入决策日期为 2019-11-01见 EIPS/eip-2378.md表明它曾进入核心开发者会议AllCoreDevs Meeting 74的候选讨论范围。EIP-3540EOF - EVM Object Format在 Rationale 中回顾了历史EVM and/or account versioning has been discussed numerous times over the past years. This proposal aims to learn from them.过去几年中 EVM 和/或账户版本化已被多次讨论本提案旨在从中学习见 EIPS/eip-3540.md。EOF 选择了另一条路线——通过代码前缀中的 magic version实现版本化0xEF起始的 EOF 容器版本号 1 字节、取值0x01–0xFF见 EIPS/eip-3540.md并明确 Validating code during the contract creation process allows code versioning without an additional version field in the account在合约创建过程中验证代码可以在不增加账户版本字段的情况下实现代码版本化见 EIPS/eip-3540.md。可以看到EIP-1702 所探索的账户内嵌版本路径最终让位于 EOF 的代码内嵌版本路径但其关于版本传播、部署时验证、家族一致性等问题的分析直接塑造了后续版本化方案的讨论框架。总结EIP-1702 提供了一个优雅而完整的状态级账户版本化蓝图在账户 RLP 中追加 256 位version标量通过代码版本决定执行语义、创建路径决定版本继承、验证阶段把关部署、LATEST_VERSION锚定创建交易四组规则实现了多 VM 同区块共存与破坏性特性平滑落地。它几乎零性能开销、完全向后兼容并预留了附加状态字段解析与 44-VERTXN / 45-VEROP 扩展接口。尽管该提案最终以 Stagnant 收场未进入主网但其设计思想——尤其是版本沿合约家族继承与部署时验证——在 EIP-615、EIP-1930、EIP-2378 等提案中持续回响并与 EIP-3540 的 EOF 方案形成了一组值得对照研读的版本化设计谱系。对于研究 EVM 演进史、硬分叉兼容性设计以及 WASM 上链方案的读者而言本仓库中的 EIPS/eip-1702.md 及其关联 EIP 是一份不可多得的原始素材。【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表