Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions op-challenger/game/client/provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package client

import (
"context"
"errors"
"fmt"

"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-service/dial"
"github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
)

var ErrNotInSync = errors.New("local node too far behind")

type Provider struct {
ctx context.Context
logger log.Logger
cfg *config.Config
l1Client *ethclient.Client
caller *batching.MultiCaller

l2EL *ethclient.Client
rollupClient *sources.RollupClient
syncValidator *RollupSyncStatusValidator
supervisorClient *sources.SupervisorClient
toClose []func()
}

func NewProvider(ctx context.Context, logger log.Logger, cfg *config.Config, l1Client *ethclient.Client) *Provider {
return &Provider{
ctx: ctx,
logger: logger,
cfg: cfg,
l1Client: l1Client,
caller: batching.NewMultiCaller(l1Client.Client(), batching.DefaultBatchSize),
}
}

func (c *Provider) Close() {
for _, closeFunc := range c.toClose {
closeFunc()
}
}

func (c *Provider) L1Client() *ethclient.Client {
return c.l1Client
}

func (c *Provider) MultiCaller() *batching.MultiCaller {
return c.caller
}

func (c *Provider) SingleChainClients() (*ethclient.Client, *sources.RollupClient, *RollupSyncStatusValidator, error) {
headers, err := c.L2HeaderSource()
if err != nil {
return nil, nil, nil, err
}
rollup, syncValidator, err := c.RollupClients()
if err != nil {
return nil, nil, nil, err
}
return headers, rollup, syncValidator, nil
}

func (c *Provider) L2HeaderSource() (*ethclient.Client, error) {
if c.l2EL != nil {
Comment thread
ajsutton marked this conversation as resolved.
return c.l2EL, nil
}
if len(c.cfg.L2Rpcs) != 1 {
return nil, fmt.Errorf("incorrect number of L2 RPCs configured, expected 1 but got %d", len(c.cfg.L2Rpcs))
}

l2Client, err := ethclient.DialContext(c.ctx, c.cfg.L2Rpcs[0])
if err != nil {
return nil, fmt.Errorf("dial l2 client %v: %w", c.cfg.L2Rpcs[0], err)
}
c.l2EL = l2Client
c.toClose = append(c.toClose, l2Client.Close)
return l2Client, nil
}

func (c *Provider) RollupClients() (*sources.RollupClient, *RollupSyncStatusValidator, error) {
if c.rollupClient != nil {
return c.rollupClient, c.syncValidator, nil
}
rollupClient, err := dial.DialRollupClientWithTimeout(c.ctx, c.logger, c.cfg.RollupRpc)
if err != nil {
return nil, nil, fmt.Errorf("dial rollup client %v: %w", c.cfg.RollupRpc, err)
}
c.rollupClient = rollupClient
c.syncValidator = NewRollupSyncStatusValidator(rollupClient)
c.toClose = append(c.toClose, rollupClient.Close)
return rollupClient, c.syncValidator, nil
}

func (c *Provider) SuperchainClients() (*sources.SupervisorClient, *SupervisorSyncValidator, error) {
supervisorClient, err := dial.DialSupervisorClientWithTimeout(c.ctx, c.logger, c.cfg.SupervisorRPC)
if err != nil {
return nil, nil, fmt.Errorf("failed to dial supervisor: %w", err)
}
c.supervisorClient = supervisorClient
c.toClose = append(c.toClose, supervisorClient.Close)
return supervisorClient, NewSupervisorSyncValidator(supervisorClient), nil
}
33 changes: 33 additions & 0 deletions op-challenger/game/client/rollup_sync.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package client

import (
"context"
"fmt"

"github.com/ethereum-optimism/optimism/op-service/eth"
)

type syncStatusProvider interface {
SyncStatus(context.Context) (*eth.SyncStatus, error)
}

type RollupSyncStatusValidator struct {
statusProvider syncStatusProvider
}

func NewRollupSyncStatusValidator(statusProvider syncStatusProvider) *RollupSyncStatusValidator {
return &RollupSyncStatusValidator{
statusProvider: statusProvider,
}
}

func (s *RollupSyncStatusValidator) ValidateNodeSynced(ctx context.Context, gameL1Head eth.BlockID) error {
syncStatus, err := s.statusProvider.SyncStatus(ctx)
if err != nil {
return fmt.Errorf("failed to retrieve local node sync status: %w", err)
}
if syncStatus.CurrentL1.Number <= gameL1Head.Number {
return fmt.Errorf("%w require L1 block above %v but at %v", ErrNotInSync, gameL1Head.Number, syncStatus.CurrentL1.Number)
}
return nil
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package fault
package client

import (
"context"
"errors"
"testing"

"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -35,7 +34,7 @@ func TestSyncStatusProvider(t *testing.T) {
},
},
statusReqErr: nil,
expected: types.ErrNotInSync,
expected: ErrNotInSync,
},
{
name: "CurrentL1EqualToGameL1Head",
Expand All @@ -46,7 +45,7 @@ func TestSyncStatusProvider(t *testing.T) {
},
},
statusReqErr: nil,
expected: types.ErrNotInSync,
expected: ErrNotInSync,
},
{
name: "CurrentL1AboveGameL1Head",
Expand All @@ -67,7 +66,7 @@ func TestSyncStatusProvider(t *testing.T) {
status: test.syncStatus,
err: test.statusReqErr,
}
validator := newSyncStatusValidator(provider)
validator := NewRollupSyncStatusValidator(provider)
err := validator.ValidateNodeSynced(context.Background(), test.gameL1Head)
require.ErrorIs(t, err, test.expected)
})
Expand Down
33 changes: 33 additions & 0 deletions op-challenger/game/client/supervisor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package client

import (
"context"
"fmt"

"github.com/ethereum-optimism/optimism/op-service/eth"
)

type SupervisorSyncStatusProvider interface {
SyncStatus(ctx context.Context) (eth.SupervisorSyncStatus, error)
}

type SupervisorSyncValidator struct {
syncStatusProvider SupervisorSyncStatusProvider
}

func NewSupervisorSyncValidator(syncStatusProvider SupervisorSyncStatusProvider) *SupervisorSyncValidator {
return &SupervisorSyncValidator{
syncStatusProvider: syncStatusProvider,
}
}

func (s SupervisorSyncValidator) ValidateNodeSynced(ctx context.Context, gameL1Head eth.BlockID) error {
syncStatus, err := s.syncStatusProvider.SyncStatus(ctx)
if err != nil {
return fmt.Errorf("failed to retrieve sync status: %w", err)
}
if syncStatus.MinSyncedL1.Number <= gameL1Head.Number {
return fmt.Errorf("%w require L1 block above %v but at %v", ErrNotInSync, gameL1Head.Number, syncStatus.MinSyncedL1.Number)
}
return nil
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package super
package client

import (
"context"
"errors"
"testing"

"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/stretchr/testify/require"
)

func TestSyncStatusProvider(t *testing.T) {
func TestSupervisorSyncStatusProvider(t *testing.T) {
requestErr := errors.New("boom")
tests := []struct {
name string
Expand All @@ -31,15 +30,15 @@ func TestSyncStatusProvider(t *testing.T) {
syncStatus: eth.SupervisorSyncStatus{
MinSyncedL1: eth.L1BlockRef{Number: 99},
},
expectedError: types.ErrNotInSync,
expectedError: ErrNotInSync,
},
{
name: "MinSyncedL1EqualToGameHead",
gameL1Head: 100,
syncStatus: eth.SupervisorSyncStatus{
MinSyncedL1: eth.L1BlockRef{Number: 100},
},
expectedError: types.ErrNotInSync,
expectedError: ErrNotInSync,
},
{
name: "InSync",
Expand All @@ -54,22 +53,22 @@ func TestSyncStatusProvider(t *testing.T) {
for _, test := range tests {
test := test // capture range variable
t.Run(test.name, func(t *testing.T) {
stubProvider := &stubSyncStatusProvider{
stubProvider := &stubSupervisorSyncStatusProvider{
status: test.syncStatus,
err: test.statusReqErr,
}
validator := NewSyncValidator(stubProvider)
validator := NewSupervisorSyncValidator(stubProvider)
err := validator.ValidateNodeSynced(context.Background(), eth.BlockID{Number: test.gameL1Head})
require.ErrorIs(t, err, test.expectedError, "expected error to be %v, got %v", test.expectedError, err)
})
}
}

type stubSyncStatusProvider struct {
type stubSupervisorSyncStatusProvider struct {
status eth.SupervisorSyncStatus
err error
}

func (f *stubSyncStatusProvider) SyncStatus(ctx context.Context) (eth.SupervisorSyncStatus, error) {
func (f *stubSupervisorSyncStatusProvider) SyncStatus(ctx context.Context) (eth.SupervisorSyncStatus, error) {
return f.status, f.err
}
83 changes: 0 additions & 83 deletions op-challenger/game/fault/clients.go

This file was deleted.

3 changes: 2 additions & 1 deletion op-challenger/game/fault/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"time"

"github.com/ethereum-optimism/optimism/op-challenger/game/client"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/claims"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/preimages"
Expand Down Expand Up @@ -183,7 +184,7 @@ func (g *GamePlayer) ProgressGame(ctx context.Context) gameTypes.GameStatus {
g.logger.Trace("Skipping completed game")
return g.status
}
if err := g.syncValidator.ValidateNodeSynced(ctx, g.gameL1Head); errors.Is(err, types.ErrNotInSync) {
if err := g.syncValidator.ValidateNodeSynced(ctx, g.gameL1Head); errors.Is(err, client.ErrNotInSync) {
g.logger.Warn("Local node not sufficiently up to date", "err", err)
return g.status
} else if err != nil {
Expand Down
Loading