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
8d8597a2
Unverified
Commit
8d8597a2
authored
Sep 07, 2023
by
OptimismBot
Committed by
GitHub
Sep 07, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #7135 from ethereum-optimism/aj/e2e-duplication
op-e2e: Remove duplicate logic for playing through a game
parents
28a6c6cc
0b828f3d
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
130 additions
and
89 deletions
+130
-89
game_helper.go
op-e2e/e2eutils/disputegame/game_helper.go
+53
-0
faultproof_test.go
op-e2e/faultproof_test.go
+77
-89
No files found.
op-e2e/e2eutils/disputegame/game_helper.go
View file @
8d8597a2
...
...
@@ -142,6 +142,59 @@ func (g *FaultGameHelper) WaitForGameStatus(ctx context.Context, expected Status
g
.
require
.
NoErrorf
(
err
,
"wait for game status. Game state:
\n
%v"
,
g
.
gameData
(
ctx
))
}
// Mover is a function that either attacks or defends the claim at parentClaimIdx
type
Mover
func
(
parentClaimIdx
int64
)
// Stepper is a function that attempts to perform a step against the claim at parentClaimIdx
type
Stepper
func
(
parentClaimIdx
int64
)
// DefendRootClaim uses the supplied Mover to perform moves in an attempt to defend the root claim.
// It is assumed that the output root being disputed is valid and that an honest op-challenger is already running.
// When the game has reached the maximum depth it waits for the honest challenger to counter the leaf claim with step.
func
(
g
*
FaultGameHelper
)
DefendRootClaim
(
ctx
context
.
Context
,
performMove
Mover
)
{
maxDepth
:=
g
.
MaxDepth
(
ctx
)
for
claimCount
:=
int64
(
1
);
claimCount
<
maxDepth
;
{
g
.
LogGameData
(
ctx
)
claimCount
++
// Wait for the challenger to counter
g
.
WaitForClaimCount
(
ctx
,
claimCount
)
// Respond with our own move
performMove
(
claimCount
-
1
)
claimCount
++
g
.
WaitForClaimCount
(
ctx
,
claimCount
)
}
// Wait for the challenger to call step and counter our invalid claim
g
.
WaitForClaimAtMaxDepth
(
ctx
,
true
)
}
// ChallengeRootClaim uses the supplied Mover and Stepper to perform moves and steps in an attempt to challenge the root claim.
// It is assumed that the output root being disputed is invalid and that an honest op-challenger is already running.
// When the game has reached the maximum depth it calls the Stepper to attempt to counter the leaf claim.
// Since the output root is invalid, it should not be possible for the Stepper to call step successfully.
func
(
g
*
FaultGameHelper
)
ChallengeRootClaim
(
ctx
context
.
Context
,
performMove
Mover
,
attemptStep
Stepper
)
{
maxDepth
:=
g
.
MaxDepth
(
ctx
)
for
claimCount
:=
int64
(
1
);
claimCount
<
maxDepth
;
{
g
.
LogGameData
(
ctx
)
// Perform our move
performMove
(
claimCount
-
1
)
claimCount
++
g
.
WaitForClaimCount
(
ctx
,
claimCount
)
// Wait for the challenger to counter
claimCount
++
g
.
WaitForClaimCount
(
ctx
,
claimCount
)
}
// Confirm the game has reached max depth and the last claim hasn't been countered
g
.
WaitForClaimAtMaxDepth
(
ctx
,
false
)
g
.
LogGameData
(
ctx
)
// It's on us to call step if we want to win but shouldn't be possible
attemptStep
(
maxDepth
)
}
func
(
g
*
FaultGameHelper
)
Attack
(
ctx
context
.
Context
,
claimIdx
int64
,
claim
common
.
Hash
)
{
tx
,
err
:=
g
.
game
.
Attack
(
g
.
opts
,
big
.
NewInt
(
claimIdx
),
claim
)
g
.
require
.
NoError
(
err
,
"Attack transaction did not send"
)
...
...
op-e2e/faultproof_test.go
View file @
8d8597a2
...
...
@@ -244,8 +244,8 @@ func TestCannonDisputeGame(t *testing.T) {
InitParallel
(
t
)
tests
:=
[]
struct
{
name
string
defend
AtClaim
int64
name
string
defend
ClaimCount
int64
}{
{
"StepFirst"
,
0
},
{
"StepMiddle"
,
28
},
...
...
@@ -271,27 +271,15 @@ func TestCannonDisputeGame(t *testing.T) {
challenger
.
WithPrivKey
(
sys
.
cfg
.
Secrets
.
Alice
),
)
maxDepth
:=
game
.
MaxDepth
(
ctx
)
for
claimCount
:=
int64
(
1
);
claimCount
<
maxDepth
;
{
game
.
LogGameData
(
ctx
)
claimCount
++
// Wait for the challenger to counter
game
.
WaitForClaimCount
(
ctx
,
claimCount
)
// Post our own counter to the latest challenger claim
if
claimCount
==
test
.
defendAtClaim
{
// Defend one claim so we don't wind up executing from the absolute pre-state
game
.
Defend
(
ctx
,
claimCount
-
1
,
common
.
Hash
{
byte
(
claimCount
)})
}
else
{
game
.
Attack
(
ctx
,
claimCount
-
1
,
common
.
Hash
{
byte
(
claimCount
)})
}
claimCount
++
game
.
WaitForClaimCount
(
ctx
,
claimCount
)
}
game
.
LogGameData
(
ctx
)
// Wait for the challenger to call step and counter our invalid claim
game
.
WaitForClaimAtMaxDepth
(
ctx
,
true
)
game
.
DefendRootClaim
(
ctx
,
func
(
parentClaimIdx
int64
)
{
if
parentClaimIdx
+
1
==
test
.
defendClaimCount
{
game
.
Defend
(
ctx
,
parentClaimIdx
,
common
.
Hash
{
byte
(
parentClaimIdx
)})
}
else
{
game
.
Attack
(
ctx
,
parentClaimIdx
,
common
.
Hash
{
byte
(
parentClaimIdx
)})
}
})
sys
.
TimeTravelClock
.
AdvanceTime
(
game
.
GameDuration
(
ctx
))
require
.
NoError
(
t
,
wait
.
ForNextBlock
(
ctx
,
l1Client
))
...
...
@@ -326,28 +314,15 @@ func TestCannonDefendStep(t *testing.T) {
challenger
.
WithPrivKey
(
sys
.
cfg
.
Secrets
.
Mallory
),
)
maxDepth
:=
game
.
MaxDepth
(
ctx
)
for
claimCount
:=
int64
(
1
);
claimCount
<
maxDepth
;
{
game
.
LogGameData
(
ctx
)
claimCount
++
// Wait for the challenger to counter
game
.
WaitForClaimCount
(
ctx
,
claimCount
)
game
.
DefendRootClaim
(
ctx
,
func
(
parentClaimIdx
int64
)
{
// Post invalid claims for most steps to get down into the early part of the trace
if
claimCount
<
28
{
game
.
Attack
(
ctx
,
claimCount
-
1
,
common
.
Hash
{
byte
(
claimCount
)})
if
parentClaimIdx
<
27
{
game
.
Attack
(
ctx
,
parentClaimIdx
,
common
.
Hash
{
byte
(
parentClaimIdx
)})
}
else
{
// Post our own counter but using the correct hash in low levels to force a defense step
correctTrace
.
Attack
(
ctx
,
claimCount
-
1
)
correctTrace
.
Attack
(
ctx
,
parentClaimIdx
)
}
claimCount
++
game
.
LogGameData
(
ctx
)
game
.
WaitForClaimCount
(
ctx
,
claimCount
)
}
game
.
LogGameData
(
ctx
)
// Wait for the challenger to call step and counter our invalid claim
game
.
WaitForClaimAtMaxDepth
(
ctx
,
true
)
})
sys
.
TimeTravelClock
.
AdvanceTime
(
game
.
GameDuration
(
ctx
))
require
.
NoError
(
t
,
wait
.
ForNextBlock
(
ctx
,
l1Client
))
...
...
@@ -358,43 +333,69 @@ func TestCannonDefendStep(t *testing.T) {
func
TestCannonProposedOutputRootInvalid
(
t
*
testing
.
T
)
{
InitParallel
(
t
)
honestStepsFail
:=
func
(
ctx
context
.
Context
,
correctTrace
*
disputegame
.
HonestHelper
,
parentClaimIdx
int64
)
{
// Attack step should fail
correctTrace
.
StepFails
(
ctx
,
parentClaimIdx
,
true
)
// Defending should fail too
correctTrace
.
StepFails
(
ctx
,
parentClaimIdx
,
false
)
}
tests
:=
[]
struct
{
name
string
outputRoot
common
.
Hash
performMove
func
(
ctx
context
.
Context
,
correctTrace
*
disputegame
.
HonestHelper
,
parentClaimIdx
int64
)
performStep
func
(
ctx
context
.
Context
,
correctTrace
*
disputegame
.
HonestHelper
,
parentClaimIdx
int64
)
}{
{
name
:
"AttackWithCorrectTrace"
,
outputRoot
:
common
.
Hash
{
0xab
},
performMove
:
func
(
ctx
context
.
Context
,
correctTrace
*
disputegame
.
HonestHelper
,
parentClaimIdx
int64
)
{
// Attack everything but oddly using the correct hash.
correctTrace
.
Attack
(
ctx
,
parentClaimIdx
)
},
performStep
:
honestStepsFail
,
},
{
name
:
"DefendWithCorrectTrace"
,
outputRoot
:
common
.
Hash
{
0xab
},
performMove
:
func
(
ctx
context
.
Context
,
correctTrace
*
disputegame
.
HonestHelper
,
parentClaimIdx
int64
)
{
// Can only attack the root claim
if
parentClaimIdx
==
0
{
correctTrace
.
Attack
(
ctx
,
parentClaimIdx
)
return
}
// Otherwise, defend everything using the correct hash.
correctTrace
.
Defend
(
ctx
,
parentClaimIdx
)
},
performStep
:
honestStepsFail
,
},
}
ctx
:=
context
.
Background
()
sys
,
l1Client
,
game
,
correctTrace
:=
setupDisputeGameForInvalidOutputRoot
(
t
,
common
.
Hash
{
0x01
,
0xab
})
t
.
Cleanup
(
sys
.
Close
)
for
_
,
test
:=
range
tests
{
test
:=
test
t
.
Run
(
test
.
name
,
func
(
t
*
testing
.
T
)
{
InitParallel
(
t
)
maxDepth
:=
game
.
MaxDepth
(
ctx
)
ctx
:=
context
.
Background
()
sys
,
l1Client
,
game
,
correctTrace
:=
setupDisputeGameForInvalidOutputRoot
(
t
,
common
.
Hash
{
0xab
})
t
.
Cleanup
(
sys
.
Close
)
// Now maliciously play the game and it should be impossible to win
// Now maliciously play the game and it should be impossible to win
game
.
ChallengeRootClaim
(
ctx
,
func
(
parentClaimIdx
int64
)
{
test
.
performMove
(
ctx
,
correctTrace
,
parentClaimIdx
)
},
func
(
parentClaimIdx
int64
)
{
test
.
performStep
(
ctx
,
correctTrace
,
parentClaimIdx
)
})
for
claimCount
:=
int64
(
1
);
claimCount
<
maxDepth
;
{
// Attack everything but oddly using the correct hash.
correctTrace
.
Attack
(
ctx
,
claimCount
-
1
)
claimCount
++
game
.
LogGameData
(
ctx
)
game
.
WaitForClaimCount
(
ctx
,
claimCount
)
// Time travel past when the game will be resolvable.
sys
.
TimeTravelClock
.
AdvanceTime
(
game
.
GameDuration
(
ctx
))
require
.
NoError
(
t
,
wait
.
ForNextBlock
(
ctx
,
l1Client
))
game
.
LogGameData
(
ctx
)
// Wait for the challenger to counter
claimCount
++
game
.
WaitForClaimCount
(
ctx
,
claimCount
)
game
.
WaitForGameStatus
(
ctx
,
disputegame
.
StatusDefenderWins
)
game
.
LogGameData
(
ctx
)
})
}
game
.
LogGameData
(
ctx
)
// Wait for the challenger to call step and counter our invalid claim
game
.
WaitForClaimAtMaxDepth
(
ctx
,
false
)
// It's on us to call step if we want to win but shouldn't be possible
correctTrace
.
StepFails
(
ctx
,
maxDepth
,
true
)
// Defending should fail too
correctTrace
.
StepFails
(
ctx
,
maxDepth
,
false
)
// Time travel past when the game will be resolvable.
sys
.
TimeTravelClock
.
AdvanceTime
(
game
.
GameDuration
(
ctx
))
require
.
NoError
(
t
,
wait
.
ForNextBlock
(
ctx
,
l1Client
))
game
.
WaitForGameStatus
(
ctx
,
disputegame
.
StatusDefenderWins
)
game
.
LogGameData
(
ctx
)
}
// setupDisputeGameForInvalidOutputRoot sets up an L2 chain with at least one valid output root followed by an invalid output root.
...
...
@@ -413,7 +414,7 @@ func setupDisputeGameForInvalidOutputRoot(t *testing.T, outputRoot common.Hash)
sys
.
L2OutputSubmitter
.
Stop
()
sys
.
L2OutputSubmitter
=
nil
// Submit an invalid output roo
o
t
// Submit an invalid output root
l2oo
.
PublishNextOutput
(
ctx
,
outputRoot
)
l1Endpoint
:=
sys
.
NodeEndpoint
(
"l1"
)
...
...
@@ -458,23 +459,10 @@ func TestCannonChallengeWithCorrectRoot(t *testing.T) {
challenger
.
WithPrivKey
(
sys
.
cfg
.
Secrets
.
Alice
),
)
maxDepth
:=
game
.
MaxDepth
(
ctx
)
for
claimCount
:=
int64
(
1
);
claimCount
<
maxDepth
;
{
game
.
LogGameData
(
ctx
)
claimCount
++
// Wait for the challenger to counter
game
.
WaitForClaimCount
(
ctx
,
claimCount
)
game
.
DefendRootClaim
(
ctx
,
func
(
parentClaimIdx
int64
)
{
// Defend everything because we have the same trace as the honest proposer
correctTrace
.
Defend
(
ctx
,
claimCount
-
1
)
claimCount
++
game
.
LogGameData
(
ctx
)
game
.
WaitForClaimCount
(
ctx
,
claimCount
)
}
game
.
LogGameData
(
ctx
)
// Wait for the challenger to call step and counter our invalid claim
game
.
WaitForClaimAtMaxDepth
(
ctx
,
true
)
correctTrace
.
Defend
(
ctx
,
parentClaimIdx
)
})
sys
.
TimeTravelClock
.
AdvanceTime
(
game
.
GameDuration
(
ctx
))
require
.
NoError
(
t
,
wait
.
ForNextBlock
(
ctx
,
l1Client
))
...
...
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