EIP-1418 区块链存储租金(Blockchain Storage Rent Payment)技术解析:为以太坊状态存储建立按块计费机制
2026/9/14 16:19:49 网站建设 项目流程

EIP-1418 区块链存储租金(Blockchain Storage Rent Payment)技术解析:为以太坊状态存储建立按块计费机制

【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs

导读

EIP-1418(Blockchain Storage Rent Payment,区块链存储租金支付)提出了一套为以太坊账户状态存储引入"按块持续计费"机制的协议级方案:每个区块都会根据账户占用的存储量(字节数 × 区块数)从其租金余额中扣除对应价值,从根本上改变当前"存储一次性付费、永久占用"的定价模型。本仓库(ethereum/EIPs 官方改进提案库)中的 EIPS/eip-1418.md 是该提案的权威规范文档。阅读本文后,你将掌握:租金机制的状态变量设计、PAYRENT/RENTBALANCE/SENDRENT等新增操作码的精确语义、账户驱逐(eviction)与懒评估(lazy evaluation)的实现思路、常量定价的经济学推导,以及与 EIP-1559 访问列表、EIP-2718 交易信封等既有协议的衔接方式。该 EIP 目前状态为Stagnant(停滞),属于 Standards Track / Core 类别,其设计思想(为无状态客户端与存储定价提供状态访问成本模型)至今仍是研究存储经济学的重要参考。

EIP-1418 是什么:为"存储占用"持续定价

EIP-1418 的核心主张非常简洁:在每个区块,根据每个账户占用的存储量,从该账户扣除一定数量的价值(称为"租金")

这一机制的目标是修正以太坊存储定价的结构性缺陷。正如提案 Motivation 部分指出的:

Ethereum is a public utility and we are underpricing the long-term costs of storage. Storage cost can be approximately modeled as bytes × time.

即:以太坊是一个公共基础设施,而当前协议对存储的长期成本严重定价不足。存储的真实成本可以近似建模为字节数 × 时间的乘积——一次SSTORE写入一个存储槽后,该数据会被全节点永久保存在状态树中,持续消耗磁盘、内存、同步带宽等资源,但写入方只支付了一次性的 gas 费用。EIP-1418 试图把这种"一次性买断"改为"持续租赁"。

该提案是 EIPS/eip-1559.md 的依赖提案(requires: 1559),两者共同指向一个更深层的方向:让节点可以不必记录完整网络状态即可参与共识。EIP-1559 为合约状态引入了 warm access(热访问),而 EIP-1418 在此基础上进一步为合约代码引入 warm access 概念,并为状态数据的持续驻留设定明确的经济对价。

规范核心:状态变量、常量与新交易类型

每个账户新增的状态变量

EIP-1418 为每个账户(account)新增两个状态字段:

  • σ[a]_rent—— 账户的租金余额,单位为 Wei,这是一个有符号值(signed value),因为驱逐(eviction)过程中租金可能变为负值,需要借用账户余额来补足;
  • σ[a]_storageWords—— 账户在存储中占用的字数(word 数),用于计算按存储量计的租金。

注意这里的变量命名采用了黄皮书式的σ[a](状态机状态)记号,表示这些字段会进入世界状态(world state),参与状态根(state root)的哈希计算——这意味着它们是共识层可见的状态变更,而非客户端本地数据。

新增常量

常量含义
RENT_WORD_COST每个 word-block 的租金成本(Wei)
RENT_ACCOUNT_COST每个 account-block 的租金成本(Wei)
FORK_BLOCK实现开始生效的区块号

新交易类型:为合约代码引入 warm access

EIP-1418 引入一种新的交易类型(transaction type)。文档给出的关键对照是:

Whereas EIP-1559 introduced warm access for contract state, this new type introduces warm access for contract code.

即 EIP-1559(更准确地说,其依赖链上的 EIPS/eip-2930.md Optional Access Lists 与 EIPS/eip-2929.md 状态访问 opcode 提价)引入了合约状态(storage slot)的热访问列表机制;而 EIP-1418 的新交易类型则在访问列表中扩展合约代码(contract code)的热访问能力。

从仓库中已 Final 的 EIPS/eip-2718.md 可以看出,TransactionType || TransactionPayload信封机制为新增交易类型提供了标准化挂载点;EIPS/eip-2930.md 中accessList的格式(rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList, signatureYParity, signatureR, signatureS]))正是 EIP-1418 扩展代码热访问的格式基础。EIP-1418 中"代码热访问"的意义在于:当合约因欠租被驱逐后,其代码与存储被节点选择性删除,此时若交易通过访问列表预先声明要读取该合约的代码并附带证明(proof),执行仍然可以进行——这与 EIP-2929 中"已访问的地址/存储槽享受降价"的思路一脉相承。

新增操作码:RENTBALANCE 与 SENDRENT

RENTBALANCE(address)

  • 气体成本:G_BALANCE(与现有BALANCEopcode 相同)
  • 语义:返回账户逻辑上的σ[a]_rent值,该值被定义为"每个区块递减"。

规范特意指出:实现层面不需要每个区块为每个账户实际改写σ[a]_rent。因为租金随时间线性递减,完全可以只在账户被访问时按"上次支付区块号(rentLastPaid)到当前区块号"的差值惰性计算,从而避免对全量账户做每块更新。这是本提案最重要的实现优化点(详见下文"懒评估")。

SENDRENT(address, amount)

  • 气体成本:G_BASE
  • 语义:把价值转换为租金并发送给目标账户,分两步执行:
    1. σ[account]_rent += amount(给目标账户增加租金余额)
    2. σ[msg.sender]_balance -= amount(从发送者余额扣除等额 Wei)

这个操作码的设计意图很明确:任何账户(包括普通 EOA 和合约)都可以为别人"充租金"。由于它不触发对目标合约的调用,SENDRENT属于"纯转账式"操作,不会引入重入(reentrancy)等调用语义风险。

更新后的操作码:PAYRENT 子程序与驱逐机制

规范建立了一个新的子程序PAYRENT(account),作为SSTORESLOADCALL等既有操作码的前置步骤。其完整伪代码如下:

PAYRENT(account) blocks_to_pay = NUMBER - σ[account]_rentLastPaid cost_per_block = RENT_ACCOUNT_COST + RENT_WORD_COST * (⌈∥σ[account]_code∥ / 32⌉ + σ[a]_storageWords) rent_to_pay = blocks_to_pay * cost_per_block σ[account]_rent -= rent_to_pay if σ[account]_rent < 0 σ[account]_value += σ[account]_rent σ[account]_rent = 0 end if σ[account]_value < 0 σ[account]_rent = σ[account]_value σ[account]_value = 0 end σ[account]_rentLastPaid = NUMBER σ[account]_rentEvictBlock = NUMBER + ⌊σ[account]_rent / cost_per_block⌋ END PAYRENT

逐行理解 PAYRENT 的计算逻辑

  1. blocks_to_pay:自上次支付租金以来经过的区块数(NUMBER - rentLastPaid)。这正是"惰性计算"的体现——租金欠款只在账户被真正触达时才一次性结算。
  2. cost_per_block:每区块的租金单价,由三部分组成:
    • RENT_ACCOUNT_COST:账户本身的存在成本(无论存储多少都要付);
    • RENT_WORD_COST × ⌈∥code∥/32⌉:合约代码按 32 字节一个 word 向上取整折算的存储成本;
    • RENT_WORD_COST × storageWords:存储槽占用的 word 数成本。
  3. rent_to_pay = blocks_to_pay × cost_per_block:累计欠租总额。
  4. 欠租结算与余额联动:若租金余额不足以支付欠租(rent < 0),则从账户价值余额(value/ETH 余额)中补足差额(value += rent,此时 rent 为负即扣除);若价值余额也被扣成负数,则把这个负数转回租金余额、价值余额归零——此时账户进入"深度欠租"状态。
  5. 更新驱逐区块号rentEvictBlock = NUMBER + ⌊rent / cost_per_block⌋,即按当前剩余租金余额还能支撑多少个区块,精确计算出账户被驱逐(evicted)的时刻。

各操作码的租金化改造

  • SSTORE(account, key, value):先执行PAYRENT(account);若账户已被驱逐(NUMBER > rentEvictBlock),交易失败——除非使用新交易类型并附带足够证明(proof)来验证旧存储根并计算新存储根。随后执行正常SSTORE逻辑,并维护storageWords计数:旧值为零且新值非零则storageWords++;旧值非零且新值为零则storageWords--(结果小于零时归零)。这保证了存储字数是精确的引用计数,而非估算值。
  • SLOAD(account, key):先检查驱逐状态,驱逐账户的读取同样要求新交易类型 + 验证现有存储根与存储值的证明,之后才执行正常SLOAD
  • CALL(及衍生操作码):若目标区块已被驱逐,交易失败——除非新交易类型附带验证现有代码的足够证明。这里首次把代码访问纳入了驱逐约束,与"代码热访问"交易类型呼应。
  • CREATE:设置σ[account]_rentLastPaid = NUMBER,执行正常CREATE,并将σ[account]_storageWord置零。规范特别提醒:这里可能存在创建前遗留的租金余额(例如创建前有人为该地址充过租金),需要妥善处理。

新增内置合约 PAYRENT(address, amount)

为了照顾普通账户(EOA),EIP-1418 还定义了一个内置合约(built-in contract)PAYRENT(address, amount),它直接调用PAYRENT子程序。动机非常实际:

simple accounts (CODESIZE == 0) cannot call arbitrary opcodes, they can only call CREATE or CALL.

普通账户无法直接执行任意 opcode,只能通过CREATECALL触发逻辑,因此需要内置合约作为"人类充租金的便利入口"。该内置合约的 gas 成本设定为10,000 或更低(if possible)。

驱逐机制的设计权衡:懒评估与责任归属

驱逐责任交给共识客户端

EIP-1418 把驱逐的执行责任交给共识客户端(consensus clients),而不是依赖外部参与者(如监控账户并请求删除以赚取赏金)。Rationale 部分给出了三条理由:

  1. 行为可预测:驱逐"恰好在应该发生的时刻"发生,不需要额外的激励设计(无需退款 gas、无需赏金 bounty);
  2. 无需追踪:一个区块内可能驱逐任意数量的账户,但这无关紧要——客户端实现不需要跟踪哪些账户被驱逐,共识的达成只需各方对被驱逐条件(NUMBER > rentEvictBlock)达成一致即可;
  3. 确定性:驱逐条件由状态根中可验证的字段决定,天然可被轻客户端与无状态客户端验证。

存储清理与未来扩展

Storage note 部分说明:对于每个被驱逐的账户,客户端可以选择性地从磁盘删除其存储。这直接服务于"节点不必记录完整网络状态"的目标——被驱逐的数据不再要求全节点永久保存。规范同时预留了两个未来 EIP 的方向:

  • 为保留被驱逐账户的额外数据提供激励(付费保留);
  • 创建客户端之间交换这些存储状态信息的机制。

这两点共同构成了"存储可以按市场价流转"的远期蓝图。

租金经济模型:常量定价与历史成本推导

为什么租金不可逆向转换

EIP-1418 明确规定:Ether 一旦转换为租金就不能再转回价值余额。Rationale 用了一个巧妙的类比:

Anybody that works in accounting and knows about gifts cards should tell you this is a good idea.

就像礼品卡一样,单向转换让系统的推理变得简单:SENDRENT的接收方(被依赖的合约)可以确信这些资金只用于"让自己继续存活",而不会被其他调用路径挥霍掉。

为什么需要独立的租金账户

这是本提案最关键的激励机制设计。规范明确回答:

Because anybody/everybody can contribute to the rent account. If you depend on a contract, you should contribute to its rent. ... By maintaining a separate rent and value balance, this allows people to contribute to the rent while being confident that this is allowing the contract to stay around.

即:任何依赖某合约的人都应该为它的租金做贡献。如果租金与价值余额混在一起,合约可以把所有资金花光,导致"充值者以为在续命、实际却被消耗"的囚徒困境。分离的租金余额让外部贡献者有信心——他们的捐赠确实只用于延长合约的存续时间。

常量定价的历史推导

Economics & constants 部分给出了一个非常具体的成本锚点推导:

  • 2015 年执行一次SSTORE花费 20,000 gas,此后经历了约 600 万个区块;
  • 同期 gas 价格约 1~50 Gwei;
  • 由此估算:每个 word 每区块约 4,000 Wei
  • 进一步假设"存储一个账户"比"存储一个 word"的代价高 10 倍;但规范随后又指出G_transaction(21,000)与G_sstore(20,000)量级相近,二者都可以创建新账户/新 word,因此实际定价倾向于让账户成本与 word 成本对齐。

最终建议的常量值:

  • RENT_WORD_COST=4,000 Wei
  • RENT_ACCOUNT_COST=4,000 Wei
  • FORK_BLOCK= 实现启动的区块号

规范强调:租金以"硬通货 Ether"计价,不由客户端协商、不是动态的(The rent is priced in cold, hard Ether. It is not negotiated by clients, it is not dynamic.)。但同时也预留了未来改进为动态定价的路径——例如要求区块公证人(notary)证明其持有当前存储数据集(不含驱逐项),或额外证明持有"含驱逐项的完整数据集"以赚取额外费用,用相对存储量与附加费用的比值形成市场反馈,为存储设定市场价格。

宏观量级参考

规范提供了一个量级估算:以太坊主网数据集约有150 亿(15B)个 word,全网已开采约1 亿(100M)ETH。如果全部 ETH 都按当前提议价格用于存储,相当于400 terabyte-years(TB·年)的存储量。作者对此的评价是:"我不确定这样看问题是否有帮助"——意在说明该定价是粗略的经验锚点,而非精密的供需均衡解。

向后兼容性与存量账户的 storageWords 估算

兼容性基础

EIP-1418 明确以 EIP-1559 为兼容性前提:

EIP-1559 already introduces a mechanism for nodes to participate without recording the full network state and for clients to warm cache with storage data in their type 2 transactions.

即 EIP-1559(及其依赖的 EIPS/eip-2718.md 类型化交易信封、EIPS/eip-2930.md 访问列表)已经为"节点不记录完整网络状态即可参与"和"type 2 交易预热存储缓存"铺好了路,EIP-1418 的代码热访问交易类型与驱逐机制正是在此基础上叠加。

存量账户 storageWords 的迁移难题

对已有账户计算σ[account]_storageWord是一个**尚未解决(DRAFT)**的迁移问题。规范明确设定了两条约束:

  • 不可接受的方案:在分叉块要求只有"知道每个账户完整存储量"的归档节点(archive nodes)参与——这会破坏去中心化;
  • 可接受的方案:所需值可以基于新交易活动增量计算(或估计)

作者初步构想了一个无偏估计器(unbiased estimator)

  • 对传统账户首次访问某 key 的SSTORE增加 1 bit 存储;
  • 每层 trie 增加 log(n) bits;
  • 假设存储 key 是随机变量。

该方案在文档中仍标注为 DRAFT("To think more about..."),说明存量迁移是提案落地的主要开放难点之一。

对既有合约的影响

Backwards Compatibility 部分坦承了两个现实风险:

  1. 用户需要被教育(Users will need to be educated):租金是全新的心智模型;
  2. 许多智能合约允许任何人无限制地使用其存储(Many smart contracts allow anybody to use an arbitrary amount of storage in them)——这类"公共存储池"合约在租金机制下可能被恶意塞满存储后拖欠租金,进而影响该合约的可用性。这也是 Security Considerations 部分唯一强调的风险点。

推荐实现变量(每账户)

为了让σ[a]_rent的惰性计算可落地,规范推荐在每个账户上维护两个实现变量:

  • σ[a]_rentLastPaid—— 上次支付租金的区块号。在以下事件发生时更新:
    • 价值转入账户(CREATECALLSELFDESTRUCT);
    • 账户代码被设置(CREATE);
    • 账户存储被更新(SSTORE)。 所有账户的初始逻辑值为FORK_BLOCK
  • σ[a]_rentEvictBlock—— 账户将被驱逐的区块号(由PAYRENT末尾的公式计算得出)。

这两个变量与σ[a]_rent配合,使客户端可以在任意时刻只通过(rentLastPaid, rentEvictBlock, rent)三元组推算账户的实时租金状态,而无需每块遍历全量账户。

安全考量与遗留问题

安全考量:规范重申了兼容性章节的担忧——允许任意人占用存储的合约(公共存储池)在租金机制下面临被滥用拖垮的风险,这是部署前必须评估的核心安全问题。

规范 TODO(草稿注释中的开放问题)

  • 被驱逐的账户在补缴欠租后,是否允许"复活"(un-evicted)?文档将"Can/should an evicted account be allowed to be un-evicted when paying past due rent?"列为待讨论议题,未给出结论。

总结与展望

EIP-1418 是存储经济学领域一份影响深远的设计提案:它把存储成本从"一次性 gas"重构为"按块持续租金",通过PAYRENT惰性结算、独立租金账户、RENTBALANCE/SENDRENT操作码与内置合约、以及基于 EIP-1559 访问列表体系扩展出的"代码热访问"交易类型,构成了一套自洽的存储续租与驱逐框架。其"驱逐责任由共识客户端承担、客户端无需追踪驱逐清单"的懒评估思想,以及"租金单向不可逆、外部贡献者可安心充值"的激励机制,对后续所有研究状态膨胀(state growth)与存储定价的提案(包括状态过期 state expiry 方向)都具有直接的参考价值。

虽然该提案目前处于 Stagnant 状态,σ[account]_storageWords的存量迁移方案也仍停留在 DRAFT,但其"字节 × 时间"的成本模型、驱逐区块号的确定性计算方式,以及为无状态客户端铺路的思路,至今仍是理解以太坊存储经济学绕不开的起点。想深入原文,可直接阅读仓库中的 EIPS/eip-1418.md,并对照其依赖链 EIPS/eip-1559.md、EIPS/eip-2718.md、EIPS/eip-2930.md 与 EIPS/eip-2929.md 了解完整的协议演进脉络。

【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询