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
1740df6a
Unverified
Commit
1740df6a
authored
Jan 02, 2024
by
Adrian Sutton
Committed by
GitHub
Jan 01, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
op-e2e: Convert output_cannon tests to use claim helper (#8743)
parent
21fa288c
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
123 additions
and
89 deletions
+123
-89
claim_helper.go
op-e2e/e2eutils/disputegame/claim_helper.go
+37
-3
game_helper.go
op-e2e/e2eutils/disputegame/game_helper.go
+2
-2
output_game_helper.go
op-e2e/e2eutils/disputegame/output_game_helper.go
+31
-34
output_honest_helper.go
op-e2e/e2eutils/disputegame/output_honest_helper.go
+10
-0
output_cannon_test.go
op-e2e/faultproofs/output_cannon_test.go
+43
-50
No files found.
op-e2e/e2eutils/disputegame/claim_helper.go
View file @
1740df6a
...
...
@@ -3,6 +3,7 @@ package disputegame
import
(
"context"
"fmt"
"slices"
"time"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
...
...
@@ -35,6 +36,10 @@ func (c *ClaimHelper) AgreesWithOutputRoot() bool {
return
c
.
position
.
Depth
()
%
2
==
0
}
func
(
c
*
ClaimHelper
)
IsRootClaim
()
bool
{
return
c
.
position
.
IsRootPosition
()
}
func
(
c
*
ClaimHelper
)
IsOutputRoot
(
ctx
context
.
Context
)
bool
{
splitDepth
:=
c
.
game
.
SplitDepth
(
ctx
)
return
int64
(
c
.
position
.
Depth
())
<=
splitDepth
...
...
@@ -45,16 +50,25 @@ func (c *ClaimHelper) IsOutputRootLeaf(ctx context.Context) bool {
return
int64
(
c
.
position
.
Depth
())
==
splitDepth
}
func
(
c
*
ClaimHelper
)
IsBottomGameRoot
(
ctx
context
.
Context
)
bool
{
splitDepth
:=
c
.
game
.
SplitDepth
(
ctx
)
return
int64
(
c
.
position
.
Depth
())
==
splitDepth
+
1
}
func
(
c
*
ClaimHelper
)
IsMaxDepth
(
ctx
context
.
Context
)
bool
{
maxDepth
:=
c
.
game
.
MaxDepth
(
ctx
)
return
int64
(
c
.
position
.
Depth
())
==
maxDepth
}
func
(
c
*
ClaimHelper
)
Depth
()
int64
{
return
int64
(
c
.
position
.
Depth
())
}
// WaitForCounterClaim waits for the claim to be countered by another claim being posted.
// It returns a helper for the claim that countered this one.
func
(
c
*
ClaimHelper
)
WaitForCounterClaim
(
ctx
context
.
Context
)
*
ClaimHelper
{
counterIdx
,
counterClaim
:=
c
.
game
.
waitForClaim
(
ctx
,
fmt
.
Sprintf
(
"failed to find claim with parent idx %v"
,
c
.
index
),
func
(
claim
ContractClaim
)
bool
{
return
int64
(
claim
.
ParentIndex
)
==
c
.
index
func
(
c
*
ClaimHelper
)
WaitForCounterClaim
(
ctx
context
.
Context
,
ignoreClaims
...*
ClaimHelper
)
*
ClaimHelper
{
counterIdx
,
counterClaim
:=
c
.
game
.
waitForClaim
(
ctx
,
fmt
.
Sprintf
(
"failed to find claim with parent idx %v"
,
c
.
index
),
func
(
claim
Idx
int64
,
claim
ContractClaim
)
bool
{
return
int64
(
claim
.
ParentIndex
)
==
c
.
index
&&
!
containsClaim
(
claimIdx
,
ignoreClaims
)
})
return
newClaimHelper
(
c
.
game
,
counterIdx
,
counterClaim
)
}
...
...
@@ -92,3 +106,23 @@ func (c *ClaimHelper) Defend(ctx context.Context, value common.Hash) *ClaimHelpe
func
(
c
*
ClaimHelper
)
RequireDifferentClaimValue
(
other
*
ClaimHelper
)
{
c
.
require
.
NotEqual
(
c
.
claim
,
other
.
claim
,
"should have posted different claims"
)
}
func
(
c
*
ClaimHelper
)
RequireOnlyCounteredBy
(
ctx
context
.
Context
,
expected
...*
ClaimHelper
)
{
claims
:=
c
.
game
.
getAllClaims
(
ctx
)
for
idx
,
claim
:=
range
claims
{
if
int64
(
claim
.
ParentIndex
)
!=
c
.
index
{
// Doesn't counter this claim, so ignore
continue
}
if
!
containsClaim
(
int64
(
idx
),
expected
)
{
// Found a countering claim not in the expected list. Fail.
c
.
require
.
FailNowf
(
"Found unexpected countering claim"
,
"Parent claim index: %v Game state:
\n
%v"
,
c
.
index
,
c
.
game
.
gameData
(
ctx
))
}
}
}
func
containsClaim
(
claimIdx
int64
,
haystack
[]
*
ClaimHelper
)
bool
{
return
slices
.
ContainsFunc
(
haystack
,
func
(
candidate
*
ClaimHelper
)
bool
{
return
candidate
.
index
==
claimIdx
})
}
op-e2e/e2eutils/disputegame/game_helper.go
View file @
1740df6a
...
...
@@ -246,7 +246,7 @@ func (g *FaultGameHelper) WaitForInactivity(ctx context.Context, numInactiveBloc
// 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
)
{
func
(
g
*
FaultGameHelper
)
DefendRootClaim
(
ctx
context
.
Context
,
performMove
func
(
parentClaimIdx
int64
)
)
{
maxDepth
:=
g
.
MaxDepth
(
ctx
)
for
claimCount
:=
int64
(
1
);
claimCount
<
maxDepth
;
{
g
.
LogGameData
(
ctx
)
...
...
@@ -268,7 +268,7 @@ func (g *FaultGameHelper) DefendRootClaim(ctx context.Context, performMove Mover
// 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
)
{
func
(
g
*
FaultGameHelper
)
ChallengeRootClaim
(
ctx
context
.
Context
,
performMove
func
(
parentClaimIdx
int64
)
,
attemptStep
Stepper
)
{
maxDepth
:=
g
.
MaxDepth
(
ctx
)
for
claimCount
:=
int64
(
1
);
claimCount
<
maxDepth
;
{
g
.
LogGameData
(
ctx
)
...
...
op-e2e/e2eutils/disputegame/output_game_helper.go
View file @
1740df6a
...
...
@@ -145,7 +145,7 @@ func (g *OutputGameHelper) MaxDepth(ctx context.Context) int64 {
return
depth
.
Int64
()
}
func
(
g
*
OutputGameHelper
)
waitForClaim
(
ctx
context
.
Context
,
errorMsg
string
,
predicate
func
(
claim
ContractClaim
)
bool
)
(
int64
,
ContractClaim
)
{
func
(
g
*
OutputGameHelper
)
waitForClaim
(
ctx
context
.
Context
,
errorMsg
string
,
predicate
func
(
claim
Idx
int64
,
claim
ContractClaim
)
bool
)
(
int64
,
ContractClaim
)
{
timedCtx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
defaultTimeout
)
defer
cancel
()
var
matchedClaim
ContractClaim
...
...
@@ -161,7 +161,7 @@ func (g *OutputGameHelper) waitForClaim(ctx context.Context, errorMsg string, pr
if
err
!=
nil
{
return
false
,
fmt
.
Errorf
(
"retrieve claim %v: %w"
,
i
,
err
)
}
if
predicate
(
claimData
)
{
if
predicate
(
i
,
claimData
)
{
matchClaimIdx
=
i
matchedClaim
=
claimData
return
true
,
nil
...
...
@@ -206,10 +206,13 @@ func (g *OutputGameHelper) GetClaimValue(ctx context.Context, claimIdx int64) co
return
claim
.
Claim
}
func
(
g
*
OutputGameHelper
)
GetClaimPosition
(
ctx
context
.
Context
,
claimIdx
int64
)
types
.
Position
{
g
.
WaitForClaimCount
(
ctx
,
claimIdx
+
1
)
claim
:=
g
.
getClaim
(
ctx
,
claimIdx
)
return
types
.
NewPositionFromGIndex
(
claim
.
Position
)
func
(
g
*
OutputGameHelper
)
getAllClaims
(
ctx
context
.
Context
)
[]
ContractClaim
{
count
:=
g
.
getClaimCount
(
ctx
)
var
claims
[]
ContractClaim
for
i
:=
int64
(
0
);
i
<
count
;
i
++
{
claims
=
append
(
claims
,
g
.
getClaim
(
ctx
,
i
))
}
return
claims
}
// getClaim retrieves the claim data for a specific index.
...
...
@@ -226,7 +229,7 @@ func (g *OutputGameHelper) WaitForClaimAtDepth(ctx context.Context, depth int) {
g
.
waitForClaim
(
ctx
,
fmt
.
Sprintf
(
"Could not find claim depth %v"
,
depth
),
func
(
claim
ContractClaim
)
bool
{
func
(
_
int64
,
claim
ContractClaim
)
bool
{
pos
:=
types
.
NewPositionFromGIndex
(
claim
.
Position
)
return
pos
.
Depth
()
==
depth
})
...
...
@@ -237,7 +240,7 @@ func (g *OutputGameHelper) WaitForClaimAtMaxDepth(ctx context.Context, countered
g
.
waitForClaim
(
ctx
,
fmt
.
Sprintf
(
"Could not find claim depth %v with countered=%v"
,
maxDepth
,
countered
),
func
(
claim
ContractClaim
)
bool
{
func
(
_
int64
,
claim
ContractClaim
)
bool
{
pos
:=
types
.
NewPositionFromGIndex
(
claim
.
Position
)
return
int64
(
pos
.
Depth
())
==
maxDepth
&&
claim
.
Countered
==
countered
})
...
...
@@ -325,50 +328,42 @@ func (g *OutputGameHelper) WaitForInactivity(ctx context.Context, numInactiveBlo
}
// Mover is a function that either attacks or defends the claim at parentClaimIdx
type
Mover
func
(
parent
ClaimIdx
int64
)
type
Mover
func
(
parent
*
ClaimHelper
)
*
ClaimHelper
// Stepper is a function that attempts to perform a step against the claim at parentClaimIdx
type
Stepper
func
(
parentClaimIdx
int64
)
// Defend
RootClaim 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.
// Defend
Claim uses the supplied Mover to perform moves in an attempt to defend the supplied
claim.
// It is assumed that the
specified claim is in
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
*
OutputGameHelper
)
Defend
RootClaim
(
ctx
context
.
Context
,
performMove
Mover
)
{
maxDepth
:=
g
.
MaxDepth
(
ctx
)
for
claimCount
:=
g
.
getClaimCount
(
ctx
);
claimCount
<
maxDepth
;
{
func
(
g
*
OutputGameHelper
)
Defend
Claim
(
ctx
context
.
Context
,
claim
*
ClaimHelper
,
performMove
Mover
)
{
g
.
t
.
Logf
(
"Defending claim %v at depth %v"
,
claim
.
index
,
claim
.
Depth
()
)
for
!
claim
.
IsMaxDepth
(
ctx
)
{
g
.
LogGameData
(
ctx
)
claimCount
++
// Wait for the challenger to counter
g
.
WaitForClaimCount
(
ctx
,
claimCount
)
claim
=
claim
.
WaitForCounterClaim
(
ctx
)
g
.
LogGameData
(
ctx
)
// Respond with our own move
performMove
(
claimCount
-
1
)
claimCount
++
g
.
WaitForClaimCount
(
ctx
,
claimCount
)
claim
=
performMove
(
claim
)
}
// Wait for the challenger to call step and counter our invalid claim
g
.
WaitForClaimAtMaxDepth
(
ctx
,
true
)
claim
.
WaitForCountered
(
ctx
)
}
// Challenge
RootClaim 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 in
valid and that an honest op-challenger is already running.
// Challenge
Claim uses the supplied functions to perform moves and steps in an attempt to challenge the supplied
claim.
// It is assumed that the
claim being disputed is
valid 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
*
OutputGameHelper
)
ChallengeRootClaim
(
ctx
context
.
Context
,
performMove
Mover
,
attemptStep
Stepper
)
{
maxDepth
:=
g
.
MaxDepth
(
ctx
)
for
claimCount
:=
g
.
getClaimCount
(
ctx
);
claimCount
<
maxDepth
;
{
// Since the output root is valid, it should not be possible for the Stepper to call step successfully.
func
(
g
*
OutputGameHelper
)
ChallengeClaim
(
ctx
context
.
Context
,
claim
*
ClaimHelper
,
performMove
Mover
,
attemptStep
Stepper
)
{
for
!
claim
.
IsMaxDepth
(
ctx
)
{
g
.
LogGameData
(
ctx
)
// Perform our move
performMove
(
claimCount
-
1
)
claimCount
++
g
.
WaitForClaimCount
(
ctx
,
claimCount
)
claim
=
performMove
(
claim
)
// Wait for the challenger to counter
claimCount
++
g
.
WaitForClaimCount
(
ctx
,
claimCount
)
g
.
LogGameData
(
ctx
)
claim
=
claim
.
WaitForCounterClaim
(
ctx
)
}
// Confirm the game has reached max depth and the last claim hasn't been countered
...
...
@@ -376,7 +371,7 @@ func (g *OutputGameHelper) ChallengeRootClaim(ctx context.Context, performMove M
g
.
LogGameData
(
ctx
)
// It's on us to call step if we want to win but shouldn't be possible
attemptStep
(
maxDepth
)
attemptStep
(
claim
.
index
)
}
func
(
g
*
OutputGameHelper
)
getClaimCount
(
ctx
context
.
Context
)
int64
{
...
...
@@ -405,6 +400,7 @@ func (g *OutputGameHelper) waitForNewClaim(ctx context.Context, checkPoint int64
}
func
(
g
*
OutputGameHelper
)
Attack
(
ctx
context
.
Context
,
claimIdx
int64
,
claim
common
.
Hash
)
{
g
.
t
.
Logf
(
"Attacking claim %v with value %v"
,
claimIdx
,
claim
)
tx
,
err
:=
g
.
game
.
Attack
(
g
.
opts
,
big
.
NewInt
(
claimIdx
),
claim
)
if
err
!=
nil
{
g
.
require
.
NoErrorf
(
err
,
"Attack transaction did not send. Game state:
\n
%v"
,
g
.
gameData
(
ctx
))
...
...
@@ -416,6 +412,7 @@ func (g *OutputGameHelper) Attack(ctx context.Context, claimIdx int64, claim com
}
func
(
g
*
OutputGameHelper
)
Defend
(
ctx
context
.
Context
,
claimIdx
int64
,
claim
common
.
Hash
)
{
g
.
t
.
Logf
(
"Defending claim %v with value %v"
,
claimIdx
,
claim
)
tx
,
err
:=
g
.
game
.
Defend
(
g
.
opts
,
big
.
NewInt
(
claimIdx
),
claim
)
if
err
!=
nil
{
g
.
require
.
NoErrorf
(
err
,
"Defend transaction did not send. Game state:
\n
%v"
,
g
.
gameData
(
ctx
))
...
...
op-e2e/e2eutils/disputegame/output_honest_helper.go
View file @
1740df6a
...
...
@@ -18,6 +18,16 @@ type OutputHonestHelper struct {
correctTrace
types
.
TraceAccessor
}
func
(
h
*
OutputHonestHelper
)
AttackClaim
(
ctx
context
.
Context
,
claim
*
ClaimHelper
)
*
ClaimHelper
{
h
.
Attack
(
ctx
,
claim
.
index
)
return
claim
.
WaitForCounterClaim
(
ctx
)
}
func
(
h
*
OutputHonestHelper
)
DefendClaim
(
ctx
context
.
Context
,
claim
*
ClaimHelper
)
*
ClaimHelper
{
h
.
Defend
(
ctx
,
claim
.
index
)
return
claim
.
WaitForCounterClaim
(
ctx
)
}
func
(
h
*
OutputHonestHelper
)
Attack
(
ctx
context
.
Context
,
claimIdx
int64
)
{
// Ensure the claim exists
h
.
game
.
WaitForClaimCount
(
ctx
,
claimIdx
+
1
)
...
...
op-e2e/faultproofs/output_cannon_test.go
View file @
1740df6a
...
...
@@ -123,18 +123,19 @@ func TestOutputCannonDisputeGame(t *testing.T) {
require
.
NotNil
(
t
,
game
)
game
.
LogGameData
(
ctx
)
game
.
DisputeLastBlock
(
ctx
)
outputClaim
:=
game
.
DisputeLastBlock
(
ctx
)
splitDepth
:=
game
.
SplitDepth
(
ctx
)
game
.
StartChallenger
(
ctx
,
"sequencer"
,
"Challenger"
,
challenger
.
WithPrivKey
(
sys
.
Cfg
.
Secrets
.
Alice
))
game
.
Defend
Root
Claim
(
game
.
DefendClaim
(
ctx
,
func
(
parentClaimIdx
int64
)
{
if
parentClaimIdx
+
1
==
splitDepth
+
test
.
defendClaimDepth
{
game
.
Defend
(
ctx
,
parentClaimIdx
,
common
.
Hash
{
byte
(
parentClaimIdx
)})
outputClaim
,
func
(
claim
*
disputegame
.
ClaimHelper
)
*
disputegame
.
ClaimHelper
{
if
claim
.
Depth
()
+
1
==
splitDepth
+
test
.
defendClaimDepth
{
return
claim
.
Defend
(
ctx
,
common
.
Hash
{
byte
(
claim
.
Depth
())})
}
else
{
game
.
Attack
(
ctx
,
parentClaimIdx
,
common
.
Hash
{
byte
(
parentClaimIdx
)})
return
claim
.
Attack
(
ctx
,
common
.
Hash
{
byte
(
claim
.
Depth
()
)})
}
})
...
...
@@ -157,21 +158,21 @@ func TestOutputCannonDefendStep(t *testing.T) {
disputeGameFactory
:=
disputegame
.
NewFactoryHelper
(
t
,
ctx
,
sys
)
game
:=
disputeGameFactory
.
StartOutputCannonGame
(
ctx
,
"sequencer"
,
1
,
common
.
Hash
{
0x01
,
0xaa
})
require
.
NotNil
(
t
,
game
)
game
.
DisputeLastBlock
(
ctx
)
outputRootClaim
:=
game
.
DisputeLastBlock
(
ctx
)
game
.
LogGameData
(
ctx
)
game
.
StartChallenger
(
ctx
,
"sequencer"
,
"Challenger"
,
challenger
.
WithPrivKey
(
sys
.
Cfg
.
Secrets
.
Alice
))
correctTrace
:=
game
.
CreateHonestActor
(
ctx
,
"sequencer"
,
challenger
.
WithPrivKey
(
sys
.
Cfg
.
Secrets
.
Mallory
))
splitDepth
:=
game
.
Split
Depth
(
ctx
)
game
.
Defend
RootClaim
(
ctx
,
func
(
parentClaimIdx
int64
)
{
maxDepth
:=
game
.
Max
Depth
(
ctx
)
game
.
Defend
Claim
(
ctx
,
outputRootClaim
,
func
(
claim
*
disputegame
.
ClaimHelper
)
*
disputegame
.
ClaimHelper
{
// Post invalid claims for most steps to get down into the early part of the trace
if
parentClaimIdx
<
splitDepth
+
27
{
game
.
Attack
(
ctx
,
parentClaimIdx
,
common
.
Hash
{
byte
(
parentClaimIdx
)
})
if
claim
.
Depth
()
<
maxDepth
-
3
{
return
claim
.
Attack
(
ctx
,
common
.
Hash
{
0xaa
})
}
else
{
// Post our own counter but using the correct hash in low levels to force a defense step
correctTrace
.
Attack
(
ctx
,
parentClaimIdx
)
return
correctTrace
.
AttackClaim
(
ctx
,
claim
)
}
})
...
...
@@ -198,7 +199,7 @@ func TestOutputCannonProposedOutputRootValid(t *testing.T) {
// 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
)
performMove
func
(
ctx
context
.
Context
,
game
*
disputegame
.
OutputCannonGameHelper
,
correctTrace
*
disputegame
.
OutputHonestHelper
,
claim
*
disputegame
.
ClaimHelper
)
*
disputegame
.
ClaimHelper
// 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.
...
...
@@ -206,38 +207,33 @@ func TestOutputCannonProposedOutputRootValid(t *testing.T) {
}{
{
name
:
"AttackWithCorrectTrace"
,
performMove
:
func
(
ctx
context
.
Context
,
game
*
disputegame
.
OutputCannonGameHelper
,
correctTrace
*
disputegame
.
OutputHonestHelper
,
parentClaimIdx
int64
)
{
performMove
:
func
(
ctx
context
.
Context
,
game
*
disputegame
.
OutputCannonGameHelper
,
correctTrace
*
disputegame
.
OutputHonestHelper
,
claim
*
disputegame
.
ClaimHelper
)
*
disputegame
.
ClaimHelper
{
// 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
{
if
claim
.
IsOutputRootLeaf
(
ctx
)
{
// TODO(client-pod#262): Verify that an attack with a valid status code is rejected
game
.
Attack
(
ctx
,
parentClaimIdx
,
common
.
Hash
{
0x01
})
return
return
claim
.
Attack
(
ctx
,
common
.
Hash
{
0x01
})
}
correctTrace
.
Attack
(
ctx
,
parentClaimIdx
)
return
correctTrace
.
AttackClaim
(
ctx
,
claim
)
},
performStep
:
honestStepsFail
,
},
{
name
:
"DefendWithCorrectTrace"
,
performMove
:
func
(
ctx
context
.
Context
,
game
*
disputegame
.
OutputCannonGameHelper
,
correctTrace
*
disputegame
.
OutputHonestHelper
,
parentClaimIdx
int64
)
{
splitDepth
:=
game
.
SplitDepth
(
ctx
)
performMove
:
func
(
ctx
context
.
Context
,
game
*
disputegame
.
OutputCannonGameHelper
,
correctTrace
*
disputegame
.
OutputHonestHelper
,
claim
*
disputegame
.
ClaimHelper
)
*
disputegame
.
ClaimHelper
{
// Can only attack the root claim or the first cannon claim
if
parentClaimIdx
==
0
{
correctTrace
.
Attack
(
ctx
,
parentClaimIdx
)
return
if
claim
.
IsRootClaim
()
{
return
correctTrace
.
AttackClaim
(
ctx
,
claim
)
}
// 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
{
if
claim
.
IsOutputRootLeaf
(
ctx
)
{
// TODO(client-pod#262): Verify that an attack with a valid status code is rejected
game
.
Attack
(
ctx
,
parentClaimIdx
,
common
.
Hash
{
0x01
})
return
return
claim
.
Attack
(
ctx
,
common
.
Hash
{
0x01
})
}
// Otherwise, defend everything using the correct hash.
correctTrace
.
Defend
(
ctx
,
parentClaimIdx
)
return
correctTrace
.
DefendClaim
(
ctx
,
claim
)
},
performStep
:
honestStepsFail
,
},
...
...
@@ -259,9 +255,10 @@ func TestOutputCannonProposedOutputRootValid(t *testing.T) {
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
)
game
.
ChallengeClaim
(
ctx
,
game
.
RootClaim
(
ctx
),
func
(
claim
*
disputegame
.
ClaimHelper
)
*
disputegame
.
ClaimHelper
{
return
test
.
performMove
(
ctx
,
game
,
correctTrace
,
claim
)
},
func
(
parentClaimIdx
int64
)
{
test
.
performStep
(
ctx
,
game
,
correctTrace
,
parentClaimIdx
)
...
...
@@ -291,52 +288,48 @@ func TestOutputCannonPoisonedPostState(t *testing.T) {
correctTrace
:=
game
.
CreateHonestActor
(
ctx
,
"sequencer"
,
challenger
.
WithPrivKey
(
sys
.
Cfg
.
Secrets
.
Alice
))
// Honest first attack at "honest" level
c
orrectTrace
.
Attack
(
ctx
,
0
)
c
laim
:=
correctTrace
.
AttackClaim
(
ctx
,
game
.
RootClaim
(
ctx
)
)
// Honest defense at "dishonest" level
c
orrectTrace
.
Defend
(
ctx
,
1
)
c
laim
=
correctTrace
.
DefendClaim
(
ctx
,
claim
)
// Dishonest attack at "honest" level - honest move would be to ignore
game
.
Attack
(
ctx
,
2
,
common
.
Hash
{
0x03
,
0xaa
})
claimToIgnore1
:=
claim
.
Attack
(
ctx
,
common
.
Hash
{
0x03
,
0xaa
})
// Honest attack at "dishonest" level - honest move would be to ignore
c
orrectTrace
.
Attack
(
ctx
,
3
)
c
laimToIgnore2
:=
correctTrace
.
AttackClaim
(
ctx
,
claimToIgnore1
)
game
.
LogGameData
(
ctx
)
// Start the honest challenger
game
.
StartChallenger
(
ctx
,
"sequencer"
,
"Honest"
,
challenger
.
WithPrivKey
(
sys
.
Cfg
.
Secrets
.
Bob
))
// Start dishonest challenger that posts correct claims
// It participates in the subgame root the honest claim index 4
claimCount
:=
int64
(
5
)
depth
:=
game
.
MaxDepth
(
ctx
)
splitDepth
:=
game
.
SplitDepth
(
ctx
)
for
{
game
.
LogGameData
(
ctx
)
claimCount
++
// Wait for the challenger to counter
game
.
WaitForClaimCount
(
ctx
,
claimCount
)
// Note that we need to ignore claimToIgnore1 which already counters this...
claim
=
claim
.
WaitForCounterClaim
(
ctx
,
claimToIgnore1
)
// Respond with our own move
if
claim
Count
==
splitDepth
+
4
{
if
claim
.
IsBottomGameRoot
(
ctx
)
{
// Root of the cannon game must have the right VM status code (so it can't be honest).
// Note this occurs when there are splitDepth + 4 claims because there are multiple forks in this game.
game
.
Attack
(
ctx
,
claimCount
-
1
,
common
.
Hash
{
0x01
})
claim
=
claim
.
Attack
(
ctx
,
common
.
Hash
{
0x01
})
}
else
{
c
orrectTrace
.
Defend
(
ctx
,
claimCount
-
1
)
c
laim
=
correctTrace
.
DefendClaim
(
ctx
,
claim
)
}
claimCount
++
game
.
WaitForClaimCount
(
ctx
,
claimCount
)
// Defender moves last. If we're at max depth, then we're done
pos
:=
game
.
GetClaimPosition
(
ctx
,
claimCount
-
1
)
if
int64
(
pos
.
Depth
())
==
depth
{
if
claim
.
IsMaxDepth
(
ctx
)
{
break
}
}
// Wait for the challenger to drive the subgame at 4 to the leaf node, which should be countered
game
.
WaitForClaimAtMaxDepth
(
ctx
,
true
)
// Wait for the challenger to call step
claim
.
WaitForCountered
(
ctx
)
// Verify that the challenger didn't challenge our poisoned claims
claimToIgnore1
.
RequireOnlyCounteredBy
(
ctx
,
claimToIgnore2
)
claimToIgnore2
.
RequireOnlyCounteredBy
(
ctx
/* nothing */
)
// Time travel past when the game will be resolvable.
sys
.
TimeTravelClock
.
AdvanceTime
(
game
.
GameDuration
(
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