Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
e0bb0187
Unverified
Commit
e0bb0187
authored
Jul 24, 2023
by
refcell.eth
Committed by
GitHub
Jul 24, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into aj/cannon-executor
parents
8d7584ee
d653ea62
Changes
26
Show whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
277 additions
and
233 deletions
+277
-233
main.go
op-challenger/cmd/main.go
+1
-1
main_test.go
op-challenger/cmd/main_test.go
+4
-5
config.go
op-challenger/config/config.go
+38
-39
config_test.go
op-challenger/config/config_test.go
+7
-8
abi_test.go
op-challenger/fault/abi_test.go
+2
-1
agent.go
op-challenger/fault/agent.go
+16
-6
alphabet_provider.go
op-challenger/fault/alphabet_provider.go
+3
-2
alphabet_provider_test.go
op-challenger/fault/alphabet_provider_test.go
+3
-2
caller.go
op-challenger/fault/caller.go
+7
-6
caller_test.go
op-challenger/fault/caller_test.go
+3
-2
loader.go
op-challenger/fault/loader.go
+12
-11
loader_test.go
op-challenger/fault/loader_test.go
+14
-13
monitor.go
op-challenger/fault/monitor.go
+5
-4
monitor_test.go
op-challenger/fault/monitor_test.go
+8
-7
responder.go
op-challenger/fault/responder.go
+5
-4
responder_test.go
op-challenger/fault/responder_test.go
+21
-20
service.go
op-challenger/fault/service.go
+4
-4
solver.go
op-challenger/fault/solver.go
+16
-15
solver_test.go
op-challenger/fault/solver_test.go
+64
-27
game.go
op-challenger/fault/types/game.go
+2
-2
game_test.go
op-challenger/fault/types/game_test.go
+1
-1
position.go
op-challenger/fault/types/position.go
+1
-1
position_test.go
op-challenger/fault/types/position_test.go
+1
-1
types.go
op-challenger/fault/types/types.go
+1
-11
flags.go
op-challenger/flags/flags.go
+35
-37
helper.go
op-e2e/e2eutils/disputegame/helper.go
+3
-3
No files found.
op-challenger/cmd/main.go
View file @
e0bb0187
...
...
@@ -60,7 +60,7 @@ func run(args []string, action ConfigAction) error {
}
logger
.
Info
(
"Starting op-challenger"
,
"version"
,
VersionWithMeta
)
cfg
,
err
:=
config
.
NewConfigFromCLI
(
ctx
)
cfg
,
err
:=
flags
.
NewConfigFromCLI
(
ctx
)
if
err
!=
nil
{
return
err
}
...
...
op-challenger/cmd/main_test.go
View file @
e0bb0187
...
...
@@ -6,7 +6,6 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/flags"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
...
...
@@ -39,12 +38,12 @@ func TestLogLevel(t *testing.T) {
func
TestDefaultCLIOptionsMatchDefaultConfig
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgs
())
defaultCfg
:=
config
.
NewConfig
(
l1EthRpc
,
common
.
HexToAddress
(
gameAddressValue
),
flags
.
TraceTypeAlphabet
,
alphabetTrace
,
cannonDatadir
,
true
,
4
)
defaultCfg
:=
config
.
NewConfig
(
l1EthRpc
,
common
.
HexToAddress
(
gameAddressValue
),
config
.
TraceTypeAlphabet
,
alphabetTrace
,
cannonDatadir
,
true
,
4
)
require
.
Equal
(
t
,
defaultCfg
,
cfg
)
}
func
TestDefaultConfigIsValid
(
t
*
testing
.
T
)
{
cfg
:=
config
.
NewConfig
(
l1EthRpc
,
common
.
HexToAddress
(
gameAddressValue
),
flags
.
TraceTypeAlphabet
,
alphabetTrace
,
cannonDatadir
,
true
,
4
)
cfg
:=
config
.
NewConfig
(
l1EthRpc
,
common
.
HexToAddress
(
gameAddressValue
),
config
.
TraceTypeAlphabet
,
alphabetTrace
,
cannonDatadir
,
true
,
4
)
require
.
NoError
(
t
,
cfg
.
Check
())
}
...
...
@@ -66,7 +65,7 @@ func TestTraceType(t *testing.T) {
verifyArgsInvalid
(
t
,
"flag trace-type is required"
,
addRequiredArgsExcept
(
"--trace-type"
))
})
for
_
,
traceType
:=
range
flags
.
TraceTypes
{
for
_
,
traceType
:=
range
config
.
TraceTypes
{
traceType
:=
traceType
t
.
Run
(
"Valid_"
+
traceType
.
String
(),
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgsExcept
(
"--trace-type"
,
"--trace-type"
,
traceType
.
String
()))
...
...
@@ -172,7 +171,7 @@ func requiredArgs() map[string]string {
"--agree-with-proposed-output"
:
agreeWithProposedOutput
,
"--l1-eth-rpc"
:
l1EthRpc
,
"--game-address"
:
gameAddressValue
,
"--trace-type"
:
flags
.
TraceTypeAlphabet
.
String
()
,
"--trace-type"
:
"alphabet"
,
"--alphabet"
:
alphabetTrace
,
"--cannon-datadir"
:
cannonDatadir
,
}
...
...
op-challenger/config/config.go
View file @
e0bb0187
...
...
@@ -2,14 +2,10 @@ package config
import
(
"errors"
"
strings
"
"
fmt
"
"github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v2"
"github.com/ethereum-optimism/optimism/op-challenger/flags"
opservice
"github.com/ethereum-optimism/optimism/op-service"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
)
var
(
...
...
@@ -20,6 +16,36 @@ var (
ErrMissingGameAddress
=
errors
.
New
(
"missing game address"
)
)
type
TraceType
string
const
(
TraceTypeAlphabet
TraceType
=
"alphabet"
TraceTypeCannon
TraceType
=
"cannon"
)
var
TraceTypes
=
[]
TraceType
{
TraceTypeAlphabet
,
TraceTypeCannon
}
func
(
t
TraceType
)
String
()
string
{
return
string
(
t
)
}
func
(
t
*
TraceType
)
Set
(
value
string
)
error
{
if
!
ValidTraceType
(
TraceType
(
value
))
{
return
fmt
.
Errorf
(
"unknown trace type: %q"
,
value
)
}
*
t
=
TraceType
(
value
)
return
nil
}
func
ValidTraceType
(
value
TraceType
)
bool
{
for
_
,
t
:=
range
TraceTypes
{
if
t
==
value
{
return
true
}
}
return
false
}
// Config is a well typed config that is parsed from the CLI params.
// This also contains config options for auxiliary services.
// It is used to initialize the challenger.
...
...
@@ -29,7 +55,7 @@ type Config struct {
AgreeWithProposedOutput
bool
// Temporary config if we agree or disagree with the posted output
GameDepth
int
// Depth of the game tree
TraceType
flags
.
TraceType
// Type of trace
TraceType
TraceType
// Type of trace
AlphabetTrace
string
// String for the AlphabetTraceProvider
CannonDatadir
string
// Cannon Data Directory for the CannonTraceProvider
...
...
@@ -39,7 +65,7 @@ type Config struct {
func
NewConfig
(
l1EthRpc
string
,
gameAddress
common
.
Address
,
traceType
flags
.
TraceType
,
traceType
TraceType
,
alphabetTrace
string
,
cannonDatadir
string
,
agreeWithProposedOutput
bool
,
...
...
@@ -70,10 +96,10 @@ func (c Config) Check() error {
if
c
.
TraceType
==
""
{
return
ErrMissingTraceType
}
if
c
.
TraceType
==
flags
.
TraceTypeCannon
&&
c
.
CannonDatadir
==
""
{
if
c
.
TraceType
==
TraceTypeCannon
&&
c
.
CannonDatadir
==
""
{
return
ErrMissingCannonDatadir
}
if
c
.
TraceType
==
flags
.
TraceTypeAlphabet
&&
c
.
AlphabetTrace
==
""
{
if
c
.
TraceType
==
TraceTypeAlphabet
&&
c
.
AlphabetTrace
==
""
{
return
ErrMissingAlphabetTrace
}
if
err
:=
c
.
TxMgrConfig
.
Check
();
err
!=
nil
{
...
...
@@ -81,30 +107,3 @@ func (c Config) Check() error {
}
return
nil
}
// NewConfigFromCLI parses the Config from the provided flags or environment variables.
func
NewConfigFromCLI
(
ctx
*
cli
.
Context
)
(
*
Config
,
error
)
{
if
err
:=
flags
.
CheckRequired
(
ctx
);
err
!=
nil
{
return
nil
,
err
}
dgfAddress
,
err
:=
opservice
.
ParseAddress
(
ctx
.
String
(
flags
.
DGFAddressFlag
.
Name
))
if
err
!=
nil
{
return
nil
,
err
}
txMgrConfig
:=
txmgr
.
ReadCLIConfig
(
ctx
)
traceTypeFlag
:=
flags
.
TraceType
(
strings
.
ToLower
(
ctx
.
String
(
flags
.
TraceTypeFlag
.
Name
)))
return
&
Config
{
// Required Flags
L1EthRpc
:
ctx
.
String
(
flags
.
L1EthRpcFlag
.
Name
),
TraceType
:
traceTypeFlag
,
GameAddress
:
dgfAddress
,
AlphabetTrace
:
ctx
.
String
(
flags
.
AlphabetFlag
.
Name
),
CannonDatadir
:
ctx
.
String
(
flags
.
CannonDatadirFlag
.
Name
),
AgreeWithProposedOutput
:
ctx
.
Bool
(
flags
.
AgreeWithProposedOutputFlag
.
Name
),
GameDepth
:
ctx
.
Int
(
flags
.
GameDepthFlag
.
Name
),
TxMgrConfig
:
txMgrConfig
,
},
nil
}
op-challenger/config/config_test.go
View file @
e0bb0187
...
...
@@ -3,7 +3,6 @@ package config
import
(
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/flags"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
...
...
@@ -18,27 +17,27 @@ var (
gameDepth
=
4
)
func
validConfig
(
traceType
flags
.
TraceType
)
Config
{
func
validConfig
(
traceType
TraceType
)
Config
{
cfg
:=
NewConfig
(
validL1EthRpc
,
validGameAddress
,
traceType
,
validAlphabetTrace
,
validCannonDatadir
,
agreeWithProposedOutput
,
gameDepth
)
return
cfg
}
// TestValidConfigIsValid checks that the config provided by validConfig is actually valid
func
TestValidConfigIsValid
(
t
*
testing
.
T
)
{
err
:=
validConfig
(
flags
.
TraceTypeCannon
)
.
Check
()
err
:=
validConfig
(
TraceTypeCannon
)
.
Check
()
require
.
NoError
(
t
,
err
)
}
func
TestTxMgrConfig
(
t
*
testing
.
T
)
{
t
.
Run
(
"Invalid"
,
func
(
t
*
testing
.
T
)
{
config
:=
validConfig
(
flags
.
TraceTypeCannon
)
config
:=
validConfig
(
TraceTypeCannon
)
config
.
TxMgrConfig
=
txmgr
.
CLIConfig
{}
require
.
Equal
(
t
,
config
.
Check
()
.
Error
(),
"must provide a L1 RPC url"
)
})
}
func
TestL1EthRpcRequired
(
t
*
testing
.
T
)
{
config
:=
validConfig
(
flags
.
TraceTypeCannon
)
config
:=
validConfig
(
TraceTypeCannon
)
config
.
L1EthRpc
=
""
require
.
ErrorIs
(
t
,
config
.
Check
(),
ErrMissingL1EthRPC
)
config
.
L1EthRpc
=
validL1EthRpc
...
...
@@ -46,7 +45,7 @@ func TestL1EthRpcRequired(t *testing.T) {
}
func
TestGameAddressRequired
(
t
*
testing
.
T
)
{
config
:=
validConfig
(
flags
.
TraceTypeCannon
)
config
:=
validConfig
(
TraceTypeCannon
)
config
.
GameAddress
=
common
.
Address
{}
require
.
ErrorIs
(
t
,
config
.
Check
(),
ErrMissingGameAddress
)
config
.
GameAddress
=
validGameAddress
...
...
@@ -54,7 +53,7 @@ func TestGameAddressRequired(t *testing.T) {
}
func
TestAlphabetTraceRequired
(
t
*
testing
.
T
)
{
config
:=
validConfig
(
flags
.
TraceTypeAlphabet
)
config
:=
validConfig
(
TraceTypeAlphabet
)
config
.
AlphabetTrace
=
""
require
.
ErrorIs
(
t
,
config
.
Check
(),
ErrMissingAlphabetTrace
)
config
.
AlphabetTrace
=
validAlphabetTrace
...
...
@@ -62,7 +61,7 @@ func TestAlphabetTraceRequired(t *testing.T) {
}
func
TestCannonTraceRequired
(
t
*
testing
.
T
)
{
config
:=
validConfig
(
flags
.
TraceTypeCannon
)
config
:=
validConfig
(
TraceTypeCannon
)
config
.
CannonDatadir
=
""
require
.
ErrorIs
(
t
,
config
.
Check
(),
ErrMissingCannonDatadir
)
config
.
CannonDatadir
=
validCannonDatadir
...
...
op-challenger/fault/abi_test.go
View file @
e0bb0187
...
...
@@ -5,6 +5,7 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -81,7 +82,7 @@ func TestBuildFaultStepData(t *testing.T) {
responder
,
_
:=
newTestFaultResponder
(
t
,
false
)
data
,
err
:=
responder
.
buildStepTxData
(
StepCallData
{
data
,
err
:=
responder
.
buildStepTxData
(
types
.
StepCallData
{
ClaimIndex
:
2
,
IsAttack
:
false
,
StateData
:
[]
byte
{
0x01
},
...
...
op-challenger/fault/agent.go
View file @
e0bb0187
...
...
@@ -5,9 +5,19 @@ import (
"errors"
"fmt"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/log"
)
// Responder takes a response action & executes.
// For full op-challenger this means executing the transaction on chain.
type
Responder
interface
{
CanResolve
(
ctx
context
.
Context
)
bool
Resolve
(
ctx
context
.
Context
)
error
Respond
(
ctx
context
.
Context
,
response
types
.
Claim
)
error
Step
(
ctx
context
.
Context
,
stepData
types
.
StepCallData
)
error
}
type
Agent
struct
{
solver
*
Solver
loader
Loader
...
...
@@ -17,7 +27,7 @@ type Agent struct {
log
log
.
Logger
}
func
NewAgent
(
loader
Loader
,
maxDepth
int
,
trace
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
{
solver
:
NewSolver
(
maxDepth
,
trace
),
loader
:
loader
,
...
...
@@ -67,7 +77,7 @@ func (a *Agent) tryResolve(ctx context.Context) bool {
}
// newGameFromContracts initializes a new game state from the state in the contract
func
(
a
*
Agent
)
newGameFromContracts
(
ctx
context
.
Context
)
(
Game
,
error
)
{
func
(
a
*
Agent
)
newGameFromContracts
(
ctx
context
.
Context
)
(
types
.
Game
,
error
)
{
claims
,
err
:=
a
.
loader
.
FetchClaims
(
ctx
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"failed to fetch claims: %w"
,
err
)
...
...
@@ -75,7 +85,7 @@ func (a *Agent) newGameFromContracts(ctx context.Context) (Game, error) {
if
len
(
claims
)
==
0
{
return
nil
,
errors
.
New
(
"no claims"
)
}
game
:=
NewGameState
(
a
.
agreeWithProposedOutput
,
claims
[
0
],
uint64
(
a
.
maxDepth
))
game
:=
types
.
NewGameState
(
a
.
agreeWithProposedOutput
,
claims
[
0
],
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
)
}
...
...
@@ -83,7 +93,7 @@ func (a *Agent) newGameFromContracts(ctx context.Context) (Game, error) {
}
// move determines & executes the next move given a claim
func
(
a
*
Agent
)
move
(
ctx
context
.
Context
,
claim
Claim
,
game
Game
)
error
{
func
(
a
*
Agent
)
move
(
ctx
context
.
Context
,
claim
types
.
Claim
,
game
types
.
Game
)
error
{
nextMove
,
err
:=
a
.
solver
.
NextMove
(
claim
,
game
.
AgreeWithClaimLevel
(
claim
))
if
err
!=
nil
{
return
fmt
.
Errorf
(
"execute next move: %w"
,
err
)
...
...
@@ -105,7 +115,7 @@ func (a *Agent) move(ctx context.Context, claim Claim, game Game) error {
}
// step determines & executes the next step against a leaf claim through the responder
func
(
a
*
Agent
)
step
(
ctx
context
.
Context
,
claim
Claim
,
game
Game
)
error
{
func
(
a
*
Agent
)
step
(
ctx
context
.
Context
,
claim
types
.
Claim
,
game
types
.
Game
)
error
{
if
claim
.
Depth
()
!=
a
.
maxDepth
{
return
nil
}
...
...
@@ -129,7 +139,7 @@ func (a *Agent) step(ctx context.Context, claim Claim, game Game) error {
a
.
log
.
Info
(
"Performing step"
,
"is_attack"
,
step
.
IsAttack
,
"depth"
,
step
.
LeafClaim
.
Depth
(),
"index_at_depth"
,
step
.
LeafClaim
.
IndexAtDepth
(),
"value"
,
step
.
LeafClaim
.
Value
)
callData
:=
StepCallData
{
callData
:=
types
.
StepCallData
{
ClaimIndex
:
uint64
(
step
.
LeafClaim
.
ContractIndex
),
IsAttack
:
step
.
IsAttack
,
StateData
:
step
.
PreState
,
...
...
op-challenger/fault/alphabet_provider.go
View file @
e0bb0187
...
...
@@ -4,11 +4,12 @@ import (
"math/big"
"strings"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
var
_
TraceProvider
=
(
*
AlphabetProvider
)(
nil
)
var
_
types
.
TraceProvider
=
(
*
AlphabetProvider
)(
nil
)
// AlphabetProvider is a [TraceProvider] that provides claims for specific
// indices in the given trace.
...
...
@@ -29,7 +30,7 @@ func NewAlphabetProvider(state string, depth uint64) *AlphabetProvider {
func
(
ap
*
AlphabetProvider
)
GetPreimage
(
i
uint64
)
([]
byte
,
[]
byte
,
error
)
{
// The index cannot be larger than the maximum index as computed by the depth.
if
i
>=
ap
.
maxLen
{
return
nil
,
nil
,
ErrIndexTooLarge
return
nil
,
nil
,
types
.
ErrIndexTooLarge
}
// We extend the deepest hash to the maximum depth if the trace is not expansive.
if
i
>=
uint64
(
len
(
ap
.
state
))
{
...
...
op-challenger/fault/alphabet_provider_test.go
View file @
e0bb0187
...
...
@@ -4,6 +4,7 @@ import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
...
...
@@ -66,7 +67,7 @@ func TestGetPreimage_Succeeds(t *testing.T) {
func
TestGetPreimage_TooLargeIndex_Fails
(
t
*
testing
.
T
)
{
ap
:=
NewAlphabetProvider
(
"abc"
,
2
)
_
,
_
,
err
:=
ap
.
GetPreimage
(
4
)
require
.
ErrorIs
(
t
,
err
,
ErrIndexTooLarge
)
require
.
ErrorIs
(
t
,
err
,
types
.
ErrIndexTooLarge
)
}
// TestGet_Succeeds tests the Get function.
...
...
@@ -83,7 +84,7 @@ func TestGet_Succeeds(t *testing.T) {
func
TestGet_IndexTooLarge
(
t
*
testing
.
T
)
{
ap
:=
NewAlphabetProvider
(
"abc"
,
2
)
_
,
err
:=
ap
.
Get
(
4
)
require
.
ErrorIs
(
t
,
err
,
ErrIndexTooLarge
)
require
.
ErrorIs
(
t
,
err
,
types
.
ErrIndexTooLarge
)
}
// TestGet_Extends tests the Get function with an index that is larger
...
...
op-challenger/fault/caller.go
View file @
e0bb0187
...
...
@@ -5,6 +5,7 @@ import (
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -59,9 +60,9 @@ func (fc *FaultCaller) LogGameInfo(ctx context.Context) {
// 0: In Progress
// 1: Challenger Won
// 2: Defender Won
func
(
fc
*
FaultCaller
)
GetGameStatus
(
ctx
context
.
Context
)
(
GameStatus
,
error
)
{
func
(
fc
*
FaultCaller
)
GetGameStatus
(
ctx
context
.
Context
)
(
types
.
GameStatus
,
error
)
{
status
,
err
:=
fc
.
Status
(
&
bind
.
CallOpts
{
Context
:
ctx
})
return
GameStatus
(
status
),
err
return
types
.
GameStatus
(
status
),
err
}
// GetClaimDataLength returns the number of claims in the game.
...
...
@@ -79,13 +80,13 @@ func (fc *FaultCaller) LogClaimDataLength(ctx context.Context) {
}
// GameStatusString returns the current game status as a string.
func
GameStatusString
(
status
GameStatus
)
string
{
func
GameStatusString
(
status
types
.
GameStatus
)
string
{
switch
status
{
case
GameStatusInProgress
:
case
types
.
GameStatusInProgress
:
return
"In Progress"
case
GameStatusChallengerWon
:
case
types
.
GameStatusChallengerWon
:
return
"Challenger Won"
case
GameStatusDefenderWon
:
case
types
.
GameStatusDefenderWon
:
return
"Defender Won"
default
:
return
"Unknown"
...
...
op-challenger/fault/caller_test.go
View file @
e0bb0187
...
...
@@ -6,6 +6,7 @@ import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/stretchr/testify/require"
)
...
...
@@ -40,7 +41,7 @@ func TestFaultCaller_GetGameStatus(t *testing.T) {
tests
:=
[]
struct
{
name
string
caller
FaultDisputeGameCaller
expectedStatus
GameStatus
expectedStatus
types
.
GameStatus
expectedErr
error
}{
{
...
...
@@ -48,7 +49,7 @@ func TestFaultCaller_GetGameStatus(t *testing.T) {
caller
:
&
mockFaultDisputeGameCaller
{
status
:
1
,
},
expectedStatus
:
GameStatusChallengerWon
,
expectedStatus
:
types
.
GameStatusChallengerWon
,
expectedErr
:
nil
,
},
{
...
...
op-challenger/fault/loader.go
View file @
e0bb0187
...
...
@@ -4,6 +4,7 @@ import (
"context"
"math/big"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
)
...
...
@@ -22,7 +23,7 @@ type ClaimFetcher interface {
// Loader is a minimal interface for loading onchain [Claim] data.
type
Loader
interface
{
FetchClaims
(
ctx
context
.
Context
)
([]
Claim
,
error
)
FetchClaims
(
ctx
context
.
Context
)
([]
types
.
Claim
,
error
)
}
// loader pulls in fault dispute game claim data periodically and over subscriptions.
...
...
@@ -38,20 +39,20 @@ func NewLoader(claimFetcher ClaimFetcher) *loader {
}
// fetchClaim fetches a single [Claim] with a hydrated parent.
func
(
l
*
loader
)
fetchClaim
(
ctx
context
.
Context
,
arrIndex
uint64
)
(
Claim
,
error
)
{
func
(
l
*
loader
)
fetchClaim
(
ctx
context
.
Context
,
arrIndex
uint64
)
(
types
.
Claim
,
error
)
{
callOpts
:=
bind
.
CallOpts
{
Context
:
ctx
,
}
fetchedClaim
,
err
:=
l
.
claimFetcher
.
ClaimData
(
&
callOpts
,
new
(
big
.
Int
)
.
SetUint64
(
arrIndex
))
if
err
!=
nil
{
return
Claim
{},
err
return
types
.
Claim
{},
err
}
claim
:=
Claim
{
ClaimData
:
ClaimData
{
claim
:=
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
fetchedClaim
.
Claim
,
Position
:
NewPositionFromGIndex
(
fetchedClaim
.
Position
.
Uint64
()),
Position
:
types
.
NewPositionFromGIndex
(
fetchedClaim
.
Position
.
Uint64
()),
},
Countered
:
fetchedClaim
.
Countered
,
Clock
:
fetchedClaim
.
Clock
.
Uint64
(),
...
...
@@ -63,11 +64,11 @@ func (l *loader) fetchClaim(ctx context.Context, arrIndex uint64) (Claim, error)
parentIndex
:=
uint64
(
fetchedClaim
.
ParentIndex
)
parentClaim
,
err
:=
l
.
claimFetcher
.
ClaimData
(
&
callOpts
,
new
(
big
.
Int
)
.
SetUint64
(
parentIndex
))
if
err
!=
nil
{
return
Claim
{},
err
return
types
.
Claim
{},
err
}
claim
.
Parent
=
ClaimData
{
claim
.
Parent
=
types
.
ClaimData
{
Value
:
parentClaim
.
Claim
,
Position
:
NewPositionFromGIndex
(
parentClaim
.
Position
.
Uint64
()),
Position
:
types
.
NewPositionFromGIndex
(
parentClaim
.
Position
.
Uint64
()),
}
}
...
...
@@ -75,7 +76,7 @@ func (l *loader) fetchClaim(ctx context.Context, arrIndex uint64) (Claim, error)
}
// FetchClaims fetches all claims from the fault dispute game.
func
(
l
*
loader
)
FetchClaims
(
ctx
context
.
Context
)
([]
Claim
,
error
)
{
func
(
l
*
loader
)
FetchClaims
(
ctx
context
.
Context
)
([]
types
.
Claim
,
error
)
{
// Get the current claim count.
claimCount
,
err
:=
l
.
claimFetcher
.
ClaimDataLen
(
&
bind
.
CallOpts
{
Context
:
ctx
,
...
...
@@ -85,7 +86,7 @@ func (l *loader) FetchClaims(ctx context.Context) ([]Claim, error) {
}
// Fetch each claim and build a list.
claimList
:=
make
([]
Claim
,
claimCount
.
Uint64
())
claimList
:=
make
([]
types
.
Claim
,
claimCount
.
Uint64
())
for
i
:=
uint64
(
0
);
i
<
claimCount
.
Uint64
();
i
++
{
claim
,
err
:=
l
.
fetchClaim
(
ctx
,
i
)
if
err
!=
nil
{
...
...
op-challenger/fault/loader_test.go
View file @
e0bb0187
...
...
@@ -6,6 +6,7 @@ import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/stretchr/testify/require"
)
...
...
@@ -94,41 +95,41 @@ func TestLoader_FetchClaims_Succeeds(t *testing.T) {
loader
:=
NewLoader
(
mockClaimFetcher
)
claims
,
err
:=
loader
.
FetchClaims
(
context
.
Background
())
require
.
NoError
(
t
,
err
)
require
.
ElementsMatch
(
t
,
[]
Claim
{
require
.
ElementsMatch
(
t
,
[]
types
.
Claim
{
{
ClaimData
:
ClaimData
{
ClaimData
:
types
.
ClaimData
{
Value
:
expectedClaims
[
0
]
.
Claim
,
Position
:
NewPositionFromGIndex
(
expectedClaims
[
0
]
.
Position
.
Uint64
()),
Position
:
types
.
NewPositionFromGIndex
(
expectedClaims
[
0
]
.
Position
.
Uint64
()),
},
Parent
:
ClaimData
{
Parent
:
types
.
ClaimData
{
Value
:
expectedClaims
[
0
]
.
Claim
,
Position
:
NewPositionFromGIndex
(
expectedClaims
[
0
]
.
Position
.
Uint64
()),
Position
:
types
.
NewPositionFromGIndex
(
expectedClaims
[
0
]
.
Position
.
Uint64
()),
},
Countered
:
false
,
Clock
:
uint64
(
0
),
ContractIndex
:
0
,
},
{
ClaimData
:
ClaimData
{
ClaimData
:
types
.
ClaimData
{
Value
:
expectedClaims
[
1
]
.
Claim
,
Position
:
NewPositionFromGIndex
(
expectedClaims
[
1
]
.
Position
.
Uint64
()),
Position
:
types
.
NewPositionFromGIndex
(
expectedClaims
[
1
]
.
Position
.
Uint64
()),
},
Parent
:
ClaimData
{
Parent
:
types
.
ClaimData
{
Value
:
expectedClaims
[
0
]
.
Claim
,
Position
:
NewPositionFromGIndex
(
expectedClaims
[
1
]
.
Position
.
Uint64
()),
Position
:
types
.
NewPositionFromGIndex
(
expectedClaims
[
1
]
.
Position
.
Uint64
()),
},
Countered
:
false
,
Clock
:
uint64
(
0
),
ContractIndex
:
1
,
},
{
ClaimData
:
ClaimData
{
ClaimData
:
types
.
ClaimData
{
Value
:
expectedClaims
[
2
]
.
Claim
,
Position
:
NewPositionFromGIndex
(
expectedClaims
[
2
]
.
Position
.
Uint64
()),
Position
:
types
.
NewPositionFromGIndex
(
expectedClaims
[
2
]
.
Position
.
Uint64
()),
},
Parent
:
ClaimData
{
Parent
:
types
.
ClaimData
{
Value
:
expectedClaims
[
0
]
.
Claim
,
Position
:
NewPositionFromGIndex
(
expectedClaims
[
2
]
.
Position
.
Uint64
()),
Position
:
types
.
NewPositionFromGIndex
(
expectedClaims
[
2
]
.
Position
.
Uint64
()),
},
Countered
:
false
,
Clock
:
uint64
(
0
),
...
...
op-challenger/fault/monitor.go
View file @
e0bb0187
...
...
@@ -4,11 +4,12 @@ import (
"context"
"time"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/log"
)
type
GameInfo
interface
{
GetGameStatus
(
context
.
Context
)
(
GameStatus
,
error
)
GetGameStatus
(
context
.
Context
)
(
types
.
GameStatus
,
error
)
LogGameInfo
(
ctx
context
.
Context
)
}
...
...
@@ -43,11 +44,11 @@ func progressGame(ctx context.Context, logger log.Logger, agreeWithProposedOutpu
if
status
,
err
:=
caller
.
GetGameStatus
(
ctx
);
err
!=
nil
{
logger
.
Warn
(
"Unable to retrieve game status"
,
"err"
,
err
)
}
else
if
status
!=
0
{
var
expectedStatus
GameStatus
var
expectedStatus
types
.
GameStatus
if
agreeWithProposedOutput
{
expectedStatus
=
GameStatusChallengerWon
expectedStatus
=
types
.
GameStatusChallengerWon
}
else
{
expectedStatus
=
GameStatusDefenderWon
expectedStatus
=
types
.
GameStatusDefenderWon
}
if
expectedStatus
==
status
{
logger
.
Info
(
"Game won"
,
"status"
,
GameStatusString
(
status
))
...
...
op-challenger/fault/monitor_test.go
View file @
e0bb0187
...
...
@@ -5,6 +5,7 @@ import (
"errors"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
...
...
@@ -43,7 +44,7 @@ func TestProgressGame_LogErrorFromAct(t *testing.T) {
func
TestProgressGame_LogErrorWhenGameLost
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
status
GameStatus
status
types
.
GameStatus
agreeWithOutput
bool
logLevel
log
.
Lvl
logMsg
string
...
...
@@ -51,7 +52,7 @@ func TestProgressGame_LogErrorWhenGameLost(t *testing.T) {
}{
{
name
:
"GameLostAsDefender"
,
status
:
GameStatusChallengerWon
,
status
:
types
.
GameStatusChallengerWon
,
agreeWithOutput
:
false
,
logLevel
:
log
.
LvlError
,
logMsg
:
"Game lost"
,
...
...
@@ -59,7 +60,7 @@ func TestProgressGame_LogErrorWhenGameLost(t *testing.T) {
},
{
name
:
"GameLostAsChallenger"
,
status
:
GameStatusDefenderWon
,
status
:
types
.
GameStatusDefenderWon
,
agreeWithOutput
:
true
,
logLevel
:
log
.
LvlError
,
logMsg
:
"Game lost"
,
...
...
@@ -67,7 +68,7 @@ func TestProgressGame_LogErrorWhenGameLost(t *testing.T) {
},
{
name
:
"GameWonAsDefender"
,
status
:
GameStatusDefenderWon
,
status
:
types
.
GameStatusDefenderWon
,
agreeWithOutput
:
false
,
logLevel
:
log
.
LvlInfo
,
logMsg
:
"Game won"
,
...
...
@@ -75,7 +76,7 @@ func TestProgressGame_LogErrorWhenGameLost(t *testing.T) {
},
{
name
:
"GameWonAsChallenger"
,
status
:
GameStatusChallengerWon
,
status
:
types
.
GameStatusChallengerWon
,
agreeWithOutput
:
true
,
logLevel
:
log
.
LvlInfo
,
logMsg
:
"Game won"
,
...
...
@@ -120,12 +121,12 @@ func (a *stubActor) Act(ctx context.Context) error {
}
type
stubGameInfo
struct
{
status
GameStatus
status
types
.
GameStatus
err
error
logCount
int
}
func
(
s
*
stubGameInfo
)
GetGameStatus
(
ctx
context
.
Context
)
(
GameStatus
,
error
)
{
func
(
s
*
stubGameInfo
)
GetGameStatus
(
ctx
context
.
Context
)
(
types
.
GameStatus
,
error
)
{
return
s
.
status
,
s
.
err
}
...
...
op-challenger/fault/responder.go
View file @
e0bb0187
...
...
@@ -5,6 +5,7 @@ import (
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
types2
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum"
...
...
@@ -62,7 +63,7 @@ func (r *faultResponder) buildResolveData() ([]byte, error) {
}
// BuildTx builds the transaction for the [faultResponder].
func
(
r
*
faultResponder
)
BuildTx
(
ctx
context
.
Context
,
response
Claim
)
([]
byte
,
error
)
{
func
(
r
*
faultResponder
)
BuildTx
(
ctx
context
.
Context
,
response
types2
.
Claim
)
([]
byte
,
error
)
{
if
response
.
DefendsParent
()
{
txData
,
err
:=
r
.
buildFaultDefendData
(
response
.
ParentContractIndex
,
response
.
ValueBytes
())
if
err
!=
nil
{
...
...
@@ -103,7 +104,7 @@ func (r *faultResponder) Resolve(ctx context.Context) error {
}
// Respond takes a [Claim] and executes the response action.
func
(
r
*
faultResponder
)
Respond
(
ctx
context
.
Context
,
response
Claim
)
error
{
func
(
r
*
faultResponder
)
Respond
(
ctx
context
.
Context
,
response
types2
.
Claim
)
error
{
txData
,
err
:=
r
.
BuildTx
(
ctx
,
response
)
if
err
!=
nil
{
return
err
...
...
@@ -131,7 +132,7 @@ func (r *faultResponder) sendTxAndWait(ctx context.Context, txData []byte) error
}
// buildStepTxData creates the transaction data for the step function.
func
(
r
*
faultResponder
)
buildStepTxData
(
stepData
StepCallData
)
([]
byte
,
error
)
{
func
(
r
*
faultResponder
)
buildStepTxData
(
stepData
types2
.
StepCallData
)
([]
byte
,
error
)
{
return
r
.
fdgAbi
.
Pack
(
"step"
,
big
.
NewInt
(
int64
(
stepData
.
ClaimIndex
)),
...
...
@@ -142,7 +143,7 @@ func (r *faultResponder) buildStepTxData(stepData StepCallData) ([]byte, error)
}
// Step accepts step data and executes the step on the fault dispute game contract.
func
(
r
*
faultResponder
)
Step
(
ctx
context
.
Context
,
stepData
StepCallData
)
error
{
func
(
r
*
faultResponder
)
Step
(
ctx
context
.
Context
,
stepData
types2
.
StepCallData
)
error
{
txData
,
err
:=
r
.
buildStepTxData
(
stepData
)
if
err
!=
nil
{
return
err
...
...
op-challenger/fault/responder_test.go
View file @
e0bb0187
...
...
@@ -7,6 +7,7 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
types2
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
...
...
@@ -107,14 +108,14 @@ func TestResponder_Resolve_Success(t *testing.T) {
// bubbles up the error returned by the [txmgr.Send] method.
func
TestResponder_Respond_SendFails
(
t
*
testing
.
T
)
{
responder
,
mockTxMgr
:=
newTestFaultResponder
(
t
,
true
)
err
:=
responder
.
Respond
(
context
.
Background
(),
Claim
{
ClaimData
:
ClaimData
{
err
:=
responder
.
Respond
(
context
.
Background
(),
types2
.
Claim
{
ClaimData
:
types2
.
ClaimData
{
Value
:
common
.
Hash
{
0x01
},
Position
:
NewPositionFromGIndex
(
2
),
Position
:
types2
.
NewPositionFromGIndex
(
2
),
},
Parent
:
ClaimData
{
Parent
:
types2
.
ClaimData
{
Value
:
common
.
Hash
{
0x02
},
Position
:
NewPositionFromGIndex
(
1
),
Position
:
types2
.
NewPositionFromGIndex
(
1
),
},
ContractIndex
:
0
,
ParentContractIndex
:
0
,
...
...
@@ -127,14 +128,14 @@ func TestResponder_Respond_SendFails(t *testing.T) {
// succeeds when the tx candidate is successfully sent through the txmgr.
func
TestResponder_Respond_Success
(
t
*
testing
.
T
)
{
responder
,
mockTxMgr
:=
newTestFaultResponder
(
t
,
false
)
err
:=
responder
.
Respond
(
context
.
Background
(),
Claim
{
ClaimData
:
ClaimData
{
err
:=
responder
.
Respond
(
context
.
Background
(),
types2
.
Claim
{
ClaimData
:
types2
.
ClaimData
{
Value
:
common
.
Hash
{
0x01
},
Position
:
NewPositionFromGIndex
(
2
),
Position
:
types2
.
NewPositionFromGIndex
(
2
),
},
Parent
:
ClaimData
{
Parent
:
types2
.
ClaimData
{
Value
:
common
.
Hash
{
0x02
},
Position
:
NewPositionFromGIndex
(
1
),
Position
:
types2
.
NewPositionFromGIndex
(
1
),
},
ContractIndex
:
0
,
ParentContractIndex
:
0
,
...
...
@@ -147,14 +148,14 @@ func TestResponder_Respond_Success(t *testing.T) {
// returns a tx candidate with the correct data for an attack tx.
func
TestResponder_BuildTx_Attack
(
t
*
testing
.
T
)
{
responder
,
_
:=
newTestFaultResponder
(
t
,
false
)
responseClaim
:=
Claim
{
ClaimData
:
ClaimData
{
responseClaim
:=
types2
.
Claim
{
ClaimData
:
types2
.
ClaimData
{
Value
:
common
.
Hash
{
0x01
},
Position
:
NewPositionFromGIndex
(
2
),
Position
:
types2
.
NewPositionFromGIndex
(
2
),
},
Parent
:
ClaimData
{
Parent
:
types2
.
ClaimData
{
Value
:
common
.
Hash
{
0x02
},
Position
:
NewPositionFromGIndex
(
1
),
Position
:
types2
.
NewPositionFromGIndex
(
1
),
},
ContractIndex
:
0
,
ParentContractIndex
:
7
,
...
...
@@ -178,14 +179,14 @@ func TestResponder_BuildTx_Attack(t *testing.T) {
// returns a tx candidate with the correct data for a defend tx.
func
TestResponder_BuildTx_Defend
(
t
*
testing
.
T
)
{
responder
,
_
:=
newTestFaultResponder
(
t
,
false
)
responseClaim
:=
Claim
{
ClaimData
:
ClaimData
{
responseClaim
:=
types2
.
Claim
{
ClaimData
:
types2
.
ClaimData
{
Value
:
common
.
Hash
{
0x01
},
Position
:
NewPositionFromGIndex
(
3
),
Position
:
types2
.
NewPositionFromGIndex
(
3
),
},
Parent
:
ClaimData
{
Parent
:
types2
.
ClaimData
{
Value
:
common
.
Hash
{
0x02
},
Position
:
NewPositionFromGIndex
(
6
),
Position
:
types2
.
NewPositionFromGIndex
(
6
),
},
ContractIndex
:
0
,
ParentContractIndex
:
7
,
...
...
op-challenger/fault/service.go
View file @
e0bb0187
...
...
@@ -7,7 +7,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/fault/cannon"
"github.com/ethereum-optimism/optimism/op-challenger/f
lag
s"
"github.com/ethereum-optimism/optimism/op-challenger/f
ault/type
s"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum-optimism/optimism/op-service/txmgr/metrics"
"github.com/ethereum/go-ethereum/ethclient"
...
...
@@ -52,11 +52,11 @@ func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*se
return
nil
,
fmt
.
Errorf
(
"failed to create the responder: %w"
,
err
)
}
var
trace
TraceProvider
var
trace
types
.
TraceProvider
switch
cfg
.
TraceType
{
case
flags
.
TraceTypeCannon
:
case
config
.
TraceTypeCannon
:
trace
=
cannon
.
NewCannonTraceProvider
(
logger
,
cfg
.
CannonDatadir
)
case
flags
.
TraceTypeAlphabet
:
case
config
.
TraceTypeAlphabet
:
trace
=
NewAlphabetProvider
(
cfg
.
AlphabetTrace
,
uint64
(
cfg
.
GameDepth
))
default
:
return
nil
,
fmt
.
Errorf
(
"unsupported trace type: %v"
,
cfg
.
TraceType
)
...
...
op-challenger/fault/solver.go
View file @
e0bb0187
...
...
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/common"
)
...
...
@@ -13,12 +14,12 @@ var (
// Solver uses a [TraceProvider] to determine the moves to make in a dispute game.
type
Solver
struct
{
TraceProvider
types
.
TraceProvider
gameDepth
int
}
// NewSolver creates a new [Solver] using the provided [TraceProvider].
func
NewSolver
(
gameDepth
int
,
traceProvider
TraceProvider
)
*
Solver
{
func
NewSolver
(
gameDepth
int
,
traceProvider
types
.
TraceProvider
)
*
Solver
{
return
&
Solver
{
traceProvider
,
gameDepth
,
...
...
@@ -26,7 +27,7 @@ func NewSolver(gameDepth int, traceProvider TraceProvider) *Solver {
}
// NextMove returns the next move to make given the current state of the game.
func
(
s
*
Solver
)
NextMove
(
claim
Claim
,
agreeWithClaimLevel
bool
)
(
*
Claim
,
error
)
{
func
(
s
*
Solver
)
NextMove
(
claim
types
.
Claim
,
agreeWithClaimLevel
bool
)
(
*
types
.
Claim
,
error
)
{
if
agreeWithClaimLevel
{
return
nil
,
nil
}
...
...
@@ -38,7 +39,7 @@ func (s *Solver) NextMove(claim Claim, agreeWithClaimLevel bool) (*Claim, error)
return
s
.
handleMiddle
(
claim
)
}
func
(
s
*
Solver
)
handleRoot
(
claim
Claim
)
(
*
Claim
,
error
)
{
func
(
s
*
Solver
)
handleRoot
(
claim
types
.
Claim
)
(
*
types
.
Claim
,
error
)
{
agree
,
err
:=
s
.
agreeWithClaim
(
claim
.
ClaimData
)
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -53,7 +54,7 @@ func (s *Solver) handleRoot(claim Claim) (*Claim, error) {
}
}
func
(
s
*
Solver
)
handleMiddle
(
claim
Claim
)
(
*
Claim
,
error
)
{
func
(
s
*
Solver
)
handleMiddle
(
claim
types
.
Claim
)
(
*
types
.
Claim
,
error
)
{
claimCorrect
,
err
:=
s
.
agreeWithClaim
(
claim
.
ClaimData
)
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -69,7 +70,7 @@ func (s *Solver) handleMiddle(claim Claim) (*Claim, error) {
}
type
StepData
struct
{
LeafClaim
Claim
LeafClaim
types
.
Claim
IsAttack
bool
PreState
[]
byte
ProofData
[]
byte
...
...
@@ -77,7 +78,7 @@ type StepData struct {
// AttemptStep determines what step should occur for a given leaf claim.
// An error will be returned if the claim is not at the max depth.
func
(
s
*
Solver
)
AttemptStep
(
claim
Claim
,
agreeWithClaimLevel
bool
)
(
StepData
,
error
)
{
func
(
s
*
Solver
)
AttemptStep
(
claim
types
.
Claim
,
agreeWithClaimLevel
bool
)
(
StepData
,
error
)
{
if
claim
.
Depth
()
!=
s
.
gameDepth
{
return
StepData
{},
errors
.
New
(
"cannot step on non-leaf claims"
)
}
...
...
@@ -114,41 +115,41 @@ func (s *Solver) AttemptStep(claim Claim, agreeWithClaimLevel bool) (StepData, e
}
// attack returns a response that attacks the claim.
func
(
s
*
Solver
)
attack
(
claim
Claim
)
(
*
Claim
,
error
)
{
func
(
s
*
Solver
)
attack
(
claim
types
.
Claim
)
(
*
types
.
Claim
,
error
)
{
position
:=
claim
.
Attack
()
value
,
err
:=
s
.
traceAtPosition
(
position
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"attack claim: %w"
,
err
)
}
return
&
Claim
{
ClaimData
:
ClaimData
{
Value
:
value
,
Position
:
position
},
return
&
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
value
,
Position
:
position
},
Parent
:
claim
.
ClaimData
,
ParentContractIndex
:
claim
.
ContractIndex
,
},
nil
}
// defend returns a response that defends the claim.
func
(
s
*
Solver
)
defend
(
claim
Claim
)
(
*
Claim
,
error
)
{
func
(
s
*
Solver
)
defend
(
claim
types
.
Claim
)
(
*
types
.
Claim
,
error
)
{
position
:=
claim
.
Defend
()
value
,
err
:=
s
.
traceAtPosition
(
position
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"defend claim: %w"
,
err
)
}
return
&
Claim
{
ClaimData
:
ClaimData
{
Value
:
value
,
Position
:
position
},
return
&
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
value
,
Position
:
position
},
Parent
:
claim
.
ClaimData
,
ParentContractIndex
:
claim
.
ContractIndex
,
},
nil
}
// agreeWithClaim returns true if the claim is correct according to the internal [TraceProvider].
func
(
s
*
Solver
)
agreeWithClaim
(
claim
ClaimData
)
(
bool
,
error
)
{
func
(
s
*
Solver
)
agreeWithClaim
(
claim
types
.
ClaimData
)
(
bool
,
error
)
{
ourValue
,
err
:=
s
.
traceAtPosition
(
claim
.
Position
)
return
ourValue
==
claim
.
Value
,
err
}
// traceAtPosition returns the [common.Hash] from internal [TraceProvider] at the given [Position].
func
(
s
*
Solver
)
traceAtPosition
(
p
Position
)
(
common
.
Hash
,
error
)
{
func
(
s
*
Solver
)
traceAtPosition
(
p
types
.
Position
)
(
common
.
Hash
,
error
)
{
index
:=
p
.
TraceIndex
(
s
.
gameDepth
)
hash
,
err
:=
s
.
Get
(
index
)
return
hash
,
err
...
...
op-challenger/fault/solver_test.go
View file @
e0bb0187
...
...
@@ -3,6 +3,7 @@ package fault
import
(
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
...
...
@@ -23,52 +24,52 @@ func TestSolver_NextMove_Opponent(t *testing.T) {
// The following claims are created using the state: "abcdexyz".
// The responses are the responses we expect from the solver.
indices
:=
[]
struct
{
claim
Claim
response
ClaimData
claim
types
.
Claim
response
types
.
ClaimData
}{
{
Claim
{
ClaimData
:
ClaimData
{
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
alphabetClaim
(
7
,
"z"
),
Position
:
NewPosition
(
0
,
0
),
Position
:
types
.
NewPosition
(
0
,
0
),
},
// Root claim has no parent
},
ClaimData
{
types
.
ClaimData
{
Value
:
alphabetClaim
(
3
,
"d"
),
Position
:
NewPosition
(
1
,
0
),
Position
:
types
.
NewPosition
(
1
,
0
),
},
},
{
Claim
{
ClaimData
:
ClaimData
{
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
alphabetClaim
(
3
,
"d"
),
Position
:
NewPosition
(
1
,
0
),
Position
:
types
.
NewPosition
(
1
,
0
),
},
Parent
:
ClaimData
{
Parent
:
types
.
ClaimData
{
Value
:
alphabetClaim
(
7
,
"h"
),
Position
:
NewPosition
(
0
,
0
),
Position
:
types
.
NewPosition
(
0
,
0
),
},
},
ClaimData
{
types
.
ClaimData
{
Value
:
alphabetClaim
(
5
,
"f"
),
Position
:
NewPosition
(
2
,
2
),
Position
:
types
.
NewPosition
(
2
,
2
),
},
},
{
Claim
{
ClaimData
:
ClaimData
{
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
alphabetClaim
(
5
,
"x"
),
Position
:
NewPosition
(
2
,
2
),
Position
:
types
.
NewPosition
(
2
,
2
),
},
Parent
:
ClaimData
{
Parent
:
types
.
ClaimData
{
Value
:
alphabetClaim
(
7
,
"h"
),
Position
:
NewPosition
(
1
,
1
),
Position
:
types
.
NewPosition
(
1
,
1
),
},
},
ClaimData
{
types
.
ClaimData
{
Value
:
alphabetClaim
(
4
,
"e"
),
Position
:
NewPosition
(
3
,
4
),
Position
:
types
.
NewPosition
(
3
,
4
),
},
},
}
...
...
@@ -85,10 +86,10 @@ func TestNoMoveAgainstOwnLevel(t *testing.T) {
mallory
:=
NewAlphabetProvider
(
"abcdepqr"
,
uint64
(
maxDepth
))
solver
:=
NewSolver
(
maxDepth
,
mallory
)
claim
:=
Claim
{
ClaimData
:
ClaimData
{
claim
:=
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
alphabetClaim
(
7
,
"z"
),
Position
:
NewPosition
(
0
,
0
),
Position
:
types
.
NewPosition
(
0
,
0
),
},
// Root claim has no parent
}
...
...
@@ -104,10 +105,10 @@ func TestAttemptStep(t *testing.T) {
solver
:=
NewSolver
(
maxDepth
,
canonicalProvider
)
_
,
_
,
middle
,
bottom
:=
createTestClaims
()
zero
:=
Claim
{
ClaimData
:
ClaimData
{
zero
:=
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
// Zero value is a purposely disagree with claim value "a"
Position
:
NewPosition
(
3
,
0
),
Position
:
types
.
NewPosition
(
3
,
0
),
},
}
...
...
@@ -150,3 +151,39 @@ func (a *alphabetWithProofProvider) GetPreimage(i uint64) ([]byte, []byte, error
}
return
preimage
,
[]
byte
{
byte
(
i
)},
nil
}
func
createTestClaims
()
(
types
.
Claim
,
types
.
Claim
,
types
.
Claim
,
types
.
Claim
)
{
// root & middle are from the trace "abcdexyz"
// top & bottom are from the trace "abcdefgh"
root
:=
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
common
.
HexToHash
(
"0x000000000000000000000000000000000000000000000000000000000000077a"
),
Position
:
types
.
NewPosition
(
0
,
0
),
},
// Root claim has no parent
}
top
:=
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000364"
),
Position
:
types
.
NewPosition
(
1
,
0
),
},
Parent
:
root
.
ClaimData
,
}
middle
:=
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000578"
),
Position
:
types
.
NewPosition
(
2
,
2
),
},
Parent
:
top
.
ClaimData
,
}
bottom
:=
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000465"
),
Position
:
types
.
NewPosition
(
3
,
4
),
},
Parent
:
middle
.
ClaimData
,
}
return
root
,
top
,
middle
,
bottom
}
op-challenger/fault/game.go
→
op-challenger/fault/
types/
game.go
View file @
e0bb0187
package
fault
package
types
import
(
"errors"
...
...
@@ -26,7 +26,7 @@ type Game interface {
// IsDuplicate returns true if the provided [Claim] already exists in the game state.
IsDuplicate
(
claim
Claim
)
bool
// AgreeWithLevel returns if the game state agrees with the provided claim level.
// AgreeWith
Claim
Level returns if the game state agrees with the provided claim level.
AgreeWithClaimLevel
(
claim
Claim
)
bool
}
...
...
op-challenger/fault/game_test.go
→
op-challenger/fault/
types/
game_test.go
View file @
e0bb0187
package
fault
package
types
import
(
"testing"
...
...
op-challenger/fault/position.go
→
op-challenger/fault/
types/
position.go
View file @
e0bb0187
package
fault
package
types
import
"fmt"
...
...
op-challenger/fault/position_test.go
→
op-challenger/fault/
types/
position_test.go
View file @
e0bb0187
package
fault
package
types
import
(
"testing"
...
...
op-challenger/fault/types.go
→
op-challenger/fault/types
/types
.go
View file @
e0bb0187
package
fault
package
types
import
(
"context"
"errors"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -83,12 +82,3 @@ func (c *Claim) IsRoot() bool {
func
(
c
*
Claim
)
DefendsParent
()
bool
{
return
(
c
.
IndexAtDepth
()
>>
1
)
!=
c
.
Parent
.
IndexAtDepth
()
}
// Responder takes a response action & executes.
// For full op-challenger this means executing the transaction on chain.
type
Responder
interface
{
CanResolve
(
ctx
context
.
Context
)
bool
Resolve
(
ctx
context
.
Context
)
error
Respond
(
ctx
context
.
Context
,
response
Claim
)
error
Step
(
ctx
context
.
Context
,
stepData
StepCallData
)
error
}
op-challenger/flags/flags.go
View file @
e0bb0187
...
...
@@ -4,6 +4,7 @@ import (
"fmt"
"strings"
"github.com/ethereum-optimism/optimism/op-challenger/config"
openum
"github.com/ethereum-optimism/optimism/op-service/enum"
"github.com/urfave/cli/v2"
...
...
@@ -20,36 +21,6 @@ func prefixEnvVars(name string) []string {
return
opservice
.
PrefixEnvVar
(
envVarPrefix
,
name
)
}
type
TraceType
string
const
(
TraceTypeAlphabet
TraceType
=
"alphabet"
TraceTypeCannon
TraceType
=
"cannon"
)
var
TraceTypes
=
[]
TraceType
{
TraceTypeAlphabet
,
TraceTypeCannon
}
func
(
t
TraceType
)
String
()
string
{
return
string
(
t
)
}
func
(
t
*
TraceType
)
Set
(
value
string
)
error
{
if
!
ValidTraceType
(
TraceType
(
value
))
{
return
fmt
.
Errorf
(
"unknown trace type: %q"
,
value
)
}
*
t
=
TraceType
(
value
)
return
nil
}
func
ValidTraceType
(
value
TraceType
)
bool
{
for
_
,
t
:=
range
TraceTypes
{
if
t
==
value
{
return
true
}
}
return
false
}
var
(
// Required Flags
L1EthRpcFlag
=
&
cli
.
StringFlag
{
...
...
@@ -64,10 +35,10 @@ var (
}
TraceTypeFlag
=
&
cli
.
GenericFlag
{
Name
:
"trace-type"
,
Usage
:
"The trace type. Valid options: "
+
openum
.
EnumString
(
TraceTypes
),
Usage
:
"The trace type. Valid options: "
+
openum
.
EnumString
(
config
.
TraceTypes
),
EnvVars
:
prefixEnvVars
(
"TRACE_TYPE"
),
Value
:
func
()
*
TraceType
{
out
:=
TraceType
(
""
)
// No default value
Value
:
func
()
*
config
.
TraceType
{
out
:=
config
.
TraceType
(
""
)
// No default value
return
&
out
}(),
}
...
...
@@ -125,18 +96,45 @@ func CheckRequired(ctx *cli.Context) error {
return
fmt
.
Errorf
(
"flag %s is required"
,
f
.
Names
()[
0
])
}
}
gameType
:=
TraceType
(
strings
.
ToLower
(
ctx
.
String
(
TraceTypeFlag
.
Name
)))
gameType
:=
config
.
TraceType
(
strings
.
ToLower
(
ctx
.
String
(
TraceTypeFlag
.
Name
)))
switch
gameType
{
case
TraceTypeCannon
:
case
config
.
TraceTypeCannon
:
if
!
ctx
.
IsSet
(
CannonDatadirFlag
.
Name
)
{
return
fmt
.
Errorf
(
"flag %s is required"
,
"cannon-datadir"
)
}
case
TraceTypeAlphabet
:
case
config
.
TraceTypeAlphabet
:
if
!
ctx
.
IsSet
(
AlphabetFlag
.
Name
)
{
return
fmt
.
Errorf
(
"flag %s is required"
,
"alphabet"
)
}
default
:
return
fmt
.
Errorf
(
"invalid trace type. must be one of %v"
,
TraceTypes
)
return
fmt
.
Errorf
(
"invalid trace type. must be one of %v"
,
config
.
TraceTypes
)
}
return
nil
}
// NewConfigFromCLI parses the Config from the provided flags or environment variables.
func
NewConfigFromCLI
(
ctx
*
cli
.
Context
)
(
*
config
.
Config
,
error
)
{
if
err
:=
CheckRequired
(
ctx
);
err
!=
nil
{
return
nil
,
err
}
dgfAddress
,
err
:=
opservice
.
ParseAddress
(
ctx
.
String
(
DGFAddressFlag
.
Name
))
if
err
!=
nil
{
return
nil
,
err
}
txMgrConfig
:=
txmgr
.
ReadCLIConfig
(
ctx
)
traceTypeFlag
:=
config
.
TraceType
(
strings
.
ToLower
(
ctx
.
String
(
TraceTypeFlag
.
Name
)))
return
&
config
.
Config
{
// Required Flags
L1EthRpc
:
ctx
.
String
(
L1EthRpcFlag
.
Name
),
TraceType
:
traceTypeFlag
,
GameAddress
:
dgfAddress
,
AlphabetTrace
:
ctx
.
String
(
AlphabetFlag
.
Name
),
CannonDatadir
:
ctx
.
String
(
CannonDatadirFlag
.
Name
),
AgreeWithProposedOutput
:
ctx
.
Bool
(
AgreeWithProposedOutputFlag
.
Name
),
GameDepth
:
ctx
.
Int
(
GameDepthFlag
.
Name
),
TxMgrConfig
:
txMgrConfig
,
},
nil
}
op-e2e/e2eutils/disputegame/helper.go
View file @
e0bb0187
...
...
@@ -11,7 +11,7 @@ import (
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/fault"
"github.com/ethereum-optimism/optimism/op-challenger/f
lag
s"
"github.com/ethereum-optimism/optimism/op-challenger/f
ault/type
s"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-service/client/utils"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
...
...
@@ -107,7 +107,7 @@ func (g *FaultGameHelper) StartChallenger(ctx context.Context, l1Endpoint string
func
(
c
*
config
.
Config
)
{
c
.
GameAddress
=
g
.
addr
c
.
GameDepth
=
alphabetGameDepth
c
.
TraceType
=
flags
.
TraceTypeAlphabet
c
.
TraceType
=
config
.
TraceTypeAlphabet
// By default the challenger agrees with the root claim (thus disagrees with the proposed output)
// This can be overridden by passing in options
c
.
AlphabetTrace
=
g
.
claimedAlphabet
...
...
@@ -169,7 +169,7 @@ func (g *FaultGameHelper) WaitForClaim(ctx context.Context, predicate func(claim
func
(
g
*
FaultGameHelper
)
WaitForClaimAtMaxDepth
(
ctx
context
.
Context
,
countered
bool
)
{
g
.
WaitForClaim
(
ctx
,
func
(
claim
ContractClaim
)
bool
{
pos
:=
fault
.
NewPositionFromGIndex
(
claim
.
Position
.
Uint64
())
pos
:=
types
.
NewPositionFromGIndex
(
claim
.
Position
.
Uint64
())
return
pos
.
Depth
()
==
g
.
maxDepth
&&
claim
.
Countered
==
countered
})
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment