MEVM
The MEVM seeks to offer every primitive of the MEV supply chain as a precompile, allowing any centralized MEV infrastructure to be transformed into a smart contract running on SUAVE.
For a high level description of the goals of the MEVM, we encourage you to read this post. On this page, we'll be diving deep into the technical implementation.
If you'd prefer to learn by running it yourself, please follow this guide.
Architecture​
Our goal is to give you what you need to write more expressive builder solidity and conduct confidential computation, such that you can build any kind of MEV application.
If you've read the two links above, you'll know that the basic flow of a transaction on SUAVE looks like this:
How do we achieve this "Confidential MEVM execution"?
At a high level, we have adapted the eth_sendRawTransaction
RPC method to accept an additional field, called confidential_data
. Users place signed transactions from other blockchains in this field. They encrypt the field for specific SUAVE node(s), and specify some builder solidity contract on SUAVE, which holds the logic for what to do with their encrypted inputs.
When a SUAVE node receives a RawTransaction
, it checks whether there are confidential inputs. If there are, we call this a confidentialComputeRequest
and the MEVM kicks into action. It enters the function being called in the builder solidity contract and, using a view
function and the confidentalInputs
precompile, gets the data it needs about the user's transaction on another blockchain. The MEVM computes some result and stores the relevant data locally, in its confidentialDataStore
. This does not permute state, as we're only using a view
function fetch data and then doing the computation locally, in the MEVM.
Computation complete, the MEVM places what we call the confidentialComputeResult
in the original RawTransaction
it received, which it then propagates to the public mempool. The confidentialComputeResult
is really a callback to another function, which does permute state and often emits some kind of event, the logs of which hold data required by others parties without revealing the original inputs. We encourage you to read about mev-share on SUAVE for a practical example.
For now, it is good enough that you understand that all our adaptations to the EVM serve the goal of confidential computation, as outlined above. These changes can be summed up in a very simple formula:
SuaveExecutionBackend + EVM = MEVM
Here is a visual overview of what that actually means in practice:
In words: the EVM is made up of a whole bunch of different parts. Those numbered 1
through 7
exist in the vanilla EVM we all know and love. Parts 8
through 13
are what we have added (or adapted in the case of the interpreter
) in order to enable confidential computation.
What do you get from the SuaveExecutionBackend that we've married to the EVM through the new runtime?
In a nutshell: 3 new API endpoints:
func NewRuntimeSuaveExecutionBackend(evm *EVM, caller common.Address) *SuaveExecutionBackend {
if !evm.Config.IsConfidential {
return nil
}
return &SuaveExecutionBackend{
ConfidentialStoreBackend: evm.suaveExecutionBackend.ConfidentialStoreBackend,
MempoolBackend: evm.suaveExecutionBackend.MempoolBackend,
ConfidentialEthBackend: evm.suaveExecutionBackend.ConfidentialEthBackend,
confidentialInputs: evm.suaveExecutionBackend.confidentialInputs,
callerStack: append(evm.suaveExecutionBackend.callerStack, &caller),
}
}
Each of these new APIs - ConfidentialStoreBackend
, MempoolBackend
, ConfidentialEthBackend
- are available in builder solidity through the use of precompiles. The precompiles also make use of confidentialInputs
to specify the data relevant to confidential computation, and callerStack
enables transaction tracing.
Notable differences from go-ethereum​
Changes to RPC methods​
New
IsConfidential
andExecutionNode
fields are added to the TransactionArgs used ineth_sendTransaction
andeth_call
methods.- If
IsConfidential
is set to true, the call will be performed as a confidential call, using the SUAVE node passed in for constructingConfidentialComputeRequest
. SuaveTransaction
is the result ofeth_sendTransaction
.
- If
New optional argument -
confidential_data
is added toeth_sendRawTransaction
,eth_sendTransaction
andeth_call
methods.- The confidential data is made available to the EVM in the confidential mode via a precompile, but does not become a part of the transaction that makes it to chain. This allows performing computation based on confidential data (like simulating a bundle, or putting the data into confidential store).
SuavePrecompiledContract​
We introduce a new interface SuavePrecompiledContract for SUAVE precompiles.
type SuavePrecompiledContract interface {
PrecompiledContract
RunConfidential(backend *SuaveExecutionBackend, input []byte) ([]byte, error)
}
The method RunConfidential
is invoked during confidential execution, and the suave execution backend which provides access to confidential APIs is passed in as input.
SUAVE Precompile Wrapper​
We introduce SuavePrecompiledContractWrapper implementing the PrecompiledContract
interface. The new structure captures the confidential APIs in its constructor, and passes the confidential APIs during the usual contract's Run
method to a separate method - RunConfidential
.
SuaveExecutionBackend​
We introduce SuaveExecutionBackend, which enables off-chain compute and confidential execution:
- Access to off-chain APIs
- Access to confidential input
- Caller stack tracing
EVM Interpreter​
The EVM interpreter is modified to enable confidential computation:
- We introduce
IsConfidential
to the interpreter's config - We modify the
Run
function to accept confidential APIsfunc (in *EVMInterpreter) Run(*SuaveExecutionBackend, *Contract, []byte, bool) ([]byte, err)
- We modify the
Run
function to trace the caller stack
Like eth_sendTransaction
, this method accepts an additional, optional confidential inputs argument.
Basic Eth block building RPC​
We implement two rpc methods that allow building Ethereum blocks from a list of either transactions or bundles: BuildEth2Block
and BuildEth2BlockFromBundles
.
These methods are defined in BlockChainAPI
func (s *BlockChainAPI) BuildEth2Block(ctx context.Context, buildArgs *types.BuildBlockArgs, txs types.Transactions) (*engine.ExecutionPayloadEnvelope, error)
func (s *BlockChainAPI) BuildEth2BlockFromBundles(ctx context.Context, buildArgs *types.BuildBlockArgs, bundles []types.SBundle) (*engine.ExecutionPayloadEnvelope, error)
The methods are implemented in worker, by buildBlockFromTxs
and buildBlockFromBundles
respectively.
buildBlockFromTxs
will build a block out of the transactions provided, while buildBlockFromBundles
will - in addition - forward the block profit to the requested fee recipient, as needed for boost relay payments.