Skip to content

Commit

Permalink
refactor: separate proxy client from engine api client
Browse files Browse the repository at this point in the history
  • Loading branch information
jim380 committed Oct 30, 2024
1 parent 8d69c2e commit 594f3f9
Show file tree
Hide file tree
Showing 3 changed files with 280 additions and 116 deletions.
43 changes: 7 additions & 36 deletions execution.go
Original file line number Diff line number Diff line change
@@ -1,49 +1,20 @@
package execution

import (
"errors"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
execution "github.com/rollkit/go-execution"
"github.com/rollkit/go-execution/proxy/jsonrpc"
rollkitTypes "github.com/rollkit/rollkit/types"
)

// Define necessary types and constants
type PayloadStatus string

const (
PayloadStatusValid PayloadStatus = "VALID"
PayloadStatusInvalid PayloadStatus = "INVALID"
PayloadStatusSyncing PayloadStatus = "SYNCING"
)

var (
ErrNilPayloadStatus = errors.New("nil payload status")
ErrInvalidPayloadStatus = errors.New("invalid payload status")
)

type EngineAPIExecutionClient struct {
ethClient *ethclient.Client
proxyClient *jsonrpc.Client
genesisHash common.Hash
feeRecipient common.Address
execute execution.Execute
}

// NewEngineAPIExecutionClient creates a new instance of EngineAPIExecutionClient.
func NewEngineAPIExecutionClient(ethURL string, proxyClient *jsonrpc.Client, genesisHash common.Hash, feeRecipient common.Address) (*EngineAPIExecutionClient, error) {
ethClient, err := ethclient.Dial(ethURL)
if err != nil {
return nil, err
}

func NewEngineAPIExecutionClient(execute execution.Execute) (*EngineAPIExecutionClient, error) {
return &EngineAPIExecutionClient{
ethClient: ethClient,
proxyClient: proxyClient,
genesisHash: genesisHash,
feeRecipient: feeRecipient,
execute: execute,
}, nil
}

Expand All @@ -55,12 +26,12 @@ func (c *EngineAPIExecutionClient) InitChain(
initialHeight uint64,
chainID string,
) (rollkitTypes.Hash, uint64, error) {
return c.proxyClient.InitChain(genesisTime, initialHeight, chainID)
return c.execute.InitChain(genesisTime, initialHeight, chainID)
}

// GetTxs retrieves transactions from the transaction pool.
func (c *EngineAPIExecutionClient) GetTxs() ([]rollkitTypes.Tx, error) {
return c.proxyClient.GetTxs()
return c.execute.GetTxs()
}

// ExecuteTxs executes the given transactions and returns the new state root and gas used.
Expand All @@ -70,10 +41,10 @@ func (c *EngineAPIExecutionClient) ExecuteTxs(
timestamp time.Time,
prevStateRoot rollkitTypes.Hash,
) (rollkitTypes.Hash, uint64, error) {
return c.proxyClient.ExecuteTxs(txs, blockHeight, timestamp, prevStateRoot)
return c.execute.ExecuteTxs(txs, blockHeight, timestamp, prevStateRoot)
}

// SetFinal marks a block at the given height as final.
func (c *EngineAPIExecutionClient) SetFinal(blockHeight uint64) error {
return c.proxyClient.SetFinal(blockHeight)
return c.execute.SetFinal(blockHeight)
}
127 changes: 47 additions & 80 deletions execution_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package execution

import (
"context"
"math/big"
"net/http/httptest"
"os"
"testing"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/rollkit/go-execution/proxy/jsonrpc"
"github.com/rollkit/go-execution-evm/proxy"
"github.com/rollkit/go-execution/mocks"
proxyJsonrpc "github.com/rollkit/go-execution/proxy/jsonrpc"
rollkitTypes "github.com/rollkit/rollkit/types"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)

Expand All @@ -22,92 +21,54 @@ const (
type testEnv struct {
server *httptest.Server
jwtSecret string
ethURL string
engineURL string
cleanup func()
client *EngineAPIExecutionClient
proxyConf *jsonrpc.Config
mockExec *MockExecutor
}

// Add MockExecutor
type MockExecutor struct {
mock.Mock
}

func NewMockExecutor() *MockExecutor {
return &MockExecutor{}
}

func (m *MockExecutor) InitChain(genesisTime time.Time, initialHeight uint64, chainID string) (rollkitTypes.Hash, uint64, error) {
args := m.Called(genesisTime, initialHeight, chainID)
return args.Get(0).(rollkitTypes.Hash), args.Get(1).(uint64), args.Error(2)
}

func (m *MockExecutor) GetTxs() ([]rollkitTypes.Tx, error) {
args := m.Called()
return args.Get(0).([]rollkitTypes.Tx), args.Error(1)
}

func (m *MockExecutor) ExecuteTxs(txs []rollkitTypes.Tx, height uint64, timestamp time.Time, prevStateRoot rollkitTypes.Hash) (rollkitTypes.Hash, uint64, error) {
args := m.Called(txs, height, timestamp, prevStateRoot)
return args.Get(0).(rollkitTypes.Hash), args.Get(1).(uint64), args.Error(2)
}

func (m *MockExecutor) SetFinal(height uint64) error {
args := m.Called(height)
return args.Error(0)
proxyConf *proxyJsonrpc.Config
mockExec *mocks.MockExecute
}

func setupTestEnv(t *testing.T) *testEnv {
t.Helper()

// Create temporary directory for JWT token
tmpDir, err := os.MkdirTemp("", "execution-test-*")
require.NoError(t, err)

// Setup cleanup
cleanup := func() {
os.RemoveAll(tmpDir)
}

// Setup proxy config
proxyConf := &jsonrpc.Config{
// setup a proxy config
proxyConf := &proxyJsonrpc.Config{
DefaultTimeout: 5 * time.Second,
MaxRequestSize: 1024 * 1024,
}

// Create mock executor
mockExec := NewMockExecutor()
// create a mock execute from mocks package
mockExec := mocks.NewMockExecute(t)

// Create proxy server with mock executor
server := jsonrpc.NewServer(mockExec, proxyConf)
// create a proxy server with mock execute
server := proxyJsonrpc.NewServer(mockExec, proxyConf)
testServer := httptest.NewServer(server)

// Create proxy client
proxyClient := jsonrpc.NewClient()
proxyClient.SetConfig(proxyConf)

err = proxyClient.Start(testServer.URL)
require.NoError(t, err)

// Create execution client with proxy client
// create a proxy client that implements the Execute interface
ethURL := "http://localhost:8545"
engineURL := "http://localhost:8551"
genesisHash := common.HexToHash("0x0")
feeRecipient := common.HexToAddress("0x0")

client, err := NewEngineAPIExecutionClient(
ethURL,
proxyClient, // Pass the proxy client
genesisHash,
feeRecipient,
)
proxyClient, err := proxy.NewClient(proxyConf, ethURL, engineURL, genesisHash, feeRecipient)
require.NoError(t, err)

err = proxyClient.Start(testServer.URL)
require.NoError(t, err)

// create an execution client with the proxy client
client, err := NewEngineAPIExecutionClient(proxyClient)
require.NoError(t, err)

return &testEnv{
server: testServer,
jwtSecret: "", // Not needed for test server
ethURL: ethURL,
jwtSecret: "",
cleanup: func() {
cleanup()
testServer.Close()
Expand All @@ -125,9 +86,8 @@ func TestEngineAPIExecutionClient_InitChain(t *testing.T) {

genesisTime := time.Now().UTC().Truncate(time.Second)
initialHeight := uint64(0)
chainID := "11155111" // Sepolia chain ID
chainID := "11155111" // sepolia chain id

// Setup mock expectations using env.mockExec
expectedStateRoot := rollkitTypes.Hash{}
copy(expectedStateRoot[:], []byte{1, 2, 3})
expectedGasLimit := uint64(1000000)
Expand All @@ -147,49 +107,56 @@ func TestEngineAPIExecutionClient_GetTxs(t *testing.T) {
env := setupTestEnv(t)
defer env.cleanup()

expectedTxs := []rollkitTypes.Tx{[]byte("tx1"), []byte("tx2")}
env.mockExec.On("GetTxs").Return(expectedTxs, nil)

txs, err := env.client.GetTxs()
require.NoError(t, err)
// Initially pool should be empty
require.Empty(t, txs)
require.Equal(t, expectedTxs, txs)

// TO-DO: Add test transaction to pool and verify it's retrieved
env.mockExec.AssertExpectations(t)
}

func TestEngineAPIExecutionClient_ExecuteTxs(t *testing.T) {
env := setupTestEnv(t)
defer env.cleanup()

// Setup test data
blockHeight := uint64(1)
timestamp := time.Now()

// Get the previous state root from the client
header, err := env.client.ethClient.HeaderByNumber(context.Background(), big.NewInt(0))
require.NoError(t, err)
timestamp := time.Now().UTC().Truncate(time.Second)
prevStateRoot := rollkitTypes.Hash{}
copy(prevStateRoot[:], []byte{1, 2, 3})
testTx := rollkitTypes.Tx("test transaction")

// Convert the header root to the expected type
headerHash := rollkitTypes.Hash(header.Root[:]) // Convert to rollkit Hash type
expectedStateRoot := rollkitTypes.Hash{}
copy(expectedStateRoot[:], []byte{4, 5, 6})
expectedGasUsed := uint64(21000)

// Create test transaction
testTx := []byte{} // Add test transaction bytes
env.mockExec.On("ExecuteTxs", []rollkitTypes.Tx{testTx}, blockHeight, timestamp, prevStateRoot).
Return(expectedStateRoot, expectedGasUsed, nil)

stateRoot, gasUsed, err := env.client.ExecuteTxs(
[]rollkitTypes.Tx{testTx},
blockHeight,
timestamp,
headerHash,
prevStateRoot,
)
require.NoError(t, err)
require.NotEqual(t, common.Hash{}, stateRoot)
require.Greater(t, gasUsed, uint64(0))
require.Equal(t, expectedStateRoot, stateRoot)
require.Equal(t, expectedGasUsed, gasUsed)

env.mockExec.AssertExpectations(t)
}

func TestEngineAPIExecutionClient_SetFinal(t *testing.T) {
env := setupTestEnv(t)
defer env.cleanup()

// First create a block
blockHeight := uint64(1)

env.mockExec.On("SetFinal", blockHeight).Return(nil)

err := env.client.SetFinal(blockHeight)
require.NoError(t, err)

env.mockExec.AssertExpectations(t)
}
Loading

0 comments on commit 594f3f9

Please sign in to comment.