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
971815e2
Unverified
Commit
971815e2
authored
Sep 11, 2023
by
mergify[bot]
Committed by
GitHub
Sep 11, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into aj/fpa-docs
parents
574c8c0b
64d1c30c
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
549 additions
and
206 deletions
+549
-206
agent.go
op-challenger/game/fault/agent.go
+30
-78
agent_test.go
op-challenger/game/fault/agent_test.go
+2
-5
abi_test.go
op-challenger/game/fault/responder/abi_test.go
+1
-7
responder.go
op-challenger/game/fault/responder/responder.go
+30
-46
responder_test.go
op-challenger/game/fault/responder/responder_test.go
+61
-49
game_solver.go
op-challenger/game/fault/solver/game_solver.go
+107
-0
game_solver_test.go
op-challenger/game/fault/solver/game_solver_test.go
+187
-0
solver.go
op-challenger/game/fault/solver/solver.go
+11
-11
solver_test.go
op-challenger/game/fault/solver/solver_test.go
+7
-8
claim_builder.go
op-challenger/game/fault/test/claim_builder.go
+35
-2
game_builder.go
op-challenger/game/fault/test/game_builder.go
+76
-0
init_game.sh
op-challenger/scripts/alphabet/init_game.sh
+2
-0
No files found.
op-challenger/game/fault/agent.go
View file @
971815e2
...
...
@@ -17,8 +17,7 @@ import (
type
Responder
interface
{
CallResolve
(
ctx
context
.
Context
)
(
gameTypes
.
GameStatus
,
error
)
Resolve
(
ctx
context
.
Context
)
error
Respond
(
ctx
context
.
Context
,
response
types
.
Claim
)
error
Step
(
ctx
context
.
Context
,
stepData
types
.
StepCallData
)
error
PerformAction
(
ctx
context
.
Context
,
action
solver
.
Action
)
error
}
type
ClaimLoader
interface
{
...
...
@@ -27,7 +26,7 @@ type ClaimLoader interface {
type
Agent
struct
{
metrics
metrics
.
Metricer
solver
*
solver
.
Solver
solver
*
solver
.
Game
Solver
loader
ClaimLoader
responder
Responder
updater
types
.
OracleUpdater
...
...
@@ -39,7 +38,7 @@ type Agent struct {
func
NewAgent
(
m
metrics
.
Metricer
,
loader
ClaimLoader
,
maxDepth
int
,
trace
types
.
TraceProvider
,
responder
Responder
,
updater
types
.
OracleUpdater
,
agreeWithProposedOutput
bool
,
log
log
.
Logger
)
*
Agent
{
return
&
Agent
{
metrics
:
m
,
solver
:
solver
.
NewSolver
(
maxDepth
,
trace
),
solver
:
solver
.
New
Game
Solver
(
maxDepth
,
trace
),
loader
:
loader
,
responder
:
responder
,
updater
:
updater
,
...
...
@@ -58,16 +57,34 @@ func (a *Agent) Act(ctx context.Context) error {
if
err
!=
nil
{
return
fmt
.
Errorf
(
"create game from contracts: %w"
,
err
)
}
// Create counter claims
for
_
,
claim
:=
range
game
.
Claims
()
{
if
err
:=
a
.
move
(
ctx
,
claim
,
game
);
err
!=
nil
&&
!
errors
.
Is
(
err
,
types
.
ErrGameDepthReached
)
{
log
.
Error
(
"Failed to move"
,
"err"
,
err
)
}
// Calculate the actions to take
actions
,
err
:=
a
.
solver
.
CalculateNextActions
(
ctx
,
game
)
if
err
!=
nil
{
log
.
Error
(
"Failed to calculate all required moves"
,
"err"
,
err
)
}
// Step on all leaf claims
for
_
,
claim
:=
range
game
.
Claims
()
{
if
err
:=
a
.
step
(
ctx
,
claim
,
game
);
err
!=
nil
{
log
.
Error
(
"Failed to step"
,
"err"
,
err
)
// Perform the actions
for
_
,
action
:=
range
actions
{
log
:=
a
.
log
.
New
(
"action"
,
action
.
Type
,
"is_attack"
,
action
.
IsAttack
,
"parent"
,
action
.
ParentIdx
,
"value"
,
action
.
Value
)
if
action
.
OracleData
!=
nil
{
a
.
log
.
Info
(
"Updating oracle data"
,
"oracleKey"
,
action
.
OracleData
.
OracleKey
,
"oracleData"
,
action
.
OracleData
.
OracleData
)
if
err
:=
a
.
updater
.
UpdateOracle
(
ctx
,
action
.
OracleData
);
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to load oracle data: %w"
,
err
)
}
}
switch
action
.
Type
{
case
solver
.
ActionTypeMove
:
a
.
metrics
.
RecordGameMove
()
case
solver
.
ActionTypeStep
:
a
.
metrics
.
RecordGameStep
()
}
log
.
Info
(
"Performing action"
)
err
:=
a
.
responder
.
PerformAction
(
ctx
,
action
)
if
err
!=
nil
{
log
.
Error
(
"Action failed"
,
"err"
,
err
)
}
}
return
nil
...
...
@@ -118,68 +135,3 @@ func (a *Agent) newGameFromContracts(ctx context.Context) (types.Game, error) {
}
return
game
,
nil
}
// move determines & executes the next move given a claim
func
(
a
*
Agent
)
move
(
ctx
context
.
Context
,
claim
types
.
Claim
,
game
types
.
Game
)
error
{
nextMove
,
err
:=
a
.
solver
.
NextMove
(
ctx
,
claim
,
game
.
AgreeWithClaimLevel
(
claim
))
if
err
!=
nil
{
return
fmt
.
Errorf
(
"execute next move: %w"
,
err
)
}
if
nextMove
==
nil
{
a
.
log
.
Debug
(
"No next move"
)
return
nil
}
move
:=
*
nextMove
log
:=
a
.
log
.
New
(
"is_defend"
,
move
.
DefendsParent
(),
"depth"
,
move
.
Depth
(),
"index_at_depth"
,
move
.
IndexAtDepth
(),
"value"
,
move
.
Value
,
"trace_index"
,
move
.
TraceIndex
(
a
.
maxDepth
),
"parent_value"
,
claim
.
Value
,
"parent_trace_index"
,
claim
.
TraceIndex
(
a
.
maxDepth
))
if
game
.
IsDuplicate
(
move
)
{
log
.
Debug
(
"Skipping duplicate move"
)
return
nil
}
a
.
metrics
.
RecordGameMove
()
log
.
Info
(
"Performing move"
)
return
a
.
responder
.
Respond
(
ctx
,
move
)
}
// step determines & executes the next step against a leaf claim through the responder
func
(
a
*
Agent
)
step
(
ctx
context
.
Context
,
claim
types
.
Claim
,
game
types
.
Game
)
error
{
if
claim
.
Depth
()
!=
a
.
maxDepth
{
return
nil
}
agreeWithClaimLevel
:=
game
.
AgreeWithClaimLevel
(
claim
)
if
agreeWithClaimLevel
{
a
.
log
.
Debug
(
"Agree with leaf claim, skipping step"
,
"claim_depth"
,
claim
.
Depth
(),
"maxDepth"
,
a
.
maxDepth
)
return
nil
}
if
claim
.
Countered
{
a
.
log
.
Debug
(
"Step already executed against claim"
,
"depth"
,
claim
.
Depth
(),
"index_at_depth"
,
claim
.
IndexAtDepth
(),
"value"
,
claim
.
Value
)
return
nil
}
a
.
log
.
Info
(
"Attempting step"
,
"claim_depth"
,
claim
.
Depth
(),
"maxDepth"
,
a
.
maxDepth
)
step
,
err
:=
a
.
solver
.
AttemptStep
(
ctx
,
claim
,
agreeWithClaimLevel
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"attempt step: %w"
,
err
)
}
if
step
.
OracleData
!=
nil
{
a
.
log
.
Info
(
"Updating oracle data"
,
"oracleKey"
,
step
.
OracleData
.
OracleKey
,
"oracleData"
,
step
.
OracleData
.
OracleData
)
if
err
:=
a
.
updater
.
UpdateOracle
(
ctx
,
step
.
OracleData
);
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to load oracle data: %w"
,
err
)
}
}
a
.
log
.
Info
(
"Performing step"
,
"is_attack"
,
step
.
IsAttack
,
"depth"
,
step
.
LeafClaim
.
Depth
(),
"index_at_depth"
,
step
.
LeafClaim
.
IndexAtDepth
(),
"value"
,
step
.
LeafClaim
.
Value
)
a
.
metrics
.
RecordGameStep
()
callData
:=
types
.
StepCallData
{
ClaimIndex
:
uint64
(
step
.
LeafClaim
.
ContractIndex
),
IsAttack
:
step
.
IsAttack
,
StateData
:
step
.
PreState
,
Proof
:
step
.
ProofData
,
}
return
a
.
responder
.
Step
(
ctx
,
callData
)
}
op-challenger/game/fault/agent_test.go
View file @
971815e2
...
...
@@ -5,6 +5,7 @@ import (
"errors"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/solver"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/test"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/alphabet"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
...
...
@@ -144,11 +145,7 @@ func (s *stubResponder) Resolve(ctx context.Context) error {
return
s
.
resolveErr
}
func
(
s
*
stubResponder
)
Respond
(
ctx
context
.
Context
,
response
types
.
Claim
)
error
{
panic
(
"Not implemented"
)
}
func
(
s
*
stubResponder
)
Step
(
ctx
context
.
Context
,
stepData
types
.
StepCallData
)
error
{
func
(
s
*
stubResponder
)
PerformAction
(
ctx
context
.
Context
,
response
solver
.
Action
)
error
{
panic
(
"Not implemented"
)
}
...
...
op-challenger/game/fault/responder/abi_test.go
View file @
971815e2
...
...
@@ -5,7 +5,6 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/game/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"
...
...
@@ -94,12 +93,7 @@ func TestBuildFaultStepData(t *testing.T) {
resp
,
_
:=
newTestFaultResponder
(
t
)
data
,
err
:=
resp
.
buildStepTxData
(
types
.
StepCallData
{
ClaimIndex
:
2
,
IsAttack
:
false
,
StateData
:
[]
byte
{
0x01
},
Proof
:
[]
byte
{
0x02
},
})
data
,
err
:=
resp
.
buildStepTxData
(
2
,
false
,
[]
byte
{
0x01
},
[]
byte
{
0x02
})
require
.
NoError
(
t
,
err
)
opts
.
GasLimit
=
100
_000
...
...
op-challenger/game/fault/responder/responder.go
View file @
971815e2
...
...
@@ -5,7 +5,7 @@ import (
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/
types
"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/
solver
"
gameTypes
"github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
...
...
@@ -16,8 +16,8 @@ import (
"github.com/ethereum/go-ethereum/log"
)
//
f
aultResponder implements the [Responder] interface to send onchain transactions.
type
f
aultResponder
struct
{
//
F
aultResponder implements the [Responder] interface to send onchain transactions.
type
F
aultResponder
struct
{
log
log
.
Logger
txMgr
txmgr
.
TxManager
...
...
@@ -26,13 +26,13 @@ type faultResponder struct {
fdgAbi
*
abi
.
ABI
}
// NewFaultResponder returns a new [
f
aultResponder].
func
NewFaultResponder
(
logger
log
.
Logger
,
txManagr
txmgr
.
TxManager
,
fdgAddr
common
.
Address
)
(
*
f
aultResponder
,
error
)
{
// NewFaultResponder returns a new [
F
aultResponder].
func
NewFaultResponder
(
logger
log
.
Logger
,
txManagr
txmgr
.
TxManager
,
fdgAddr
common
.
Address
)
(
*
F
aultResponder
,
error
)
{
fdgAbi
,
err
:=
bindings
.
FaultDisputeGameMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
return
&
f
aultResponder
{
return
&
F
aultResponder
{
log
:
logger
,
txMgr
:
txManagr
,
fdgAddr
:
fdgAddr
,
...
...
@@ -41,7 +41,7 @@ func NewFaultResponder(logger log.Logger, txManagr txmgr.TxManager, fdgAddr comm
}
// buildFaultDefendData creates the transaction data for the Defend function.
func
(
r
*
f
aultResponder
)
buildFaultDefendData
(
parentContractIndex
int
,
pivot
[
32
]
byte
)
([]
byte
,
error
)
{
func
(
r
*
F
aultResponder
)
buildFaultDefendData
(
parentContractIndex
int
,
pivot
[
32
]
byte
)
([]
byte
,
error
)
{
return
r
.
fdgAbi
.
Pack
(
"defend"
,
big
.
NewInt
(
int64
(
parentContractIndex
)),
...
...
@@ -50,7 +50,7 @@ func (r *faultResponder) buildFaultDefendData(parentContractIndex int, pivot [32
}
// buildFaultAttackData creates the transaction data for the Attack function.
func
(
r
*
f
aultResponder
)
buildFaultAttackData
(
parentContractIndex
int
,
pivot
[
32
]
byte
)
([]
byte
,
error
)
{
func
(
r
*
F
aultResponder
)
buildFaultAttackData
(
parentContractIndex
int
,
pivot
[
32
]
byte
)
([]
byte
,
error
)
{
return
r
.
fdgAbi
.
Pack
(
"attack"
,
big
.
NewInt
(
int64
(
parentContractIndex
)),
...
...
@@ -59,30 +59,13 @@ func (r *faultResponder) buildFaultAttackData(parentContractIndex int, pivot [32
}
// buildResolveData creates the transaction data for the Resolve function.
func
(
r
*
f
aultResponder
)
buildResolveData
()
([]
byte
,
error
)
{
func
(
r
*
F
aultResponder
)
buildResolveData
()
([]
byte
,
error
)
{
return
r
.
fdgAbi
.
Pack
(
"resolve"
)
}
// BuildTx builds the transaction for the [faultResponder].
func
(
r
*
faultResponder
)
BuildTx
(
ctx
context
.
Context
,
response
types
.
Claim
)
([]
byte
,
error
)
{
if
response
.
DefendsParent
()
{
txData
,
err
:=
r
.
buildFaultDefendData
(
response
.
ParentContractIndex
,
response
.
ValueBytes
())
if
err
!=
nil
{
return
nil
,
err
}
return
txData
,
nil
}
else
{
txData
,
err
:=
r
.
buildFaultAttackData
(
response
.
ParentContractIndex
,
response
.
ValueBytes
())
if
err
!=
nil
{
return
nil
,
err
}
return
txData
,
nil
}
}
// CallResolve determines if the resolve function on the fault dispute game contract
// would succeed. Returns the game status if the call would succeed, errors otherwise.
func
(
r
*
f
aultResponder
)
CallResolve
(
ctx
context
.
Context
)
(
gameTypes
.
GameStatus
,
error
)
{
func
(
r
*
F
aultResponder
)
CallResolve
(
ctx
context
.
Context
)
(
gameTypes
.
GameStatus
,
error
)
{
txData
,
err
:=
r
.
buildResolveData
()
if
err
!=
nil
{
return
gameTypes
.
GameStatusInProgress
,
err
...
...
@@ -102,7 +85,7 @@ func (r *faultResponder) CallResolve(ctx context.Context) (gameTypes.GameStatus,
}
// Resolve executes a resolve transaction to resolve a fault dispute game.
func
(
r
*
f
aultResponder
)
Resolve
(
ctx
context
.
Context
)
error
{
func
(
r
*
F
aultResponder
)
Resolve
(
ctx
context
.
Context
)
error
{
txData
,
err
:=
r
.
buildResolveData
()
if
err
!=
nil
{
return
err
...
...
@@ -111,9 +94,19 @@ func (r *faultResponder) Resolve(ctx context.Context) error {
return
r
.
sendTxAndWait
(
ctx
,
txData
)
}
// Respond takes a [Claim] and executes the response action.
func
(
r
*
faultResponder
)
Respond
(
ctx
context
.
Context
,
response
types
.
Claim
)
error
{
txData
,
err
:=
r
.
BuildTx
(
ctx
,
response
)
func
(
r
*
FaultResponder
)
PerformAction
(
ctx
context
.
Context
,
action
solver
.
Action
)
error
{
var
txData
[]
byte
var
err
error
switch
action
.
Type
{
case
solver
.
ActionTypeMove
:
if
action
.
IsAttack
{
txData
,
err
=
r
.
buildFaultAttackData
(
action
.
ParentIdx
,
action
.
Value
)
}
else
{
txData
,
err
=
r
.
buildFaultDefendData
(
action
.
ParentIdx
,
action
.
Value
)
}
case
solver
.
ActionTypeStep
:
txData
,
err
=
r
.
buildStepTxData
(
uint64
(
action
.
ParentIdx
),
action
.
IsAttack
,
action
.
PreState
,
action
.
ProofData
)
}
if
err
!=
nil
{
return
err
}
...
...
@@ -122,7 +115,7 @@ func (r *faultResponder) Respond(ctx context.Context, response types.Claim) erro
// sendTxAndWait sends a transaction through the [txmgr] and waits for a receipt.
// This sets the tx GasLimit to 0, performing gas estimation online through the [txmgr].
func
(
r
*
f
aultResponder
)
sendTxAndWait
(
ctx
context
.
Context
,
txData
[]
byte
)
error
{
func
(
r
*
F
aultResponder
)
sendTxAndWait
(
ctx
context
.
Context
,
txData
[]
byte
)
error
{
receipt
,
err
:=
r
.
txMgr
.
Send
(
ctx
,
txmgr
.
TxCandidate
{
To
:
&
r
.
fdgAddr
,
TxData
:
txData
,
...
...
@@ -140,21 +133,12 @@ func (r *faultResponder) sendTxAndWait(ctx context.Context, txData []byte) error
}
// buildStepTxData creates the transaction data for the step function.
func
(
r
*
faultResponder
)
buildStepTxData
(
stepData
types
.
StepCallData
)
([]
byte
,
error
)
{
func
(
r
*
FaultResponder
)
buildStepTxData
(
claimIdx
uint64
,
isAttack
bool
,
stateData
[]
byte
,
proof
[]
byte
)
([]
byte
,
error
)
{
return
r
.
fdgAbi
.
Pack
(
"step"
,
big
.
NewInt
(
int64
(
stepData
.
ClaimInde
x
)),
stepData
.
I
sAttack
,
st
epData
.
St
ateData
,
stepData
.
P
roof
,
big
.
NewInt
(
int64
(
claimId
x
)),
i
sAttack
,
stateData
,
p
roof
,
)
}
// Step accepts step data and executes the step on the fault dispute game contract.
func
(
r
*
faultResponder
)
Step
(
ctx
context
.
Context
,
stepData
types
.
StepCallData
)
error
{
txData
,
err
:=
r
.
buildStepTxData
(
stepData
)
if
err
!=
nil
{
return
err
}
return
r
.
sendTxAndWait
(
ctx
,
txData
)
}
op-challenger/game/fault/responder/responder_test.go
View file @
971815e2
...
...
@@ -7,7 +7,7 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/
types
"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/
solver
"
gameTypes
"github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
...
...
@@ -74,73 +74,98 @@ func TestResolve(t *testing.T) {
}
// TestRespond tests the [Responder.Respond] method.
func
Test
Respond
(
t
*
testing
.
T
)
{
func
Test
PerformAction
(
t
*
testing
.
T
)
{
t
.
Run
(
"send fails"
,
func
(
t
*
testing
.
T
)
{
responder
,
mockTxMgr
:=
newTestFaultResponder
(
t
)
mockTxMgr
.
sendFails
=
true
err
:=
responder
.
Respond
(
context
.
Background
(),
generateMockResponseClaim
())
err
:=
responder
.
PerformAction
(
context
.
Background
(),
solver
.
Action
{
Type
:
solver
.
ActionTypeMove
,
ParentIdx
:
123
,
IsAttack
:
true
,
Value
:
common
.
Hash
{
0xaa
},
})
require
.
ErrorIs
(
t
,
err
,
mockSendError
)
require
.
Equal
(
t
,
0
,
mockTxMgr
.
sends
)
})
t
.
Run
(
"sends response"
,
func
(
t
*
testing
.
T
)
{
responder
,
mockTxMgr
:=
newTestFaultResponder
(
t
)
err
:=
responder
.
Respond
(
context
.
Background
(),
generateMockResponseClaim
())
err
:=
responder
.
PerformAction
(
context
.
Background
(),
solver
.
Action
{
Type
:
solver
.
ActionTypeMove
,
ParentIdx
:
123
,
IsAttack
:
true
,
Value
:
common
.
Hash
{
0xaa
},
})
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
1
,
mockTxMgr
.
sends
)
})
}
// TestBuildTx tests the [Responder.BuildTx] method.
func
TestBuildTx
(
t
*
testing
.
T
)
{
t
.
Run
(
"attack"
,
func
(
t
*
testing
.
T
)
{
responder
,
_
:=
newTestFaultResponder
(
t
)
responseClaim
:=
generateMockResponseClaim
()
responseClaim
.
ParentContractIndex
=
7
tx
,
err
:=
responder
.
BuildTx
(
context
.
Background
(),
responseClaim
)
responder
,
mockTxMgr
:=
newTestFaultResponder
(
t
)
action
:=
solver
.
Action
{
Type
:
solver
.
ActionTypeMove
,
ParentIdx
:
123
,
IsAttack
:
true
,
Value
:
common
.
Hash
{
0xaa
},
}
err
:=
responder
.
PerformAction
(
context
.
Background
(),
action
)
require
.
NoError
(
t
,
err
)
// Pack the tx data manually.
fdgAbi
,
err
:=
bindings
.
FaultDisputeGameMetaData
.
GetAbi
()
require
.
NoError
(
t
,
err
)
parent
:=
big
.
NewInt
(
int64
(
7
))
claim
:=
responseClaim
.
ValueBytes
()
expected
,
err
:=
fdgAbi
.
Pack
(
"attack"
,
parent
,
claim
)
expected
,
err
:=
fdgAbi
.
Pack
(
"attack"
,
big
.
NewInt
(
int64
(
action
.
ParentIdx
)),
action
.
Value
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expected
,
tx
)
require
.
Len
(
t
,
mockTxMgr
.
sent
,
1
)
require
.
Equal
(
t
,
expected
,
mockTxMgr
.
sent
[
0
]
.
TxData
)
})
t
.
Run
(
"defend"
,
func
(
t
*
testing
.
T
)
{
responder
,
_
:=
newTestFaultResponder
(
t
)
responseClaim
:=
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
common
.
Hash
{
0x01
},
Position
:
types
.
NewPositionFromGIndex
(
3
),
},
Parent
:
types
.
ClaimData
{
Value
:
common
.
Hash
{
0x02
},
Position
:
types
.
NewPositionFromGIndex
(
6
),
},
ContractIndex
:
0
,
ParentContractIndex
:
7
,
responder
,
mockTxMgr
:=
newTestFaultResponder
(
t
)
action
:=
solver
.
Action
{
Type
:
solver
.
ActionTypeMove
,
ParentIdx
:
123
,
IsAttack
:
false
,
Value
:
common
.
Hash
{
0xaa
},
}
tx
,
err
:=
responder
.
BuildTx
(
context
.
Background
(),
responseClaim
)
err
:=
responder
.
PerformAction
(
context
.
Background
(),
action
)
require
.
NoError
(
t
,
err
)
// Pack the tx data manually.
fdgAbi
,
err
:=
bindings
.
FaultDisputeGameMetaData
.
GetAbi
()
require
.
NoError
(
t
,
err
)
parent
:=
big
.
NewInt
(
int64
(
7
))
claim
:=
responseClaim
.
ValueBytes
()
expected
,
err
:=
fdgAbi
.
Pack
(
"defend"
,
parent
,
claim
)
expected
,
err
:=
fdgAbi
.
Pack
(
"defend"
,
big
.
NewInt
(
int64
(
action
.
ParentIdx
)),
action
.
Value
)
require
.
NoError
(
t
,
err
)
require
.
Len
(
t
,
mockTxMgr
.
sent
,
1
)
require
.
Equal
(
t
,
expected
,
mockTxMgr
.
sent
[
0
]
.
TxData
)
})
t
.
Run
(
"step"
,
func
(
t
*
testing
.
T
)
{
responder
,
mockTxMgr
:=
newTestFaultResponder
(
t
)
action
:=
solver
.
Action
{
Type
:
solver
.
ActionTypeStep
,
ParentIdx
:
123
,
IsAttack
:
true
,
PreState
:
[]
byte
{
1
,
2
,
3
},
ProofData
:
[]
byte
{
4
,
5
,
6
},
}
err
:=
responder
.
PerformAction
(
context
.
Background
(),
action
)
require
.
NoError
(
t
,
err
)
// Pack the tx data manually.
fdgAbi
,
err
:=
bindings
.
FaultDisputeGameMetaData
.
GetAbi
()
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expected
,
tx
)
expected
,
err
:=
fdgAbi
.
Pack
(
"step"
,
big
.
NewInt
(
int64
(
action
.
ParentIdx
)),
true
,
action
.
PreState
,
action
.
ProofData
)
require
.
NoError
(
t
,
err
)
require
.
Len
(
t
,
mockTxMgr
.
sent
,
1
)
require
.
Equal
(
t
,
expected
,
mockTxMgr
.
sent
[
0
]
.
TxData
)
})
}
func
newTestFaultResponder
(
t
*
testing
.
T
)
(
*
f
aultResponder
,
*
mockTxManager
)
{
func
newTestFaultResponder
(
t
*
testing
.
T
)
(
*
F
aultResponder
,
*
mockTxManager
)
{
log
:=
testlog
.
Logger
(
t
,
log
.
LvlError
)
mockTxMgr
:=
&
mockTxManager
{}
responder
,
err
:=
NewFaultResponder
(
log
,
mockTxMgr
,
mockFdgAddress
)
...
...
@@ -151,6 +176,7 @@ func newTestFaultResponder(t *testing.T) (*faultResponder, *mockTxManager) {
type
mockTxManager
struct
{
from
common
.
Address
sends
int
sent
[]
txmgr
.
TxCandidate
calls
int
sendFails
bool
callFails
bool
...
...
@@ -162,6 +188,7 @@ func (m *mockTxManager) Send(ctx context.Context, candidate txmgr.TxCandidate) (
return
nil
,
mockSendError
}
m
.
sends
++
m
.
sent
=
append
(
m
.
sent
,
candidate
)
return
ethtypes
.
NewReceipt
(
[]
byte
{},
false
,
...
...
@@ -189,18 +216,3 @@ func (m *mockTxManager) BlockNumber(ctx context.Context) (uint64, error) {
func
(
m
*
mockTxManager
)
From
()
common
.
Address
{
return
m
.
from
}
func
generateMockResponseClaim
()
types
.
Claim
{
return
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
common
.
Hash
{
0x01
},
Position
:
types
.
NewPositionFromGIndex
(
2
),
},
Parent
:
types
.
ClaimData
{
Value
:
common
.
Hash
{
0x02
},
Position
:
types
.
NewPositionFromGIndex
(
1
),
},
ContractIndex
:
0
,
ParentContractIndex
:
0
,
}
}
op-challenger/game/fault/solver/game_solver.go
0 → 100644
View file @
971815e2
package
solver
import
(
"context"
"errors"
"fmt"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum/go-ethereum/common"
)
type
ActionType
string
const
(
ActionTypeMove
ActionType
=
"move"
ActionTypeStep
ActionType
=
"step"
)
func
(
a
ActionType
)
String
()
string
{
return
string
(
a
)
}
type
Action
struct
{
Type
ActionType
ParentIdx
int
IsAttack
bool
// Moves
Value
common
.
Hash
// Steps
PreState
[]
byte
ProofData
[]
byte
OracleData
*
types
.
PreimageOracleData
}
type
GameSolver
struct
{
claimSolver
*
claimSolver
gameDepth
int
}
func
NewGameSolver
(
gameDepth
int
,
trace
types
.
TraceProvider
)
*
GameSolver
{
return
&
GameSolver
{
claimSolver
:
newClaimSolver
(
gameDepth
,
trace
),
gameDepth
:
gameDepth
,
}
}
func
(
s
*
GameSolver
)
CalculateNextActions
(
ctx
context
.
Context
,
game
types
.
Game
)
([]
Action
,
error
)
{
var
errs
[]
error
var
actions
[]
Action
for
_
,
claim
:=
range
game
.
Claims
()
{
var
action
*
Action
var
err
error
if
claim
.
Depth
()
==
s
.
gameDepth
{
action
,
err
=
s
.
calculateStep
(
ctx
,
game
,
claim
)
}
else
{
action
,
err
=
s
.
calculateMove
(
ctx
,
game
,
claim
)
}
if
err
!=
nil
{
errs
=
append
(
errs
,
err
)
continue
}
if
action
==
nil
{
continue
}
actions
=
append
(
actions
,
*
action
)
}
return
actions
,
errors
.
Join
(
errs
...
)
}
func
(
s
*
GameSolver
)
calculateStep
(
ctx
context
.
Context
,
game
types
.
Game
,
claim
types
.
Claim
)
(
*
Action
,
error
)
{
if
claim
.
Countered
{
return
nil
,
nil
}
if
game
.
AgreeWithClaimLevel
(
claim
)
{
return
nil
,
nil
}
step
,
err
:=
s
.
claimSolver
.
AttemptStep
(
ctx
,
claim
,
game
.
AgreeWithClaimLevel
(
claim
))
if
err
!=
nil
{
return
nil
,
err
}
return
&
Action
{
Type
:
ActionTypeStep
,
ParentIdx
:
step
.
LeafClaim
.
ContractIndex
,
IsAttack
:
step
.
IsAttack
,
PreState
:
step
.
PreState
,
ProofData
:
step
.
ProofData
,
OracleData
:
step
.
OracleData
,
},
nil
}
func
(
s
*
GameSolver
)
calculateMove
(
ctx
context
.
Context
,
game
types
.
Game
,
claim
types
.
Claim
)
(
*
Action
,
error
)
{
move
,
err
:=
s
.
claimSolver
.
NextMove
(
ctx
,
claim
,
game
.
AgreeWithClaimLevel
(
claim
))
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"failed to calculate next move for claim index %v: %w"
,
claim
.
ContractIndex
,
err
)
}
if
move
==
nil
||
game
.
IsDuplicate
(
*
move
)
{
return
nil
,
nil
}
return
&
Action
{
Type
:
ActionTypeMove
,
IsAttack
:
!
move
.
DefendsParent
(),
ParentIdx
:
move
.
ParentContractIndex
,
Value
:
move
.
Value
,
},
nil
}
op-challenger/game/fault/solver/game_solver_test.go
0 → 100644
View file @
971815e2
package
solver
import
(
"context"
"encoding/hex"
"testing"
faulttest
"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"
"github.com/stretchr/testify/require"
)
type
actionMaker
func
(
game
types
.
Game
)
Action
func
TestCalculateNextActions
(
t
*
testing
.
T
)
{
maxDepth
:=
4
claimBuilder
:=
faulttest
.
NewAlphabetClaimBuilder
(
t
,
maxDepth
)
attackClaim
:=
func
(
parentIdx
int
)
actionMaker
{
return
func
(
game
types
.
Game
)
Action
{
parentClaim
:=
game
.
Claims
()[
parentIdx
]
return
Action
{
Type
:
ActionTypeMove
,
ParentIdx
:
parentIdx
,
IsAttack
:
true
,
Value
:
claimBuilder
.
CorrectClaimAtPosition
(
parentClaim
.
Position
.
Attack
()),
}
}
}
defendClaim
:=
func
(
parentIdx
int
)
actionMaker
{
return
func
(
game
types
.
Game
)
Action
{
parentClaim
:=
game
.
Claims
()[
parentIdx
]
return
Action
{
Type
:
ActionTypeMove
,
ParentIdx
:
parentIdx
,
IsAttack
:
false
,
Value
:
claimBuilder
.
CorrectClaimAtPosition
(
parentClaim
.
Position
.
Defend
()),
}
}
}
stepAttack
:=
func
(
parentIdx
int
)
actionMaker
{
return
func
(
game
types
.
Game
)
Action
{
parentClaim
:=
game
.
Claims
()[
parentIdx
]
traceIdx
:=
parentClaim
.
Position
.
TraceIndex
(
maxDepth
)
return
Action
{
Type
:
ActionTypeStep
,
ParentIdx
:
parentIdx
,
IsAttack
:
true
,
PreState
:
claimBuilder
.
CorrectPreState
(
traceIdx
),
ProofData
:
claimBuilder
.
CorrectProofData
(
traceIdx
),
OracleData
:
claimBuilder
.
CorrectOracleData
(
traceIdx
),
}
}
}
stepDefend
:=
func
(
parentIdx
int
)
actionMaker
{
return
func
(
game
types
.
Game
)
Action
{
parentClaim
:=
game
.
Claims
()[
parentIdx
]
traceIdx
:=
parentClaim
.
Position
.
TraceIndex
(
maxDepth
)
+
1
return
Action
{
Type
:
ActionTypeStep
,
ParentIdx
:
parentIdx
,
IsAttack
:
false
,
PreState
:
claimBuilder
.
CorrectPreState
(
traceIdx
),
ProofData
:
claimBuilder
.
CorrectProofData
(
traceIdx
),
OracleData
:
claimBuilder
.
CorrectOracleData
(
traceIdx
),
}
}
}
tests
:=
[]
struct
{
name
string
agreeWithOutputRoot
bool
rootClaimCorrect
bool
setupGame
func
(
builder
*
faulttest
.
GameBuilder
)
expectedActions
[]
actionMaker
}{
{
name
:
"AttackRootClaim"
,
agreeWithOutputRoot
:
true
,
setupGame
:
func
(
builder
*
faulttest
.
GameBuilder
)
{},
expectedActions
:
[]
actionMaker
{
attackClaim
(
0
),
},
},
{
name
:
"DoNotAttackRootClaimWhenDisagreeWithOutputRoot"
,
agreeWithOutputRoot
:
false
,
setupGame
:
func
(
builder
*
faulttest
.
GameBuilder
)
{},
expectedActions
:
nil
,
},
{
// Note: The fault dispute game contract should prevent a correct root claim from actually being posted
// But for completeness, test we ignore it so we don't get sucked into playing an unwinnable game.
name
:
"DoNotAttackCorrectRootClaim_AgreeWithOutputRoot"
,
agreeWithOutputRoot
:
true
,
rootClaimCorrect
:
true
,
setupGame
:
func
(
builder
*
faulttest
.
GameBuilder
)
{},
expectedActions
:
nil
,
},
{
// Note: The fault dispute game contract should prevent a correct root claim from actually being posted
// But for completeness, test we ignore it so we don't get sucked into playing an unwinnable game.
name
:
"DoNotAttackCorrectRootClaim_DisagreeWithOutputRoot"
,
agreeWithOutputRoot
:
false
,
rootClaimCorrect
:
true
,
setupGame
:
func
(
builder
*
faulttest
.
GameBuilder
)
{},
expectedActions
:
nil
,
},
{
name
:
"DoNotPerformDuplicateMoves"
,
agreeWithOutputRoot
:
true
,
setupGame
:
func
(
builder
*
faulttest
.
GameBuilder
)
{
// Expected move has already been made.
builder
.
Seq
()
.
AttackCorrect
()
},
expectedActions
:
nil
,
},
{
name
:
"RespondToAllClaimsAtDisagreeingLevel"
,
agreeWithOutputRoot
:
true
,
setupGame
:
func
(
builder
*
faulttest
.
GameBuilder
)
{
honestClaim
:=
builder
.
Seq
()
.
AttackCorrect
()
// 1
honestClaim
.
AttackCorrect
()
// 2
honestClaim
.
DefendCorrect
()
// 3
honestClaim
.
Attack
(
common
.
Hash
{
0xaa
})
// 4
honestClaim
.
Attack
(
common
.
Hash
{
0xbb
})
// 5
honestClaim
.
Defend
(
common
.
Hash
{
0xcc
})
// 6
honestClaim
.
Defend
(
common
.
Hash
{
0xdd
})
// 7
},
expectedActions
:
[]
actionMaker
{
// Defend the correct claims
defendClaim
(
2
),
defendClaim
(
3
),
// Attack the incorrect claims
attackClaim
(
4
),
attackClaim
(
5
),
attackClaim
(
6
),
attackClaim
(
7
),
},
},
{
name
:
"StepAtMaxDepth"
,
agreeWithOutputRoot
:
true
,
setupGame
:
func
(
builder
*
faulttest
.
GameBuilder
)
{
lastHonestClaim
:=
builder
.
Seq
()
.
AttackCorrect
()
.
// 1 - Honest
AttackCorrect
()
.
// 2 - Dishonest
DefendCorrect
()
// 3 - Honest
lastHonestClaim
.
AttackCorrect
()
// 4 - Dishonest
lastHonestClaim
.
Attack
(
common
.
Hash
{
0xdd
})
// 5 - Dishonest
},
expectedActions
:
[]
actionMaker
{
stepDefend
(
4
),
stepAttack
(
5
),
},
},
}
for
_
,
test
:=
range
tests
{
test
:=
test
t
.
Run
(
test
.
name
,
func
(
t
*
testing
.
T
)
{
builder
:=
claimBuilder
.
GameBuilder
(
test
.
agreeWithOutputRoot
,
test
.
rootClaimCorrect
)
test
.
setupGame
(
builder
)
game
:=
builder
.
Game
for
i
,
claim
:=
range
game
.
Claims
()
{
t
.
Logf
(
"Claim %v: Pos: %v ParentIdx: %v, Countered: %v, Value: %v"
,
i
,
claim
.
Position
.
ToGIndex
(),
claim
.
ParentContractIndex
,
claim
.
Countered
,
claim
.
Value
)
}
solver
:=
NewGameSolver
(
maxDepth
,
claimBuilder
.
CorrectTraceProvider
())
actions
,
err
:=
solver
.
CalculateNextActions
(
context
.
Background
(),
game
)
require
.
NoError
(
t
,
err
)
for
i
,
action
:=
range
actions
{
t
.
Logf
(
"Move %v: Type: %v, ParentIdx: %v, Attack: %v, Value: %v, PreState: %v, ProofData: %v"
,
i
,
action
.
Type
,
action
.
ParentIdx
,
action
.
IsAttack
,
action
.
Value
,
hex
.
EncodeToString
(
action
.
PreState
),
hex
.
EncodeToString
(
action
.
ProofData
))
}
require
.
Len
(
t
,
actions
,
len
(
test
.
expectedActions
))
for
i
,
action
:=
range
test
.
expectedActions
{
require
.
Containsf
(
t
,
actions
,
action
(
game
),
"Expected claim %v missing"
,
i
)
}
})
}
}
op-challenger/game/fault/solver/solver.go
View file @
971815e2
...
...
@@ -15,22 +15,22 @@ var (
ErrStepAgreedClaim
=
errors
.
New
(
"cannot step on claims we agree with"
)
)
// Solver uses a [TraceProvider] to determine the moves to make in a dispute game.
type
Solver
struct
{
//
claim
Solver uses a [TraceProvider] to determine the moves to make in a dispute game.
type
claim
Solver
struct
{
trace
types
.
TraceProvider
gameDepth
int
}
//
NewSolver creates a new [
Solver] using the provided [TraceProvider].
func
NewSolver
(
gameDepth
int
,
traceProvider
types
.
TraceProvider
)
*
Solver
{
return
&
Solver
{
//
newClaimSolver creates a new [claim
Solver] using the provided [TraceProvider].
func
newClaimSolver
(
gameDepth
int
,
traceProvider
types
.
TraceProvider
)
*
claim
Solver
{
return
&
claim
Solver
{
traceProvider
,
gameDepth
,
}
}
// NextMove returns the next move to make given the current state of the game.
func
(
s
*
Solver
)
NextMove
(
ctx
context
.
Context
,
claim
types
.
Claim
,
agreeWithClaimLevel
bool
)
(
*
types
.
Claim
,
error
)
{
func
(
s
*
claim
Solver
)
NextMove
(
ctx
context
.
Context
,
claim
types
.
Claim
,
agreeWithClaimLevel
bool
)
(
*
types
.
Claim
,
error
)
{
if
agreeWithClaimLevel
{
return
nil
,
nil
}
...
...
@@ -58,7 +58,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
(
ctx
context
.
Context
,
claim
types
.
Claim
,
agreeWithClaimLevel
bool
)
(
StepData
,
error
)
{
func
(
s
*
claim
Solver
)
AttemptStep
(
ctx
context
.
Context
,
claim
types
.
Claim
,
agreeWithClaimLevel
bool
)
(
StepData
,
error
)
{
if
claim
.
Depth
()
!=
s
.
gameDepth
{
return
StepData
{},
ErrStepNonLeafNode
}
...
...
@@ -100,7 +100,7 @@ func (s *Solver) AttemptStep(ctx context.Context, claim types.Claim, agreeWithCl
}
// attack returns a response that attacks the claim.
func
(
s
*
Solver
)
attack
(
ctx
context
.
Context
,
claim
types
.
Claim
)
(
*
types
.
Claim
,
error
)
{
func
(
s
*
claim
Solver
)
attack
(
ctx
context
.
Context
,
claim
types
.
Claim
)
(
*
types
.
Claim
,
error
)
{
position
:=
claim
.
Attack
()
value
,
err
:=
s
.
traceAtPosition
(
ctx
,
position
)
if
err
!=
nil
{
...
...
@@ -114,7 +114,7 @@ func (s *Solver) attack(ctx context.Context, claim types.Claim) (*types.Claim, e
}
// defend returns a response that defends the claim.
func
(
s
*
Solver
)
defend
(
ctx
context
.
Context
,
claim
types
.
Claim
)
(
*
types
.
Claim
,
error
)
{
func
(
s
*
claim
Solver
)
defend
(
ctx
context
.
Context
,
claim
types
.
Claim
)
(
*
types
.
Claim
,
error
)
{
if
claim
.
IsRoot
()
{
return
nil
,
nil
}
...
...
@@ -131,13 +131,13 @@ func (s *Solver) defend(ctx context.Context, claim types.Claim) (*types.Claim, e
}
// agreeWithClaim returns true if the claim is correct according to the internal [TraceProvider].
func
(
s
*
Solver
)
agreeWithClaim
(
ctx
context
.
Context
,
claim
types
.
ClaimData
)
(
bool
,
error
)
{
func
(
s
*
claim
Solver
)
agreeWithClaim
(
ctx
context
.
Context
,
claim
types
.
ClaimData
)
(
bool
,
error
)
{
ourValue
,
err
:=
s
.
traceAtPosition
(
ctx
,
claim
.
Position
)
return
bytes
.
Equal
(
ourValue
[
:
],
claim
.
Value
[
:
]),
err
}
// traceAtPosition returns the [common.Hash] from internal [TraceProvider] at the given [Position].
func
(
s
*
Solver
)
traceAtPosition
(
ctx
context
.
Context
,
p
types
.
Position
)
(
common
.
Hash
,
error
)
{
func
(
s
*
claim
Solver
)
traceAtPosition
(
ctx
context
.
Context
,
p
types
.
Position
)
(
common
.
Hash
,
error
)
{
index
:=
p
.
TraceIndex
(
s
.
gameDepth
)
hash
,
err
:=
s
.
trace
.
Get
(
ctx
,
index
)
return
hash
,
err
...
...
op-challenger/game/fault/solver/solver_test.go
View file @
971815e2
package
solver
_test
package
solver
import
(
"context"
"errors"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/solver"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/test"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/stretchr/testify/require"
...
...
@@ -84,7 +83,7 @@ func TestNextMove(t *testing.T) {
for
_
,
test
:=
range
tests
{
test
:=
test
t
.
Run
(
test
.
name
,
func
(
t
*
testing
.
T
)
{
solver
:=
solver
.
New
Solver
(
maxDepth
,
builder
.
CorrectTraceProvider
())
solver
:=
newClaim
Solver
(
maxDepth
,
builder
.
CorrectTraceProvider
())
move
,
err
:=
solver
.
NextMove
(
context
.
Background
(),
test
.
claim
,
test
.
agreeWithLevel
)
if
test
.
expectedErr
==
nil
{
require
.
NoError
(
t
,
err
)
...
...
@@ -174,19 +173,19 @@ func TestAttemptStep(t *testing.T) {
{
name
:
"CannotStepNonLeaf"
,
claim
:
builder
.
Seq
(
false
)
.
Attack
(
false
)
.
Get
(),
expectedErr
:
solver
.
ErrStepNonLeafNode
,
expectedErr
:
ErrStepNonLeafNode
,
},
{
name
:
"CannotStepAgreedNode"
,
claim
:
builder
.
Seq
(
false
)
.
Attack
(
false
)
.
Get
(),
agreeWithLevel
:
true
,
expectedErr
:
solver
.
ErrStepNonLeafNode
,
expectedErr
:
ErrStepNonLeafNode
,
},
{
name
:
"CannotStepAgreedNode"
,
claim
:
builder
.
Seq
(
false
)
.
Attack
(
false
)
.
Get
(),
agreeWithLevel
:
true
,
expectedErr
:
solver
.
ErrStepNonLeafNode
,
expectedErr
:
ErrStepNonLeafNode
,
},
}
...
...
@@ -198,7 +197,7 @@ func TestAttemptStep(t *testing.T) {
alphabetProvider
=
test
.
NewAlphabetWithProofProvider
(
t
,
maxDepth
,
errProvider
)
}
builder
=
test
.
NewClaimBuilder
(
t
,
maxDepth
,
alphabetProvider
)
alphabetSolver
:=
solver
.
New
Solver
(
maxDepth
,
builder
.
CorrectTraceProvider
())
alphabetSolver
:=
newClaim
Solver
(
maxDepth
,
builder
.
CorrectTraceProvider
())
step
,
err
:=
alphabetSolver
.
AttemptStep
(
ctx
,
tableTest
.
claim
,
tableTest
.
agreeWithLevel
)
if
tableTest
.
expectedErr
==
nil
{
require
.
NoError
(
t
,
err
)
...
...
@@ -212,7 +211,7 @@ func TestAttemptStep(t *testing.T) {
require
.
Equal
(
t
,
tableTest
.
expectedOracleData
.
OracleOffset
,
step
.
OracleData
.
OracleOffset
)
}
else
{
require
.
ErrorIs
(
t
,
err
,
tableTest
.
expectedErr
)
require
.
Equal
(
t
,
solver
.
StepData
{},
step
)
require
.
Equal
(
t
,
StepData
{},
step
)
}
})
}
...
...
op-challenger/game/fault/test/claim_builder.go
View file @
971815e2
...
...
@@ -38,6 +38,13 @@ func (c *ClaimBuilder) CorrectClaim(idx uint64) common.Hash {
return
value
}
// CorrectClaimAtPosition returns the canonical claim at a specified position
func
(
c
*
ClaimBuilder
)
CorrectClaimAtPosition
(
pos
types
.
Position
)
common
.
Hash
{
value
,
err
:=
c
.
correct
.
Get
(
context
.
Background
(),
pos
.
TraceIndex
(
c
.
maxDepth
))
c
.
require
.
NoError
(
err
)
return
value
}
// CorrectPreState returns the pre-state (not hashed) required to execute the valid step at the specified trace index
func
(
c
*
ClaimBuilder
)
CorrectPreState
(
idx
uint64
)
[]
byte
{
preimage
,
_
,
_
,
err
:=
c
.
correct
.
GetStepData
(
context
.
Background
(),
idx
)
...
...
@@ -102,7 +109,20 @@ func (c *ClaimBuilder) AttackClaim(claim types.Claim, correct bool) types.Claim
Value
:
c
.
claim
(
pos
.
TraceIndex
(
c
.
maxDepth
),
correct
),
Position
:
pos
,
},
Parent
:
claim
.
ClaimData
,
Parent
:
claim
.
ClaimData
,
ParentContractIndex
:
claim
.
ContractIndex
,
}
}
func
(
c
*
ClaimBuilder
)
AttackClaimWithValue
(
claim
types
.
Claim
,
value
common
.
Hash
)
types
.
Claim
{
pos
:=
claim
.
Position
.
Attack
()
return
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
value
,
Position
:
pos
,
},
Parent
:
claim
.
ClaimData
,
ParentContractIndex
:
claim
.
ContractIndex
,
}
}
...
...
@@ -113,6 +133,19 @@ func (c *ClaimBuilder) DefendClaim(claim types.Claim, correct bool) types.Claim
Value
:
c
.
claim
(
pos
.
TraceIndex
(
c
.
maxDepth
),
correct
),
Position
:
pos
,
},
Parent
:
claim
.
ClaimData
,
Parent
:
claim
.
ClaimData
,
ParentContractIndex
:
claim
.
ContractIndex
,
}
}
func
(
c
*
ClaimBuilder
)
DefendClaimWithValue
(
claim
types
.
Claim
,
value
common
.
Hash
)
types
.
Claim
{
pos
:=
claim
.
Position
.
Defend
()
return
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Value
:
value
,
Position
:
pos
,
},
Parent
:
claim
.
ClaimData
,
ParentContractIndex
:
claim
.
ContractIndex
,
}
}
op-challenger/game/fault/test/game_builder.go
0 → 100644
View file @
971815e2
package
test
import
(
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum/go-ethereum/common"
)
type
GameBuilder
struct
{
builder
*
ClaimBuilder
Game
types
.
Game
}
func
(
c
*
ClaimBuilder
)
GameBuilder
(
agreeWithOutputRoot
bool
,
rootCorrect
bool
)
*
GameBuilder
{
return
&
GameBuilder
{
builder
:
c
,
Game
:
types
.
NewGameState
(
agreeWithOutputRoot
,
c
.
CreateRootClaim
(
rootCorrect
),
uint64
(
c
.
maxDepth
)),
}
}
type
GameBuilderSeq
struct
{
builder
*
ClaimBuilder
lastClaim
types
.
Claim
game
types
.
Game
}
func
(
g
*
GameBuilder
)
Seq
()
*
GameBuilderSeq
{
return
&
GameBuilderSeq
{
builder
:
g
.
builder
,
game
:
g
.
Game
,
lastClaim
:
g
.
Game
.
Claims
()[
0
],
}
}
func
(
s
*
GameBuilderSeq
)
AttackCorrect
()
*
GameBuilderSeq
{
claim
:=
s
.
builder
.
AttackClaim
(
s
.
lastClaim
,
true
)
claim
.
ContractIndex
=
len
(
s
.
game
.
Claims
())
s
.
builder
.
require
.
NoError
(
s
.
game
.
Put
(
claim
))
return
&
GameBuilderSeq
{
builder
:
s
.
builder
,
game
:
s
.
game
,
lastClaim
:
claim
,
}
}
func
(
s
*
GameBuilderSeq
)
Attack
(
value
common
.
Hash
)
*
GameBuilderSeq
{
claim
:=
s
.
builder
.
AttackClaimWithValue
(
s
.
lastClaim
,
value
)
claim
.
ContractIndex
=
len
(
s
.
game
.
Claims
())
s
.
builder
.
require
.
NoError
(
s
.
game
.
Put
(
claim
))
return
&
GameBuilderSeq
{
builder
:
s
.
builder
,
game
:
s
.
game
,
lastClaim
:
claim
,
}
}
func
(
s
*
GameBuilderSeq
)
DefendCorrect
()
*
GameBuilderSeq
{
claim
:=
s
.
builder
.
DefendClaim
(
s
.
lastClaim
,
true
)
claim
.
ContractIndex
=
len
(
s
.
game
.
Claims
())
s
.
builder
.
require
.
NoError
(
s
.
game
.
Put
(
claim
))
return
&
GameBuilderSeq
{
builder
:
s
.
builder
,
game
:
s
.
game
,
lastClaim
:
claim
,
}
}
func
(
s
*
GameBuilderSeq
)
Defend
(
value
common
.
Hash
)
*
GameBuilderSeq
{
claim
:=
s
.
builder
.
DefendClaimWithValue
(
s
.
lastClaim
,
value
)
claim
.
ContractIndex
=
len
(
s
.
game
.
Claims
())
s
.
builder
.
require
.
NoError
(
s
.
game
.
Put
(
claim
))
return
&
GameBuilderSeq
{
builder
:
s
.
builder
,
game
:
s
.
game
,
lastClaim
:
claim
,
}
}
op-challenger/scripts/alphabet/init_game.sh
View file @
971815e2
...
...
@@ -62,5 +62,7 @@ done
# Root claim commits to the entire trace.
# Alphabet game claim construction: keccak256(abi.encode(trace_index, trace[trace_index]))
ROOT_CLAIM
=
$(
cast keccak
$(
cast abi-encode
"f(uint256,uint256)"
15 122
))
# Replace the first byte of the claim with the invalid vm status indicator
ROOT_CLAIM
=
"0x01
${
ROOT_CLAIM
:4:60
}
"
GAME_TYPE
=
255
${
SOURCE_DIR
}
/../create_game.sh http://localhost:8545
"
${
DISPUTE_GAME_FACTORY
}
"
"
${
ROOT_CLAIM
}
"
--private-key
"
${
DEVNET_SPONSOR
}
"
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