Should builder block submissions set a different gas limit than what proposer specified?
When Flashbots builder builds a block, it adheres strictly to proposer gas limit when setting the header for the built block.
For example, if on registration a proposer sets gas limit to 30_000_000, Flashbots builder will set header gas limit to 30_000_000 for its built block.
Strict adherence to proposer gas limit is problematic. If the proposer’s gas limit exceeds what’s allowed by the protocol, relays will reject the builders block.
For example, consider when a parent block has gas limit of 29_900_000. The protocol would only allow child block gas limit up to 29_929_199. If the proposer’s gas limit of 30_000_000 is used, builder block gets rejected
Rather than strict adherence to proposer gas limit, we’d like to explore a “best-effort” approach where Flashbots builder attempts to move towards proposer’s gas limit while staying within protocol limits.
For example if proposer has gas limit of 30_000_000 and protocol allows up to 29_929_199, builder would submit block with gas limit set to 29_929_199 instead of 30_000_000
Should builder block submissions set a different gas limit than what proposer specified? Are there downsides or implications with this approach?
We would appreciate feedback from the community on this proposal, and encourage all to voice their questions and concerns! Please let us know your thoughts - we’d like to make a decision in a week assuming there are no significant concerns.
Good question - in my experience, the proposer does not often change the default gas limit, which is typically set to 30_000_000.
However, anecdotally I have observed a greater proportion of parent blocks with a different gas limit. There can be many reasons why, but one possibility is that other block builders are proposing blocks with a different gas limit than what the proposer set, causing greater fluctuations that lead to proposer’s gas limit being rejected from exceeding allowed limits.
By default, proposers will use the hardcoded default of 30M for block gas limit.
However, the target gas limit for a new block will follow a set of rules in order to ensure there isn’t large divergence in gas between blocks. The allowed or target gas limit is based a few factors, including the parent’s gas limit, and the desired gas limit, where the desired gas limit is the proposer’s value.
In my experience it isn’t the proposer that changes this value. What tends to happen is that the Flashbots builder creates a new block with a given parent block. The parent block has a specified gas limit set. The in-protocol rules restrict how much the gas limit for a new block can diverge from the parent block gas limit. If the proposer’s desired gas limit exceeds this boundary, a block built with their desired gas limit is rejected.
There can be numerous reasons why the parent block gas limit would be different, one hypothesis is described here
hardcoded default is 30M, but per-block limit is dynamic based on protocol rules
proposers don’t typically change this value, but a parent block’s gas limit affects tolerable gas limits for child block
we observe many parent blocks with values that cause rejection of child blocks that use proposer’s hardcoded value
The validator’s gas limit getting passed is exactly what I’m saying. That’s the problem. We don’t change it, and block gets rejected. I am quite confident because I have both verified and tested changing this behavior.
Should mention that I run a block builder which was ignoring the validator’s gas limit preference completely. Saw some occasional errors from the flashbots relay, so I plumbed the preference through CalcGasLimit, and the validation errors disappeared.
Yes, unfortunately. The code paths are complex, we initially thought the same thing as you in that the calculated gas limit was being passed in. However, you can think of the code path you’re tracing as the “commit path” - where worker “commits” to their block for submission
The problem is that the “commit” path is dependent on the “submit” path - if the submit path fails, you can essentially end up with an “empty” commit path, which would use a valid header but without transactions.
This pretty much describes my thought process and experience as well - the proposal is suggesting pretty much what you’re doing, and just re-using gas limit calculation from validation code on the “submit” path for builder block submissions.