Should builder block submissions set a different gas limit than what proposer specified?

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.


1 Like

For my own context: Do proposers often specify gas limits that are outside of protocol limits?

Some dump questions: Isn’t the block gas limit hardcoded in the protocol to 30 M gas? If not, why would a proposer lower it, and why would that affect a subsequent block?

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

Please note that I have updated the original post to request feedback within a week.

We have observed that competitive builders have already implemented the logic described in this proposal, and Flashbots builder suffers from a large number of rejected blocks without this change.

We encourage the community to voice feedback and concerns. If there are no significant concerns we’d like to reach a decision soon. Thank you!

I don’t think this is correct. I looked through your builder code - the validator’s gas limit gets passed to the miner.worker who uses it as a target (rather than setting directly)

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.

Am I tracing it wrong?

I see the validator’s gasLimit being passed through to here:

CalcGasLimit takes into account the protocol rules and does not produce an invalid gas limit …

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.

Validation code also seems to agree with this method:

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

However, there is a separate path, we can consider it as the “submit” path - in this path, we directly reference the validator’s hardcoded gas limit value and submit with that value to the relay: builder/builder/builder.go at c5985be43d4921798bc9afa3d6f33357f4f6daf6 · flashbots/builder · GitHub

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.

You can see it setting to the hardcoded validator value here: builder/builder/builder.go at c5985be43d4921798bc9afa3d6f33357f4f6daf6 · flashbots/builder · GitHub

Which gets propagated down the “submit” path

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.

Hmmm … still don’t see this getting directly set as a header.GasLimit anywhere, but I’ll take your word for it.

Glad I spun up my own builder now! :wink: