Skip to content

Commit

Permalink
Feature/3518 use generic eth client for l2 (#3519)
Browse files Browse the repository at this point in the history
* #3518 compatibility with ethereum-API L2 node
* migrate docker-compose to v2 because ubuntu:latest have deprecated it
* fix case trusted URL is not set
  • Loading branch information
joanestebanr authored Apr 4, 2024
1 parent 31aecea commit 26ec1b5
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 68 deletions.
23 changes: 22 additions & 1 deletion cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
"github.com/0xPolygonHermez/zkevm-node/state/runtime/executor"
"github.com/0xPolygonHermez/zkevm-node/synchronizer"
"github.com/0xPolygonHermez/zkevm-node/synchronizer/common/syncinterfaces"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/urfave/cli/v2"
Expand Down Expand Up @@ -280,6 +281,15 @@ func newEtherman(c config.Config) (*etherman.Client, error) {
return etherman.NewClient(c.Etherman, c.NetworkConfig.L1Config)
}

func newL2EthClient(url string) (*ethclient.Client, error) {
ethClient, err := ethclient.Dial(url)
if err != nil {
log.Errorf("error connecting L1 to %s: %+v", url, err)
return nil, err
}
return ethClient, nil
}

func runSynchronizer(cfg config.Config, etherman *etherman.Client, ethTxManagerStorage *ethtxmanager.PostgresStorage, st *state.State, pool *pool.Pool, eventLog *event.EventLog) {
var trustedSequencerURL string
var err error
Expand All @@ -295,6 +305,17 @@ func runSynchronizer(cfg config.Config, etherman *etherman.Client, ethTxManagerS
}
log.Info("trustedSequencerURL ", trustedSequencerURL)
}
var ethClientForL2 *ethclient.Client
if trustedSequencerURL != "" {
log.Infof("Creating L2 ethereum client %s", trustedSequencerURL)
ethClientForL2, err = newL2EthClient(trustedSequencerURL)
if err != nil {
log.Fatalf("Can't create L2 ethereum client. Err:%w", err)
}
} else {
ethClientForL2 = nil
log.Infof("skipping creating L2 ethereum client because URL is empty")
}
zkEVMClient := client.NewClient(trustedSequencerURL)
etherManForL1 := []syncinterfaces.EthermanFullInterface{}
// If synchronizer are using sequential mode, we only need one etherman client
Expand All @@ -310,7 +331,7 @@ func runSynchronizer(cfg config.Config, etherman *etherman.Client, ethTxManagerS
etm := ethtxmanager.New(cfg.EthTxManager, etherman, ethTxManagerStorage, st)
sy, err := synchronizer.NewSynchronizer(
cfg.IsTrustedSequencer, etherman, etherManForL1, st, pool, etm,
zkEVMClient, eventLog, cfg.NetworkConfig.Genesis, cfg.Synchronizer, cfg.Log.Environment == "development",
zkEVMClient, ethClientForL2, eventLog, cfg.NetworkConfig.Genesis, cfg.Synchronizer, cfg.Log.Environment == "development",
)
if err != nil {
log.Fatal(err)
Expand Down
13 changes: 8 additions & 5 deletions synchronizer/actions/check_l2block.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"fmt"
"math/big"

"github.com/0xPolygonHermez/zkevm-node/jsonrpc/types"
"github.com/0xPolygonHermez/zkevm-node/log"
"github.com/0xPolygonHermez/zkevm-node/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/jackc/pgx/v4"
)

Expand Down Expand Up @@ -129,11 +129,14 @@ func (p *CheckL2BlockHash) iterationCheckL2Block(ctx context.Context, l2BlockNum
}

func compareL2Blocks(prefixLogs string, localL2Block *state.L2Block, trustedL2Block *types.Block) error {
if localL2Block == nil || trustedL2Block == nil || trustedL2Block.Hash == nil {
return fmt.Errorf("%s localL2Block or trustedL2Block or trustedHash are nil", prefixLogs)
if localL2Block == nil || trustedL2Block == nil {
return fmt.Errorf("%s localL2Block or trustedL2Block are nil", prefixLogs)
}
if localL2Block.Hash() != trustedL2Block.Hash() {
return fmt.Errorf("%s localL2Block.Hash %s and trustedL2Block.Hash %s are different", prefixLogs, localL2Block.Hash().String(), trustedL2Block.Hash().String())
}
if localL2Block.Hash() != *trustedL2Block.Hash {
return fmt.Errorf("%s localL2Block.Hash %s and trustedL2Block.Hash %s are different", prefixLogs, localL2Block.Hash().String(), (*trustedL2Block.Hash).String())
if localL2Block.ParentHash() != trustedL2Block.ParentHash() {
return fmt.Errorf("%s localL2Block.ParentHash %s and trustedL2Block.ParentHash %s are different", prefixLogs, localL2Block.ParentHash().String(), trustedL2Block.ParentHash().String())
}
return nil
}
37 changes: 21 additions & 16 deletions synchronizer/actions/check_l2block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"math/big"
"testing"

rpctypes "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types"
"github.com/0xPolygonHermez/zkevm-node/state"
"github.com/0xPolygonHermez/zkevm-node/synchronizer/actions"
mock_syncinterfaces "github.com/0xPolygonHermez/zkevm-node/synchronizer/common/syncinterfaces/mocks"
Expand All @@ -19,7 +18,7 @@ import (
type CheckL2BlocksTestData struct {
sut *actions.CheckL2BlockHash
mockState *mock_syncinterfaces.StateFullInterface
zKEVMClient *mock_syncinterfaces.ZKEVMClientInterface
zKEVMClient *mock_syncinterfaces.ZKEVMClientEthereumCompatibleInterface
}

func TestCheckL2BlockHash_GetMinimumL2BlockToCheck(t *testing.T) {
Expand Down Expand Up @@ -57,7 +56,7 @@ func TestCheckL2BlockHashNotEnoughBlocksToCheck(t *testing.T) {
func newCheckL2BlocksTestData(t *testing.T, initialL2Block, modulus uint64) CheckL2BlocksTestData {
res := CheckL2BlocksTestData{
mockState: mock_syncinterfaces.NewStateFullInterface(t),
zKEVMClient: mock_syncinterfaces.NewZKEVMClientInterface(t),
zKEVMClient: mock_syncinterfaces.NewZKEVMClientEthereumCompatibleInterface(t),
}
res.sut = actions.NewCheckL2BlockHash(res.mockState, res.zKEVMClient, initialL2Block, modulus)
return res
Expand Down Expand Up @@ -97,18 +96,23 @@ func TestCheckL2BlockHashMatch(t *testing.T) {

data.mockState.EXPECT().GetLastL2BlockNumber(mock.Anything, mock.Anything).Return(lastL2Block, nil)
data.mockState.EXPECT().GetL2BlockByNumber(mock.Anything, lastL2Block, mock.Anything).Return(stateBlock, nil)
l2blockHash := stateBlock.Hash()
rpcL2Block := rpctypes.Block{
Hash: &l2blockHash,
Number: rpctypes.ArgUint64(lastL2Block),
}
//l2blockHash := stateBlock.Hash()
// rpcL2Block := rpctypes.Block{
// Hash: &l2blockHash,
// Number: rpctypes.ArgUint64(lastL2Block),
// }
// create a types.Block object

rpcL2Block := types.NewBlock(&types.Header{
Number: big.NewInt(int64(lastL2Block)),
}, nil, nil, nil, nil)

data.zKEVMClient.EXPECT().BlockByNumber(mock.Anything, lastL2BlockBigInt).Return(&rpcL2Block, nil)
data.zKEVMClient.EXPECT().BlockByNumber(mock.Anything, lastL2BlockBigInt).Return(rpcL2Block, nil)
err := data.sut.CheckL2Block(context.Background(), nil)
require.NoError(t, err)
}

func TestCheckL2BlockHashMissmatch(t *testing.T) {
func TestCheckL2BlockHashMismatch(t *testing.T) {
data := newCheckL2BlocksTestData(t, 1, 10)
lastL2Block := uint64(14)
lastL2BlockBigInt := big.NewInt(int64(lastL2Block))
Expand All @@ -119,13 +123,14 @@ func TestCheckL2BlockHashMissmatch(t *testing.T) {

data.mockState.EXPECT().GetLastL2BlockNumber(mock.Anything, mock.Anything).Return(lastL2Block, nil)
data.mockState.EXPECT().GetL2BlockByNumber(mock.Anything, lastL2Block, mock.Anything).Return(stateBlock, nil)
l2blockHash := common.HexToHash("0x1234")
rpcL2Block := rpctypes.Block{
Hash: &l2blockHash,
Number: rpctypes.ArgUint64(lastL2Block),
}
//l2blockHash := common.HexToHash("0x1234")

rpcL2Block := types.NewBlock(&types.Header{
Number: big.NewInt(int64(lastL2Block)),
ParentHash: common.HexToHash("0x1234"),
}, nil, nil, nil, nil)

data.zKEVMClient.EXPECT().BlockByNumber(mock.Anything, lastL2BlockBigInt).Return(&rpcL2Block, nil)
data.zKEVMClient.EXPECT().BlockByNumber(mock.Anything, lastL2BlockBigInt).Return(rpcL2Block, nil)
err := data.sut.CheckL2Block(context.Background(), nil)
require.Error(t, err)
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package syncinterfaces

import (
"context"
"math/big"

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

// ZKEVMClientEthereumCompatibleInterface contains the methods required to interact with zkEVM-RPC as a ethereum-API compatible
//
// Reason behind: the zkEVMClient have some extensions to ethereum-API that are not compatible with all nodes. So if you need to maximize
// the compatibility the idea is to use a regular ethereum-API compatible client
type ZKEVMClientEthereumCompatibleInterface interface {
ZKEVMClientEthereumCompatibleL2BlockGetter
}

// ZKEVMClientEthereumCompatibleL2BlockGetter contains the methods required to interact with zkEVM-RPC as a ethereum-API compatible for obtain Block information
type ZKEVMClientEthereumCompatibleL2BlockGetter interface {
BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error)
}
61 changes: 32 additions & 29 deletions synchronizer/synchronizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,18 @@ type ClientSynchronizer struct {
etherMan syncinterfaces.EthermanFullInterface
latestFlushID uint64
// If true the lastFlushID is stored in DB and we don't need to check again
latestFlushIDIsFulfilled bool
etherManForL1 []syncinterfaces.EthermanFullInterface
state syncinterfaces.StateFullInterface
pool syncinterfaces.PoolInterface
ethTxManager syncinterfaces.EthTxManager
zkEVMClient syncinterfaces.ZKEVMClientInterface
eventLog syncinterfaces.EventLogInterface
ctx context.Context
cancelCtx context.CancelFunc
genesis state.Genesis
cfg Config
latestFlushIDIsFulfilled bool
etherManForL1 []syncinterfaces.EthermanFullInterface
state syncinterfaces.StateFullInterface
pool syncinterfaces.PoolInterface
ethTxManager syncinterfaces.EthTxManager
zkEVMClient syncinterfaces.ZKEVMClientInterface
zkEVMClientEthereumCompatible syncinterfaces.ZKEVMClientEthereumCompatibleInterface
eventLog syncinterfaces.EventLogInterface
ctx context.Context
cancelCtx context.CancelFunc
genesis state.Genesis
cfg Config
// Id of the 'process' of the executor. Each time that it starts this value changes
// This value is obtained from the call state.GetStoredFlushID
// It starts as an empty string and it is filled in the first call
Expand All @@ -85,30 +86,32 @@ func NewSynchronizer(
pool syncinterfaces.PoolInterface,
ethTxManager syncinterfaces.EthTxManager,
zkEVMClient syncinterfaces.ZKEVMClientInterface,
zkEVMClientEthereumCompatible syncinterfaces.ZKEVMClientEthereumCompatibleInterface,
eventLog syncinterfaces.EventLogInterface,
genesis state.Genesis,
cfg Config,
runInDevelopmentMode bool) (Synchronizer, error) {
ctx, cancel := context.WithCancel(context.Background())
metrics.Register()
res := &ClientSynchronizer{
isTrustedSequencer: isTrustedSequencer,
state: st,
etherMan: ethMan,
etherManForL1: etherManForL1,
pool: pool,
ctx: ctx,
cancelCtx: cancel,
ethTxManager: ethTxManager,
zkEVMClient: zkEVMClient,
eventLog: eventLog,
genesis: genesis,
cfg: cfg,
proverID: "",
previousExecutorFlushID: 0,
l1SyncOrchestration: nil,
l1EventProcessors: nil,
halter: syncCommon.NewCriticalErrorHalt(eventLog, 5*time.Second), //nolint:gomnd
isTrustedSequencer: isTrustedSequencer,
state: st,
etherMan: ethMan,
etherManForL1: etherManForL1,
pool: pool,
ctx: ctx,
cancelCtx: cancel,
ethTxManager: ethTxManager,
zkEVMClient: zkEVMClient,
zkEVMClientEthereumCompatible: zkEVMClientEthereumCompatible,
eventLog: eventLog,
genesis: genesis,
cfg: cfg,
proverID: "",
previousExecutorFlushID: 0,
l1SyncOrchestration: nil,
l1EventProcessors: nil,
halter: syncCommon.NewCriticalErrorHalt(eventLog, 5*time.Second), //nolint:gomnd
}

if !isTrustedSequencer {
Expand Down Expand Up @@ -143,7 +146,7 @@ func NewSynchronizer(
log.Errorf("error getting last L2Block number from state. Error: %v", err)
return nil, err
}
l1checkerL2Blocks = actions.NewCheckL2BlockHash(res.state, res.zkEVMClient, initialL2Block, cfg.L1SyncCheckL2BlockNumberhModulus)
l1checkerL2Blocks = actions.NewCheckL2BlockHash(res.state, res.zkEVMClientEthereumCompatible, initialL2Block, cfg.L1SyncCheckL2BlockNumberhModulus)
} else {
log.Infof("Trusted Node can't check L2Block hash, ignoring parameter")
}
Expand Down
Loading

0 comments on commit 26ec1b5

Please sign in to comment.