Skip to content

Commit

Permalink
feat: interop invariant checks
Browse files Browse the repository at this point in the history
  • Loading branch information
tremarkley committed Jul 22, 2024
1 parent d84f3a8 commit 093b93b
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 6 deletions.
8 changes: 8 additions & 0 deletions anvil/anvil.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,11 @@ func (a *Anvil) EthSendTransaction(ctx context.Context, tx *types.Transaction) e
func (a *Anvil) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
return a.ethClient.SubscribeFilterLogs(ctx, q, ch)
}

func (a *Anvil) DebugTraceCall(ctx context.Context, txArgs config.TransactionArgs) (config.DebugTraceCallResponse, error) {
var result config.DebugTraceCallResponse
if err := a.rpcClient.CallContext(ctx, &result, "debug_traceCall", txArgs, "latest"); err != nil {
return config.DebugTraceCallResponse{}, err
}
return result, nil
}
33 changes: 33 additions & 0 deletions config/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)

Expand Down Expand Up @@ -64,6 +65,37 @@ type ChainConfig struct {
ForkConfig *ForkConfig
}

type TransactionArgs struct {
From string `json:"from"`
To string `json:"to"`
Gas string `json:"gas"`
GasPrice string `json:"gasPrice"`
Data string `json:"data"`
Value string `json:"value"`
}

type StructLog struct {
Pc uint64 `json:"pc"`
Op string `json:"op"`
Gas uint64 `json:"gas"`
GasCost uint64 `json:"gasCost"`
Memory []string `json:"memory,omitempty"`
MemorySize int `json:"memSize"`
Stack []string `json:"stack"`
ReturnData []byte `json:"returnData,omitempty"`
Storage map[common.Hash]common.Hash `json:"-"`
Depth int `json:"depth"`
RefundCounter uint64 `json:"refund"`
Err error `json:"-"`
}

type DebugTraceCallResponse struct {
Failed bool `json:"failed"`
Gas uint64 `json:"gas"`
ReturnValue string `json:"returnValue"`
StructLogs []StructLog `json:"structLogs"`
}

type Chain interface {
Name() string
Endpoint() string
Expand All @@ -74,6 +106,7 @@ type Chain interface {
EthSendTransaction(ctx context.Context, tx *types.Transaction) error
EthGetLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error)
SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)
DebugTraceCall(ctx context.Context, txArgs TransactionArgs) (DebugTraceCallResponse, error)
}

// Note: The default secrets config is used everywhere
Expand Down
63 changes: 57 additions & 6 deletions opsimulator/opsimulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package opsimulator
import (
"bytes"
"context"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
Expand All @@ -17,7 +18,11 @@ import (

ophttp "github.com/ethereum-optimism/optimism/op-service/httputil"
"github.com/ethereum-optimism/supersim/config"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
ethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)

const (
Expand Down Expand Up @@ -59,7 +64,7 @@ func (opSim *OpSimulator) Start(ctx context.Context) error {
}

mux := http.NewServeMux()
mux.Handle("/", handler(proxy))
mux.Handle("/", opSim.handler(proxy, ctx))

hs, err := ophttp.StartHTTPServer(net.JoinHostPort(host, fmt.Sprintf("%d", opSim.port)), mux)
if err != nil {
Expand Down Expand Up @@ -96,7 +101,7 @@ func (a *OpSimulator) Stopped() bool {
return a.stopped.Load()
}

func handler(proxy *httputil.ReverseProxy) http.HandlerFunc {
func (a *OpSimulator) handler(proxy *httputil.ReverseProxy, ctx context.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
Expand All @@ -115,7 +120,13 @@ func handler(proxy *httputil.ReverseProxy) http.HandlerFunc {
// TODO(https://github.com/ethereum-optimism/supersim/issues/55): support batch txs

if req.Method == "eth_sendRawTransaction" {
checkInteropInvariants()
param := req.Params[0]
paramStr, ok := param.(string)
if !ok {
http.Error(w, "Bad param to eth_sendRawTransaction", http.StatusBadRequest)
return
}
a.checkInteropInvariants(ctx, paramStr)
}

r.Body = io.NopCloser(bytes.NewReader(body))
Expand All @@ -124,9 +135,49 @@ func handler(proxy *httputil.ReverseProxy) http.HandlerFunc {
}
}

// TODO(https://github.com/ethereum-optimism/supersim/issues/19): add logic for checking that an interop transaction is valid.
func checkInteropInvariants() bool {
return true
func (a *OpSimulator) checkInteropInvariants(ctx context.Context, rawTx string) (bool, error) {
tx, rawTxErr := a.decodeRawTransaction(rawTx)
if rawTxErr != nil {
return false, fmt.Errorf("failed to check interop invariants: %v", rawTxErr)
}

from, fromAddErr := getFromAddress(&tx)

if fromAddErr != nil {
return false, fmt.Errorf("failed to check interop invariants: %v", fromAddErr)
}
result, traceErr := a.l2Chain.DebugTraceCall(ctx, config.TransactionArgs{From: from.String(), To: tx.To().String(), Gas: string(tx.Gas()), GasPrice: tx.GasPrice().String(), Data: string(tx.Data()), Value: tx.Value().String()})
if traceErr != nil {
return false, fmt.Errorf("failed to simulate transaction: %v", traceErr)
}
fmt.Println(result)

return true, nil
}

func isExecutingMessage(l *ethTypes.Log) {

}

func (a *OpSimulator) decodeRawTransaction(rawTx string) (ethTypes.Transaction, error) {
rawTxBytes, err := hex.DecodeString(rawTx)
if err != nil {
return ethTypes.Transaction{}, fmt.Errorf("failed to decode raw transaction: %v", err)
}

var tx types.Transaction
err = rlp.DecodeBytes(rawTxBytes, &tx)
if err != nil {
return ethTypes.Transaction{}, fmt.Errorf("failed to decode RLP encoded transaction: %v", err)
}

return tx, nil
}

func getFromAddress(tx *ethTypes.Transaction) (common.Address, error) {
from, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx)

return from, err
}

func (opSim *OpSimulator) createReverseProxy() (*httputil.ReverseProxy, error) {
Expand Down

0 comments on commit 093b93b

Please sign in to comment.