Alert Source Discuss
🚧 Stagnant Standards Track: Core

EIP-1418: 区块链存储租金支付

在每个区块,基于每个账户使用的存储量,从每个账户中扣除价值(租金)。

Authors William Entriken (@fulldecent)
Created 2018-09-16
Discussion Link https://ethereum-magicians.org/t/eip-1418-storage-rent/10737
Requires EIP-1559

摘要

在每个区块,基于每个账户使用的存储量,从每个账户中扣除一定数量的价值(“租金”)。

动机

以太坊是一个公共事业,我们低估了长期存储的成本。存储成本可以近似地建模为 字节 × 时间。

规范

更新的交易类型

引入了一种新的交易类型。 EIP-1559 引入了合约状态的热访问,而这种新的类型引入了合约代码的热访问。

新的状态变量(每个账户)

  • σ[a]_rent – 一定数量的价值,以 Wei 为单位,这是一个有符号的值
  • σ[a]_storageWords – 存储中的字数

新的常量

  • RENT_WORD_COST – 每个字-块需要支付的租金成本,以 Wei 为单位
  • RENT_ACCOUNT_COST – 每个账户-块需要支付的租金成本,以 Wei 为单位
  • FORK_BLOCK – 何时开始实施

新的操作码

  • RENTBALANCE(address) – G_BALANCE – 类似于 BALANCE
    • 这将返回逻辑上的 σ[a]_rent 值,该值被定义为每个区块递减。实现可以使用推荐的实现变量来计算此值,而不是为每个账户的每个区块存储和更新 σ[a]_rent
  • SENDRENT(address, amount) – G_BASE – 将价值转换为租金并发送到账户
    1. σ[account]_rent += amount
    2. σ[msg.sender]_balance -= amount

更新的操作码

建立一个新的子程序,用于支付租金,如下所示:

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
  • SSTORE(account, key, value)
    • 执行 PAYRENT(account)
    • 如果 account 被驱逐(即 NUMBER > σ[account]_rentEvictBlock),则交易失败,除非使用新的交易类型并包含足够的证明来验证旧的存储根并计算新的根。
    • 执行正常的 SSTORE 操作
    • 如果此 [account, key] 的旧值为零,而新值为非零,则 σ[account]_storageWords++
    • 如果此 [account, key] 的旧值为非零,而新值为零,则 σ[account]_storageWords--,如果结果为负数,则设置为零
  • SLOAD(account, key)
    • 如果 account 被驱逐(即 NUMBER > σ[account]_rentEvictBlock),则交易失败,除非使用新的交易类型并包含足够的证明来验证现有的存储根和现有的存储值。
    • 执行正常的 SLOAD 操作。
  • CALL (及其衍生)
    • 如果目标块被驱逐(即 NUMBER > σ[account]_rentEvictBlock),则交易失败,除非使用新的交易类型并包含足够的证明来验证现有的代码。
    • 执行正常的 CALL 操作
  • CREATE
    • 设置 σ[account]_rentLastPaid = NUMBER
    • 执行正常的 CREATE 操作
    • σ[account]_storageWord = 0
    • 注意:这里可能存在一个先前存在的租金余额

新的内置合约

  • PAYRENT(address, amount) – 调用 PAYRENT 操作码
    • 这方便了人们从他们的账户发送 Ether 并将其转换为租金。请注意,简单账户 (CODESIZE == 0) 不能调用任意操作码,它们只能调用 CREATE 或 CALL。
    • 如果可能,PAYRENT 的 Gas 成本将为 10,000 或更低。

计算现有账户的 σ[account]_storageWord

草案…

如果在分叉块上,只有知道每个账户的完整存储量的存档节点才需要参与,这不是一个可接受的升级。

如果所需的 σ[account]_storageWord 可以根据新的交易活动逐步计算(或估计),那么这将是一个可接受的升级。

草案:我认为可以使用无偏估计器来进行这种可接受的升级

  • 在首次访问给定密钥时,为旧账户的每个 SSTORE 添加一个存储位
  • 为每个 trie 级别添加 log(n) 位
  • 假设存储密钥是一个随机变量

更多思考…

当前操作码 Gas 成本没有变化。

理由

没有调用

合约不会知道或对租金的接收做出反应。这没关系。解决方法:如果合约真的需要知道谁提供了租金支付,那么它可以在其 ABI 中创建一个函数来归属这些支付。已经可以通过使用 SELFDESTRUCT 在没有归属的情况下向合约发送付款。像 TRON 这样的其他区块链允许将价值转移到合约,而无需执行调用。

驱逐责任 / 延迟评估

该规范将驱逐的责任赋予共识客户端。这是最可预测的行为,因为它恰好在应该发生的时候发生。此外,不需要任何激励机制(退还 gas,赏金)供外部参与者(链下)监控账户并请求移除。

一个区块中可能会驱逐任意数量的账户。这没关系。客户端实现不需要跟踪哪些账户被驱逐,只需就账户被驱逐的条件达成一致即可实现共识。

没有将租金转换为价值

转换为租金的 Ether 无法转换回来。任何从事会计工作并了解礼品卡的人都会告诉你这是一个好主意。它使对系统的推理变得容易得多。

账户支付租金

是的,他们支付租金。计算他们的余额需要资源,所以我们向他们收取租金。

为什么需要单独的租金账户?

因为任何人/每个人都可以为租金账户做出贡献。如果你依赖一个合约,你应该为其租金做出贡献。

但是合约可以花费其所有价值。

通过维护一个单独的租金和价值余额,这使得人们可以为租金做出贡献,同时确信这可以让合约保持存在。

注意:克隆。有了这个 EIP,允许存储克隆可能变得可行。是的,真的。因为新的克隆将支付租金。参见其他 EIP,我认为是由 Augur 团队制作的。

经济学和常量

2015 年执行的 SSTORE 消耗了 20,000 gas,并且已经持续了大约 600 万个区块。Gas 价格一直在 1 ~ 50 Gwei 左右。所以到目前为止,每个区块每个字基本上是 4,000 Wei。也许存储一个账户比存储一个字密集 10 倍。但实际上 G_transaction 是 21,000,G_sstore 是 20,000,所以这些是相似的,它们都可以创建新的账户/字。

怎么样:

  • RENT_WORD_COST – 4,000 Wei
  • RENT_ACCOUNT_COST – 4,000 Wei
  • FORK_BLOCK – 何时开始实施

租金以冷酷无情的 Ether 定价。它不是由客户端协商的,也不是动态的。

未来的 EIP 可能会更改此定价以使其变为动态。例如,为了公证一个区块,公证人可能需要证明他们拥有当前的存储数据集(不包括驱逐)。此外,他们可能还会证明他们拥有数据集加上驱逐以赚取额外的费用。被驱逐账户的相对存储量,以及其他账户与额外费用的价值的对比,可以用作反馈机制来设定存储的市场价格。

仅供参考,以太坊主网数据集中大约有 150 亿个字,总共开采了大约 1 亿个 Ether。这意味着如果所有 Ether 都以当前拟议的价格花费在存储上,则将是 400 TB-年 的存储。我不确定以这种方式看待它是否有帮助。

向后兼容性

EIP-1559 已经引入了一种机制,允许节点在不记录完整的网络状态的情况下参与,并允许客户端在其类型 2 交易中使用存储数据来预热缓存。

用户需要接受教育。

许多智能合约允许任何人在其中使用任意数量的存储。这可能会限制在现有链上部署此提案的有用性。

推荐的实现变量(每个账户)

  • σ[a]_rentLastPaid – 块号,在以下情况下设置:
    • 价值被转移到账户 (CREATE, CALL, SELFDESTRUCT)
    • 为账户设置代码 (CREATE)
    • 账户的存储被更新 (SSTORE)
    • 对于所有账户,这都以 FORK_BLOCK 的逻辑值开始
  • σ[a]_rentEvictBlock – 此账户将被驱逐的块号

存储说明

对于每个被驱逐的账户,客户端可以选择从磁盘中删除该存储。未来的 EIP 可能会激励保留这些额外数据以收取费用。未来的 EIP 可以创建一个机制,供客户端交换有关这些存储状态的信息。

安全考虑

许多智能合约允许任何人在其中使用任意数量的存储。

版权

通过 CC0 放弃版权和相关权利。

Citation

Please cite this document as:

William Entriken (@fulldecent), "EIP-1418: 区块链存储租金支付 [DRAFT]," Ethereum Improvement Proposals, no. 1418, September 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1418.