Commit a19535eb authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #6424 from ethereum-optimism/refcell/solver-module

fix(op-challenger): Refactor Solver Component into its own Module
parents 94ab1561 18c4160a
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/ethereum-optimism/optimism/op-challenger/fault/solver"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
...@@ -19,7 +20,7 @@ type Responder interface { ...@@ -19,7 +20,7 @@ type Responder interface {
} }
type Agent struct { type Agent struct {
solver *Solver solver *solver.Solver
loader Loader loader Loader
responder Responder responder Responder
maxDepth int maxDepth int
...@@ -29,7 +30,7 @@ type Agent struct { ...@@ -29,7 +30,7 @@ type Agent struct {
func NewAgent(loader Loader, maxDepth int, trace types.TraceProvider, responder Responder, agreeWithProposedOutput bool, log log.Logger) *Agent { func NewAgent(loader Loader, maxDepth int, trace types.TraceProvider, responder Responder, agreeWithProposedOutput bool, log log.Logger) *Agent {
return &Agent{ return &Agent{
solver: NewSolver(maxDepth, trace), solver: solver.NewSolver(maxDepth, trace),
loader: loader, loader: loader,
responder: responder, responder: responder,
maxDepth: maxDepth, maxDepth: maxDepth,
...@@ -49,7 +50,7 @@ func (a *Agent) Act(ctx context.Context) error { ...@@ -49,7 +50,7 @@ func (a *Agent) Act(ctx context.Context) error {
} }
// Create counter claims // Create counter claims
for _, claim := range game.Claims() { for _, claim := range game.Claims() {
if err := a.move(ctx, claim, game); err != nil && !errors.Is(err, ErrGameDepthReached) { if err := a.move(ctx, claim, game); err != nil && !errors.Is(err, types.ErrGameDepthReached) {
log.Error("Failed to move", "err", err) log.Error("Failed to move", "err", err)
} }
} }
......
package fault package solver
import ( import (
"errors" "errors"
...@@ -9,9 +9,8 @@ import ( ...@@ -9,9 +9,8 @@ import (
) )
var ( var (
ErrGameDepthReached = errors.New("game depth reached") ErrStepNonLeafNode = errors.New("cannot step on non-leaf claims")
ErrStepNonLeafNode = errors.New("cannot step on non-leaf claims") ErrStepAgreedClaim = errors.New("cannot step on claims we agree with")
ErrStepAgreedClaim = errors.New("cannot step on claims we agree with")
) )
// Solver uses a [TraceProvider] to determine the moves to make in a dispute game. // Solver uses a [TraceProvider] to determine the moves to make in a dispute game.
...@@ -62,7 +61,7 @@ func (s *Solver) handleMiddle(claim types.Claim) (*types.Claim, error) { ...@@ -62,7 +61,7 @@ func (s *Solver) handleMiddle(claim types.Claim) (*types.Claim, error) {
return nil, err return nil, err
} }
if claim.Depth() == s.gameDepth { if claim.Depth() == s.gameDepth {
return nil, ErrGameDepthReached return nil, types.ErrGameDepthReached
} }
if claimCorrect { if claimCorrect {
return s.defend(claim) return s.defend(claim)
......
package fault package solver_test
import ( import (
"fmt" "fmt"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-challenger/fault/solver"
"github.com/ethereum-optimism/optimism/op-challenger/fault/test"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestNextMove(t *testing.T) { func TestNextMove(t *testing.T) {
maxDepth := 4 maxDepth := 4
builder := NewClaimBuilder(t, maxDepth) builder := test.NewAlphabetClaimBuilder(t, maxDepth)
tests := []struct { tests := []struct {
name string name string
claim types.Claim claim types.Claim
...@@ -70,18 +72,18 @@ func TestNextMove(t *testing.T) { ...@@ -70,18 +72,18 @@ func TestNextMove(t *testing.T) {
{ {
name: "ErrorWhenClaimIsLeaf_Correct", name: "ErrorWhenClaimIsLeaf_Correct",
claim: builder.CreateLeafClaim(4, true), claim: builder.CreateLeafClaim(4, true),
expectedErr: ErrGameDepthReached, expectedErr: types.ErrGameDepthReached,
}, },
{ {
name: "ErrorWhenClaimIsLeaf_Incorrect", name: "ErrorWhenClaimIsLeaf_Incorrect",
claim: builder.CreateLeafClaim(6, false), claim: builder.CreateLeafClaim(6, false),
expectedErr: ErrGameDepthReached, expectedErr: types.ErrGameDepthReached,
}, },
} }
for _, test := range tests { for _, test := range tests {
test := test test := test
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
solver := NewSolver(maxDepth, builder.CorrectTraceProvider()) solver := solver.NewSolver(maxDepth, builder.CorrectTraceProvider())
move, err := solver.NextMove(test.claim, test.agreeWithLevel) move, err := solver.NextMove(test.claim, test.agreeWithLevel)
if test.expectedErr == nil { if test.expectedErr == nil {
require.NoError(t, err) require.NoError(t, err)
...@@ -100,8 +102,8 @@ func TestNextMove(t *testing.T) { ...@@ -100,8 +102,8 @@ func TestNextMove(t *testing.T) {
func TestAttemptStep(t *testing.T) { func TestAttemptStep(t *testing.T) {
maxDepth := 3 maxDepth := 3
builder := NewClaimBuilder(t, maxDepth) builder := test.NewAlphabetClaimBuilder(t, maxDepth)
solver := NewSolver(maxDepth, builder.CorrectTraceProvider()) alphabetSolver := solver.NewSolver(maxDepth, builder.CorrectTraceProvider())
// Last accessible leaf is the second last trace index // Last accessible leaf is the second last trace index
// The root node is used for the last trace index and can only be attacked. // The root node is used for the last trace index and can only be attacked.
...@@ -161,13 +163,13 @@ func TestAttemptStep(t *testing.T) { ...@@ -161,13 +163,13 @@ func TestAttemptStep(t *testing.T) {
{ {
name: "CannotStepNonLeaf", name: "CannotStepNonLeaf",
claim: builder.Seq(false).Attack(false).Get(), claim: builder.Seq(false).Attack(false).Get(),
expectedErr: ErrStepNonLeafNode, expectedErr: solver.ErrStepNonLeafNode,
}, },
{ {
name: "CannotStepAgreedNode", name: "CannotStepAgreedNode",
claim: builder.Seq(false).Attack(false).Get(), claim: builder.Seq(false).Attack(false).Get(),
agreeWithLevel: true, agreeWithLevel: true,
expectedErr: ErrStepNonLeafNode, expectedErr: solver.ErrStepNonLeafNode,
}, },
} }
...@@ -175,7 +177,7 @@ func TestAttemptStep(t *testing.T) { ...@@ -175,7 +177,7 @@ func TestAttemptStep(t *testing.T) {
test := test test := test
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
fmt.Printf("%v\n", test.claim.Position.TraceIndex(maxDepth)) fmt.Printf("%v\n", test.claim.Position.TraceIndex(maxDepth))
step, err := solver.AttemptStep(test.claim, test.agreeWithLevel) step, err := alphabetSolver.AttemptStep(test.claim, test.agreeWithLevel)
if test.expectedErr == nil { if test.expectedErr == nil {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, test.claim, step.LeafClaim) require.Equal(t, test.claim, step.LeafClaim)
...@@ -184,7 +186,7 @@ func TestAttemptStep(t *testing.T) { ...@@ -184,7 +186,7 @@ func TestAttemptStep(t *testing.T) {
require.Equal(t, test.expectProofData, step.ProofData) require.Equal(t, test.expectProofData, step.ProofData)
} else { } else {
require.ErrorIs(t, err, test.expectedErr) require.ErrorIs(t, err, test.expectedErr)
require.Equal(t, StepData{}, step) require.Equal(t, solver.StepData{}, step)
} }
}) })
} }
......
package test
import (
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/fault/alphabet"
)
func NewAlphabetClaimBuilder(t *testing.T, maxDepth int) *ClaimBuilder {
alphabetProvider := &alphabetWithProofProvider{alphabet.NewAlphabetProvider("abcdefghijklmnopqrstuvwxyz", uint64(maxDepth))}
return NewClaimBuilder(t, maxDepth, alphabetProvider)
}
type alphabetWithProofProvider struct {
*alphabet.AlphabetProvider
}
func (a *alphabetWithProofProvider) GetPreimage(i uint64) ([]byte, []byte, error) {
preimage, _, err := a.AlphabetProvider.GetPreimage(i)
if err != nil {
return nil, nil, err
}
return preimage, []byte{byte(i)}, nil
}
package fault package test
import ( import (
"math/big" "math/big"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-challenger/fault/alphabet"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -17,11 +16,12 @@ type ClaimBuilder struct { ...@@ -17,11 +16,12 @@ type ClaimBuilder struct {
correct types.TraceProvider correct types.TraceProvider
} }
func NewClaimBuilder(t *testing.T, maxDepth int) *ClaimBuilder { // NewClaimBuilder creates a new [ClaimBuilder].
func NewClaimBuilder(t *testing.T, maxDepth int, provider types.TraceProvider) *ClaimBuilder {
return &ClaimBuilder{ return &ClaimBuilder{
require: require.New(t), require: require.New(t),
maxDepth: maxDepth, maxDepth: maxDepth,
correct: &alphabetWithProofProvider{alphabet.NewAlphabetProvider("abcdefghijklmnopqrstuvwxyz", uint64(maxDepth))}, correct: provider,
} }
} }
...@@ -109,51 +109,3 @@ func (c *ClaimBuilder) DefendClaim(claim types.Claim, correct bool) types.Claim ...@@ -109,51 +109,3 @@ func (c *ClaimBuilder) DefendClaim(claim types.Claim, correct bool) types.Claim
Parent: claim.ClaimData, Parent: claim.ClaimData,
} }
} }
type SequenceBuilder struct {
builder *ClaimBuilder
lastClaim types.Claim
}
// Seq starts building a claim by following a sequence of attack and defend moves from the root
// The returned SequenceBuilder can be used to add additional moves. e.g:
// claim := Seq(true).Attack(false).Attack(true).Defend(true).Get()
func (c *ClaimBuilder) Seq(rootCorrect bool) *SequenceBuilder {
claim := c.CreateRootClaim(rootCorrect)
return &SequenceBuilder{
builder: c,
lastClaim: claim,
}
}
func (s *SequenceBuilder) Attack(correct bool) *SequenceBuilder {
claim := s.builder.AttackClaim(s.lastClaim, correct)
return &SequenceBuilder{
builder: s.builder,
lastClaim: claim,
}
}
func (s *SequenceBuilder) Defend(correct bool) *SequenceBuilder {
claim := s.builder.DefendClaim(s.lastClaim, correct)
return &SequenceBuilder{
builder: s.builder,
lastClaim: claim,
}
}
func (s *SequenceBuilder) Get() types.Claim {
return s.lastClaim
}
type alphabetWithProofProvider struct {
*alphabet.AlphabetProvider
}
func (a *alphabetWithProofProvider) GetPreimage(i uint64) ([]byte, []byte, error) {
preimage, _, err := a.AlphabetProvider.GetPreimage(i)
if err != nil {
return nil, nil, err
}
return preimage, []byte{byte(i)}, nil
}
package test
import (
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
)
type SequenceBuilder struct {
builder *ClaimBuilder
lastClaim types.Claim
}
// Seq starts building a claim by following a sequence of attack and defend moves from the root
// The returned SequenceBuilder can be used to add additional moves. e.g:
// claim := Seq(true).Attack(false).Attack(true).Defend(true).Get()
func (c *ClaimBuilder) Seq(rootCorrect bool) *SequenceBuilder {
claim := c.CreateRootClaim(rootCorrect)
return &SequenceBuilder{
builder: c,
lastClaim: claim,
}
}
func (s *SequenceBuilder) Attack(correct bool) *SequenceBuilder {
claim := s.builder.AttackClaim(s.lastClaim, correct)
return &SequenceBuilder{
builder: s.builder,
lastClaim: claim,
}
}
func (s *SequenceBuilder) Defend(correct bool) *SequenceBuilder {
claim := s.builder.DefendClaim(s.lastClaim, correct)
return &SequenceBuilder{
builder: s.builder,
lastClaim: claim,
}
}
func (s *SequenceBuilder) Get() types.Claim {
return s.lastClaim
}
package types package types
import ( import (
"errors"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
var (
ErrGameDepthReached = errors.New("game depth reached")
)
type GameStatus uint8 type GameStatus uint8
const ( const (
......
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