ralexstokes / mev-rs

a gateway to a network of block builders
Other
418 stars 77 forks source link

Implement a `reth`-based relay #129

Open ralexstokes opened 1 year ago

ralexstokes commented 1 year ago

Following the successful integration of reth in the builder (see #112), I'd like to scope out what it would look like to build a relay using reth.

The relay would follow a similar design built as an extension around reth and have access to a local CL node.

The relevant relay API requiring the execution node is the block submission endpoint where builders submit bids for the mev-boost auction.

Requirements

At a high-level, this endpoint:

  1. identifies the chain tip for the submission (slot and parent_hash, and implicitly checking proposer via the preferences validation done next)
  2. get the validator preferences for this chain tip and verify they match what is in the bid (proposer_fee_recipient and gas_limit)
  3. verify the builder signature
  4. verify the execution of the payload is valid
  5. payment verification

Steps (4) and (5) require EL support. To address (4), we would like some API to hand a payload off to reth and have it verify the execution. Moreover, it should support execution on any chain tip it knows about, not just the canonical chain. To address (5), we need to know which payment scheme(s) the relay supports. Two common schemes are "end-of-block (EOB)" ETH transfers and COINBASE payments. The following just focuses on EOB payments and leaves the COINBASE route to future work.

Implementing (4)

I have already sketched out a high-level API here to handle block validation. This sketch suggests one route: just extend reth with this endpoint w/ a custom RPC call. I would prefer a more direct route that skips what is ultimately an unnecessary API call as we can find a tighter integration w/ the reth software.

If we just do the ad-hoc thing, it would be exposing some kind of BlockValidator as an extension to the CLI that exposes the client's implementation of this trait BlockExecutor. I have traced a call to this here: https://github.com/paradigmxyz/reth/blob/main/crates/storage/provider/src/traits/executor.rs#L22 which is used in the debug_cmd binary.

One possible implementation for the relay under this design is that the relay has a BlockValidator component that implements the required CLI extension trait to be called during reth startup. This component could e.g. launch an async (blocking) task that just waits for block validation requests on some channel (coming from the rest of the relay infra), call the BlockExecutor::execute_and_verify_receipt method and then return the result as desired.

Implementing (5)

To handle EOB payments, we actually just need to know the last payment in the block was successful (and the rest of the block was valid). The rest of the verifications are just static checks we can perform outside reth proper, even just using something like ethers. Assuming we knew the full block was valid from the prior step, we can simply take advantage of the execute_and_verify_receipt API and grab the receipts from the PostState returned from that method. We can then see if the payment transaction was successfully executed and then check everything else about the syntax of the transaction.

To implement COINBASE payments, we could likely also look at the PostState object but I'll leave this alone for now.

if someone wants to make a pass at this, here's the PR for the relevant functionality we would want to support: https://github.com/flashbots/builder/pull/93

Other notes

Can we just use BlockExecutor::execute? Upon closer inspection, it looks like execute_and_verify_receipt just supports an older behavior from many execution forks ago, which I don't feel the need to support here.

I think the "just add a block validator CLI ext" method would work and work well, although it is a bit ad-hoc. Hoping some reth devs can chime in if they see a better solution.

PatStiles commented 1 year ago

Interested in working on this as expressed in #113 3 for my EPF. For now I’ll finish up the validation checks I laid out in this pr and open a separate WIP one for (4). Will then reach out for your guys feedback @ralexstokes @jacobkaufmann

ralexstokes commented 1 year ago

@PatStiles great! we are working through the right way to integrate reth and given that this decision will have pretty far-reaching consequences for the structure of the relay we want to sort this out first before doing much more on the other parts of the relay

I intend to open a "dev roadmap" to a relay MVP soon once we have this (big) question figured out

ralexstokes commented 1 year ago

I have some notes on a design here:

https://hackmd.io/@ralexstokes/mev-relay-rs-design-doc

PatStiles commented 1 year ago

I have some notes on a design here:

https://hackmd.io/@ralexstokes/mev-relay-rs-design-doc

It’s not visible on my end due to permissions.

ralexstokes commented 1 year ago

I have some notes on a design here: https://hackmd.io/@ralexstokes/mev-relay-rs-design-doc

It’s not visible on my end due to permissions.

@PatStiles I believe you just need to be logged in (you can authenticate w/ GitHub)

PatStiles commented 1 year ago

@ralexstokes Was debating starting the Proposer Auction as @chirag-bgh has started implementing the Builder Auction per your comments in the design doc. Was wondering if I should hold off?

ralexstokes commented 1 year ago

there will be explicit issues in this repo once we have left the design phase, if you move ahead of that process you may be doing some work that will be thrown away

chirag-bgh commented 1 year ago

Implementing (4)

I have already sketched out a high-level API here to handle block validation. This sketch suggests one route: just extend reth with this endpoint w/ a custom RPC call. I would prefer a more direct route that skips what is ultimately an unnecessary API call as we can find a tighter integration w/ the reth software.

If we just do the ad-hoc thing, it would be exposing some kind of BlockValidator as an extension to the CLI that exposes the client's implementation of this trait BlockExecutor. I have traced a call to this here: https://github.com/paradigmxyz/reth/blob/main/crates/storage/provider/src/traits/executor.rs#L22 which is used in the debug_cmd binary.

One possible implementation for the relay under this design is that the relay has a BlockValidator component that implements the required CLI extension trait to be called during reth startup. This component could e.g. launch an async (blocking) task that just waits for block validation requests on some channel (coming from the rest of the relay infra), call the BlockExecutor::execute_and_verify_receipt method and then return the result as desired.

I think we can take inspiration from this: https://github.com/ultrasoundmoney/reth-block-validator/pull/5 This would be more of what we need exactly: https://github.com/ckoopmann/reth-block-validator/pull/1

ckoopmann commented 1 year ago

Implementing (4)

I have already sketched out a high-level API here to handle block validation. This sketch suggests one route: just extend reth with this endpoint w/ a custom RPC call. I would prefer a more direct route that skips what is ultimately an unnecessary API call as we can find a tighter integration w/ the reth software. If we just do the ad-hoc thing, it would be exposing some kind of BlockValidator as an extension to the CLI that exposes the client's implementation of this trait BlockExecutor. I have traced a call to this here: https://github.com/paradigmxyz/reth/blob/main/crates/storage/provider/src/traits/executor.rs#L22 which is used in the debug_cmd binary. One possible implementation for the relay under this design is that the relay has a BlockValidator component that implements the required CLI extension trait to be called during reth startup. This component could e.g. launch an async (blocking) task that just waits for block validation requests on some channel (coming from the rest of the relay infra), call the BlockExecutor::execute_and_verify_receipt method and then return the result as desired.

I think we can take inspiration from this: ultrasoundmoney/reth#5 This would be more of what we need exactly: ultrasoundmoney/reth-payload-validator#1

Would love to support / colab on this. Btw: The most performant way might be trying to implement the reth communication using direct db access instead of going via rpc. But will probably be more complex. (if possible at all to implement all required features).

See: https://github.com/paradigmxyz/reth/blob/main/examples/db-access.rs

chirag-bgh commented 1 year ago

Would love to support / colab on this. Btw: The most performant way might be trying to implement the reth communication using direct db access instead of going via rpc. But will probably be more complex. (if possible at all to implement all required features).

See: https://github.com/paradigmxyz/reth/blob/main/examples/db-access.rs

Sure! This could be helpful for direct db access bypassing the rpc: https://github.com/SorellaLabs/ethers-reth