-
Notifications
You must be signed in to change notification settings - Fork 3k
/
actors.go
136 lines (115 loc) · 3.54 KB
/
actors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package solver
import (
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/test"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum/go-ethereum/common"
)
type actor interface {
Apply(t *testing.T, game types.Game, correctTrace types.TraceProvider) (types.Game, bool)
}
type actorFn func(t *testing.T, game types.Game, correctTrace types.TraceProvider) (types.Game, bool)
func (a actorFn) Apply(t *testing.T, game types.Game, correctTrace types.TraceProvider) (types.Game, bool) {
return a(t, game, correctTrace)
}
type builderFn func(builder *test.GameBuilder) bool
func (a builderFn) Apply(t *testing.T, game types.Game, correctTrace types.TraceProvider) (types.Game, bool) {
builder := test.NewGameBuilderFromGame(t, correctTrace, game)
done := a(builder)
return builder.Game, done
}
func combineActors(actors ...actor) actor {
return actorFn(func(t *testing.T, game types.Game, correctTrace types.TraceProvider) (types.Game, bool) {
done := true
for _, actor := range actors {
newGame, actorDone := actor.Apply(t, game, correctTrace)
game = newGame
done = done && actorDone
}
return game, done
})
}
var doNothingActor builderFn = func(builder *test.GameBuilder) bool {
return true
}
var correctAttackLastClaim = respondLastClaim(func(seq *test.GameBuilderSeq) {
seq.Attack()
})
var correctDefendLastClaim = respondLastClaim(func(seq *test.GameBuilderSeq) {
if seq.IsRoot() {
// Must attack the root
seq.Attack()
} else {
seq.Defend()
}
})
var incorrectAttackLastClaim = respondLastClaim(func(seq *test.GameBuilderSeq) {
seq.Attack(test.WithValue(common.Hash{0xaa}))
})
var incorrectDefendLastClaim = respondLastClaim(func(seq *test.GameBuilderSeq) {
if seq.IsRoot() {
// Must attack the root
seq.Attack(test.WithValue(common.Hash{0xdd}))
} else {
seq.Defend(test.WithValue(common.Hash{0xdd}))
}
})
var attackEverythingCorrect = respondAllClaims(func(seq *test.GameBuilderSeq) {
seq.Attack()
})
var defendEverythingCorrect = respondAllClaims(func(seq *test.GameBuilderSeq) {
if seq.IsRoot() {
// Must attack root
seq.Attack()
} else {
seq.Defend()
}
})
var attackEverythingIncorrect = respondAllClaims(func(seq *test.GameBuilderSeq) {
seq.Attack(test.WithValue(common.Hash{0xaa}))
})
var defendEverythingIncorrect = respondAllClaims(func(seq *test.GameBuilderSeq) {
if seq.IsRoot() {
// Must attack root
seq.Attack(test.WithValue(common.Hash{0xbb}))
} else {
seq.Defend(test.WithValue(common.Hash{0xbb}))
}
})
var exhaustive = respondAllClaims(func(seq *test.GameBuilderSeq) {
seq.Attack()
seq.Attack(test.WithValue(common.Hash{0xaa}))
if !seq.IsRoot() {
seq.Defend()
seq.Defend(test.WithValue(common.Hash{0xdd}))
}
})
func respondLastClaim(respond func(seq *test.GameBuilderSeq)) builderFn {
return func(builder *test.GameBuilder) bool {
seq := seqFromLastClaim(builder)
if seq.IsMaxDepth() {
// Can't counter the leaf claim
return true
}
respond(seq)
return false
}
}
func respondAllClaims(respond func(seq *test.GameBuilderSeq)) builderFn {
return func(builder *test.GameBuilder) bool {
startingCount := len(builder.Game.Claims())
for _, claim := range builder.Game.Claims() {
if claim.Depth() == builder.Game.MaxDepth() {
continue
}
respond(builder.SeqFrom(claim))
}
finalCount := len(builder.Game.Claims())
return finalCount == startingCount
}
}
func seqFromLastClaim(builder *test.GameBuilder) *test.GameBuilderSeq {
claims := builder.Game.Claims()
claim := claims[len(claims)-1]
return builder.SeqFrom(claim)
}