Commit fe5f61e9 authored by Adrian Sutton's avatar Adrian Sutton

op-challenger: Remove claim loader

It was only used in an unused e2e helper method.
parent a6d211ab
package fault
import (
"context"
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
)
// MinimalFaultDisputeGameCaller is a minimal interface around [bindings.FaultDisputeGameCaller].
// This needs to be updated if the [bindings.FaultDisputeGameCaller] interface changes.
type MinimalFaultDisputeGameCaller interface {
ClaimData(opts *bind.CallOpts, arg0 *big.Int) (struct {
ParentIndex uint32
Countered bool
Claim [32]byte
Position *big.Int
Clock *big.Int
}, error)
Status(opts *bind.CallOpts) (uint8, error)
ClaimDataLen(opts *bind.CallOpts) (*big.Int, error)
MAXGAMEDEPTH(opts *bind.CallOpts) (*big.Int, error)
ABSOLUTEPRESTATE(opts *bind.CallOpts) ([32]byte, error)
}
// loader pulls in fault dispute game claim data periodically and over subscriptions.
type loader struct {
caller MinimalFaultDisputeGameCaller
}
// NewLoader creates a new [loader].
func NewLoader(caller MinimalFaultDisputeGameCaller) *loader {
return &loader{
caller: caller,
}
}
// NewLoaderFromBindings creates a new [loader] from a [bindings.FaultDisputeGameCaller].
func NewLoaderFromBindings(fdgAddr common.Address, client bind.ContractCaller) (*loader, error) {
caller, err := bindings.NewFaultDisputeGameCaller(fdgAddr, client)
if err != nil {
return nil, err
}
return NewLoader(caller), nil
}
// GetGameStatus returns the current game status.
func (l *loader) GetGameStatus(ctx context.Context) (gameTypes.GameStatus, error) {
status, err := l.caller.Status(&bind.CallOpts{Context: ctx})
return gameTypes.GameStatus(status), err
}
// GetClaimCount returns the number of claims in the game.
func (l *loader) GetClaimCount(ctx context.Context) (uint64, error) {
count, err := l.caller.ClaimDataLen(&bind.CallOpts{Context: ctx})
if err != nil {
return 0, err
}
return count.Uint64(), nil
}
// FetchGameDepth fetches the game depth from the fault dispute game.
func (l *loader) FetchGameDepth(ctx context.Context) (uint64, error) {
callOpts := bind.CallOpts{
Context: ctx,
}
gameDepth, err := l.caller.MAXGAMEDEPTH(&callOpts)
if err != nil {
return 0, err
}
return gameDepth.Uint64(), nil
}
// fetchClaim fetches a single [Claim] with a hydrated parent.
func (l *loader) fetchClaim(ctx context.Context, arrIndex uint64) (types.Claim, error) {
callOpts := bind.CallOpts{
Context: ctx,
}
fetchedClaim, err := l.caller.ClaimData(&callOpts, new(big.Int).SetUint64(arrIndex))
if err != nil {
return types.Claim{}, err
}
claim := types.Claim{
ClaimData: types.ClaimData{
Value: fetchedClaim.Claim,
Position: types.NewPositionFromGIndex(fetchedClaim.Position),
},
Countered: fetchedClaim.Countered,
Clock: fetchedClaim.Clock.Uint64(),
ContractIndex: int(arrIndex),
ParentContractIndex: int(fetchedClaim.ParentIndex),
}
return claim, nil
}
// FetchClaims fetches all claims from the fault dispute game.
func (l *loader) FetchClaims(ctx context.Context) ([]types.Claim, error) {
// Get the current claim count.
claimCount, err := l.caller.ClaimDataLen(&bind.CallOpts{
Context: ctx,
})
if err != nil {
return nil, err
}
// Fetch each claim and build a list.
claimList := make([]types.Claim, claimCount.Uint64())
for i := uint64(0); i < claimCount.Uint64(); i++ {
claim, err := l.fetchClaim(ctx, i)
if err != nil {
return nil, err
}
claimList[i] = claim
}
return claimList, nil
}
// FetchAbsolutePrestateHash fetches the hashed absolute prestate from the fault dispute game.
func (l *loader) FetchAbsolutePrestateHash(ctx context.Context) (common.Hash, error) {
callOpts := bind.CallOpts{
Context: ctx,
}
absolutePrestate, err := l.caller.ABSOLUTEPRESTATE(&callOpts)
if err != nil {
return common.Hash{}, err
}
return absolutePrestate, nil
}
package fault
import (
"context"
"fmt"
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
var (
mockClaimDataError = fmt.Errorf("claim data errored")
mockClaimLenError = fmt.Errorf("claim len errored")
mockMaxGameDepthError = fmt.Errorf("max game depth errored")
mockPrestateError = fmt.Errorf("prestate errored")
mockStatusError = fmt.Errorf("status errored")
)
// TestLoader_GetGameStatus tests fetching the game status.
func TestLoader_GetGameStatus(t *testing.T) {
tests := []struct {
name string
status uint8
expectedError bool
}{
{
name: "challenger won status",
status: uint8(gameTypes.GameStatusChallengerWon),
},
{
name: "defender won status",
status: uint8(gameTypes.GameStatusDefenderWon),
},
{
name: "in progress status",
status: uint8(gameTypes.GameStatusInProgress),
},
{
name: "error bubbled up",
expectedError: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
mockCaller := newMockCaller()
mockCaller.status = test.status
mockCaller.statusError = test.expectedError
loader := NewLoader(mockCaller)
status, err := loader.GetGameStatus(context.Background())
if test.expectedError {
require.ErrorIs(t, err, mockStatusError)
} else {
require.NoError(t, err)
require.Equal(t, gameTypes.GameStatus(test.status), status)
}
})
}
}
// TestLoader_FetchGameDepth tests fetching the game depth.
func TestLoader_FetchGameDepth(t *testing.T) {
t.Run("Succeeds", func(t *testing.T) {
mockCaller := newMockCaller()
mockCaller.maxGameDepth = 10
loader := NewLoader(mockCaller)
depth, err := loader.FetchGameDepth(context.Background())
require.NoError(t, err)
require.Equal(t, uint64(10), depth)
})
t.Run("Errors", func(t *testing.T) {
mockCaller := newMockCaller()
mockCaller.maxGameDepthError = true
loader := NewLoader(mockCaller)
depth, err := loader.FetchGameDepth(context.Background())
require.ErrorIs(t, mockMaxGameDepthError, err)
require.Equal(t, depth, uint64(0))
})
}
// TestLoader_FetchAbsolutePrestateHash tests fetching the absolute prestate hash.
func TestLoader_FetchAbsolutePrestateHash(t *testing.T) {
t.Run("Succeeds", func(t *testing.T) {
mockCaller := newMockCaller()
loader := NewLoader(mockCaller)
prestate, err := loader.FetchAbsolutePrestateHash(context.Background())
require.NoError(t, err)
require.ElementsMatch(t, common.HexToHash("0xdEad"), prestate)
})
t.Run("Errors", func(t *testing.T) {
mockCaller := newMockCaller()
mockCaller.prestateError = true
loader := NewLoader(mockCaller)
prestate, err := loader.FetchAbsolutePrestateHash(context.Background())
require.Error(t, err)
require.ElementsMatch(t, common.Hash{}, prestate)
})
}
// TestLoader_FetchClaims tests fetching claims.
func TestLoader_FetchClaims(t *testing.T) {
t.Run("Succeeds", func(t *testing.T) {
mockCaller := newMockCaller()
expectedClaims := mockCaller.returnClaims
loader := NewLoader(mockCaller)
claims, err := loader.FetchClaims(context.Background())
require.NoError(t, err)
require.ElementsMatch(t, []types.Claim{
{
ClaimData: types.ClaimData{
Value: expectedClaims[0].Claim,
Position: types.NewPositionFromGIndex(expectedClaims[0].Position),
},
Countered: false,
Clock: uint64(0),
ContractIndex: 0,
},
{
ClaimData: types.ClaimData{
Value: expectedClaims[1].Claim,
Position: types.NewPositionFromGIndex(expectedClaims[1].Position),
},
Countered: false,
Clock: uint64(0),
ContractIndex: 1,
ParentContractIndex: 0,
},
{
ClaimData: types.ClaimData{
Value: expectedClaims[2].Claim,
Position: types.NewPositionFromGIndex(expectedClaims[2].Position),
},
Countered: false,
Clock: uint64(0),
ContractIndex: 2,
ParentContractIndex: 1,
},
}, claims)
})
t.Run("Claim Data Errors", func(t *testing.T) {
mockCaller := newMockCaller()
mockCaller.claimDataError = true
loader := NewLoader(mockCaller)
claims, err := loader.FetchClaims(context.Background())
require.ErrorIs(t, err, mockClaimDataError)
require.Empty(t, claims)
})
t.Run("Claim Len Errors", func(t *testing.T) {
mockCaller := newMockCaller()
mockCaller.claimLenError = true
loader := NewLoader(mockCaller)
claims, err := loader.FetchClaims(context.Background())
require.ErrorIs(t, err, mockClaimLenError)
require.Empty(t, claims)
})
}
type mockCaller struct {
claimDataError bool
claimLenError bool
maxGameDepthError bool
prestateError bool
statusError bool
maxGameDepth uint64
currentIndex uint64
status uint8
returnClaims []struct {
ParentIndex uint32
Countered bool
Claim [32]byte
Position *big.Int
Clock *big.Int
}
}
func newMockCaller() *mockCaller {
return &mockCaller{
returnClaims: []struct {
ParentIndex uint32
Countered bool
Claim [32]byte
Position *big.Int
Clock *big.Int
}{
{
Claim: [32]byte{0x00},
Position: big.NewInt(1),
Countered: false,
Clock: big.NewInt(0),
},
{
Claim: [32]byte{0x01},
Position: big.NewInt(2),
Countered: false,
Clock: big.NewInt(0),
ParentIndex: 0,
},
{
Claim: [32]byte{0x02},
Position: big.NewInt(3),
Countered: false,
Clock: big.NewInt(0),
ParentIndex: 1,
},
},
}
}
func (m *mockCaller) ClaimData(opts *bind.CallOpts, arg0 *big.Int) (struct {
ParentIndex uint32
Countered bool
Claim [32]byte
Position *big.Int
Clock *big.Int
}, error) {
if m.claimDataError {
return struct {
ParentIndex uint32
Countered bool
Claim [32]byte
Position *big.Int
Clock *big.Int
}{}, mockClaimDataError
}
returnClaim := m.returnClaims[arg0.Uint64()]
m.currentIndex++
return returnClaim, nil
}
func (m *mockCaller) Status(opts *bind.CallOpts) (uint8, error) {
if m.statusError {
return 0, mockStatusError
}
return m.status, nil
}
func (m *mockCaller) ClaimDataLen(opts *bind.CallOpts) (*big.Int, error) {
if m.claimLenError {
return big.NewInt(0), mockClaimLenError
}
return big.NewInt(int64(len(m.returnClaims))), nil
}
func (m *mockCaller) MAXGAMEDEPTH(opts *bind.CallOpts) (*big.Int, error) {
if m.maxGameDepthError {
return nil, mockMaxGameDepthError
}
return big.NewInt(int64(m.maxGameDepth)), nil
}
func (m *mockCaller) ABSOLUTEPRESTATE(opts *bind.CallOpts) ([32]byte, error) {
if m.prestateError {
return [32]byte{}, mockPrestateError
}
return common.HexToHash("0xdEad"), nil
}
......@@ -8,7 +8,6 @@ import (
"time"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
......@@ -356,25 +355,6 @@ func (g *FaultGameHelper) ResolveClaim(ctx context.Context, claimIdx int64) {
g.require.NoError(err, "ResolveClaim transaction was not OK")
}
// ResolveAllClaims resolves all subgames
// This function does not resolve the game. That's the responsibility of challengers
func (g *FaultGameHelper) ResolveAllClaims(ctx context.Context) {
loader := fault.NewLoader(g.game)
claims, err := loader.FetchClaims(ctx)
g.require.NoError(err, "Failed to fetch claims")
subgames := make(map[int]bool)
for i := len(claims) - 1; i > 0; i-- {
subgames[claims[i].ParentContractIndex] = true
// Subgames containing only one node are implicitly resolved
// i.e. uncountered and claims at MAX_DEPTH
if !subgames[i] {
continue
}
g.ResolveClaim(ctx, int64(i))
}
g.ResolveClaim(ctx, 0)
}
func (g *FaultGameHelper) gameData(ctx context.Context) string {
opts := &bind.CallOpts{Context: ctx}
maxDepth := int(g.MaxDepth(ctx))
......
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