{"action":"created","issue":{"url":"https://api.github.com/repos/ethereum/EIPs/issues/35","labels_url":"https://api.github.com/repos/ethereum/EIPs/issues/35/labels{/name}","comments_url":"https://api.github.com/repos/ethereum/EIPs/issues/35/comments","events_url":"https://api.github.com/repos/ethereum/EIPs/issues/35/events","html_url":"https://github.com/ethereum/EIPs/issues/35","id":118813928,"number":35,"title":"EIP 103 (Serenity): Blockchain rent","user":{"login":"vbuterin","id":2230894,"avatar_url":"https://avatars.githubusercontent.com/u/2230894?v=3","gravatar_id":"","url":"https://api.github.com/users/vbuterin","html_url":"https://github.com/vbuterin","followers_url":"https://api.github.com/users/vbuterin/followers","following_url":"https://api.github.com/users/vbuterin/following{/other_user}","gists_url":"https://api.github.com/users/vbuterin/gists{/gist_id}","starred_url":"https://api.github.com/users/vbuterin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vbuterin/subscriptions","organizations_url":"https://api.github.com/users/vbuterin/orgs","repos_url":"https://api.github.com/users/vbuterin/repos","events_url":"https://api.github.com/users/vbuterin/events{/privacy}","received_events_url":"https://api.github.com/users/vbuterin/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/ethereum/EIPs/labels/EIP","name":"EIP","color":"bfd4f2"}],"state":"open","locked":false,"assignee":{"login":"vbuterin","id":2230894,"avatar_url":"https://avatars.githubusercontent.com/u/2230894?v=3","gravatar_id":"","url":"https://api.github.com/users/vbuterin","html_url":"https://github.com/vbuterin","followers_url":"https://api.github.com/users/vbuterin/followers","following_url":"https://api.github.com/users/vbuterin/following{/other_user}","gists_url":"https://api.github.com/users/vbuterin/gists{/gist_id}","starred_url":"https://api.github.com/users/vbuterin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vbuterin/subscriptions","organizations_url":"https://api.github.com/users/vbuterin/orgs","repos_url":"https://api.github.com/users/vbuterin/repos","events_url":"https://api.github.com/users/vbuterin/events{/privacy}","received_events_url":"https://api.github.com/users/vbuterin/received_events","type":"User","site_admin":false},"milestone":null,"comments":36,"created_at":"2015-11-25T11:11:21Z","updated_at":"2015-11-27T16:02:07Z","closed_at":null,"body":"### Motivation\r\n\r\nThe Ethereum platform gives users access to a number of computational resources: particularly computational steps, memory, logs / bloom filter usage and permanent storage in the Ethereum state. For most of these resources, the gas system is roughly incentive-compatible, although price-fixing the exchange rates between these resources is, in the current framework, unfortunately required. Storage, however, is unique in that it is not ephemeral; once storage is filled, it must be stored by all full nodes forever until/if it is deliberately cleared. The cost of storage is `bytes * time`, but users are only paying for `bytes`.\r\n\r\nA partial solution exists for Ethereum 1.0 in the form of the `SSTORE` clearing refund, where a user gets up to a net 10000 gas back for converting a filled storage slot into an empty slot. However, this approach is imperfect for two reasons:\r\n\r\n1. During a block where transaction inclusion demand does not reach the gas limit (or even where the opportunity-cost gasprice is cheaper than average), miners have the incentive to fill up storage slots so as to use them as a \"bank\" that expensive transactions can use to grant themselves additional gas at a time when gasprice is expensive; essentially, conducting inter-temporal gas arbitrage with the additional negative externality of requiring all full nodes to store extra data in the meantime.\r\n2. There is no incentive to use storage slots for a short period of time instead of a long period of time.\r\n\r\n### Proposal\r\n\r\nA proposal for solving this is to introduce \"blockchain rent\": rather than charging for bytes, actually charge for bytes * time. Here is a proposed protocol for doing so:\r\n\r\n* In the account RLP, keep track of the variables `last_accessed` and `total_storage_bytes`. `last_accessed` is meant to represent the block number at which storage was most recently changed, and `total_storage_bytes` is meant to represent the total number of bytes in account storage.\r\n* When you perform an `SSTORE(k, v)` operation on the account, let `fee = (TOTFEE[block.number] - TOTFEE[last_accessed]) * account.total_storage_bytes`, where `TOTFEE[n]` is the sum of the data storage fees from block 0 to block n (eg. `TOTFEE[n] = n * c` for some constant `c` would work as a basic policy but one can come up with more dynamic policies that change per block). Set `account.balance -= fee`, `account.last_accessed = block.number` and `account.total_storage_bytes += len(v) + (len(k) if v != '' else 0) - len(old value of account.storage[k]) - (len(k) if old value of account.storage[k] != '' else 0)`. If `account.balance < 0`, destroy the account.\r\n* Create a special type of `ping` transaction which performs a dummy `SSTORE(0, account.storage[0])` operation on any desired account. Miners can run this if they see an account that needs to be deleted in order to process fees and delete it if it is in fact bankrupt. If and only if a ping leads to an account bankruptcy, it requires no gas.\r\n\r\nFor example, suppose that `TOTFEE[n] = n * 10` (ie. 10 wei per block per second), a block was last accessed in block 321070, the current block is 312085, the account has a pre-existing balance of 1000, and it only has two keys in storage:  `{\"cow\": \"dog\", \"horse\": \"doge\"}`. We should have `account.last_accessed = 321070` and `account.total_storage_bytes = 3 + 3 + 5 + 4 = 15`. Now, suppose we have a transaction that sends 10000 wei and, in the process of executing code, sets `SSTORE(\"moose\", \"deer\")`. We compute:\r\n\r\n* Balance increased from `1000` to `11000`\r\n* `fee = (TOTFEE[312085] - TOTFEE[312070]) * 15 = (3120850 - 3120700) * 15 = 2250`\r\n* Balance decreased from `11000` to `8750` due to the fee\r\n* `account.total_storage_bytes += len(\"deer\") + len(\"moose\") - 0 - 0`, ie. increased by 9 for a new total of `15 + 9 = 24`. The values subtracted are both zero because there was nothing pre-existing in that key.\r\n* `account.last_accessed = 312085`\r\n\r\n### Setting `TOTFEE`\r\n\r\nThe hardest challenge in this scheme is setting the `TOTFEE` function. One could set this to a static value (ie. `TOTFEE[n] = c * n`), but this is essentially a form of price-fixing and so is arguably hard to set in a way that is economically efficient. A somewhat more effective strategy is to set a space limit (arguably, this is no less reasonable than setting a gas limit), and targeting `TOTFEE` based on that value. For example, consider a policy where we have some function for setting a space limit `L` (eg. a flat `L = 2**35` or a linearly growing `L = 2**10 * (block.timestamp - genesis.timestamp)`). Then, every block, we set `TOTFEE[n] = TOTFEE[n-1] + 2**(20 * L / (L - total_state_size))` (ie. the fee is 2**20 wei ~= 0.001 shannon initially, then when the total state size increases to 5% of the maximum it doubles, when it increases to 10% of the maximum it doubles again, and so forth, with the doubling intervals decreasing in size and ultimately converging to a singularity at L). In theory, the amount of storage usage should increase until it hits an equilibrium equal to the marginal demand for storage at a supply somewhere less than `L` (in the case of the above example, roughly `L / 2` is plausible); the main tradeoff to be made is in the steepness of the supply function. Steeper supply functions are more robust to mistakes made in the initial supply-function-setting process, but they also lead to more volatile rent charges.\r\n\r\n### Why should I _want_ to support a proposal that adds in a \"weird new tax\" when storage usage per second is free now?\r\n\r\n* The `SSTORE` gas costs may go down, _benefiting_ dapp developers that only use storage for short time durations\r\n* The disk space requirements for a full node will go down"},"comment":{"url":"https://api.github.com/repos/ethereum/EIPs/issues/comments/160166738","html_url":"https://github.com/ethereum/EIPs/issues/35#issuecomment-160166738","issue_url":"https://api.github.com/repos/ethereum/EIPs/issues/35","id":160166738,"user":{"login":"alexvandesande","id":112898,"avatar_url":"https://avatars.githubusercontent.com/u/112898?v=3","gravatar_id":"","url":"https://api.github.com/users/alexvandesande","html_url":"https://github.com/alexvandesande","followers_url":"https://api.github.com/users/alexvandesande/followers","following_url":"https://api.github.com/users/alexvandesande/following{/other_user}","gists_url":"https://api.github.com/users/alexvandesande/gists{/gist_id}","starred_url":"https://api.github.com/users/alexvandesande/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexvandesande/subscriptions","organizations_url":"https://api.github.com/users/alexvandesande/orgs","repos_url":"https://api.github.com/users/alexvandesande/repos","events_url":"https://api.github.com/users/alexvandesande/events{/privacy}","received_events_url":"https://api.github.com/users/alexvandesande/received_events","type":"User","site_admin":false},"created_at":"2015-11-27T16:02:07Z","updated_at":"2015-11-27T16:02:07Z","body":"@smithgift the idea of a miner paying to ignore a transaction that was\narchived was only meant to create an incentive where the transaction is\nignored the bigger the incentive to execute it. But your approach where\ncosts scale linearly with the time since the transaction was last called\ncould also work for that. The real purpose of ignoring archived\ntransactions is actually so a miner can keep executing other transactions\nduring the time it takes to retrieve the old contract from the archive.\n\nI like where this is going. To be honest I'm not sure we even need to pay\nthe \"rent\" anymore. A rational miner would execute any transaction where\nthe fee paid was bigger than the cost of the contract + cost of reviving it.\n\nOn Fri, Nov 27, 2015 at 1:07 PM, Smithgift <notifications@github.com> wrote:\n\n> Going with a \"users pay rent\" system in an archiving world, a contract\n> call costs an additional (timeSinceLastRent * rentFee * spaceUsed) gas. An\n> older contract costs more to call, but that's reasonable in a high-usage\n> world (more popular contracts may be cached by the miners.) When that\n> additional cost reaches the cost it would take to revive the contract, the\n> additional cost is capped, but the contract may be archived.\n>\n> In this system, revival costs scale linearly with the size of the\n> contract. This may mean that sufficiently large contracts are practically\n> impossible to revive, but this may not be a bad thing.\n>\n> Unfortunately, this system may be naive in incentives for the users,\n> because the first user to use a contract in a while will have to pay for\n> the whole usage, whereas the next in the same block has it free. Perhaps\n> the unpaid rent balance should be payed in parts by some function, such\n> that the cost is spread between users.\n>\n> An alarm clock system that automatically pays rent based on insurance\n> bonds would not be difficult to implement.\n>\n> —\n> Reply to this email directly or view it on GitHub\n> <https://github.com/ethereum/EIPs/issues/35#issuecomment-160156815>.\n>\n\n\n\n-- \n\nAlex Van de Sande\nUX Designer\n"}}