Alert Source Discuss
🛑 Withdrawn Standards Track: Core

EIP-1682: 存储租金

Authors Felix J Lange (@fjl), Martin Holst Swende (@holiman)
Created 2018-11-10
Discussion Link https://ethereum-magicians.org/t/storage-rent-eip/2357

摘要

本 EIP 描述了一种对状态中的数据收费,以及“存档”不再被支付的数据的方案。它还描述了“存档”数据如何恢复。

动机

以太坊区块链以目前的形式是不可持续的,因为它会无限增长。任何区块链都是如此,但以太坊的增长速度超过大多数链。存在许多减缓增长的实现策略。一种常见的策略是“状态修剪”,它会丢弃历史状态,仅保留合约数据的活动副本和一些最近的版本,以处理短程链重组。一些实现还采用压缩技术来尽可能地保持活动状态副本的大小。

即使应用了高级存储优化,今天参与共识的完整节点也需要存储大量数据。未来的存储需求是无限的,因为按照协议规定,存储在合约中的任何数据都必须永久保留。本 EIP 试图通过添加新的共识规则来纠正这一点,这些规则对以太坊状态的大小设置了上限。

添加这些新规则会改变系统的基本保证,并且需要进行硬分叉。以太坊用户已经为创建和修改账户及其存储条目付费。在本 EIP 引入的规则下,用户还必须付费以保持账户可访问。类似的租金方案在 EIP-103 中提出,但即使在当时也被拒绝,因为该提案会扰乱人们的期望。作为以太坊的实施者,我们仍然认为状态租金是以太坊区块链长期可持续发展的正确道路,并且其不良影响可以通过链下工具和谨慎的设计来克服。

规范

随时间存储账户的成本称为 rent(租金)。应付的 rent 金额取决于账户的大小。用于支付 rentether(以太币)会被销毁。每当账户被触及时,就会扣除 rent

rent 可以从账户的常规 balance(余额)或从其“rent balance”(租金余额)中支付。可以通过新的 EVM 操作码为账户提供 rent balance。收取 rent 时,首先从 rent balance 中扣除。当 rent balance 为零时,则从账户的常规 balance 中扣除。

分离 balancerent balance 的原因是某些合约不接受 ether 发送,或者总是将整个余额发送到其他目的地。对于这些情况,需要单独的 rent balance

当账户的 balance 不足以支付租金时,该账户将变为 inactive(非活跃)。其存储和合约代码将被移除。非活跃账户无法与之交互,即它的行为就像没有合约代码一样。

可以通过重新上传其存储来恢复非活跃账户。要恢复非活跃账户 A,需要创建一个新的账户 B,其中包含任意代码,并使用 SSTORE 操作修改其存储,直到它与 A 的存储根匹配。账户 B 可以通过 RESTORETO 操作码恢复 A。这意味着恢复账户的成本相当于通过连续的 SSTORE 操作重新创建它。

状态的变更

在顶层,向账户 trie 添加了一个新的键 size。此键跟踪所有账户(包括存储 trie 节点)中的 trie 节点总数。为了跟踪租金,账户条目的结构也发生了变化。

在处理此 EIP 生效的区块之前,客户端会迭代整个状态一次,以计算 trie 节点的数量并将所有账户的表示形式更改为新格式。

账户表示

account = [nonce, balance, storageroot, codehash, rentbalance, rentblock, storagesize]

每个账户都有三个额外的属性:rentbalancerentblockstoragesize

rentbalance 字段跟踪账户可用的 rent balance 金额。在自毁时,任何剩余的 rent balance 都会转移给受益人。对账户的任何修改都会重新计算其当前的 rent balance

rentblock 字段跟踪上次重新计算 rent balance 的区块号。创建时,此字段将使用当前区块号进行初始化。每当修改账户时,rentblock 也会使用当前区块号进行更新。

storagesize 字段跟踪与账户相关的存储量。它是一个包含当前设置的存储槽数量的数字。非活跃账户的 storagesize 为零。

收取租金

有一个新的协议常量 MAX_STORAGE_SIZE,它指定了状态树节点的数量上限:

MAX_STORAGE_SIZE = 2**32 # ~160GB 的状态

每个区块的“存储费用因子”由此常量得出,因此费用会随着接近限制而增加。

def storagefee_factor(block):
    ramp = MAX_STORAGE_SIZE / (MAX_STORAGE_SIZE - total_storage_size(block))
    return 2**22 * ramp

处理一个区块时,在处理完交易后,会从该区块中交易修改的所有账户中扣除 rent。每个账户应付的金额基于该账户的存储大小。

def rent(prestate, poststate, addr, currentblock):
    fee = 0
    for b in range(prestate[addr].rentblock+1, 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 = currentblock

新的 EVM 操作码

PAYRENT <amount> <addr>

在任何时候,都可以通过 PAYRENT 操作码来增加账户的 rent balancePAYRENT 从执行操作码的账户中扣除给定的 ether 金额,并将其添加到指定为受益人的地址的 rent balance 中。

任何参与者都可以为任何其他参与者支付租金。

Gas 成本:待定

RENTBALANCE <addr>

可以通过 RENTBALANCE 操作码来查询帐户的rent balance。它将给定地址的rentbalance字段推送到堆栈。

Gas 成本:类似于 EXTCODEHASH

SSIZE <addr>

此操作码将给定帐户的 storagesize 字段推送到堆栈。

Gas 成本:类似于 EXTCODEHASH

RESTORETO <addr> <codeaddr>

此操作码恢复给定地址处的非活动帐户。这有点像 SELFDESTRUCT,但具有更具体的语义。

addr 处的帐户必须为 inactive(即具有 storagesize 零),并且其 storageroot 必须与执行 RESTORETO 的合约的 storageroot 匹配。codeaddr 指定从中获取代码的合约的地址。codeaddr 帐户的代码必须与 addrcodehash 匹配。

如果满足所有这些前提条件,则 RESTORETO 会将执行操作码的帐户的存储转移到 addr,并将其 storagesize 重置为存储的完整大小。addr 的代码也会被恢复。RESTORETO 还会将任何剩余的余额和租金余额转移到 addr。执行 RESTORETO 的合约将被删除。

Gas 成本:待定

理由

为什么我们需要单独的租金余额?

帐户需要单独的租金余额,因为某些合约是不可支付的,即它们拒绝常规价值转移。此类合约可能无法维持自身运行,但是这些合约的用户可以通过为其支付租金来保持它们的运行。

拥有额外的余额也使代表用户持有余额的合约更容易。考虑典型的众筹示例,该合约在达到一定余额后会更改行为,并跟踪各个用户的余额。从合约的主要余额中扣除租金会弄乱合约的帐户,如果未达到阈值余额,则使其无法准确地偿还用户。

为什么需要恢复?

以太坊提供的基本保证之一是只有合约本身才能更改合约存储,并且存储将永久存在。如果您在合约中持有 token 余额,您将永远拥有这些 token。通过添加恢复,我们可以一定程度上保持这一保证。

实现影响

拟议的更改试图适应现有的状态转换模型。请注意,没有在帐户无法支付租金时立即停用帐户的机制。用户必须触摸帐户以确保删除其存储,否则我们需要在辅助数据结构中跟踪所有帐户及其租金要求。

向后兼容性

待定

测试用例

待定

实现

待定

版权

CC0 下放弃版权和相关权利。

Citation

Please cite this document as:

Felix J Lange (@fjl), Martin Holst Swende (@holiman), "EIP-1682: 存储租金 [DRAFT]," Ethereum Improvement Proposals, no. 1682, November 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1682.