Revm Endgame
Devcon 7 SEA·Thu, Nov 14, 2024, 04:58 AM · 24:45
Speaker
Revm is a critical component of the Ethereum ecosystem, used by builders, toolings and clients. It is an audited and proven library that is both fast and easy to use. As more projects adopt Revm, I feel the increasing burden of making breaking changes and the need to consolidate its functionality. That’s why I am thinking about Revm Endgame, a solution to support experimentation, Layer 2 features, and EIPs without the need for repository forks.
Transcript
The introduction. Yeah, in this talk I would like to talk about Endgame, the last step of RIVM project. It started a few years ago and I think I found the solution that's going to last for a while. Before that, let's talk about history and basic evolution of the project. It started in 2021.
I took a break from the work. I basically went to the seaside, relaxed a little bit, and after I came back, I did basically want to do some project that's related to infrastructure, wanted to build something that uses EVM, and I started researching what's basically on the market. And there was like three things. Open Ethereum was the client that I worked on before and it was GPA license so it was not suitable. EVModim was the new one.
It has some, it's built by an ex-colleague, it has some experimental and exotic Rust night features and it was like just interpreter. So in that So it was not enough for me. Sputnik VM, I was most interested in it. And it was older project, older EVM, but it was not that maintained. It was hard to use it.
And if you want to do inspection, tracing, you need to basically build it in some different way. And that's very hard to use. So after making PR to the Sputnik to add some generics on the instruction set, basically after two weeks of no response, nothing, and seeing the project not moving anywhere, I closed that PR and made my own REVM. In the month I had some initial initial code that can be run. This PR is fun to look at that.
By the end of 2021 I supported the latest forks, state tests for passing, it supported all precompiles, and most importantly, interface was simple. I wanted to have, from my experience with Open Ethereum, I wanted to have EVM where you settle the data and say, transect. And then basically it gives you the output of that execution. The database trait was the abstraction that allows you runtime fetching of account and storage. Environment was the way how you set transaction block, configuration, everything around it.
And inspector was the good abstraction, very powerful one that allows you runtime inspection of your EVM when you it's run get it this PR it was optimized few times but this PR was most impactful it's basically 4x the performance it was no std from the start the idea was to use it in JavaScript or Wasm. It was MIT license, and by that year, I basically jumped to another project, and REVM became my hobby. First adopters came next year. Foundry was the biggest one, the first one. The way how I met Georgios was he tweeted if there is any EVMs out there and I responded on the tweet, hey, fresh feedback if you're interested and he was in the minutes my DMs, that's Georgios, he's basically amazing in that sense.
They started integrated a few months, I think the Oliver did the first integration five months after the start, that was like March 2022. Harhead started to get their RAST backend, they published DDR this year. Builder Surges was one of the big users of the library and they would, the first one they sync from the Genesis to the tip of the mainnet and it was very nice to hear hey we are syncing everything is fine. By the end of 2022 all focus was supported, optimization was done, our REVM-GS was supported but removed by the end of the year, there is no traction. A few more optimizations were done and most importantly RET, the client, started to be made October 2022.
At that point of time I joined Paradigm to work on the client. I think I had H on my open Ethereum times. Second year, RET are mostly basically focused on the client implementation. We needed to make something stable and we did it very fastly. Team was amazing.
I planned to stay there just for a few months but I'm still there now in Intaka but either way same team. Shankar and Kakum were added and I moved on. This year, RET01 was released, big stability improvement, it was audited, it was the people liked it, people wanted to use it, it is amazing. REVM on its own hit its own milestone, it got audited. It was community driven by the company.
And it's basically the guy that finds a lot of EVM bugs. There is blog post if you want to hear more. You have got supported. And start of the year, ZK EVM become a thing. This year, I could claim, I feel that it's okay to claim that, the REVM became the most popular EVM library out there.
And it's become the critical component of Ethereum ecosystem. There's a few types of the REVM users that I can see. They're basically clients and chain. RET first, Helios, Delight client, Trin. As the execution clients, there are different chains, Optimus, Crawl, Binance, Polygon.
They are all interested to have REVM in their code, or basically, in this sense, RET and in that connection, REVM in their code or basically in the sense RET and in that connection REVM. The tooling both the foundry hardheads are basically using REVM. Builder searches, they're a little bit private but always in my DMs are the big users of it and ZKEVM basically became the standard library that's used in that field. There is even a grant by EF Foundation that basically targets REVM formal verification with the usage of the RISC-V and ZKEVMs. This all affected the future of REV and how I look at it.
So, the problems. First problem, how to do AIP testing. How to allow AIP champions to come to the code base, improve their thing, implement it, test it in the foundry if needed, and basically do their own thing and do their basically on their own time. One of the example is transient storage. I want to just move on that path.
In July 24 I got issue in GitHub. Hey can you implement that? That was one of the AIP champions that wanted this included in Aravian for him to test it in the Foundry. AIP was not included in the any hard fork, there is no even notion for it to be included. So that was mostly it.
Few months after, AAP got CFI'd so it potentially can be included in Shanghai, but either way there is not like strong guarantee. Shanghai happened, A AIP was not in sight. Next, Harfork, Cancun. July, PR was made for that AIP. August, it was merged.
In March, the AIP landed on Manet. Approximately four months before that, the AIP should be made inside the clients for the testing, for the damn nets and for test nets at the end. Another example was 3074 and I want to say all the requests that champions made were reasonable. It is from their point of view but the question that I had is like should I have started working on the API right away when I first request comes? It's a little bit silly because I have different priorities.
I cannot do everything. Should I just merge PR when it was made? The question with that is who is going to do maintenance? Who is going to remove it if the AIP was not included? Do I do it for every IP?
That would be a lot of unnecessary code. And in the end who is going to maintain all of that? Second problem with the maintainers is how to add testing dev experimental features. One of those I always try to facilitate and enable big projects that depend on our EVM to give it support, to give a way to make tech functionality happen. Sometimes there's like features, Rust features that basically enable those things as configuration, but sometimes if this is only the EVM project simple EVM project our EVMC R55 integration that require different execution environment would not be possible and problem three is chain support most of the end chains have small difference and they're not like, they don't want to move away from EVM a lot.
They're most like new chain spec hardbox, new transaction types, maybe few AIPs, but in general they're like small difference from the mainnet, the mainnet EVM. Only way to do that previously it was like to fork the project and that brings the maintenance issue and burden of maintaining to basically repos. So solution for all that is to make EVM framework. I think that's the the last stage of REVM and its endgame. What do you mean by that?
Let's make the code extensible. Chain can use REVM as the library, override the functionality that they need, add new transactions that they need and just use it as a library. That makes the core of the library same across all the chains. Implementing new AIPs that are on the mainnet would become easier and all the chains can just reuse the code. Tooling could create their own custom way to inspect.
Maybe they need more performant way. Maybe they need need RVNC, needed new execution environment. New API can be implemented and tested separately. And, for example, this is the first look how basically I'm not coming to the code a little bit. But, yeah, the main, Spectrum main, Optimize, Spectrum Optimize.
You will have different types for your different EVM that you need idea came initial idea came few years ago I looked at TV and bomb and they had like array of functions and area functions that was different by fork. So my first idea was, hey, can we introduce custom instruction and make it like allow users to implement or add their own custom instruction? That idea expanded. So it's not just on instruction, but on full logic. And that full logic function overriding was the handler from the last year I think it was very great idea but implementation wise it was like box or a pointer of function that was not the greatest and more flexible way I liked the insights that I got while implementing that and the EVM framework introduced two things.
It introduced generics on the data, on the section, block, config and it reworked the handler in a more trait-like way. So it's more easier to use few examples of that is basically how are basic of the optimism that was the first few that was first and it was included our EVM in sense of the it was included as the feature. It was very like, intrusive. With the handlers, I tried, I succeeded to extract some functionality to the handlers. But with EWM framework, that became even easier.
Currently it stands on Crate. I still have work to do on EWM framework, but it became a possibility. Another chain is called, they did the similar thing on their own repo. Just imagine like every EVM chain doing their own creates and having Foundry, RET or all the tooling support those variants of REVM. And all be tested, all be done, and basically it eases the integration with all the stack.
The split that was inside the head with the handler is there is split between the data that is currently context and the handler that is the logic part of REVM. Context contains intersection, block, usual things. It contains journaling state that allows you to revert things when the revert happens in the calls. And it contains database that fetches the runtime data. Transient storage and warming of account is all done in journaling.
Handler on the other hand has four parts. Validator that validates the interaction between block, transaction and config. Config can have chain ID that needs to be checked with the transaction chain ID, for example. Prevalidation, do some warming, do some deduct the call balance, do AIP 7702. Yeah, change delegate code to the state.
Execution is a little bit complex. It has two main loops. The frame is the loop around the calls and interpreter is loop around the bytecode, basically instructions. And in the end, we have post-execution that does refund of not spent gas. It reimbursed the caller, it basically rewards the beneficiary and creates the outcome of the execution.
In code, as you see, context has a lot of generics and it allows you basically to have it generalize. and it allows you basically to have it generalized. There is some to-dos to do. Spec needs to be moved inside configuration, but in general, this is the first view of the new context in EVM framework. Validation bar, one of the four stages in the handler, has basically self-contained.
It contains associated types of the context, an error, a few functions that need to be called. Other handler types are in similar fashion made. And you can have Ethereum validation that basically does the Ethereum-specific implementation. Many VMs become just the context and the handler. And to create your own EVR, this is an example of main EVM, it's still pending and it's probably going to be changed in small or maybe medium way.
You basically specify everything you need. For example, you have your context with some predefined data. The section and, for example, the structure inside the REVM, but you can add your intersection limitation on it. And you can specify the handler that has their own functionality. Execution, Ethereum Executor has a few fields that are maybe interesting to people.
They have a pre-compile provider and instruction provider where you can generate your basic list of pre-compiles and there is a trade that you need to implement for this to happen. On the other hand, this is an example of Inspector. Main EVM is still a work in progress, but the idea is you create your own Inspector types that implement those trades, and you can just override it. In the end, this inspector main uses the DB and inspector generics. And this is how you use it.
There are probably going to be some helper functions that allow a little bit more flexibility and utility. But I wanted to show you just an example of how this could look. In the end, I would assume a lot of users are going to come and implement their own EVM or their own extensions and just use our EVM in that form. I think that's it. Thank you very much for having me and that's it.
Thank you Dragan. It's really amazing what you have managed to do all those years with REVM. So let's start with our questions. The first question is about testing. So do you use any kind of equivalent testing or basically differential testing as part of your CI?
Yeah. or basically differential testing as part of your CI? Yeah, on every PR, state tests are run. Basically, state tests made by Ethereum Foundation, the testing team, and it's like a good first line of defense if everything is okay, if everything works. Other than that, there is fuzzing team, fuzzing projects that are run in the background by Ethereum Foundation by I think Martin Razet from GoEVM lab from GoEthereum but GoEVM lab I think is project but yeah it's there are few stages of the testing done and this is based on every new PR?
Yeah. Fuzzing is done in the background. It's not on every PR, but the state test, running it on the web assembly, some specific Rust target, running it on different targets, basically allows you to test all those things. So are there any early architectural decisions that you have regret? Yeah.
I think I didn't understand how the calls and everything that works. I still struggle with that. I didn't find a good fit on top of it. The frame and how the frame basically works with other frames, it seems it's nice but still need to land on the good abstraction on top of it. Initially the calling, the sub calling was behind the basically you call your sub call and stack became the problem so I needed to move all that to the the loop so yeah there are a few of those things the next question is if there are any plans to natively support zkvms like SP1?
Because currently you need to do some hacky patches to be able to run them. We should talk with them, basically. EVM framework is an idea that basically would allow and support this. Great. Another question, again related to ZK EVMs.
So, REVM is now used on both CPUs and ZKVMs, and these two environments have very different performance profiles. How can you optimize for the one or the other or both? In general everything is Rust compiler so it would compile optimization of Darm basically on Rust compiler so the target is different zkvms use RISC-V while the CPUs has different instruction set that are made more performant in general I didn't do the testing on the on top of it so that would be like good way to check those. I guess a follow-up here is, and probably you haven't checked yourself, and that's more about the ZKVMs, but have you any intuitions that some LLVM optimizations might be better for ZKVMs or may be better to not use some optimizations? Compiler optimization, basically.
I'm not sure. I didn't look at it. So what is missing in our EVM to be more performant than EVM1? I have some tasks in my backlog that require basically testing. Every change that happened on the performance side needs to be tested, measured, and validated that assumptions that I made are correct.
So I need to look at tail call optimization to check it. I need to look at the stack verification if this is extracted from the instruction to before it starts with the main loop, if this is going to affect the performance. Is it easy to add new precompiles? Yeah, it was one of the use cases that Odyssey used a lot and it was very easy. It's one of the biggest use cases of how you can extend, easiest and biggest ways to extend the REMM.
What's the most interesting use case that you have seen so far? ZKVMs was really, really unexpected, to be honest. It just landed, and it was like, hey, it can be used in that way. I didn't expect that. I made it nice to use it in maybe front-end so that JavaScript can be implemented on top of it.
Maybe it can be used in Wasm as some project that does that way. But ZKVM was an unexpected surprise. And it was amazing in general. Let's thank again our speakers, Dragan, for the excellent presentation. Thank you.
Automatic transcript — names and jargon may be misspelled.