/ EIPS / eip-1418.md
eip-1418.md
  1  ---
  2  eip: 1418
  3  title: Blockchain Storage Rent Payment
  4  author: William Entriken (@fulldecent)
  5  discussions-to: https://github.com/ethereum/EIPs/issues/1418
  6  status: Draft
  7  type: Standards Track
  8  category: Core
  9  created: 2018-09-16
 10  ---
 11  
 12  # Simple Summary
 13  
 14  At each block, deduct an amount of value from every account based on the quantity of storage used by that account.
 15  
 16  # Abstract
 17  
 18  The most naive implementation would be to simply loop through every account on each block and deduct a certain fee. We show that a better implementation could achieve reasonable performance. Also we review practical considerations of switching to a fee-based rent system.
 19  
 20  In other words, `product=0; while(factor1--)product+= factor2;` is slow, but equivalently `product = factor1 * factor2` is fast. And we can reason about both at the same time.
 21  
 22  # Motivation
 23  
 24  Ethereum is a public utility and we are underpricing the long-term costs of storage. Storage cost can be approximately modeled as bytes × time.
 25  
 26  # Specification
 27  
 28  **New state variables (per account)**
 29  
 30  * rent -- σ[a]_r -- an amount of value, in Wei
 31  * rentLastPaid -- σ[a]_p -- a block number that is set when:
 32    * Value is transferred into an account
 33    * Code is set for an account (CREATE)
 34    * An account's storage is updated (SSTORE)
 35  * storageWords -- σ[a]_w -- number of words in storage
 36  * rentEvictBlock -- σ[a]_e -- the block number when this account will be destructed
 37    * Note: it is possible that a client could implement the Yellow Paper without storing this value explicitly. It can be calculated simply on demand.
 38  
 39  **New constants**
 40  
 41  * RENT_WORD_COST -- The rent cost, in Wei, paid for each word-block
 42  * RENT_ACCOUNT_COST -- The rent cost, in Wei, paid for each account-block
 43  * RENT_STIPEND -- The amount of rent, in Wei, given to accounts when touched
 44  
 45  **New opcodes**
 46  
 47  * RENTBALANCE(address) -- G_BALANCE -- Similar to BALANCE
 48  * SENDRENT(address, amount) -- G_BASE -- Convert value to rent and send to account
 49    1. σ[account]_rent += amount
 50    2. σ[msg.sender]_balance -= amount
 51  
 52  **Updated opcodes**
 53  
 54  A new subroutine, paying for rent, is established as such:
 55  
 56  ```pseudocode
 57  PAYRENT(account)
 58      ASSERT(σ[account]_rentEviction >= NUMBER) // TODO: I'm not sure if should be > or >=
 59      blocks_to_pay = NUMBER - σ[account]_rentLastPaid
 60      cost_per_block = RENT_ACCOUNT_COST + RENT_WORD_COST * ⌈∥σ[account]_code∥ / 32⌉ + RENT_WORD_COST * σ[a]_storageWords
 61      rent_to_pay = blocks_to_pay * cost_per_block
 62      σ[account]_rent -= rent_to_pay
 63      σ[account]_rentLastPaid = NUMBER
 64      σ[account]_rentEvictBlock = NUMBER + ⌊σ[account]_rent / cost_per_block⌋
 65  END PAYRENT
 66  ```
 67  
 68  * SSTORE(account, key, value)
 69    * Perform PAYRENT(account)
 70    * Set σ[account]_rent = MAX(σ[account]_rent, RENT_STIPEND)
 71    * Do normal SSTORE operation
 72    * If the old value was zero for this [account, key] and the new value is non-zero, then σ[account]_storageSize++
 73    * If the old value was non-zero for this [account, key] and the new value is zero, then σ[account]_storageSize--
 74  * CALL (and derivatives)
 75    * If value > 0 then perform PAYRENT(account)
 76    * Do normal CALL operation
 77  * CREATE
 78    * Set σ[account]_rent = MAX(σ[account]_rent, RENT_STIPEND)
 79    * Set σ[account]_rentLastPaid = HEIGHT
 80    * Do normal CREATE operation
 81    * Note: it is possible there is a pre-existing rent balance here
 82  
 83  **Updated substate**
 84  
 85  The substate tuple is defined as:
 86  
 87  > A ≡ (As, Al, At, Ar)
 88  
 89  This includes A_t, "the set of touched accounts, of which the empty ones are deleted at the end of a transaction".
 90  
 91  This definition is updated to: "the set of touched accounts, of which the empty ones or evicted ones (BLOCK >= σ[a]_rentEvictBlock) are deleted at the end of a transaction"
 92  
 93  // TODO: I'm not sure if that should be > or >=
 94  
 95  **New built-in contract**
 96  
 97  * PAYRENT(address, amount) -- Calls PAYRENT opcode
 98  
 99  *This is a convenience for humans to send Ether from their accounts and turn it into rent. Note that simple accounts (CODESIZE == 0) cannot call arbitrary opcodes, they can only call CREATE or CALL.*
100  
101  The gas cost of PAYRENT will be 10,000.
102  
103  **No changes to current opcode gas costs.**
104  
105  # Rationale 
106  
107  **No call**
108  
109  A contract will not know or react to the receipt of rent. This is okay. Workaround: if a contract really needed to know who provided rent payments then it could create a function in its ABI to attribute these payments. It is already possible to send payments to a contract without attribution by using SELFDESTRUCT.
110  
111  **Eviction responsibility / lazy evaluation**
112  
113  The specification gives responsibility for eviction to the consensus clients. This is the most predictable behavior because it happens exactly when it should. Also there need not be any incentive mechanism (refund gas, bounty) for outside participants (off chain) to monitor accounts and request removal.
114  
115  This adds a computational responsibility to the clients to track eviction dates. This is possible in efficient time (at double the memory) using a double-ended priority queue (one for addressing by account address, the other for addressing by eviction date). There may be other ways of implementing this with different time-memory guarantees.
116  
117  **No converting rent to value**
118  
119  Ether converted to rent cannot be converted back. Anybody that works in accounting and knows about gifts cards should tell you this is a good idea. It makes reasoning about the system much easier.
120  
121  **Accounts pay rent**
122  
123  Yes, they pay rent. It costs money to keep their balances so we charge them rent.
124  
125  **You can lose all your money**
126  
127  Yes, if you do not pay rent for your account or contract then you lose it all. User education is required.
128  
129  Alternative: spend value (Ether balance) when rent is depleted
130   * Rename rentEvictBlock to rentUsingValueBlock
131   * Update eviction calculation to include RENT + VALUE. Also update CALL (and friends) operations to recalculate eviction date when value is transferred. This is the new rentEvictBlock.
132   * Update CALL (and friends), RENTBALANCE and SENDRENT operations. If HEIGHT >= rentUsingValueBlock then proceed as if rent started paying using value.
133  
134  This alternative is a good idea, if there is support I can include this part formally in the specification. The specification is a little complicated so I like the informal definition above until we have some consent around it.
135  
136  Alternative2: do not have a separate rent account -- directly deduct rent from value
137   * Every time the state is updated (including receiving value) you get a rent subsidity
138   * Need to review invariants of existing contracts to see what problems and broken assumptions this will cause in real life
139  
140  **Permanent removal**
141  
142  All state about an account is destructed during eviction. The data cannot be recovered. That's the point.
143  
144  Hint to implementers: make sure this works:
145  
146  1. Send value to a new account (gets stipend)
147  2. Pay rent to that account
148  3. Wait until after the rent expires (account is gone)
149  4. Send value to that account (gets stipend again)
150  5. Deploy a contract (CREATE) to that account (stipend gets topped off)
151  
152  # Rationale -- economics & constants
153  
154  An `SSTORE` executed in 2015 cost 20,000 gas and has survived about 6 million blocks. The gas price has been around 1 ~ 50 Gwei. So basically 4,000 Wei per block per word so far. Maybe storing an account is 10 times more intensive than storing a word. But actually G_transaction is 21,000 and G_sstore is 20,000 so these are similar and they can both create new accounts / words.
155  
156  How about:
157  
158  * RENT_WORD_COST -- 4,000 Wei
159  * RENT_ACCOUNT_COST -- 4,000 Wei
160  * RENT_STIPEND -- 4,000 Wei * 360 days worth of blocks
161  
162  The rent is priced in cold, hard Ether. It is not negotiated by clients, it is not dynamic. It is linear. Why is this a good idea? Because right now Ethereum is a system with multiple free variables -- Ether/gas price, gas/opcodes costs, Ether/block reward. [Add some note here about reducing a system of equations...] So the end result is that we can peg one of the values and it will be okay.
163  
164  By setting the RENT price in Ether and by having the existing gas prices set based on the floating rate, there is an implicit price of ~4 gwei set into the Yellow Paper. In other words, if in the future the price of gas goes to 1 Ether then people will be upset because they will say "I paid 20,000 gas for an SSTORE" but I only got 360 days of stipend. If I paid for the rent directly I would have gotten enough rent to last until the Sun explodes." I acknowledge this complaint and do not think it is sufficient to warrant dismissing this proposal.
165  
166  Q: There is a finite-ish amount of Ether and this proposal introduces a word-price in Ether, do math for me. A: The current size of Ethereum is about ~1 TB, maybe half of that is branch nodes. So that's like 15B words. There is about 100M Ether mined. The answer is that all the Ether can be spent on 400,000 terabyte-years of storage. I'm not sure if it is helpful to look at it that way.
167  
168  # Backwards compatibility
169  
170  There is a 360-day transition period (related to the RENT_STIPEND). This requires a hard fork. On the block of the fork, every account is immediately funded with enough rent to pay for ~ 360 days' worth of their current storage requirements. The formal implementation is that this new rule is applied if any existing account has σ[account]_rentLastPaid = 0. Therefore this can be implemented by clients lazily or eagerly.
171  
172  Preexisting accounts which increase their storage needs will evict sooner than 360 days.
173  
174  Users will need to be educated.
175  
176  # Test Cases
177  
178  TO BE ADDED
179  
180  # Implementation
181  
182  TO BE ADDED
183  
184  # Copyright
185  
186  Copyright and related rights waived via CC0.