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
134f6883
Unverified
Commit
134f6883
authored
Feb 22, 2024
by
refcell
Committed by
GitHub
Feb 22, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(op-dispute-mon): claim resolution delay max calculation (#9567)
parent
3b8933d3
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
371 additions
and
41 deletions
+371
-41
faultdisputegame.go
op-challenger/game/fault/contracts/faultdisputegame.go
+10
-8
faultdisputegame_test.go
op-challenger/game/fault/contracts/faultdisputegame_test.go
+4
-1
metrics.go
op-dispute-mon/metrics/metrics.go
+13
-0
noop.go
op-dispute-mon/metrics/noop.go
+2
-0
bonds.go
op-dispute-mon/mon/bonds/bonds.go
+2
-3
bonds_test.go
op-dispute-mon/mon/bonds/bonds_test.go
+2
-5
caller.go
op-dispute-mon/mon/extract/caller.go
+2
-2
extractor.go
op-dispute-mon/mon/extract/extractor.go
+2
-1
extractor_test.go
op-dispute-mon/mon/extract/extractor_test.go
+10
-7
forecast.go
op-dispute-mon/mon/forecast.go
+3
-1
forecast_test.go
op-dispute-mon/mon/forecast_test.go
+38
-0
monitor.go
op-dispute-mon/mon/monitor.go
+5
-0
monitor_test.go
op-dispute-mon/mon/monitor_test.go
+25
-11
delay.go
op-dispute-mon/mon/resolution/delay.go
+52
-0
delay_test.go
op-dispute-mon/mon/resolution/delay_test.go
+181
-0
resolver.go
op-dispute-mon/mon/resolution/resolver.go
+1
-1
resolver_test.go
op-dispute-mon/mon/resolution/resolver_test.go
+1
-1
service.go
op-dispute-mon/mon/service.go
+8
-0
types.go
op-dispute-mon/mon/types/types.go
+6
-0
types_test.go
op-dispute-mon/mon/types/types_test.go
+4
-0
No files found.
op-challenger/game/fault/contracts/faultdisputegame.go
View file @
134f6883
...
@@ -80,25 +80,27 @@ func (c *FaultDisputeGameContract) GetBlockRange(ctx context.Context) (prestateB
...
@@ -80,25 +80,27 @@ func (c *FaultDisputeGameContract) GetBlockRange(ctx context.Context) (prestateB
return
return
}
}
// GetGameMetadata returns the game's L2 block number, root claim,
and status
.
// GetGameMetadata returns the game's L2 block number, root claim,
status, and game duration
.
func
(
c
*
FaultDisputeGameContract
)
GetGameMetadata
(
ctx
context
.
Context
)
(
uint64
,
common
.
Hash
,
gameTypes
.
GameStatus
,
error
)
{
func
(
c
*
FaultDisputeGameContract
)
GetGameMetadata
(
ctx
context
.
Context
)
(
uint64
,
common
.
Hash
,
gameTypes
.
GameStatus
,
uint64
,
error
)
{
results
,
err
:=
c
.
multiCaller
.
Call
(
ctx
,
batching
.
BlockLatest
,
results
,
err
:=
c
.
multiCaller
.
Call
(
ctx
,
batching
.
BlockLatest
,
c
.
contract
.
Call
(
methodL2BlockNumber
),
c
.
contract
.
Call
(
methodL2BlockNumber
),
c
.
contract
.
Call
(
methodRootClaim
),
c
.
contract
.
Call
(
methodRootClaim
),
c
.
contract
.
Call
(
methodStatus
))
c
.
contract
.
Call
(
methodStatus
),
c
.
contract
.
Call
(
methodGameDuration
))
if
err
!=
nil
{
if
err
!=
nil
{
return
0
,
common
.
Hash
{},
0
,
fmt
.
Errorf
(
"failed to retrieve game metadata: %w"
,
err
)
return
0
,
common
.
Hash
{},
0
,
0
,
fmt
.
Errorf
(
"failed to retrieve game metadata: %w"
,
err
)
}
}
if
len
(
results
)
!=
3
{
if
len
(
results
)
!=
4
{
return
0
,
common
.
Hash
{},
0
,
fmt
.
Errorf
(
"expected 3 results but got %v"
,
len
(
results
))
return
0
,
common
.
Hash
{},
0
,
0
,
fmt
.
Errorf
(
"expected 3 results but got %v"
,
len
(
results
))
}
}
l2BlockNumber
:=
results
[
0
]
.
GetBigInt
(
0
)
.
Uint64
()
l2BlockNumber
:=
results
[
0
]
.
GetBigInt
(
0
)
.
Uint64
()
rootClaim
:=
results
[
1
]
.
GetHash
(
0
)
rootClaim
:=
results
[
1
]
.
GetHash
(
0
)
duration
:=
results
[
3
]
.
GetUint64
(
0
)
status
,
err
:=
gameTypes
.
GameStatusFromUint8
(
results
[
2
]
.
GetUint8
(
0
))
status
,
err
:=
gameTypes
.
GameStatusFromUint8
(
results
[
2
]
.
GetUint8
(
0
))
if
err
!=
nil
{
if
err
!=
nil
{
return
0
,
common
.
Hash
{},
0
,
fmt
.
Errorf
(
"failed to convert game status: %w"
,
err
)
return
0
,
common
.
Hash
{},
0
,
0
,
fmt
.
Errorf
(
"failed to convert game status: %w"
,
err
)
}
}
return
l2BlockNumber
,
rootClaim
,
status
,
nil
return
l2BlockNumber
,
rootClaim
,
status
,
duration
,
nil
}
}
func
(
c
*
FaultDisputeGameContract
)
GetGenesisOutputRoot
(
ctx
context
.
Context
)
(
common
.
Hash
,
error
)
{
func
(
c
*
FaultDisputeGameContract
)
GetGenesisOutputRoot
(
ctx
context
.
Context
)
(
common
.
Hash
,
error
)
{
...
...
op-challenger/game/fault/contracts/faultdisputegame_test.go
View file @
134f6883
...
@@ -319,16 +319,19 @@ func TestGetSplitDepth(t *testing.T) {
...
@@ -319,16 +319,19 @@ func TestGetSplitDepth(t *testing.T) {
func
TestGetGameMetadata
(
t
*
testing
.
T
)
{
func
TestGetGameMetadata
(
t
*
testing
.
T
)
{
stubRpc
,
contract
:=
setupFaultDisputeGameTest
(
t
)
stubRpc
,
contract
:=
setupFaultDisputeGameTest
(
t
)
expectedL2BlockNumber
:=
uint64
(
123
)
expectedL2BlockNumber
:=
uint64
(
123
)
expectedGameDuration
:=
uint64
(
456
)
expectedRootClaim
:=
common
.
Hash
{
0x01
,
0x02
}
expectedRootClaim
:=
common
.
Hash
{
0x01
,
0x02
}
expectedStatus
:=
types
.
GameStatusChallengerWon
expectedStatus
:=
types
.
GameStatusChallengerWon
stubRpc
.
SetResponse
(
fdgAddr
,
methodL2BlockNumber
,
batching
.
BlockLatest
,
nil
,
[]
interface
{}{
new
(
big
.
Int
)
.
SetUint64
(
expectedL2BlockNumber
)})
stubRpc
.
SetResponse
(
fdgAddr
,
methodL2BlockNumber
,
batching
.
BlockLatest
,
nil
,
[]
interface
{}{
new
(
big
.
Int
)
.
SetUint64
(
expectedL2BlockNumber
)})
stubRpc
.
SetResponse
(
fdgAddr
,
methodRootClaim
,
batching
.
BlockLatest
,
nil
,
[]
interface
{}{
expectedRootClaim
})
stubRpc
.
SetResponse
(
fdgAddr
,
methodRootClaim
,
batching
.
BlockLatest
,
nil
,
[]
interface
{}{
expectedRootClaim
})
stubRpc
.
SetResponse
(
fdgAddr
,
methodStatus
,
batching
.
BlockLatest
,
nil
,
[]
interface
{}{
expectedStatus
})
stubRpc
.
SetResponse
(
fdgAddr
,
methodStatus
,
batching
.
BlockLatest
,
nil
,
[]
interface
{}{
expectedStatus
})
l2BlockNumber
,
rootClaim
,
status
,
err
:=
contract
.
GetGameMetadata
(
context
.
Background
())
stubRpc
.
SetResponse
(
fdgAddr
,
methodGameDuration
,
batching
.
BlockLatest
,
nil
,
[]
interface
{}{
expectedGameDuration
})
l2BlockNumber
,
rootClaim
,
status
,
duration
,
err
:=
contract
.
GetGameMetadata
(
context
.
Background
())
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
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
)
}
}
func
TestGetGenesisOutputRoot
(
t
*
testing
.
T
)
{
func
TestGetGenesisOutputRoot
(
t
*
testing
.
T
)
{
...
...
op-dispute-mon/metrics/metrics.go
View file @
134f6883
...
@@ -36,6 +36,8 @@ type Metricer interface {
...
@@ -36,6 +36,8 @@ type Metricer interface {
RecordInfo
(
version
string
)
RecordInfo
(
version
string
)
RecordUp
()
RecordUp
()
RecordClaimResolutionDelayMax
(
delay
float64
)
RecordGamesStatus
(
inProgress
,
defenderWon
,
challengerWon
int
)
RecordGamesStatus
(
inProgress
,
defenderWon
,
challengerWon
int
)
RecordGameAgreement
(
status
GameAgreementStatus
,
count
int
)
RecordGameAgreement
(
status
GameAgreementStatus
,
count
int
)
...
@@ -55,6 +57,8 @@ type Metrics struct {
...
@@ -55,6 +57,8 @@ type Metrics struct {
info
prometheus
.
GaugeVec
info
prometheus
.
GaugeVec
up
prometheus
.
Gauge
up
prometheus
.
Gauge
claimResolutionDelayMax
prometheus
.
Gauge
trackedGames
prometheus
.
GaugeVec
trackedGames
prometheus
.
GaugeVec
gamesAgreement
prometheus
.
GaugeVec
gamesAgreement
prometheus
.
GaugeVec
}
}
...
@@ -88,6 +92,11 @@ func NewMetrics() *Metrics {
...
@@ -88,6 +92,11 @@ func NewMetrics() *Metrics {
Name
:
"up"
,
Name
:
"up"
,
Help
:
"1 if the op-challenger has finished starting up"
,
Help
:
"1 if the op-challenger has finished starting up"
,
}),
}),
claimResolutionDelayMax
:
factory
.
NewGauge
(
prometheus
.
GaugeOpts
{
Namespace
:
Namespace
,
Name
:
"claim_resolution_delay_max"
,
Help
:
"Maximum claim resolution delay in seconds"
,
}),
trackedGames
:
*
factory
.
NewGaugeVec
(
prometheus
.
GaugeOpts
{
trackedGames
:
*
factory
.
NewGaugeVec
(
prometheus
.
GaugeOpts
{
Namespace
:
Namespace
,
Namespace
:
Namespace
,
Name
:
"tracked_games"
,
Name
:
"tracked_games"
,
...
@@ -132,6 +141,10 @@ func (m *Metrics) RecordUp() {
...
@@ -132,6 +141,10 @@ func (m *Metrics) RecordUp() {
m
.
up
.
Set
(
1
)
m
.
up
.
Set
(
1
)
}
}
func
(
m
*
Metrics
)
RecordClaimResolutionDelayMax
(
delay
float64
)
{
m
.
claimResolutionDelayMax
.
Set
(
delay
)
}
func
(
m
*
Metrics
)
Document
()
[]
opmetrics
.
DocumentedMetric
{
func
(
m
*
Metrics
)
Document
()
[]
opmetrics
.
DocumentedMetric
{
return
m
.
factory
.
Document
()
return
m
.
factory
.
Document
()
}
}
...
...
op-dispute-mon/metrics/noop.go
View file @
134f6883
...
@@ -10,5 +10,7 @@ func (*NoopMetricsImpl) RecordUp() {}
...
@@ -10,5 +10,7 @@ func (*NoopMetricsImpl) RecordUp() {}
func
(
*
NoopMetricsImpl
)
CacheAdd
(
_
string
,
_
int
,
_
bool
)
{}
func
(
*
NoopMetricsImpl
)
CacheAdd
(
_
string
,
_
int
,
_
bool
)
{}
func
(
*
NoopMetricsImpl
)
CacheGet
(
_
string
,
_
bool
)
{}
func
(
*
NoopMetricsImpl
)
CacheGet
(
_
string
,
_
bool
)
{}
func
(
*
NoopMetricsImpl
)
RecordClaimResolutionDelayMax
(
delay
float64
)
{}
func
(
*
NoopMetricsImpl
)
RecordGamesStatus
(
inProgress
,
defenderWon
,
challengerWon
int
)
{}
func
(
*
NoopMetricsImpl
)
RecordGamesStatus
(
inProgress
,
defenderWon
,
challengerWon
int
)
{}
func
(
*
NoopMetricsImpl
)
RecordGameAgreement
(
status
GameAgreementStatus
,
count
int
)
{}
func
(
*
NoopMetricsImpl
)
RecordGameAgreement
(
status
GameAgreementStatus
,
count
int
)
{}
op-dispute-mon/mon/bonds/bonds.go
View file @
134f6883
...
@@ -6,13 +6,12 @@ import (
...
@@ -6,13 +6,12 @@ import (
"math/big"
"math/big"
faultTypes
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
faultTypes
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
monTypes
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"golang.org/x/exp/maps"
"golang.org/x/exp/maps"
)
)
var
noBond
=
new
(
big
.
Int
)
.
Sub
(
new
(
big
.
Int
)
.
Lsh
(
big
.
NewInt
(
1
),
128
),
big
.
NewInt
(
1
))
type
BondContract
interface
{
type
BondContract
interface
{
GetCredits
(
ctx
context
.
Context
,
block
batching
.
Block
,
recipients
...
common
.
Address
)
([]
*
big
.
Int
,
error
)
GetCredits
(
ctx
context
.
Context
,
block
batching
.
Block
,
recipients
...
common
.
Address
)
([]
*
big
.
Int
,
error
)
}
}
...
@@ -24,7 +23,7 @@ func CalculateRequiredCollateral(ctx context.Context, contract BondContract, blo
...
@@ -24,7 +23,7 @@ func CalculateRequiredCollateral(ctx context.Context, contract BondContract, blo
unpaidBonds
:=
big
.
NewInt
(
0
)
unpaidBonds
:=
big
.
NewInt
(
0
)
recipients
:=
make
(
map
[
common
.
Address
]
bool
)
recipients
:=
make
(
map
[
common
.
Address
]
bool
)
for
_
,
claim
:=
range
claims
{
for
_
,
claim
:=
range
claims
{
if
noBond
.
Cmp
(
claim
.
Bond
)
!=
0
{
if
monTypes
.
ResolvedBondAmount
.
Cmp
(
claim
.
Bond
)
!=
0
{
unpaidBonds
=
new
(
big
.
Int
)
.
Add
(
unpaidBonds
,
claim
.
Bond
)
unpaidBonds
=
new
(
big
.
Int
)
.
Add
(
unpaidBonds
,
claim
.
Bond
)
}
}
recipients
[
claim
.
Claimant
]
=
true
recipients
[
claim
.
Claimant
]
=
true
...
...
op-dispute-mon/mon/bonds/bonds_test.go
View file @
134f6883
...
@@ -6,20 +6,17 @@ import (
...
@@ -6,20 +6,17 @@ import (
"testing"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
monTypes
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/require"
)
)
func
TestMaxValue
(
t
*
testing
.
T
)
{
require
.
Equal
(
t
,
noBond
.
String
(),
"340282366920938463463374607431768211455"
)
}
func
TestCalculateRequiredCollateral
(
t
*
testing
.
T
)
{
func
TestCalculateRequiredCollateral
(
t
*
testing
.
T
)
{
claims
:=
[]
types
.
Claim
{
claims
:=
[]
types
.
Claim
{
{
{
ClaimData
:
types
.
ClaimData
{
ClaimData
:
types
.
ClaimData
{
Bond
:
noBond
,
Bond
:
monTypes
.
ResolvedBondAmount
,
},
},
Claimant
:
common
.
Address
{
0x01
},
Claimant
:
common
.
Address
{
0x01
},
CounteredBy
:
common
.
Address
{
0x02
},
CounteredBy
:
common
.
Address
{
0x02
},
...
...
op-dispute-mon/mon/extract/caller.go
View file @
134f6883
...
@@ -16,8 +16,8 @@ import (
...
@@ -16,8 +16,8 @@ import (
const
metricsLabel
=
"game_caller_creator"
const
metricsLabel
=
"game_caller_creator"
type
GameCaller
interface
{
type
GameCaller
interface
{
GetGameMetadata
(
context
.
Context
)
(
uint64
,
common
.
Hash
,
types
.
GameStatus
,
error
)
GetGameMetadata
(
context
.
Context
)
(
uint64
,
common
.
Hash
,
types
.
GameStatus
,
uint64
,
error
)
GetAllClaims
(
c
tx
c
ontext
.
Context
)
([]
faultTypes
.
Claim
,
error
)
GetAllClaims
(
context
.
Context
)
([]
faultTypes
.
Claim
,
error
)
}
}
type
GameCallerCreator
struct
{
type
GameCallerCreator
struct
{
...
...
op-dispute-mon/mon/extract/extractor.go
View file @
134f6883
...
@@ -44,7 +44,7 @@ func (e *Extractor) enrichGames(ctx context.Context, games []gameTypes.GameMetad
...
@@ -44,7 +44,7 @@ func (e *Extractor) enrichGames(ctx context.Context, games []gameTypes.GameMetad
e
.
logger
.
Error
(
"failed to create game caller"
,
"err"
,
err
)
e
.
logger
.
Error
(
"failed to create game caller"
,
"err"
,
err
)
continue
continue
}
}
l2BlockNum
,
rootClaim
,
status
,
err
:=
caller
.
GetGameMetadata
(
ctx
)
l2BlockNum
,
rootClaim
,
status
,
duration
,
err
:=
caller
.
GetGameMetadata
(
ctx
)
if
err
!=
nil
{
if
err
!=
nil
{
e
.
logger
.
Error
(
"failed to fetch game metadata"
,
"err"
,
err
)
e
.
logger
.
Error
(
"failed to fetch game metadata"
,
"err"
,
err
)
continue
continue
...
@@ -59,6 +59,7 @@ func (e *Extractor) enrichGames(ctx context.Context, games []gameTypes.GameMetad
...
@@ -59,6 +59,7 @@ func (e *Extractor) enrichGames(ctx context.Context, games []gameTypes.GameMetad
L2BlockNumber
:
l2BlockNum
,
L2BlockNumber
:
l2BlockNum
,
RootClaim
:
rootClaim
,
RootClaim
:
rootClaim
,
Status
:
status
,
Status
:
status
,
Duration
:
duration
,
Claims
:
claims
,
Claims
:
claims
,
})
})
}
}
...
...
op-dispute-mon/mon/extract/extractor_test.go
View file @
134f6883
...
@@ -37,7 +37,7 @@ func TestExtractor_Extract(t *testing.T) {
...
@@ -37,7 +37,7 @@ func TestExtractor_Extract(t *testing.T) {
require
.
Equal
(
t
,
1
,
creator
.
calls
)
require
.
Equal
(
t
,
1
,
creator
.
calls
)
require
.
Equal
(
t
,
0
,
creator
.
caller
.
metadataCalls
)
require
.
Equal
(
t
,
0
,
creator
.
caller
.
metadataCalls
)
require
.
Equal
(
t
,
0
,
creator
.
caller
.
claimsCalls
)
require
.
Equal
(
t
,
0
,
creator
.
caller
.
claimsCalls
)
verifyLogs
(
t
,
logs
,
1
,
0
,
0
)
verifyLogs
(
t
,
logs
,
1
,
0
,
0
,
0
)
})
})
t
.
Run
(
"MetadataFetchErrorLog"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"MetadataFetchErrorLog"
,
func
(
t
*
testing
.
T
)
{
...
@@ -51,7 +51,7 @@ func TestExtractor_Extract(t *testing.T) {
...
@@ -51,7 +51,7 @@ func TestExtractor_Extract(t *testing.T) {
require
.
Equal
(
t
,
1
,
creator
.
calls
)
require
.
Equal
(
t
,
1
,
creator
.
calls
)
require
.
Equal
(
t
,
1
,
creator
.
caller
.
metadataCalls
)
require
.
Equal
(
t
,
1
,
creator
.
caller
.
metadataCalls
)
require
.
Equal
(
t
,
0
,
creator
.
caller
.
claimsCalls
)
require
.
Equal
(
t
,
0
,
creator
.
caller
.
claimsCalls
)
verifyLogs
(
t
,
logs
,
0
,
1
,
0
)
verifyLogs
(
t
,
logs
,
0
,
1
,
0
,
0
)
})
})
t
.
Run
(
"ClaimsFetchErrorLog"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"ClaimsFetchErrorLog"
,
func
(
t
*
testing
.
T
)
{
...
@@ -65,7 +65,7 @@ func TestExtractor_Extract(t *testing.T) {
...
@@ -65,7 +65,7 @@ func TestExtractor_Extract(t *testing.T) {
require
.
Equal
(
t
,
1
,
creator
.
calls
)
require
.
Equal
(
t
,
1
,
creator
.
calls
)
require
.
Equal
(
t
,
1
,
creator
.
caller
.
metadataCalls
)
require
.
Equal
(
t
,
1
,
creator
.
caller
.
metadataCalls
)
require
.
Equal
(
t
,
1
,
creator
.
caller
.
claimsCalls
)
require
.
Equal
(
t
,
1
,
creator
.
caller
.
claimsCalls
)
verifyLogs
(
t
,
logs
,
0
,
0
,
1
)
verifyLogs
(
t
,
logs
,
0
,
0
,
1
,
0
)
})
})
t
.
Run
(
"Success"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"Success"
,
func
(
t
*
testing
.
T
)
{
...
@@ -81,7 +81,7 @@ func TestExtractor_Extract(t *testing.T) {
...
@@ -81,7 +81,7 @@ func TestExtractor_Extract(t *testing.T) {
})
})
}
}
func
verifyLogs
(
t
*
testing
.
T
,
logs
*
testlog
.
CapturingHandler
,
createErr
int
,
metadataErr
int
,
claimsErr
int
)
{
func
verifyLogs
(
t
*
testing
.
T
,
logs
*
testlog
.
CapturingHandler
,
createErr
int
,
metadataErr
int
,
claimsErr
int
,
durationErr
int
)
{
errorLevelFilter
:=
testlog
.
NewLevelFilter
(
log
.
LevelError
)
errorLevelFilter
:=
testlog
.
NewLevelFilter
(
log
.
LevelError
)
createMessageFilter
:=
testlog
.
NewMessageFilter
(
"failed to create game caller"
)
createMessageFilter
:=
testlog
.
NewMessageFilter
(
"failed to create game caller"
)
l
:=
logs
.
FindLogs
(
errorLevelFilter
,
createMessageFilter
)
l
:=
logs
.
FindLogs
(
errorLevelFilter
,
createMessageFilter
)
...
@@ -92,6 +92,9 @@ func verifyLogs(t *testing.T, logs *testlog.CapturingHandler, createErr int, met
...
@@ -92,6 +92,9 @@ func verifyLogs(t *testing.T, logs *testlog.CapturingHandler, createErr int, met
claimsMessageFilter
:=
testlog
.
NewMessageFilter
(
"failed to fetch game claims"
)
claimsMessageFilter
:=
testlog
.
NewMessageFilter
(
"failed to fetch game claims"
)
l
=
logs
.
FindLogs
(
errorLevelFilter
,
claimsMessageFilter
)
l
=
logs
.
FindLogs
(
errorLevelFilter
,
claimsMessageFilter
)
require
.
Len
(
t
,
l
,
claimsErr
)
require
.
Len
(
t
,
l
,
claimsErr
)
durationMessageFilter
:=
testlog
.
NewMessageFilter
(
"failed to fetch game duration"
)
l
=
logs
.
FindLogs
(
errorLevelFilter
,
durationMessageFilter
)
require
.
Len
(
t
,
l
,
durationErr
)
}
}
func
setupExtractorTest
(
t
*
testing
.
T
)
(
*
Extractor
,
*
mockGameCallerCreator
,
*
mockGameFetcher
,
*
testlog
.
CapturingHandler
)
{
func
setupExtractorTest
(
t
*
testing
.
T
)
(
*
Extractor
,
*
mockGameCallerCreator
,
*
mockGameFetcher
,
*
testlog
.
CapturingHandler
)
{
...
@@ -146,12 +149,12 @@ type mockGameCaller struct {
...
@@ -146,12 +149,12 @@ type mockGameCaller struct {
claims
[]
faultTypes
.
Claim
claims
[]
faultTypes
.
Claim
}
}
func
(
m
*
mockGameCaller
)
GetGameMetadata
(
_
context
.
Context
)
(
uint64
,
common
.
Hash
,
types
.
GameStatus
,
error
)
{
func
(
m
*
mockGameCaller
)
GetGameMetadata
(
_
context
.
Context
)
(
uint64
,
common
.
Hash
,
types
.
GameStatus
,
uint64
,
error
)
{
m
.
metadataCalls
++
m
.
metadataCalls
++
if
m
.
metadataErr
!=
nil
{
if
m
.
metadataErr
!=
nil
{
return
0
,
common
.
Hash
{},
0
,
m
.
metadataErr
return
0
,
common
.
Hash
{},
0
,
0
,
m
.
metadataErr
}
}
return
0
,
mockRootClaim
,
0
,
nil
return
0
,
mockRootClaim
,
0
,
0
,
nil
}
}
func
(
m
*
mockGameCaller
)
GetAllClaims
(
ctx
context
.
Context
)
([]
faultTypes
.
Claim
,
error
)
{
func
(
m
*
mockGameCaller
)
GetAllClaims
(
ctx
context
.
Context
)
([]
faultTypes
.
Claim
,
error
)
{
...
...
op-dispute-mon/mon/forecast.go
View file @
134f6883
...
@@ -7,6 +7,7 @@ import (
...
@@ -7,6 +7,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-dispute-mon/metrics"
"github.com/ethereum-optimism/optimism/op-dispute-mon/metrics"
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/resolution"
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/transform"
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/transform"
monTypes
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
monTypes
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
...
@@ -21,6 +22,7 @@ var (
...
@@ -21,6 +22,7 @@ var (
)
)
type
ForecastMetrics
interface
{
type
ForecastMetrics
interface
{
RecordClaimResolutionDelayMax
(
delay
float64
)
RecordGameAgreement
(
status
metrics
.
GameAgreementStatus
,
count
int
)
RecordGameAgreement
(
status
metrics
.
GameAgreementStatus
,
count
int
)
}
}
...
@@ -65,7 +67,7 @@ func (f *forecast) forecastGame(ctx context.Context, game *monTypes.EnrichedGame
...
@@ -65,7 +67,7 @@ func (f *forecast) forecastGame(ctx context.Context, game *monTypes.EnrichedGame
tree
:=
transform
.
CreateBidirectionalTree
(
game
.
Claims
)
tree
:=
transform
.
CreateBidirectionalTree
(
game
.
Claims
)
// Compute the resolution status of the game.
// Compute the resolution status of the game.
status
:=
Resolve
(
tree
)
status
:=
resolution
.
Resolve
(
tree
)
// Check the root agreement.
// Check the root agreement.
agreement
,
expected
,
err
:=
f
.
validator
.
CheckRootAgreement
(
ctx
,
game
.
L2BlockNumber
,
game
.
RootClaim
)
agreement
,
expected
,
err
:=
f
.
validator
.
CheckRootAgreement
(
ctx
,
game
.
L2BlockNumber
,
game
.
RootClaim
)
...
...
op-dispute-mon/mon/forecast_test.go
View file @
134f6883
...
@@ -4,6 +4,8 @@ import (
...
@@ -4,6 +4,8 @@ import (
"context"
"context"
"errors"
"errors"
"fmt"
"fmt"
"math"
"math/big"
"testing"
"testing"
faultTypes
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
faultTypes
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
...
@@ -267,6 +269,7 @@ type mockForecastMetrics struct {
...
@@ -267,6 +269,7 @@ type mockForecastMetrics struct {
disagreeDefenderAhead
int
disagreeDefenderAhead
int
agreeChallengerAhead
int
agreeChallengerAhead
int
disagreeChallengerAhead
int
disagreeChallengerAhead
int
claimResolutionDelayMax
float64
}
}
func
(
m
*
mockForecastMetrics
)
RecordGameAgreement
(
status
metrics
.
GameAgreementStatus
,
count
int
)
{
func
(
m
*
mockForecastMetrics
)
RecordGameAgreement
(
status
metrics
.
GameAgreementStatus
,
count
int
)
{
...
@@ -281,3 +284,38 @@ func (m *mockForecastMetrics) RecordGameAgreement(status metrics.GameAgreementSt
...
@@ -281,3 +284,38 @@ func (m *mockForecastMetrics) RecordGameAgreement(status metrics.GameAgreementSt
m
.
disagreeChallengerAhead
=
count
m
.
disagreeChallengerAhead
=
count
}
}
}
}
func
(
m
*
mockForecastMetrics
)
RecordClaimResolutionDelayMax
(
delay
float64
)
{
m
.
claimResolutionDelayMax
=
delay
}
func
createDeepClaimList
()
[]
faultTypes
.
Claim
{
return
[]
faultTypes
.
Claim
{
{
ClaimData
:
faultTypes
.
ClaimData
{
Position
:
faultTypes
.
NewPosition
(
0
,
big
.
NewInt
(
0
)),
},
ContractIndex
:
0
,
CounteredBy
:
common
.
HexToAddress
(
"0x222222"
),
ParentContractIndex
:
math
.
MaxInt64
,
Claimant
:
common
.
HexToAddress
(
"0x111111"
),
},
{
ClaimData
:
faultTypes
.
ClaimData
{
Position
:
faultTypes
.
NewPosition
(
1
,
big
.
NewInt
(
0
)),
},
CounteredBy
:
common
.
HexToAddress
(
"0x111111"
),
ContractIndex
:
1
,
ParentContractIndex
:
0
,
Claimant
:
common
.
HexToAddress
(
"0x222222"
),
},
{
ClaimData
:
faultTypes
.
ClaimData
{
Position
:
faultTypes
.
NewPosition
(
2
,
big
.
NewInt
(
0
)),
},
ContractIndex
:
2
,
ParentContractIndex
:
1
,
Claimant
:
common
.
HexToAddress
(
"0x111111"
),
},
}
}
op-dispute-mon/mon/monitor.go
View file @
134f6883
...
@@ -18,6 +18,7 @@ type Forecast func(ctx context.Context, games []*types.EnrichedGameData)
...
@@ -18,6 +18,7 @@ type Forecast func(ctx context.Context, games []*types.EnrichedGameData)
type
BlockHashFetcher
func
(
ctx
context
.
Context
,
number
*
big
.
Int
)
(
common
.
Hash
,
error
)
type
BlockHashFetcher
func
(
ctx
context
.
Context
,
number
*
big
.
Int
)
(
common
.
Hash
,
error
)
type
BlockNumberFetcher
func
(
ctx
context
.
Context
)
(
uint64
,
error
)
type
BlockNumberFetcher
func
(
ctx
context
.
Context
)
(
uint64
,
error
)
type
Extract
func
(
ctx
context
.
Context
,
blockHash
common
.
Hash
,
minTimestamp
uint64
)
([]
*
types
.
EnrichedGameData
,
error
)
type
Extract
func
(
ctx
context
.
Context
,
blockHash
common
.
Hash
,
minTimestamp
uint64
)
([]
*
types
.
EnrichedGameData
,
error
)
type
RecordClaimResolutionDelayMax
func
([]
*
types
.
EnrichedGameData
)
type
gameMonitor
struct
{
type
gameMonitor
struct
{
logger
log
.
Logger
logger
log
.
Logger
...
@@ -30,6 +31,7 @@ type gameMonitor struct {
...
@@ -30,6 +31,7 @@ type gameMonitor struct {
gameWindow
time
.
Duration
gameWindow
time
.
Duration
monitorInterval
time
.
Duration
monitorInterval
time
.
Duration
delays
RecordClaimResolutionDelayMax
detect
Detect
detect
Detect
forecast
Forecast
forecast
Forecast
extract
Extract
extract
Extract
...
@@ -43,6 +45,7 @@ func newGameMonitor(
...
@@ -43,6 +45,7 @@ func newGameMonitor(
cl
clock
.
Clock
,
cl
clock
.
Clock
,
monitorInterval
time
.
Duration
,
monitorInterval
time
.
Duration
,
gameWindow
time
.
Duration
,
gameWindow
time
.
Duration
,
delays
RecordClaimResolutionDelayMax
,
detect
Detect
,
detect
Detect
,
forecast
Forecast
,
forecast
Forecast
,
extract
Extract
,
extract
Extract
,
...
@@ -56,6 +59,7 @@ func newGameMonitor(
...
@@ -56,6 +59,7 @@ func newGameMonitor(
done
:
make
(
chan
struct
{}),
done
:
make
(
chan
struct
{}),
monitorInterval
:
monitorInterval
,
monitorInterval
:
monitorInterval
,
gameWindow
:
gameWindow
,
gameWindow
:
gameWindow
,
delays
:
delays
,
detect
:
detect
,
detect
:
detect
,
forecast
:
forecast
,
forecast
:
forecast
,
extract
:
extract
,
extract
:
extract
,
...
@@ -90,6 +94,7 @@ func (m *gameMonitor) monitorGames() error {
...
@@ -90,6 +94,7 @@ func (m *gameMonitor) monitorGames() error {
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to load games: %w"
,
err
)
return
fmt
.
Errorf
(
"failed to load games: %w"
,
err
)
}
}
m
.
delays
(
enrichedGames
)
m
.
detect
(
m
.
ctx
,
enrichedGames
)
m
.
detect
(
m
.
ctx
,
enrichedGames
)
m
.
forecast
(
m
.
ctx
,
enrichedGames
)
m
.
forecast
(
m
.
ctx
,
enrichedGames
)
return
nil
return
nil
...
...
op-dispute-mon/mon/monitor_test.go
View file @
134f6883
...
@@ -24,20 +24,20 @@ func TestMonitor_MinGameTimestamp(t *testing.T) {
...
@@ -24,20 +24,20 @@ func TestMonitor_MinGameTimestamp(t *testing.T) {
t
.
Parallel
()
t
.
Parallel
()
t
.
Run
(
"ZeroGameWindow"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"ZeroGameWindow"
,
func
(
t
*
testing
.
T
)
{
monitor
,
_
,
_
,
_
:=
setupMonitorTest
(
t
)
monitor
,
_
,
_
,
_
,
_
:=
setupMonitorTest
(
t
)
monitor
.
gameWindow
=
time
.
Duration
(
0
)
monitor
.
gameWindow
=
time
.
Duration
(
0
)
require
.
Equal
(
t
,
monitor
.
minGameTimestamp
(),
uint64
(
0
))
require
.
Equal
(
t
,
monitor
.
minGameTimestamp
(),
uint64
(
0
))
})
})
t
.
Run
(
"ZeroClock"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"ZeroClock"
,
func
(
t
*
testing
.
T
)
{
monitor
,
_
,
_
,
_
:=
setupMonitorTest
(
t
)
monitor
,
_
,
_
,
_
,
_
:=
setupMonitorTest
(
t
)
monitor
.
gameWindow
=
time
.
Minute
monitor
.
gameWindow
=
time
.
Minute
monitor
.
clock
=
clock
.
NewDeterministicClock
(
time
.
Unix
(
0
,
0
))
monitor
.
clock
=
clock
.
NewDeterministicClock
(
time
.
Unix
(
0
,
0
))
require
.
Equal
(
t
,
uint64
(
0
),
monitor
.
minGameTimestamp
())
require
.
Equal
(
t
,
uint64
(
0
),
monitor
.
minGameTimestamp
())
})
})
t
.
Run
(
"ValidArithmetic"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"ValidArithmetic"
,
func
(
t
*
testing
.
T
)
{
monitor
,
_
,
_
,
_
:=
setupMonitorTest
(
t
)
monitor
,
_
,
_
,
_
,
_
:=
setupMonitorTest
(
t
)
monitor
.
gameWindow
=
time
.
Minute
monitor
.
gameWindow
=
time
.
Minute
frozen
:=
time
.
Unix
(
int64
(
time
.
Hour
.
Seconds
()),
0
)
frozen
:=
time
.
Unix
(
int64
(
time
.
Hour
.
Seconds
()),
0
)
monitor
.
clock
=
clock
.
NewDeterministicClock
(
frozen
)
monitor
.
clock
=
clock
.
NewDeterministicClock
(
frozen
)
...
@@ -50,7 +50,7 @@ func TestMonitor_MonitorGames(t *testing.T) {
...
@@ -50,7 +50,7 @@ func TestMonitor_MonitorGames(t *testing.T) {
t
.
Parallel
()
t
.
Parallel
()
t
.
Run
(
"FailedFetchBlocknumber"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"FailedFetchBlocknumber"
,
func
(
t
*
testing
.
T
)
{
monitor
,
_
,
_
,
_
:=
setupMonitorTest
(
t
)
monitor
,
_
,
_
,
_
,
_
:=
setupMonitorTest
(
t
)
boom
:=
errors
.
New
(
"boom"
)
boom
:=
errors
.
New
(
"boom"
)
monitor
.
fetchBlockNumber
=
func
(
ctx
context
.
Context
)
(
uint64
,
error
)
{
monitor
.
fetchBlockNumber
=
func
(
ctx
context
.
Context
)
(
uint64
,
error
)
{
return
0
,
boom
return
0
,
boom
...
@@ -60,7 +60,7 @@ func TestMonitor_MonitorGames(t *testing.T) {
...
@@ -60,7 +60,7 @@ func TestMonitor_MonitorGames(t *testing.T) {
})
})
t
.
Run
(
"FailedFetchBlockHash"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"FailedFetchBlockHash"
,
func
(
t
*
testing
.
T
)
{
monitor
,
_
,
_
,
_
:=
setupMonitorTest
(
t
)
monitor
,
_
,
_
,
_
,
_
:=
setupMonitorTest
(
t
)
boom
:=
errors
.
New
(
"boom"
)
boom
:=
errors
.
New
(
"boom"
)
monitor
.
fetchBlockHash
=
func
(
ctx
context
.
Context
,
number
*
big
.
Int
)
(
common
.
Hash
,
error
)
{
monitor
.
fetchBlockHash
=
func
(
ctx
context
.
Context
,
number
*
big
.
Int
)
(
common
.
Hash
,
error
)
{
return
common
.
Hash
{},
boom
return
common
.
Hash
{},
boom
...
@@ -70,19 +70,23 @@ func TestMonitor_MonitorGames(t *testing.T) {
...
@@ -70,19 +70,23 @@ func TestMonitor_MonitorGames(t *testing.T) {
})
})
t
.
Run
(
"DetectsWithNoGames"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"DetectsWithNoGames"
,
func
(
t
*
testing
.
T
)
{
monitor
,
factory
,
detector
,
_
:=
setupMonitorTest
(
t
)
monitor
,
factory
,
detector
,
forecast
,
delays
:=
setupMonitorTest
(
t
)
factory
.
games
=
[]
*
monTypes
.
EnrichedGameData
{}
factory
.
games
=
[]
*
monTypes
.
EnrichedGameData
{}
err
:=
monitor
.
monitorGames
()
err
:=
monitor
.
monitorGames
()
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
1
,
detector
.
calls
)
require
.
Equal
(
t
,
1
,
detector
.
calls
)
require
.
Equal
(
t
,
1
,
forecast
.
calls
)
require
.
Equal
(
t
,
1
,
delays
.
calls
)
})
})
t
.
Run
(
"DetectsMultipleGames"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"DetectsMultipleGames"
,
func
(
t
*
testing
.
T
)
{
monitor
,
factory
,
detector
,
_
:=
setupMonitorTest
(
t
)
monitor
,
factory
,
detector
,
forecast
,
delays
:=
setupMonitorTest
(
t
)
factory
.
games
=
[]
*
monTypes
.
EnrichedGameData
{{},
{},
{}}
factory
.
games
=
[]
*
monTypes
.
EnrichedGameData
{{},
{},
{}}
err
:=
monitor
.
monitorGames
()
err
:=
monitor
.
monitorGames
()
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
1
,
detector
.
calls
)
require
.
Equal
(
t
,
1
,
detector
.
calls
)
require
.
Equal
(
t
,
1
,
forecast
.
calls
)
require
.
Equal
(
t
,
1
,
delays
.
calls
)
})
})
}
}
...
@@ -90,7 +94,7 @@ func TestMonitor_StartMonitoring(t *testing.T) {
...
@@ -90,7 +94,7 @@ func TestMonitor_StartMonitoring(t *testing.T) {
t
.
Run
(
"MonitorsGames"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"MonitorsGames"
,
func
(
t
*
testing
.
T
)
{
addr1
:=
common
.
Address
{
0xaa
}
addr1
:=
common
.
Address
{
0xaa
}
addr2
:=
common
.
Address
{
0xbb
}
addr2
:=
common
.
Address
{
0xbb
}
monitor
,
factory
,
detector
,
_
:=
setupMonitorTest
(
t
)
monitor
,
factory
,
detector
,
_
,
_
:=
setupMonitorTest
(
t
)
factory
.
games
=
[]
*
monTypes
.
EnrichedGameData
{
newEnrichedGameData
(
addr1
,
9999
),
newEnrichedGameData
(
addr2
,
9999
)}
factory
.
games
=
[]
*
monTypes
.
EnrichedGameData
{
newEnrichedGameData
(
addr1
,
9999
),
newEnrichedGameData
(
addr2
,
9999
)}
factory
.
maxSuccess
=
len
(
factory
.
games
)
// Only allow two successful fetches
factory
.
maxSuccess
=
len
(
factory
.
games
)
// Only allow two successful fetches
...
@@ -103,7 +107,7 @@ func TestMonitor_StartMonitoring(t *testing.T) {
...
@@ -103,7 +107,7 @@ func TestMonitor_StartMonitoring(t *testing.T) {
})
})
t
.
Run
(
"FailsToFetchGames"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"FailsToFetchGames"
,
func
(
t
*
testing
.
T
)
{
monitor
,
factory
,
detector
,
_
:=
setupMonitorTest
(
t
)
monitor
,
factory
,
detector
,
_
,
_
:=
setupMonitorTest
(
t
)
factory
.
fetchErr
=
errors
.
New
(
"boom"
)
factory
.
fetchErr
=
errors
.
New
(
"boom"
)
monitor
.
StartMonitoring
()
monitor
.
StartMonitoring
()
...
@@ -125,7 +129,7 @@ func newEnrichedGameData(proxy common.Address, timestamp uint64) *monTypes.Enric
...
@@ -125,7 +129,7 @@ func newEnrichedGameData(proxy common.Address, timestamp uint64) *monTypes.Enric
}
}
}
}
func
setupMonitorTest
(
t
*
testing
.
T
)
(
*
gameMonitor
,
*
mockExtractor
,
*
mockDetector
,
*
mockForecast
)
{
func
setupMonitorTest
(
t
*
testing
.
T
)
(
*
gameMonitor
,
*
mockExtractor
,
*
mockDetector
,
*
mockForecast
,
*
mockDelayCalculator
)
{
logger
:=
testlog
.
Logger
(
t
,
log
.
LvlDebug
)
logger
:=
testlog
.
Logger
(
t
,
log
.
LvlDebug
)
fetchBlockNum
:=
func
(
ctx
context
.
Context
)
(
uint64
,
error
)
{
fetchBlockNum
:=
func
(
ctx
context
.
Context
)
(
uint64
,
error
)
{
return
1
,
nil
return
1
,
nil
...
@@ -139,19 +143,29 @@ func setupMonitorTest(t *testing.T) (*gameMonitor, *mockExtractor, *mockDetector
...
@@ -139,19 +143,29 @@ func setupMonitorTest(t *testing.T) (*gameMonitor, *mockExtractor, *mockDetector
extractor
:=
&
mockExtractor
{}
extractor
:=
&
mockExtractor
{}
detect
:=
&
mockDetector
{}
detect
:=
&
mockDetector
{}
forecast
:=
&
mockForecast
{}
forecast
:=
&
mockForecast
{}
delays
:=
&
mockDelayCalculator
{}
monitor
:=
newGameMonitor
(
monitor
:=
newGameMonitor
(
context
.
Background
(),
context
.
Background
(),
logger
,
logger
,
cl
,
cl
,
monitorInterval
,
monitorInterval
,
time
.
Duration
(
10
*
time
.
Second
),
time
.
Duration
(
10
*
time
.
Second
),
delays
.
RecordClaimResolutionDelayMax
,
detect
.
Detect
,
detect
.
Detect
,
forecast
.
Forecast
,
forecast
.
Forecast
,
extractor
.
Extract
,
extractor
.
Extract
,
fetchBlockNum
,
fetchBlockNum
,
fetchBlockHash
,
fetchBlockHash
,
)
)
return
monitor
,
extractor
,
detect
,
forecast
return
monitor
,
extractor
,
detect
,
forecast
,
delays
}
type
mockDelayCalculator
struct
{
calls
int
}
func
(
m
*
mockDelayCalculator
)
RecordClaimResolutionDelayMax
(
games
[]
*
monTypes
.
EnrichedGameData
)
{
m
.
calls
++
}
}
type
mockForecast
struct
{
type
mockForecast
struct
{
...
...
op-dispute-mon/mon/resolution/delay.go
0 → 100644
View file @
134f6883
package
resolution
import
(
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
monTypes
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum-optimism/optimism/op-service/clock"
)
type
DelayMetrics
interface
{
RecordClaimResolutionDelayMax
(
delay
float64
)
}
type
DelayCalculator
struct
{
metrics
DelayMetrics
clock
clock
.
Clock
}
func
NewDelayCalculator
(
metrics
DelayMetrics
,
clock
clock
.
Clock
)
*
DelayCalculator
{
return
&
DelayCalculator
{
metrics
:
metrics
,
clock
:
clock
,
}
}
func
(
d
*
DelayCalculator
)
RecordClaimResolutionDelayMax
(
games
[]
*
monTypes
.
EnrichedGameData
)
{
var
maxDelay
uint64
=
0
for
_
,
game
:=
range
games
{
maxDelay
=
max
(
d
.
getMaxResolutionDelay
(
game
),
maxDelay
)
}
d
.
metrics
.
RecordClaimResolutionDelayMax
(
float64
(
maxDelay
))
}
func
(
d
*
DelayCalculator
)
getMaxResolutionDelay
(
game
*
monTypes
.
EnrichedGameData
)
uint64
{
var
maxDelay
uint64
=
0
for
_
,
claim
:=
range
game
.
Claims
{
maxDelay
=
max
(
d
.
getOverflowTime
(
game
.
Duration
,
&
claim
),
maxDelay
)
}
return
maxDelay
}
func
(
d
*
DelayCalculator
)
getOverflowTime
(
maxGameDuration
uint64
,
claim
*
types
.
Claim
)
uint64
{
// If the bond amount is the max uint128 value, the claim is resolved.
if
monTypes
.
ResolvedBondAmount
.
Cmp
(
claim
.
ClaimData
.
Bond
)
==
0
{
return
0
}
maxChessTime
:=
maxGameDuration
/
2
accumulatedTime
:=
uint64
(
claim
.
ChessTime
(
d
.
clock
.
Now
()))
if
accumulatedTime
<
maxChessTime
{
return
0
}
return
accumulatedTime
-
maxChessTime
}
op-dispute-mon/mon/resolution/delay_test.go
0 → 100644
View file @
134f6883
package
resolution
import
(
"math/big"
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
monTypes
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/stretchr/testify/require"
)
var
(
maxGameDuration
=
uint64
(
960
)
frozen
=
time
.
Unix
(
int64
(
time
.
Hour
.
Seconds
()),
0
)
)
func
TestDelayCalculator_getOverflowTime
(
t
*
testing
.
T
)
{
t
.
Run
(
"NoClock"
,
func
(
t
*
testing
.
T
)
{
d
,
metrics
,
_
:=
setupDelayCalculatorTest
(
t
)
claim
:=
&
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Bond
:
monTypes
.
ResolvedBondAmount
,
},
}
delay
:=
d
.
getOverflowTime
(
maxGameDuration
,
claim
)
require
.
Equal
(
t
,
uint64
(
0
),
delay
)
require
.
Equal
(
t
,
0
,
metrics
.
calls
)
})
t
.
Run
(
"RemainingTime"
,
func
(
t
*
testing
.
T
)
{
d
,
metrics
,
cl
:=
setupDelayCalculatorTest
(
t
)
duration
:=
uint64
(
3
*
60
)
timestamp
:=
uint64
(
cl
.
Now
()
.
Add
(
-
time
.
Minute
)
.
Unix
())
claim
:=
&
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Bond
:
big
.
NewInt
(
5
),
},
Clock
:
types
.
NewClock
(
duration
,
timestamp
),
}
delay
:=
d
.
getOverflowTime
(
maxGameDuration
,
claim
)
require
.
Equal
(
t
,
uint64
(
0
),
delay
)
require
.
Equal
(
t
,
0
,
metrics
.
calls
)
})
t
.
Run
(
"OverflowTime"
,
func
(
t
*
testing
.
T
)
{
d
,
metrics
,
cl
:=
setupDelayCalculatorTest
(
t
)
duration
:=
maxGameDuration
/
2
timestamp
:=
uint64
(
cl
.
Now
()
.
Add
(
4
*
-
time
.
Minute
)
.
Unix
())
claim
:=
&
types
.
Claim
{
ClaimData
:
types
.
ClaimData
{
Bond
:
big
.
NewInt
(
5
),
},
Clock
:
types
.
NewClock
(
duration
,
timestamp
),
}
delay
:=
d
.
getOverflowTime
(
maxGameDuration
,
claim
)
require
.
Equal
(
t
,
uint64
(
240
),
delay
)
require
.
Equal
(
t
,
0
,
metrics
.
calls
)
})
}
func
TestDelayCalculator_getMaxResolutionDelay
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
claims
[]
types
.
Claim
want
uint64
}{
{
"NoClaims"
,
[]
types
.
Claim
{},
0
},
{
"SingleClaim"
,
createClaimList
()[
:
1
],
180
},
{
"MultipleClaims"
,
createClaimList
()[
:
2
],
300
},
{
"ClaimsWithMaxUint128"
,
createClaimList
(),
300
},
}
for
_
,
test
:=
range
tests
{
test
:=
test
t
.
Run
(
test
.
name
,
func
(
t
*
testing
.
T
)
{
d
,
metrics
,
_
:=
setupDelayCalculatorTest
(
t
)
game
:=
&
monTypes
.
EnrichedGameData
{
Claims
:
test
.
claims
,
Duration
:
maxGameDuration
,
}
got
:=
d
.
getMaxResolutionDelay
(
game
)
require
.
Equal
(
t
,
0
,
metrics
.
calls
)
require
.
Equal
(
t
,
test
.
want
,
got
)
})
}
}
func
TestDelayCalculator_RecordClaimResolutionDelayMax
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
games
[]
*
monTypes
.
EnrichedGameData
want
float64
}{
{
"NoGames"
,
createGameWithClaimsList
()[
:
0
],
0
},
{
"SingleGame"
,
createGameWithClaimsList
()[
:
1
],
180
},
{
"MultipleGames"
,
createGameWithClaimsList
()[
:
2
],
300
},
{
"ClaimsWithMaxUint128"
,
createGameWithClaimsList
(),
300
},
}
for
_
,
test
:=
range
tests
{
test
:=
test
t
.
Run
(
test
.
name
,
func
(
t
*
testing
.
T
)
{
d
,
metrics
,
_
:=
setupDelayCalculatorTest
(
t
)
d
.
RecordClaimResolutionDelayMax
(
test
.
games
)
require
.
Equal
(
t
,
1
,
metrics
.
calls
)
require
.
Equal
(
t
,
test
.
want
,
metrics
.
maxDelay
)
})
}
}
func
setupDelayCalculatorTest
(
t
*
testing
.
T
)
(
*
DelayCalculator
,
*
mockDelayMetrics
,
*
clock
.
DeterministicClock
)
{
metrics
:=
&
mockDelayMetrics
{}
cl
:=
clock
.
NewDeterministicClock
(
frozen
)
return
NewDelayCalculator
(
metrics
,
cl
),
metrics
,
cl
}
func
createGameWithClaimsList
()
[]
*
monTypes
.
EnrichedGameData
{
return
[]
*
monTypes
.
EnrichedGameData
{
{
Claims
:
createClaimList
()[
:
1
],
Duration
:
maxGameDuration
,
},
{
Claims
:
createClaimList
()[
:
2
],
Duration
:
maxGameDuration
,
},
{
Claims
:
createClaimList
(),
Duration
:
maxGameDuration
,
},
}
}
func
createClaimList
()
[]
types
.
Claim
{
newClock
:=
func
(
multiplier
int
)
*
types
.
Clock
{
duration
:=
maxGameDuration
/
2
timestamp
:=
uint64
(
frozen
.
Add
(
-
time
.
Minute
*
time
.
Duration
(
multiplier
))
.
Unix
())
return
types
.
NewClock
(
duration
,
timestamp
)
}
return
[]
types
.
Claim
{
{
ClaimData
:
types
.
ClaimData
{
Bond
:
big
.
NewInt
(
5
),
},
Clock
:
newClock
(
3
),
},
{
ClaimData
:
types
.
ClaimData
{
Bond
:
big
.
NewInt
(
10
),
},
Clock
:
newClock
(
5
),
},
{
ClaimData
:
types
.
ClaimData
{
Bond
:
big
.
NewInt
(
100
),
},
Clock
:
newClock
(
2
),
},
{
// This claim should be skipped because it's resolved.
ClaimData
:
types
.
ClaimData
{
Bond
:
monTypes
.
ResolvedBondAmount
,
},
Clock
:
newClock
(
10
),
},
}
}
type
mockDelayMetrics
struct
{
calls
int
maxDelay
float64
}
func
(
m
*
mockDelayMetrics
)
RecordClaimResolutionDelayMax
(
delay
float64
)
{
m
.
calls
++
if
delay
>
m
.
maxDelay
{
m
.
maxDelay
=
delay
}
}
op-dispute-mon/mon/resolver.go
→
op-dispute-mon/mon/resol
ution/resol
ver.go
View file @
134f6883
package
m
on
package
resoluti
on
import
(
import
(
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
...
...
op-dispute-mon/mon/resolver_test.go
→
op-dispute-mon/mon/resol
ution/resol
ver_test.go
View file @
134f6883
package
m
on
package
resoluti
on
import
(
import
(
"math"
"math"
...
...
op-dispute-mon/mon/service.go
View file @
134f6883
...
@@ -14,6 +14,7 @@ import (
...
@@ -14,6 +14,7 @@ import (
"github.com/ethereum-optimism/optimism/op-dispute-mon/config"
"github.com/ethereum-optimism/optimism/op-dispute-mon/config"
"github.com/ethereum-optimism/optimism/op-dispute-mon/metrics"
"github.com/ethereum-optimism/optimism/op-dispute-mon/metrics"
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/extract"
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/extract"
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/resolution"
"github.com/ethereum-optimism/optimism/op-dispute-mon/version"
"github.com/ethereum-optimism/optimism/op-dispute-mon/version"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
...
@@ -35,6 +36,7 @@ type Service struct {
...
@@ -35,6 +36,7 @@ type Service struct {
cl
clock
.
Clock
cl
clock
.
Clock
delays
*
resolution
.
DelayCalculator
extractor
*
extract
.
Extractor
extractor
*
extract
.
Extractor
forecast
*
forecast
forecast
*
forecast
game
*
extract
.
GameCallerCreator
game
*
extract
.
GameCallerCreator
...
@@ -85,6 +87,7 @@ func (s *Service) initFromConfig(ctx context.Context, cfg *config.Config) error
...
@@ -85,6 +87,7 @@ func (s *Service) initFromConfig(ctx context.Context, cfg *config.Config) error
s
.
initOutputValidator
()
// Must be called before initForecast
s
.
initOutputValidator
()
// Must be called before initForecast
s
.
initGameCallerCreator
()
// Must be called before initForecast
s
.
initGameCallerCreator
()
// Must be called before initForecast
s
.
initDelayCalculator
()
s
.
initExtractor
()
s
.
initExtractor
()
s
.
initForecast
(
cfg
)
s
.
initForecast
(
cfg
)
...
@@ -106,6 +109,10 @@ func (s *Service) initGameCallerCreator() {
...
@@ -106,6 +109,10 @@ func (s *Service) initGameCallerCreator() {
s
.
game
=
extract
.
NewGameCallerCreator
(
s
.
metrics
,
batching
.
NewMultiCaller
(
s
.
l1Client
.
Client
(),
batching
.
DefaultBatchSize
))
s
.
game
=
extract
.
NewGameCallerCreator
(
s
.
metrics
,
batching
.
NewMultiCaller
(
s
.
l1Client
.
Client
(),
batching
.
DefaultBatchSize
))
}
}
func
(
s
*
Service
)
initDelayCalculator
()
{
s
.
delays
=
resolution
.
NewDelayCalculator
(
s
.
metrics
,
s
.
cl
)
}
func
(
s
*
Service
)
initExtractor
()
{
func
(
s
*
Service
)
initExtractor
()
{
s
.
extractor
=
extract
.
NewExtractor
(
s
.
logger
,
s
.
game
.
CreateContract
,
s
.
factoryContract
.
GetGamesAtOrAfter
)
s
.
extractor
=
extract
.
NewExtractor
(
s
.
logger
,
s
.
game
.
CreateContract
,
s
.
factoryContract
.
GetGamesAtOrAfter
)
}
}
...
@@ -195,6 +202,7 @@ func (s *Service) initMonitor(ctx context.Context, cfg *config.Config) {
...
@@ -195,6 +202,7 @@ func (s *Service) initMonitor(ctx context.Context, cfg *config.Config) {
s
.
cl
,
s
.
cl
,
cfg
.
MonitorInterval
,
cfg
.
MonitorInterval
,
cfg
.
GameWindow
,
cfg
.
GameWindow
,
s
.
delays
.
RecordClaimResolutionDelayMax
,
s
.
detector
.
Detect
,
s
.
detector
.
Detect
,
s
.
forecast
.
Forecast
,
s
.
forecast
.
Forecast
,
s
.
extractor
.
Extract
,
s
.
extractor
.
Extract
,
...
...
op-dispute-mon/mon/types/types.go
View file @
134f6883
package
types
package
types
import
(
import
(
"math/big"
faultTypes
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
faultTypes
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
)
)
// ResolvedBondAmount is the uint128 value where a bond is considered claimed.
var
ResolvedBondAmount
=
new
(
big
.
Int
)
.
Sub
(
new
(
big
.
Int
)
.
Lsh
(
big
.
NewInt
(
1
),
128
),
big
.
NewInt
(
1
))
type
EnrichedGameData
struct
{
type
EnrichedGameData
struct
{
types
.
GameMetadata
types
.
GameMetadata
L2BlockNumber
uint64
L2BlockNumber
uint64
RootClaim
common
.
Hash
RootClaim
common
.
Hash
Status
types
.
GameStatus
Status
types
.
GameStatus
Duration
uint64
Claims
[]
faultTypes
.
Claim
Claims
[]
faultTypes
.
Claim
}
}
...
...
op-dispute-mon/mon/types/types_test.go
View file @
134f6883
...
@@ -8,6 +8,10 @@ import (
...
@@ -8,6 +8,10 @@ import (
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/require"
)
)
func
TestMaxValue
(
t
*
testing
.
T
)
{
require
.
Equal
(
t
,
ResolvedBondAmount
.
String
(),
"340282366920938463463374607431768211455"
)
}
func
TestStatusBatch_Add
(
t
*
testing
.
T
)
{
func
TestStatusBatch_Add
(
t
*
testing
.
T
)
{
statusExpectations
:=
[]
struct
{
statusExpectations
:=
[]
struct
{
status
types
.
GameStatus
status
types
.
GameStatus
...
...
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