Commit d0a63191 authored by clabby's avatar clabby Committed by GitHub

feat(ctb): Clock extensions (#10182)

* feat(ctb): Clock extensions

* Add configurable clock extension immutable

locks,bindings,etc.

comment fixes

x

* `clockExtension` config checks

* feat(ctb): Enforce max supported depth in `FaultDisputeGame` constructor

## Overview

Enforces the max supported depth of the `LibPosition` library's
implemented functionality on the `Position` type in the
`FaultDisputeGame`'s constructor

* use clock dur * 2 in bond monitor
parent 34a44375
...@@ -130,7 +130,7 @@ def init_devnet_l1_deploy_config(paths, update_timestamp=False): ...@@ -130,7 +130,7 @@ def init_devnet_l1_deploy_config(paths, update_timestamp=False):
deploy_config['l1GenesisBlockTimestamp'] = '{:#x}'.format(int(time.time())) deploy_config['l1GenesisBlockTimestamp'] = '{:#x}'.format(int(time.time()))
if DEVNET_FPAC: if DEVNET_FPAC:
deploy_config['useFaultProofs'] = True deploy_config['useFaultProofs'] = True
deploy_config['faultGameMaxDuration'] = 10 deploy_config['faultGameMaxClockDuration'] = 10
deploy_config['faultGameWithdrawalDelay'] = 0 deploy_config['faultGameWithdrawalDelay'] = 0
if DEVNET_PLASMA: if DEVNET_PLASMA:
deploy_config['usePlasma'] = True deploy_config['usePlasma'] = True
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -210,10 +210,12 @@ type DeployConfig struct { ...@@ -210,10 +210,12 @@ type DeployConfig struct {
// supports. Ideally, this should be conservatively set so that there is always enough // supports. Ideally, this should be conservatively set so that there is always enough
// room for a full Cannon trace. // room for a full Cannon trace.
FaultGameMaxDepth uint64 `json:"faultGameMaxDepth"` FaultGameMaxDepth uint64 `json:"faultGameMaxDepth"`
// FaultGameMaxDuration is the maximum amount of time (in seconds) that the fault dispute // FaultGameClockExtension is the amount of time that the dispute game will set the potential grandchild claim's,
// game can run for before it is ready to be resolved. Each side receives half of this value // clock to, if the remaining time is less than this value at the time of a claim's creation.
// on their chess clock at the inception of the dispute. FaultGameClockExtension uint64 `json:"faultGameClockExtension"`
FaultGameMaxDuration uint64 `json:"faultGameMaxDuration"` // FaultGameMaxClockDuration is the maximum amount of time that may accumulate on a team's chess clock before they
// may no longer respond.
FaultGameMaxClockDuration uint64 `json:"faultGameMaxClockDuration"`
// FaultGameGenesisBlock is the block number for genesis. // FaultGameGenesisBlock is the block number for genesis.
FaultGameGenesisBlock uint64 `json:"faultGameGenesisBlock"` FaultGameGenesisBlock uint64 `json:"faultGameGenesisBlock"`
// FaultGameGenesisOutputRoot is the output root for the genesis block. // FaultGameGenesisOutputRoot is the output root for the genesis block.
......
...@@ -69,7 +69,8 @@ ...@@ -69,7 +69,8 @@
"fundDevAccounts": true, "fundDevAccounts": true,
"faultGameAbsolutePrestate": "0x0000000000000000000000000000000000000000000000000000000000000000", "faultGameAbsolutePrestate": "0x0000000000000000000000000000000000000000000000000000000000000000",
"faultGameMaxDepth": 63, "faultGameMaxDepth": 63,
"faultGameMaxDuration": 604800, "faultGameClockExtension": 10800,
"faultGameMaxClockDuration": 302400,
"faultGameGenesisBlock": 0, "faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"faultGameSplitDepth": 0, "faultGameSplitDepth": 0,
......
...@@ -33,17 +33,17 @@ type ClaimLoader interface { ...@@ -33,17 +33,17 @@ type ClaimLoader interface {
} }
type Agent struct { type Agent struct {
metrics metrics.Metricer metrics metrics.Metricer
systemClock clock.Clock systemClock clock.Clock
l1Clock types.ClockReader l1Clock types.ClockReader
solver *solver.GameSolver solver *solver.GameSolver
loader ClaimLoader loader ClaimLoader
responder Responder responder Responder
selective bool selective bool
claimants []common.Address claimants []common.Address
maxDepth types.Depth maxDepth types.Depth
gameDuration time.Duration maxClockDuration time.Duration
log log.Logger log log.Logger
} }
func NewAgent( func NewAgent(
...@@ -52,7 +52,7 @@ func NewAgent( ...@@ -52,7 +52,7 @@ func NewAgent(
l1Clock types.ClockReader, l1Clock types.ClockReader,
loader ClaimLoader, loader ClaimLoader,
maxDepth types.Depth, maxDepth types.Depth,
gameDuration time.Duration, maxClockDuration time.Duration,
trace types.TraceAccessor, trace types.TraceAccessor,
responder Responder, responder Responder,
log log.Logger, log log.Logger,
...@@ -60,17 +60,17 @@ func NewAgent( ...@@ -60,17 +60,17 @@ func NewAgent(
claimants []common.Address, claimants []common.Address,
) *Agent { ) *Agent {
return &Agent{ return &Agent{
metrics: m, metrics: m,
systemClock: systemClock, systemClock: systemClock,
l1Clock: l1Clock, l1Clock: l1Clock,
solver: solver.NewGameSolver(maxDepth, trace), solver: solver.NewGameSolver(maxDepth, trace),
loader: loader, loader: loader,
responder: responder, responder: responder,
selective: selective, selective: selective,
claimants: claimants, claimants: claimants,
maxDepth: maxDepth, maxDepth: maxDepth,
gameDuration: gameDuration, maxClockDuration: maxClockDuration,
log: log, log: log,
} }
} }
...@@ -163,11 +163,10 @@ func (a *Agent) tryResolveClaims(ctx context.Context) error { ...@@ -163,11 +163,10 @@ func (a *Agent) tryResolveClaims(ctx context.Context) error {
if len(claims) == 0 { if len(claims) == 0 {
return errNoResolvableClaims return errNoResolvableClaims
} }
maxChessTime := a.gameDuration / 2
var resolvableClaims []uint64 var resolvableClaims []uint64
for _, claim := range claims { for _, claim := range claims {
if claim.ChessTime(a.l1Clock.Now()) <= maxChessTime { if claim.ChessTime(a.l1Clock.Now()) <= a.maxClockDuration {
continue continue
} }
if a.selective { if a.selective {
......
...@@ -139,7 +139,7 @@ func TestSkipAttemptingToResolveClaimsWhenClockNotExpired(t *testing.T) { ...@@ -139,7 +139,7 @@ func TestSkipAttemptingToResolveClaimsWhenClockNotExpired(t *testing.T) {
claimBuilder := test.NewClaimBuilder(t, depth, alphabet.NewTraceProvider(big.NewInt(0), depth)) claimBuilder := test.NewClaimBuilder(t, depth, alphabet.NewTraceProvider(big.NewInt(0), depth))
claimLoader.claims = []types.Claim{ claimLoader.claims = []types.Claim{
claimBuilder.CreateRootClaim(test.WithExpiredClock(agent.gameDuration)), claimBuilder.CreateRootClaim(test.WithExpiredClock(agent.maxClockDuration)),
} }
require.NoError(t, agent.Act(context.Background())) require.NoError(t, agent.Act(context.Background()))
...@@ -170,7 +170,7 @@ func setupTestAgent(t *testing.T) (*Agent, *stubClaimLoader, *stubResponder) { ...@@ -170,7 +170,7 @@ func setupTestAgent(t *testing.T) (*Agent, *stubClaimLoader, *stubResponder) {
logger := testlog.Logger(t, log.LevelInfo) logger := testlog.Logger(t, log.LevelInfo)
claimLoader := &stubClaimLoader{} claimLoader := &stubClaimLoader{}
depth := types.Depth(4) depth := types.Depth(4)
gameDuration := 6 * time.Minute gameDuration := 3 * time.Minute
provider := alphabet.NewTraceProvider(big.NewInt(0), depth) provider := alphabet.NewTraceProvider(big.NewInt(0), depth)
responder := &stubResponder{} responder := &stubResponder{}
systemClock := clock.NewDeterministicClock(time.UnixMilli(120200)) systemClock := clock.NewDeterministicClock(time.UnixMilli(120200))
......
...@@ -19,7 +19,7 @@ import ( ...@@ -19,7 +19,7 @@ import (
) )
var ( var (
methodGameDuration = "gameDuration" methodMaxClockDuration = "maxClockDuration"
methodMaxGameDepth = "maxGameDepth" methodMaxGameDepth = "maxGameDepth"
methodAbsolutePrestate = "absolutePrestate" methodAbsolutePrestate = "absolutePrestate"
methodStatus = "status" methodStatus = "status"
...@@ -107,7 +107,7 @@ func (f *FaultDisputeGameContract) GetBlockRange(ctx context.Context) (prestateB ...@@ -107,7 +107,7 @@ func (f *FaultDisputeGameContract) GetBlockRange(ctx context.Context) (prestateB
return return
} }
// GetGameMetadata returns the game's L1 head, L2 block number, root claim, status, and game duration. // GetGameMetadata returns the game's L1 head, L2 block number, root claim, status, and max clock duration.
func (f *FaultDisputeGameContract) GetGameMetadata(ctx context.Context, block rpcblock.Block) (common.Hash, uint64, common.Hash, gameTypes.GameStatus, uint64, error) { func (f *FaultDisputeGameContract) GetGameMetadata(ctx context.Context, block rpcblock.Block) (common.Hash, uint64, common.Hash, gameTypes.GameStatus, uint64, error) {
defer f.metrics.StartContractRequest("GetGameMetadata")() defer f.metrics.StartContractRequest("GetGameMetadata")()
results, err := f.multiCaller.Call(ctx, block, results, err := f.multiCaller.Call(ctx, block,
...@@ -115,7 +115,7 @@ func (f *FaultDisputeGameContract) GetGameMetadata(ctx context.Context, block rp ...@@ -115,7 +115,7 @@ func (f *FaultDisputeGameContract) GetGameMetadata(ctx context.Context, block rp
f.contract.Call(methodL2BlockNumber), f.contract.Call(methodL2BlockNumber),
f.contract.Call(methodRootClaim), f.contract.Call(methodRootClaim),
f.contract.Call(methodStatus), f.contract.Call(methodStatus),
f.contract.Call(methodGameDuration)) f.contract.Call(methodMaxClockDuration))
if err != nil { if err != nil {
return common.Hash{}, 0, common.Hash{}, 0, 0, fmt.Errorf("failed to retrieve game metadata: %w", err) return common.Hash{}, 0, common.Hash{}, 0, 0, fmt.Errorf("failed to retrieve game metadata: %w", err)
} }
...@@ -274,11 +274,11 @@ func (f *FaultDisputeGameContract) GetOracle(ctx context.Context) (*PreimageOrac ...@@ -274,11 +274,11 @@ func (f *FaultDisputeGameContract) GetOracle(ctx context.Context) (*PreimageOrac
return vm.Oracle(ctx) return vm.Oracle(ctx)
} }
func (f *FaultDisputeGameContract) GetGameDuration(ctx context.Context) (time.Duration, error) { func (f *FaultDisputeGameContract) GetMaxClockDuration(ctx context.Context) (time.Duration, error) {
defer f.metrics.StartContractRequest("GetGameDuration")() defer f.metrics.StartContractRequest("GetMaxClockDuration")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodGameDuration)) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodMaxClockDuration))
if err != nil { if err != nil {
return 0, fmt.Errorf("failed to fetch game duration: %w", err) return 0, fmt.Errorf("failed to fetch max clock duration: %w", err)
} }
return time.Duration(result.GetUint64(0)) * time.Second, nil return time.Duration(result.GetUint64(0)) * time.Second, nil
} }
......
...@@ -44,12 +44,12 @@ func TestSimpleGetters(t *testing.T) { ...@@ -44,12 +44,12 @@ func TestSimpleGetters(t *testing.T) {
}, },
}, },
{ {
methodAlias: "gameDuration", methodAlias: "maxClockDuration",
method: methodGameDuration, method: methodMaxClockDuration,
result: uint64(5566), result: uint64(5566),
expected: 5566 * time.Second, expected: 5566 * time.Second,
call: func(game *FaultDisputeGameContract) (any, error) { call: func(game *FaultDisputeGameContract) (any, error) {
return game.GetGameDuration(context.Background()) return game.GetMaxClockDuration(context.Background())
}, },
}, },
{ {
...@@ -341,7 +341,7 @@ func TestGetGameMetadata(t *testing.T) { ...@@ -341,7 +341,7 @@ func TestGetGameMetadata(t *testing.T) {
stubRpc, contract := setupFaultDisputeGameTest(t) stubRpc, contract := setupFaultDisputeGameTest(t)
expectedL1Head := common.Hash{0x0a, 0x0b} expectedL1Head := common.Hash{0x0a, 0x0b}
expectedL2BlockNumber := uint64(123) expectedL2BlockNumber := uint64(123)
expectedGameDuration := uint64(456) expectedMaxClockDuration := uint64(456)
expectedRootClaim := common.Hash{0x01, 0x02} expectedRootClaim := common.Hash{0x01, 0x02}
expectedStatus := types.GameStatusChallengerWon expectedStatus := types.GameStatusChallengerWon
block := rpcblock.ByNumber(889) block := rpcblock.ByNumber(889)
...@@ -349,14 +349,14 @@ func TestGetGameMetadata(t *testing.T) { ...@@ -349,14 +349,14 @@ func TestGetGameMetadata(t *testing.T) {
stubRpc.SetResponse(fdgAddr, methodL2BlockNumber, block, nil, []interface{}{new(big.Int).SetUint64(expectedL2BlockNumber)}) stubRpc.SetResponse(fdgAddr, methodL2BlockNumber, block, nil, []interface{}{new(big.Int).SetUint64(expectedL2BlockNumber)})
stubRpc.SetResponse(fdgAddr, methodRootClaim, block, nil, []interface{}{expectedRootClaim}) stubRpc.SetResponse(fdgAddr, methodRootClaim, block, nil, []interface{}{expectedRootClaim})
stubRpc.SetResponse(fdgAddr, methodStatus, block, nil, []interface{}{expectedStatus}) stubRpc.SetResponse(fdgAddr, methodStatus, block, nil, []interface{}{expectedStatus})
stubRpc.SetResponse(fdgAddr, methodGameDuration, block, nil, []interface{}{expectedGameDuration}) stubRpc.SetResponse(fdgAddr, methodMaxClockDuration, block, nil, []interface{}{expectedMaxClockDuration})
l1Head, l2BlockNumber, rootClaim, status, duration, err := contract.GetGameMetadata(context.Background(), block) l1Head, l2BlockNumber, rootClaim, status, duration, err := contract.GetGameMetadata(context.Background(), block)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, expectedL1Head, l1Head) require.Equal(t, expectedL1Head, l1Head)
require.Equal(t, expectedL2BlockNumber, l2BlockNumber) require.Equal(t, expectedL2BlockNumber, l2BlockNumber)
require.Equal(t, expectedRootClaim, rootClaim) require.Equal(t, expectedRootClaim, rootClaim)
require.Equal(t, expectedStatus, status) require.Equal(t, expectedStatus, status)
require.Equal(t, expectedGameDuration, duration) require.Equal(t, expectedMaxClockDuration, duration)
} }
func TestGetStartingRootHash(t *testing.T) { func TestGetStartingRootHash(t *testing.T) {
......
...@@ -59,7 +59,7 @@ type GameContract interface { ...@@ -59,7 +59,7 @@ type GameContract interface {
ClaimLoader ClaimLoader
GetStatus(ctx context.Context) (gameTypes.GameStatus, error) GetStatus(ctx context.Context) (gameTypes.GameStatus, error)
GetMaxGameDepth(ctx context.Context) (types.Depth, error) GetMaxGameDepth(ctx context.Context) (types.Depth, error)
GetGameDuration(ctx context.Context) (time.Duration, error) GetMaxClockDuration(ctx context.Context) (time.Duration, error)
GetOracle(ctx context.Context) (*contracts.PreimageOracleContract, error) GetOracle(ctx context.Context) (*contracts.PreimageOracleContract, error)
GetL1Head(ctx context.Context) (common.Hash, error) GetL1Head(ctx context.Context) (common.Hash, error)
} }
...@@ -104,7 +104,7 @@ func NewGamePlayer( ...@@ -104,7 +104,7 @@ func NewGamePlayer(
}, nil }, nil
} }
gameDuration, err := loader.GetGameDuration(ctx) maxClockDuration, err := loader.GetMaxClockDuration(ctx)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch the game duration: %w", err) return nil, fmt.Errorf("failed to fetch the game duration: %w", err)
} }
...@@ -146,7 +146,7 @@ func NewGamePlayer( ...@@ -146,7 +146,7 @@ func NewGamePlayer(
return nil, fmt.Errorf("failed to create the responder: %w", err) return nil, fmt.Errorf("failed to create the responder: %w", err)
} }
agent := NewAgent(m, systemClock, l1Clock, loader, gameDepth, gameDuration, accessor, responder, logger, selective, claimants) agent := NewAgent(m, systemClock, l1Clock, loader, gameDepth, maxClockDuration, accessor, responder, logger, selective, claimants)
return &GamePlayer{ return &GamePlayer{
act: agent.Act, act: agent.Act,
loader: loader, loader: loader,
......
...@@ -63,9 +63,10 @@ func WithParent(claim types.Claim) ClaimOpt { ...@@ -63,9 +63,10 @@ func WithParent(claim types.Claim) ClaimOpt {
cfg.parentIdx = claim.ContractIndex cfg.parentIdx = claim.ContractIndex
}) })
} }
func WithExpiredClock(gameDuration time.Duration) ClaimOpt {
func WithExpiredClock(maxClockDuration time.Duration) ClaimOpt {
return claimOptFn(func(cfg *claimCfg) { return claimOptFn(func(cfg *claimCfg) {
cfg.clockDuration = gameDuration / 2 cfg.clockDuration = maxClockDuration
}) })
} }
......
...@@ -47,7 +47,7 @@ func (b *Bonds) CheckBonds(games []*types.EnrichedGameData) { ...@@ -47,7 +47,7 @@ func (b *Bonds) CheckBonds(games []*types.EnrichedGameData) {
func (b *Bonds) checkCredits(game *types.EnrichedGameData) { func (b *Bonds) checkCredits(game *types.EnrichedGameData) {
// Check if the max duration has been reached for this game // Check if the max duration has been reached for this game
duration := uint64(b.clock.Now().Unix()) - game.Timestamp duration := uint64(b.clock.Now().Unix()) - game.Timestamp
maxDurationReached := duration >= game.Duration maxDurationReached := duration >= game.MaxClockDuration*2
// Iterate over claims and filter out resolved ones // Iterate over claims and filter out resolved ones
recipients := make(map[int]common.Address) recipients := make(map[int]common.Address)
......
...@@ -60,7 +60,7 @@ func (c *ClaimMonitor) checkGameClaims( ...@@ -60,7 +60,7 @@ func (c *ClaimMonitor) checkGameClaims(
) { ) {
// Check if the game is in the first half // Check if the game is in the first half
duration := uint64(c.clock.Now().Unix()) - game.Timestamp duration := uint64(c.clock.Now().Unix()) - game.Timestamp
firstHalf := duration <= (game.Duration / 2) firstHalf := duration <= game.MaxClockDuration
// Iterate over the game's claims // Iterate over the game's claims
for _, claim := range game.Claims { for _, claim := range game.Claims {
...@@ -74,7 +74,7 @@ func (c *ClaimMonitor) checkGameClaims( ...@@ -74,7 +74,7 @@ func (c *ClaimMonitor) checkGameClaims(
c.logger.Error("Claim resolved in the first half of the game duration", "game", game.Proxy, "claimContractIndex", claim.ContractIndex) c.logger.Error("Claim resolved in the first half of the game duration", "game", game.Proxy, "claimContractIndex", claim.ContractIndex)
} }
maxChessTime := time.Duration(game.Duration/2) * time.Second maxChessTime := time.Duration(game.MaxClockDuration) * time.Second
accumulatedTime := claim.ChessTime(c.clock.Now()) accumulatedTime := claim.ChessTime(c.clock.Now())
clockExpired := accumulatedTime >= maxChessTime clockExpired := accumulatedTime >= maxChessTime
......
...@@ -53,8 +53,8 @@ func newTestClaimMonitor(t *testing.T) (*ClaimMonitor, *clock.DeterministicClock ...@@ -53,8 +53,8 @@ func newTestClaimMonitor(t *testing.T) (*ClaimMonitor, *clock.DeterministicClock
cl := clock.NewDeterministicClock(frozen) cl := clock.NewDeterministicClock(frozen)
metrics := &stubClaimMetrics{} metrics := &stubClaimMetrics{}
honestActors := []common.Address{ honestActors := []common.Address{
common.Address{0x01}, {0x01},
common.Address{0x02}, {0x02},
} }
return NewClaimMonitor(logger, cl, honestActors, metrics), cl, metrics return NewClaimMonitor(logger, cl, honestActors, metrics), cl, metrics
} }
...@@ -87,11 +87,11 @@ func makeMultipleTestGames(duration uint64) []*types.EnrichedGameData { ...@@ -87,11 +87,11 @@ func makeMultipleTestGames(duration uint64) []*types.EnrichedGameData {
func makeTestGame(duration uint64) *types.EnrichedGameData { func makeTestGame(duration uint64) *types.EnrichedGameData {
return &types.EnrichedGameData{ return &types.EnrichedGameData{
Duration: duration, MaxClockDuration: duration / 2,
Recipients: map[common.Address]bool{ Recipients: map[common.Address]bool{
common.Address{0x02}: true, {0x02}: true,
common.Address{0x03}: true, {0x03}: true,
common.Address{0x04}: true, {0x04}: true,
}, },
Claims: []types.EnrichedClaim{ Claims: []types.EnrichedClaim{
{ {
......
...@@ -12,8 +12,10 @@ import ( ...@@ -12,8 +12,10 @@ import (
monTypes "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types" monTypes "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
) )
type CreateGameCaller func(game gameTypes.GameMetadata) (GameCaller, error) type (
type FactoryGameFetcher func(ctx context.Context, blockHash common.Hash, earliestTimestamp uint64) ([]gameTypes.GameMetadata, error) CreateGameCaller func(game gameTypes.GameMetadata) (GameCaller, error)
FactoryGameFetcher func(ctx context.Context, blockHash common.Hash, earliestTimestamp uint64) ([]gameTypes.GameMetadata, error)
)
type Enricher interface { type Enricher interface {
Enrich(ctx context.Context, block rpcblock.Block, caller GameCaller, game *monTypes.EnrichedGameData) error Enrich(ctx context.Context, block rpcblock.Block, caller GameCaller, game *monTypes.EnrichedGameData) error
...@@ -66,13 +68,13 @@ func (e *Extractor) enrichGames(ctx context.Context, blockHash common.Hash, game ...@@ -66,13 +68,13 @@ func (e *Extractor) enrichGames(ctx context.Context, blockHash common.Hash, game
enrichedClaims[i] = monTypes.EnrichedClaim{Claim: claim} enrichedClaims[i] = monTypes.EnrichedClaim{Claim: claim}
} }
enrichedGame := &monTypes.EnrichedGameData{ enrichedGame := &monTypes.EnrichedGameData{
GameMetadata: game, GameMetadata: game,
L1Head: l1Head, L1Head: l1Head,
L2BlockNumber: l2BlockNum, L2BlockNumber: l2BlockNum,
RootClaim: rootClaim, RootClaim: rootClaim,
Status: status, Status: status,
Duration: duration, MaxClockDuration: duration,
Claims: enrichedClaims, Claims: enrichedClaims,
} }
if err := e.applyEnrichers(ctx, blockHash, caller, enrichedGame); err != nil { if err := e.applyEnrichers(ctx, blockHash, caller, enrichedGame); err != nil {
e.logger.Error("Failed to enrich game", "err", err) e.logger.Error("Failed to enrich game", "err", err)
......
...@@ -34,16 +34,16 @@ func (d *DelayCalculator) RecordClaimResolutionDelayMax(games []*types.EnrichedG ...@@ -34,16 +34,16 @@ func (d *DelayCalculator) RecordClaimResolutionDelayMax(games []*types.EnrichedG
func (d *DelayCalculator) getMaxResolutionDelay(game *types.EnrichedGameData) uint64 { func (d *DelayCalculator) getMaxResolutionDelay(game *types.EnrichedGameData) uint64 {
var maxDelay uint64 = 0 var maxDelay uint64 = 0
for _, claim := range game.Claims { for _, claim := range game.Claims {
maxDelay = max(d.getOverflowTime(game.Duration, &claim), maxDelay) maxDelay = max(d.getOverflowTime(game.MaxClockDuration, &claim), maxDelay)
} }
return maxDelay return maxDelay
} }
func (d *DelayCalculator) getOverflowTime(maxGameDuration uint64, claim *types.EnrichedClaim) uint64 { func (d *DelayCalculator) getOverflowTime(maxClockDuration uint64, claim *types.EnrichedClaim) uint64 {
if claim.Resolved { if claim.Resolved {
return 0 return 0
} }
maxChessTime := time.Duration(maxGameDuration/2) * time.Second maxChessTime := time.Duration(maxClockDuration) * time.Second
accumulatedTime := claim.ChessTime(d.clock.Now()) accumulatedTime := claim.ChessTime(d.clock.Now())
if accumulatedTime < maxChessTime { if accumulatedTime < maxChessTime {
return 0 return 0
......
...@@ -12,8 +12,8 @@ import ( ...@@ -12,8 +12,8 @@ import (
) )
var ( var (
maxGameDuration = uint64(960) maxClockDuration = uint64(480)
frozen = time.Unix(int64(time.Hour.Seconds()), 0) frozen = time.Unix(int64(time.Hour.Seconds()), 0)
) )
func TestDelayCalculator_getOverflowTime(t *testing.T) { func TestDelayCalculator_getOverflowTime(t *testing.T) {
...@@ -22,7 +22,7 @@ func TestDelayCalculator_getOverflowTime(t *testing.T) { ...@@ -22,7 +22,7 @@ func TestDelayCalculator_getOverflowTime(t *testing.T) {
claim := &monTypes.EnrichedClaim{ claim := &monTypes.EnrichedClaim{
Resolved: true, Resolved: true,
} }
delay := d.getOverflowTime(maxGameDuration, claim) delay := d.getOverflowTime(maxClockDuration, claim)
require.Equal(t, uint64(0), delay) require.Equal(t, uint64(0), delay)
require.Equal(t, 0, metrics.calls) require.Equal(t, 0, metrics.calls)
}) })
...@@ -39,14 +39,14 @@ func TestDelayCalculator_getOverflowTime(t *testing.T) { ...@@ -39,14 +39,14 @@ func TestDelayCalculator_getOverflowTime(t *testing.T) {
Clock: types.NewClock(duration, timestamp), Clock: types.NewClock(duration, timestamp),
}, },
} }
delay := d.getOverflowTime(maxGameDuration, claim) delay := d.getOverflowTime(maxClockDuration, claim)
require.Equal(t, uint64(0), delay) require.Equal(t, uint64(0), delay)
require.Equal(t, 0, metrics.calls) require.Equal(t, 0, metrics.calls)
}) })
t.Run("OverflowTime", func(t *testing.T) { t.Run("OverflowTime", func(t *testing.T) {
d, metrics, cl := setupDelayCalculatorTest(t) d, metrics, cl := setupDelayCalculatorTest(t)
duration := time.Duration(maxGameDuration/2) * time.Second duration := time.Duration(maxClockDuration) * time.Second
timestamp := cl.Now().Add(4 * -time.Minute) timestamp := cl.Now().Add(4 * -time.Minute)
claim := &monTypes.EnrichedClaim{ claim := &monTypes.EnrichedClaim{
Claim: types.Claim{ Claim: types.Claim{
...@@ -56,7 +56,7 @@ func TestDelayCalculator_getOverflowTime(t *testing.T) { ...@@ -56,7 +56,7 @@ func TestDelayCalculator_getOverflowTime(t *testing.T) {
Clock: types.NewClock(duration, timestamp), Clock: types.NewClock(duration, timestamp),
}, },
} }
delay := d.getOverflowTime(maxGameDuration, claim) delay := d.getOverflowTime(maxClockDuration, claim)
require.Equal(t, uint64(240), delay) require.Equal(t, uint64(240), delay)
require.Equal(t, 0, metrics.calls) require.Equal(t, 0, metrics.calls)
}) })
...@@ -79,8 +79,8 @@ func TestDelayCalculator_getMaxResolutionDelay(t *testing.T) { ...@@ -79,8 +79,8 @@ func TestDelayCalculator_getMaxResolutionDelay(t *testing.T) {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
d, metrics, _ := setupDelayCalculatorTest(t) d, metrics, _ := setupDelayCalculatorTest(t)
game := &monTypes.EnrichedGameData{ game := &monTypes.EnrichedGameData{
Claims: test.claims, Claims: test.claims,
Duration: maxGameDuration, MaxClockDuration: maxClockDuration,
} }
got := d.getMaxResolutionDelay(game) got := d.getMaxResolutionDelay(game)
require.Equal(t, 0, metrics.calls) require.Equal(t, 0, metrics.calls)
...@@ -121,23 +121,23 @@ func setupDelayCalculatorTest(t *testing.T) (*DelayCalculator, *mockDelayMetrics ...@@ -121,23 +121,23 @@ func setupDelayCalculatorTest(t *testing.T) (*DelayCalculator, *mockDelayMetrics
func createGameWithClaimsList() []*monTypes.EnrichedGameData { func createGameWithClaimsList() []*monTypes.EnrichedGameData {
return []*monTypes.EnrichedGameData{ return []*monTypes.EnrichedGameData{
{ {
Claims: createClaimList()[:1], Claims: createClaimList()[:1],
Duration: maxGameDuration, MaxClockDuration: maxClockDuration,
}, },
{ {
Claims: createClaimList()[:2], Claims: createClaimList()[:2],
Duration: maxGameDuration, MaxClockDuration: maxClockDuration,
}, },
{ {
Claims: createClaimList(), Claims: createClaimList(),
Duration: maxGameDuration, MaxClockDuration: maxClockDuration,
}, },
} }
} }
func createClaimList() []monTypes.EnrichedClaim { func createClaimList() []monTypes.EnrichedClaim {
newClock := func(multiplier int) types.Clock { newClock := func(multiplier int) types.Clock {
duration := maxGameDuration / 2 duration := maxClockDuration
timestamp := frozen.Add(-time.Minute * time.Duration(multiplier)) timestamp := frozen.Add(-time.Minute * time.Duration(multiplier))
return types.NewClock(time.Duration(duration)*time.Second, timestamp) return types.NewClock(time.Duration(duration)*time.Second, timestamp)
} }
......
...@@ -52,7 +52,7 @@ func (r *ResolutionMonitor) CheckResolutions(games []*types.EnrichedGameData) { ...@@ -52,7 +52,7 @@ func (r *ResolutionMonitor) CheckResolutions(games []*types.EnrichedGameData) {
for _, game := range games { for _, game := range games {
complete := game.Status != gameTypes.GameStatusInProgress complete := game.Status != gameTypes.GameStatusInProgress
duration := uint64(r.clock.Now().Unix()) - game.Timestamp duration := uint64(r.clock.Now().Unix()) - game.Timestamp
maxDurationReached := duration >= game.Duration maxDurationReached := duration >= game.MaxClockDuration
status.Inc(complete, maxDurationReached) status.Inc(complete, maxDurationReached)
} }
r.metrics.RecordGameResolutionStatus(true, true, status.completeMaxDuration) r.metrics.RecordGameResolutionStatus(true, true, status.completeMaxDuration)
......
...@@ -45,7 +45,7 @@ func (s *stubResolutionMetrics) RecordGameResolutionStatus(complete bool, maxDur ...@@ -45,7 +45,7 @@ func (s *stubResolutionMetrics) RecordGameResolutionStatus(complete bool, maxDur
func newTestGames(duration uint64) []*types.EnrichedGameData { func newTestGames(duration uint64) []*types.EnrichedGameData {
newTestGame := func(duration uint64, status gameTypes.GameStatus) *types.EnrichedGameData { newTestGame := func(duration uint64, status gameTypes.GameStatus) *types.EnrichedGameData {
return &types.EnrichedGameData{Duration: duration, Status: status} return &types.EnrichedGameData{MaxClockDuration: duration, Status: status}
} }
return []*types.EnrichedGameData{ return []*types.EnrichedGameData{
newTestGame(duration, gameTypes.GameStatusInProgress), newTestGame(duration, gameTypes.GameStatusInProgress),
......
...@@ -17,13 +17,13 @@ type EnrichedClaim struct { ...@@ -17,13 +17,13 @@ type EnrichedClaim struct {
type EnrichedGameData struct { type EnrichedGameData struct {
types.GameMetadata types.GameMetadata
L1Head common.Hash L1Head common.Hash
L1HeadNum uint64 L1HeadNum uint64
L2BlockNumber uint64 L2BlockNumber uint64
RootClaim common.Hash RootClaim common.Hash
Status types.GameStatus Status types.GameStatus
Duration uint64 MaxClockDuration uint64
Claims []EnrichedClaim Claims []EnrichedClaim
// Recipients maps addresses to true if they are a bond recipient in the game. // Recipients maps addresses to true if they are a bond recipient in the game.
Recipients map[common.Address]bool Recipients map[common.Address]bool
......
...@@ -564,7 +564,7 @@ func (s *CrossLayerUser) ResolveClaim(t Testing, l2TxHash common.Hash) common.Ha ...@@ -564,7 +564,7 @@ func (s *CrossLayerUser) ResolveClaim(t Testing, l2TxHash common.Hash) common.Ha
game, err := s.getDisputeGame(t, *params) game, err := s.getDisputeGame(t, *params)
require.NoError(t, err) require.NoError(t, err)
expiry, err := game.GameDuration(&bind.CallOpts{}) expiry, err := game.MaxClockDuration(&bind.CallOpts{})
require.Nil(t, err) require.Nil(t, err)
time.Sleep(time.Duration(expiry) * time.Second) time.Sleep(time.Duration(expiry) * time.Second)
......
...@@ -32,9 +32,9 @@ func (g *FaultGameHelper) Addr() common.Address { ...@@ -32,9 +32,9 @@ func (g *FaultGameHelper) Addr() common.Address {
return g.addr return g.addr
} }
func (g *FaultGameHelper) GameDuration(ctx context.Context) time.Duration { func (g *FaultGameHelper) MaxClockDuration(ctx context.Context) time.Duration {
duration, err := g.game.GameDuration(&bind.CallOpts{Context: ctx}) duration, err := g.game.MaxClockDuration(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "failed to get game duration") g.require.NoError(err, "failed to get max clock duration")
return time.Duration(duration) * time.Second return time.Duration(duration) * time.Second
} }
......
...@@ -161,9 +161,9 @@ func (g *OutputGameHelper) correctOutputRoot(ctx context.Context, pos types.Posi ...@@ -161,9 +161,9 @@ func (g *OutputGameHelper) correctOutputRoot(ctx context.Context, pos types.Posi
return outputRoot return outputRoot
} }
func (g *OutputGameHelper) GameDuration(ctx context.Context) time.Duration { func (g *OutputGameHelper) MaxClockDuration(ctx context.Context) time.Duration {
duration, err := g.game.GameDuration(&bind.CallOpts{Context: ctx}) duration, err := g.game.MaxClockDuration(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "failed to get game duration") g.require.NoError(err, "failed to get max clock duration")
return time.Duration(duration) * time.Second return time.Duration(duration) * time.Second
} }
......
...@@ -67,7 +67,7 @@ func TestOutputAlphabetGame_ChallengerWins(t *testing.T) { ...@@ -67,7 +67,7 @@ func TestOutputAlphabetGame_ChallengerWins(t *testing.T) {
claim.WaitForCountered(ctx) claim.WaitForCountered(ctx)
game.LogGameData(ctx) game.LogGameData(ctx)
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins) game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
game.LogGameData(ctx) game.LogGameData(ctx)
...@@ -109,7 +109,7 @@ func TestOutputAlphabetGame_ReclaimBond(t *testing.T) { ...@@ -109,7 +109,7 @@ func TestOutputAlphabetGame_ReclaimBond(t *testing.T) {
balance = game.WethBalance(ctx, game.Addr()) balance = game.WethBalance(ctx, game.Addr())
require.Truef(t, balance.Cmp(big.NewInt(0)) > 0, "Expected game balance to be above zero") require.Truef(t, balance.Cmp(big.NewInt(0)) > 0, "Expected game balance to be above zero")
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins) game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
game.LogGameData(ctx) game.LogGameData(ctx)
...@@ -160,7 +160,7 @@ func TestOutputAlphabetGame_ValidOutputRoot(t *testing.T) { ...@@ -160,7 +160,7 @@ func TestOutputAlphabetGame_ValidOutputRoot(t *testing.T) {
game.LogGameData(ctx) game.LogGameData(ctx)
} }
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForGameStatus(ctx, disputegame.StatusDefenderWins) game.WaitForGameStatus(ctx, disputegame.StatusDefenderWins)
} }
...@@ -210,7 +210,7 @@ func TestChallengerCompleteExhaustiveDisputeGame(t *testing.T) { ...@@ -210,7 +210,7 @@ func TestChallengerCompleteExhaustiveDisputeGame(t *testing.T) {
// Wait for 4 blocks of no challenger responses. The challenger may still be stepping on invalid claims at max depth // Wait for 4 blocks of no challenger responses. The challenger may still be stepping on invalid claims at max depth
game.WaitForInactivity(ctx, 4, false) game.WaitForInactivity(ctx, 4, false)
gameDuration := game.GameDuration(ctx) gameDuration := game.MaxClockDuration(ctx)
sys.TimeTravelClock.AdvanceTime(gameDuration) sys.TimeTravelClock.AdvanceTime(gameDuration)
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
...@@ -287,7 +287,7 @@ func TestOutputAlphabetGame_FreeloaderEarnsNothing(t *testing.T) { ...@@ -287,7 +287,7 @@ func TestOutputAlphabetGame_FreeloaderEarnsNothing(t *testing.T) {
} }
game.LogGameData(ctx) game.LogGameData(ctx)
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForGameStatus(ctx, disputegame.StatusDefenderWins) game.WaitForGameStatus(ctx, disputegame.StatusDefenderWins)
......
...@@ -68,7 +68,7 @@ func TestOutputCannonGame(t *testing.T) { ...@@ -68,7 +68,7 @@ func TestOutputCannonGame(t *testing.T) {
claim.WaitForCountered(ctx) claim.WaitForCountered(ctx)
game.LogGameData(ctx) game.LogGameData(ctx)
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins) game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
} }
...@@ -96,7 +96,7 @@ func TestOutputCannon_ChallengeAllZeroClaim(t *testing.T) { ...@@ -96,7 +96,7 @@ func TestOutputCannon_ChallengeAllZeroClaim(t *testing.T) {
game.LogGameData(ctx) game.LogGameData(ctx)
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins) game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
game.LogGameData(ctx) game.LogGameData(ctx)
...@@ -171,7 +171,7 @@ func TestOutputCannonDisputeGame(t *testing.T) { ...@@ -171,7 +171,7 @@ func TestOutputCannonDisputeGame(t *testing.T) {
} }
}) })
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.LogGameData(ctx) game.LogGameData(ctx)
...@@ -208,7 +208,7 @@ func TestOutputCannonDefendStep(t *testing.T) { ...@@ -208,7 +208,7 @@ func TestOutputCannonDefendStep(t *testing.T) {
} }
}) })
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForInactivity(ctx, 10, true) game.WaitForInactivity(ctx, 10, true)
...@@ -426,7 +426,7 @@ func TestOutputCannonProposedOutputRootValid(t *testing.T) { ...@@ -426,7 +426,7 @@ func TestOutputCannonProposedOutputRootValid(t *testing.T) {
}) })
// Time travel past when the game will be resolvable. // Time travel past when the game will be resolvable.
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForInactivity(ctx, 10, true) game.WaitForInactivity(ctx, 10, true)
...@@ -493,7 +493,7 @@ func TestOutputCannonPoisonedPostState(t *testing.T) { ...@@ -493,7 +493,7 @@ func TestOutputCannonPoisonedPostState(t *testing.T) {
claimToIgnore2.RequireOnlyCounteredBy(ctx /* nothing */) claimToIgnore2.RequireOnlyCounteredBy(ctx /* nothing */)
// Time travel past when the game will be resolvable. // Time travel past when the game will be resolvable.
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.LogGameData(ctx) game.LogGameData(ctx)
...@@ -543,7 +543,7 @@ func TestDisputeOutputRootBeyondProposedBlock_ValidOutputRoot(t *testing.T) { ...@@ -543,7 +543,7 @@ func TestDisputeOutputRootBeyondProposedBlock_ValidOutputRoot(t *testing.T) {
correctTrace.StepClaimFails(ctx, claim, false) correctTrace.StepClaimFails(ctx, claim, false)
// Time travel past when the game will be resolvable. // Time travel past when the game will be resolvable.
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForGameStatus(ctx, disputegame.StatusDefenderWins) game.WaitForGameStatus(ctx, disputegame.StatusDefenderWins)
...@@ -594,7 +594,7 @@ func TestDisputeOutputRootBeyondProposedBlock_InvalidOutputRoot(t *testing.T) { ...@@ -594,7 +594,7 @@ func TestDisputeOutputRootBeyondProposedBlock_InvalidOutputRoot(t *testing.T) {
claim.WaitForCountered(ctx) claim.WaitForCountered(ctx)
// Time travel past when the game will be resolvable. // Time travel past when the game will be resolvable.
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins) game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
...@@ -654,7 +654,7 @@ func TestDisputeOutputRoot_ChangeClaimedOutputRoot(t *testing.T) { ...@@ -654,7 +654,7 @@ func TestDisputeOutputRoot_ChangeClaimedOutputRoot(t *testing.T) {
claim.WaitForCountered(ctx) claim.WaitForCountered(ctx)
// Time travel past when the game will be resolvable. // Time travel past when the game will be resolvable.
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins) game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
...@@ -714,7 +714,7 @@ func TestInvalidateUnsafeProposal(t *testing.T) { ...@@ -714,7 +714,7 @@ func TestInvalidateUnsafeProposal(t *testing.T) {
}) })
// Time travel past when the game will be resolvable. // Time travel past when the game will be resolvable.
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins) game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
...@@ -776,7 +776,7 @@ func TestInvalidateProposalForFutureBlock(t *testing.T) { ...@@ -776,7 +776,7 @@ func TestInvalidateProposalForFutureBlock(t *testing.T) {
}) })
// Time travel past when the game will be resolvable. // Time travel past when the game will be resolvable.
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client)) require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins) game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
......
...@@ -200,7 +200,7 @@ func FinalizeWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Clie ...@@ -200,7 +200,7 @@ func FinalizeWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Clie
proxy, err := bindings.NewFaultDisputeGame(game.DisputeGameProxy, l1Client) proxy, err := bindings.NewFaultDisputeGame(game.DisputeGameProxy, l1Client)
require.Nil(t, err) require.Nil(t, err)
expiry, err := proxy.GameDuration(&bind.CallOpts{}) expiry, err := proxy.MaxClockDuration(&bind.CallOpts{})
require.Nil(t, err) require.Nil(t, err)
time.Sleep(time.Duration(expiry) * time.Second) time.Sleep(time.Duration(expiry) * time.Second)
......
...@@ -51,7 +51,8 @@ ...@@ -51,7 +51,8 @@
"recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000", "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
"faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98", "faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98",
"faultGameMaxDepth": 50, "faultGameMaxDepth": 50,
"faultGameMaxDuration": 2400, "faultGameClockExtension": 0,
"faultGameMaxClockDuration": 1200,
"faultGameGenesisBlock": 0, "faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", "faultGameGenesisOutputRoot": "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
"faultGameSplitDepth": 14, "faultGameSplitDepth": 14,
......
...@@ -45,7 +45,8 @@ ...@@ -45,7 +45,8 @@
"fundDevAccounts": false, "fundDevAccounts": false,
"faultGameAbsolutePrestate": "0x03e1255457128b9afd9acf93239c1d477bdff88624901f9ca8fe0783b756dbe0", "faultGameAbsolutePrestate": "0x03e1255457128b9afd9acf93239c1d477bdff88624901f9ca8fe0783b756dbe0",
"faultGameMaxDepth": 73, "faultGameMaxDepth": 73,
"faultGameMaxDuration": 604800, "faultGameClockExtension": 10800,
"faultGameMaxClockDuration": 302400,
"faultGameGenesisBlock": 4061224, "faultGameGenesisBlock": 4061224,
"faultGameGenesisOutputRoot": "0xd08055c58b2c5149565c636b44fad2c25b5ccddef1385a2cb721529d7480b242", "faultGameGenesisOutputRoot": "0xd08055c58b2c5149565c636b44fad2c25b5ccddef1385a2cb721529d7480b242",
"faultGameSplitDepth": 32, "faultGameSplitDepth": 32,
......
...@@ -47,7 +47,8 @@ ...@@ -47,7 +47,8 @@
"recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000", "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
"faultGameAbsolutePrestate": "0x0000000000000000000000000000000000000000000000000000000000000000", "faultGameAbsolutePrestate": "0x0000000000000000000000000000000000000000000000000000000000000000",
"faultGameMaxDepth": 8, "faultGameMaxDepth": 8,
"faultGameMaxDuration": 2400, "faultGameClockExtension": 0,
"faultGameMaxClockDuration": 1200,
"faultGameGenesisBlock": 0, "faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", "faultGameGenesisOutputRoot": "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
"faultGameSplitDepth": 4, "faultGameSplitDepth": 4,
......
...@@ -70,7 +70,8 @@ ...@@ -70,7 +70,8 @@
"systemConfigStartBlock": 4071248, "systemConfigStartBlock": 4071248,
"faultGameAbsolutePrestate": "0x031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f808", "faultGameAbsolutePrestate": "0x031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f808",
"faultGameMaxDepth": 73, "faultGameMaxDepth": 73,
"faultGameMaxDuration": 604800, "faultGameClockExtension": 10800,
"faultGameMaxClockDuration": 302400,
"faultGameGenesisBlock": 0, "faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0x91bd00ecd596a86c9f4e12c0646578e77022881c87c06ec6aa31e656d2730688", "faultGameGenesisOutputRoot": "0x91bd00ecd596a86c9f4e12c0646578e77022881c87c06ec6aa31e656d2730688",
"faultGameSplitDepth": 30, "faultGameSplitDepth": 30,
......
...@@ -45,7 +45,8 @@ ...@@ -45,7 +45,8 @@
"fundDevAccounts": false, "fundDevAccounts": false,
"faultGameAbsolutePrestate": "0x031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f808", "faultGameAbsolutePrestate": "0x031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f808",
"faultGameMaxDepth": 73, "faultGameMaxDepth": 73,
"faultGameMaxDuration": 604800, "faultGameClockExtension": 10800,
"faultGameMaxClockDuration": 302400,
"faultGameGenesisBlock": 9496192, "faultGameGenesisBlock": 9496192,
"faultGameGenesisOutputRoot": "0x63b1cda487c072b020a57c1203f7c2921754005cadbd54bed7f558111b8278d8", "faultGameGenesisOutputRoot": "0x63b1cda487c072b020a57c1203f7c2921754005cadbd54bed7f558111b8278d8",
"faultGameSplitDepth": 30, "faultGameSplitDepth": 30,
......
...@@ -1363,7 +1363,8 @@ contract Deploy is Deployer { ...@@ -1363,7 +1363,8 @@ contract Deploy is Deployer {
_absolutePrestate: _params.absolutePrestate, _absolutePrestate: _params.absolutePrestate,
_maxGameDepth: _params.maxGameDepth, _maxGameDepth: _params.maxGameDepth,
_splitDepth: cfg.faultGameSplitDepth(), _splitDepth: cfg.faultGameSplitDepth(),
_gameDuration: Duration.wrap(uint64(cfg.faultGameMaxDuration())), _clockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())),
_maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())),
_vm: _params.faultVm, _vm: _params.faultVm,
_weth: _params.weth, _weth: _params.weth,
_anchorStateRegistry: _params.anchorStateRegistry, _anchorStateRegistry: _params.anchorStateRegistry,
...@@ -1378,7 +1379,8 @@ contract Deploy is Deployer { ...@@ -1378,7 +1379,8 @@ contract Deploy is Deployer {
_absolutePrestate: _params.absolutePrestate, _absolutePrestate: _params.absolutePrestate,
_maxGameDepth: _params.maxGameDepth, _maxGameDepth: _params.maxGameDepth,
_splitDepth: cfg.faultGameSplitDepth(), _splitDepth: cfg.faultGameSplitDepth(),
_gameDuration: Duration.wrap(uint64(cfg.faultGameMaxDuration())), _clockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())),
_maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())),
_vm: _params.faultVm, _vm: _params.faultVm,
_weth: _params.weth, _weth: _params.weth,
_anchorStateRegistry: _params.anchorStateRegistry, _anchorStateRegistry: _params.anchorStateRegistry,
......
...@@ -55,7 +55,8 @@ contract DeployConfig is Script { ...@@ -55,7 +55,8 @@ contract DeployConfig is Script {
bytes32 public faultGameGenesisOutputRoot; bytes32 public faultGameGenesisOutputRoot;
uint256 public faultGameMaxDepth; uint256 public faultGameMaxDepth;
uint256 public faultGameSplitDepth; uint256 public faultGameSplitDepth;
uint256 public faultGameMaxDuration; uint256 public faultGameClockExtension;
uint256 public faultGameMaxClockDuration;
uint256 public faultGameWithdrawalDelay; uint256 public faultGameWithdrawalDelay;
uint256 public preimageOracleMinProposalSize; uint256 public preimageOracleMinProposalSize;
uint256 public preimageOracleChallengePeriod; uint256 public preimageOracleChallengePeriod;
...@@ -128,7 +129,8 @@ contract DeployConfig is Script { ...@@ -128,7 +129,8 @@ contract DeployConfig is Script {
faultGameAbsolutePrestate = stdJson.readUint(_json, "$.faultGameAbsolutePrestate"); faultGameAbsolutePrestate = stdJson.readUint(_json, "$.faultGameAbsolutePrestate");
faultGameMaxDepth = stdJson.readUint(_json, "$.faultGameMaxDepth"); faultGameMaxDepth = stdJson.readUint(_json, "$.faultGameMaxDepth");
faultGameSplitDepth = stdJson.readUint(_json, "$.faultGameSplitDepth"); faultGameSplitDepth = stdJson.readUint(_json, "$.faultGameSplitDepth");
faultGameMaxDuration = stdJson.readUint(_json, "$.faultGameMaxDuration"); faultGameClockExtension = stdJson.readUint(_json, "$.faultGameClockExtension");
faultGameMaxClockDuration = stdJson.readUint(_json, "$.faultGameMaxClockDuration");
faultGameGenesisBlock = stdJson.readUint(_json, "$.faultGameGenesisBlock"); faultGameGenesisBlock = stdJson.readUint(_json, "$.faultGameGenesisBlock");
faultGameGenesisOutputRoot = stdJson.readBytes32(_json, "$.faultGameGenesisOutputRoot"); faultGameGenesisOutputRoot = stdJson.readBytes32(_json, "$.faultGameGenesisOutputRoot");
faultGameWithdrawalDelay = stdJson.readUint(_json, "$.faultGameWithdrawalDelay"); faultGameWithdrawalDelay = stdJson.readUint(_json, "$.faultGameWithdrawalDelay");
......
...@@ -181,7 +181,8 @@ contract FPACOPS is Deploy, StdAssertions { ...@@ -181,7 +181,8 @@ contract FPACOPS is Deploy, StdAssertions {
FaultDisputeGame gameImpl = FaultDisputeGame(payable(address(dgfProxy.gameImpls(GameTypes.CANNON)))); FaultDisputeGame gameImpl = FaultDisputeGame(payable(address(dgfProxy.gameImpls(GameTypes.CANNON))));
assertEq(gameImpl.maxGameDepth(), cfg.faultGameMaxDepth()); assertEq(gameImpl.maxGameDepth(), cfg.faultGameMaxDepth());
assertEq(gameImpl.splitDepth(), cfg.faultGameSplitDepth()); assertEq(gameImpl.splitDepth(), cfg.faultGameSplitDepth());
assertEq(gameImpl.gameDuration().raw(), cfg.faultGameMaxDuration()); assertEq(gameImpl.clockExtension().raw(), cfg.faultGameClockExtension());
assertEq(gameImpl.maxClockDuration().raw(), cfg.faultGameMaxClockDuration());
assertEq(gameImpl.absolutePrestate().raw(), bytes32(cfg.faultGameAbsolutePrestate())); assertEq(gameImpl.absolutePrestate().raw(), bytes32(cfg.faultGameAbsolutePrestate()));
// Check the security override yoke configuration. // Check the security override yoke configuration.
...@@ -191,7 +192,8 @@ contract FPACOPS is Deploy, StdAssertions { ...@@ -191,7 +192,8 @@ contract FPACOPS is Deploy, StdAssertions {
assertEq(soyGameImpl.challenger(), cfg.l2OutputOracleChallenger()); assertEq(soyGameImpl.challenger(), cfg.l2OutputOracleChallenger());
assertEq(soyGameImpl.maxGameDepth(), cfg.faultGameMaxDepth()); assertEq(soyGameImpl.maxGameDepth(), cfg.faultGameMaxDepth());
assertEq(soyGameImpl.splitDepth(), cfg.faultGameSplitDepth()); assertEq(soyGameImpl.splitDepth(), cfg.faultGameSplitDepth());
assertEq(soyGameImpl.gameDuration().raw(), cfg.faultGameMaxDuration()); assertEq(soyGameImpl.clockExtension().raw(), cfg.faultGameClockExtension());
assertEq(soyGameImpl.maxClockDuration().raw(), cfg.faultGameMaxClockDuration());
assertEq(soyGameImpl.absolutePrestate().raw(), bytes32(cfg.faultGameAbsolutePrestate())); assertEq(soyGameImpl.absolutePrestate().raw(), bytes32(cfg.faultGameAbsolutePrestate()));
// Check the AnchorStateRegistry configuration. // Check the AnchorStateRegistry configuration.
...@@ -211,13 +213,14 @@ contract FPACOPS is Deploy, StdAssertions { ...@@ -211,13 +213,14 @@ contract FPACOPS is Deploy, StdAssertions {
console.log(" 1. Absolute Prestate: %x", cfg.faultGameAbsolutePrestate()); console.log(" 1. Absolute Prestate: %x", cfg.faultGameAbsolutePrestate());
console.log(" 2. Max Depth: %d", cfg.faultGameMaxDepth()); console.log(" 2. Max Depth: %d", cfg.faultGameMaxDepth());
console.log(" 3. Output / Execution split Depth: %d", cfg.faultGameSplitDepth()); console.log(" 3. Output / Execution split Depth: %d", cfg.faultGameSplitDepth());
console.log(" 4. Game Duration (seconds): %d", cfg.faultGameMaxDuration()); console.log(" 4. Clock Extension (seconds): %d", cfg.faultGameClockExtension());
console.log(" 5. L2 Genesis block number: %d", cfg.faultGameGenesisBlock()); console.log(" 5. Max Clock Duration (seconds): %d", cfg.faultGameMaxClockDuration());
console.log(" 6. L2 Genesis output root: %x", uint256(cfg.faultGameGenesisOutputRoot())); console.log(" 6. L2 Genesis block number: %d", cfg.faultGameGenesisBlock());
console.log(" 7. Proof Maturity Delay (seconds): ", cfg.proofMaturityDelaySeconds()); console.log(" 7. L2 Genesis output root: %x", uint256(cfg.faultGameGenesisOutputRoot()));
console.log(" 8. Dispute Game Finality Delay (seconds): ", cfg.disputeGameFinalityDelaySeconds()); console.log(" 8. Proof Maturity Delay (seconds): ", cfg.proofMaturityDelaySeconds());
console.log(" 9. Respected Game Type: ", cfg.respectedGameType()); console.log(" 9. Dispute Game Finality Delay (seconds): ", cfg.disputeGameFinalityDelaySeconds());
console.log(" 10. Preimage Oracle Min Proposal Size (bytes): ", cfg.preimageOracleMinProposalSize()); console.log(" 10. Respected Game Type: ", cfg.respectedGameType());
console.log(" 11. Preimage Oracle Challenge Period (seconds): ", cfg.preimageOracleChallengePeriod()); console.log(" 11. Preimage Oracle Min Proposal Size (bytes): ", cfg.preimageOracleMinProposalSize());
console.log(" 12. Preimage Oracle Challenge Period (seconds): ", cfg.preimageOracleChallengePeriod());
} }
} }
...@@ -91,7 +91,8 @@ config=$(cat << EOL ...@@ -91,7 +91,8 @@ config=$(cat << EOL
"faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98", "faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98",
"faultGameMaxDepth": 44, "faultGameMaxDepth": 44,
"faultGameMaxDuration": 1200, "faultGameClockExtension": 0,
"faultGameMaxClockDuration": 600,
"faultGameGenesisBlock": 0, "faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"faultGameSplitDepth": 14, "faultGameSplitDepth": 14,
......
...@@ -116,8 +116,8 @@ ...@@ -116,8 +116,8 @@
"sourceCodeHash": "0xc4dbd17217b63f8117f56f78c213e57dda304fee7577fe296e1d804ebe049542" "sourceCodeHash": "0xc4dbd17217b63f8117f56f78c213e57dda304fee7577fe296e1d804ebe049542"
}, },
"src/dispute/FaultDisputeGame.sol": { "src/dispute/FaultDisputeGame.sol": {
"initCodeHash": "0x42c04ec50860cf8f1f772bc77dcbd20e7e06554a0962d16eaad2ee5fd748cfe0", "initCodeHash": "0xf1a4519238b2e5ac5d1ca83c33135dc47e5c38029c82443975cfd00abf76a8bf",
"sourceCodeHash": "0x8ea9b68ddfc6fce606065a789b7323d8b119aadb162c139f1878a9322b1e892b" "sourceCodeHash": "0x221732fb84ae56d7c526c2437820ec15cdd3ef293ae47f3383df8c943c737805"
}, },
"src/dispute/weth/DelayedWETH.sol": { "src/dispute/weth/DelayedWETH.sol": {
"initCodeHash": "0x7b6ec89eaec09e369426e73161a9c6932223bb1f974377190c3f6f552995da35", "initCodeHash": "0x7b6ec89eaec09e369426e73161a9c6932223bb1f974377190c3f6f552995da35",
......
...@@ -23,7 +23,12 @@ ...@@ -23,7 +23,12 @@
}, },
{ {
"internalType": "Duration", "internalType": "Duration",
"name": "_gameDuration", "name": "_clockExtension",
"type": "uint64"
},
{
"internalType": "Duration",
"name": "_maxClockDuration",
"type": "uint64" "type": "uint64"
}, },
{ {
...@@ -187,6 +192,19 @@ ...@@ -187,6 +192,19 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "clockExtension",
"outputs": [
{
"internalType": "Duration",
"name": "clockExtension_",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "createdAt", "name": "createdAt",
...@@ -286,19 +304,6 @@ ...@@ -286,19 +304,6 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "gameDuration",
"outputs": [
{
"internalType": "Duration",
"name": "gameDuration_",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "gameType", "name": "gameType",
...@@ -396,6 +401,19 @@ ...@@ -396,6 +401,19 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "maxClockDuration",
"outputs": [
{
"internalType": "Duration",
"name": "maxClockDuration_",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "maxGameDepth", "name": "maxGameDepth",
...@@ -724,6 +742,11 @@ ...@@ -724,6 +742,11 @@
"name": "IncorrectBondAmount", "name": "IncorrectBondAmount",
"type": "error" "type": "error"
}, },
{
"inputs": [],
"name": "InvalidClockExtension",
"type": "error"
},
{ {
"inputs": [], "inputs": [],
"name": "InvalidLocalIdent", "name": "InvalidLocalIdent",
...@@ -744,6 +767,11 @@ ...@@ -744,6 +767,11 @@
"name": "InvalidSplitDepth", "name": "InvalidSplitDepth",
"type": "error" "type": "error"
}, },
{
"inputs": [],
"name": "MaxDepthTooLarge",
"type": "error"
},
{ {
"inputs": [], "inputs": [],
"name": "NoCreditToClaim", "name": "NoCreditToClaim",
......
...@@ -23,7 +23,12 @@ ...@@ -23,7 +23,12 @@
}, },
{ {
"internalType": "Duration", "internalType": "Duration",
"name": "_gameDuration", "name": "_clockExtension",
"type": "uint64"
},
{
"internalType": "Duration",
"name": "_maxClockDuration",
"type": "uint64" "type": "uint64"
}, },
{ {
...@@ -210,6 +215,19 @@ ...@@ -210,6 +215,19 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "clockExtension",
"outputs": [
{
"internalType": "Duration",
"name": "clockExtension_",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "createdAt", "name": "createdAt",
...@@ -309,19 +327,6 @@ ...@@ -309,19 +327,6 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "gameDuration",
"outputs": [
{
"internalType": "Duration",
"name": "gameDuration_",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "gameType", "name": "gameType",
...@@ -419,6 +424,19 @@ ...@@ -419,6 +424,19 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "maxClockDuration",
"outputs": [
{
"internalType": "Duration",
"name": "maxClockDuration_",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "maxGameDepth", "name": "maxGameDepth",
...@@ -765,6 +783,11 @@ ...@@ -765,6 +783,11 @@
"name": "IncorrectBondAmount", "name": "IncorrectBondAmount",
"type": "error" "type": "error"
}, },
{
"inputs": [],
"name": "InvalidClockExtension",
"type": "error"
},
{ {
"inputs": [], "inputs": [],
"name": "InvalidLocalIdent", "name": "InvalidLocalIdent",
...@@ -785,6 +808,11 @@ ...@@ -785,6 +808,11 @@
"name": "InvalidSplitDepth", "name": "InvalidSplitDepth",
"type": "error" "type": "error"
}, },
{
"inputs": [],
"name": "MaxDepthTooLarge",
"type": "error"
},
{ {
"inputs": [], "inputs": [],
"name": "NoCreditToClaim", "name": "NoCreditToClaim",
......
...@@ -1988,7 +1988,7 @@ ...@@ -1988,7 +1988,7 @@
"newValue": "0x0000000000000000000000000000000000000000000000000000000000000000", "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000",
"previousValue": "0x0000000000000000000000000000000000000000000000000000000000000000", "previousValue": "0x0000000000000000000000000000000000000000000000000000000000000000",
"reverted": false, "reverted": false,
"slot": "0x000000000000000000000000000000000000000000000000000000000000003b" "slot": "0x000000000000000000000000000000000000000000000000000000000000003c"
} }
], ],
"value": 0 "value": 0
...@@ -2014,7 +2014,7 @@ ...@@ -2014,7 +2014,7 @@
"newValue": "0x0000000000000000000000000000000000000000000000000000000000000000", "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000",
"previousValue": "0x0000000000000000000000000000000000000000000000000000000000000000", "previousValue": "0x0000000000000000000000000000000000000000000000000000000000000000",
"reverted": false, "reverted": false,
"slot": "0x000000000000000000000000000000000000000000000000000000000000003c" "slot": "0x000000000000000000000000000000000000000000000000000000000000003d"
} }
], ],
"value": 0 "value": 0
...@@ -2475,7 +2475,7 @@ ...@@ -2475,7 +2475,7 @@
"newValue": "0x0000000000000000000000000000000000000000000000000000000000000000", "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000",
"previousValue": "0x0000000000000000000000000000000000000000000000000000000000000000", "previousValue": "0x0000000000000000000000000000000000000000000000000000000000000000",
"reverted": false, "reverted": false,
"slot": "0x000000000000000000000000000000000000000000000000000000000000003b" "slot": "0x000000000000000000000000000000000000000000000000000000000000003c"
} }
], ],
"value": 0 "value": 0
...@@ -2553,7 +2553,7 @@ ...@@ -2553,7 +2553,7 @@
"newValue": "0x0000000000000000000000000000000000000000000000000000000000000000", "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000",
"previousValue": "0x0000000000000000000000000000000000000000000000000000000000000000", "previousValue": "0x0000000000000000000000000000000000000000000000000000000000000000",
"reverted": false, "reverted": false,
"slot": "0x000000000000000000000000000000000000000000000000000000000000003c" "slot": "0x000000000000000000000000000000000000000000000000000000000000003d"
} }
], ],
"value": 0 "value": 0
...@@ -7246,7 +7246,7 @@ ...@@ -7246,7 +7246,7 @@
"newValue": "0x0000000000000000000000000000000000000000000000000000000000000000", "newValue": "0x0000000000000000000000000000000000000000000000000000000000000000",
"previousValue": "0x0000000000000000000000000000000000000000000000000000000000000000", "previousValue": "0x0000000000000000000000000000000000000000000000000000000000000000",
"reverted": false, "reverted": false,
"slot": "0x000000000000000000000000000000000000000000000000000000000000003a" "slot": "0x000000000000000000000000000000000000000000000000000000000000003b"
} }
], ],
"value": 0 "value": 0
...@@ -36,8 +36,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -36,8 +36,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
/// this depth, execution trace bisection begins. /// this depth, execution trace bisection begins.
uint256 internal immutable SPLIT_DEPTH; uint256 internal immutable SPLIT_DEPTH;
/// @notice The duration of the game. /// @notice The maximum duration that may accumulate on a team's chess clock before they may no longer respond.
Duration internal immutable GAME_DURATION; Duration internal immutable MAX_CLOCK_DURATION;
/// @notice An onchain VM that performs single instruction steps on a fault proof program trace. /// @notice An onchain VM that performs single instruction steps on a fault proof program trace.
IBigStepper internal immutable VM; IBigStepper internal immutable VM;
...@@ -54,6 +54,10 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -54,6 +54,10 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
/// @notice The chain ID of the L2 network this contract argues about. /// @notice The chain ID of the L2 network this contract argues about.
uint256 internal immutable L2_CHAIN_ID; uint256 internal immutable L2_CHAIN_ID;
/// @notice The duration of the clock extension. Will be doubled if the grandchild is the root claim of an execution
/// trace bisection subgame.
Duration internal immutable CLOCK_EXTENSION;
/// @notice The global root claim's position is always at gindex 1. /// @notice The global root claim's position is always at gindex 1.
Position internal constant ROOT_POSITION = Position.wrap(1); Position internal constant ROOT_POSITION = Position.wrap(1);
...@@ -88,14 +92,15 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -88,14 +92,15 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
OutputRoot public startingOutputRoot; OutputRoot public startingOutputRoot;
/// @notice Semantic version. /// @notice Semantic version.
/// @custom:semver 0.15.0 /// @custom:semver 0.16.1
string public constant version = "0.15.0"; string public constant version = "0.16.1";
/// @param _gameType The type ID of the game. /// @param _gameType The type ID of the game.
/// @param _absolutePrestate The absolute prestate of the instruction trace. /// @param _absolutePrestate The absolute prestate of the instruction trace.
/// @param _maxGameDepth The maximum depth of bisection. /// @param _maxGameDepth The maximum depth of bisection.
/// @param _splitDepth The final depth of the output bisection portion of the game. /// @param _splitDepth The final depth of the output bisection portion of the game.
/// @param _gameDuration The duration of the game. /// @param _clockExtension The clock extension to perform when the remaining duration is less than the extension.
/// @param _maxClockDuration The maximum amount of time that may accumulate on a team's chess clock.
/// @param _vm An onchain VM that performs single instruction steps on an FPP trace. /// @param _vm An onchain VM that performs single instruction steps on an FPP trace.
/// @param _weth WETH contract for holding ETH. /// @param _weth WETH contract for holding ETH.
/// @param _anchorStateRegistry The contract that stores the anchor state for each game type. /// @param _anchorStateRegistry The contract that stores the anchor state for each game type.
...@@ -105,20 +110,26 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -105,20 +110,26 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
Claim _absolutePrestate, Claim _absolutePrestate,
uint256 _maxGameDepth, uint256 _maxGameDepth,
uint256 _splitDepth, uint256 _splitDepth,
Duration _gameDuration, Duration _clockExtension,
Duration _maxClockDuration,
IBigStepper _vm, IBigStepper _vm,
IDelayedWETH _weth, IDelayedWETH _weth,
IAnchorStateRegistry _anchorStateRegistry, IAnchorStateRegistry _anchorStateRegistry,
uint256 _l2ChainId uint256 _l2ChainId
) { ) {
// The max game depth may not be greater than `LibPosition.MAX_POSITION_BITLEN - 1`.
if (_maxGameDepth > LibPosition.MAX_POSITION_BITLEN - 1) revert MaxDepthTooLarge();
// The split depth cannot be greater than or equal to the max game depth. // The split depth cannot be greater than or equal to the max game depth.
if (_splitDepth >= _maxGameDepth) revert InvalidSplitDepth(); if (_splitDepth >= _maxGameDepth) revert InvalidSplitDepth();
// The clock extension may not be greater than the max clock duration.
if (_clockExtension.raw() > _maxClockDuration.raw()) revert InvalidClockExtension();
GAME_TYPE = _gameType; GAME_TYPE = _gameType;
ABSOLUTE_PRESTATE = _absolutePrestate; ABSOLUTE_PRESTATE = _absolutePrestate;
MAX_GAME_DEPTH = _maxGameDepth; MAX_GAME_DEPTH = _maxGameDepth;
SPLIT_DEPTH = _splitDepth; SPLIT_DEPTH = _splitDepth;
GAME_DURATION = _gameDuration; CLOCK_EXTENSION = _clockExtension;
MAX_CLOCK_DURATION = _maxClockDuration;
VM = _vm; VM = _vm;
WETH = _weth; WETH = _weth;
ANCHOR_STATE_REGISTRY = _anchorStateRegistry; ANCHOR_STATE_REGISTRY = _anchorStateRegistry;
...@@ -261,9 +272,22 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -261,9 +272,22 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
// parent's clock timestamp. // parent's clock timestamp.
Duration nextDuration = getChallengerDuration(_challengeIndex); Duration nextDuration = getChallengerDuration(_challengeIndex);
// INVARIANT: A move can never be made once its clock has exceeded `GAME_DURATION / 2` // INVARIANT: A move can never be made once its clock has exceeded `MAX_CLOCK_DURATION`
// seconds of time. // seconds of time.
if (nextDuration.raw() == GAME_DURATION.raw() >> 1) revert ClockTimeExceeded(); if (nextDuration.raw() == MAX_CLOCK_DURATION.raw()) revert ClockTimeExceeded();
// If the remaining clock time has less than `CLOCK_EXTENSION` seconds remaining, grant the potential
// grandchild's clock `CLOCK_EXTENSION` seconds. This is to ensure that, even if a player has to inherit another
// team's clock to counter a freeloader claim, they will always have enough time to to respond. This extension
// is bounded by the depth of the tree. If the potential grandchild is an execution trace bisection root, the
// clock extension is doubled. This is to allow for extra time for the off-chain challenge agent to generate
// the initial instruction trace on the native FPVM.
if (nextDuration.raw() > MAX_CLOCK_DURATION.raw() - CLOCK_EXTENSION.raw()) {
// If the potential grandchild is an execution trace bisection root, double the clock extension.
uint64 extensionPeriod =
nextPositionDepth == SPLIT_DEPTH - 1 ? CLOCK_EXTENSION.raw() * 2 : CLOCK_EXTENSION.raw();
nextDuration = Duration.wrap(MAX_CLOCK_DURATION.raw() - extensionPeriod);
}
// Construct the next clock with the new duration and the current block timestamp. // Construct the next clock with the new duration and the current block timestamp.
Clock nextClock = LibClock.wrap(nextDuration, Timestamp.wrap(uint64(block.timestamp))); Clock nextClock = LibClock.wrap(nextDuration, Timestamp.wrap(uint64(block.timestamp)));
...@@ -387,9 +411,9 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -387,9 +411,9 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
Duration challengeClockDuration = getChallengerDuration(_claimIndex); Duration challengeClockDuration = getChallengerDuration(_claimIndex);
// INVARIANT: Cannot resolve a subgame unless the clock of its would-be counter has expired // INVARIANT: Cannot resolve a subgame unless the clock of its would-be counter has expired
// INVARIANT: Assuming ordered subgame resolution, challengeClockDuration is always >= GAME_DURATION / 2 if all // INVARIANT: Assuming ordered subgame resolution, challengeClockDuration is always >= MAX_CLOCK_DURATION if all
// descendant subgames are resolved // descendant subgames are resolved
if (challengeClockDuration.raw() < GAME_DURATION.raw() >> 1) revert ClockNotExpired(); if (challengeClockDuration.raw() < MAX_CLOCK_DURATION.raw()) revert ClockNotExpired();
// INVARIANT: Cannot resolve a subgame twice. // INVARIANT: Cannot resolve a subgame twice.
if (resolvedSubgames[_claimIndex]) revert ClaimAlreadyResolved(); if (resolvedSubgames[_claimIndex]) revert ClaimAlreadyResolved();
...@@ -634,7 +658,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -634,7 +658,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
} }
/// @notice Returns the amount of time elapsed on the potential challenger to `_claimIndex`'s chess clock. Maxes /// @notice Returns the amount of time elapsed on the potential challenger to `_claimIndex`'s chess clock. Maxes
/// out at `GAME_DURATION / 2`. /// out at `MAX_CLOCK_DURATION`.
/// @param _claimIndex The index of the subgame root claim. /// @param _claimIndex The index of the subgame root claim.
/// @return duration_ The time elapsed on the potential challenger to `_claimIndex`'s chess clock. /// @return duration_ The time elapsed on the potential challenger to `_claimIndex`'s chess clock.
function getChallengerDuration(uint256 _claimIndex) public view returns (Duration duration_) { function getChallengerDuration(uint256 _claimIndex) public view returns (Duration duration_) {
...@@ -655,12 +679,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -655,12 +679,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
// Compute the duration elapsed of the potential challenger's clock. // Compute the duration elapsed of the potential challenger's clock.
uint64 challengeDuration = uint64 challengeDuration =
uint64(parentClock.duration().raw() + (block.timestamp - subgameRootClaim.clock.timestamp().raw())); uint64(parentClock.duration().raw() + (block.timestamp - subgameRootClaim.clock.timestamp().raw()));
uint64 maxClockTime = GAME_DURATION.raw() >> 1; duration_ = challengeDuration > MAX_CLOCK_DURATION.raw() ? MAX_CLOCK_DURATION : Duration.wrap(challengeDuration);
if (challengeDuration > maxClockTime) {
duration_ = Duration.wrap(maxClockTime);
} else {
duration_ = Duration.wrap(challengeDuration);
}
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
...@@ -682,9 +701,14 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -682,9 +701,14 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
splitDepth_ = SPLIT_DEPTH; splitDepth_ = SPLIT_DEPTH;
} }
/// @notice Returns the game duration. /// @notice Returns the max clock duration.
function gameDuration() external view returns (Duration gameDuration_) { function maxClockDuration() external view returns (Duration maxClockDuration_) {
gameDuration_ = GAME_DURATION; maxClockDuration_ = MAX_CLOCK_DURATION;
}
/// @notice Returns the clock extension constant.
function clockExtension() external view returns (Duration clockExtension_) {
clockExtension_ = CLOCK_EXTENSION;
} }
/// @notice Returns the address of the VM. /// @notice Returns the address of the VM.
...@@ -879,10 +903,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -879,10 +903,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
{ {
// A position of 0 indicates that the starting claim is the absolute prestate. In this special case, // A position of 0 indicates that the starting claim is the absolute prestate. In this special case,
// we do not include the starting claim within the local context hash. // we do not include the starting claim within the local context hash.
if (_startingPos.raw() == 0) { uuid_ = _startingPos.raw() == 0
uuid_ = Hash.wrap(keccak256(abi.encode(_disputed, _disputedPos))); ? Hash.wrap(keccak256(abi.encode(_disputed, _disputedPos)))
} else { : Hash.wrap(keccak256(abi.encode(_starting, _startingPos, _disputed, _disputedPos)));
uuid_ = Hash.wrap(keccak256(abi.encode(_starting, _startingPos, _disputed, _disputedPos)));
}
} }
} }
...@@ -34,7 +34,8 @@ contract PermissionedDisputeGame is FaultDisputeGame { ...@@ -34,7 +34,8 @@ contract PermissionedDisputeGame is FaultDisputeGame {
/// @param _absolutePrestate The absolute prestate of the instruction trace. /// @param _absolutePrestate The absolute prestate of the instruction trace.
/// @param _maxGameDepth The maximum depth of bisection. /// @param _maxGameDepth The maximum depth of bisection.
/// @param _splitDepth The final depth of the output bisection portion of the game. /// @param _splitDepth The final depth of the output bisection portion of the game.
/// @param _gameDuration The duration of the game. /// @param _clockExtension The clock extension to perform when the remaining duration is less than the extension.
/// @param _maxClockDuration The maximum amount of time that may accumulate on a team's chess clock.
/// @param _vm An onchain VM that performs single instruction steps on an FPP trace. /// @param _vm An onchain VM that performs single instruction steps on an FPP trace.
/// @param _weth WETH contract for holding ETH. /// @param _weth WETH contract for holding ETH.
/// @param _anchorStateRegistry The contract that stores the anchor state for each game type. /// @param _anchorStateRegistry The contract that stores the anchor state for each game type.
...@@ -46,7 +47,8 @@ contract PermissionedDisputeGame is FaultDisputeGame { ...@@ -46,7 +47,8 @@ contract PermissionedDisputeGame is FaultDisputeGame {
Claim _absolutePrestate, Claim _absolutePrestate,
uint256 _maxGameDepth, uint256 _maxGameDepth,
uint256 _splitDepth, uint256 _splitDepth,
Duration _gameDuration, Duration _clockExtension,
Duration _maxClockDuration,
IBigStepper _vm, IBigStepper _vm,
IDelayedWETH _weth, IDelayedWETH _weth,
IAnchorStateRegistry _anchorStateRegistry, IAnchorStateRegistry _anchorStateRegistry,
...@@ -59,7 +61,8 @@ contract PermissionedDisputeGame is FaultDisputeGame { ...@@ -59,7 +61,8 @@ contract PermissionedDisputeGame is FaultDisputeGame {
_absolutePrestate, _absolutePrestate,
_maxGameDepth, _maxGameDepth,
_splitDepth, _splitDepth,
_gameDuration, _clockExtension,
_maxClockDuration,
_vm, _vm,
_weth, _weth,
_anchorStateRegistry, _anchorStateRegistry,
......
...@@ -7,6 +7,10 @@ import "src/libraries/DisputeErrors.sol"; ...@@ -7,6 +7,10 @@ import "src/libraries/DisputeErrors.sol";
/// @title LibPosition /// @title LibPosition
/// @notice This library contains helper functions for working with the `Position` type. /// @notice This library contains helper functions for working with the `Position` type.
library LibPosition { library LibPosition {
/// @notice the `MAX_POSITION_BITLEN` is the number of bits that the `Position` type, and the implementation of
/// its behavior within this library, can safely support.
uint8 internal constant MAX_POSITION_BITLEN = 126;
/// @notice Computes a generalized index (2^{depth} + indexAtDepth). /// @notice Computes a generalized index (2^{depth} + indexAtDepth).
/// @param _depth The depth of the position. /// @param _depth The depth of the position.
/// @param _indexAtDepth The index at the depth of the position. /// @param _indexAtDepth The index at the depth of the position.
......
...@@ -91,6 +91,12 @@ error ClaimAboveSplit(); ...@@ -91,6 +91,12 @@ error ClaimAboveSplit();
/// depth of the game. /// depth of the game.
error InvalidSplitDepth(); error InvalidSplitDepth();
/// @notice Thrown on deployment if the max clock duration is less than or equal to the clock extension.
error InvalidClockExtension();
/// @notice Thrown on deployment if the max depth is greater than `LibPosition.`
error MaxDepthTooLarge();
/// @notice Thrown when trying to step against a claim for a second time, after it has already been countered with /// @notice Thrown when trying to step against a claim for a second time, after it has already been countered with
/// an instruction step. /// an instruction step.
error DuplicateStep(); error DuplicateStep();
......
...@@ -343,7 +343,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -343,7 +343,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
_proposedGameIndex = disputeGameFactory.gameCount() - 1; _proposedGameIndex = disputeGameFactory.gameCount() - 1;
// Warp beyond the chess clocks and finalize the game. // Warp beyond the chess clocks and finalize the game.
vm.warp(block.timestamp + game.gameDuration().raw() / 2 + 1 seconds); vm.warp(block.timestamp + game.maxClockDuration().raw() + 1 seconds);
// Fund the portal so that we can withdraw ETH. // Fund the portal so that we can withdraw ETH.
vm.deal(address(optimismPortal2), 0xFFFFFFFF); vm.deal(address(optimismPortal2), 0xFFFFFFFF);
......
...@@ -57,7 +57,8 @@ contract PermissionedDisputeGame_Init is DisputeGameFactory_Init { ...@@ -57,7 +57,8 @@ contract PermissionedDisputeGame_Init is DisputeGameFactory_Init {
_absolutePrestate: absolutePrestate, _absolutePrestate: absolutePrestate,
_maxGameDepth: 2 ** 3, _maxGameDepth: 2 ** 3,
_splitDepth: 2 ** 2, _splitDepth: 2 ** 2,
_gameDuration: Duration.wrap(7 days), _clockExtension: Duration.wrap(3 hours),
_maxClockDuration: Duration.wrap(3.5 days),
_vm: _vm, _vm: _vm,
_weth: _weth, _weth: _weth,
_anchorStateRegistry: anchorStateRegistry, _anchorStateRegistry: anchorStateRegistry,
...@@ -79,7 +80,7 @@ contract PermissionedDisputeGame_Init is DisputeGameFactory_Init { ...@@ -79,7 +80,7 @@ contract PermissionedDisputeGame_Init is DisputeGameFactory_Init {
assertEq(gameProxy.absolutePrestate().raw(), absolutePrestate.raw()); assertEq(gameProxy.absolutePrestate().raw(), absolutePrestate.raw());
assertEq(gameProxy.maxGameDepth(), 2 ** 3); assertEq(gameProxy.maxGameDepth(), 2 ** 3);
assertEq(gameProxy.splitDepth(), 2 ** 2); assertEq(gameProxy.splitDepth(), 2 ** 2);
assertEq(gameProxy.gameDuration().raw(), 7 days); assertEq(gameProxy.maxClockDuration().raw(), 3.5 days);
assertEq(address(gameProxy.vm()), address(_vm)); assertEq(address(gameProxy.vm()), address(_vm));
// Label the proxy // Label the proxy
......
...@@ -127,7 +127,7 @@ contract OptimismPortal2_Invariant_Harness is CommonTest { ...@@ -127,7 +127,7 @@ contract OptimismPortal2_Invariant_Harness is CommonTest {
_proposedGameIndex = disputeGameFactory.gameCount() - 1; _proposedGameIndex = disputeGameFactory.gameCount() - 1;
// Warp beyond the finalization period for the dispute game and resolve it. // Warp beyond the finalization period for the dispute game and resolve it.
vm.warp(block.timestamp + game.gameDuration().raw() + 1 seconds); vm.warp(block.timestamp + (game.maxClockDuration().raw() * 2) + 1 seconds);
game.resolveClaim(0); game.resolveClaim(0);
game.resolve(); game.resolve();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment