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
267aac82
Unverified
Commit
267aac82
authored
Dec 22, 2023
by
Adrian Sutton
Committed by
GitHub
Dec 21, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
op-e2e: Introduce ClaimHelper to simplify test logic (#8547)
parent
5e60f1dc
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
137 additions
and
27 deletions
+137
-27
claim_helper.go
op-e2e/e2eutils/disputegame/claim_helper.go
+90
-0
output_game_helper.go
op-e2e/e2eutils/disputegame/output_game_helper.go
+20
-8
output_cannon_test.go
op-e2e/faultproofs/output_cannon_test.go
+27
-19
No files found.
op-e2e/e2eutils/disputegame/claim_helper.go
0 → 100644
View file @
267aac82
package
disputegame
import
(
"context"
"fmt"
"time"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
type
ClaimHelper
struct
{
require
*
require
.
Assertions
game
*
OutputGameHelper
index
int64
parentIndex
uint32
position
types
.
Position
claim
common
.
Hash
}
func
newClaimHelper
(
game
*
OutputGameHelper
,
idx
int64
,
claim
ContractClaim
)
*
ClaimHelper
{
return
&
ClaimHelper
{
require
:
game
.
require
,
game
:
game
,
index
:
idx
,
parentIndex
:
claim
.
ParentIndex
,
position
:
types
.
NewPositionFromGIndex
(
claim
.
Position
),
claim
:
claim
.
Claim
,
}
}
func
(
c
*
ClaimHelper
)
AgreesWithOutputRoot
()
bool
{
return
c
.
position
.
Depth
()
%
2
==
0
}
func
(
c
*
ClaimHelper
)
IsOutputRoot
(
ctx
context
.
Context
)
bool
{
splitDepth
:=
c
.
game
.
SplitDepth
(
ctx
)
return
int64
(
c
.
position
.
Depth
())
<=
splitDepth
}
func
(
c
*
ClaimHelper
)
IsOutputRootLeaf
(
ctx
context
.
Context
)
bool
{
splitDepth
:=
c
.
game
.
SplitDepth
(
ctx
)
return
int64
(
c
.
position
.
Depth
())
==
splitDepth
}
func
(
c
*
ClaimHelper
)
IsMaxDepth
(
ctx
context
.
Context
)
bool
{
maxDepth
:=
c
.
game
.
MaxDepth
(
ctx
)
return
int64
(
c
.
position
.
Depth
())
==
maxDepth
}
// 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
})
return
newClaimHelper
(
c
.
game
,
counterIdx
,
counterClaim
)
}
// WaitForCountered waits until the claim is countered either by a child claim or by a step call.
func
(
c
*
ClaimHelper
)
WaitForCountered
(
ctx
context
.
Context
)
{
timedCtx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
defaultTimeout
)
defer
cancel
()
err
:=
wait
.
For
(
timedCtx
,
time
.
Second
,
func
()
(
bool
,
error
)
{
latestData
:=
c
.
game
.
getClaim
(
ctx
,
c
.
index
)
return
latestData
.
Countered
,
nil
})
if
err
!=
nil
{
// Avoid waiting time capturing game data when there's no error
c
.
require
.
NoErrorf
(
err
,
"Claim %v was not countered
\n
%v"
,
c
.
index
,
c
.
game
.
gameData
(
ctx
))
}
}
func
(
c
*
ClaimHelper
)
RequireCorrectOutputRoot
(
ctx
context
.
Context
)
{
c
.
require
.
True
(
c
.
IsOutputRoot
(
ctx
),
"Should not expect a valid output root in the bottom game"
)
expected
,
err
:=
c
.
game
.
correctOutputProvider
.
Get
(
ctx
,
c
.
position
)
c
.
require
.
NoError
(
err
,
"Failed to get correct output root"
)
c
.
require
.
Equalf
(
expected
,
c
.
claim
,
"Should have correct output root in claim %v and position %v"
,
c
.
index
,
c
.
position
)
}
func
(
c
*
ClaimHelper
)
Attack
(
ctx
context
.
Context
,
value
common
.
Hash
)
*
ClaimHelper
{
c
.
game
.
Attack
(
ctx
,
c
.
index
,
value
)
return
c
.
WaitForCounterClaim
(
ctx
)
}
func
(
c
*
ClaimHelper
)
Defend
(
ctx
context
.
Context
,
value
common
.
Hash
)
*
ClaimHelper
{
c
.
game
.
Defend
(
ctx
,
c
.
index
,
value
)
return
c
.
WaitForCounterClaim
(
ctx
)
}
op-e2e/e2eutils/disputegame/output_game_helper.go
View file @
267aac82
...
...
@@ -57,32 +57,39 @@ func (g *OutputGameHelper) GenesisBlockNum(ctx context.Context) uint64 {
// DisputeLastBlock posts claims from both the honest and dishonest actor to progress the output root part of the game
// through to the split depth and the claims are setup such that the last block in the game range is the block
// to execute cannon on. ie the first block the honest and dishonest actors disagree about is the l2 block of the game.
func
(
g
*
OutputGameHelper
)
DisputeLastBlock
(
ctx
context
.
Context
)
{
func
(
g
*
OutputGameHelper
)
DisputeLastBlock
(
ctx
context
.
Context
)
*
ClaimHelper
{
rootClaim
:=
g
.
GetClaimValue
(
ctx
,
0
)
disputeBlockNum
:=
g
.
L2BlockNum
(
ctx
)
splitDepth
:=
int
(
g
.
SplitDepth
(
ctx
))
pos
:=
types
.
NewPositionFromGIndex
(
big
.
NewInt
(
1
))
getClaimValue
:=
func
(
parentClaim
Idx
int
,
claimPos
types
.
Position
)
common
.
Hash
{
getClaimValue
:=
func
(
parentClaim
*
ClaimHelper
,
claimPos
types
.
Position
)
common
.
Hash
{
claimBlockNum
,
err
:=
g
.
correctOutputProvider
.
BlockNumber
(
claimPos
)
g
.
require
.
NoError
(
err
,
"failed to calculate claim block number"
)
// Use the correct output root for the challenger and incorrect for the defender
if
parentClaim
Idx
%
2
==
0
||
claimBlockNum
<
disputeBlockNum
{
if
parentClaim
.
AgreesWithOutputRoot
()
||
claimBlockNum
<
disputeBlockNum
{
return
g
.
correctOutputRoot
(
ctx
,
claimPos
)
}
else
{
return
rootClaim
}
}
for
i
:=
0
;
i
<
splitDepth
;
i
++
{
claim
:=
g
.
RootClaim
(
ctx
)
for
!
claim
.
IsOutputRootLeaf
(
ctx
)
{
parentClaimBlockNum
,
err
:=
g
.
correctOutputProvider
.
BlockNumber
(
pos
)
g
.
require
.
NoError
(
err
,
"failed to calculate parent claim block number"
)
if
parentClaimBlockNum
>=
disputeBlockNum
{
pos
=
pos
.
Attack
()
g
.
Attack
(
ctx
,
int64
(
i
),
getClaimValue
(
i
,
pos
))
claim
=
claim
.
Attack
(
ctx
,
getClaimValue
(
claim
,
pos
))
}
else
{
pos
=
pos
.
Defend
()
g
.
Defend
(
ctx
,
int64
(
i
),
getClaimValue
(
i
,
pos
))
claim
=
claim
.
Defend
(
ctx
,
getClaimValue
(
claim
,
pos
))
}
}
return
claim
}
func
(
g
*
OutputGameHelper
)
RootClaim
(
ctx
context
.
Context
)
*
ClaimHelper
{
claim
:=
g
.
getClaim
(
ctx
,
0
)
return
newClaimHelper
(
g
,
0
,
claim
)
}
func
(
g
*
OutputGameHelper
)
WaitForCorrectOutputRoot
(
ctx
context
.
Context
,
claimIdx
int64
)
{
...
...
@@ -138,9 +145,11 @@ 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
)
{
func
(
g
*
OutputGameHelper
)
waitForClaim
(
ctx
context
.
Context
,
errorMsg
string
,
predicate
func
(
claim
ContractClaim
)
bool
)
(
int64
,
ContractClaim
)
{
timedCtx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
defaultTimeout
)
defer
cancel
()
var
matchedClaim
ContractClaim
var
matchClaimIdx
int64
err
:=
wait
.
For
(
timedCtx
,
time
.
Second
,
func
()
(
bool
,
error
)
{
count
,
err
:=
g
.
game
.
ClaimDataLen
(
&
bind
.
CallOpts
{
Context
:
timedCtx
})
if
err
!=
nil
{
...
...
@@ -153,6 +162,8 @@ func (g *OutputGameHelper) waitForClaim(ctx context.Context, errorMsg string, pr
return
false
,
fmt
.
Errorf
(
"retrieve claim %v: %w"
,
i
,
err
)
}
if
predicate
(
claimData
)
{
matchClaimIdx
=
i
matchedClaim
=
claimData
return
true
,
nil
}
}
...
...
@@ -161,6 +172,7 @@ func (g *OutputGameHelper) waitForClaim(ctx context.Context, errorMsg string, pr
if
err
!=
nil
{
// Avoid waiting time capturing game data when there's no error
g
.
require
.
NoErrorf
(
err
,
"%v
\n
%v"
,
errorMsg
,
g
.
gameData
(
ctx
))
}
return
matchClaimIdx
,
matchedClaim
}
func
(
g
*
OutputGameHelper
)
waitForNoClaim
(
ctx
context
.
Context
,
errorMsg
string
,
predicate
func
(
claim
ContractClaim
)
bool
)
{
...
...
op-e2e/faultproofs/output_cannon_test.go
View file @
267aac82
...
...
@@ -28,33 +28,41 @@ func TestOutputCannonGame(t *testing.T) {
game
.
StartChallenger
(
ctx
,
"sequencer"
,
"Challenger"
,
challenger
.
WithPrivKey
(
sys
.
Cfg
.
Secrets
.
Alice
))
game
.
LogGameData
(
ctx
)
// Challenger should post an output root to counter claims down to the leaf level of the top game
splitDepth
:=
game
.
SplitDepth
(
ctx
)
for
i
:=
int64
(
1
);
i
<
splitDepth
;
i
+=
2
{
game
.
WaitForCorrectOutputRoot
(
ctx
,
i
)
game
.
Attack
(
ctx
,
i
,
common
.
Hash
{
0xaa
})
game
.
LogGameData
(
ctx
)
claim
:=
game
.
RootClaim
(
ctx
)
for
claim
.
IsOutputRoot
(
ctx
)
&&
!
claim
.
IsOutputRootLeaf
(
ctx
)
{
if
claim
.
AgreesWithOutputRoot
()
{
// If the latest claim agrees with the output root, expect the honest challenger to counter it
claim
=
claim
.
WaitForCounterClaim
(
ctx
)
game
.
LogGameData
(
ctx
)
claim
.
RequireCorrectOutputRoot
(
ctx
)
}
else
{
// Otherwise we should counter
claim
=
claim
.
Attack
(
ctx
,
common
.
Hash
{
0xaa
})
game
.
LogGameData
(
ctx
)
}
}
// Wait for the challenger to post the first claim in the cannon trace
game
.
WaitForClaimAtDepth
(
ctx
,
int
(
splitDepth
+
1
)
)
claim
=
claim
.
WaitForCounterClaim
(
ctx
)
game
.
LogGameData
(
ctx
)
game
.
Attack
(
ctx
,
splitDepth
+
1
,
common
.
Hash
{
0x00
,
0xcc
})
gameDepth
:=
game
.
MaxDepth
(
ctx
)
for
i
:=
splitDepth
+
3
;
i
<
gameDepth
;
i
+=
2
{
// Wait for challenger to respond
game
.
WaitForClaimAtDepth
(
ctx
,
int
(
i
))
game
.
LogGameData
(
ctx
)
// Respond to push the game down to the max depth
game
.
Defend
(
ctx
,
i
,
common
.
Hash
{
0x00
,
0xdd
})
game
.
LogGameData
(
ctx
)
// Attack the root of the cannon trace subgame
claim
=
claim
.
Attack
(
ctx
,
common
.
Hash
{
0x00
,
0xcc
})
for
!
claim
.
IsMaxDepth
(
ctx
)
{
if
claim
.
AgreesWithOutputRoot
()
{
// If the latest claim supports the output root, wait for the honest challenger to respond
claim
=
claim
.
WaitForCounterClaim
(
ctx
)
game
.
LogGameData
(
ctx
)
}
else
{
// Otherwise we need to counter the honest claim
claim
=
claim
.
Defend
(
ctx
,
common
.
Hash
{
0x00
,
0xdd
})
game
.
LogGameData
(
ctx
)
}
}
game
.
LogGameData
(
ctx
)
// Challenger should be able to call step and counter the leaf claim.
game
.
WaitForClaimAtMaxDepth
(
ctx
,
true
)
claim
.
WaitForCountered
(
ctx
)
game
.
LogGameData
(
ctx
)
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