Account/wallet contracts implement a permissioned storage interface standard (using a sort of ACL).
Instead of ledger-within-ledger token contracts, the user of the wallet grants the token contract permission to write to the user’s own storage. Token balances, NFTs etc are now stored on the user’s account, thus the users are charged rent for their own assets. To decrease rent fees users can remove unwanted assets.
This could be a solution to the dust griefing attack mentioned in the slides.
Users can ‘deny’ tokens from storing data in their contract, reducing the viability of spam tokens. Airdrops can still be performed using a withdraw() scheme.
Token contracts will pay significantly less storage rent. Users are incentivised to pay their ‘account cost’ and be custodians of their own data usage.
(I’m uncertain if I’m reformulating the Step 3 - Linear cross-contract storage here, so please let me know if I whooshed there)
Thank you @AlexeyAkhunov . I appreciate that you had some concerns around the blowback that certain teams high up on the ‘Contracts by Storage’ list will/may receive from folks acting in bad faith. And I appreciate those concerns comes from a good and empathetic place. However, this research is excellent and concisely presented and should not have to accomodate the actions of a 'lowest common denominator.
This is really great! I’m wondering if we can split up the rent problem for contracts into two groups:
How can we get active contracts that are using lots of storage to pay a rent that more accurately represents the cost of storing that data permanently on-chain over a period of time. As you pointed out, for many contracts (Token contracts) this suffers from the free rider problem. I think the Actor/Asset model (or Linear cross-contract storage as you call it) could be an interesting solution here.
How can we clear the state of abandoned contracts that are not being used anymore? As calling SELFDESTRUCT is not free, most people don’t clear their old contracts when abandoning them (I am guilty of this too). For this case, maybe we can store an expiration_time for each contract and refresh it to now+12 months on every call to that contract. Though there may be some types of contracts that are still in-use but called very infrequently (libraries, multi-sig wallets)
#1 would offload a lot of state from large, central contracts to the actual users of the contract where rent could be applied more fairly. And #2 would help purge any state remaining on the contract itself once abandoned
I did not include this into the deck, but as it stands at the moment, abandoned contracts (those not used for the last 12 months) represent only 6% of the state. That is why measures specifically designed to go after them were not in the proposal. And they are also quite easy to neutralise if someone wishes to.
Hey Alexey, I would like to second the sentiment shared by @hershy and I’m very happy to be able to ask stupid questions here as well
Currently I understand that once a contract is evicted, it’s cross-contract storage is cleared, including the storage (on the owner’s side) that holds for example the tokens of a user. How does this influence actual ownership of assets, something that is specifically the goal of the NFT community and one of the promises of ‘gaming on Ethereum’ (once the servers go down, you still own the assets).
From a user perspective, I’m probably not aware this contract has run out of rent; my point of discovering this is when I’ve lost my assets. Additionally the community would have to rework current token standards to have actual ownership of items.
The rent model is a very elegant solution (not a UX nightmare at all); having an ‘open account’ means you pay a small fee for keeping the account open. If you store your own data, then you can do your own ‘cost’ housekeeping. The above scenario where you can lose your data is scary for a user with regards to ownership. Could you elaborate on why it is necessary to clear the user’s storage to help me understand the reasoning here?
No, when contract is evicted, only the storage it owns gets evicted, but not the storage it writes. That means, if an NFT contract suddenly goes away, users will be able to bring it back using resurrection, and all their assets will be intact, as long as they keep paying for them. And, if NFT contract is very lean and popular, it might be able to effectively immortalise itself (because it will accumulate huge rent balance) by using call-fee (page 48).
Data owners should not be allowed to modify storage written by other contracts. But they should be able to withdraw that write permission, to stop paying for the store. For example, if you sold your tokens, you do not want to pay for number “0” kept in your storage
Thanks for clearing this up for me. It makes complete sense that you shouldn’t be able to write to the storage other contracts have grown, but should be capable of cleaning it. I was mistakenly assuming it would wipe all storage written to by the <writer> when reading the eviction slide (including the user’s). Very grateful for the help.
Probably the last stupid question : It seems this is not very far removed from the actor/asset model if there is a ‘safe’ way to move that storage to another address? And if an asset could be isolated, as currently there would be an issue with the storage being a blob. As a hack for this, I can deploy a contract that won’t pay for its rent but writes to a user’s storage (so the storage is isolated) after deployment? Would an xmove and partitioned storage make this actor/asset model possible?
(I like the idea of not needing the original contract for moving my assets, doing an exchange. I don’t need to pay any extra fees to resurrect the inevitable transfer function that is built into every contract. I’m having a hunch that the above isn’t as obvious as it seems and isolating the data storage per asset encapsulates a lot more than that. And this doesn’t work for fungible tokens.)
I am afraid I did not study actor/asset model. Will look into it shortly.
I don’t quite understand, sorry Under this proposal, in the end, everything which is deployed, will pay rent, otherwise it will create abuse of primitives.
It might get quite complicated if you want to start delegating writing rights to other contracts. We are trying to propose something that will be able to curb state growth, but that won’t destroy the ecosystem. Other extensions are possible, but only if they can be added without increasing complexity.
Sorry, that was a hamfisted way of explaining what I intended to . I’m intrigued by the fact that the rent proposal almost makes it possible for contracts/users (actors) to move/transfer/own their assets (items in storage) without any further interaction with the creating contract. This would allow ‘assets’ to be treated as first class-citizens similarly to a users’ ether balance.
However, I’m admittedly not very proficient in the base layer/evm/assembly level. As I understand it, this comes with a lot of increase in complexity. Moving around storage/memory is more complicated than I make it out to be in the above example.
The described proposal in your state rent document is very elegant without doing so and I really appreciate your patience in answering these questions and helping me understand these things a bit more.
One other random thought: how we actually pay the rent (specifically using the actor/asset model)
The naive way would be to have whatever ether balance an address has be the rent payment. This makes it easier to collect rent for “large, central contracts” – just send ether to that address and it gets deducted at a rate of storage costs. If it runs out, the storage gets archived, then removed after some period (only the root remains).
However, let’s say you want to hibernate your holdings (meaning you will accept the burden of storing the state tree entry matching the root that remains). Your holdings include some significant amount of ether that you don’t want drained as you go into hibernation. A way to do that in my mind might be to make use of “semi-fungible tokens” (related to ERC 1410) where Ether holdings can be split into 2 holding groups: rent payment balance and free (non-rent) holdings. This would help contracts who are programmed to deal with escrow of Ether not to get their balances mixed with the rent payment balance.
I’ve noticed some focus on “mitigating GasToken” on other forums like ethresear.ch. Why is that? The point of GasToken is to save state and later clear it to get refunds when gas prices are high, so it’s unlikely to continue growing unbounded compared to other contract types.
I did not include this into the deck, but as it stands at the moment, abandoned contracts (those not used for the last 12 months) represent only 6% of the state.
Super interesting! From just eyeballing charts 1 and 2, it looks like total state was ~30% of current size 12 months ago. Is this right? So if 6% of current state is abandoned, that means 20% of the total state as of 12 months ago is now abandoned? That may suggest the 6% number will start growing dramatically in the coming months
Data owners should not be allowed to modify storage written by other contracts. But they should be able to withdraw that write permission, to stop paying for the store.
I’m guessing we would make a contract’s write permission all-or-nothing? E.g. assume a contract stores user balances and debts. If the user could withdraw permission for the debt-storage field, that would enable them to drain the contract.
But then is there also a token-dusting attack vector if a contract’s write permission is all-or-nothing? E.g. someone can send me dust from millions of tokens on EtherDelta which would make the rent prohibitively high. Unless we require authorization for each storage field used which seems like really complicated UX
Interesting line of thought. It might be possible to quite easily achieve that with a wrapped ETH token contract, which under the new model will have a constance storage size and can easily sustain itself by eating into the wrapped ETH it contains, or utilising callfee (page 48).
CallFee and Linear cross-contract storage both seem like powerful abstractions. Are these things that you want to add to the base layer or do you think they can be implemented in the scripting language?