Applications of Transient Storage (EIP-1153)
ETHCC 5 · July 2022 · 15:07
Moody Salem examines applications of transient storage in the EVM through the proposed EIP-1153.
Speakers
Topics
From ETHCC 5, hosted by Ethereum France.
Transcript
foreign thanks for coming to my late evening talk on uh applications of transient storage my name is Moody I'm an advisor at uniswap labs um just quick intro worked at unit swap for two years developed Universal V3 and now I'm an advisor always up for Smash Bros so come find me um or table tennis and my goal with this talk is just to convince everyone that transient storage is more than just a gas optimization
um so transient storage is a sort of a different way of using storage and so let's get into that um first with a background what it is and how it's used today and then we're going to go through a little story of building a Marketplace protocol um just to get an idea of like how this helps you improve the protocols You're Building um so so first first things first is uh you probably already do use transient storage and uh really it's just when you're using a storage slot uh by writing a non-zero value and then writing it back to zero before the end of the transaction so the most common use case is re-entrancy locks and oftentimes you'll
see a modifier lock which does locked equals true underscore locked equals false that's the most common use case and most people already use it we use it as well for uh constructing swap pools using it for outbox um like uh L2 Roll-Ups like R which means that um and so there's a lot of use cases in the ecosystem today and the reason it's uh it has a special uh classification is because when you do this zero to non-zero to zero right and you actually get an a refund from the evm a gas refund um
so let's get into the usages the first one I talked about re-entered C walks look like this uh what they do is prevent reentrancy which is uh which causes a huge uh fraction of uh all smart contract vulnerabilities so you've probably already seen this so this prevents re-entrance another usage which we use is a little more esoteric most people don't use it we use it to basically get a code hash of a usual pool a constant which makes it cheaper to compute the address of a pool and chain significantly cheaper um and so you know the deployer will set some parameters for the Constructor arguments we'll deploy the pool and then we'll delete those parameters from
storage and so that's an example of a transient storage use um here's another usage not a unit swap it's the arbitrant outbox um so what they'll do is when they're executing a transaction sent from L2 to L1 they'll put the context of the L2 transaction in storage call make the l2.1 call and then they'll delete this from storage and so this surfaces the L2 context to the L1 transaction without making any assumptions on the interface of of the contract that's being called so
transient storage is already in the evm so why do we need an EIP what's what's the difference um so there's some issues with the current approach and the biggest one the most recent one is that refunds are now capped as of the London hard Fork to uh 20 of all the gas using a transaction so if you if you go over that cap for a refund you basically pay 20K gas for something that's not ever writing to storage um and it's really just 32 bytes of memory so that's way way more expensive than um the actual M store and M load um and the context for that is gas token
getting a gas token and block sizability um so there are good reasons for doing that um also storage refunds are not given on revert so if you write a slot uh and then you write back to zero and then you revert you don't even get the refund so there's there's a lot of gas wasted there which never writes to disk um and a really important distinction is that uh with regular storage you can't avoid reading the original zero value from disk um so uh even though in your contract you know that locked is always false when someone enters your contract and always falls when they successfully exit
or revert um you the node still has to read from them from the tree to get the value zero so it's it's a wasted s load in wasted reads always um and probably the most um important one is that uh this one and under emphasize the storage refund logic is really complicated and I was actually working on a slide to like uh describe exactly how much gas in a store would cost and I had to go through like four different eips which refer to each other and I couldn't even figure it out so I ended up discarding that slide um but yeah it's really hard for a developer if you show them a piece of
code to understand uh how much gas a particular piece of code will cost if it touches storage so that's where eiplm53 comes in it brings two new opcodes one of them is T load you know there's t-store they behave exactly the same as s load and s store except they only persist within a single transaction and so because of that they never have to read from disk and they never have to write to disk which are the most expensive operations for a node um and so they can be priced much cheaper uh but they do have to be a little bit more
expensive than memory because uh they still have to revert just like s store and s-load deal with reverts um yeah so here's a here's a visualization from The ethereum Magicians thread uh by Pascal um and the important thing they gathered from this is that transient storage is a lot more like machine State uh than like persistent storage and yeah another way to think of it is it's it's like a transaction persistent memory region for for contracts um and so going back to those previous use cases
um they're all just way cheaper now you don't have to read the original value from storage and uh and it's also just you don't have to deal with refunds so you have to worry about how much gas uh the transaction is spending whether you're going to get the full refund which you often wouldn't with in the case of uh use swap V2 and so we actually did a trick here where instead of doing zero one uh one zero rates we did one zero one rates and that's because the refund for doing that is a little bit smaller but the drawback is now you're just wasting uh 32 bytes uh on every pool for no reason um and plus you're wasting all those reads um so yeah that's that's sort of the
background but uh I want to make the argument that uh you know uh it doesn't just improve uh these existing use cases it uh because it's so much cheaper and so much more accessible you can you can create a smart contracts with uh new patterns um and we're going to go through that with this next story so let's say let's say we're uh designing a Marketplace contract customers can buy items for fixed prices customers can sell items for fixed prices and so you can imagine it's something like Seaport but maybe just like fixed prices on every nft um so version one might look something like
this uh you have a function on the contract called buy a function on the contract called cell and when you call by you receive the item you have to send the payment for item one when you call by you have to do the same thing again and when you call cell you transfer the item receive payment um and so this is a little naive because you're doing extra calls extra transfers um it doesn't work very it's just more expensive than it used to be so you might want to do something like uh batching all your buys and then batching all your cells um and so you might you know refactor and make it look like this where you allow the user to specify multiple times they want to buy and then they have to send the net payment
and then multiple items in the cell and receive that payment um but let's say like the user wants to buy item one and two and then sell item three to partly pay for it this doesn't work very well for that because they have to put up front all the money for buyer or call sell before buy so it imposes some restrictions um so what you do is you design this new method execute orders which takes some list of like arbitrary operations with their own arguments buy one buy two sell three sell four uh and so uh within this method you only have to deal with the
net uh amount that you have to pay or that you're being paid um and so this works but what if uh pricing is dynamic um or like what if the user has to respond to the price they get when they buy two or they want to sell three and then only sell four uh if the result of some contract call is true um or like if they don't have enough to buy one two by only selling three so so like the user will want to impose like their own logic in between these contract calls and so that makes this a little bit uh uh difficult to work with and there are ways you can solve this by adding different kind of operations
let's say in between your buy and sell you have another call to another contract um to to do some additional logic or conditional cells but you're getting into more and more complex designs which are very hard to work with and you're gonna have to deal with encoding this very complex order on chain noodle chain um so you when we think about these uh types of orders is there they're sort of like codes within arguments um and you're kind of Designing you're designing a virtual machine which is your protocol with these like biop code cell op codes you know conditional cell Etc and it's like it's really hard to design the perfect VM which is the whole reason we have eaps
um so yeah instead instead of trying to design the perfect uh Execute Order function uh there's this alternate design where you enforce contract level invariants so you can call into this lock function the customer will get a call back and you can do the buys and sells you can do anything you want within the context of the evm you can call arbitrary contracts and then at the end all you have to do is pay uh the differences and transfer the items that you owe the contract and the way the contract remembers in between these different calls uh how much you owe it is the buys and sells and then it checks the the invariance and transient storage at the end
um so this this allows the user the full freedom of the evm to do any action they want uh within the context of the lock as long as they uh meet the invariance of the marketplace um so here's an easy way to think about talking about how you can call the till pattern it acts sort of as a cash register so it's like a till uh you check the total value in the till and you can also think of it you can remember because you're deferring all the validation till the end so it's kind of like until the user is done interacting with your contracts um and yeah here's the current state of it uh it's being implemented by unoswap Labs mostly but they're working with contractors uh Mark time white kicked it off with uh he's from optimism at 8
Denver at a hackathon he started the ethereum jsbm death has completed worked nevermind progress so so we're making a lot of progress towards it Hari call out to Hari today just implemented the assembly op codes and solidity um and you can test against it today if you just use a particular hard hat uh package version um so yeah please add your uh use cases to the thread and I hear some additional links any questions if there's any question don't hesitate to ask location is there any current estimated timeline
yeah so uh it's definitely not going with the merge obviously um Shanghai I think probably will be uh maybe early mid next year I don't know if anyone really knows but um but like we're trying to get it to be CFI for Shanghai but there's a little bit of pushback just because of priorities um so been next year rivers and storage and more expensive than memory do you have any number on the gas cost of these up codes yeah so right now it's priced at 100 gas and we did some uh both of them are 100 gas
each and we did some testing uh with inferior to make sure that it didn't pose a threat to dossing any of the clients um caveat extreme X so I don't know it it may not be it may be a little too cheap right now but we haven't gotten two final numbers any more questions yeah thank you [Applause]