From 30M to 300M: The Engineering Behind Ethereum’s Gas Limit Leap
EthCC[9] · 1 Apr 2026 · 19:12
Toni Wahrstaetter examines engineering work behind proposed increases to Ethereum’s gas limit. The presentation focuses on execution, networking and validation bottlenecks that constrain throughput.
Speakers
Topics
From EthCC[9], hosted by Ethereum France.
Transcript
Yeah, hello everyone. My name is Tony. I'm with the firm foundation. Happy to be here. And today's topic will basically be scaling. So, before we get into the topic, I want to quickly tell you like some history, how we got where we are today, and also in the end of the talk looking a bit into the future. So, getting into it, how we got where we are today. This is basically the daily gas used summed up per day, and you can see that Ethereum has been scaling quite a lot since the beginning.
Um especially the most important and most significant event that you see on this chart is the London hard fork where we shipped 1559. And since then, since the London hard fork, we had the merge that very stable stabilized like the daily gas usage. But since then, not much happened basically. And the London hard fork allowed us to go from um 50 million gas limit to 30 million. So, basically already doubling the gas limit. But then, for 3 years um we weren't really scaling.
And because of that, the community developed like this appetite for scaling. And more and more people were pushing for increasing the gas limit. And nothing happened for 3 years. And then, at the end of this chart at the very right-hand side, we entered 2024. And this was when the people basically reached out and wanted to increase the gas limit. So, this is from an Ethereum Foundation Reddit um AMA where some person asked Vitalik like, "Hey, can we increase the gas limit?"
And Vitalik very reasonable said like, "Yeah, it should be possible. A moderate gas limit increase is possible." Um reasoning about Moore's law. And this is basically how everything started. Other people like Dankrad, for example, who was also very much pushing for a higher gas limit, they were still like calling for patience because at the same time, Ethereum was just about to ship the Cancun hard fork that introduced blobs to the network. And as you might know, blobs already added a lot of data. So, people need to download and propagate all the data. And this meant if we increase the gas limit at the same time, we would also increase the network um packages by quite a lot.
So, we were still very hesitant about increasing the gas limit at that time. But over time, more and more people pushed for it. The Sepolia incident was one of those events that also slowed things down a bit because we stumbled across a bug that was caused by a big block. So, you could submit a block that was going over the 10 megabytes. And what happened on Sepolia was Geth basically forking off. And this was a very serious bug because it could have happened on mainnet, and it would have been very difficult to recover from such a bug. And fortunately, it happened only on Sepolia.
But it just showed us like just increasing the gas limit naively by just pumping some numbers is not the way to go. Then continuing, we entered the pump the gas era. And many of you might remember this era. Here we see um Paolo and Martin Köppelmann from No Syss like pushing for higher gas limit. mariano.eth launched pumpthegas.org. And this basically kind of created this great momentum for the community to eventually push for higher gas limits.
And the community wanted to go to 60 million. At the minimum, 45 million. And there were other people that had like a different opinion, you know? Just calling out this guy here who wanted to even lower the gas limit because of course we have rollups now, right? So, let's just solve the rollup fragmentation. We can even lower the gas limit. And to be clear, you know, this is like 1 and 1/2 years ago, and I was not alone. Like many people reached out and were like, "Yeah, actually that's the way to go. Let's make sure we have small blocks on Ethereum, and instead we increase the block count."
But yeah, I was convinced that this is not only a controversial take, but maybe a bad take. Then we got more and more people, Dankrad, Feeder, Sazzle. Many people were pushing hard for increasing the gas limit, but then reality hit us hard. Because what we found is if you push the gas limit beyond 39 million, we would basically break the network again. Some clients were not yet ready for gas limit increases, and what could happen is we pump the gas limit, and some nodes would just fork off.
So, this was very bad. We were basically confronted with reality once again, and realized, "Okay, we actually need to focus more on that topic." Like laying the path for um further gas limit increases. So, what happened here? We suggested the 36 million gas limit in this blog post. Um and wanted to wait until EIP-7623 is shipped. So, EIP-7623 increased the call data cost, which directly led to smaller worst-case blocks. And this is quite nice because it gave us some room to then increase the gas limit.
Justin was basically the first to then increased the gas limit to 36 million on his validator, and many people followed. And in the following weeks, we eventually got to the 36 million, which was already a very small step, but still a quite a success story. And since then, we got way more professional when dealing with the gas limit. We had dashboards like this one. We launched gas limit tests on testnets first, first on local devnets, then on the public test testnets. And in the end, there were much more people just looking into it. For example, here you can see a blog post from the EF PandaOps team. Basically our uh our DevOps team, and they were
focusing a lot on what we what do we need to do in order to make sure that we can further increase the gas limit from 36 million to 60 million. And in the end, we even had an EIP that set the default gas limit to 60 million. So, this is very powerful because as soon as you update your node, you don't run any custom flags that set the gas limit, you will just go with the 60 million. So, this eventually got us to 60 million where we are today. And this is a chart from Etherscan where you can you can see like the stepwise increase that happened over the recent year, basically going from 16 uh 36 million to 45 million, and then to 60 million.
And what all we did so far was basically squeezing out everything that we can from clients. So, there was no major change that allowed us to increase the gas limit. It was more like core devs just grinding hard trying to squeeze out every little bit of efficiency from their clients without actually doing protocol changes that would support further gas limit increases. And then, at some point we were just asking ourselves, "Yeah, how do we continue from there on?" Because clients are tired optimizing their clients. And at some point we need to do something to actually scale the chain.
So, there were a bunch of options, right? Other chains were looking into parallelization. Terence was just talking about EPBS, which is basically using the slack time in the slot for something more useful. What about CKVMs, right? Everyone has heard about CKVMs. Are they already around the corner? Can we use them? And the same applies to network optimizations. Like, can we without changing the core protocol, can we just make things on the networking side more efficient to scale the gas limit? And one thing was very clear from the beginning, we will not just increase the node requirements because this will be the shortcut here, a very simple shortcut, but at the same time it could mean we sacrifice some of the core properties of Ethereum. So, just
increasing the node requirements was always like not a very viable option even though it would be reasonable in our time, might be doable, but we were not ready with for that for that yet. So, this confronted us with this situation like, "What do we do? Like, go do we go do we go all in the crops?" Basically censorship resistance, open source, privacy, security, all the values Ethereum stands for. Or do we want to focus on scaling? And the community was very divided. But fortunately, there was this very nice trick that we have haven't really thought about it.
And it's basically this. You can use your thumb your pinky finger, and then you get both of it. You can get crops, and you can get scaling. And this is where we in the end ended up with doing both. So, what happened was the core devs, the community, they really mobilized behind scaling the L1. So, scaling the L1 was suddenly this big theme. And everyone was on board. Also, the Ethereum Foundation had um with Tomasz laying out those three buckets, scale the L1, scale the L2, improve UX. So, there was a lot of momentum at that time to just increase the gas limit.
And in the end, this is where we are basically today. We decided to ship two EIPs for Cancun. So, those are the two headliner EIPs. We just heard about EPBS, EIP-7732. And the other one is EIP-7928, block level access list. And in my talk, I want to mainly focus on block level access list. And some of you might remember like I was always an advocate for delayed execution, which was the the competitor of EPBS in that sense. But in the end, we went for EPBS.
And if you are interested in EPBS, I won't um repeat everything that was already said on that, but we have like great resources, basically the EIP itself, Proto's talk, and the annotated EIP specs, and of course Terrence's talk. But, let's get into the slot autonomy of anatomy of today. So, the first part of the slot is basically used for um the block validation execution, whereas the rest of the block um slot is basically used for propagation of attestations and aggregation.
And now, if we added parallelization, we could get to a picture like this. So, nothing changes, but we just parallelize the block execution. EPBS, we already saw that earlier. We would just basically split the beacon block from the payload, allow the payload to travel independently from the beacon block, giving it much more time for propagation. And now, adding the parallelization on top, you get to an image like this, and this will be what we will see in Glamsterdam, basically having parallelized payload execution that has a lot of time for propagation.
So, let's dive deeper into 7928, block level access list, which will be the EIP shipped in Glamsterdam for parallelization. There are four problems we have today with parallelizing transactions. First of all, there are unknown dependencies, transactions conflict with each other, they touch state, and so on. Then um dynamic access patterns, transactions could branch into random directions based on the runtime, right? So, when you block when your transaction lands at the top of the block, it could could do something completely different than if you would place it in the middle of the block or at the end of the block. And this makes um optimistically paralleliz- parallelizing transactions very
challenging. And finally, there is EIP 2930 that some of you might remember like the transaction access access lists, but unfortunately, it's optional, and it's not really accurate because you as a user, you can't really know what your transaction is going to do because as I said, it might dep- depend on the runtime. So, to solve those four problems, we came up with EIP um 7928, and the TLDR was basically let you introduce parallelism to Ethereum. So, looking at how it works. So, this is how block validation looks like today.
You download the block, you propagate it, and then you usually do some IO, you go to disk, you load state, you execute, you go to disk again, and so on. And at the end of the block, you calculate the state root because you need the state root in your header. And this is basically what we can't parallelize as of today because we don't know what is going to happen. With block level access list, we suddenly can. So, basically, you download the block, and then IO, execution, post state root calculation can all be done in parallel. And this allows us to scale the gas limit in the end quite massively.
Looking at how transactions are executed here, exactly what I mentioned earlier. You go to disk, you execute, you go to disk, and so on. And with block level access list, we get to a picture like the following where you have one thread that fetches everything you need in that block from the disk, and the rest of the threads are basically busy already executing. And transaction It doesn't matter anymore if transactions have conflicts with each other because the block level access list allows you to resolve those conflicts and get you to perfect parallelization. So, in the worst case, you can always parallelize transactions, no matter what.
And this is what the blocks block access lists contains. It's two things, state locations, which means what do I need from state for executing that block? And the second thing, which is even more important, is this state diff or to be more granular, a post transaction state diff. So, you get exactly the values that you would find on state after executing a certain transaction. And because the values after one transactions are the value before another transactions, you can use that as basically almost like a if you had the state for each transaction available. And this allows you in the end to execute transactions in any arbitrary order.
So, the block level access list looks like the following. I won't go too deep into this, but basically, it's a very simple structure where you have accounts, each account is mapped to changes like the slot changes, storage keys, the balance changes, nonce changes, and code changes that makes up all the state. And then, coming from the slot changes, you can see that a slot change consists again of a storage key. So, you have account, then storage keys, and then the exact mapping to which transaction changes the state, and what is the value after that transaction.
So, the block level access list is essentially also a state diff for the block. And the benefits we get are those four. We get execution parallelism, we get batch prefe- prefetch, we get parallel state root computation, and one that I haven't mentioned so far that I like a lot because I think it's a super powerful use case is faster snap sync. So, you can basically replace um the get trie node method in the healing phase for snap sync with block level access lists. And then, you would do um for those of you that are familiar with snap sync, you would do the skeleton sync, you would download the block bodies, and usually, you would start the healing phase in that in that
um time, but here, you would still do healing, but instead of trie node fetching, you would apply block level access lists. And this is a major simplification for um the snap sync process. We don't have to go too deep. I've basically explained most of um how snap sync works anyway, but this will be um EIP 8189. It's You can look it up. It will also probably be shipped around Glamsterdam later this year, and you can find it under snap V2. Awesome. This is all I have, and thanks everyone.
>> [applause] >> Thank you. Do you have any question, anybody? Um Great talk, by the way. Um how much overhead do the access lists add to the block payload? So, from a I guess you from a data si- from a bit data perspective. Yeah, so you can you can assume that uh it always grows sublinearly because there is some aggregation possible within the block level access list, but on average, it's as big as the block.
So, blocks today are around 70 kilobytes. So, you if the block is 70 kilobytes, you can also assume the block level access list will also be around 70 kilobytes. Thanks for the talk. Um doesn't increasing parallelism effectively also raise node requirements because now you can do more? Yeah, that's a very good question. So, today, there is a there is an EIP. I forgot its number that defines like different hardware specs that full nodes, validators, and builders should at least have.
It's very conservative, but those have already like eight cores. And if you execute transactions today, and you get like a worst case block where everything is like dependent on another transaction, then you would essentially end up using only one core. So, you couldn't really do much with it. Of course, you would still maintain a transaction pool, and you would still have your consensus client also needing to do some work, but in the end, you would not really make use of most of your cores. And this is more like making use of what people already have. And how hard is it for the block proposer to generate this list?
Yeah, another good question. It should be very simple. Of course, um you would already have to execute the block, and you would just while executing, keep track of the state changes, and in the end, you would you could have a function. For example, in the specs, we have a function where you just throw in all the state changes, and it gives you the block level access list, which is nothing else than all the state changes, but then a little bit more aggregated and packed into each other. So, it should be super simple. The only thing is block builders can't use the block level access list, of course, because they have to build it, and yeah.
So, they will not profit from the parallelization. All right, no more question. Thank you. Thanks. >> [applause]