Skip to content

Commit

Permalink
Add local mode execution
Browse files Browse the repository at this point in the history
  • Loading branch information
ferranbt committed Feb 2, 2024
1 parent 24fd9b1 commit 1a89156
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 22 deletions.
158 changes: 136 additions & 22 deletions cmd/geth/forgecmd.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,128 @@
package main

import (
"bytes"
"context"
"encoding/hex"
"fmt"
"math/big"
"os"
"reflect"
"strings"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/suave/artifacts"
suave_backends "github.com/ethereum/go-ethereum/suave/backends"
suave "github.com/ethereum/go-ethereum/suave/core"
"github.com/flashbots/go-boost-utils/bls"
"github.com/naoina/toml"
"github.com/urfave/cli/v2"
)

var defaultRemoteSuaveHost = "http://localhost:8545"

var (
isLocalForgeFlag = &cli.BoolFlag{
Name: "local",
Usage: `Whether to run the query command locally`,
}
whiteListForgeFlag = &cli.StringSliceFlag{
Name: "whitelist",
Usage: `The whitelist external endpoints to call`,
}
ethBackendForgeFlag = &cli.StringFlag{
Name: "eth-backend",
Usage: `The endpoint of the confidential eth backend`,
}
tomlConfigForgeFlag = &cli.StringFlag{
Name: "config",
Usage: `The path to the forge toml config file`,
}
)

type suaveForgeConfig struct {
Whitelist []string
EthBackend string
}

func readContext(ctx *cli.Context) (*vm.SuaveContext, error) {
// try to read the config from the toml config file
cfg := &suaveForgeConfig{}

if ctx.IsSet(tomlConfigForgeFlag.Name) {
// read the toml config file
data, err := os.ReadFile(ctx.String(tomlConfigForgeFlag.Name))
if err != nil {
return nil, err
}

// this is decoding
// [profile.suave]
var config struct {
Profile struct {
Suave *suaveForgeConfig
}
}

tomlConfig := toml.DefaultConfig
tomlConfig.MissingField = func(rt reflect.Type, field string) error {
return nil
}
if err := tomlConfig.NewDecoder(bytes.NewReader(data)).Decode(&config); err != nil {
return nil, err
}
cfg = config.Profile.Suave
}

// override the config if the flags are set
if ctx.IsSet(ethBackendForgeFlag.Name) {
cfg.EthBackend = ctx.String(ethBackendForgeFlag.Name)
}
if ctx.IsSet(whiteListForgeFlag.Name) {
cfg.Whitelist = ctx.StringSlice(whiteListForgeFlag.Name)
}

// create the suave context
var suaveEthBackend suave.ConfidentialEthBackend
if cfg.EthBackend != "" {
suaveEthBackend = suave_backends.NewRemoteEthBackend(ctx.String(ethBackendForgeFlag.Name))
} else {
suaveEthBackend = &suave_backends.EthMock{}
}

ecdsaKey, _ := crypto.GenerateKey()
blsKey, _ := bls.GenerateRandomSecretKey()

backend := &vm.SuaveExecutionBackend{
ExternalWhitelist: cfg.Whitelist,
ConfidentialEthBackend: suaveEthBackend,
EthBlockSigningKey: blsKey,
EthBundleSigningKey: ecdsaKey,
}
suaveCtx := &vm.SuaveContext{
Backend: backend,
}
return suaveCtx, nil
}

var (
forgeCommand = &cli.Command{
Name: "forge",
Usage: "Internal command for MEVM forge commands",
ArgsUsage: "",
Description: `Internal command used by MEVM precompiles in forge to access the MEVM API utilities.`,
Flags: []cli.Flag{
isLocalForgeFlag,
whiteListForgeFlag,
ethBackendForgeFlag,
tomlConfigForgeFlag,
},
Subcommands: []*cli.Command{
forgeStatusCmd,
resetConfStore,
Expand Down Expand Up @@ -56,34 +156,48 @@ var (
return fmt.Errorf("failed to decode input: %w", err)
}

rpcClient, err := rpc.Dial(defaultRemoteSuaveHost)
if err != nil {
return fmt.Errorf("failed to dial rpc: %w", err)
}
if ctx.IsSet(isLocalForgeFlag.Name) {
suaveCtx, err := readContext(ctx)
if err != nil {
return fmt.Errorf("failed to read context: %w", err)
}

ethClient := ethclient.NewClient(rpcClient)
result, err := vm.NewSuavePrecompiledContractWrapper(common.HexToAddress(addr), suaveCtx).Run(input)
if err != nil {
return fmt.Errorf("failed to run precompile: %w", err)
}
fmt.Println(hex.EncodeToString(result))
} else {
rpcClient, err := rpc.Dial(defaultRemoteSuaveHost)
if err != nil {
return fmt.Errorf("failed to dial rpc: %w", err)
}

chainIdRaw, err := ethClient.ChainID(context.Background())
if err != nil {
return fmt.Errorf("failed to get chain id: %w", err)
}
ethClient := ethclient.NewClient(rpcClient)

chainId := hexutil.Big(*chainIdRaw)
toAddr := common.HexToAddress(addr)
chainIdRaw, err := ethClient.ChainID(context.Background())
if err != nil {
return fmt.Errorf("failed to get chain id: %w", err)
}

callArgs := ethapi.TransactionArgs{
To: &toAddr,
IsConfidential: true,
ChainID: &chainId,
Data: (*hexutil.Bytes)(&input),
}
var simResult hexutil.Bytes
if err := rpcClient.Call(&simResult, "eth_call", setTxArgsDefaults(callArgs), "latest"); err != nil {
return err
chainId := hexutil.Big(*chainIdRaw)
toAddr := common.HexToAddress(addr)

callArgs := ethapi.TransactionArgs{
To: &toAddr,
IsConfidential: true,
ChainID: &chainId,
Data: (*hexutil.Bytes)(&input),
}
var simResult hexutil.Bytes
if err := rpcClient.Call(&simResult, "eth_call", setTxArgsDefaults(callArgs), "latest"); err != nil {
return err
}

// return the result without the 0x prefix
fmt.Println(simResult.String()[2:])
}

// return the result without the 0x prefix
fmt.Println(simResult.String()[2:])
return nil
},
}
Expand Down
10 changes: 10 additions & 0 deletions cmd/geth/forgecmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package main

import (
"fmt"
"testing"
)

func TestForgeReadConfig(t *testing.T) {
fmt.Println(app.Run([]string{"geth", "forge", "--local", "--config", "./testdata/forge.toml", "confidentialInputs"}))
}
5 changes: 5 additions & 0 deletions cmd/geth/testdata/forge.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[profile.suave]
whitelist = ["a", "b"]
[profile.ci.fuzz]
runs = 10_000
solc_version = "0.8.23"

0 comments on commit 1a89156

Please sign in to comment.