-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add bid proofs to the builder bid response #51
base: main
Are you sure you want to change the base?
Conversation
2d10381
to
a8312fa
Compare
a8312fa
to
db11adc
Compare
The relay will need to provide the block header to the CL, along with the block hash, if it isn't already. The CL/EL of the proposer would then validate the header/hash match, validate that it builds off of a known history/parent, and validate that the post-state proof of balance has increased fsrom parent as much as the relay claimed. I don't think you need a pre-state root here, as long as there is a condition that the builder must build on top of the block that the proposer agrees is latest according to fork choice. Having the proposer validate that the builder is building on the correct chain is valuable by itself if this isn't enforced yet. |
yes, this proposal PR adds proofs to the header response, other verification is already in place (building on top of the asked parent header)
Yes i agree pre-balance proof is not required as it (pre-balance) can be fetched locally from the EL using the beacon's |
Please check out and participate in the discussion here: https://collective.flashbots.net/t/block-scoring-for-mev-boost-relays/202?u=thegostep The consensus this far is to do block level scoring. The payment proof can be generated using merkle proofs of the pre and post state account balance. Worth noting that the payment proof is not a proof of block validity. |
Is block level scoring pre-submission or post-submission (by the validator after signing the blinded block)? |
The relay does the block scoring when it receives a block submission by a builder, to verify it and ensure that the payment to the proposer is actually correct. A proof on the pre and post state account balance could be generated/verified there, and included in the builder bid. |
awesome, the BN would only need post state account balance proof, as the This PR |
@metachris what do you think of adding this response as |
I think that might make sense, mev-boost won't allow unknown fields in the decoding, so it's not really backwards compatible. Fwiw, I think there's a push towards block scoring by payment transaction, because it accurately reflects the additional block value to the proposer (which is certainly my preference). A merkle proof for such a transaction should also be easier to verify inside mev-boost. |
Ok, on rethink the payment diff makes sense in the response (see the parallel thread ethereum/execution-apis#307 (comment)) Now the question is how will the merkle proof of the transaction look like. Although mev boost verifying the proof would be great ease, but it should also be verifiable by the BN in my opinion. |
Anything that's verifiable by mev-boost is also verifiable by the BN. But mev-boost needs to be able to verify, otherwise it couldn't pick the best valid bid from all the relays.
I think the proof will need to include:
Would love to hear the thoughts of people more familiar with proofs. cc/ @mcdee @lightclient @ralexstokes |
To verify a transaction proof you need the full block header and the payment transaction and the merkle proof for that payment transaction with a root that matches the root in the block header. Note: This only works if the payment transaction is a simple ETH send, which means you can't send from a contract. This actually makes me pretty strongly 👎 on this mechanism because it hinders the adoption/implementation of account abstraction. |
The existing systems all seem to have issues. Pre/post balance for the proposer fee recipient address works most of the time, but will fail if funds are moved in or out of said address for purposes other than inclusion payments. Payment transaction value fails if the builder recipient is a smart contract that transfers value (notably a splitter), and transaction balance diff needs state to be able to prove anything useful. There are a few options here that I can think of off-hand that could make the builder bid more easily verifiable, but they all have issues of their own:
Instead, I think that the best approach will be to stick with the block-based value but to expand the builder bid information beyond a single
Then the overall change in the proposer fee recipient balance would be |
I'm generally fine with making builder life a tad harder and requiring them to solve the hard problem of "avoiding transfers/transactions from the validator in blocks in order to be competitive".
Hmm, is the idea here that a validator could transact from their fee recipient account and as long as the builder provided a proof of inclusion of that transaction, then transaction fees and attached ETH would not be counted against the builder's bid? If so then you would need to include a proof of both the transaction and the receipt, as the transaction could fail (resulting in no ETH actually sent, and you need to get the gas used). Even this could theoretically break as the recipient can send to a contract that doesn't revert but does refund the ETH. Similarly, if the recipient is a contract that returns or splits the ETH you wouldn't be able to deduct that. I think it is worth asking whether these edge cases are worth solving. We should be caring about solo stakers, who are producing relatively few blocks and thus the chance of them landing a transaction in their own block is very low, and if a builder refuses to include such transactions (because it hurts their bid) then the transaction will just land in the next block, so not a big deal. The people who may get long delays are institutional stakers who we very much should be optimizing against. Builders can do the naive strategy of just including everything and looking at balance changes (which will probably work 99% of the time) or they can write code that tries to avoid any unintentional fee recipient balance changes for that little extra edge. I don't think we need to complicate things in order to "balance the scales" between builders following these two different strategies. |
+1, this should be trivial for the builder to solve.
It seems to me like this analysis can be performed after the fact and does not need to be done in the builder pipeline. Obtaining a "pure" mev score is only really useful for the sake of analysis. If a validator wants to artificially boost the blocks of a builder by sending themselves some ETH, they are paying the cost of less builder competition. |
Surely it is also useful for comparison purposes, which is a part of why we are doing this. If builder A comes up with a value of 2 Ether and builder B comes up with a value of 2.5 Ether but includes a transaction that transfers 1 Ether to the proposer fee recipient this is a distortion of the value to the proposer.
Or reduce it by transferring some ETH away, which given the address is gathering ETH isn't a completely off-the-wall scenario. Either way, aren't we trying to achieve the answer to the question "what is this block worth to me as the proposer?" to the best of our abilities? That includes both a sensibly-defined value and a proof that can be (relatively) verified. |
@mcdee thanks for looking into it and expanding on your thoughts with details about the proofs 🙏
Re proposer feeRecipient being a smart contract that forwards/splits the value: balance checks wouldn't work either way, no matter if the payment is done through coinbase or a payment transaction, right? There's legitimate cases where a proposer would forward the funds out, leading to an incorrect balance diff on a totally correct builder payment. Another central question is which proofs mev-boost could verify internally (without having any previous state or access to the EL). mev-boost-the-middleware needs to be able to filter out invalid bids before presenting a final valid best bid to the proposer. |
The idea is not to discriminate against the proposer fee recipient address when calculating he value. Putting restrictions on builders just makes life harder for those attempting to verify the payment when these restrictions are ignored (for whatever reason).
Why not? If the proposer fee recipient is a contract it would recognize the value transferred to it as part of its value, and any return or split as a transfer out. Take the degenerate case of a forwarder: the proposer fee recipient receives 1 ETH and forwards it to another address, the value is still 1 ETH but the balance of the proposer fee recipient address doesn't change because transfers out is also 1 ETH.
That's what I'm trying to do here by providing a mechanism that allows proposers to easily verify the payment in a block. I'm not sure where this is failing that test. |
Can you expand on this? The transfer doesn't have to originate from the coinbase, so you could set the coinbase as a splitter smart contract, and make the transfer to proposer's fee recipient from one of the splitters recipients. Would that work? |
I believe that post-block balance proofs are the simplest solution of those proposed so far. My general argument is that the failure modes of that solution are not pathologically bad, just kind of annoying/unfortunate, and it isn't worth increasing complexity to deal with those failure modes as they are likely to not come up very often. The most compelling failure mode that I have seen so far is a validator with a forwarder fee recipient, as they would always score all blocks at 0, thus making them ineligible for MEV Boost. I'm somewhat dubious that solo stakers will run with a forwarder address, and any that do want this they could setup a mailbox instead (ETH is pulled out later rather than pushed out immediately). I think splitters and the like are much more likely to be used by pooled/custodial stakers, whom I have no particular desire to add complexity for. @mcdee Do you see any failure modes of the post-block balance proof solution that ... |
I agree that simplest and easiest proof are of pre/post block balances and builders should exclude any txs in/out of the proposer fee recipient in the block .
on the BN side, apart from simple merkle proof verification of post balance proof, it would become too complicated to look at split and verify the receipts. We want to impose no restrictions to ENGINE's block since they can clearly/cleanly return transaction fees, i.e. they return a diff in balance. |
Proof: | ||
type: array | ||
items: | ||
allOf: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is allOf
necessary here?
I agree with this limitation being the most salient one, but not overly restrictive. A mailbox with call forwarding enables all use cases I can think of.
I would argue that block level scoring of the change in proposer fee recipient balance, without looking at inputs or outputs is still the most accurate representation of "what is this block worth to me". The incentives of builders is still to maximize this value and naturally filter out outbound transfers.
My suggestion would be to keep things simple with block level scoring and look at the single number that is balance of the proposer fee recipient post execution. For profit switching, all you need is an account proof of the post execution account balance. This can be provided by the EL and the relays allowing MEV-Boost or the CL to simply select the block with the highest balance. AccountProofRefer to EIP-1186.
If the goal is to provide a proof of the "value of the block", then you can trivially provide an account proof on the pre and post execution state - but this does not seem necessary. At this point, enshrining a transaction at the end of the block seems unjustified. |
Co-authored-by: lightclient <[email protected]>
Co-authored-by: lightclient <[email protected]>
Last time I looked there were a number of blocks (>0.1%, if I remember correctly) that contain transactions either from or involving the builder or proposer fee recipient. I don't know if these are solo stakers or not, or if this counts as common, but if there are patterns out there that we don't understand I'm not a fan of waving them away as being edge cases of no relevance. I'm also not a fan of having a system that disincentivizes builders to include certain transactions. If builders are configured to exclude transactions either from or involving the proposer fee recipient then a simple balance check should suffice, but aren't we then pushing complexity onto builders and reducing utility to proposers to make our lives easier? |
Generally speaking, I'm a fan of pushing as much complexity as possible to the builders and away from proposers. This is similar to how there has been talk about having builders be the ones who create block witnesses (in a PBS+verkle world) so that validators (proposers) don't have to retain state. This would add a lot of complexity to builders, while removing state requirements from proposers.
I support investigating these cases and trying to understand them, but pending evidence to the contrary I'm currently satisfied with the narrative of "sometimes proposers do transactions from the fee recipient account, and sometimes those end up in the proposer's block". Assuming we don't find evidence that contradicts that narrative, then I'm fine with "breaking" those edge cases as the transactions will just show up in the next block. |
If this is something that we would like to account for then we can have |
My current feeling is that the a tx proof is by far the simplest solution. It requires no communication to a CL/EL on behalf of mev-boost, because the relay already sends an The one downside of this is as @MicahZoltu mentioned, it precludes sending non-ether assets as payment. We could of course open the scope a bit and do receipt proofs as well so that the builder could prove that the last tx in the block sent them the expected amount of an ERC-20 token. |
@@ -0,0 +1,78 @@ | |||
get: | |||
operationId: "getHeaderV2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really don't like this VX
post-fix notation. At minimum, we should rehome the api at a v2
root. I think actually prefer just expanding the existing types with optional fields.
receipt proof + the beacon registered builder payout address could just work with no extra constraints required. |
This would mean contracts cannot make the payment, it has to route through an EOA. Given that we want to push everyone to contract wallets rather than EOAs, I don't think we should be adding anything that prevents the use of contract wallets or otherwise sending assets from a contract. It also means that if anyone were to send the validator assets for any other reason, the block builder could claim that the send was from them, unless we create some sort of mechanism to prove that the builder is in fact the sender (signature verification or something). |
@MicahZoltu EOAs instantiating txs is a fundamental attribute of the protocol that we have no intention of changing in the medium term (see EIP-4337). And as I also said, we could also support receipt verification which would allow us to prove that a certain ERC-20 was transferred to the beneficiary. That would allow for users of smart contract wallets to pay. The balance check requires additional communication overhead to the EL/CL and I think we should focus on self-contained validation where possible.
This is a non-issue IMO. We can easily create the mapping. |
Perhaps I'm misunderstanding the proposal, but what I thought you meant by "tx proof" was that someone would give you a proof of transaction inclusion of a transaction that had For ERC20s we could prove the receipt, as you suggested, which would allow us to look at the events that occurred in the transaction and notice a token transfer, but then things get very complicated if multiple tokens are supported. If only WETH was supported the receipt solution could work which is perhaps what you are actually proposing?
Why does the balance check require additional communication with EL/CL? MEV Boost has the block header for the proposed block so it can validate a proof of the post-state balance. For the pre-state balance you only need the parent block's header (which can come from anywhere as you can validate it in MEV Boost). We could just require that the bidder provides the parent block header if we don't want MEV Boost to ask the EL/CL for it, though I think we already have mechanisms for asking for headers don't we?
A mapping of what to what? |
No you understand the proposal correctly. It would be of an EOA transaction. It doesn't work with contract wallets and IMO that is okay.
Yeah we would really only be able to support a fixed number of trusted tokens since the interaction needs to be authenticated solely via the contract's events.
Okay fair, it is also possible to avoid the EL/CL communication if the relay provides the parent header. The reason to avoid the communication is because it creates another required connection and vector of failure. Currently, mev-boost only makes requests against the CL builder-api server. We could expand the builder-api, but I prefer not to because we have reasonable solutions which don't require it.
A mapping of EL address to builder so the builder can't claim some arbitrary payment to fee recipient is "from them" as payment for the block. -- I still think the tx/receipt method is superior because you don't need to enforce some invariant that the fee recipient receives nothing during the block. |
In my opinion, we should not "support"/"facilitate" non eth payments as this needs to be directly compared with the engine blocks fee value and should only anchor the protocol to the native token. |
How is this builder list populated/maintained? |
We can extend one of the messages to include an EL address and a signature from the builder (we already have BLS pubkeys for them). |
In discussion with @MicahZoltu regarding how builders are paying validator's
fee_recipient
, he (strongly) suggested that builders should easily be able to provide proof for thefees
disbursement.Context:
Builder bid promises to transfer a certain value to the
fee_recipient
set by the validator/beacon combo, however a lot is left to trust to the builder.Its easy for builder to provide proof of pre and post balance of fee recipient, which can be verified by the beacon using the
stateRoot
of the executionprestate
(using the beacon'sprestate
'slatestBlockHeader
) and execution poststate (present in theheader
)How can builders formulate this proof: Most ELs have getProof
How can CLs verify this proof: valid merkle proof checks
This is a very primitive PR to push the discussion in this front, and hence may require some further work.