New Ethereum talks, every Monday. The week's conference uploads by event, in your inbox.

Loading player…

EVM Object Format (EOF) - History and motivation by Danno Ferrin | Devcon SEA

DevconThu, Oct 9, 2025, 12:00 AM

EOF is one of the important parts of the upcoming Pectra upgrade, delivering long-standing feature requests to the EVM. This talk aims to provide insight into its history, significance, and role in Ethereum and EVM improvement, and explore the rationale for including it in the next upgrade, its potential impacts and implications, as well as long-term advantages and possible challenges. Speaker(s): Danno Ferrin Skill level: Intermediate Track: Core Protocol Keywords: Core Protocol, developer, experience, Core, Protocol Follow us: https://twitter.com/efdevcon, https://twitter.com/ethereum, https://warpcast.com/devcon Learn more about devcon: https://www.devcon.org/ Learn more about ethereum: https://ethereum.org/ Visit the https://archive.devcon.org/ to gain access to the entire library of Devcon talks with the ease of filtering, playlists, personalized suggestions, decentralized access on Swarm, IPFS and more. Devcon is the Ethereum conference for developers, researchers, thinkers, and makers. Devcon SEA was held in Bangkok, Thailand on Nov 12 - Nov 15, 2024. Devcon is organized and presented by the Ethereum Foundation. To find out more, please visit https://ethereum.foundation/

Transcript

[Music] [Music] some of the reasons we want we want to put eof into the into uh evm so about two years uh in the beginning the legend has it that the two two of the early core developers were responsible for writing evm and they did it over the weekend um and it wasn't perfect but it was it was really good and it got almost everything right I think the only thing that they changed before before it went public was they added um one of the C++ client developers who's on tpon now asked them to add the jump dust operation in there for jumps to signal that this is a correct place to land and they needed that for jit compilation for the llvm and that's an important thing to to keep in mind is that this is that jit compilation is is going to be a running theme it's going to come up with with the Z kvms so they added that feature and it was good enough it wasn't the thing with the most problems that was you know stuff like you know sinking nodes and keeping consensus together so they moved on from that so it it worked but there was still um a few things that that needed to be added early on into the evm call code didn't work like they thought it would so they replaced it with delegate call um there were some performance issues with some of the op codes so they increased the prices on some of them appropriately um the there is a bit shifting math wasn't uh wasn't exactly what they expected it to be uh so they added some bit shifting code uh and there are some developer experience requests to put in things like the rever op code so you could signal to the system that when when a call fil failed in an unexpected way that you could pass data back within the stack and outside of the stack and also some pre-compiled for some Advanced cryptography were added because that's just too inefficient for the evm to execute so one of the first big proposals to do more than just add one or two small things to the evm was EIP 615 that's a really low EIP number um and it was proposing um the the Top Line in the motivation says the design of the evm makes near linear time compilation to machine code difficult um the jump dust analysis and a few other things that were in there um a malicious person could write a piece of evm software that would take a really long time to compile and provide another form of attack to the evm so that's why uh it wasn't really you know evm uh Justin Time compilation really hasn't gone too far it's because of issues like that and so this was designed to address some of those issues and the biggest things they added was they provided a static jump instead of a relative jump and they also added um subes and the last three items if you look look at them and squint really hard it looks a lot like what we have designed in eof um they have a begin data section to say anything after this op code is data they have an object header that says this is evm code and they have code validation rules that say that everything between the beginning of the header and the beginning of the data has to be valid executable code if you stand back and squint your eyes that's some of the key features of eof so way back in 2017 a lot of the needs for eof were recognized so the obvious question is well why wasn't this done at that point in time we had all the stuff in place to get it done the reason is ethereum 2.0 AKA Serenity was announced about not too long after this this EIP was announced and it it pro it was proposing some major changes to the theorum itself among those was switching to proof of stake um and also introducing data sharding and as part of step two uh introducing ewm as as an alternate form of execution and then finally step the phase three step four was a bunch of other improvements and you'll notice the further down we go down the list the more and more it changed from the original Vision proof of stake shipped pretty much as envisioned in Serenity um the the data sharding became the rollup Centric road map and the ewm was eventually abandoned for reasons I'll get to in the next slide but that last Point um they didn't have the idea of oifc built in yet and there's a big push to aify the protocol at this point so why was ewam abandoned why they put a lot of effort into it Why didn't it ship um there were a number of reasons and one of them was just the complexity around it um we were going to have to keep the evm around and ewm around and there was there was proposals and and plans to try and get the shifting between the two versions um to to to cross compile evm and ewom um but also didn't ewom does not natively support uh the gas into it you would have to weave the gas into it and have validation rules relating to the gas and there are also issues Rel reled to the 256-bit math and that really is what caused a lot of performance problems they the the ipsilon team went through a summary of the performance of their ewm prototype in Osaka and you know they had a they came public that it wasn't as performant as they was hoping it was going to be um there were some things can be done to fix it but that it wasn't going to hit its main goal which was to be faster than interpreted evm it was kind of kind of a gut punch to to the Epsilon team but they they did the right thing and they they brought the data out and showed what was going on with it so looking at all these things with the evm is probably we should probably look and ask before we ask why eof we should ask why not eof couldn't we just do all these changes without doing a big change to the evm and just do these things peac meal so this next section we'll talk about answer that question of why not why couldn't we just you know just introduce uh immediate jumps with immediate codes why couldn't we just do SUB routines why couldn't we just enforce code data separation and validate the code why do we have to do this all at once in this big giant change and the problem is all these features are deeply intertwined you really need to do them all at once because the value comes in all of them together at the same time not on them individually and doing them individually actually creates new problems so the first thing we'll talk about is relative jumps and relative jumps um as as I mentioned before uh you needed to put the jump Target into the code using something called an immediate argument um and the push data the push op code is an example of things that have the the immediate argument so if we added a new one let's say we're going to pretend we're going to do this e z is going to be the new R jump instruction and we have a two bit two byte signed field that's going tell relative jumps and you'll see from this that we actually you know on average save a bite if if the uh if the contract is over 256 bit bytes long the problem comes with existing code that may have this op code in place for a number of reasons so here's an example up here I have of of a code that may exist um that has a couple of push instructions one of those push instruction has the 5B instruction that is the the uh the jump dust Target and then we go into some extra data that has a bunch of invalid op codes the ezo op code is not allocated so the evm doesn't care the 5B exists after the EZ FF C9 2A so if we introduce a new ezero OP code that takes two immediate bytes without doing anything to this other predeployment and hit that jump D is now going to fail and you've done nothing to change that contract except change the rules of the VM and this is the sort of change in ethereum that we frown upon and we try our best not to do we try not to break what has already been out there so to add immediate op codes would break things that exist already and here's another piece of op code that shows um why we really need to get rid of relative jumps this is a nightmare code that I learned about a few weeks ago um you could literally take that someone actually wanted to make sure that they could still kind of do any f is you can you can take some info from the call data trim it off and jump to a specific spot in your code based on that call data they were using it as a vector jump instruction but it was just this was just mind-blowing that people were actually I thought this was something that you would do as a malicious attack not that something you to find utility in and there are people that like to do things like this in their code so it's this is why we need to provide you know stronger guardrails around some of this um so one thing one approach that was tried was to just version the contracts IP 1702 was briefly in Berlin before it was taken out and so we would say great you were going to introduce um e e0 with an immediate data great all new contracts um deployed after Berlin and later will have this Rule and all contracts defined below won't have the ezero op code and we'll just have these versions and every Fork will add a new version this was ultimately rejected because every Fork was going to create a new version of evm rules that would grow and grow and grow sometimes they apply and sometimes they don't rather than having just two sets of rules you would have an infinitely growing set of rules which was going to be problematic complexity wise so that was ultimately taken back out of Berlin um after it was initially brought into it um another thing that was taken out after it was putting in was the simple sub routines and this also underscored another problem that we had during the design process of some of these up codes is we didn't always directly interact with the compiler developers so this was implemented by all of the clients it was ready to go tests were written and then a couple of weeks before we were scheduling test Nets someone pointed out that solidity said we're not going to use this this op code so solidity is not going to use it that there was quite a discussion on allore devs about why do we even have this in there and ultimately the decision was to take it out I think it was in Istanbul and this was taken out of Istanbul but we did get one change in before before the merge that is very important and foundational for E any contract that begins with ef um cannot be deployed anymore so we can guarantee you that if the deploy if the con if the code starts with the EF bite um that certain rules will be able to appli within it so so as part of the Berlin uh hard Fork that was passed in and no the London hard one of them before the merch is there's so many of them I keep forgetting but um it was it was uh enforced so that you could not Implement code that would uh use this we could preserve space for our for our validated contract containers uh there was some some uh emojis that were deployed to kind of cause problems but where this brings us up to is this brings us up to the merge and the merge is kind of an important milestone in a lot of these evm changes because for a while and all cordev to ensure that we were focusing on getting proof of stake pushed through on all the clients any and all consideration of evm changes was was put on pause until after the merge so during this time ipsilon team went and they were cooking and they they they thought about all the things that they learned from ewam and they came up with this plan for for eof and they presented it at Devcon Bogota and that brings us to talking about little eof and big EF they had originally designed it in multiple pieces and the to present it to to all the cevs say how much do we want to do do we want to do a little bit of it do we want to do a lot do we want to bring in these modules and do it all together so it was kind of a cafeteria approach how much do we want to break as part of this and so they were called little eof and big eoff little eof started with the evm object format V1 this was the container format the foundation code starts EF 0000001 you have a header section you have code you have data it's separated one of the neat things about this that's better than EIP 615 is you know the size of the container so you know if you get a truncated eof container you know you don't have all the code and you can just reject it so you're not accidentally missing code that was something that uh 615 didn't have ability to say the code ends here the data ends here this is the whole container um the next feature that was added was code validation so for that code section if the op code was not allocated it couldn't exist and if you had a code requiring immediate data all of the data for that immediate had to be present in the code or it would be rejected an important thing about the eof validation container format is if it doesn't parse the code is the entire transaction and the code is rejected the contract cannot be put on the Chain so similarly with code validation if code validation fails the contract is rejected and can't be placed on the Chain so after code validation they started to add new OP codes because as part of code validation they also went ahead and banned op codes they banned the old Dynamic jumps and replac them with relative jumps and again in the relative jumps they did one more Improvement above 615 and that they made these relative jumps not just static jumps 6 15 had static jumps and would list the PC you would jump to but these are relative giving a a two byte signed integer to say how many oper before after do you move to which is nice for compilers because they can lift and shift all the code that they need and then we added and then for big we added functions which is the answer to sub routines um it allows us to basically provide all the same functionality with sub routines just with multiple code sections and this is something that account abstraction is looking to use to provide a secondary entry point in for a lot of their functionality so it's a bit Superior to subar tees in that regard and finally stack validation this is the most complex piece of code um and specification that is in it and I think it's the most important piece of code that is in big eof what this allows us to do is if you can evaluate your code and you can pass all the stack validation rules then at runtime for all of your operands you can just ignore stack validation you know that you will have enough operands on the stack and you know there will be room on the stack and you can remove all the code that you were doing to check to say is there enough room in the stack do I have enough operands do I have too few operands the downside is it makes you do good things with code but any modern compiler is going to spit out code that is completely compatible with stack validation one minor cave yet for an optimization we added ranges for validations and this was useful and requested by solidity so they could you have one revert section rather than having to have a revert section for each stack height so you can come into that reverse section with a range of op codes and then exit the entire the entire contract so this is a tweet that I came across uh a few weeks ago and this was like some something really exciting to me uh a uh uh someone had a residency as ainc labs and they went through and they implemented uh eof in in a in a ZK context with the same contracts that way you do with Legacy and they got some amazing numbers just by implementing these features um you can get rid of all the stack checks and a lot of the other validation checks because you presume it's valid and it reduced in an improved performance by three times so that much time was spent just validating stack Heights and that that's to me I mean when you ship a 10% Improvement that's what I'm when I get excited and I start shipping stuff this is like 300% this is better than I hope for so it's already providing real value in ZK context and aots they get they get benefit but not nearly as much as zk's got this is amazing so we were ready to ship this in Shanghai except we had one minor issue with the solidity Constructor um but but vitalic about a month before our interrupt Dropped a Bomb in that he wanted to get rid of code introspection which was another thing um that that was bothering him for Z for zks the ability to take memory into code and code into memory caused all sorts of problems with zks and made things really difficult for them so we wanted to remove all the code introspection so the interrupt was decided that we were going to take it completely out of Shanghai and add new features to remove code introspection and also everyone said well while we're breaking things let's break everything we want to break do it one time do it once and for all because we'll never have to do this again right um and hopefully we'll be able to just get everything that we want broken and get it fixed and do it right so that brings us to Mega eof where we break everything that needed to be broken we do it once we try and reduce the number of times we're going to have to update the base major version of eof the first thing we started with is is contract creation which is a code introspection code introspection mostly impacts to create op codes and also to create transaction so the the solution that eof came up with um was that they would put the subcontracts in as subobjects in the container that would be validated at a contract creation time so when you do a create uh a create or a create to type operation you take that already validated code you deploy it on the blockchain validation is done and it never has to hit the memory so you say I want to deploy that and there's some some other things going in there you're allowed to put extra data into that and append data onto the existing data and let it grow so you can do your Constructor arguments um and do things like like the um Unis swaps pair contracts wants to have the token numbers burnt into the code so this allows you to do that um the next thing was the contract creation transaction this is a slight modification of existing contract Creation in that if there's any data after the um after the eof container it's passed in as input data so you can provide Constructor parameters in addition to to creating it and through this you can create objects without you can create contracts without having to copy any of it to system memory another request that came from the um that came from that we needed to do to to to ensure that we have uh I forgot which slide I'm on um but one thing we need to add to make sure that we had code ners inspection fixed was we need to be able to get out the data section before the EXT code copied everything in the container so we needed to add new OP codes that would um that would allow you to access just the data section it's just your data section right now so we get some a little bit of code privac uh benefits there um so you can return only the data you want so we need to add new OP codes for that and then after we're done with code introspection the next thing um was to get rid of gas introspection uh gas introspecting and restricting the amount of gas that you send on to your next layer of contract has created some problems uh with breaking contracts when we increase and change the gas schedule so if we don't allow you to mess with the gas like that then we're safe changing the gas schedule and doing whatever changes are necessary and the solution there is just to get new callop codes we introduced three new callop codes that don't um have gas as part of their input parameters um and also as a nice side effect we can address a dress Bas expansion because all the op codes in the evm trim all addresses above uh 160 bytes so these call op codes do not so it's safer address based expansion and that only leaves balance is the only open op code and that's one op code to fix to get full address base expansion safety if we decide we want to do that uh the compiler teams ask for a swap and dup instructions and the Viper team specifically ask for an exchange instruction which is kind of like a super swap rather than swapping it at position one to something deep in the stack you take something up to 16 items deep in the oper an stack and you swap with something else another 16 or so uh spaces deeper in the oper an stack so you can switch stuff around you can save two instructions by doing one exchange instruction it's pretty neat now this wasn't everything that we wanted to put in eof in order to uh reduce it and make it more um more testable and reduce the attack surfaces and risk surfaces there are about four features that we we removed from it um TX create is something that we might see return um it's a way to do contract Creations through a transaction variable length quantities if we want to increase the contract sizes above 64k we're probably going to need to do some changes to the contracts to make sure we can access the areas don't necessarily need it though um uh there are some issues with ISP with the with the nft erc's and with some some op um some erc's that that deal with tokens like erc20 style that that require detecting if a contract is an eoa or not and they do that via code size so we're looking in ways to address that we'll probably address that in Osaka I'm optimistic we'll get that in there and finally external data copy um we're going to investigate that and figure out if it's needed so here's a here's a diagram that Dragon put together um that explains the similarities similarities and differences between eof and evm unvalidated contracts they're more similar than are different eof just has a container format and different validation rules and a few different op codes than the evm does and when you go into executing it it uses the same execution Logic for evm and eof I know I've been in all the major clients it uses the same Loop so it's pretty awesome and I'll just finish on this slide um solidity said that by orders of magnitude the eof design is what they want for the future of the evm right thanks thank you thank you we have time for a few questions um and again you can vote to get the question that you want pushed to the top um and so we're going to start with what is the motivation for not allowing eof contracts to delegate to Legacy code one of the op codes we banned was self-destruct and self-destruct deletes the code and it deletes all of the storage and it moves value over um we wanted to remove the concept of code disappearing so the reason had a band delegate code is you could delegate call into a legacy contract that had a self-destruct operation and you could bring the effect of a self-destruct into an evm OP code um and also delegate call on alt VMS has been an attack Vector for some of their pre-compiled so it's just solves two birds with one stone thank you all right is eof the new via IR um it's kind of an inside baseball question um I don't know not not really I mean some people don't like V but what it is going to solve the stack to deep problem you're going to be able to use more than 16 variables so it's better than the new V uh since eof will have performance benefit are there plans to decrease gas cost when using eof um I think more likely we would increase gas cost of Legacy if we did that um but the performance benefits from the gas cost of eof are you just have fewer bite codes you have fewer operations so you'll see um we've we've measured this between like 3 and 5% just by using eof in the same contracts so you'll get savings just by using it without having to change the schedule amazing how far is solidity support for eof um so the one of the engineers from the ipsilon team has a prototype that compiles to the existing format of eof V1 and that's where we got our numbers for the 3 to 5% gas savings so um EO solidity is not going to ship it until eof ships so it's going to stay in a branch until it actually is in the test Nets amazing do you expect solidity to require a breaking change between 0 8X and 0.9 to add eof support um it wouldn't surprise me uh that's a decision for solidity to make um but that is probably the best way to Signal um that you're going to be using uh eof semantics other things they might require new pragmas but I think that's something for solidity to answer what was the reason why solidity didn't use sub routines in that prior iteration and are those concerns mitigated in eof um I think it actually cost a few extra bites um the way it was implemented um it wasn't saving enough bites it was actually costing a few more bytes and with 24K contract size limits every bite's precious so I think that was their main motivation for rejecting it why does eof not suffer from the complexity of versioning um it will uh 5 to 10 years down the road um what we're doing right now is what's taking so long is we're taking every possible breaking change so we don't have to do that major breaking change in the future so what we're left with is we're left with a codebase where we can add the new features that we have in a compatible way so when we add this new feature every version of every possible eof contract that existed before would still be compatible in a hypothetical eof v11 or V12 so it's fully backwards compatible by Design is eof more ZK friendly um yes in two ways uh getting rid of the code introspection means they don't have to worry about bite code coming off of the memory and creating a new contract you can know before you'd write your ZK proof what contracts you're going to have to worry about and the relative jumps in getting rid of jump test analysis and being more certain about where your jumps are going to land is huge and I think we have time for one maybe two more uh will sub routines and eof make code size analysis easier um it can uh it depends on what the compilers do with it and if people are trying to obate their code it's going to provide new creative ways to obate so it's it goes both ways this is this is a good one uh when can we get rid of the evm entirely the evm or the Legacy evm um so the problem with the legacy evm is there's some old contracts that we still need to support uh getting rid of uh sunsetting the legacy is something that we have in mind we either need to we don't know the answer to it we need to be able to say we can't do it because of reasons XYZ or we need to have a plan to do it and that's something we're going to be looking to in the next couple years amazing um and the last one is a little bit more of comment than a question so I don't know if there's uh a place you can direct people for uh to read the data section of other contracts right so the reason why we didn't want to directly do that is we want to give contracts the option of saying no one can read my data if you want to allow someone to read your data you expose a function that you then copy your data and send it back um but we're going to figure out over the next couple months if that's going to be sufficient if there's going to cause problems so there is a way out the question is is it the right designed choice so I'd encourage people who care about this to call into our evm implementor calls and and let us know why you feel it's important thank you so much

Automatic transcript — names and jargon may be misspelled.