ARTICLE DETAIL

资讯详情

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

深入解读 EIP-1682:以太坊状态租金(Storage Rent)方案的设计、账本改造与实现影响

深入解读 EIP-1682:以太坊状态租金(Storage Rent)方案的设计、账本改造与实现影响 深入解读 EIP-1682以太坊状态租金Storage Rent方案的设计、账本改造与实现影响【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs本篇文章围绕 EIP 仓库中的 EIP-1682Storage Rent展开系统讲解以太坊早期为约束状态无限增长而提出的状态租金共识方案包括租金计费模型、账户表示法改造、新增 EVM 操作码以及账户失活与恢复机制。读者阅读完本文后将能完整理解这套方案的协议级设计细节并能结合仓库内 EIP-1418、EIP-2026 等关联提案看清状态租金演进脉络与各类方案的取舍。提案背景与定位EIP-1682 全称Storage Rent作者为 Felix J Langefjl与 Martin Holst Swendeholiman创建于 2018-11-10类型为 Standards Track / Core当前状态为Withdrawn已撤回。按照 EIP-1 流程规范 的定义Withdrawn 表示提案作者主动撤回该编号具有终局性日后若再推进相同思路将视为新提案。该提案针对的是一个被反复讨论的底层问题以太坊全节点参与共识所需存储的数据量即使在先进存储优化下依然庞大且由于协议规定任何存入合约的数据必须被永久保留未来存储需求是无界的。EIP-1682 试图通过新增共识规则为以太坊状态state规模设置一个上限。值得注意的是EIP-1682 并非仓库中唯一讨论状态租金的提案。同一仓库内的 EIP-1418Blockchain Storage Rent Payment 采用每区块按账户存储量扣除租金的思路EIP-2026State Rent H - Fixed Prepayment for accounts 则是 State Rent 路线图中固定预付的一环而 EIP-5022 在讨论短期定价修补时也明确提到像状态租金或状态过期这类方案短期内无法就绪。这些文档共同构成了理解 EIP-1682 的上下文。核心设计总览EIP-1682 的完整机制可概括为以下几点租金rent账户随时间产生的存储成本其数额取决于账户的大小用于支付租金的 ether 会被销毁destroyed不会进入矿工或任何人的口袋。扣费时机租金在**账户被触及touched**时扣除即账户发生修改的区块处理完交易之后统一结算。双余额机制租金可以从账户普通balance支付也可以从新增的rent balance支付通过新 EVM 操作码可为账户充入 rent balance。失活inactive当账户余额不足以支付租金时账户变为 inactive其存储与合约代码被移除账户表现为没有合约代码无法再被交互。恢复restorationinactive 账户可通过RESTORETO操作码由重建其存储根的账户恢复恢复成本等价于用一系列SSTORE重新创建该账户。为什么要设置独立的 rent balance提案给出两个原因其一某些合约拒绝接收普通 ether 转账non-payable无法靠自身余额续命但用户可以为它们代付租金其二对代用户保管余额的合约如众筹合约若直接从主余额扣租金会破坏其内部记账导致无法在未达阈值时准确退款。这一动机与 EIP-2026 中将预付存入账户专用字段 rentbalance而不是提高 gas 费用的思路一脉相承——后者同样指出独立 rentbalance 使得自毁时可返还余额。状态账本改造Changes To State顶层状态结构提案在账户树accounts trie顶层新增一个键size用于追踪所有账户的 trie 节点总数包含各账户存储 trie 的节点。同时账户条目本身的结构也被改变以支持租金追踪。在该 EIP 生效的区块处理之前客户端需要完整遍历一次状态完成两件事统计 trie 节点数量填充size并把所有账户转换为新格式。账户表示法新账户格式为一个七元组account [nonce, balance, storageroot, codehash, rentbalance, rentblock, storagesize]相比原格式每个账户新增三个属性字段语义rentbalance账户可用的 rent balance 数额账户被自毁self-destruction时剩余 rent balance 转给受益人任何对账户的修改都会重新计算其当前 rent balancerentblock上次重算 rent balance 时的区块号账户创建时初始化为当前区块号账户被修改时更新为当前区块号storagesize与账户相关的存储量即当前已设置的存储槽storage slot数量inactive 账户的 storagesize 为 0rentblock的关键作用在于租金按上次计费到现在的区块区间累积因此只需记录重算区块号而不必每个区块对所有账户主动扫描扣费——这正是实现层面惰性计费的基础。租金计费模型Charging Rent协议常量与费用因子提案新增协议常量MAX_STORAGE_SIZE用于规定状态树节点的上限MAX_STORAGE_SIZE 2**32 # ~160GB of state即约 160GB 的状态规模上限。在此基础上每个区块派生一个存储费用因子storage fee factor其特点是状态越接近上限费用越高def storagefee_factor(block): ramp MAX_STORAGE_SIZE / (MAX_STORAGE_SIZE - total_storage_size(block)) return 2**22 * ramp可以看到当total_storage_size(block)趋近MAX_STORAGE_SIZE时ramp趋近无穷大费用因子随之急剧上升形成对状态膨胀的渐进式惩罚。租金计算与扣费伪代码区块处理时租金在区块内交易处理完成后从所有被交易修改过的账户中扣除扣费金额基于账户的 storagesizedef rent(prestate, poststate, addr, currentblock): fee 0 for b in range(prestate[addr].rentblock1, currentblock-1): fee storagefee_factor(b) * prestate[addr].storagesize return fee storagefee_factor(currentblock) * poststate[addr].storagesize def charge_rent(prestate, poststate, addr, currentblock): fee rent(prestate, poststate, addr, currentblock) if fee poststate[addr].rentbalance: poststate[addr].rentbalance - fee else: fee - poststate[addr].rentbalance poststate[addr].rentbalance 0 poststate[addr].balance - min(poststate[addr].balance, fee) poststate[addr].rentblock currentblockrent()的计算区间是[rentblock1, currentblock-1]即上一次计费之后、当前区块之前的完整区间加上当前区块按 poststate 存储量的费用charge_rent()则先扣 rentbalance不足部分再从普通 balance 中扣除最多扣至 0最后把rentblock更新为当前区块号完成一次计费周期。若两者都不足以覆盖租金账户便进入 inactive 状态。新增 EVM 操作码提案定义了四个新操作码PAYRENT amount addr任何参与者可为任何其他账户代付租金从执行该操作码的账户扣除指定数量的 ether加到指定受益地址的 rent balance 上。Gas 成本TBD待定。这一设计解决了合约本身无法支付租金的场景——外部用户可主动为其续费保活。RENTBALANCE addr查询指定地址的rentbalance字段并压入栈顶。Gas 成本与EXTCODEHASH相当。类似地EIP-1418 也定义了RENTBALANCE(address)操作码其 gas 与BALANCE相当可见查询租金余额是各版本状态租金方案公认的基础能力。SSIZE addr将指定账户的storagesize字段压入栈顶用于查询账户当前占用的存储槽数量。Gas 成本与EXTCODEHASH相当。RESTORETO addr codeaddr该操作码用于恢复 inactive 账户语义上比SELFDESTRUCT更具体。其前置条件与执行流程如下addr账户必须处于 inactive即storagesize为 0且其storageroot必须与执行RESTORETO的合约的 storageroot 匹配codeaddr指定提供代码的合约地址其代码必须与addr的codehash匹配全部条件满足后RESTORETO将执行该操作码的合约的存储转移给addr并把addr的storagesize重置为完整存储大小同时恢复addr的代码执行合约的剩余 balance 与 rent balance 一并转给addr执行合约本身被删除。Gas 成本TBD。提案特别说明恢复 inactive 账户的方式是新建一个任意代码的账户 B用SSTORE操作逐步修改其存储直至与 A 的存储根一致再通过RESTORETO恢复 A——因此恢复成本等价于用一系列 SSTORE 重新创建该账户从经济学上避免了廉价复活带来的状态反复膨胀。设计动机与取舍Rationale为什么要独立 rent balance除前文提到的 non-payable 合约场景外提案以经典众筹合约为例合约在余额达到阈值后改变行为并记录每个用户的余额。若从合约主余额直接扣除租金会打乱合约内部账目——当最终余额未达阈值时合约将无法准确向用户退款。独立 rent balance 将维持合约存活的成本与合约业务资金彻底隔离。为什么要支持恢复restoration以太坊的基本保证之一是合约存储的更改只能由合约自身发起且存储永久存在——持有代币余额意味着永久持有。如果租金机制只做删除不做恢复将彻底打破这一用户预期。通过恢复机制可以在为状态规模设限与维持存储持久性保证之间取得平衡。实现影响Implementation Impact提案强调设计尽量贴合现有状态转换模型但也坦诚指出一个关键限制没有机制能在账户无法支付租金的当下立刻将其失活。用户必须触及账户其存储才会被移除——否则客户端需要在辅助数据结构中跟踪所有账户及其租金需求。换言之这是一个依赖惰性计费的方案失活不是即时的而是随账户被访问/修改时触发。这一点与 EIP-1418 的惰性求值lazy evaluation设计形成呼应后者同样将驱逐责任的实现交给共识客户端且认为这是最可预测的行为因为驱逐恰好在它应当发生的时刻发生。后续状态与关联提案EIP-1682 的 Backwards Compatibility向后兼容、Test Cases测试用例与 Implementation实现三个章节均为 TBA待定且提案最终被撤回。但它的核心思想——为状态规模设上限、按存储量随时间收费、账户失活与恢复——在仓库的其他提案中得到了延续和演变EIP-1418Blockchain Storage Rent PaymentStagnant以RENT_WORD_COST、RENT_ACCOUNT_COST等常量定义每字-区块与每账户-区块的固定租金并引入SENDRENT、PAYRENT子程序及驱逐区块rentEvictBlock概念对SSTORE/SLOAD/CALL/CREATE的语义进行扩展EIP-2026State Rent H - Fixed Prepayment把状态租金路线图拆分为多个硬分叉第一步先引入创建/修改账户时的固定预付ACCOUNT_PREPAYMENT从理论上限制账户总数并为后续真正引入租金做准备EIP-2937其SET_INDESTRUCTIBLE设计明确讨论了与到期未缴费即删除合约这类状态租金方案的兼容性问题EIP-5022指出状态租金/状态过期在短期难以就绪主张先用操作码重定价作为过渡修补。可以看到围绕状态无限增长这一根因仓库内的多个 Core 类提案从租金、预付、过期到重定价进行了多路探索而 EIP-1682 正是其中最早、也最具完整协议形态的尝试之一。结语EIP-1682 是一份设计完整、思路清晰但最终被撤回的共识层提案。它提出了一套可操作的状态租金协议用size键约束状态树总量、用rentbalance/rentblock/storagesize三个新字段支撑按区块区间计费、用四个新操作码实现充值、查询与恢复。尽管该提案没有进入实现阶段其双余额设计、惰性扣费与恢复机制等思想深刻影响了后续状态规模治理方案的讨论方向。对于希望理解以太坊状态膨胀问题及其治理思路的开发者EIP-1682 原文与上述关联提案是绝佳的入门阅读材料。版权说明本文内容基于 EIP-1682 原始提案整理原文档版权已通过 CC0 协议 放弃。【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表