Commit 3cedb234 authored by Adrian Sutton's avatar Adrian Sutton

op-challenger: Remove Put and PutAll from game.

parent 0a6a781b
...@@ -196,9 +196,6 @@ func (a *Agent) newGameFromContracts(ctx context.Context) (types.Game, error) { ...@@ -196,9 +196,6 @@ func (a *Agent) newGameFromContracts(ctx context.Context) (types.Game, error) {
if len(claims) == 0 { if len(claims) == 0 {
return nil, errors.New("no claims") return nil, errors.New("no claims")
} }
game := types.NewGameState(a.agreeWithProposedOutput, claims[0], uint64(a.maxDepth)) game := types.NewGameState(a.agreeWithProposedOutput, claims, uint64(a.maxDepth))
if err := game.PutAll(claims[1:]); err != nil {
return nil, fmt.Errorf("failed to load claims into the local state: %w", err)
}
return game, nil return game, nil
} }
...@@ -6,15 +6,17 @@ import ( ...@@ -6,15 +6,17 @@ import (
) )
type GameBuilder struct { type GameBuilder struct {
builder *ClaimBuilder builder *ClaimBuilder
Game types.Game Game types.Game
ExpectedActions []types.Action ExpectedActions []types.Action
agreeWithOutputRoot bool
} }
func (c *ClaimBuilder) GameBuilder(agreeWithOutputRoot bool, rootCorrect bool) *GameBuilder { func (c *ClaimBuilder) GameBuilder(agreeWithOutputRoot bool, rootCorrect bool) *GameBuilder {
return &GameBuilder{ return &GameBuilder{
builder: c, builder: c,
Game: types.NewGameState(agreeWithOutputRoot, c.CreateRootClaim(rootCorrect), uint64(c.maxDepth)), agreeWithOutputRoot: agreeWithOutputRoot,
Game: types.NewGameState(agreeWithOutputRoot, []types.Claim{c.CreateRootClaim(rootCorrect)}, uint64(c.maxDepth)),
} }
} }
...@@ -22,62 +24,60 @@ type GameBuilderSeq struct { ...@@ -22,62 +24,60 @@ type GameBuilderSeq struct {
gameBuilder *GameBuilder gameBuilder *GameBuilder
builder *ClaimBuilder builder *ClaimBuilder
lastClaim types.Claim lastClaim types.Claim
game types.Game
} }
func (g *GameBuilder) Seq() *GameBuilderSeq { func (g *GameBuilder) Seq() *GameBuilderSeq {
return &GameBuilderSeq{ return &GameBuilderSeq{
gameBuilder: g, gameBuilder: g,
builder: g.builder, builder: g.builder,
game: g.Game,
lastClaim: g.Game.Claims()[0], lastClaim: g.Game.Claims()[0],
} }
} }
// addClaimToGame replaces the game being built with a new instance that has claim as the latest claim.
// The ContractIndex in claim is updated with its position in the game's claim array.
func (s *GameBuilderSeq) addClaimToGame(claim *types.Claim) {
claim.ContractIndex = len(s.gameBuilder.Game.Claims())
claims := append(s.gameBuilder.Game.Claims(), *claim)
s.gameBuilder.Game = types.NewGameState(s.gameBuilder.agreeWithOutputRoot, claims, uint64(s.builder.maxDepth))
}
func (s *GameBuilderSeq) AttackCorrect() *GameBuilderSeq { func (s *GameBuilderSeq) AttackCorrect() *GameBuilderSeq {
claim := s.builder.AttackClaim(s.lastClaim, true) claim := s.builder.AttackClaim(s.lastClaim, true)
claim.ContractIndex = len(s.game.Claims()) s.addClaimToGame(&claim)
s.builder.require.NoError(s.game.Put(claim))
return &GameBuilderSeq{ return &GameBuilderSeq{
gameBuilder: s.gameBuilder, gameBuilder: s.gameBuilder,
builder: s.builder, builder: s.builder,
game: s.game,
lastClaim: claim, lastClaim: claim,
} }
} }
func (s *GameBuilderSeq) Attack(value common.Hash) *GameBuilderSeq { func (s *GameBuilderSeq) Attack(value common.Hash) *GameBuilderSeq {
claim := s.builder.AttackClaimWithValue(s.lastClaim, value) claim := s.builder.AttackClaimWithValue(s.lastClaim, value)
claim.ContractIndex = len(s.game.Claims()) s.addClaimToGame(&claim)
s.builder.require.NoError(s.game.Put(claim))
return &GameBuilderSeq{ return &GameBuilderSeq{
gameBuilder: s.gameBuilder, gameBuilder: s.gameBuilder,
builder: s.builder, builder: s.builder,
game: s.game,
lastClaim: claim, lastClaim: claim,
} }
} }
func (s *GameBuilderSeq) DefendCorrect() *GameBuilderSeq { func (s *GameBuilderSeq) DefendCorrect() *GameBuilderSeq {
claim := s.builder.DefendClaim(s.lastClaim, true) claim := s.builder.DefendClaim(s.lastClaim, true)
claim.ContractIndex = len(s.game.Claims()) s.addClaimToGame(&claim)
s.builder.require.NoError(s.game.Put(claim))
return &GameBuilderSeq{ return &GameBuilderSeq{
gameBuilder: s.gameBuilder, gameBuilder: s.gameBuilder,
builder: s.builder, builder: s.builder,
game: s.game,
lastClaim: claim, lastClaim: claim,
} }
} }
func (s *GameBuilderSeq) Defend(value common.Hash) *GameBuilderSeq { func (s *GameBuilderSeq) Defend(value common.Hash) *GameBuilderSeq {
claim := s.builder.DefendClaimWithValue(s.lastClaim, value) claim := s.builder.DefendClaimWithValue(s.lastClaim, value)
claim.ContractIndex = len(s.game.Claims()) s.addClaimToGame(&claim)
s.builder.require.NoError(s.game.Put(claim))
return &GameBuilderSeq{ return &GameBuilderSeq{
gameBuilder: s.gameBuilder, gameBuilder: s.gameBuilder,
builder: s.builder, builder: s.builder,
game: s.game,
lastClaim: claim, lastClaim: claim,
} }
} }
......
...@@ -18,12 +18,6 @@ var ( ...@@ -18,12 +18,6 @@ var (
// Game is an interface that represents the state of a dispute game. // Game is an interface that represents the state of a dispute game.
type Game interface { type Game interface {
// Put adds a claim into the game state.
Put(claim Claim) error
// PutAll adds a list of claims into the game state.
PutAll(claims []Claim) error
// Claims returns all of the claims in the game. // Claims returns all of the claims in the game.
Claims() []Claim Claims() []Claim
...@@ -62,12 +56,14 @@ type gameState struct { ...@@ -62,12 +56,14 @@ type gameState struct {
// NewGameState returns a new game state. // NewGameState returns a new game state.
// The provided [Claim] is used as the root node. // The provided [Claim] is used as the root node.
func NewGameState(agreeWithProposedOutput bool, root Claim, depth uint64) *gameState { func NewGameState(agreeWithProposedOutput bool, claims []Claim, depth uint64) *gameState {
claimIDs := make(map[claimID]bool) claimIDs := make(map[claimID]bool)
claimIDs[computeClaimID(root)] = true for _, claim := range claims {
claimIDs[computeClaimID(claim)] = true
}
return &gameState{ return &gameState{
agreeWithProposedOutput: agreeWithProposedOutput, agreeWithProposedOutput: agreeWithProposedOutput,
claims: []Claim{root}, claims: claims,
claimIDs: claimIDs, claimIDs: claimIDs,
depth: depth, depth: depth,
} }
...@@ -85,33 +81,6 @@ func (g *gameState) AgreeWithClaimLevel(claim Claim) bool { ...@@ -85,33 +81,6 @@ func (g *gameState) AgreeWithClaimLevel(claim Claim) bool {
} }
} }
// PutAll adds a list of claims into the [Game] state.
// If any of the claims already exist in the game state, an error is returned.
func (g *gameState) PutAll(claims []Claim) error {
for _, claim := range claims {
if err := g.Put(claim); err != nil {
return err
}
}
return nil
}
// Put adds a claim into the game state.
func (g *gameState) Put(claim Claim) error {
if claim.IsRoot() || g.IsDuplicate(claim) {
return ErrClaimExists
}
parent := g.getParent(claim)
if parent == nil {
return errors.New("no parent claim")
}
g.claims = append(g.claims, claim)
g.claimIDs[computeClaimID(claim)] = true
return nil
}
func (g *gameState) IsDuplicate(claim Claim) bool { func (g *gameState) IsDuplicate(claim Claim) bool {
return g.claimIDs[computeClaimID(claim)] return g.claimIDs[computeClaimID(claim)]
} }
......
...@@ -54,8 +54,7 @@ func createTestClaims() (Claim, Claim, Claim, Claim) { ...@@ -54,8 +54,7 @@ func createTestClaims() (Claim, Claim, Claim, Claim) {
func TestIsDuplicate(t *testing.T) { func TestIsDuplicate(t *testing.T) {
// Setup the game state. // Setup the game state.
root, top, middle, bottom := createTestClaims() root, top, middle, bottom := createTestClaims()
g := NewGameState(false, root, testMaxDepth) g := NewGameState(false, []Claim{root, top}, testMaxDepth)
require.NoError(t, g.Put(top))
// Root + Top should be duplicates // Root + Top should be duplicates
require.True(t, g.IsDuplicate(root)) require.True(t, g.IsDuplicate(root))
...@@ -66,137 +65,13 @@ func TestIsDuplicate(t *testing.T) { ...@@ -66,137 +65,13 @@ func TestIsDuplicate(t *testing.T) {
require.False(t, g.IsDuplicate(bottom)) require.False(t, g.IsDuplicate(bottom))
} }
// TestGame_Put_RootAlreadyExists tests the [Game.Put] method using a [gameState] func TestGame_Claims(t *testing.T) {
// instance errors when the root claim already exists in state.
func TestGame_Put_RootAlreadyExists(t *testing.T) {
// Setup the game state. // Setup the game state.
top, _, _, _ := createTestClaims()
g := NewGameState(false, top, testMaxDepth)
// Try to put the root claim into the game state again.
err := g.Put(top)
require.ErrorIs(t, err, ErrClaimExists)
}
// TestGame_PutAll_RootAlreadyExists tests the [Game.PutAll] method using a [gameState]
// instance errors when the root claim already exists in state.
func TestGame_PutAll_RootAlreadyExists(t *testing.T) {
// Setup the game state.
root, _, _, _ := createTestClaims()
g := NewGameState(false, root, testMaxDepth)
// Try to put the root claim into the game state again.
err := g.PutAll([]Claim{root})
require.ErrorIs(t, err, ErrClaimExists)
}
// TestGame_PutAll_AlreadyExists tests the [Game.PutAll] method using a [gameState]
// instance errors when the given claim already exists in state.
func TestGame_PutAll_AlreadyExists(t *testing.T) {
root, top, middle, bottom := createTestClaims() root, top, middle, bottom := createTestClaims()
g := NewGameState(false, root, testMaxDepth) expected := []Claim{root, top, middle, bottom}
g := NewGameState(false, expected, testMaxDepth)
err := g.PutAll([]Claim{top, middle})
require.NoError(t, err)
err = g.PutAll([]Claim{middle, bottom})
require.ErrorIs(t, err, ErrClaimExists)
}
// TestGame_PutAll_ParentsAndChildren tests the [Game.PutAll] method using a [gameState] instance.
func TestGame_PutAll_ParentsAndChildren(t *testing.T) {
// Setup the game state.
root, top, middle, bottom := createTestClaims()
g := NewGameState(false, root, testMaxDepth)
// We should not be able to get the parent of the root claim.
parent, err := g.GetParent(root)
require.ErrorIs(t, err, ErrClaimNotFound)
require.Equal(t, parent, Claim{})
// Put the rest of the claims in the state.
err = g.PutAll([]Claim{top, middle, bottom})
require.NoError(t, err)
parent, err = g.GetParent(top)
require.NoError(t, err)
require.Equal(t, parent, root)
parent, err = g.GetParent(middle)
require.NoError(t, err)
require.Equal(t, parent, top)
parent, err = g.GetParent(bottom)
require.NoError(t, err)
require.Equal(t, parent, middle)
}
// TestGame_Put_AlreadyExists tests the [Game.Put] method using a [gameState]
// instance errors when the given claim already exists in state.
func TestGame_Put_AlreadyExists(t *testing.T) {
// Setup the game state.
top, middle, _, _ := createTestClaims()
g := NewGameState(false, top, testMaxDepth)
// Put the next claim into state.
err := g.Put(middle)
require.NoError(t, err)
// Put the claim into the game state again.
err = g.Put(middle)
require.ErrorIs(t, err, ErrClaimExists)
}
// TestGame_Put_ParentsAndChildren tests the [Game.Put] method using a [gameState] instance.
func TestGame_Put_ParentsAndChildren(t *testing.T) {
// Setup the game state.
root, top, middle, bottom := createTestClaims()
g := NewGameState(false, root, testMaxDepth)
// We should not be able to get the parent of the root claim.
parent, err := g.GetParent(root)
require.ErrorIs(t, err, ErrClaimNotFound)
require.Equal(t, parent, Claim{})
// Put + Check Top
err = g.Put(top)
require.NoError(t, err)
parent, err = g.GetParent(top)
require.NoError(t, err)
require.Equal(t, parent, root)
// Put + Check Top Middle
err = g.Put(middle)
require.NoError(t, err)
parent, err = g.GetParent(middle)
require.NoError(t, err)
require.Equal(t, parent, top)
// Put + Check Top Bottom
err = g.Put(bottom)
require.NoError(t, err)
parent, err = g.GetParent(bottom)
require.NoError(t, err)
require.Equal(t, parent, middle)
}
// TestGame_ClaimPairs tests the [Game.ClaimPairs] method using a [gameState] instance.
func TestGame_ClaimPairs(t *testing.T) {
// Setup the game state.
root, top, middle, bottom := createTestClaims()
g := NewGameState(false, root, testMaxDepth)
// Add top claim to the game state.
err := g.Put(top)
require.NoError(t, err)
// Add the middle claim to the game state.
err = g.Put(middle)
require.NoError(t, err)
// Add the bottom claim to the game state.
err = g.Put(bottom)
require.NoError(t, err)
// Validate claim pairs. // Validate claim pairs.
expected := []Claim{root, top, middle, bottom} actual := g.Claims()
claims := g.Claims() require.ElementsMatch(t, expected, actual)
require.ElementsMatch(t, expected, claims)
} }
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