Commit fbe7bad4 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

Merge pull request #8268 from ethereum-optimism/aj/load-games-by-hash

op-challenger: Load games by block hash instead of block number
parents 7046de8e 36ee1ec6
......@@ -32,16 +32,16 @@ func NewDisputeGameFactoryContract(addr common.Address, caller *batching.MultiCa
}, nil
}
func (f *DisputeGameFactoryContract) GetGameCount(ctx context.Context, blockNum uint64) (uint64, error) {
result, err := f.multiCaller.SingleCall(ctx, batching.BlockByNumber(blockNum), f.contract.Call(methodGameCount))
func (f *DisputeGameFactoryContract) GetGameCount(ctx context.Context, blockHash common.Hash) (uint64, error) {
result, err := f.multiCaller.SingleCall(ctx, batching.BlockByHash(blockHash), f.contract.Call(methodGameCount))
if err != nil {
return 0, fmt.Errorf("failed to load game count: %w", err)
}
return result.GetBigInt(0).Uint64(), nil
}
func (f *DisputeGameFactoryContract) GetGame(ctx context.Context, idx uint64, blockNum uint64) (types.GameMetadata, error) {
result, err := f.multiCaller.SingleCall(ctx, batching.BlockByNumber(blockNum), f.contract.Call(methodGameAtIndex, new(big.Int).SetUint64(idx)))
func (f *DisputeGameFactoryContract) GetGame(ctx context.Context, idx uint64, blockHash common.Hash) (types.GameMetadata, error) {
result, err := f.multiCaller.SingleCall(ctx, batching.BlockByHash(blockHash), f.contract.Call(methodGameAtIndex, new(big.Int).SetUint64(idx)))
if err != nil {
return types.GameMetadata{}, fmt.Errorf("failed to load game %v: %w", idx, err)
}
......
......@@ -18,7 +18,7 @@ var (
)
func TestDisputeGameFactorySimpleGetters(t *testing.T) {
blockNum := uint64(23)
blockHash := common.Hash{0xbb, 0xcd}
tests := []struct {
method string
args []interface{}
......@@ -31,7 +31,7 @@ func TestDisputeGameFactorySimpleGetters(t *testing.T) {
result: big.NewInt(9876),
expected: uint64(9876),
call: func(game *DisputeGameFactoryContract) (any, error) {
return game.GetGameCount(context.Background(), blockNum)
return game.GetGameCount(context.Background(), blockHash)
},
},
}
......@@ -39,7 +39,7 @@ func TestDisputeGameFactorySimpleGetters(t *testing.T) {
test := test
t.Run(test.method, func(t *testing.T) {
stubRpc, factory := setupDisputeGameFactoryTest(t)
stubRpc.SetResponse(factoryAddr, test.method, batching.BlockByNumber(blockNum), nil, []interface{}{test.result})
stubRpc.SetResponse(factoryAddr, test.method, batching.BlockByHash(blockHash), nil, []interface{}{test.result})
status, err := test.call(factory)
require.NoError(t, err)
expected := test.expected
......@@ -52,7 +52,7 @@ func TestDisputeGameFactorySimpleGetters(t *testing.T) {
}
func TestLoadGame(t *testing.T) {
blockNum := uint64(23)
blockHash := common.Hash{0xbb, 0xce}
stubRpc, factory := setupDisputeGameFactoryTest(t)
game0 := types.GameMetadata{
GameType: 0,
......@@ -71,18 +71,18 @@ func TestLoadGame(t *testing.T) {
}
expectedGames := []types.GameMetadata{game0, game1, game2}
for idx, expected := range expectedGames {
expectGetGame(stubRpc, idx, blockNum, expected)
actual, err := factory.GetGame(context.Background(), uint64(idx), blockNum)
expectGetGame(stubRpc, idx, blockHash, expected)
actual, err := factory.GetGame(context.Background(), uint64(idx), blockHash)
require.NoError(t, err)
require.Equal(t, expected, actual)
}
}
func expectGetGame(stubRpc *batchingTest.AbiBasedRpc, idx int, blockNum uint64, game types.GameMetadata) {
func expectGetGame(stubRpc *batchingTest.AbiBasedRpc, idx int, blockHash common.Hash, game types.GameMetadata) {
stubRpc.SetResponse(
factoryAddr,
methodGameAtIndex,
batching.BlockByNumber(blockNum),
batching.BlockByHash(blockHash),
[]interface{}{big.NewInt(int64(idx))},
[]interface{}{
game.GameType,
......
......@@ -2,21 +2,17 @@ package loader
import (
"context"
"errors"
"fmt"
"github.com/ethereum-optimism/optimism/op-challenger/game/types"
)
var (
ErrMissingBlockNumber = errors.New("game loader missing block number")
"github.com/ethereum/go-ethereum/common"
)
// MinimalDisputeGameFactoryCaller is a minimal interface around [bindings.DisputeGameFactoryCaller].
// This needs to be updated if the [bindings.DisputeGameFactoryCaller] interface changes.
type MinimalDisputeGameFactoryCaller interface {
GetGameCount(ctx context.Context, blockNum uint64) (uint64, error)
GetGame(ctx context.Context, idx uint64, blockNum uint64) (types.GameMetadata, error)
GetGameCount(ctx context.Context, blockHash common.Hash) (uint64, error)
GetGame(ctx context.Context, idx uint64, blockHash common.Hash) (types.GameMetadata, error)
}
type GameLoader struct {
......@@ -31,15 +27,15 @@ func NewGameLoader(caller MinimalDisputeGameFactoryCaller) *GameLoader {
}
// FetchAllGamesAtBlock fetches all dispute games from the factory at a given block number.
func (l *GameLoader) FetchAllGamesAtBlock(ctx context.Context, earliestTimestamp uint64, blockNumber uint64) ([]types.GameMetadata, error) {
gameCount, err := l.caller.GetGameCount(ctx, blockNumber)
func (l *GameLoader) FetchAllGamesAtBlock(ctx context.Context, earliestTimestamp uint64, blockHash common.Hash) ([]types.GameMetadata, error) {
gameCount, err := l.caller.GetGameCount(ctx, blockHash)
if err != nil {
return nil, fmt.Errorf("failed to fetch game count: %w", err)
}
games := make([]types.GameMetadata, 0, gameCount)
for i := gameCount; i > 0; i-- {
game, err := l.caller.GetGame(ctx, i-1, blockNumber)
game, err := l.caller.GetGame(ctx, i-1, blockHash)
if err != nil {
return nil, fmt.Errorf("failed to fetch game at index %d: %w", i-1, err)
}
......
......@@ -24,39 +24,39 @@ func TestGameLoader_FetchAllGames(t *testing.T) {
name string
caller *mockMinimalDisputeGameFactoryCaller
earliest uint64
blockNumber uint64
blockHash common.Hash
expectedErr error
expectedLen int
}{
{
name: "success",
caller: newMockMinimalDisputeGameFactoryCaller(10, false, false),
blockNumber: 1,
blockHash: common.Hash{0x01},
expectedLen: 10,
},
{
name: "expired game ignored",
caller: newMockMinimalDisputeGameFactoryCaller(10, false, false),
earliest: 500,
blockNumber: 1,
blockHash: common.Hash{0x01},
expectedLen: 5,
},
{
name: "game count error",
caller: newMockMinimalDisputeGameFactoryCaller(10, true, false),
blockNumber: 1,
blockHash: common.Hash{0x01},
expectedErr: gameCountErr,
},
{
name: "game index error",
caller: newMockMinimalDisputeGameFactoryCaller(10, false, true),
blockNumber: 1,
blockHash: common.Hash{0x01},
expectedErr: gameIndexErr,
},
{
name: "no games",
caller: newMockMinimalDisputeGameFactoryCaller(0, false, false),
blockNumber: 1,
name: "no games",
caller: newMockMinimalDisputeGameFactoryCaller(0, false, false),
blockHash: common.Hash{0x01},
},
}
......@@ -67,7 +67,7 @@ func TestGameLoader_FetchAllGames(t *testing.T) {
t.Parallel()
loader := NewGameLoader(test.caller)
games, err := loader.FetchAllGamesAtBlock(context.Background(), test.earliest, test.blockNumber)
games, err := loader.FetchAllGamesAtBlock(context.Background(), test.earliest, test.blockHash)
require.ErrorIs(t, err, test.expectedErr)
require.Len(t, games, test.expectedLen)
expectedGames := test.caller.games
......@@ -138,7 +138,7 @@ func newMockMinimalDisputeGameFactoryCaller(count uint64, gameCountErr bool, ind
}
}
func (m *mockMinimalDisputeGameFactoryCaller) GetGameCount(_ context.Context, blockNum uint64) (uint64, error) {
func (m *mockMinimalDisputeGameFactoryCaller) GetGameCount(_ context.Context, _ common.Hash) (uint64, error) {
if m.gameCountErr {
return 0, gameCountErr
}
......@@ -146,7 +146,7 @@ func (m *mockMinimalDisputeGameFactoryCaller) GetGameCount(_ context.Context, bl
return m.gameCount, nil
}
func (m *mockMinimalDisputeGameFactoryCaller) GetGame(_ context.Context, index uint64, blockNum uint64) (types.GameMetadata, error) {
func (m *mockMinimalDisputeGameFactoryCaller) GetGame(_ context.Context, index uint64, _ common.Hash) (types.GameMetadata, error) {
if m.indexErrors[index] {
return struct {
GameType uint8
......
......@@ -23,7 +23,7 @@ type blockNumberFetcher func(ctx context.Context) (uint64, error)
// gameSource loads information about the games available to play
type gameSource interface {
FetchAllGamesAtBlock(ctx context.Context, earliest uint64, blockNumber uint64) ([]types.GameMetadata, error)
FetchAllGamesAtBlock(ctx context.Context, earliest uint64, blockHash common.Hash) ([]types.GameMetadata, error)
}
type gameScheduler interface {
......@@ -101,8 +101,8 @@ func (m *gameMonitor) minGameTimestamp() uint64 {
return 0
}
func (m *gameMonitor) progressGames(ctx context.Context, blockNum uint64) error {
games, err := m.source.FetchAllGamesAtBlock(ctx, m.minGameTimestamp(), blockNum)
func (m *gameMonitor) progressGames(ctx context.Context, blockHash common.Hash) error {
games, err := m.source.FetchAllGamesAtBlock(ctx, m.minGameTimestamp(), blockHash)
if err != nil {
return fmt.Errorf("failed to load games: %w", err)
}
......@@ -123,7 +123,7 @@ func (m *gameMonitor) progressGames(ctx context.Context, blockNum uint64) error
}
func (m *gameMonitor) onNewL1Head(ctx context.Context, sig eth.L1BlockRef) {
if err := m.progressGames(ctx, sig.Number); err != nil {
if err := m.progressGames(ctx, sig.Hash); err != nil {
m.logger.Error("Failed to progress games", "err", err)
}
}
......
......@@ -145,7 +145,7 @@ func TestMonitorCreateAndProgressGameAgents(t *testing.T) {
addr2 := common.Address{0xbb}
source.games = []types.GameMetadata{newFDG(addr1, 9999), newFDG(addr2, 9999)}
require.NoError(t, monitor.progressGames(context.Background(), uint64(1)))
require.NoError(t, monitor.progressGames(context.Background(), common.Hash{0x01}))
require.Len(t, sched.scheduled, 1)
require.Equal(t, []common.Address{addr1, addr2}, sched.scheduled[0])
......@@ -157,7 +157,7 @@ func TestMonitorOnlyScheduleSpecifiedGame(t *testing.T) {
monitor, source, sched, _ := setupMonitorTest(t, []common.Address{addr2})
source.games = []types.GameMetadata{newFDG(addr1, 9999), newFDG(addr2, 9999)}
require.NoError(t, monitor.progressGames(context.Background(), uint64(1)))
require.NoError(t, monitor.progressGames(context.Background(), common.Hash{0x01}))
require.Len(t, sched.scheduled, 1)
require.Equal(t, []common.Address{addr2}, sched.scheduled[0])
......@@ -232,7 +232,7 @@ type stubGameSource struct {
func (s *stubGameSource) FetchAllGamesAtBlock(
ctx context.Context,
earliest uint64,
blockNumber uint64,
blockHash common.Hash,
) ([]types.GameMetadata, error) {
return s.games, nil
}
......
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