From 05447fbaee054c0f0d32563f5cf466483a41149b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 18 Sep 2019 14:37:33 +0200 Subject: [PATCH] EIP-1682: Storage Rent (#1682) * add storage rent EIP * clarifications * Update eip-draft_storagerent.md * Rename eip-draft_storagerent.md to eip-1682.md * Added discussion URL * Slight formatting fix * Rename Simple Summary to Abstract (as per latest EIP-1 rules) * Set status to Abandoned * Added missing section placeholders --- EIPS/eip-1682.md | 220 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 EIPS/eip-1682.md diff --git a/EIPS/eip-1682.md b/EIPS/eip-1682.md new file mode 100644 index 00000000..6c815182 --- /dev/null +++ b/EIPS/eip-1682.md @@ -0,0 +1,220 @@ +--- +eip: 1682 +title: Storage Rent +author: Felix J Lange (@fjl), Martin Holst Swende (@holiman) +discussions-to: https://ethereum-magicians.org/t/storage-rent-eip/2357 +status: Abandoned +type: Standards Track +category: Core +created: 2018-11-10 +--- + +## Abstract + +This EIP describes a scheme to charge for data in state, and 'archive' data which is no longer being paid for. It also describes how resurrection of 'archived' data happens. + +## Motivation + +The Ethereum blockchain in its current form is not sustainable because it grows +indefinitely. This is true of any blockchain, but Ethereum grows faster than most chains. +Many implementation strategies to slow down growth exist. A common strategy is 'state +pruning' which discards historical state, keeping only the active copy of contract data +and a few recent versions to deal with short-range chain reorganizations. Several +implementations also employ compression techniques to keep the active copy of the state as +small as possible. + +A full node participating in consensus today requires storing large amounts of data even +with advanced storage optimizations applied. Future storage requirements are unbounded +because any data stored in a contract must be retained forever as dictated by the +protocol. This EIP attempts to correct this by adding new consensus rules that put an +upper bound on the size of the Ethereum state. + +Adding these new rules changes fundamental guarantees of the system and requires a hard +fork. Users of Ethereum already pay for the creation and modification of accounts and +their storage entries. Under the rules introduced in this EIP, users must also pay to keep +accounts accessible. A similar rent scheme was proposed in [EIP-103] but rejected +even back then because the proposal would've upset peoples expectations. As implementers +of Ethereum, we still feel that state rent is the right path to long-term sustainability +of the Ethereum blockchain and that its undesirable implications can be overcome with +off-protocol tooling and careful design. + +[EIP-103]: https://github.com/ethereum/EIPs/issues/35 + +## Specification + +The cost of storing an account over time is called `rent`. The amount of `rent` due depends +on the size of the account. The `ether` that is paid for `rent` is destroyed. The `rent` is deducted whenever an account is touched. + +`rent` can be paid from the account's regular `balance` or from its 'rent balance'. Accounts +can be endowed with `rent balance` through a new EVM opcode. When `rent` is charged, it is +first taken from the `rent balance`. When `rent balance` is zero, it is instead charged from the account's regular `balance` instead. + +The reason to separate `balance` and `rent balance` is that certain contracts do not accept `ether` sends, or always send the entire balance off to some other destination. For these cases, a separate`rent balance` is required. + +When an account's `balance` is insufficient to pay rent, the account becomes `inactive`. Its +storage and contract code are removed. Inactive accounts cannot be interacted with, i.e. +it behaves as if it has no contract code. + +Inactive accounts can be restored by re-uploading their storage. To restore an inactive +account `A`, a new account `B` is created with arbitrary code and its storage modified +with `SSTORE` operations until it matches the storage root of `A`. Account `B` can restore +`A` through the `RESTORETO` opcode. This means the cost of restoring an account is +equivalent to recreating it via successive `SSTORE` operations. + +### Changes To State + +At the top level, a new key `size` is added to the accounts trie. This key tracks the +total number of trie nodes across all accounts, including storage trie nodes. To track +rent, the structure of account entries is changed as well. + +Before processing the block in which this EIP becomes active, clients iterate the whole +state once to count the number of trie nodes and to change the representation of all +accounts to the new format. + +#### Account Representation + +```text +account = [nonce, balance, storageroot, codehash, rentbalance, rentblock, storagesize] +``` + +Each account gets three additional properties: `rentbalance`, `rentblock` and +`storagesize`. + +The `rentbalace` field tracks the amount of `rent balance` available to the account. Upon +self-destruction any remaining `rent balance` is transferred to the beneficiary. Any +modification of the account recomputes its current `rent balance`. + +The `rentblock` field tracks the block number in which the `rent balance` was last +recomputed. Upon creation, this field is initialized with the current block number. +`rentblock` is also updated with the current block number whenever the account is +modified. + +The `storagesize` field tracks the amount of storage related to the account. It is a +number containing the number of storage slots currently set. The `storagesize` of an +inactive account is zero. + +### Charging Rent + +There is a new protocol constant `MAX_STORAGE_SIZE` that specifies the upper bound on the +number of state tree nodes: + +```python +MAX_STORAGE_SIZE = 2**32 # ~160GB of state +``` + +A 'storage fee factor' for each block is derived from this constant such that fees +increase as the limit is approached. + +```python +def storagefee_factor(block): + ramp = MAX_STORAGE_SIZE / (MAX_STORAGE_SIZE - total_storage_size(block)) + return 2**22 * ramp +``` + +When a block is processed, `rent` is deducted from all accounts modified by transactions in +the block after the transactions have been processed. The amount due for each account is +based on the account's storage size. + +```python +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 +``` + +### New EVM Opcodes + +#### `PAYRENT ` + +At any time, the `rent balance` of an account may be topped up by the `PAYRENT` opcode. +`PAYRENT` deducts the given amount of `ether` from the account executing the opcode and adds +it to the `rent balance` of the address specified as beneficiary. + +Any participant can pay the rent for any other participant. + +Gas cost: TBD + +#### `RENTBALANCE ` + +The `rent balance` of an account may be queried through the `RENTBALANCE` opcode. It pushes the +`rentbalance` field of the given address to the stack. + +Gas cost: like `EXTCODEHASH`. + +#### `SSIZE ` + +This opcode pushes the `storagesize` field of the given account to the stack. + +Gas cost: like `EXTCODEHASH`. + +#### `RESTORETO ` + +This opcode restores the inactive account at the given address. This is a bit like +`SELFDESTRUCT` but has more specific semantics. + +The account at `addr` must be `inactive` (i.e. have `storagesize` zero) and its +`storageroot` must match the `storageroot` of the contract executing `RESTORETO`. The +`codeaddr` specifies the address of a contract from which code is taken. The code of the +`codeaddr` account must match the `codehash` of `addr`. + +If all these preconditions are met, `RESTORETO` transfers the storage of the account +executing the opcode to `addr` and resets its `storagesize` to the full size of the +storage. The code of `addr` is restored as well. `RESTORETO` also transfers any remaining +balance and rent balance to `addr`. The contract executing `RESTORETO` is deleted. + +Gas cost: TBD + +## Rationale + +### Why do we need a separate rent balance? + +Accounts need a separate rent balance because some contracts are non-payable, i.e. they +reject regular value transfers. Such contracts might not be able to keep themselves alive, +but users of those contracts can keep them alive by paying rent for them. + +Having the additional balance also makes things easier for contracts that hold balance on +behalf of a user. Consider the canonical crowdfunding example, a contract which changes +behavior once a certain balance is reached and which tracks individual user's balances. +Deducting rent from the main balance of the contract would mess up the contract's +accounting, leaving it unable to pay back users accurately if the threshold balance isn't +reached. + +### Why restoration? + +One of the fundamental guarantees provided by Ethereum is that changes to contract storage +can only be made by the contract itself and storage will persist forever. If you hold a +token balance in a contract, you'll have those tokens forever. By adding restoration, we +can maintain this guarantee to a certain extent. + +### Implementation Impact + +The proposed changes tries to fit within the existing state transition model. Note that +there is no mechanism for deactivating accounts the moment they can't pay rent. Users must +touch accounts to ensure their storage is removed because we'd need to track all accounts +and their rent requirements in an auxlilary data structure otherwise. + +## Backwards Compatibility + +TBA + +## Test Cases + +TBA + +## Implementation + +TBA + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).