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
b01ff541
Unverified
Commit
b01ff541
authored
Nov 16, 2023
by
Adrian Sutton
Committed by
GitHub
Nov 16, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #8159 from ethereum-optimism/aj/register-output-game
op-challenger: Start wiring up output cannon trace type
parents
c7f6938e
b12bf0ea
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
320 additions
and
71 deletions
+320
-71
config.go
op-challenger/config/config.go
+4
-0
config_test.go
op-challenger/config/config_test.go
+8
-7
register.go
op-challenger/game/fault/register.go
+83
-26
access.go
op-challenger/game/fault/trace/access.go
+5
-1
output_cannon.go
op-challenger/game/fault/trace/outputs/output_cannon.go
+26
-0
helper.go
op-e2e/e2eutils/challenger/helper.go
+41
-18
helper.go
op-e2e/e2eutils/disputegame/helper.go
+53
-19
output_cannon_helper.go
op-e2e/e2eutils/disputegame/output_cannon_helper.go
+68
-0
faultproof_test.go
op-e2e/faultproof_test.go
+32
-0
No files found.
op-challenger/config/config.go
View file @
b01ff541
...
...
@@ -34,6 +34,7 @@ var (
ErrCannonNetworkAndL2Genesis
=
errors
.
New
(
"only specify one of network or l2 genesis path"
)
ErrCannonNetworkUnknown
=
errors
.
New
(
"unknown cannon network"
)
ErrMissingRollupRpc
=
errors
.
New
(
"missing rollup rpc url"
)
ErrCannonAndOutputCannonConflict
=
errors
.
New
(
"trace types cannon and outputCannon cannot be enabled at the same time"
)
)
type
TraceType
string
...
...
@@ -187,6 +188,9 @@ func (c Config) Check() error {
return
ErrMissingRollupRpc
}
}
if
c
.
TraceTypeEnabled
(
TraceTypeCannon
)
&&
c
.
TraceTypeEnabled
(
TraceTypeOutputCannon
)
{
return
ErrCannonAndOutputCannonConflict
}
if
c
.
TraceTypeEnabled
(
TraceTypeCannon
)
||
c
.
TraceTypeEnabled
(
TraceTypeOutputCannon
)
{
if
c
.
CannonBin
==
""
{
return
ErrMissingCannonBin
...
...
op-challenger/config/config_test.go
View file @
b01ff541
...
...
@@ -135,6 +135,12 @@ func TestRollupRpcRequired(t *testing.T) {
require
.
ErrorIs
(
t
,
config
.
Check
(),
ErrMissingRollupRpc
)
}
func
TestCannotEnableBothCannonAndOutputCannonTraceTypes
(
t
*
testing
.
T
)
{
config
:=
validConfig
(
TraceTypeOutputCannon
)
config
.
TraceTypes
=
append
(
config
.
TraceTypes
,
TraceTypeCannon
)
require
.
ErrorIs
(
t
,
config
.
Check
(),
ErrCannonAndOutputCannonConflict
)
}
func
TestCannonL2Required
(
t
*
testing
.
T
)
{
config
:=
validConfig
(
TraceTypeCannon
)
config
.
CannonL2
=
""
...
...
@@ -195,19 +201,14 @@ func TestNetworkMustBeValid(t *testing.T) {
require
.
ErrorIs
(
t
,
cfg
.
Check
(),
ErrCannonNetworkUnknown
)
}
func
TestRequireConfigFor
AllSupported
TraceTypes
(
t
*
testing
.
T
)
{
func
TestRequireConfigFor
Multiple
TraceTypes
(
t
*
testing
.
T
)
{
cfg
:=
validConfig
(
TraceTypeCannon
)
cfg
.
TraceTypes
=
[]
TraceType
{
TraceTypeCannon
,
TraceType
OutputCannon
,
TraceType
Alphabet
}
cfg
.
TraceTypes
=
[]
TraceType
{
TraceTypeCannon
,
TraceTypeAlphabet
}
// Set all required options and check its valid
cfg
.
RollupRpc
=
validRollupRpc
cfg
.
AlphabetTrace
=
validAlphabetTrace
require
.
NoError
(
t
,
cfg
.
Check
())
// Require output cannon specific args
cfg
.
RollupRpc
=
""
require
.
ErrorIs
(
t
,
cfg
.
Check
(),
ErrMissingRollupRpc
)
cfg
.
RollupRpc
=
validRollupRpc
// Require cannon specific args
cfg
.
CannonL2
=
""
require
.
ErrorIs
(
t
,
cfg
.
Check
(),
ErrMissingCannonL2
)
...
...
op-challenger/game/fault/register.go
View file @
b01ff541
...
...
@@ -9,6 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/alphabet"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/cannon"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/outputs"
faultTypes
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-challenger/game/scheduler"
"github.com/ethereum-optimism/optimism/op-challenger/game/types"
...
...
@@ -20,8 +21,9 @@ import (
)
var
(
cannonGameType
=
uint8
(
0
)
alphabetGameType
=
uint8
(
255
)
cannonGameType
=
uint8
(
0
)
outputCannonGameType
=
uint8
(
0
)
// TODO(client-pod#43): This should be a unique game type
alphabetGameType
=
uint8
(
255
)
)
type
Registry
interface
{
...
...
@@ -37,35 +39,90 @@ func RegisterGameTypes(
txMgr
txmgr
.
TxManager
,
client
*
ethclient
.
Client
,
)
{
if
cfg
.
TraceTypeEnabled
(
config
.
TraceTypeOutputCannon
)
{
registerOutputCannon
(
registry
,
ctx
,
logger
,
m
,
cfg
,
txMgr
,
client
)
}
if
cfg
.
TraceTypeEnabled
(
config
.
TraceTypeCannon
)
{
resourceCreator
:=
func
(
addr
common
.
Address
,
contract
*
contracts
.
FaultDisputeGameContract
,
gameDepth
uint64
,
dir
string
)
(
faultTypes
.
TraceAccessor
,
gameValidator
,
error
)
{
logger
:=
logger
.
New
(
"game"
,
addr
)
provider
,
err
:=
cannon
.
NewTraceProvider
(
ctx
,
logger
,
m
,
cfg
,
contract
,
cannon
.
NoLocalContext
,
dir
,
gameDepth
)
if
err
!=
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"create cannon trace provider: %w"
,
err
)
}
validator
:=
func
(
ctx
context
.
Context
,
contract
*
contracts
.
FaultDisputeGameContract
)
error
{
return
ValidateAbsolutePrestate
(
ctx
,
provider
,
contract
)
}
return
trace
.
NewSimpleTraceAccessor
(
provider
),
validator
,
nil
registerCannon
(
registry
,
ctx
,
logger
,
m
,
cfg
,
txMgr
,
client
)
}
if
cfg
.
TraceTypeEnabled
(
config
.
TraceTypeAlphabet
)
{
registerAlphabet
(
registry
,
ctx
,
logger
,
m
,
cfg
,
txMgr
,
client
)
}
}
func
registerOutputCannon
(
registry
Registry
,
ctx
context
.
Context
,
logger
log
.
Logger
,
m
metrics
.
Metricer
,
cfg
*
config
.
Config
,
txMgr
txmgr
.
TxManager
,
client
*
ethclient
.
Client
)
{
resourceCreator
:=
func
(
addr
common
.
Address
,
contract
*
contracts
.
FaultDisputeGameContract
,
gameDepth
uint64
,
dir
string
)
(
faultTypes
.
TraceAccessor
,
gameValidator
,
error
)
{
logger
:=
logger
.
New
(
"game"
,
addr
)
// TODO(client-pod#43): Updated contracts should expose this as the pre and post state blocks
agreed
,
disputed
,
err
:=
contract
.
GetProposals
(
ctx
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
accessor
,
err
:=
outputs
.
NewOutputCannonTraceAccessor
(
ctx
,
logger
,
cfg
.
RollupRpc
,
gameDepth
,
agreed
.
L2BlockNumber
.
Uint64
(),
disputed
.
L2BlockNumber
.
Uint64
())
if
err
!=
nil
{
return
nil
,
nil
,
err
}
playerCreator
:=
func
(
game
types
.
GameMetadata
,
dir
string
)
(
scheduler
.
GamePlayer
,
error
)
{
return
NewGamePlayer
(
ctx
,
logger
,
m
,
cfg
,
dir
,
game
.
Proxy
,
txMgr
,
client
,
resourceCreator
)
// TODO(client-pod#44): Validate absolute pre-state for split games
noopValidator
:=
func
(
ctx
context
.
Context
,
gameContract
*
contracts
.
FaultDisputeGameContract
)
error
{
return
nil
}
re
gistry
.
RegisterGameType
(
cannonGameType
,
playerCreator
)
re
turn
accessor
,
noopValidator
,
nil
}
if
cfg
.
TraceTypeEnabled
(
config
.
TraceTypeAlphabet
)
{
resourceCreator
:=
func
(
addr
common
.
Address
,
contract
*
contracts
.
FaultDisputeGameContract
,
gameDepth
uint64
,
dir
string
)
(
faultTypes
.
TraceAccessor
,
gameValidator
,
error
)
{
provider
:=
alphabet
.
NewTraceProvider
(
cfg
.
AlphabetTrace
,
gameDepth
)
validator
:=
func
(
ctx
context
.
Context
,
contract
*
contracts
.
FaultDisputeGameContract
)
error
{
return
ValidateAbsolutePrestate
(
ctx
,
provider
,
contract
)
}
return
trace
.
NewSimpleTraceAccessor
(
provider
),
validator
,
nil
playerCreator
:=
func
(
game
types
.
GameMetadata
,
dir
string
)
(
scheduler
.
GamePlayer
,
error
)
{
return
NewGamePlayer
(
ctx
,
logger
,
m
,
cfg
,
dir
,
game
.
Proxy
,
txMgr
,
client
,
resourceCreator
)
}
registry
.
RegisterGameType
(
outputCannonGameType
,
playerCreator
)
}
func
registerCannon
(
registry
Registry
,
ctx
context
.
Context
,
logger
log
.
Logger
,
m
metrics
.
Metricer
,
cfg
*
config
.
Config
,
txMgr
txmgr
.
TxManager
,
client
*
ethclient
.
Client
)
{
resourceCreator
:=
func
(
addr
common
.
Address
,
contract
*
contracts
.
FaultDisputeGameContract
,
gameDepth
uint64
,
dir
string
)
(
faultTypes
.
TraceAccessor
,
gameValidator
,
error
)
{
logger
:=
logger
.
New
(
"game"
,
addr
)
provider
,
err
:=
cannon
.
NewTraceProvider
(
ctx
,
logger
,
m
,
cfg
,
contract
,
cannon
.
NoLocalContext
,
dir
,
gameDepth
)
if
err
!=
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"create cannon trace provider: %w"
,
err
)
}
validator
:=
func
(
ctx
context
.
Context
,
contract
*
contracts
.
FaultDisputeGameContract
)
error
{
return
ValidateAbsolutePrestate
(
ctx
,
provider
,
contract
)
}
playerCreator
:=
func
(
game
types
.
GameMetadata
,
dir
string
)
(
scheduler
.
GamePlayer
,
error
)
{
return
NewGamePlayer
(
ctx
,
logger
,
m
,
cfg
,
dir
,
game
.
Proxy
,
txMgr
,
client
,
resourceCreator
)
return
trace
.
NewSimpleTraceAccessor
(
provider
),
validator
,
nil
}
playerCreator
:=
func
(
game
types
.
GameMetadata
,
dir
string
)
(
scheduler
.
GamePlayer
,
error
)
{
return
NewGamePlayer
(
ctx
,
logger
,
m
,
cfg
,
dir
,
game
.
Proxy
,
txMgr
,
client
,
resourceCreator
)
}
registry
.
RegisterGameType
(
cannonGameType
,
playerCreator
)
}
func
registerAlphabet
(
registry
Registry
,
ctx
context
.
Context
,
logger
log
.
Logger
,
m
metrics
.
Metricer
,
cfg
*
config
.
Config
,
txMgr
txmgr
.
TxManager
,
client
*
ethclient
.
Client
)
{
resourceCreator
:=
func
(
addr
common
.
Address
,
contract
*
contracts
.
FaultDisputeGameContract
,
gameDepth
uint64
,
dir
string
)
(
faultTypes
.
TraceAccessor
,
gameValidator
,
error
)
{
provider
:=
alphabet
.
NewTraceProvider
(
cfg
.
AlphabetTrace
,
gameDepth
)
validator
:=
func
(
ctx
context
.
Context
,
contract
*
contracts
.
FaultDisputeGameContract
)
error
{
return
ValidateAbsolutePrestate
(
ctx
,
provider
,
contract
)
}
registry
.
RegisterGameType
(
alphabetGameType
,
playerCreator
)
return
trace
.
NewSimpleTraceAccessor
(
provider
),
validator
,
nil
}
playerCreator
:=
func
(
game
types
.
GameMetadata
,
dir
string
)
(
scheduler
.
GamePlayer
,
error
)
{
return
NewGamePlayer
(
ctx
,
logger
,
m
,
cfg
,
dir
,
game
.
Proxy
,
txMgr
,
client
,
resourceCreator
)
}
registry
.
RegisterGameType
(
alphabetGameType
,
playerCreator
)
}
op-challenger/game/fault/trace/access.go
View file @
b01ff541
...
...
@@ -11,11 +11,15 @@ func NewSimpleTraceAccessor(trace types.TraceProvider) *Accessor {
selector
:=
func
(
_
context
.
Context
,
_
types
.
Game
,
_
types
.
Claim
,
_
types
.
Position
)
(
types
.
TraceProvider
,
error
)
{
return
trace
,
nil
}
return
&
Accessor
{
selector
}
return
NewAccessor
(
selector
)
}
type
ProviderSelector
func
(
ctx
context
.
Context
,
game
types
.
Game
,
ref
types
.
Claim
,
pos
types
.
Position
)
(
types
.
TraceProvider
,
error
)
func
NewAccessor
(
selector
ProviderSelector
)
*
Accessor
{
return
&
Accessor
{
selector
}
}
type
Accessor
struct
{
selector
ProviderSelector
}
...
...
op-challenger/game/fault/trace/outputs/output_cannon.go
0 → 100644
View file @
b01ff541
package
outputs
import
(
"context"
"errors"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum/go-ethereum/log"
)
func
NewOutputCannonTraceAccessor
(
ctx
context
.
Context
,
logger
log
.
Logger
,
rollupRpc
string
,
gameDepth
uint64
,
prestateBlock
uint64
,
poststateBlock
uint64
)
(
*
trace
.
Accessor
,
error
)
{
topDepth
:=
gameDepth
/
2
// TODO(client-pod#43): Load this from the contract
outputProvider
,
err
:=
NewTraceProvider
(
ctx
,
logger
,
rollupRpc
,
topDepth
,
prestateBlock
,
poststateBlock
)
if
err
!=
nil
{
return
nil
,
err
}
cannonCreator
:=
func
(
ctx
context
.
Context
,
pre
types
.
Claim
,
post
types
.
Claim
)
(
types
.
TraceProvider
,
error
)
{
// TODO(client-pod#43): Actually create the cannon trace provider for the trace between the given claims.
return
nil
,
errors
.
New
(
"not implemented"
)
}
selector
:=
newSplitProviderSelector
(
outputProvider
,
int
(
topDepth
),
cannonCreator
)
return
trace
.
NewAccessor
(
selector
),
nil
}
op-e2e/e2eutils/challenger/helper.go
View file @
b01ff541
...
...
@@ -78,25 +78,48 @@ func WithCannon(
l2Endpoint
string
,
)
Option
{
return
func
(
c
*
config
.
Config
)
{
require
:=
require
.
New
(
t
)
c
.
TraceTypes
=
append
(
c
.
TraceTypes
,
config
.
TraceTypeCannon
)
c
.
CannonL2
=
l2Endpoint
c
.
CannonBin
=
"../cannon/bin/cannon"
c
.
CannonServer
=
"../op-program/bin/op-program"
c
.
CannonAbsolutePreState
=
"../op-program/bin/prestate.json"
c
.
CannonSnapshotFreq
=
10
_000_000
genesisBytes
,
err
:=
json
.
Marshal
(
l2Genesis
)
require
.
NoError
(
err
,
"marshall l2 genesis config"
)
genesisFile
:=
filepath
.
Join
(
c
.
Datadir
,
"l2-genesis.json"
)
require
.
NoError
(
os
.
WriteFile
(
genesisFile
,
genesisBytes
,
0644
))
c
.
CannonL2GenesisPath
=
genesisFile
rollupBytes
,
err
:=
json
.
Marshal
(
rollupCfg
)
require
.
NoError
(
err
,
"marshall rollup config"
)
rollupFile
:=
filepath
.
Join
(
c
.
Datadir
,
"rollup.json"
)
require
.
NoError
(
os
.
WriteFile
(
rollupFile
,
rollupBytes
,
0644
))
c
.
CannonRollupConfigPath
=
rollupFile
applyCannonConfig
(
c
,
t
,
rollupCfg
,
l2Genesis
,
l2Endpoint
)
}
}
func
applyCannonConfig
(
c
*
config
.
Config
,
t
*
testing
.
T
,
rollupCfg
*
rollup
.
Config
,
l2Genesis
*
core
.
Genesis
,
l2Endpoint
string
,
)
{
require
:=
require
.
New
(
t
)
c
.
CannonL2
=
l2Endpoint
c
.
CannonBin
=
"../cannon/bin/cannon"
c
.
CannonServer
=
"../op-program/bin/op-program"
c
.
CannonAbsolutePreState
=
"../op-program/bin/prestate.json"
c
.
CannonSnapshotFreq
=
10
_000_000
genesisBytes
,
err
:=
json
.
Marshal
(
l2Genesis
)
require
.
NoError
(
err
,
"marshall l2 genesis config"
)
genesisFile
:=
filepath
.
Join
(
c
.
Datadir
,
"l2-genesis.json"
)
require
.
NoError
(
os
.
WriteFile
(
genesisFile
,
genesisBytes
,
0644
))
c
.
CannonL2GenesisPath
=
genesisFile
rollupBytes
,
err
:=
json
.
Marshal
(
rollupCfg
)
require
.
NoError
(
err
,
"marshall rollup config"
)
rollupFile
:=
filepath
.
Join
(
c
.
Datadir
,
"rollup.json"
)
require
.
NoError
(
os
.
WriteFile
(
rollupFile
,
rollupBytes
,
0644
))
c
.
CannonRollupConfigPath
=
rollupFile
}
func
WithOutputCannon
(
t
*
testing
.
T
,
rollupCfg
*
rollup
.
Config
,
l2Genesis
*
core
.
Genesis
,
rollupEndpoint
string
,
l2Endpoint
string
)
Option
{
return
func
(
c
*
config
.
Config
)
{
c
.
TraceTypes
=
append
(
c
.
TraceTypes
,
config
.
TraceTypeOutputCannon
)
c
.
RollupRpc
=
rollupEndpoint
applyCannonConfig
(
c
,
t
,
rollupCfg
,
l2Genesis
,
l2Endpoint
)
}
}
...
...
op-e2e/e2eutils/disputegame/helper.go
View file @
b01ff541
...
...
@@ -21,6 +21,7 @@ import (
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/dial"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -33,6 +34,7 @@ import (
const
alphabetGameType
uint8
=
255
const
cannonGameType
uint8
=
0
const
outputCannonGameType
uint8
=
0
// TODO(client-pod#43): This should be a unique game type
const
alphabetGameDepth
=
4
var
lastAlphabetTraceIndex
=
big
.
NewInt
(
1
<<
alphabetGameDepth
-
1
)
...
...
@@ -101,8 +103,7 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, deployments *genesis.L1
}
func
(
h
*
FactoryHelper
)
StartAlphabetGame
(
ctx
context
.
Context
,
claimedAlphabet
string
)
*
AlphabetGameHelper
{
l2BlockNumber
:=
h
.
waitForProposals
(
ctx
)
l1Head
:=
h
.
checkpointL1Block
(
ctx
)
extraData
,
_
,
_
:=
h
.
createDisputeGameExtraData
(
ctx
)
ctx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
2
*
time
.
Minute
)
defer
cancel
()
...
...
@@ -111,9 +112,6 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s
pos
:=
faultTypes
.
NewPosition
(
alphabetGameDepth
,
lastAlphabetTraceIndex
)
rootClaim
,
err
:=
trace
.
Get
(
ctx
,
pos
)
h
.
require
.
NoError
(
err
,
"get root claim"
)
extraData
:=
make
([]
byte
,
64
)
binary
.
BigEndian
.
PutUint64
(
extraData
[
24
:
],
l2BlockNumber
)
binary
.
BigEndian
.
PutUint64
(
extraData
[
56
:
],
l1Head
.
Uint64
())
tx
,
err
:=
transactions
.
PadGasEstimate
(
h
.
opts
,
2
,
func
(
opts
*
bind
.
TransactOpts
)
(
*
types
.
Transaction
,
error
)
{
return
h
.
factory
.
Create
(
opts
,
alphabetGameType
,
rootClaim
,
extraData
)
})
...
...
@@ -141,13 +139,49 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s
}
}
func
(
h
*
FactoryHelper
)
StartOutputCannonGame
(
ctx
context
.
Context
,
rollupEndpoint
string
,
rootClaim
common
.
Hash
)
*
OutputCannonGameHelper
{
extraData
,
_
,
_
:=
h
.
createDisputeGameExtraData
(
ctx
)
ctx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
1
*
time
.
Minute
)
defer
cancel
()
tx
,
err
:=
transactions
.
PadGasEstimate
(
h
.
opts
,
2
,
func
(
opts
*
bind
.
TransactOpts
)
(
*
types
.
Transaction
,
error
)
{
return
h
.
factory
.
Create
(
opts
,
outputCannonGameType
,
rootClaim
,
extraData
)
})
h
.
require
.
NoError
(
err
,
"create fault dispute game"
)
rcpt
,
err
:=
wait
.
ForReceiptOK
(
ctx
,
h
.
client
,
tx
.
Hash
())
h
.
require
.
NoError
(
err
,
"wait for create fault dispute game receipt to be OK"
)
h
.
require
.
Len
(
rcpt
.
Logs
,
1
,
"should have emitted a single DisputeGameCreated event"
)
createdEvent
,
err
:=
h
.
factory
.
ParseDisputeGameCreated
(
*
rcpt
.
Logs
[
0
])
h
.
require
.
NoError
(
err
)
game
,
err
:=
bindings
.
NewFaultDisputeGame
(
createdEvent
.
DisputeProxy
,
h
.
client
)
h
.
require
.
NoError
(
err
)
rollupClient
,
err
:=
dial
.
DialRollupClientWithTimeout
(
ctx
,
30
*
time
.
Second
,
testlog
.
Logger
(
h
.
t
,
log
.
LvlInfo
),
rollupEndpoint
)
h
.
require
.
NoError
(
err
)
return
&
OutputCannonGameHelper
{
FaultGameHelper
:
FaultGameHelper
{
t
:
h
.
t
,
require
:
h
.
require
,
client
:
h
.
client
,
opts
:
h
.
opts
,
game
:
game
,
factoryAddr
:
h
.
factoryAddr
,
addr
:
createdEvent
.
DisputeProxy
,
},
rollupClient
:
rollupClient
,
}
}
func
(
h
*
FactoryHelper
)
StartCannonGame
(
ctx
context
.
Context
,
rootClaim
common
.
Hash
)
*
CannonGameHelper
{
l2BlockNumber
,
l1Head
:=
h
.
prepareCannonGame
(
ctx
)
return
h
.
createCannonGame
(
ctx
,
l2BlockNumber
,
l1Head
,
rootClaim
)
extraData
,
_
,
_
:=
h
.
createDisputeGameExtraData
(
ctx
)
return
h
.
createCannonGame
(
ctx
,
rootClaim
,
extraData
)
}
func
(
h
*
FactoryHelper
)
StartCannonGameWithCorrectRoot
(
ctx
context
.
Context
,
rollupCfg
*
rollup
.
Config
,
l2Genesis
*
core
.
Genesis
,
l1Endpoint
string
,
l2Endpoint
string
,
options
...
challenger
.
Option
)
(
*
CannonGameHelper
,
*
HonestHelper
)
{
l2BlockNumber
,
l1Head
:=
h
.
prepareCannonGame
(
ctx
)
extraData
,
l1Head
,
l2BlockNumber
:=
h
.
createDisputeGameExtraData
(
ctx
)
challengerOpts
:=
[]
challenger
.
Option
{
challenger
.
WithCannon
(
h
.
t
,
rollupCfg
,
l2Genesis
,
l2Endpoint
),
challenger
.
WithFactoryAddress
(
h
.
factoryAddr
),
...
...
@@ -202,7 +236,7 @@ func (h *FactoryHelper) StartCannonGameWithCorrectRoot(ctx context.Context, roll
// Otherwise creating the game will fail
rootClaim
[
0
]
=
mipsevm
.
VMStatusInvalid
game
:=
h
.
createCannonGame
(
ctx
,
l2BlockNumber
,
l1Head
,
rootClaim
)
game
:=
h
.
createCannonGame
(
ctx
,
rootClaim
,
extraData
)
correctMaxDepth
:=
game
.
MaxDepth
(
ctx
)
provider
.
SetMaxDepth
(
uint64
(
correctMaxDepth
))
honestHelper
:=
&
HonestHelper
{
...
...
@@ -214,13 +248,10 @@ func (h *FactoryHelper) StartCannonGameWithCorrectRoot(ctx context.Context, roll
return
game
,
honestHelper
}
func
(
h
*
FactoryHelper
)
createCannonGame
(
ctx
context
.
Context
,
l2BlockNumber
uint64
,
l1Head
*
big
.
Int
,
rootClaim
common
.
Hash
)
*
CannonGameHelper
{
func
(
h
*
FactoryHelper
)
createCannonGame
(
ctx
context
.
Context
,
rootClaim
common
.
Hash
,
extraData
[]
byte
)
*
CannonGameHelper
{
ctx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
1
*
time
.
Minute
)
defer
cancel
()
extraData
:=
make
([]
byte
,
64
)
binary
.
BigEndian
.
PutUint64
(
extraData
[
24
:
],
l2BlockNumber
)
binary
.
BigEndian
.
PutUint64
(
extraData
[
56
:
],
l1Head
.
Uint64
())
tx
,
err
:=
transactions
.
PadGasEstimate
(
h
.
opts
,
2
,
func
(
opts
*
bind
.
TransactOpts
)
(
*
types
.
Transaction
,
error
)
{
return
h
.
factory
.
Create
(
opts
,
cannonGameType
,
rootClaim
,
extraData
)
})
...
...
@@ -246,6 +277,15 @@ func (h *FactoryHelper) createCannonGame(ctx context.Context, l2BlockNumber uint
}
}
func
(
h
*
FactoryHelper
)
createDisputeGameExtraData
(
ctx
context
.
Context
)
(
extraData
[]
byte
,
l1Head
*
big
.
Int
,
l2BlockNumber
uint64
)
{
l2BlockNumber
=
h
.
waitForProposals
(
ctx
)
l1Head
=
h
.
checkpointL1Block
(
ctx
)
extraData
=
make
([]
byte
,
64
)
binary
.
BigEndian
.
PutUint64
(
extraData
[
24
:
],
l2BlockNumber
)
binary
.
BigEndian
.
PutUint64
(
extraData
[
56
:
],
l1Head
.
Uint64
())
return
}
func
(
h
*
FactoryHelper
)
StartChallenger
(
ctx
context
.
Context
,
l1Endpoint
string
,
name
string
,
options
...
challenger
.
Option
)
*
challenger
.
Helper
{
opts
:=
[]
challenger
.
Option
{
challenger
.
WithFactoryAddress
(
h
.
factoryAddr
),
...
...
@@ -258,12 +298,6 @@ func (h *FactoryHelper) StartChallenger(ctx context.Context, l1Endpoint string,
return
c
}
func
(
h
*
FactoryHelper
)
prepareCannonGame
(
ctx
context
.
Context
)
(
uint64
,
*
big
.
Int
)
{
l2BlockNumber
:=
h
.
waitForProposals
(
ctx
)
l1Head
:=
h
.
checkpointL1Block
(
ctx
)
return
l2BlockNumber
,
l1Head
}
// waitForProposals waits until there are at least two proposals in the output oracle
// This is the minimum required for creating a game.
// Returns the l2 block number of the latest available proposal
...
...
op-e2e/e2eutils/disputegame/output_cannon_helper.go
0 → 100644
View file @
b01ff541
package
disputegame
import
(
"context"
"math/big"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core"
)
type
OutputCannonGameHelper
struct
{
FaultGameHelper
rollupClient
*
sources
.
RollupClient
}
func
(
g
*
OutputCannonGameHelper
)
StartChallenger
(
ctx
context
.
Context
,
rollupCfg
*
rollup
.
Config
,
l2Genesis
*
core
.
Genesis
,
rollupEndpoint
string
,
l1Endpoint
string
,
l2Endpoint
string
,
name
string
,
options
...
challenger
.
Option
,
)
*
challenger
.
Helper
{
opts
:=
[]
challenger
.
Option
{
challenger
.
WithOutputCannon
(
g
.
t
,
rollupCfg
,
l2Genesis
,
rollupEndpoint
,
l2Endpoint
),
challenger
.
WithFactoryAddress
(
g
.
factoryAddr
),
challenger
.
WithGameAddress
(
g
.
addr
),
}
opts
=
append
(
opts
,
options
...
)
c
:=
challenger
.
NewChallenger
(
g
.
t
,
ctx
,
l1Endpoint
,
name
,
opts
...
)
g
.
t
.
Cleanup
(
func
()
{
_
=
c
.
Close
()
})
return
c
}
func
(
g
*
OutputCannonGameHelper
)
WaitForCorrectOutputRoot
(
ctx
context
.
Context
,
claimIdx
int64
)
{
g
.
WaitForClaimCount
(
ctx
,
claimIdx
+
1
)
claim
:=
g
.
getClaim
(
ctx
,
claimIdx
)
err
,
blockNum
:=
g
.
blockNumForClaim
(
ctx
,
claim
)
g
.
require
.
NoError
(
err
)
output
,
err
:=
g
.
rollupClient
.
OutputAtBlock
(
ctx
,
blockNum
)
g
.
require
.
NoErrorf
(
err
,
"Failed to get output at block %v"
,
blockNum
)
g
.
require
.
EqualValuesf
(
output
.
OutputRoot
,
claim
.
Claim
,
"Incorrect output root at claim %v. Expected to be from block %v"
,
claimIdx
,
blockNum
)
}
func
(
g
*
OutputCannonGameHelper
)
blockNumForClaim
(
ctx
context
.
Context
,
claim
ContractClaim
)
(
error
,
uint64
)
{
proposals
,
err
:=
g
.
game
.
Proposals
(
&
bind
.
CallOpts
{
Context
:
ctx
})
g
.
require
.
NoError
(
err
,
"failed to retrieve proposals"
)
prestateBlockNum
:=
proposals
.
Starting
.
L2BlockNumber
disputedBlockNum
:=
proposals
.
Disputed
.
L2BlockNumber
gameDepth
:=
g
.
MaxDepth
(
ctx
)
// TODO(client-pod#43): Load this from the contract
topDepth
:=
gameDepth
/
2
traceIdx
:=
types
.
NewPositionFromGIndex
(
claim
.
Position
)
.
TraceIndex
(
int
(
topDepth
))
blockNum
:=
new
(
big
.
Int
)
.
Add
(
prestateBlockNum
,
traceIdx
)
.
Uint64
()
+
1
if
blockNum
>
disputedBlockNum
.
Uint64
()
{
blockNum
=
disputedBlockNum
.
Uint64
()
}
return
err
,
blockNum
}
op-e2e/faultproof_test.go
View file @
b01ff541
...
...
@@ -592,6 +592,38 @@ func TestCannonChallengeWithCorrectRoot(t *testing.T) {
require
.
EqualValues
(
t
,
disputegame
.
StatusChallengerWins
,
game
.
Status
(
ctx
))
}
func
TestOutputCannonGame
(
t
*
testing
.
T
)
{
InitParallel
(
t
,
UsesCannon
,
UseExecutor
(
0
))
ctx
:=
context
.
Background
()
sys
,
l1Client
:=
startFaultDisputeSystem
(
t
)
t
.
Cleanup
(
sys
.
Close
)
rollupEndpoint
:=
sys
.
RollupNodes
[
"sequencer"
]
.
HTTPEndpoint
()
l1Endpoint
:=
sys
.
NodeEndpoint
(
"l1"
)
l2Endpoint
:=
sys
.
NodeEndpoint
(
"sequencer"
)
require
.
NotEqual
(
t
,
rollupEndpoint
,
l2Endpoint
)
disputeGameFactory
:=
disputegame
.
NewFactoryHelper
(
t
,
ctx
,
sys
.
cfg
.
L1Deployments
,
l1Client
)
game
:=
disputeGameFactory
.
StartOutputCannonGame
(
ctx
,
rollupEndpoint
,
common
.
Hash
{
0x01
})
game
.
LogGameData
(
ctx
)
game
.
StartChallenger
(
ctx
,
sys
.
RollupConfig
,
sys
.
L2GenesisCfg
,
rollupEndpoint
,
l1Endpoint
,
l2Endpoint
,
"Challenger"
,
// Agree with the proposed output, so disagree with the root claim
challenger
.
WithAgreeProposedOutput
(
true
),
challenger
.
WithPrivKey
(
sys
.
cfg
.
Secrets
.
Alice
),
)
game
.
LogGameData
(
ctx
)
maxDepth
:=
game
.
MaxDepth
(
ctx
)
// Challenger should post an output root to counter claims down to the leaf level of the top game
// TODO(client-pod#43): Load the depth of the top game from the contract instead of deriving it
for
i
:=
int64
(
1
);
i
<=
maxDepth
/
2
+
1
;
i
+=
2
{
game
.
WaitForCorrectOutputRoot
(
ctx
,
i
)
game
.
Attack
(
ctx
,
i
,
common
.
Hash
{
0xaa
})
game
.
LogGameData
(
ctx
)
}
}
func
startFaultDisputeSystem
(
t
*
testing
.
T
)
(
*
System
,
*
ethclient
.
Client
)
{
cfg
:=
DefaultSystemConfig
(
t
)
delete
(
cfg
.
Nodes
,
"verifier"
)
...
...
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