Skip to content

Commit

Permalink
Merge pull request ethereum-optimism#8110 from ethereum-optimism/aj/s…
Browse files Browse the repository at this point in the history
…plit-providers

op-challenger: Add a provider selector function for split output games
  • Loading branch information
ajsutton authored Nov 13, 2023
2 parents 111f3f3 + c2e4696 commit 290f58c
Show file tree
Hide file tree
Showing 10 changed files with 460 additions and 217 deletions.
6 changes: 5 additions & 1 deletion op-challenger/game/fault/test/game_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,14 @@ type GameBuilderSeq struct {
}

func (g *GameBuilder) Seq() *GameBuilderSeq {
return g.SeqFrom(g.Game.Claims()[0])
}

func (g *GameBuilder) SeqFrom(claim types.Claim) *GameBuilderSeq {
return &GameBuilderSeq{
gameBuilder: g,
builder: g.builder,
lastClaim: g.Game.Claims()[0],
lastClaim: claim,
}
}

Expand Down
6 changes: 3 additions & 3 deletions op-challenger/game/fault/trace/access.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import (
"github.com/ethereum/go-ethereum/common"
)

type ProviderCreator func(ctx context.Context, pre types.Claim, post types.Claim) (types.TraceProvider, error)

func NewSimpleTraceAccessor(trace types.TraceProvider) *Accessor {
selector := func(_ context.Context, _ types.Game, _ types.Claim, _ types.Position) (types.TraceProvider, error) {
return trace, nil
}
return &Accessor{selector}
}

type ProviderSelector func(ctx context.Context, game types.Game, ref types.Claim, pos types.Position) (types.TraceProvider, error)

type Accessor struct {
selector func(ctx context.Context, game types.Game, ref types.Claim, pos types.Position) (types.TraceProvider, error)
selector ProviderSelector
}

func (t *Accessor) Get(ctx context.Context, game types.Game, ref types.Claim, pos types.Position) (common.Hash, error) {
Expand Down
6 changes: 5 additions & 1 deletion op-challenger/game/fault/trace/alphabet/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package alphabet
import (
"context"
"errors"
"fmt"
"math/big"
"strings"

Expand Down Expand Up @@ -43,7 +44,7 @@ func (ap *AlphabetTraceProvider) GetStepData(ctx context.Context, i types.Positi
traceIndex = traceIndex.Sub(traceIndex, big.NewInt(1))
// The index cannot be larger than the maximum index as computed by the depth.
if traceIndex.Cmp(big.NewInt(int64(ap.maxLen))) >= 0 {
return nil, nil, nil, ErrIndexTooLarge
return nil, nil, nil, fmt.Errorf("%w traceIndex: %v max: %v pos: %v", ErrIndexTooLarge, traceIndex, ap.maxLen, i)
}
// We extend the deepest hash to the maximum depth if the trace is not expansive.
if traceIndex.Cmp(big.NewInt(int64(len(ap.state)))) >= 0 {
Expand All @@ -54,6 +55,9 @@ func (ap *AlphabetTraceProvider) GetStepData(ctx context.Context, i types.Positi

// Get returns the claim value at the given index in the trace.
func (ap *AlphabetTraceProvider) Get(ctx context.Context, i types.Position) (common.Hash, error) {
if uint64(i.Depth()) > ap.depth {
return common.Hash{}, fmt.Errorf("%w depth: %v max: %v", ErrIndexTooLarge, i.Depth(), ap.depth)
}
// Step data returns the pre-state, so add 1 to get the state for index i
ti := i.TraceIndex(int(ap.depth))
postPosition := types.NewPosition(int(ap.depth), new(big.Int).Add(ti, big.NewInt(1)))
Expand Down
8 changes: 8 additions & 0 deletions op-challenger/game/fault/trace/alphabet/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ func TestGet_IndexTooLarge(t *testing.T) {
require.ErrorIs(t, err, ErrIndexTooLarge)
}

func TestGet_DepthTooLarge(t *testing.T) {
depth := 2
ap := NewTraceProvider("abc", uint64(depth))
pos := types.NewPosition(depth+1, big.NewInt(0))
_, err := ap.Get(context.Background(), pos)
require.ErrorIs(t, err, ErrIndexTooLarge)
}

// TestGet_Extends tests the Get function with an index that is larger
// than the trace, but smaller than the maximum depth.
func TestGet_Extends(t *testing.T) {
Expand Down
89 changes: 89 additions & 0 deletions op-challenger/game/fault/trace/outputs/split.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package outputs

import (
"context"
"errors"
"fmt"
"math/big"

"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
)

var (
errRefClaimNotDeepEnough = errors.New("reference claim is not deep enough")
)

type ProviderCreator func(ctx context.Context, pre types.Claim, post types.Claim) (types.TraceProvider, error)

func newSplitProviderSelector(topProvider types.TraceProvider, topDepth int, bottomProviderCreator ProviderCreator) trace.ProviderSelector {
return func(ctx context.Context, game types.Game, ref types.Claim, pos types.Position) (types.TraceProvider, error) {
if pos.Depth() <= topDepth {
return topProvider, nil
}
if ref.Position.Depth() < topDepth {
return nil, fmt.Errorf("%w, claim depth: %v, depth required: %v", errRefClaimNotDeepEnough, ref.Position.Depth(), topDepth)
}

// Find the ancestor claim at the leaf level for the top game.
topLeaf, err := findAncestorAtDepth(game, ref, topDepth)
if err != nil {
return nil, err
}

var pre, post types.Claim
// If pos is to the right of the leaf from the top game, we must be defending that output root
// otherwise, we're attacking it.
if pos.TraceIndex(pos.Depth()).Cmp(topLeaf.TraceIndex(pos.Depth())) > 0 {
// Defending the top leaf claim, so use it as the pre-claim and find the post
pre = topLeaf
postTraceIdx := new(big.Int).Add(pre.TraceIndex(topDepth), big.NewInt(1))
post, err = findAncestorWithTraceIndex(game, topLeaf, topDepth, postTraceIdx)
if err != nil {
return nil, fmt.Errorf("failed to find post claim: %w", err)
}
} else {
// Attacking the top leaf claim, so use it as the post-claim and find the pre
post = topLeaf
postTraceIdx := post.TraceIndex(topDepth)
if postTraceIdx.Cmp(big.NewInt(0)) == 0 {
pre = types.Claim{}
} else {
preTraceIdx := new(big.Int).Sub(postTraceIdx, big.NewInt(1))
pre, err = findAncestorWithTraceIndex(game, topLeaf, topDepth, preTraceIdx)
if err != nil {
return nil, fmt.Errorf("failed to find pre claim: %w", err)
}
}
}
provider, err := bottomProviderCreator(ctx, pre, post)
if err != nil {
return nil, err
}
// Translate such that the root of the bottom game is the level below the top game leaf
return trace.Translate(provider, uint64(topDepth)+1), nil
}
}

func findAncestorAtDepth(game types.Game, claim types.Claim, depth int) (types.Claim, error) {
for claim.Depth() > depth {
parent, err := game.GetParent(claim)
if err != nil {
return types.Claim{}, fmt.Errorf("failed to find ancestor at depth %v: %w", depth, err)
}
claim = parent
}
return claim, nil
}

func findAncestorWithTraceIndex(game types.Game, ref types.Claim, depth int, traceIdx *big.Int) (types.Claim, error) {
candidate := ref
for candidate.TraceIndex(depth).Cmp(traceIdx) != 0 {
parent, err := game.GetParent(candidate)
if err != nil {
return types.Claim{}, fmt.Errorf("failed to get parent of claim %v: %w", candidate.ContractIndex, err)
}
candidate = parent
}
return candidate, nil
}
Loading

0 comments on commit 290f58c

Please sign in to comment.