Commit 38b4a12d authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into clabby/e2e/garbage-batch

parents 3b166752 ff01cd62
......@@ -124,6 +124,10 @@ func (n *OpNode) initL1(ctx context.Context, cfg *Config) error {
return fmt.Errorf("failed to create L1 source: %w", err)
}
if err := cfg.Rollup.ValidateL1Config(ctx, n.l1Source); err != nil {
return err
}
// Keep subscribed to the L1 heads, which keeps the L1 maintainer pointing to the best headers to sync
n.l1HeadsSub = event.ResubscribeErr(time.Second*10, func(ctx context.Context, err error) (event.Subscription, error) {
if err != nil {
......@@ -189,6 +193,10 @@ func (n *OpNode) initL2(ctx context.Context, cfg *Config, snapshotLog log.Logger
return fmt.Errorf("failed to create Engine client: %w", err)
}
if err := cfg.Rollup.ValidateL2Config(ctx, n.l2Source); err != nil {
return err
}
n.l2Driver = driver.NewDriver(&cfg.Driver, &cfg.Rollup, n.l2Source, n.l1Source, n, n.log, snapshotLog, n.metrics)
return nil
......
package rollup
import (
"context"
"errors"
"fmt"
"math/big"
......@@ -55,6 +56,94 @@ type Config struct {
L1SystemConfigAddress common.Address `json:"l1_system_config_address"`
}
// ValidateL1Config checks L1 config variables for errors.
func (cfg *Config) ValidateL1Config(ctx context.Context, client L1Client) error {
// Validate the L1 Client Chain ID
if err := cfg.CheckL1ChainID(ctx, client); err != nil {
return err
}
// Validate the Rollup L1 Genesis Blockhash
if err := cfg.CheckL1GenesisBlockHash(ctx, client); err != nil {
return err
}
return nil
}
// ValidateL2Config checks L2 config variables for errors.
func (cfg *Config) ValidateL2Config(ctx context.Context, client L2Client) error {
// Validate the L2 Client Chain ID
if err := cfg.CheckL2ChainID(ctx, client); err != nil {
return err
}
// Validate the Rollup L2 Genesis Blockhash
if err := cfg.CheckL2GenesisBlockHash(ctx, client); err != nil {
return err
}
return nil
}
type L1Client interface {
ChainID(context.Context) (*big.Int, error)
L1BlockRefByNumber(context.Context, uint64) (eth.L1BlockRef, error)
}
// CheckL1ChainID checks that the configured L1 chain ID matches the client's chain ID.
func (cfg *Config) CheckL1ChainID(ctx context.Context, client L1Client) error {
id, err := client.ChainID(ctx)
if err != nil {
return err
}
if cfg.L1ChainID.Cmp(id) != 0 {
return fmt.Errorf("incorrect L1 RPC chain id %d, expected %d", cfg.L1ChainID, id)
}
return nil
}
// CheckL1GenesisBlockHash checks that the configured L1 genesis block hash is valid for the given client.
func (cfg *Config) CheckL1GenesisBlockHash(ctx context.Context, client L1Client) error {
l1GenesisBlockRef, err := client.L1BlockRefByNumber(ctx, cfg.Genesis.L1.Number)
if err != nil {
return err
}
if l1GenesisBlockRef.Hash != cfg.Genesis.L1.Hash {
return fmt.Errorf("incorrect L1 genesis block hash %d, expected %d", cfg.Genesis.L1.Hash, l1GenesisBlockRef.Hash)
}
return nil
}
type L2Client interface {
ChainID(context.Context) (*big.Int, error)
L2BlockRefByNumber(context.Context, uint64) (eth.L2BlockRef, error)
}
// CheckL2ChainID checks that the configured L2 chain ID matches the client's chain ID.
func (cfg *Config) CheckL2ChainID(ctx context.Context, client L2Client) error {
id, err := client.ChainID(ctx)
if err != nil {
return err
}
if cfg.L2ChainID.Cmp(id) != 0 {
return fmt.Errorf("incorrect L2 RPC chain id %d, expected %d", cfg.L2ChainID, id)
}
return nil
}
// CheckL2GenesisBlockHash checks that the configured L2 genesis block hash is valid for the given client.
func (cfg *Config) CheckL2GenesisBlockHash(ctx context.Context, client L2Client) error {
l2GenesisBlockRef, err := client.L2BlockRefByNumber(ctx, cfg.Genesis.L2.Number)
if err != nil {
return err
}
if l2GenesisBlockRef.Hash != cfg.Genesis.L2.Hash {
return fmt.Errorf("incorrect L2 genesis block hash %d, expected %d", cfg.Genesis.L2.Hash, l2GenesisBlockRef.Hash)
}
return nil
}
// Check verifies that the given configuration makes sense
func (cfg *Config) Check() error {
if cfg.BlockTime == 0 {
......
package rollup
import (
"context"
"encoding/json"
"math/big"
"math/rand"
......@@ -55,3 +56,159 @@ func TestConfigJSON(t *testing.T) {
assert.NoError(t, json.Unmarshal(data, &roundTripped))
assert.Equal(t, &roundTripped, config)
}
type mockL1Client struct {
chainID *big.Int
Hash common.Hash
}
func (m *mockL1Client) ChainID(context.Context) (*big.Int, error) {
return m.chainID, nil
}
func (m *mockL1Client) L1BlockRefByNumber(ctx context.Context, number uint64) (eth.L1BlockRef, error) {
return eth.L1BlockRef{
Hash: m.Hash,
Number: 100,
}, nil
}
func TestValidateL1Config(t *testing.T) {
config := randConfig()
config.L1ChainID = big.NewInt(100)
config.Genesis.L1.Number = 100
config.Genesis.L1.Hash = [32]byte{0x01}
mockClient := mockL1Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
err := config.ValidateL1Config(context.TODO(), &mockClient)
assert.NoError(t, err)
}
func TestValidateL1ConfigInvalidChainIdFails(t *testing.T) {
config := randConfig()
config.L1ChainID = big.NewInt(101)
config.Genesis.L1.Number = 100
config.Genesis.L1.Hash = [32]byte{0x01}
mockClient := mockL1Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
err := config.ValidateL1Config(context.TODO(), &mockClient)
assert.Error(t, err)
config.L1ChainID = big.NewInt(99)
err = config.ValidateL1Config(context.TODO(), &mockClient)
assert.Error(t, err)
}
func TestValidateL1ConfigInvalidGenesisHashFails(t *testing.T) {
config := randConfig()
config.L1ChainID = big.NewInt(100)
config.Genesis.L1.Number = 100
config.Genesis.L1.Hash = [32]byte{0x00}
mockClient := mockL1Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
err := config.ValidateL1Config(context.TODO(), &mockClient)
assert.Error(t, err)
config.Genesis.L1.Hash = [32]byte{0x02}
err = config.ValidateL1Config(context.TODO(), &mockClient)
assert.Error(t, err)
}
func TestCheckL1ChainID(t *testing.T) {
config := randConfig()
config.L1ChainID = big.NewInt(100)
err := config.CheckL1ChainID(context.TODO(), &mockL1Client{chainID: big.NewInt(100)})
assert.NoError(t, err)
err = config.CheckL1ChainID(context.TODO(), &mockL1Client{chainID: big.NewInt(101)})
assert.Error(t, err)
err = config.CheckL1ChainID(context.TODO(), &mockL1Client{chainID: big.NewInt(99)})
assert.Error(t, err)
}
func TestCheckL1BlockRefByNumber(t *testing.T) {
config := randConfig()
config.Genesis.L1.Number = 100
config.Genesis.L1.Hash = [32]byte{0x01}
mockClient := mockL1Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
err := config.CheckL1GenesisBlockHash(context.TODO(), &mockClient)
assert.NoError(t, err)
mockClient.Hash = common.Hash{0x02}
err = config.CheckL1GenesisBlockHash(context.TODO(), &mockClient)
assert.Error(t, err)
mockClient.Hash = common.Hash{0x00}
err = config.CheckL1GenesisBlockHash(context.TODO(), &mockClient)
assert.Error(t, err)
}
type mockL2Client struct {
chainID *big.Int
Hash common.Hash
}
func (m *mockL2Client) ChainID(context.Context) (*big.Int, error) {
return m.chainID, nil
}
func (m *mockL2Client) L2BlockRefByNumber(ctx context.Context, number uint64) (eth.L2BlockRef, error) {
return eth.L2BlockRef{
Hash: m.Hash,
Number: 100,
}, nil
}
func TestValidateL2Config(t *testing.T) {
config := randConfig()
config.L2ChainID = big.NewInt(100)
config.Genesis.L2.Number = 100
config.Genesis.L2.Hash = [32]byte{0x01}
mockClient := mockL2Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
err := config.ValidateL2Config(context.TODO(), &mockClient)
assert.NoError(t, err)
}
func TestValidateL2ConfigInvalidChainIdFails(t *testing.T) {
config := randConfig()
config.L2ChainID = big.NewInt(101)
config.Genesis.L2.Number = 100
config.Genesis.L2.Hash = [32]byte{0x01}
mockClient := mockL2Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
err := config.ValidateL2Config(context.TODO(), &mockClient)
assert.Error(t, err)
config.L2ChainID = big.NewInt(99)
err = config.ValidateL2Config(context.TODO(), &mockClient)
assert.Error(t, err)
}
func TestValidateL2ConfigInvalidGenesisHashFails(t *testing.T) {
config := randConfig()
config.L2ChainID = big.NewInt(100)
config.Genesis.L2.Number = 100
config.Genesis.L2.Hash = [32]byte{0x00}
mockClient := mockL2Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
err := config.ValidateL2Config(context.TODO(), &mockClient)
assert.Error(t, err)
config.Genesis.L2.Hash = [32]byte{0x02}
err = config.ValidateL2Config(context.TODO(), &mockClient)
assert.Error(t, err)
}
func TestCheckL2ChainID(t *testing.T) {
config := randConfig()
config.L2ChainID = big.NewInt(100)
err := config.CheckL2ChainID(context.TODO(), &mockL2Client{chainID: big.NewInt(100)})
assert.NoError(t, err)
err = config.CheckL2ChainID(context.TODO(), &mockL2Client{chainID: big.NewInt(101)})
assert.Error(t, err)
err = config.CheckL2ChainID(context.TODO(), &mockL2Client{chainID: big.NewInt(99)})
assert.Error(t, err)
}
func TestCheckL2BlockRefByNumber(t *testing.T) {
config := randConfig()
config.Genesis.L2.Number = 100
config.Genesis.L2.Hash = [32]byte{0x01}
mockClient := mockL2Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
err := config.CheckL2GenesisBlockHash(context.TODO(), &mockClient)
assert.NoError(t, err)
mockClient.Hash = common.Hash{0x02}
err = config.CheckL2GenesisBlockHash(context.TODO(), &mockClient)
assert.Error(t, err)
mockClient.Hash = common.Hash{0x00}
err = config.CheckL2GenesisBlockHash(context.TODO(), &mockClient)
assert.Error(t, err)
}
......@@ -12,6 +12,7 @@ package sources
import (
"context"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
......@@ -216,6 +217,16 @@ func (s *EthClient) payloadCall(ctx context.Context, method string, id any) (*et
return payload, nil
}
// ChainID fetches the chain id of the internal RPC.
func (s *EthClient) ChainID(ctx context.Context) (*big.Int, error) {
var id hexutil.Big
err := s.client.CallContext(ctx, &id, "eth_chainId")
if err != nil {
return nil, err
}
return (*big.Int)(&id), nil
}
func (s *EthClient) InfoByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, error) {
if header, ok := s.headersCache.Get(hash); ok {
return header.(*HeaderInfo), nil
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment