From 72afdc44ab0de98b70f60ce1dbcf0b0553ed2653 Mon Sep 17 00:00:00 2001 From: Victor Castell <0x@vcastellm.xyz> Date: Thu, 4 Jan 2024 13:50:59 +0100 Subject: [PATCH] Refactor and tests --- interop/executor.go | 23 +++--- interop/executor_test.go | 58 +++++++++++++ rpc/rpc.go | 30 +++---- rpc/rpc_test.go | 135 ++++--------------------------- test/mocks.go | 120 +++++++++++++++++++++++++++ {interop => types}/interfaces.go | 2 +- 6 files changed, 222 insertions(+), 146 deletions(-) create mode 100644 interop/executor_test.go create mode 100644 test/mocks.go rename {interop => types}/interfaces.go (98%) diff --git a/interop/executor.go b/interop/executor.go index 2b34a2b..bc223d8 100644 --- a/interop/executor.go +++ b/interop/executor.go @@ -8,20 +8,21 @@ import ( "github.com/0xPolygon/beethoven/config" "github.com/0xPolygon/beethoven/tx" - "github.com/0xPolygonHermez/zkevm-node/jsonrpc/client" + "github.com/0xPolygon/beethoven/types" - "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" + "github.com/0xPolygonHermez/zkevm-node/jsonrpc/client" + rpctypes "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" "github.com/0xPolygonHermez/zkevm-node/log" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/jackc/pgx/v4" ) -var _ ZkEVMClientClientCreator = (*zkEVMClientCreator)(nil) +var _ types.ZkEVMClientClientCreator = (*zkEVMClientCreator)(nil) type zkEVMClientCreator struct{} -func (zc *zkEVMClientCreator) NewClient(rpc string) ZkEVMClientInterface { +func (zc *zkEVMClientCreator) NewClient(rpc string) types.ZkEVMClientInterface { return client.NewClient(rpc) } @@ -29,15 +30,15 @@ type Executor struct { logger *log.Logger interopAdminAddr common.Address config *config.Config - ethTxMan EthTxManager - etherman EthermanInterface - ZkEVMClientCreator ZkEVMClientClientCreator + ethTxMan types.EthTxManager + etherman types.EthermanInterface + ZkEVMClientCreator types.ZkEVMClientClientCreator } func New(logger *log.Logger, cfg *config.Config, interopAdminAddr common.Address, - etherman EthermanInterface, - ethTxManager EthTxManager, + etherman types.EthermanInterface, + ethTxManager types.EthTxManager, ) *Executor { return &Executor{ logger: logger, @@ -169,11 +170,11 @@ func (e *Executor) Settle(signedTx tx.SignedTx, dbTx pgx.Tx) (common.Hash, error return signedTx.Tx.Hash(), nil } -func (e *Executor) GetTxStatus(ctx context.Context, hash common.Hash, dbTx pgx.Tx) (result string, err types.Error) { +func (e *Executor) GetTxStatus(ctx context.Context, hash common.Hash, dbTx pgx.Tx) (result string, err rpctypes.Error) { res, innerErr := e.ethTxMan.Result(ctx, ethTxManOwner, hash.Hex(), dbTx) if innerErr != nil { result = "0x0" - err = types.NewRPCError(types.DefaultErrorCode, fmt.Sprintf("failed to get tx, error: %s", innerErr)) + err = rpctypes.NewRPCError(rpctypes.DefaultErrorCode, fmt.Sprintf("failed to get tx, error: %s", innerErr)) return } diff --git a/interop/executor_test.go b/interop/executor_test.go new file mode 100644 index 0000000..8ee89f0 --- /dev/null +++ b/interop/executor_test.go @@ -0,0 +1,58 @@ +package interop + +import ( + "context" + "testing" + + "github.com/0xPolygon/beethoven/config" + "github.com/0xPolygon/beethoven/test" + "github.com/0xPolygon/beethoven/tx" + + "github.com/0xPolygonHermez/zkevm-node/log" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" +) + +func TestNewExecutor(t *testing.T) { + cfg := &config.Config{ + // Set your desired config values here + } + interopAdminAddr := common.HexToAddress("0x1234567890abcdef") + etherman := &test.EthermanMock{} + ethTxManager := &test.EthTxManagerMock{} + + executor := New(nil, cfg, interopAdminAddr, etherman, ethTxManager) + + assert.NotNil(t, executor) + assert.Equal(t, interopAdminAddr, executor.interopAdminAddr) + assert.Equal(t, cfg, executor.config) + assert.Equal(t, ethTxManager, executor.ethTxMan) + assert.Equal(t, etherman, executor.etherman) + assert.NotNil(t, executor.ZkEVMClientCreator) +} + +func TestExecutor_CheckTx(t *testing.T) { + cfg := &config.Config{ + // Set your desired config values here + } + interopAdminAddr := common.HexToAddress("0x1234567890abcdef") + etherman := &test.EthermanMock{} + ethTxManager := &test.EthTxManagerMock{} + + executor := New(log.WithFields("test", "test"), cfg, interopAdminAddr, etherman, ethTxManager) + + // Create a sample signed transaction for testing + signedTx := tx.SignedTx{ + Tx: tx.Tx{ + LastVerifiedBatch: 0, + NewVerifiedBatch: 1, + ZKP: tx.ZKP{ + Proof: []byte("sampleProof"), + }, + L1Contract: common.HexToAddress("0x1234567890abcdef"), + }, + } + + err := executor.CheckTx(context.Background(), signedTx) + assert.NoError(t, err) +} diff --git a/rpc/rpc.go b/rpc/rpc.go index 108b42f..d24e5e0 100644 --- a/rpc/rpc.go +++ b/rpc/rpc.go @@ -5,7 +5,9 @@ import ( "fmt" "github.com/0xPolygon/beethoven/interop" - "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" + "github.com/0xPolygon/beethoven/types" + + rpctypes "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" "github.com/0xPolygonHermez/zkevm-node/log" "github.com/ethereum/go-ethereum/common" @@ -22,14 +24,14 @@ const ( type InteropEndpoints struct { ctx context.Context executor *interop.Executor - db interop.DBInterface + db types.DBInterface } // NewInteropEndpoints returns InteropEndpoints func NewInteropEndpoints( ctx context.Context, executor *interop.Executor, - db interop.DBInterface, + db types.DBInterface, ) *InteropEndpoints { return &InteropEndpoints{ ctx: ctx, @@ -38,25 +40,25 @@ func NewInteropEndpoints( } } -func (i *InteropEndpoints) SendTx(signedTx tx.SignedTx) (interface{}, types.Error) { +func (i *InteropEndpoints) SendTx(signedTx tx.SignedTx) (interface{}, rpctypes.Error) { // Check if the RPC is actually registered, if not it won't be possible to assert soundness (in the future once we are stateless won't be needed) if err := i.executor.CheckTx(i.ctx, signedTx); err != nil { - return "0x0", types.NewRPCError(types.DefaultErrorCode, fmt.Sprintf("there is no RPC registered for %s", signedTx.Tx.L1Contract)) + return "0x0", rpctypes.NewRPCError(rpctypes.DefaultErrorCode, fmt.Sprintf("there is no RPC registered for %s", signedTx.Tx.L1Contract)) } // Verify ZKP using eth_call if err := i.executor.Verify(signedTx); err != nil { - return "0x0", types.NewRPCError(types.DefaultErrorCode, fmt.Sprintf("failed to verify tx: %s", err)) + return "0x0", rpctypes.NewRPCError(rpctypes.DefaultErrorCode, fmt.Sprintf("failed to verify tx: %s", err)) } if err := i.executor.Execute(signedTx); err != nil { - return "0x0", types.NewRPCError(types.DefaultErrorCode, fmt.Sprintf("failed to execute tx: %s", err)) + return "0x0", rpctypes.NewRPCError(rpctypes.DefaultErrorCode, fmt.Sprintf("failed to execute tx: %s", err)) } // Send L1 tx dbTx, err := i.db.BeginStateTransaction(i.ctx) if err != nil { - return "0x0", types.NewRPCError(types.DefaultErrorCode, fmt.Sprintf("failed to begin dbTx, error: %s", err)) + return "0x0", rpctypes.NewRPCError(rpctypes.DefaultErrorCode, fmt.Sprintf("failed to begin dbTx, error: %s", err)) } _, err = i.executor.Settle(signedTx, dbTx) @@ -64,21 +66,21 @@ func (i *InteropEndpoints) SendTx(signedTx tx.SignedTx) (interface{}, types.Erro if errRollback := dbTx.Rollback(i.ctx); errRollback != nil { log.Error("rollback err: ", errRollback) } - return "0x0", types.NewRPCError(types.DefaultErrorCode, fmt.Sprintf("failed to add tx to ethTxMan, error: %s", err)) + return "0x0", rpctypes.NewRPCError(rpctypes.DefaultErrorCode, fmt.Sprintf("failed to add tx to ethTxMan, error: %s", err)) } if err := dbTx.Commit(i.ctx); err != nil { - return "0x0", types.NewRPCError(types.DefaultErrorCode, fmt.Sprintf("failed to commit dbTx, error: %s", err)) + return "0x0", rpctypes.NewRPCError(rpctypes.DefaultErrorCode, fmt.Sprintf("failed to commit dbTx, error: %s", err)) } log.Debugf("successfuly added tx %s to ethTxMan", signedTx.Tx.Hash().Hex()) return signedTx.Tx.Hash(), nil } -func (i *InteropEndpoints) GetTxStatus(hash common.Hash) (result interface{}, err types.Error) { +func (i *InteropEndpoints) GetTxStatus(hash common.Hash) (result interface{}, err rpctypes.Error) { dbTx, innerErr := i.db.BeginStateTransaction(i.ctx) if innerErr != nil { result = "0x0" - err = types.NewRPCError(types.DefaultErrorCode, fmt.Sprintf("failed to begin dbTx, error: %s", innerErr)) + err = rpctypes.NewRPCError(rpctypes.DefaultErrorCode, fmt.Sprintf("failed to begin dbTx, error: %s", innerErr)) return } @@ -86,14 +88,14 @@ func (i *InteropEndpoints) GetTxStatus(hash common.Hash) (result interface{}, er defer func() { if innerErr := dbTx.Rollback(i.ctx); innerErr != nil { result = "0x0" - err = types.NewRPCError(types.DefaultErrorCode, fmt.Sprintf("failed to rollback dbTx, error: %s", innerErr)) + err = rpctypes.NewRPCError(rpctypes.DefaultErrorCode, fmt.Sprintf("failed to rollback dbTx, error: %s", innerErr)) } }() result, innerErr = i.executor.GetTxStatus(i.ctx, hash, dbTx) if innerErr != nil { result = "0x0" - err = types.NewRPCError(types.DefaultErrorCode, fmt.Sprintf("failed to get tx, error: %s", innerErr)) + err = rpctypes.NewRPCError(rpctypes.DefaultErrorCode, fmt.Sprintf("failed to get tx, error: %s", innerErr)) return } diff --git a/rpc/rpc_test.go b/rpc/rpc_test.go index ceac090..036eef7 100644 --- a/rpc/rpc_test.go +++ b/rpc/rpc_test.go @@ -9,141 +9,36 @@ import ( "github.com/0xPolygon/beethoven/config" "github.com/0xPolygon/beethoven/interop" "github.com/0xPolygon/beethoven/mocks" + "github.com/0xPolygon/beethoven/test" beethovenTypes "github.com/0xPolygon/beethoven/rpc/types" "github.com/0xPolygonHermez/zkevm-node/ethtxmanager" validiumTypes "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" "github.com/0xPolygonHermez/zkevm-node/log" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/jackc/pgx/v4" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/0xPolygon/beethoven/tx" ) -var _ interop.EthermanInterface = (*ethermanMock)(nil) - -type ethermanMock struct { - mock.Mock -} - -func (e *ethermanMock) GetSequencerAddr(l1Contract common.Address) (common.Address, error) { - args := e.Called(l1Contract) - - return args.Get(0).(common.Address), args.Error(1) //nolint:forcetypeassert -} - -func (e *ethermanMock) BuildTrustedVerifyBatchesTxData(lastVerifiedBatch, - newVerifiedBatch uint64, proof tx.ZKP) (data []byte, err error) { - args := e.Called(lastVerifiedBatch, newVerifiedBatch, proof) - - return args.Get(0).([]byte), args.Error(1) //nolint:forcetypeassert -} - -func (e *ethermanMock) CallContract(ctx context.Context, call ethereum.CallMsg, - blockNumber *big.Int) ([]byte, error) { - args := e.Called(ctx, call, blockNumber) - - return args.Get(0).([]byte), args.Error(1) //nolint:forcetypeassert -} - -var _ interop.DBInterface = (*dbMock)(nil) - -type dbMock struct { - mock.Mock -} - -func (db *dbMock) BeginStateTransaction(ctx context.Context) (pgx.Tx, error) { - args := db.Called(ctx) - - tx, ok := args.Get(0).(pgx.Tx) - if !ok { - return nil, args.Error(1) - } - - return tx, args.Error(1) -} - -var _ interop.EthTxManager = (*ethTxManagerMock)(nil) - -type ethTxManagerMock struct { - mock.Mock -} - -func (e *ethTxManagerMock) Add(ctx context.Context, owner, id string, - from common.Address, to *common.Address, value *big.Int, data []byte, gasOffset uint64, dbTx pgx.Tx) error { - args := e.Called(ctx, owner, id, from, to, value, data, dbTx) - - return args.Error(0) -} - -func (e *ethTxManagerMock) Result(ctx context.Context, owner, - id string, dbTx pgx.Tx) (ethtxmanager.MonitoredTxResult, error) { - args := e.Called(ctx, owner, id, dbTx) - - return args.Get(0).(ethtxmanager.MonitoredTxResult), args.Error(1) //nolint:forcetypeassert -} - -func (e *ethTxManagerMock) ResultsByStatus(ctx context.Context, owner string, - statuses []ethtxmanager.MonitoredTxStatus, dbTx pgx.Tx) ([]ethtxmanager.MonitoredTxResult, error) { - e.Called(ctx, owner, statuses, dbTx) - - return nil, nil -} - -func (e *ethTxManagerMock) ProcessPendingMonitoredTxs(ctx context.Context, owner string, - failedResultHandler ethtxmanager.ResultHandler, dbTx pgx.Tx) { - e.Called(ctx, owner, failedResultHandler, dbTx) -} - -var _ interop.ZkEVMClientInterface = (*zkEVMClientMock)(nil) - -type zkEVMClientMock struct { - mock.Mock -} - -func (zkc *zkEVMClientMock) BatchByNumber(ctx context.Context, number *big.Int) (*validiumTypes.Batch, error) { - args := zkc.Called(ctx, number) - - batch, ok := args.Get(0).(*validiumTypes.Batch) - if !ok { - return nil, args.Error(1) - } - - return batch, args.Error(1) -} - -var _ interop.ZkEVMClientClientCreator = (*zkEVMClientCreatorMock)(nil) - -type zkEVMClientCreatorMock struct { - mock.Mock -} - -func (zc *zkEVMClientCreatorMock) NewClient(rpc string) interop.ZkEVMClientInterface { - args := zc.Called(rpc) - - return args.Get(0).(interop.ZkEVMClientInterface) //nolint:forcetypeassert -} - func TestInteropEndpointsGetTxStatus(t *testing.T) { t.Parallel() t.Run("BeginStateTransaction returns an error", func(t *testing.T) { t.Parallel() - dbMock := new(dbMock) + dbMock := new(test.DbMock) dbMock.On("BeginStateTransaction", mock.Anything).Return(nil, errors.New("error")).Once() e := interop.New( log.WithFields("module", "test"), &config.Config{}, common.HexToAddress("0xadmin"), - new(ethermanMock), - new(ethTxManagerMock), + new(test.EthermanMock), + new(test.EthTxManagerMock), ) i := NewInteropEndpoints(context.Background(), e, dbMock) @@ -163,10 +58,10 @@ func TestInteropEndpointsGetTxStatus(t *testing.T) { txMock := new(mocks.TxMock) txMock.On("Rollback", mock.Anything).Return(nil).Once() - dbMock := new(dbMock) + dbMock := new(test.DbMock) dbMock.On("BeginStateTransaction", mock.Anything).Return(txMock, nil).Once() - txManagerMock := new(ethTxManagerMock) + txManagerMock := new(test.EthTxManagerMock) txManagerMock.On("Result", mock.Anything, ethTxManOwner, txHash.Hex(), txMock). Return(ethtxmanager.MonitoredTxResult{}, errors.New("error")).Once() @@ -174,7 +69,7 @@ func TestInteropEndpointsGetTxStatus(t *testing.T) { log.WithFields("module", "test"), &config.Config{}, common.HexToAddress("0xadmin"), - new(ethermanMock), + new(test.EthermanMock), txManagerMock, ) i := NewInteropEndpoints(context.Background(), e, dbMock) @@ -207,10 +102,10 @@ func TestInteropEndpointsGetTxStatus(t *testing.T) { txMock := new(mocks.TxMock) txMock.On("Rollback", mock.Anything).Return(nil).Once() - dbMock := new(dbMock) + dbMock := new(test.DbMock) dbMock.On("BeginStateTransaction", mock.Anything).Return(txMock, nil).Once() - txManagerMock := new(ethTxManagerMock) + txManagerMock := new(test.EthTxManagerMock) txManagerMock.On("Result", mock.Anything, ethTxManOwner, txHash.Hex(), txMock). Return(result, nil).Once() @@ -218,7 +113,7 @@ func TestInteropEndpointsGetTxStatus(t *testing.T) { log.WithFields("module", "test"), &config.Config{}, common.HexToAddress("0xadmin"), - new(ethermanMock), + new(test.EthermanMock), txManagerMock, ) i := NewInteropEndpoints(context.Background(), e, dbMock) @@ -267,12 +162,12 @@ func TestInteropEndpointsSendTx(t *testing.T) { }, } signedTx := &tx.SignedTx{Tx: tnx} - ethermanMock := new(ethermanMock) - zkEVMClientCreatorMock := new(zkEVMClientCreatorMock) - zkEVMClientMock := new(zkEVMClientMock) - dbMock := new(dbMock) + ethermanMock := new(test.EthermanMock) + zkEVMClientCreatorMock := new(test.ZkEVMClientCreatorMock) + zkEVMClientMock := new(test.ZkEVMClientMock) + dbMock := new(test.DbMock) txMock := new(mocks.TxMock) - ethTxManagerMock := new(ethTxManagerMock) + ethTxManagerMock := new(test.EthTxManagerMock) executeTestFn := func() { e := interop.New( diff --git a/test/mocks.go b/test/mocks.go new file mode 100644 index 0000000..9221dac --- /dev/null +++ b/test/mocks.go @@ -0,0 +1,120 @@ +package test + +import ( + "context" + "math/big" + + "github.com/0xPolygon/beethoven/tx" + "github.com/0xPolygon/beethoven/types" + + "github.com/0xPolygonHermez/zkevm-node/ethtxmanager" + validiumTypes "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/jackc/pgx/v4" + "github.com/stretchr/testify/mock" +) + +var _ types.EthermanInterface = (*EthermanMock)(nil) + +type EthermanMock struct { + mock.Mock +} + +func (e *EthermanMock) GetSequencerAddr(l1Contract common.Address) (common.Address, error) { + args := e.Called(l1Contract) + + return args.Get(0).(common.Address), args.Error(1) //nolint:forcetypeassert +} + +func (e *EthermanMock) BuildTrustedVerifyBatchesTxData(lastVerifiedBatch, + newVerifiedBatch uint64, proof tx.ZKP) (data []byte, err error) { + args := e.Called(lastVerifiedBatch, newVerifiedBatch, proof) + + return args.Get(0).([]byte), args.Error(1) //nolint:forcetypeassert +} + +func (e *EthermanMock) CallContract(ctx context.Context, call ethereum.CallMsg, + blockNumber *big.Int) ([]byte, error) { + args := e.Called(ctx, call, blockNumber) + + return args.Get(0).([]byte), args.Error(1) //nolint:forcetypeassert +} + +var _ types.DBInterface = (*DbMock)(nil) + +type DbMock struct { + mock.Mock +} + +func (db *DbMock) BeginStateTransaction(ctx context.Context) (pgx.Tx, error) { + args := db.Called(ctx) + + tx, ok := args.Get(0).(pgx.Tx) + if !ok { + return nil, args.Error(1) + } + + return tx, args.Error(1) +} + +var _ types.EthTxManager = (*EthTxManagerMock)(nil) + +type EthTxManagerMock struct { + mock.Mock +} + +func (e *EthTxManagerMock) Add(ctx context.Context, owner, id string, + from common.Address, to *common.Address, value *big.Int, data []byte, gasOffset uint64, dbTx pgx.Tx) error { + args := e.Called(ctx, owner, id, from, to, value, data, dbTx) + + return args.Error(0) +} + +func (e *EthTxManagerMock) Result(ctx context.Context, owner, + id string, dbTx pgx.Tx) (ethtxmanager.MonitoredTxResult, error) { + args := e.Called(ctx, owner, id, dbTx) + + return args.Get(0).(ethtxmanager.MonitoredTxResult), args.Error(1) //nolint:forcetypeassert +} + +func (e *EthTxManagerMock) ResultsByStatus(ctx context.Context, owner string, + statuses []ethtxmanager.MonitoredTxStatus, dbTx pgx.Tx) ([]ethtxmanager.MonitoredTxResult, error) { + e.Called(ctx, owner, statuses, dbTx) + + return nil, nil +} + +func (e *EthTxManagerMock) ProcessPendingMonitoredTxs(ctx context.Context, owner string, + failedResultHandler ethtxmanager.ResultHandler, dbTx pgx.Tx) { + e.Called(ctx, owner, failedResultHandler, dbTx) +} + +var _ types.ZkEVMClientInterface = (*ZkEVMClientMock)(nil) + +type ZkEVMClientMock struct { + mock.Mock +} + +func (zkc *ZkEVMClientMock) BatchByNumber(ctx context.Context, number *big.Int) (*validiumTypes.Batch, error) { + args := zkc.Called(ctx, number) + + batch, ok := args.Get(0).(*validiumTypes.Batch) + if !ok { + return nil, args.Error(1) + } + + return batch, args.Error(1) +} + +var _ types.ZkEVMClientClientCreator = (*ZkEVMClientCreatorMock)(nil) + +type ZkEVMClientCreatorMock struct { + mock.Mock +} + +func (zc *ZkEVMClientCreatorMock) NewClient(rpc string) types.ZkEVMClientInterface { + args := zc.Called(rpc) + + return args.Get(0).(types.ZkEVMClientInterface) //nolint:forcetypeassert +} diff --git a/interop/interfaces.go b/types/interfaces.go similarity index 98% rename from interop/interfaces.go rename to types/interfaces.go index 8b58b29..b61de5d 100644 --- a/interop/interfaces.go +++ b/types/interfaces.go @@ -1,4 +1,4 @@ -package interop +package types import ( "context"