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
150f704d
Unverified
Commit
150f704d
authored
Dec 13, 2023
by
Adrian Sutton
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
op-e2e: Add output_cannon e2e test for disputing a valid output root.
parent
f8de1ed1
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
119 additions
and
8 deletions
+119
-8
helper.go
op-e2e/e2eutils/disputegame/helper.go
+14
-3
output_game_helper.go
op-e2e/e2eutils/disputegame/output_game_helper.go
+9
-4
output_honest_helper.go
op-e2e/e2eutils/disputegame/output_honest_helper.go
+1
-1
output_cannon_test.go
op-e2e/faultproofs/output_cannon_test.go
+95
-0
No files found.
op-e2e/e2eutils/disputegame/helper.go
View file @
150f704d
...
@@ -157,6 +157,13 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s
...
@@ -157,6 +157,13 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s
}
}
}
}
func
(
h
*
FactoryHelper
)
StartOutputCannonGameWithCorrectRoot
(
ctx
context
.
Context
,
l2Node
string
,
l2BlockNumber
uint64
)
*
OutputCannonGameHelper
{
h
.
waitForBlockToBeSafe
(
l2Node
,
l2BlockNumber
)
output
,
err
:=
h
.
system
.
RollupClient
(
l2Node
)
.
OutputAtBlock
(
ctx
,
l2BlockNumber
)
h
.
require
.
NoErrorf
(
err
,
"Failed to get output at block %v"
,
l2BlockNumber
)
return
h
.
StartOutputCannonGame
(
ctx
,
l2Node
,
l2BlockNumber
,
common
.
Hash
(
output
.
OutputRoot
))
}
func
(
h
*
FactoryHelper
)
StartOutputCannonGame
(
ctx
context
.
Context
,
l2Node
string
,
l2BlockNumber
uint64
,
rootClaim
common
.
Hash
)
*
OutputCannonGameHelper
{
func
(
h
*
FactoryHelper
)
StartOutputCannonGame
(
ctx
context
.
Context
,
l2Node
string
,
l2BlockNumber
uint64
,
rootClaim
common
.
Hash
)
*
OutputCannonGameHelper
{
logger
:=
testlog
.
Logger
(
h
.
t
,
log
.
LvlInfo
)
.
New
(
"role"
,
"OutputCannonGameHelper"
)
logger
:=
testlog
.
Logger
(
h
.
t
,
log
.
LvlInfo
)
.
New
(
"role"
,
"OutputCannonGameHelper"
)
rollupClient
:=
h
.
system
.
RollupClient
(
l2Node
)
rollupClient
:=
h
.
system
.
RollupClient
(
l2Node
)
...
@@ -353,15 +360,19 @@ func (h *FactoryHelper) createCannonGame(ctx context.Context, rootClaim common.H
...
@@ -353,15 +360,19 @@ func (h *FactoryHelper) createCannonGame(ctx context.Context, rootClaim common.H
}
}
func
(
h
*
FactoryHelper
)
createBisectionGameExtraData
(
l2Node
string
,
l2BlockNumber
uint64
)
[]
byte
{
func
(
h
*
FactoryHelper
)
createBisectionGameExtraData
(
l2Node
string
,
l2BlockNumber
uint64
)
[]
byte
{
l2Client
:=
h
.
system
.
NodeClient
(
l2Node
)
h
.
waitForBlockToBeSafe
(
l2Node
,
l2BlockNumber
)
_
,
err
:=
geth
.
WaitForBlockToBeSafe
(
new
(
big
.
Int
)
.
SetUint64
(
l2BlockNumber
),
l2Client
,
1
*
time
.
Minute
)
h
.
require
.
NoErrorf
(
err
,
"Block number %v did not become safe"
,
l2BlockNumber
)
h
.
t
.
Logf
(
"Creating game with l2 block number: %v"
,
l2BlockNumber
)
h
.
t
.
Logf
(
"Creating game with l2 block number: %v"
,
l2BlockNumber
)
extraData
:=
make
([]
byte
,
32
)
extraData
:=
make
([]
byte
,
32
)
binary
.
BigEndian
.
PutUint64
(
extraData
[
24
:
],
l2BlockNumber
)
binary
.
BigEndian
.
PutUint64
(
extraData
[
24
:
],
l2BlockNumber
)
return
extraData
return
extraData
}
}
func
(
h
*
FactoryHelper
)
waitForBlockToBeSafe
(
l2Node
string
,
l2BlockNumber
uint64
)
{
l2Client
:=
h
.
system
.
NodeClient
(
l2Node
)
_
,
err
:=
geth
.
WaitForBlockToBeSafe
(
new
(
big
.
Int
)
.
SetUint64
(
l2BlockNumber
),
l2Client
,
1
*
time
.
Minute
)
h
.
require
.
NoErrorf
(
err
,
"Block number %v did not become safe"
,
l2BlockNumber
)
}
func
(
h
*
FactoryHelper
)
createDisputeGameExtraData
(
ctx
context
.
Context
)
(
extraData
[]
byte
,
l1Head
*
big
.
Int
,
l2BlockNumber
uint64
)
{
func
(
h
*
FactoryHelper
)
createDisputeGameExtraData
(
ctx
context
.
Context
)
(
extraData
[]
byte
,
l1Head
*
big
.
Int
,
l2BlockNumber
uint64
)
{
l2BlockNumber
=
h
.
waitForProposals
(
ctx
)
l2BlockNumber
=
h
.
waitForProposals
(
ctx
)
l1Head
=
h
.
checkpointL1Block
(
ctx
)
l1Head
=
h
.
checkpointL1Block
(
ctx
)
...
...
op-e2e/e2eutils/disputegame/output_game_helper.go
View file @
150f704d
...
@@ -323,9 +323,7 @@ type Stepper func(parentClaimIdx int64)
...
@@ -323,9 +323,7 @@ type Stepper func(parentClaimIdx int64)
// When the game has reached the maximum depth it waits for the honest challenger to counter the leaf claim with step.
// When the game has reached the maximum depth it waits for the honest challenger to counter the leaf claim with step.
func
(
g
*
OutputGameHelper
)
DefendRootClaim
(
ctx
context
.
Context
,
performMove
Mover
)
{
func
(
g
*
OutputGameHelper
)
DefendRootClaim
(
ctx
context
.
Context
,
performMove
Mover
)
{
maxDepth
:=
g
.
MaxDepth
(
ctx
)
maxDepth
:=
g
.
MaxDepth
(
ctx
)
claimCount
,
err
:=
g
.
game
.
ClaimDataLen
(
&
bind
.
CallOpts
{
Context
:
ctx
})
for
claimCount
:=
g
.
getClaimCount
(
ctx
);
claimCount
<
maxDepth
;
{
g
.
require
.
NoError
(
err
,
"Failed to get current claim count"
)
for
claimCount
:=
claimCount
.
Int64
();
claimCount
<
maxDepth
;
{
g
.
LogGameData
(
ctx
)
g
.
LogGameData
(
ctx
)
claimCount
++
claimCount
++
// Wait for the challenger to counter
// Wait for the challenger to counter
...
@@ -348,7 +346,8 @@ func (g *OutputGameHelper) DefendRootClaim(ctx context.Context, performMove Move
...
@@ -348,7 +346,8 @@ func (g *OutputGameHelper) DefendRootClaim(ctx context.Context, performMove Move
// Since the output root is invalid, it should not be possible for the Stepper to call step successfully.
// Since the output root is invalid, it should not be possible for the Stepper to call step successfully.
func
(
g
*
OutputGameHelper
)
ChallengeRootClaim
(
ctx
context
.
Context
,
performMove
Mover
,
attemptStep
Stepper
)
{
func
(
g
*
OutputGameHelper
)
ChallengeRootClaim
(
ctx
context
.
Context
,
performMove
Mover
,
attemptStep
Stepper
)
{
maxDepth
:=
g
.
MaxDepth
(
ctx
)
maxDepth
:=
g
.
MaxDepth
(
ctx
)
for
claimCount
:=
int64
(
1
);
claimCount
<
maxDepth
;
{
for
claimCount
:=
g
.
getClaimCount
(
ctx
);
claimCount
<
maxDepth
;
{
g
.
LogGameData
(
ctx
)
g
.
LogGameData
(
ctx
)
// Perform our move
// Perform our move
performMove
(
claimCount
-
1
)
performMove
(
claimCount
-
1
)
...
@@ -368,6 +367,12 @@ func (g *OutputGameHelper) ChallengeRootClaim(ctx context.Context, performMove M
...
@@ -368,6 +367,12 @@ func (g *OutputGameHelper) ChallengeRootClaim(ctx context.Context, performMove M
attemptStep
(
maxDepth
)
attemptStep
(
maxDepth
)
}
}
func
(
g
*
OutputGameHelper
)
getClaimCount
(
ctx
context
.
Context
)
int64
{
claimCount
,
err
:=
g
.
game
.
ClaimDataLen
(
&
bind
.
CallOpts
{
Context
:
ctx
})
g
.
require
.
NoError
(
err
,
"Failed to get current claim count"
)
return
claimCount
.
Int64
()
}
func
(
g
*
OutputGameHelper
)
WaitForNewClaim
(
ctx
context
.
Context
,
checkPoint
int64
)
(
int64
,
error
)
{
func
(
g
*
OutputGameHelper
)
WaitForNewClaim
(
ctx
context
.
Context
,
checkPoint
int64
)
(
int64
,
error
)
{
return
g
.
waitForNewClaim
(
ctx
,
checkPoint
,
defaultTimeout
)
return
g
.
waitForNewClaim
(
ctx
,
checkPoint
,
defaultTimeout
)
}
}
...
...
op-e2e/e2eutils/disputegame/output_honest_helper.go
View file @
150f704d
...
@@ -27,7 +27,7 @@ func (h *OutputHonestHelper) Attack(ctx context.Context, claimIdx int64) {
...
@@ -27,7 +27,7 @@ func (h *OutputHonestHelper) Attack(ctx context.Context, claimIdx int64) {
game
,
claim
:=
h
.
loadState
(
ctx
,
claimIdx
)
game
,
claim
:=
h
.
loadState
(
ctx
,
claimIdx
)
attackPos
:=
claim
.
Position
.
Attack
()
attackPos
:=
claim
.
Position
.
Attack
()
h
.
t
.
Logf
(
"Attacking
at position %v with g index %v"
,
attackPos
,
attackPos
.
ToGIndex
())
h
.
t
.
Logf
(
"Attacking
claim %v at position %v with g index %v"
,
claimIdx
,
attackPos
,
attackPos
.
ToGIndex
())
value
,
err
:=
h
.
correctTrace
.
Get
(
ctx
,
game
,
claim
,
attackPos
)
value
,
err
:=
h
.
correctTrace
.
Get
(
ctx
,
game
,
claim
,
attackPos
)
h
.
require
.
NoErrorf
(
err
,
"Get correct claim at position %v with g index %v"
,
attackPos
,
attackPos
.
ToGIndex
())
h
.
require
.
NoErrorf
(
err
,
"Get correct claim at position %v with g index %v"
,
attackPos
,
attackPos
.
ToGIndex
())
h
.
t
.
Log
(
"Performing attack"
)
h
.
t
.
Log
(
"Performing attack"
)
...
...
op-e2e/faultproofs/output_cannon_test.go
View file @
150f704d
...
@@ -174,3 +174,98 @@ func TestOutputCannonDefendStep(t *testing.T) {
...
@@ -174,3 +174,98 @@ func TestOutputCannonDefendStep(t *testing.T) {
game
.
LogGameData
(
ctx
)
game
.
LogGameData
(
ctx
)
require
.
EqualValues
(
t
,
disputegame
.
StatusChallengerWins
,
game
.
Status
(
ctx
))
require
.
EqualValues
(
t
,
disputegame
.
StatusChallengerWins
,
game
.
Status
(
ctx
))
}
}
func
TestOutputCannonProposedOutputRootValid
(
t
*
testing
.
T
)
{
op_e2e
.
InitParallel
(
t
,
op_e2e
.
UsesCannon
,
op_e2e
.
UseExecutor
(
outputCannonTestExecutor
))
// honestStepsFail attempts to perform both an attack and defend step using the correct trace.
honestStepsFail
:=
func
(
ctx
context
.
Context
,
game
*
disputegame
.
OutputCannonGameHelper
,
correctTrace
*
disputegame
.
OutputHonestHelper
,
parentClaimIdx
int64
)
{
// Attack step should fail
correctTrace
.
StepFails
(
ctx
,
parentClaimIdx
,
true
)
// Defending should fail too
correctTrace
.
StepFails
(
ctx
,
parentClaimIdx
,
false
)
}
tests
:=
[]
struct
{
// name is the name of the test
name
string
// performMove is called to respond to each claim posted by the honest op-challenger.
// It should either attack or defend the claim at parentClaimIdx
performMove
func
(
ctx
context
.
Context
,
game
*
disputegame
.
OutputCannonGameHelper
,
correctTrace
*
disputegame
.
OutputHonestHelper
,
parentClaimIdx
int64
)
// performStep is called once the maximum game depth is reached. It should perform a step to counter the
// claim at parentClaimIdx. Since the proposed output root is invalid, the step call should always revert.
performStep
func
(
ctx
context
.
Context
,
game
*
disputegame
.
OutputCannonGameHelper
,
correctTrace
*
disputegame
.
OutputHonestHelper
,
parentClaimIdx
int64
)
}{
{
name
:
"AttackWithCorrectTrace"
,
performMove
:
func
(
ctx
context
.
Context
,
game
*
disputegame
.
OutputCannonGameHelper
,
correctTrace
*
disputegame
.
OutputHonestHelper
,
parentClaimIdx
int64
)
{
// Attack everything but oddly using the correct hash.
// Except the root of the cannon game must have an invalid VM status code.
splitDepth
:=
game
.
SplitDepth
(
ctx
)
if
splitDepth
==
parentClaimIdx
{
// TODO(client-pod#262): Verify that an attack with a valid status code is rejected
game
.
Attack
(
ctx
,
parentClaimIdx
,
common
.
Hash
{
0x01
})
return
}
correctTrace
.
Attack
(
ctx
,
parentClaimIdx
)
},
performStep
:
honestStepsFail
,
},
{
name
:
"DefendWithCorrectTrace"
,
performMove
:
func
(
ctx
context
.
Context
,
game
*
disputegame
.
OutputCannonGameHelper
,
correctTrace
*
disputegame
.
OutputHonestHelper
,
parentClaimIdx
int64
)
{
splitDepth
:=
game
.
SplitDepth
(
ctx
)
// Can only attack the root claim or the first cannon claim
if
parentClaimIdx
==
0
{
correctTrace
.
Attack
(
ctx
,
parentClaimIdx
)
return
}
// The root of the cannon game must have an invalid VM status code
// Attacking ensure we're running the cannon trace between two different blocks
// instead of being in the trace extension of the output root bisection
if
splitDepth
==
parentClaimIdx
{
// TODO(client-pod#262): Verify that an attack with a valid status code is rejected
game
.
Attack
(
ctx
,
parentClaimIdx
,
common
.
Hash
{
0x01
})
return
}
// Otherwise, defend everything using the correct hash.
correctTrace
.
Defend
(
ctx
,
parentClaimIdx
)
},
performStep
:
honestStepsFail
,
},
}
for
_
,
test
:=
range
tests
{
test
:=
test
t
.
Run
(
test
.
name
,
func
(
t
*
testing
.
T
)
{
op_e2e
.
InitParallel
(
t
,
op_e2e
.
UseExecutor
(
0
))
ctx
:=
context
.
Background
()
sys
,
l1Client
:=
startFaultDisputeSystem
(
t
)
t
.
Cleanup
(
sys
.
Close
)
disputeGameFactory
:=
disputegame
.
NewFactoryHelper
(
t
,
ctx
,
sys
)
game
:=
disputeGameFactory
.
StartOutputCannonGameWithCorrectRoot
(
ctx
,
"sequencer"
,
1
)
correctTrace
:=
game
.
CreateHonestActor
(
ctx
,
"sequencer"
,
challenger
.
WithPrivKey
(
sys
.
Cfg
.
Secrets
.
Mallory
))
game
.
StartChallenger
(
ctx
,
"sequencer"
,
"Challenger"
,
challenger
.
WithPrivKey
(
sys
.
Cfg
.
Secrets
.
Alice
))
// Now maliciously play the game and it should be impossible to win
game
.
ChallengeRootClaim
(
ctx
,
func
(
parentClaimIdx
int64
)
{
test
.
performMove
(
ctx
,
game
,
correctTrace
,
parentClaimIdx
)
},
func
(
parentClaimIdx
int64
)
{
test
.
performStep
(
ctx
,
game
,
correctTrace
,
parentClaimIdx
)
})
// Time travel past when the game will be resolvable.
sys
.
TimeTravelClock
.
AdvanceTime
(
game
.
GameDuration
(
ctx
))
require
.
NoError
(
t
,
wait
.
ForNextBlock
(
ctx
,
l1Client
))
game
.
WaitForInactivity
(
ctx
,
10
,
true
)
game
.
LogGameData
(
ctx
)
require
.
EqualValues
(
t
,
disputegame
.
StatusDefenderWins
,
game
.
Status
(
ctx
))
})
}
}
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