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
a145e096
Unverified
Commit
a145e096
authored
Aug 23, 2023
by
mergify[bot]
Committed by
GitHub
Aug 23, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into dependabot/npm_and_yarn/eslint-plugin-prettier-4.2.1
parents
fd71b159
2963dd94
Changes
41
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
41 changed files
with
776 additions
and
459 deletions
+776
-459
deposits.go
indexer/api/routes/deposits.go
+1
-1
withdrawals.go
indexer/api/routes/withdrawals.go
+1
-1
blocks.go
indexer/database/blocks.go
+5
-5
bridge_messages.go
indexer/database/bridge_messages.go
+3
-2
bridge_transactions.go
indexer/database/bridge_transactions.go
+6
-5
u256.go
indexer/database/serializers/u256.go
+60
-0
types.go
indexer/database/types.go
+5
-59
bridge_messages_e2e_test.go
indexer/e2e_tests/bridge_messages_e2e_test.go
+6
-6
bridge_transactions_e2e_test.go
indexer/e2e_tests/bridge_transactions_e2e_test.go
+5
-5
bridge_transfers_e2e_test.go
indexer/e2e_tests/bridge_transfers_e2e_test.go
+4
-4
etl_e2e_test.go
indexer/e2e_tests/etl_e2e_test.go
+5
-5
l1_etl.go
indexer/etl/l1_etl.go
+1
-1
l2_etl.go
indexer/etl/l2_etl.go
+1
-1
bridge.go
indexer/processors/bridge.go
+1
-1
cross_domain_messenger.go
indexer/processors/contracts/cross_domain_messenger.go
+3
-3
l2_to_l1_message_passer.go
indexer/processors/contracts/l2_to_l1_message_passer.go
+5
-5
optimism_portal.go
indexer/processors/contracts/optimism_portal.go
+3
-3
standard_bridge.go
indexer/processors/contracts/standard_bridge.go
+2
-2
main_test.go
op-challenger/cmd/main_test.go
+18
-0
config.go
op-challenger/config/config.go
+12
-3
abi_test.go
op-challenger/fault/abi_test.go
+3
-3
agent.go
op-challenger/fault/agent.go
+19
-2
agent_test.go
op-challenger/fault/agent_test.go
+31
-0
caller.go
op-challenger/fault/caller.go
+1
-2
provider.go
op-challenger/fault/cannon/provider.go
+4
-0
provider_test.go
op-challenger/fault/cannon/provider_test.go
+8
-0
factory.go
op-challenger/fault/factory.go
+11
-6
factory_test.go
op-challenger/fault/factory_test.go
+11
-8
monitor.go
op-challenger/fault/monitor.go
+37
-4
monitor_test.go
op-challenger/fault/monitor_test.go
+102
-5
player.go
op-challenger/fault/player.go
+22
-4
player_test.go
op-challenger/fault/player_test.go
+60
-28
responder.go
op-challenger/fault/responder.go
+13
-6
responder_test.go
op-challenger/fault/responder_test.go
+135
-137
service.go
op-challenger/fault/service.go
+1
-1
types.go
op-challenger/fault/types/types.go
+9
-0
types_test.go
op-challenger/fault/types/types_test.go
+23
-0
flags.go
op-challenger/flags/flags.go
+8
-0
package.json
package.json
+1
-1
package.json
packages/contracts-bedrock/package.json
+1
-1
pnpm-lock.yaml
pnpm-lock.yaml
+129
-139
No files found.
indexer/api/routes/deposits.go
View file @
a145e096
...
...
@@ -46,7 +46,7 @@ func newDepositResponse(deposits *database.L1BridgeDepositsResponse) DepositResp
},
From
:
deposit
.
L1BridgeDeposit
.
Tx
.
FromAddress
.
String
(),
To
:
deposit
.
L1BridgeDeposit
.
Tx
.
ToAddress
.
String
(),
Amount
:
deposit
.
L1BridgeDeposit
.
Tx
.
Amount
.
Int
.
String
(),
Amount
:
deposit
.
L1BridgeDeposit
.
Tx
.
Amount
.
String
(),
L1Token
:
TokenInfo
{
ChainId
:
1
,
Address
:
deposit
.
L1BridgeDeposit
.
TokenPair
.
LocalTokenAddress
.
String
(),
...
...
indexer/api/routes/withdrawals.go
View file @
a145e096
...
...
@@ -60,7 +60,7 @@ func newWithdrawalResponse(withdrawals *database.L2BridgeWithdrawalsResponse) Wi
From
:
withdrawal
.
L2BridgeWithdrawal
.
Tx
.
FromAddress
.
String
(),
To
:
withdrawal
.
L2BridgeWithdrawal
.
Tx
.
ToAddress
.
String
(),
TransactionHash
:
withdrawal
.
L2TransactionHash
.
String
(),
Amount
:
withdrawal
.
L2BridgeWithdrawal
.
Tx
.
Amount
.
Int
.
String
(),
Amount
:
withdrawal
.
L2BridgeWithdrawal
.
Tx
.
Amount
.
String
(),
Proof
:
Proof
{
TransactionHash
:
withdrawal
.
ProvenL1TransactionHash
.
String
(),
BlockTimestamp
:
withdrawal
.
L2BridgeWithdrawal
.
Tx
.
Timestamp
,
...
...
indexer/database/blocks.go
View file @
a145e096
...
...
@@ -20,7 +20,7 @@ import (
type
BlockHeader
struct
{
Hash
common
.
Hash
`gorm:"primaryKey;serializer:bytes"`
ParentHash
common
.
Hash
`gorm:"serializer:bytes"`
Number
U256
Number
*
big
.
Int
`gorm:"serializer:u256"`
Timestamp
uint64
RLPHeader
*
RLPHeader
`gorm:"serializer:rlp;column:rlp_bytes"`
...
...
@@ -30,7 +30,7 @@ func BlockHeaderFromHeader(header *types.Header) BlockHeader {
return
BlockHeader
{
Hash
:
header
.
Hash
(),
ParentHash
:
header
.
ParentHash
,
Number
:
U256
{
Int
:
header
.
Number
}
,
Number
:
header
.
Number
,
Timestamp
:
header
.
Time
,
RLPHeader
:
(
*
RLPHeader
)(
header
),
...
...
@@ -58,8 +58,8 @@ type LegacyStateBatch struct {
type
OutputProposal
struct
{
OutputRoot
common
.
Hash
`gorm:"primaryKey;serializer:bytes"`
L2OutputIndex
U256
L2BlockNumber
U256
L2OutputIndex
*
big
.
Int
`gorm:"serializer:u256"`
L2BlockNumber
*
big
.
Int
`gorm:"serializer:u256"`
L1ContractEventGUID
uuid
.
UUID
}
...
...
@@ -165,7 +165,7 @@ func (db *blocksDB) LatestCheckpointedOutput() (*OutputProposal, error) {
func
(
db
*
blocksDB
)
OutputProposal
(
index
*
big
.
Int
)
(
*
OutputProposal
,
error
)
{
var
outputProposal
OutputProposal
result
:=
db
.
gorm
.
Where
(
&
OutputProposal
{
L2OutputIndex
:
U256
{
Int
:
index
}
})
.
Take
(
&
outputProposal
)
result
:=
db
.
gorm
.
Where
(
&
OutputProposal
{
L2OutputIndex
:
index
})
.
Take
(
&
outputProposal
)
if
result
.
Error
!=
nil
{
if
errors
.
Is
(
result
.
Error
,
gorm
.
ErrRecordNotFound
)
{
return
nil
,
nil
...
...
indexer/database/bridge_messages.go
View file @
a145e096
...
...
@@ -3,6 +3,7 @@ package database
import
(
"errors"
"fmt"
"math/big"
"gorm.io/gorm"
...
...
@@ -17,13 +18,13 @@ import (
type
BridgeMessage
struct
{
MessageHash
common
.
Hash
`gorm:"primaryKey;serializer:bytes"`
Nonce
U256
Nonce
*
big
.
Int
`gorm:"serializer:u256"`
SentMessageEventGUID
uuid
.
UUID
RelayedMessageEventGUID
*
uuid
.
UUID
Tx
Transaction
`gorm:"embedded"`
GasLimit
U256
GasLimit
*
big
.
Int
`gorm:"serializer:u256"`
}
type
L1BridgeMessage
struct
{
...
...
indexer/database/bridge_transactions.go
View file @
a145e096
...
...
@@ -3,6 +3,7 @@ package database
import
(
"errors"
"fmt"
"math/big"
"github.com/google/uuid"
"gorm.io/gorm"
...
...
@@ -17,8 +18,8 @@ import (
type
Transaction
struct
{
FromAddress
common
.
Address
`gorm:"serializer:bytes"`
ToAddress
common
.
Address
`gorm:"serializer:bytes"`
Amount
U256
Data
Bytes
`gorm:"serializer:bytes"`
Amount
*
big
.
Int
`gorm:"serializer:u256"`
Data
Bytes
`gorm:"serializer:bytes"`
Timestamp
uint64
}
...
...
@@ -28,12 +29,12 @@ type L1TransactionDeposit struct {
InitiatedL1EventGUID
uuid
.
UUID
Tx
Transaction
`gorm:"embedded"`
GasLimit
U256
GasLimit
*
big
.
Int
`gorm:"serializer:u256"`
}
type
L2TransactionWithdrawal
struct
{
WithdrawalHash
common
.
Hash
`gorm:"serializer:bytes;primaryKey"`
Nonce
U256
Nonce
*
big
.
Int
`gorm:"serializer:u256"`
InitiatedL2EventGUID
uuid
.
UUID
ProvenL1EventGUID
*
uuid
.
UUID
...
...
@@ -41,7 +42,7 @@ type L2TransactionWithdrawal struct {
Succeeded
*
bool
Tx
Transaction
`gorm:"embedded"`
GasLimit
U256
GasLimit
*
big
.
Int
`gorm:"serializer:u256"`
}
type
BridgeTransactionsView
interface
{
...
...
indexer/database/serializers/u256.go
0 → 100644
View file @
a145e096
package
serializers
import
(
"context"
"fmt"
"math/big"
"reflect"
"github.com/jackc/pgtype"
"gorm.io/gorm/schema"
)
var
(
big10
=
big
.
NewInt
(
10
)
u256BigIntOverflow
=
new
(
big
.
Int
)
.
Exp
(
big
.
NewInt
(
2
),
big
.
NewInt
(
256
),
nil
)
)
type
U256Serializer
struct
{}
func
init
()
{
schema
.
RegisterSerializer
(
"u256"
,
U256Serializer
{})
}
func
(
U256Serializer
)
Scan
(
ctx
context
.
Context
,
field
*
schema
.
Field
,
dst
reflect
.
Value
,
dbValue
interface
{})
error
{
if
dbValue
==
nil
{
return
nil
}
else
if
field
.
FieldType
!=
reflect
.
TypeOf
((
*
big
.
Int
)(
nil
))
{
return
fmt
.
Errorf
(
"can only deserialize into a *big.Int: %T"
,
field
.
FieldType
)
}
numeric
:=
new
(
pgtype
.
Numeric
)
err
:=
numeric
.
Scan
(
dbValue
)
if
err
!=
nil
{
return
err
}
bigInt
:=
numeric
.
Int
if
numeric
.
Exp
>
0
{
factor
:=
new
(
big
.
Int
)
.
Exp
(
big10
,
big
.
NewInt
(
int64
(
numeric
.
Exp
)),
nil
)
bigInt
.
Mul
(
bigInt
,
factor
)
}
if
bigInt
.
Cmp
(
u256BigIntOverflow
)
>=
0
{
return
fmt
.
Errorf
(
"deserialized number larger than u256 can hold: %s"
,
bigInt
)
}
field
.
ReflectValueOf
(
ctx
,
dst
)
.
Set
(
reflect
.
ValueOf
(
bigInt
))
return
nil
}
func
(
U256Serializer
)
Value
(
ctx
context
.
Context
,
field
*
schema
.
Field
,
dst
reflect
.
Value
,
fieldValue
interface
{})
(
interface
{},
error
)
{
if
fieldValue
==
nil
||
(
field
.
FieldType
.
Kind
()
==
reflect
.
Pointer
&&
reflect
.
ValueOf
(
fieldValue
)
.
IsNil
())
{
return
nil
,
nil
}
else
if
field
.
FieldType
!=
reflect
.
TypeOf
((
*
big
.
Int
)(
nil
))
{
return
nil
,
fmt
.
Errorf
(
"can only serialize a *big.Int: %T"
,
field
.
FieldType
)
}
numeric
:=
pgtype
.
Numeric
{
Int
:
fieldValue
.
(
*
big
.
Int
),
Status
:
pgtype
.
Present
}
return
numeric
.
Value
()
}
indexer/database/types.go
View file @
a145e096
package
database
import
(
"database/sql/driver"
"errors"
"io"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/jackc/pgtype"
)
var
u256BigIntOverflow
=
new
(
big
.
Int
)
.
Exp
(
big
.
NewInt
(
2
),
big
.
NewInt
(
256
),
nil
)
var
big10
=
big
.
NewInt
(
10
)
var
ErrU256Overflow
=
errors
.
New
(
"number exceeds u256"
)
var
ErrU256ContainsDecimal
=
errors
.
New
(
"number contains fractional digits"
)
var
ErrU256Null
=
errors
.
New
(
"number cannot be null"
)
// U256 is a wrapper over big.Int that conforms to the database U256 numeric domain type
type
U256
struct
{
Int
*
big
.
Int
}
// Scan implements the database/sql Scanner interface.
func
(
u256
*
U256
)
Scan
(
src
interface
{})
error
{
// deserialize as a numeric
var
numeric
pgtype
.
Numeric
err
:=
numeric
.
Scan
(
src
)
if
err
!=
nil
{
return
err
}
else
if
numeric
.
Exp
<
0
{
return
ErrU256ContainsDecimal
}
else
if
numeric
.
Status
==
pgtype
.
Null
{
return
ErrU256Null
}
// factor in the powers of 10
num
:=
numeric
.
Int
if
numeric
.
Exp
>
0
{
factor
:=
new
(
big
.
Int
)
.
Exp
(
big10
,
big
.
NewInt
(
int64
(
numeric
.
Exp
)),
nil
)
num
.
Mul
(
num
,
factor
)
}
// check bounds before setting the u256
if
num
.
Cmp
(
u256BigIntOverflow
)
>=
0
{
return
ErrU256Overflow
}
else
{
u256
.
Int
=
num
}
return
nil
}
// Value implements the database/sql/driver Valuer interface.
func
(
u256
U256
)
Value
()
(
driver
.
Value
,
error
)
{
// check bounds
if
u256
.
Int
==
nil
{
return
nil
,
ErrU256Null
}
else
if
u256
.
Int
.
Cmp
(
u256BigIntOverflow
)
>=
0
{
return
nil
,
ErrU256Overflow
}
// simply encode as a numeric with no Exp set (non-decimal)
numeric
:=
pgtype
.
Numeric
{
Int
:
u256
.
Int
,
Status
:
pgtype
.
Present
}
return
numeric
.
Value
()
}
// Wrapper over types.Header such that we can get an RLP
// encoder over it via a `types.Block` wrapper
type
RLPHeader
types
.
Header
...
...
@@ -94,6 +37,9 @@ func (h *RLPHeader) Hash() common.Hash {
return
h
.
Header
()
.
Hash
()
}
// Type definition for []byte to conform to the
// interface expected by the `bytes` serializer
type
Bytes
[]
byte
func
(
b
Bytes
)
Bytes
()
[]
byte
{
...
...
indexer/e2e_tests/bridge_messages_e2e_test.go
View file @
a145e096
...
...
@@ -59,9 +59,9 @@ func TestE2EBridgeL1CrossDomainMessenger(t *testing.T) {
require
.
NotNil
(
t
,
sentMessage
)
require
.
NotNil
(
t
,
sentMessage
.
SentMessageEventGUID
)
require
.
Equal
(
t
,
depositInfo
.
DepositTx
.
SourceHash
,
sentMessage
.
TransactionSourceHash
)
require
.
Equal
(
t
,
nonce
.
Uint64
(),
sentMessage
.
Nonce
.
Int
.
Uint64
())
require
.
Equal
(
t
,
uint64
(
100
_000
),
sentMessage
.
GasLimit
.
Int
.
Uint64
())
require
.
Equal
(
t
,
big
.
NewInt
(
params
.
Ether
),
sentMessage
.
Tx
.
Amount
.
Int
)
require
.
Equal
(
t
,
nonce
.
Uint64
(),
sentMessage
.
Nonce
.
Uint64
())
require
.
Equal
(
t
,
uint64
(
100
_000
),
sentMessage
.
GasLimit
.
Uint64
())
require
.
Equal
(
t
,
uint64
(
params
.
Ether
),
sentMessage
.
Tx
.
Amount
.
Uint64
()
)
require
.
Equal
(
t
,
aliceAddr
,
sentMessage
.
Tx
.
FromAddress
)
require
.
Equal
(
t
,
aliceAddr
,
sentMessage
.
Tx
.
ToAddress
)
require
.
ElementsMatch
(
t
,
calldata
,
sentMessage
.
Tx
.
Data
)
...
...
@@ -146,9 +146,9 @@ func TestE2EBridgeL2CrossDomainMessenger(t *testing.T) {
require
.
NotNil
(
t
,
sentMessage
)
require
.
NotNil
(
t
,
sentMessage
.
SentMessageEventGUID
)
require
.
Equal
(
t
,
withdrawalHash
,
sentMessage
.
TransactionWithdrawalHash
)
require
.
Equal
(
t
,
nonce
.
Uint64
(),
sentMessage
.
Nonce
.
Int
.
Uint64
())
require
.
Equal
(
t
,
uint64
(
100
_000
),
sentMessage
.
GasLimit
.
Int
.
Uint64
())
require
.
Equal
(
t
,
big
.
NewInt
(
params
.
Ether
),
sentMessage
.
Tx
.
Amount
.
Int
)
require
.
Equal
(
t
,
nonce
.
Uint64
(),
sentMessage
.
Nonce
.
Uint64
())
require
.
Equal
(
t
,
uint64
(
100
_000
),
sentMessage
.
GasLimit
.
Uint64
())
require
.
Equal
(
t
,
uint64
(
params
.
Ether
),
sentMessage
.
Tx
.
Amount
.
Uint64
()
)
require
.
Equal
(
t
,
aliceAddr
,
sentMessage
.
Tx
.
FromAddress
)
require
.
Equal
(
t
,
aliceAddr
,
sentMessage
.
Tx
.
ToAddress
)
require
.
ElementsMatch
(
t
,
calldata
,
sentMessage
.
Tx
.
Data
)
...
...
indexer/e2e_tests/bridge_transactions_e2e_test.go
View file @
a145e096
...
...
@@ -54,8 +54,8 @@ func TestE2EBridgeTransactionsOptimismPortalDeposits(t *testing.T) {
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
deposit
)
require
.
Equal
(
t
,
depositL2TxHash
,
deposit
.
L2TransactionHash
)
require
.
Equal
(
t
,
big
.
NewInt
(
100
_000
),
deposit
.
GasLimit
.
Int
)
require
.
Equal
(
t
,
big
.
NewInt
(
params
.
Ether
),
deposit
.
Tx
.
Amount
.
Int
)
require
.
Equal
(
t
,
uint64
(
100
_000
),
deposit
.
GasLimit
.
Uint64
()
)
require
.
Equal
(
t
,
uint64
(
params
.
Ether
),
deposit
.
Tx
.
Amount
.
Uint64
()
)
require
.
Equal
(
t
,
aliceAddr
,
deposit
.
Tx
.
FromAddress
)
require
.
Equal
(
t
,
aliceAddr
,
deposit
.
Tx
.
ToAddress
)
require
.
ElementsMatch
(
t
,
calldata
,
deposit
.
Tx
.
Data
)
...
...
@@ -113,9 +113,9 @@ func TestE2EBridgeTransactionsL2ToL1MessagePasserWithdrawal(t *testing.T) {
withdraw
,
err
:=
testSuite
.
DB
.
BridgeTransactions
.
L2TransactionWithdrawal
(
withdrawalHash
)
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
withdraw
)
require
.
Equal
(
t
,
msgPassed
.
Nonce
.
Uint64
(),
withdraw
.
Nonce
.
Int
.
Uint64
())
require
.
Equal
(
t
,
big
.
NewInt
(
100
_000
),
withdraw
.
GasLimit
.
Int
)
require
.
Equal
(
t
,
big
.
NewInt
(
params
.
Ether
),
withdraw
.
Tx
.
Amount
.
Int
)
require
.
Equal
(
t
,
msgPassed
.
Nonce
.
Uint64
(),
withdraw
.
Nonce
.
Uint64
())
require
.
Equal
(
t
,
uint64
(
100
_000
),
withdraw
.
GasLimit
.
Uint64
()
)
require
.
Equal
(
t
,
uint64
(
params
.
Ether
),
withdraw
.
Tx
.
Amount
.
Uint64
()
)
require
.
Equal
(
t
,
aliceAddr
,
withdraw
.
Tx
.
FromAddress
)
require
.
Equal
(
t
,
aliceAddr
,
withdraw
.
Tx
.
ToAddress
)
require
.
ElementsMatch
(
t
,
calldata
,
withdraw
.
Tx
.
Data
)
...
...
indexer/e2e_tests/bridge_transfers_e2e_test.go
View file @
a145e096
...
...
@@ -63,7 +63,7 @@ func TestE2EBridgeTransfersStandardBridgeETHDeposit(t *testing.T) {
require
.
Equal
(
t
,
depositInfo
.
DepositTx
.
SourceHash
,
deposit
.
TransactionSourceHash
)
require
.
Equal
(
t
,
predeploys
.
LegacyERC20ETHAddr
,
deposit
.
TokenPair
.
LocalTokenAddress
)
require
.
Equal
(
t
,
predeploys
.
LegacyERC20ETHAddr
,
deposit
.
TokenPair
.
RemoteTokenAddress
)
require
.
Equal
(
t
,
big
.
NewInt
(
params
.
Ether
),
deposit
.
Tx
.
Amount
.
Int
)
require
.
Equal
(
t
,
uint64
(
params
.
Ether
),
deposit
.
Tx
.
Amount
.
Uint64
()
)
require
.
Equal
(
t
,
aliceAddr
,
deposit
.
Tx
.
FromAddress
)
require
.
Equal
(
t
,
aliceAddr
,
deposit
.
Tx
.
ToAddress
)
require
.
Equal
(
t
,
byte
(
1
),
deposit
.
Tx
.
Data
[
0
])
...
...
@@ -235,7 +235,7 @@ func TestE2EBridgeTransfersOptimismPortalETHReceive(t *testing.T) {
require
.
Equal
(
t
,
depositInfo
.
DepositTx
.
SourceHash
,
deposit
.
TransactionSourceHash
)
require
.
Equal
(
t
,
predeploys
.
LegacyERC20ETHAddr
,
deposit
.
TokenPair
.
LocalTokenAddress
)
require
.
Equal
(
t
,
predeploys
.
LegacyERC20ETHAddr
,
deposit
.
TokenPair
.
RemoteTokenAddress
)
require
.
Equal
(
t
,
big
.
NewInt
(
params
.
Ether
),
deposit
.
Tx
.
Amount
.
Int
)
require
.
Equal
(
t
,
uint64
(
params
.
Ether
),
deposit
.
Tx
.
Amount
.
Uint64
()
)
require
.
Equal
(
t
,
aliceAddr
,
deposit
.
Tx
.
FromAddress
)
require
.
Equal
(
t
,
aliceAddr
,
deposit
.
Tx
.
ToAddress
)
require
.
Len
(
t
,
deposit
.
Tx
.
Data
,
0
)
...
...
@@ -306,7 +306,7 @@ func TestE2EBridgeTransfersStandardBridgeETHWithdrawal(t *testing.T) {
require
.
Equal
(
t
,
withdrawalHash
,
withdrawal
.
TransactionWithdrawalHash
)
require
.
Equal
(
t
,
predeploys
.
LegacyERC20ETHAddr
,
withdrawal
.
TokenPair
.
LocalTokenAddress
)
require
.
Equal
(
t
,
predeploys
.
LegacyERC20ETHAddr
,
withdrawal
.
TokenPair
.
RemoteTokenAddress
)
require
.
Equal
(
t
,
big
.
NewInt
(
params
.
Ether
),
withdrawal
.
Tx
.
Amount
.
Int
)
require
.
Equal
(
t
,
uint64
(
params
.
Ether
),
withdrawal
.
Tx
.
Amount
.
Uint64
()
)
require
.
Equal
(
t
,
aliceAddr
,
withdrawal
.
Tx
.
FromAddress
)
require
.
Equal
(
t
,
aliceAddr
,
withdrawal
.
Tx
.
ToAddress
)
require
.
Equal
(
t
,
byte
(
1
),
withdrawal
.
Tx
.
Data
[
0
])
...
...
@@ -390,7 +390,7 @@ func TestE2EBridgeTransfersL2ToL1MessagePasserETHReceive(t *testing.T) {
require
.
Equal
(
t
,
withdrawalHash
,
withdrawal
.
TransactionWithdrawalHash
)
require
.
Equal
(
t
,
predeploys
.
LegacyERC20ETHAddr
,
withdrawal
.
TokenPair
.
LocalTokenAddress
)
require
.
Equal
(
t
,
predeploys
.
LegacyERC20ETHAddr
,
withdrawal
.
TokenPair
.
RemoteTokenAddress
)
require
.
Equal
(
t
,
big
.
NewInt
(
params
.
Ether
),
withdrawal
.
Tx
.
Amount
.
Int
)
require
.
Equal
(
t
,
uint64
(
params
.
Ether
),
withdrawal
.
Tx
.
Amount
.
Uint64
()
)
require
.
Equal
(
t
,
aliceAddr
,
withdrawal
.
Tx
.
FromAddress
)
require
.
Equal
(
t
,
aliceAddr
,
withdrawal
.
Tx
.
ToAddress
)
require
.
Len
(
t
,
withdrawal
.
Tx
.
Data
,
0
)
...
...
indexer/e2e_tests/etl_e2e_test.go
View file @
a145e096
...
...
@@ -40,19 +40,19 @@ func TestE2EETL(t *testing.T) {
l2Header
,
err
:=
testSuite
.
DB
.
Blocks
.
L2LatestBlockHeader
()
require
.
NoError
(
t
,
err
)
return
(
l1Header
!=
nil
&&
l1Header
.
Number
.
Int
.
Uint64
()
>=
l1Height
)
&&
(
l2Header
!=
nil
&&
l2Header
.
Number
.
Int
.
Uint64
()
>=
9
),
nil
return
(
l1Header
!=
nil
&&
l1Header
.
Number
.
Uint64
()
>=
l1Height
)
&&
(
l2Header
!=
nil
&&
l2Header
.
Number
.
Uint64
()
>=
9
),
nil
}))
t
.
Run
(
"indexes all L2 blocks"
,
func
(
t
*
testing
.
T
)
{
latestL2Header
,
err
:=
testSuite
.
DB
.
Blocks
.
L2LatestBlockHeader
()
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
latestL2Header
)
require
.
True
(
t
,
latestL2Header
.
Number
.
Int
.
Uint64
()
>=
9
)
require
.
True
(
t
,
latestL2Header
.
Number
.
Uint64
()
>=
9
)
for
i
:=
int64
(
0
);
i
<
10
;
i
++
{
height
:=
big
.
NewInt
(
i
)
indexedHeader
,
err
:=
testSuite
.
DB
.
Blocks
.
L2BlockHeaderWithFilter
(
database
.
BlockHeader
{
Number
:
database
.
U256
{
Int
:
height
}
})
indexedHeader
,
err
:=
testSuite
.
DB
.
Blocks
.
L2BlockHeaderWithFilter
(
database
.
BlockHeader
{
Number
:
height
})
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
indexedHeader
)
...
...
@@ -60,7 +60,7 @@ func TestE2EETL(t *testing.T) {
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
indexedHeader
)
require
.
Equal
(
t
,
header
.
Number
.
Int64
(),
indexedHeader
.
Number
.
Int
.
Int
64
())
require
.
Equal
(
t
,
header
.
Number
.
Int64
(),
indexedHeader
.
Number
.
Int64
())
require
.
Equal
(
t
,
header
.
Hash
(),
indexedHeader
.
Hash
)
require
.
Equal
(
t
,
header
.
ParentHash
,
indexedHeader
.
ParentHash
)
require
.
Equal
(
t
,
header
.
Time
,
indexedHeader
.
Timestamp
)
...
...
@@ -144,7 +144,7 @@ func TestE2EETL(t *testing.T) {
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
block
.
Hash
(),
l1BlockHeader
.
Hash
)
require
.
Equal
(
t
,
block
.
ParentHash
(),
l1BlockHeader
.
ParentHash
)
require
.
Equal
(
t
,
block
.
Number
()
,
l1BlockHeader
.
Number
.
Int
)
require
.
Equal
(
t
,
block
.
Number
()
.
Uint64
(),
l1BlockHeader
.
Number
.
Uint64
()
)
require
.
Equal
(
t
,
block
.
Time
(),
l1BlockHeader
.
Timestamp
)
// ensure the right rlp encoding is stored. checking the hashes
...
...
indexer/etl/l1_etl.go
View file @
a145e096
...
...
@@ -38,7 +38,7 @@ func NewL1ETL(log log.Logger, db *database.DB, client node.EthClient, startHeigh
// Determine the starting height for traversal
var
fromHeader
*
types
.
Header
if
latestHeader
!=
nil
{
log
.
Info
(
"detected last indexed block"
,
"number"
,
latestHeader
.
Number
.
Int
,
"hash"
,
latestHeader
.
Hash
)
log
.
Info
(
"detected last indexed block"
,
"number"
,
latestHeader
.
Number
,
"hash"
,
latestHeader
.
Hash
)
fromHeader
=
latestHeader
.
RLPHeader
.
Header
()
}
else
if
startHeight
.
BitLen
()
>
0
{
...
...
indexer/etl/l2_etl.go
View file @
a145e096
...
...
@@ -35,7 +35,7 @@ func NewL2ETL(log log.Logger, db *database.DB, client node.EthClient) (*L2ETL, e
var
fromHeader
*
types
.
Header
if
latestHeader
!=
nil
{
log
.
Info
(
"detected last indexed block"
,
"number"
,
latestHeader
.
Number
.
Int
,
"hash"
,
latestHeader
.
Hash
)
log
.
Info
(
"detected last indexed block"
,
"number"
,
latestHeader
.
Number
,
"hash"
,
latestHeader
.
Hash
)
fromHeader
=
latestHeader
.
RLPHeader
.
Header
()
}
else
{
log
.
Info
(
"no indexed state, starting from genesis"
)
...
...
indexer/processors/bridge.go
View file @
a145e096
...
...
@@ -107,7 +107,7 @@ func (b *BridgeProcessor) Start(ctx context.Context) error {
continue
}
toL1Height
,
toL2Height
:=
latestEpoch
.
L1BlockHeader
.
Number
.
Int
,
latestEpoch
.
L2BlockHeader
.
Number
.
Int
toL1Height
,
toL2Height
:=
latestEpoch
.
L1BlockHeader
.
Number
,
latestEpoch
.
L2BlockHeader
.
Number
fromL1Height
,
fromL2Height
:=
big
.
NewInt
(
0
),
big
.
NewInt
(
0
)
if
b
.
LatestL1Header
!=
nil
{
// `NewBridgeProcessor` ensures that LatestL2Header must not be nil if LatestL1Header is set
...
...
indexer/processors/contracts/cross_domain_messenger.go
View file @
a145e096
...
...
@@ -94,13 +94,13 @@ func CrossDomainMessengerSentMessageEvents(chainSelector string, contractAddress
Event
:
&
sentMessageEvents
[
i
],
BridgeMessage
:
database
.
BridgeMessage
{
MessageHash
:
messageHash
,
Nonce
:
database
.
U256
{
Int
:
sentMessage
.
MessageNonce
}
,
Nonce
:
sentMessage
.
MessageNonce
,
SentMessageEventGUID
:
sentMessageEvents
[
i
]
.
GUID
,
GasLimit
:
database
.
U256
{
Int
:
sentMessage
.
GasLimit
}
,
GasLimit
:
sentMessage
.
GasLimit
,
Tx
:
database
.
Transaction
{
FromAddress
:
sentMessage
.
Sender
,
ToAddress
:
sentMessage
.
Target
,
Amount
:
database
.
U256
{
Int
:
sentMessageExtension
.
Value
}
,
Amount
:
sentMessageExtension
.
Value
,
Data
:
sentMessage
.
Message
,
Timestamp
:
sentMessageEvents
[
i
]
.
Timestamp
,
},
...
...
indexer/processors/contracts/l2_to_l1_message_passer.go
View file @
a145e096
...
...
@@ -11,8 +11,8 @@ import (
type
L2ToL1MessagePasserMessagePassed
struct
{
Event
*
database
.
ContractEvent
WithdrawalHash
common
.
Hash
GasLimit
database
.
U256
Nonce
database
.
U256
GasLimit
*
big
.
Int
Nonce
*
big
.
Int
Tx
database
.
Transaction
}
...
...
@@ -40,12 +40,12 @@ func L2ToL1MessagePasserMessagePassedEvents(contractAddress common.Address, db *
messagesPassed
[
i
]
=
L2ToL1MessagePasserMessagePassed
{
Event
:
&
messagePassedEvents
[
i
]
.
ContractEvent
,
WithdrawalHash
:
messagePassed
.
WithdrawalHash
,
Nonce
:
database
.
U256
{
Int
:
messagePassed
.
Nonce
}
,
GasLimit
:
database
.
U256
{
Int
:
messagePassed
.
GasLimit
}
,
Nonce
:
messagePassed
.
Nonce
,
GasLimit
:
messagePassed
.
GasLimit
,
Tx
:
database
.
Transaction
{
FromAddress
:
messagePassed
.
Sender
,
ToAddress
:
messagePassed
.
Target
,
Amount
:
database
.
U256
{
Int
:
messagePassed
.
Value
}
,
Amount
:
messagePassed
.
Value
,
Data
:
messagePassed
.
Data
,
Timestamp
:
messagePassedEvents
[
i
]
.
Timestamp
,
},
...
...
indexer/processors/contracts/optimism_portal.go
View file @
a145e096
...
...
@@ -16,7 +16,7 @@ type OptimismPortalTransactionDepositEvent struct {
Event
*
database
.
ContractEvent
DepositTx
*
types
.
DepositTx
Tx
database
.
Transaction
GasLimit
database
.
U256
GasLimit
*
big
.
Int
}
type
OptimismPortalWithdrawalProvenEvent
struct
{
...
...
@@ -67,11 +67,11 @@ func OptimismPortalTransactionDepositEvents(contractAddress common.Address, db *
optimismPortalTxDeposits
[
i
]
=
OptimismPortalTransactionDepositEvent
{
Event
:
&
transactionDepositEvents
[
i
]
.
ContractEvent
,
DepositTx
:
depositTx
,
GasLimit
:
database
.
U256
{
Int
:
new
(
big
.
Int
)
.
SetUint64
(
depositTx
.
Gas
)}
,
GasLimit
:
new
(
big
.
Int
)
.
SetUint64
(
depositTx
.
Gas
)
,
Tx
:
database
.
Transaction
{
FromAddress
:
txDeposit
.
From
,
ToAddress
:
txDeposit
.
To
,
Amount
:
d
atabase
.
U256
{
Int
:
depositTx
.
Value
}
,
Amount
:
d
epositTx
.
Value
,
Data
:
depositTx
.
Data
,
Timestamp
:
transactionDepositEvents
[
i
]
.
Timestamp
,
},
...
...
indexer/processors/contracts/standard_bridge.go
View file @
a145e096
...
...
@@ -101,7 +101,7 @@ func _standardBridgeInitiatedEvents[BridgeEventType bindings.StandardBridgeETHBr
Tx
:
database
.
Transaction
{
FromAddress
:
erc20Bridge
.
From
,
ToAddress
:
erc20Bridge
.
To
,
Amount
:
database
.
U256
{
Int
:
erc20Bridge
.
Amount
}
,
Amount
:
erc20Bridge
.
Amount
,
Data
:
erc20Bridge
.
ExtraData
,
Timestamp
:
initiatedBridgeEvents
[
i
]
.
Timestamp
,
},
...
...
@@ -161,7 +161,7 @@ func _standardBridgeFinalizedEvents[BridgeEventType bindings.StandardBridgeETHBr
Tx
:
database
.
Transaction
{
FromAddress
:
erc20Bridge
.
From
,
ToAddress
:
erc20Bridge
.
To
,
Amount
:
database
.
U256
{
Int
:
erc20Bridge
.
Amount
}
,
Amount
:
erc20Bridge
.
Amount
,
Data
:
erc20Bridge
.
ExtraData
,
Timestamp
:
bridgeFinalizedEvents
[
i
]
.
Timestamp
,
},
...
...
op-challenger/cmd/main_test.go
View file @
a145e096
...
...
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
...
...
@@ -233,6 +234,23 @@ func TestCannonSnapshotFreq(t *testing.T) {
})
}
func
TestGameWindow
(
t
*
testing
.
T
)
{
t
.
Run
(
"UsesDefault"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
config
.
TraceTypeAlphabet
))
require
.
Equal
(
t
,
config
.
DefaultGameWindow
,
cfg
.
GameWindow
)
})
t
.
Run
(
"Valid"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
config
.
TraceTypeAlphabet
,
"--game-window=1m"
))
require
.
Equal
(
t
,
time
.
Duration
(
time
.
Minute
),
cfg
.
GameWindow
)
})
t
.
Run
(
"ParsesDefault"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
config
.
TraceTypeAlphabet
,
"--game-window=264h"
))
require
.
Equal
(
t
,
config
.
DefaultGameWindow
,
cfg
.
GameWindow
)
})
}
func
TestRequireEitherCannonNetworkOrRollupAndGenesis
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
...
...
op-challenger/config/config.go
View file @
a145e096
...
...
@@ -3,6 +3,7 @@ package config
import
(
"errors"
"fmt"
"time"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -73,7 +74,14 @@ func ValidTraceType(value TraceType) bool {
return
false
}
const
DefaultCannonSnapshotFreq
=
uint
(
1
_000_000_000
)
const
(
DefaultCannonSnapshotFreq
=
uint
(
1
_000_000_000
)
// DefaultGameWindow is the default maximum time duration in the past
// that the challenger will look for games to progress.
// The default value is 11 days, which is a 4 day resolution buffer
// plus the 7 day game finalization window.
DefaultGameWindow
=
time
.
Duration
(
11
*
24
*
time
.
Hour
)
)
// Config is a well typed config that is parsed from the CLI params.
// This also contains config options for auxiliary services.
...
...
@@ -82,9 +90,9 @@ type Config struct {
L1EthRpc
string
// L1 RPC Url
GameFactoryAddress
common
.
Address
// Address of the dispute game factory
GameAllowlist
[]
common
.
Address
// Allowlist of fault game addresses
GameWindow
time
.
Duration
// Maximum time duration to look for games to progress
AgreeWithProposedOutput
bool
// Temporary config if we agree or disagree with the posted output
TraceType
TraceType
// Type of trace
TraceType
TraceType
// Type of trace
// Specific to the alphabet trace provider
AlphabetTrace
string
// String for the AlphabetTraceProvider
...
...
@@ -124,6 +132,7 @@ func NewConfig(
PprofConfig
:
oppprof
.
DefaultCLIConfig
(),
CannonSnapshotFreq
:
DefaultCannonSnapshotFreq
,
GameWindow
:
DefaultGameWindow
,
}
}
...
...
op-challenger/fault/abi_test.go
View file @
a145e096
...
...
@@ -55,7 +55,7 @@ func TestBuildFaultDefendData(t *testing.T) {
_
,
opts
,
_
,
contract
,
err
:=
setupFaultDisputeGame
()
require
.
NoError
(
t
,
err
)
responder
,
_
:=
newTestFaultResponder
(
t
,
false
)
responder
,
_
:=
newTestFaultResponder
(
t
)
data
,
err
:=
responder
.
buildFaultDefendData
(
1
,
[
32
]
byte
{
0x02
,
0x03
})
require
.
NoError
(
t
,
err
)
...
...
@@ -72,7 +72,7 @@ func TestBuildFaultAttackData(t *testing.T) {
_
,
opts
,
_
,
contract
,
err
:=
setupFaultDisputeGame
()
require
.
NoError
(
t
,
err
)
responder
,
_
:=
newTestFaultResponder
(
t
,
false
)
responder
,
_
:=
newTestFaultResponder
(
t
)
data
,
err
:=
responder
.
buildFaultAttackData
(
1
,
[
32
]
byte
{
0x02
,
0x03
})
require
.
NoError
(
t
,
err
)
...
...
@@ -89,7 +89,7 @@ func TestBuildFaultStepData(t *testing.T) {
_
,
opts
,
_
,
contract
,
err
:=
setupFaultDisputeGame
()
require
.
NoError
(
t
,
err
)
responder
,
_
:=
newTestFaultResponder
(
t
,
false
)
responder
,
_
:=
newTestFaultResponder
(
t
)
data
,
err
:=
responder
.
buildStepTxData
(
types
.
StepCallData
{
ClaimIndex
:
2
,
...
...
op-challenger/fault/agent.go
View file @
a145e096
...
...
@@ -13,7 +13,7 @@ import (
// Responder takes a response action & executes.
// For full op-challenger this means executing the transaction on chain.
type
Responder
interface
{
Ca
nResolve
(
ctx
context
.
Context
)
bool
Ca
llResolve
(
ctx
context
.
Context
)
(
types
.
GameStatus
,
error
)
Resolve
(
ctx
context
.
Context
)
error
Respond
(
ctx
context
.
Context
,
response
types
.
Claim
)
error
Step
(
ctx
context
.
Context
,
stepData
types
.
StepCallData
)
error
...
...
@@ -65,10 +65,27 @@ func (a *Agent) Act(ctx context.Context) error {
return
nil
}
// shouldResolve returns true if the agent should resolve the game.
// This method will return false if the game is still in progress.
func
(
a
*
Agent
)
shouldResolve
(
ctx
context
.
Context
,
status
types
.
GameStatus
)
bool
{
expected
:=
types
.
GameStatusDefenderWon
if
a
.
agreeWithProposedOutput
{
expected
=
types
.
GameStatusChallengerWon
}
if
expected
!=
status
{
a
.
log
.
Warn
(
"Game will be lost"
,
"expected"
,
expected
,
"actual"
,
status
)
}
return
expected
==
status
}
// tryResolve resolves the game if it is in a terminal state
// and returns true if the game resolves successfully.
func
(
a
*
Agent
)
tryResolve
(
ctx
context
.
Context
)
bool
{
if
!
a
.
responder
.
CanResolve
(
ctx
)
{
status
,
err
:=
a
.
responder
.
CallResolve
(
ctx
)
if
err
!=
nil
{
return
false
}
if
!
a
.
shouldResolve
(
ctx
,
status
)
{
return
false
}
a
.
log
.
Info
(
"Resolving game"
)
...
...
op-challenger/fault/agent_test.go
0 → 100644
View file @
a145e096
package
fault
import
(
"context"
"testing"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum-optimism/optimism/op-node/testlog"
)
// TestShouldResolve tests the resolution logic.
func
TestShouldResolve
(
t
*
testing
.
T
)
{
log
:=
testlog
.
Logger
(
t
,
log
.
LvlCrit
)
t
.
Run
(
"AgreeWithProposedOutput"
,
func
(
t
*
testing
.
T
)
{
agent
:=
NewAgent
(
nil
,
0
,
nil
,
nil
,
nil
,
true
,
log
)
require
.
False
(
t
,
agent
.
shouldResolve
(
context
.
Background
(),
types
.
GameStatusDefenderWon
))
require
.
True
(
t
,
agent
.
shouldResolve
(
context
.
Background
(),
types
.
GameStatusChallengerWon
))
require
.
False
(
t
,
agent
.
shouldResolve
(
context
.
Background
(),
types
.
GameStatusInProgress
))
})
t
.
Run
(
"DisagreeWithProposedOutput"
,
func
(
t
*
testing
.
T
)
{
agent
:=
NewAgent
(
nil
,
0
,
nil
,
nil
,
nil
,
false
,
log
)
require
.
True
(
t
,
agent
.
shouldResolve
(
context
.
Background
(),
types
.
GameStatusDefenderWon
))
require
.
False
(
t
,
agent
.
shouldResolve
(
context
.
Background
(),
types
.
GameStatusChallengerWon
))
require
.
False
(
t
,
agent
.
shouldResolve
(
context
.
Background
(),
types
.
GameStatusInProgress
))
})
}
op-challenger/fault/caller.go
View file @
a145e096
...
...
@@ -8,7 +8,6 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
type
FaultDisputeGameCaller
interface
{
...
...
@@ -26,7 +25,7 @@ func NewFaultCaller(caller FaultDisputeGameCaller) *FaultCaller {
}
}
func
NewFaultCallerFromBindings
(
fdgAddr
common
.
Address
,
client
*
ethclient
.
Client
)
(
*
FaultCaller
,
error
)
{
func
NewFaultCallerFromBindings
(
fdgAddr
common
.
Address
,
client
bind
.
ContractCaller
)
(
*
FaultCaller
,
error
)
{
caller
,
err
:=
bindings
.
NewFaultDisputeGameCaller
(
fdgAddr
,
client
)
if
err
!=
nil
{
return
nil
,
err
...
...
op-challenger/fault/cannon/provider.go
View file @
a145e096
...
...
@@ -118,6 +118,10 @@ func (p *CannonTraceProvider) AbsolutePreState(ctx context.Context) ([]byte, err
return
state
.
EncodeWitness
(),
nil
}
func
(
p
*
CannonTraceProvider
)
Cleanup
()
error
{
return
os
.
RemoveAll
(
p
.
dir
)
}
// loadProof will attempt to load or generate the proof data at the specified index
// If the requested index is beyond the end of the actual trace it is extended with no-op instructions.
func
(
p
*
CannonTraceProvider
)
loadProof
(
ctx
context
.
Context
,
i
uint64
)
(
*
proofData
,
error
)
{
...
...
op-challenger/fault/cannon/provider_test.go
View file @
a145e096
...
...
@@ -204,6 +204,14 @@ func TestUseGameSpecificSubdir(t *testing.T) {
require
.
Equal
(
t
,
filepath
.
Join
(
dataDir
,
gameDirName
),
provider
.
dir
,
"should use game specific subdir"
)
}
func
TestCleanup
(
t
*
testing
.
T
)
{
dataDir
,
prestate
:=
setupTestData
(
t
)
provider
,
_
:=
setupWithTestData
(
t
,
dataDir
,
prestate
)
require
.
NoError
(
t
,
provider
.
Cleanup
())
_
,
err
:=
os
.
Stat
(
dataDir
)
require
.
ErrorIs
(
t
,
err
,
os
.
ErrNotExist
)
}
func
setupPreState
(
t
*
testing
.
T
,
dataDir
string
,
filename
string
)
{
srcDir
:=
filepath
.
Join
(
"test_data"
)
path
:=
filepath
.
Join
(
srcDir
,
filename
)
...
...
op-challenger/fault/factory.go
View file @
a145e096
...
...
@@ -43,7 +43,7 @@ func NewGameLoader(caller MinimalDisputeGameFactoryCaller) *gameLoader {
}
// FetchAllGamesAtBlock fetches all dispute games from the factory at a given block number.
func
(
l
*
gameLoader
)
FetchAllGamesAtBlock
(
ctx
context
.
Context
,
blockNumber
*
big
.
Int
)
([]
FaultDisputeGame
,
error
)
{
func
(
l
*
gameLoader
)
FetchAllGamesAtBlock
(
ctx
context
.
Context
,
earliestTimestamp
uint64
,
blockNumber
*
big
.
Int
)
([]
FaultDisputeGame
,
error
)
{
if
blockNumber
==
nil
{
return
nil
,
ErrMissingBlockNumber
}
...
...
@@ -56,14 +56,19 @@ func (l *gameLoader) FetchAllGamesAtBlock(ctx context.Context, blockNumber *big.
return
nil
,
fmt
.
Errorf
(
"failed to fetch game count: %w"
,
err
)
}
games
:=
make
([]
FaultDisputeGame
,
gameCount
.
Uint64
())
for
i
:=
uint64
(
0
);
i
<
gameCount
.
Uint64
();
i
++
{
game
,
err
:=
l
.
caller
.
GameAtIndex
(
callOpts
,
big
.
NewInt
(
int64
(
i
)))
games
:=
make
([]
FaultDisputeGame
,
0
)
if
gameCount
.
Uint64
()
==
0
{
return
games
,
nil
}
for
i
:=
gameCount
.
Uint64
();
i
>
0
;
i
--
{
game
,
err
:=
l
.
caller
.
GameAtIndex
(
callOpts
,
big
.
NewInt
(
int64
(
i
-
1
)))
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"failed to fetch game at index %d: %w"
,
i
,
err
)
}
games
[
i
]
=
game
if
game
.
Timestamp
<
earliestTimestamp
{
break
}
games
=
append
(
games
,
game
)
}
return
games
,
nil
...
...
op-challenger/fault/factory_test.go
View file @
a145e096
...
...
@@ -25,6 +25,7 @@ func TestGameLoader_FetchAllGames(t *testing.T) {
tests
:=
[]
struct
{
name
string
caller
*
mockMinimalDisputeGameFactoryCaller
earliest
uint64
blockNumber
*
big
.
Int
expectedErr
error
expectedLen
int
...
...
@@ -33,35 +34,36 @@ func TestGameLoader_FetchAllGames(t *testing.T) {
name
:
"success"
,
caller
:
newMockMinimalDisputeGameFactoryCaller
(
10
,
false
,
false
),
blockNumber
:
big
.
NewInt
(
1
),
expectedErr
:
nil
,
expectedLen
:
10
,
},
{
name
:
"expired game ignored"
,
caller
:
newMockMinimalDisputeGameFactoryCaller
(
10
,
false
,
false
),
earliest
:
500
,
blockNumber
:
big
.
NewInt
(
1
),
expectedLen
:
5
,
},
{
name
:
"game count error"
,
caller
:
newMockMinimalDisputeGameFactoryCaller
(
10
,
true
,
false
),
blockNumber
:
big
.
NewInt
(
1
),
expectedErr
:
gameCountErr
,
expectedLen
:
0
,
},
{
name
:
"game index error"
,
caller
:
newMockMinimalDisputeGameFactoryCaller
(
10
,
false
,
true
),
blockNumber
:
big
.
NewInt
(
1
),
expectedErr
:
gameIndexErr
,
expectedLen
:
0
,
},
{
name
:
"no games"
,
caller
:
newMockMinimalDisputeGameFactoryCaller
(
0
,
false
,
false
),
blockNumber
:
big
.
NewInt
(
1
),
expectedErr
:
nil
,
expectedLen
:
0
,
},
{
name
:
"missing block number"
,
caller
:
newMockMinimalDisputeGameFactoryCaller
(
0
,
false
,
false
),
expectedErr
:
ErrMissingBlockNumber
,
expectedLen
:
0
,
},
}
...
...
@@ -72,10 +74,11 @@ func TestGameLoader_FetchAllGames(t *testing.T) {
t
.
Parallel
()
loader
:=
NewGameLoader
(
test
.
caller
)
games
,
err
:=
loader
.
FetchAllGamesAtBlock
(
context
.
Background
(),
test
.
blockNumber
)
games
,
err
:=
loader
.
FetchAllGamesAtBlock
(
context
.
Background
(),
test
.
earliest
,
test
.
blockNumber
)
require
.
ErrorIs
(
t
,
err
,
test
.
expectedErr
)
require
.
Len
(
t
,
games
,
test
.
expectedLen
)
expectedGames
:=
test
.
caller
.
games
expectedGames
=
expectedGames
[
len
(
expectedGames
)
-
test
.
expectedLen
:
]
if
test
.
expectedErr
!=
nil
{
expectedGames
=
make
([]
FaultDisputeGame
,
0
)
}
...
...
@@ -90,7 +93,7 @@ func generateMockGames(count uint64) []FaultDisputeGame {
for
i
:=
uint64
(
0
);
i
<
count
;
i
++
{
games
[
i
]
=
FaultDisputeGame
{
Proxy
:
common
.
BigToAddress
(
big
.
NewInt
(
int64
(
i
))),
Timestamp
:
i
,
Timestamp
:
i
*
100
,
}
}
...
...
op-challenger/fault/monitor.go
View file @
a145e096
...
...
@@ -13,6 +13,7 @@ import (
type
gamePlayer
interface
{
ProgressGame
(
ctx
context
.
Context
)
bool
Cleanup
()
error
}
type
playerCreator
func
(
address
common
.
Address
)
(
gamePlayer
,
error
)
...
...
@@ -20,24 +21,26 @@ type blockNumberFetcher func(ctx context.Context) (uint64, error)
// gameSource loads information about the games available to play
type
gameSource
interface
{
FetchAllGamesAtBlock
(
ctx
context
.
Context
,
blockNumber
*
big
.
Int
)
([]
FaultDisputeGame
,
error
)
FetchAllGamesAtBlock
(
ctx
context
.
Context
,
earliest
uint64
,
blockNumber
*
big
.
Int
)
([]
FaultDisputeGame
,
error
)
}
type
gameMonitor
struct
{
logger
log
.
Logger
clock
clock
.
Clock
source
gameSource
gameWindow
time
.
Duration
createPlayer
playerCreator
fetchBlockNumber
blockNumberFetcher
allowedGames
[]
common
.
Address
players
map
[
common
.
Address
]
gamePlayer
}
func
newGameMonitor
(
logger
log
.
Logger
,
cl
clock
.
Clock
,
fetchBlockNumber
blockNumberFetcher
,
allowedGames
[]
common
.
Address
,
source
gameSource
,
createGame
playerCreator
)
*
gameMonitor
{
func
newGameMonitor
(
logger
log
.
Logger
,
gameWindow
time
.
Duration
,
cl
clock
.
Clock
,
fetchBlockNumber
blockNumberFetcher
,
allowedGames
[]
common
.
Address
,
source
gameSource
,
createGame
playerCreator
)
*
gameMonitor
{
return
&
gameMonitor
{
logger
:
logger
,
clock
:
cl
,
source
:
source
,
gameWindow
:
gameWindow
,
createPlayer
:
createGame
,
fetchBlockNumber
:
fetchBlockNumber
,
allowedGames
:
allowedGames
,
...
...
@@ -57,26 +60,56 @@ func (m *gameMonitor) allowedGame(game common.Address) bool {
return
false
}
func
(
m
*
gameMonitor
)
minGameTimestamp
()
uint64
{
if
m
.
gameWindow
.
Seconds
()
==
0
{
return
0
}
// time: "To compute t-d for a duration d, use t.Add(-d)."
// https://pkg.go.dev/time#Time.Sub
if
m
.
clock
.
Now
()
.
Unix
()
>
int64
(
m
.
gameWindow
.
Seconds
())
{
return
uint64
(
m
.
clock
.
Now
()
.
Add
(
-
m
.
gameWindow
)
.
Unix
())
}
return
0
}
func
(
m
*
gameMonitor
)
progressGames
(
ctx
context
.
Context
)
error
{
blockNum
,
err
:=
m
.
fetchBlockNumber
(
ctx
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to load current block number: %w"
,
err
)
}
games
,
err
:=
m
.
source
.
FetchAllGamesAtBlock
(
ctx
,
new
(
big
.
Int
)
.
SetUint64
(
blockNum
))
games
,
err
:=
m
.
source
.
FetchAllGamesAtBlock
(
ctx
,
m
.
minGameTimestamp
(),
new
(
big
.
Int
)
.
SetUint64
(
blockNum
))
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to load games: %w"
,
err
)
}
requiredGames
:=
make
(
map
[
common
.
Address
]
bool
)
for
_
,
game
:=
range
games
{
if
!
m
.
allowedGame
(
game
.
Proxy
)
{
m
.
logger
.
Debug
(
"Skipping game not on allow list"
,
"game"
,
game
.
Proxy
)
continue
}
requiredGames
[
game
.
Proxy
]
=
true
player
,
err
:=
m
.
fetchOrCreateGamePlayer
(
game
)
if
err
!=
nil
{
m
.
logger
.
Error
(
"Error while progressing game"
,
"game"
,
game
.
Proxy
,
"err"
,
err
)
continue
}
player
.
ProgressGame
(
ctx
)
done
:=
player
.
ProgressGame
(
ctx
)
if
done
{
// Remove resources on disk as soon as the game is complete to save disk space.
// We keep the player in memory to avoid recreating it on every update but will no longer
// need the resources on disk because there are no further actions required on the game.
if
err
:=
player
.
Cleanup
();
err
!=
nil
{
m
.
logger
.
Error
(
"Unable to cleanup player data"
,
"err"
,
err
)
}
}
}
// Remove the player for any game that's no longer being returned from the list of active games
for
addr
:=
range
m
.
players
{
if
_
,
ok
:=
requiredGames
[
addr
];
ok
{
// Game still required
continue
}
delete
(
m
.
players
,
addr
)
}
return
nil
}
...
...
op-challenger/fault/monitor_test.go
View file @
a145e096
...
...
@@ -4,6 +4,7 @@ import (
"context"
"math/big"
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -13,6 +14,32 @@ import (
"github.com/ethereum-optimism/optimism/op-node/testlog"
)
func
TestMonitorMinGameTimestamp
(
t
*
testing
.
T
)
{
t
.
Parallel
()
t
.
Run
(
"zero game window returns zero"
,
func
(
t
*
testing
.
T
)
{
monitor
,
_
,
_
:=
setupMonitorTest
(
t
,
[]
common
.
Address
{})
monitor
.
gameWindow
=
time
.
Duration
(
0
)
require
.
Equal
(
t
,
monitor
.
minGameTimestamp
(),
uint64
(
0
))
})
t
.
Run
(
"non-zero game window with zero clock"
,
func
(
t
*
testing
.
T
)
{
monitor
,
_
,
_
:=
setupMonitorTest
(
t
,
[]
common
.
Address
{})
monitor
.
gameWindow
=
time
.
Minute
monitor
.
clock
=
clock
.
NewDeterministicClock
(
time
.
Unix
(
0
,
0
))
require
.
Equal
(
t
,
monitor
.
minGameTimestamp
(),
uint64
(
0
))
})
t
.
Run
(
"minimum computed correctly"
,
func
(
t
*
testing
.
T
)
{
monitor
,
_
,
_
:=
setupMonitorTest
(
t
,
[]
common
.
Address
{})
monitor
.
gameWindow
=
time
.
Minute
frozen
:=
time
.
Unix
(
int64
(
time
.
Hour
.
Seconds
()),
0
)
monitor
.
clock
=
clock
.
NewDeterministicClock
(
frozen
)
expected
:=
uint64
(
frozen
.
Add
(
-
time
.
Minute
)
.
Unix
())
require
.
Equal
(
t
,
monitor
.
minGameTimestamp
(),
expected
)
})
}
func
TestMonitorExitsWhenContextDone
(
t
*
testing
.
T
)
{
monitor
,
_
,
_
:=
setupMonitorTest
(
t
,
[]
common
.
Address
{
common
.
Address
{}})
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
...
...
@@ -77,6 +104,69 @@ func TestMonitorOnlyCreateSpecifiedGame(t *testing.T) {
require
.
Equal
(
t
,
1
,
games
.
created
[
addr2
]
.
progressCount
)
}
func
TestDeletePlayersWhenNoLongerInListOfGames
(
t
*
testing
.
T
)
{
addr1
:=
common
.
Address
{
0xaa
}
addr2
:=
common
.
Address
{
0xbb
}
monitor
,
source
,
games
:=
setupMonitorTest
(
t
,
nil
)
allGames
:=
[]
FaultDisputeGame
{
{
Proxy
:
addr1
,
Timestamp
:
9999
,
},
{
Proxy
:
addr2
,
Timestamp
:
9999
,
},
}
source
.
games
=
allGames
require
.
NoError
(
t
,
monitor
.
progressGames
(
context
.
Background
()))
require
.
Len
(
t
,
games
.
created
,
2
)
require
.
Contains
(
t
,
games
.
created
,
addr1
)
require
.
Contains
(
t
,
games
.
created
,
addr2
)
// First game is now old enough it's not returned in the list of active games
source
.
games
=
source
.
games
[
1
:
]
require
.
NoError
(
t
,
monitor
.
progressGames
(
context
.
Background
()))
require
.
Len
(
t
,
games
.
created
,
2
)
require
.
Contains
(
t
,
games
.
created
,
addr1
)
require
.
Contains
(
t
,
games
.
created
,
addr2
)
// Forget that we created the first game so it can be recreated if needed
delete
(
games
.
created
,
addr1
)
// First game now reappears (inexplicably but usefully for our testing)
source
.
games
=
allGames
require
.
NoError
(
t
,
monitor
.
progressGames
(
context
.
Background
()))
// A new player is created for it because the original was deleted
require
.
Len
(
t
,
games
.
created
,
2
)
require
.
Contains
(
t
,
games
.
created
,
addr1
)
require
.
Contains
(
t
,
games
.
created
,
addr2
)
require
.
Equal
(
t
,
1
,
games
.
created
[
addr1
]
.
progressCount
)
}
func
TestCleanupResourcesOfCompletedGames
(
t
*
testing
.
T
)
{
monitor
,
source
,
games
:=
setupMonitorTest
(
t
,
[]
common
.
Address
{})
games
.
createCompleted
=
true
addr1
:=
common
.
Address
{
0xaa
}
source
.
games
=
[]
FaultDisputeGame
{
{
Proxy
:
addr1
,
Timestamp
:
9999
,
},
}
err
:=
monitor
.
progressGames
(
context
.
Background
())
require
.
NoError
(
t
,
err
)
require
.
Len
(
t
,
games
.
created
,
1
,
"should create game agents"
)
require
.
Contains
(
t
,
games
.
created
,
addr1
)
require
.
Equal
(
t
,
1
,
games
.
created
[
addr1
]
.
progressCount
)
require
.
Equal
(
t
,
1
,
games
.
created
[
addr1
]
.
cleanupCount
,
"should clean up once game is done"
)
}
func
setupMonitorTest
(
t
*
testing
.
T
,
allowedGames
[]
common
.
Address
)
(
*
gameMonitor
,
*
stubGameSource
,
*
createdGames
)
{
logger
:=
testlog
.
Logger
(
t
,
log
.
LvlDebug
)
source
:=
&
stubGameSource
{}
...
...
@@ -87,7 +177,7 @@ func setupMonitorTest(t *testing.T, allowedGames []common.Address) (*gameMonitor
fetchBlockNum
:=
func
(
ctx
context
.
Context
)
(
uint64
,
error
)
{
return
1234
,
nil
}
monitor
:=
newGameMonitor
(
logger
,
clock
.
SystemClock
,
fetchBlockNum
,
allowedGames
,
source
,
games
.
CreateGame
)
monitor
:=
newGameMonitor
(
logger
,
time
.
Duration
(
0
),
clock
.
SystemClock
,
fetchBlockNum
,
allowedGames
,
source
,
games
.
CreateGame
)
return
monitor
,
source
,
games
}
...
...
@@ -95,13 +185,14 @@ type stubGameSource struct {
games
[]
FaultDisputeGame
}
func
(
s
*
stubGameSource
)
FetchAllGamesAtBlock
(
ctx
context
.
Context
,
blockNumber
*
big
.
Int
)
([]
FaultDisputeGame
,
error
)
{
func
(
s
*
stubGameSource
)
FetchAllGamesAtBlock
(
ctx
context
.
Context
,
earliest
uint64
,
blockNumber
*
big
.
Int
)
([]
FaultDisputeGame
,
error
)
{
return
s
.
games
,
nil
}
type
stubGame
struct
{
addr
common
.
Address
progressCount
int
cleanupCount
int
done
bool
}
...
...
@@ -110,16 +201,22 @@ func (g *stubGame) ProgressGame(ctx context.Context) bool {
return
g
.
done
}
func
(
g
*
stubGame
)
Cleanup
()
error
{
g
.
cleanupCount
++
return
nil
}
type
createdGames
struct
{
t
*
testing
.
T
created
map
[
common
.
Address
]
*
stubGame
t
*
testing
.
T
createCompleted
bool
created
map
[
common
.
Address
]
*
stubGame
}
func
(
c
*
createdGames
)
CreateGame
(
addr
common
.
Address
)
(
gamePlayer
,
error
)
{
if
_
,
exists
:=
c
.
created
[
addr
];
exists
{
c
.
t
.
Fatalf
(
"game %v already exists"
,
addr
)
}
game
:=
&
stubGame
{
addr
:
addr
}
game
:=
&
stubGame
{
addr
:
addr
,
done
:
c
.
createCompleted
}
c
.
created
[
addr
]
=
game
return
game
,
nil
}
op-challenger/fault/player.go
View file @
a145e096
...
...
@@ -10,8 +10,8 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/fault/cannon"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
)
...
...
@@ -29,6 +29,9 @@ type GamePlayer struct {
agreeWithProposedOutput
bool
caller
GameInfo
logger
log
.
Logger
cleanup
func
()
error
completed
bool
}
func
NewGamePlayer
(
...
...
@@ -37,7 +40,7 @@ func NewGamePlayer(
cfg
*
config
.
Config
,
addr
common
.
Address
,
txMgr
txmgr
.
TxManager
,
client
*
ethclient
.
Client
,
client
bind
.
ContractCaller
,
)
(
*
GamePlayer
,
error
)
{
logger
=
logger
.
New
(
"game"
,
addr
)
contract
,
err
:=
bindings
.
NewFaultDisputeGameCaller
(
addr
,
client
)
...
...
@@ -54,18 +57,22 @@ func NewGamePlayer(
var
provider
types
.
TraceProvider
var
updater
types
.
OracleUpdater
var
cleanup
func
()
error
switch
cfg
.
TraceType
{
case
config
.
TraceTypeCannon
:
provider
,
err
=
cannon
.
NewTraceProvider
(
ctx
,
logger
,
cfg
,
client
,
addr
)
cannonProvider
,
err
:
=
cannon
.
NewTraceProvider
(
ctx
,
logger
,
cfg
,
client
,
addr
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"create cannon trace provider: %w"
,
err
)
}
cleanup
=
cannonProvider
.
Cleanup
provider
=
cannonProvider
updater
,
err
=
cannon
.
NewOracleUpdater
(
ctx
,
logger
,
txMgr
,
addr
,
client
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"failed to create the cannon updater: %w"
,
err
)
}
case
config
.
TraceTypeAlphabet
:
provider
=
alphabet
.
NewTraceProvider
(
cfg
.
AlphabetTrace
,
gameDepth
)
cleanup
=
func
()
error
{
return
nil
}
updater
=
alphabet
.
NewOracleUpdater
(
logger
)
default
:
return
nil
,
fmt
.
Errorf
(
"unsupported trace type: %v"
,
cfg
.
TraceType
)
...
...
@@ -90,10 +97,16 @@ func NewGamePlayer(
agreeWithProposedOutput
:
cfg
.
AgreeWithProposedOutput
,
caller
:
caller
,
logger
:
logger
,
cleanup
:
cleanup
,
},
nil
}
func
(
g
*
GamePlayer
)
ProgressGame
(
ctx
context
.
Context
)
bool
{
if
g
.
completed
{
// Game is already complete so don't try to perform further actions.
g
.
logger
.
Trace
(
"Skipping completed game"
)
return
true
}
g
.
logger
.
Trace
(
"Checking if actions are required"
)
if
err
:=
g
.
agent
.
Act
(
ctx
);
err
!=
nil
{
g
.
logger
.
Error
(
"Error when acting on game"
,
"err"
,
err
)
...
...
@@ -102,7 +115,8 @@ func (g *GamePlayer) ProgressGame(ctx context.Context) bool {
g
.
logger
.
Warn
(
"Unable to retrieve game status"
,
"err"
,
err
)
}
else
{
g
.
logGameStatus
(
ctx
,
status
)
return
status
!=
types
.
GameStatusInProgress
g
.
completed
=
status
!=
types
.
GameStatusInProgress
return
g
.
completed
}
return
false
}
...
...
@@ -129,3 +143,7 @@ func (g *GamePlayer) logGameStatus(ctx context.Context, status types.GameStatus)
g
.
logger
.
Error
(
"Game lost"
,
"status"
,
status
)
}
}
func
(
g
*
GamePlayer
)
Cleanup
()
error
{
return
g
.
cleanup
()
}
op-challenger/fault/player_test.go
View file @
a145e096
...
...
@@ -12,14 +12,14 @@ import (
)
func
TestProgressGame_LogErrorFromAct
(
t
*
testing
.
T
)
{
handler
,
game
,
actor
,
_
:=
setupProgressGameTest
(
t
,
true
)
actor
.
e
rr
=
errors
.
New
(
"boom"
)
handler
,
game
,
actor
:=
setupProgressGameTest
(
t
,
true
)
actor
.
actE
rr
=
errors
.
New
(
"boom"
)
done
:=
game
.
ProgressGame
(
context
.
Background
())
require
.
False
(
t
,
done
,
"should not be done"
)
require
.
Equal
(
t
,
1
,
actor
.
callCount
,
"should perform next actions"
)
errLog
:=
handler
.
FindLog
(
log
.
LvlError
,
"Error when acting on game"
)
require
.
NotNil
(
t
,
errLog
,
"should log error"
)
require
.
Equal
(
t
,
actor
.
e
rr
,
errLog
.
GetContextValue
(
"err"
))
require
.
Equal
(
t
,
actor
.
actE
rr
,
errLog
.
GetContextValue
(
"err"
))
// Should still log game status
msg
:=
handler
.
FindLog
(
log
.
LvlInfo
,
"Game info"
)
...
...
@@ -27,6 +27,24 @@ func TestProgressGame_LogErrorFromAct(t *testing.T) {
require
.
Equal
(
t
,
uint64
(
1
),
msg
.
GetContextValue
(
"claims"
))
}
func
TestCleanup
(
t
*
testing
.
T
)
{
t
.
Run
(
"default cleanup"
,
func
(
t
*
testing
.
T
)
{
game
:=
&
GamePlayer
{
cleanup
:
func
()
error
{
return
nil
},
}
require
.
NoError
(
t
,
game
.
Cleanup
())
})
t
.
Run
(
"cleanup bubbles up error"
,
func
(
t
*
testing
.
T
)
{
err
:=
errors
.
New
(
"wassie"
)
game
:=
&
GamePlayer
{
cleanup
:
func
()
error
{
return
err
},
}
require
.
Error
(
t
,
err
,
game
.
Cleanup
())
})
}
func
TestProgressGame_LogGameStatus
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
...
...
@@ -74,11 +92,11 @@ func TestProgressGame_LogGameStatus(t *testing.T) {
for
_
,
test
:=
range
tests
{
test
:=
test
t
.
Run
(
test
.
name
,
func
(
t
*
testing
.
T
)
{
handler
,
game
,
actor
,
gameInfo
:=
setupProgressGameTest
(
t
,
test
.
agreeWithOutput
)
game
Info
.
status
=
test
.
status
handler
,
game
,
gameState
:=
setupProgressGameTest
(
t
,
test
.
agreeWithOutput
)
game
State
.
status
=
test
.
status
done
:=
game
.
ProgressGame
(
context
.
Background
())
require
.
Equal
(
t
,
1
,
actor
.
callCount
,
"should perform next actions"
)
require
.
Equal
(
t
,
1
,
gameState
.
callCount
,
"should perform next actions"
)
require
.
Equal
(
t
,
test
.
status
!=
types
.
GameStatusInProgress
,
done
,
"should be done when not in progress"
)
errLog
:=
handler
.
FindLog
(
test
.
logLevel
,
test
.
logMsg
)
require
.
NotNil
(
t
,
errLog
,
"should log game result"
)
...
...
@@ -87,43 +105,57 @@ func TestProgressGame_LogGameStatus(t *testing.T) {
}
}
func
setupProgressGameTest
(
t
*
testing
.
T
,
agreeWithProposedRoot
bool
)
(
*
testlog
.
CapturingHandler
,
*
GamePlayer
,
*
stubActor
,
*
stubGameInfo
)
{
func
TestDoNotActOnCompleteGame
(
t
*
testing
.
T
)
{
for
_
,
status
:=
range
[]
types
.
GameStatus
{
types
.
GameStatusChallengerWon
,
types
.
GameStatusDefenderWon
}
{
t
.
Run
(
status
.
String
(),
func
(
t
*
testing
.
T
)
{
_
,
game
,
gameState
:=
setupProgressGameTest
(
t
,
true
)
gameState
.
status
=
status
done
:=
game
.
ProgressGame
(
context
.
Background
())
require
.
Equal
(
t
,
1
,
gameState
.
callCount
,
"acts the first time"
)
require
.
True
(
t
,
done
,
"should be done"
)
// Should not act when it knows the game is already complete
done
=
game
.
ProgressGame
(
context
.
Background
())
require
.
Equal
(
t
,
1
,
gameState
.
callCount
,
"does not act after game is complete"
)
require
.
True
(
t
,
done
,
"should still be done"
)
})
}
}
func
setupProgressGameTest
(
t
*
testing
.
T
,
agreeWithProposedRoot
bool
)
(
*
testlog
.
CapturingHandler
,
*
GamePlayer
,
*
stubGameState
)
{
logger
:=
testlog
.
Logger
(
t
,
log
.
LvlDebug
)
handler
:=
&
testlog
.
CapturingHandler
{
Delegate
:
logger
.
GetHandler
(),
}
logger
.
SetHandler
(
handler
)
actor
:=
&
stubActor
{}
gameInfo
:=
&
stubGameInfo
{
claimCount
:
1
}
gameState
:=
&
stubGameState
{
claimCount
:
1
}
game
:=
&
GamePlayer
{
agent
:
actor
,
agent
:
gameState
,
agreeWithProposedOutput
:
agreeWithProposedRoot
,
caller
:
game
Info
,
caller
:
game
State
,
logger
:
logger
,
}
return
handler
,
game
,
actor
,
gameInfo
}
type
stubActor
struct
{
callCount
int
err
error
return
handler
,
game
,
gameState
}
func
(
a
*
stubActor
)
Act
(
ctx
context
.
Context
)
error
{
a
.
callCount
++
return
a
.
err
}
type
stubGameInfo
struct
{
type
stubGameState
struct
{
status
types
.
GameStatus
claimCount
uint64
err
error
callCount
int
actErr
error
Err
error
}
func
(
s
*
stubGameState
)
Act
(
ctx
context
.
Context
)
error
{
s
.
callCount
++
return
s
.
actErr
}
func
(
s
*
stubGame
Info
)
GetGameStatus
(
ctx
context
.
Context
)
(
types
.
GameStatus
,
error
)
{
return
s
.
status
,
s
.
err
func
(
s
*
stubGame
State
)
GetGameStatus
(
ctx
context
.
Context
)
(
types
.
GameStatus
,
error
)
{
return
s
.
status
,
nil
}
func
(
s
*
stubGame
Info
)
GetClaimCount
(
ctx
context
.
Context
)
(
uint64
,
error
)
{
return
s
.
claimCount
,
s
.
err
func
(
s
*
stubGame
State
)
GetClaimCount
(
ctx
context
.
Context
)
(
uint64
,
error
)
{
return
s
.
claimCount
,
nil
}
op-challenger/fault/responder.go
View file @
a145e096
...
...
@@ -79,18 +79,25 @@ func (r *faultResponder) BuildTx(ctx context.Context, response types.Claim) ([]b
}
}
// Ca
n
Resolve determines if the resolve function on the fault dispute game contract
// would succeed. Returns t
rue if the game can be resolved, otherwise fal
se.
func
(
r
*
faultResponder
)
Ca
nResolve
(
ctx
context
.
Context
)
bool
{
// Ca
ll
Resolve determines if the resolve function on the fault dispute game contract
// would succeed. Returns t
he game status if the call would succeed, errors otherwi
se.
func
(
r
*
faultResponder
)
Ca
llResolve
(
ctx
context
.
Context
)
(
types
.
GameStatus
,
error
)
{
txData
,
err
:=
r
.
buildResolveData
()
if
err
!=
nil
{
return
false
return
types
.
GameStatusInProgress
,
err
}
_
,
err
=
r
.
txMgr
.
Call
(
ctx
,
ethereum
.
CallMsg
{
res
,
err
:
=
r
.
txMgr
.
Call
(
ctx
,
ethereum
.
CallMsg
{
To
:
&
r
.
fdgAddr
,
Data
:
txData
,
},
nil
)
return
err
==
nil
if
err
!=
nil
{
return
types
.
GameStatusInProgress
,
err
}
var
status
uint8
if
err
=
r
.
fdgAbi
.
UnpackIntoInterface
(
&
status
,
"resolve"
,
res
);
err
!=
nil
{
return
types
.
GameStatusInProgress
,
err
}
return
types
.
GameStatusFromUint8
(
status
)
}
// Resolve executes a resolve transaction to resolve a fault dispute game.
...
...
op-challenger/fault/responder_test.go
View file @
a145e096
This diff is collapsed.
Click to expand it.
op-challenger/fault/service.go
View file @
a145e096
...
...
@@ -73,7 +73,7 @@ func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*se
}
loader
:=
NewGameLoader
(
factory
)
monitor
:=
newGameMonitor
(
logger
,
cl
,
client
.
BlockNumber
,
cfg
.
GameAllowlist
,
loader
,
func
(
addr
common
.
Address
)
(
gamePlayer
,
error
)
{
monitor
:=
newGameMonitor
(
logger
,
c
fg
.
GameWindow
,
c
l
,
client
.
BlockNumber
,
cfg
.
GameAllowlist
,
loader
,
func
(
addr
common
.
Address
)
(
gamePlayer
,
error
)
{
return
NewGamePlayer
(
ctx
,
logger
,
cfg
,
addr
,
txMgr
,
client
)
})
...
...
op-challenger/fault/types/types.go
View file @
a145e096
...
...
@@ -3,6 +3,7 @@ package types
import
(
"context"
"errors"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -34,6 +35,14 @@ func (s GameStatus) String() string {
}
}
// GameStatusFromUint8 returns a game status from the uint8 representation.
func
GameStatusFromUint8
(
i
uint8
)
(
GameStatus
,
error
)
{
if
i
>
2
{
return
GameStatus
(
i
),
fmt
.
Errorf
(
"invalid game status: %d"
,
i
)
}
return
GameStatus
(
i
),
nil
}
// PreimageOracleData encapsulates the preimage oracle data
// to load into the onchain oracle.
type
PreimageOracleData
struct
{
...
...
op-challenger/fault/types/types_test.go
View file @
a145e096
package
types
import
(
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
var
validGameStatuses
=
[]
GameStatus
{
GameStatusInProgress
,
GameStatusChallengerWon
,
GameStatusDefenderWon
,
}
func
TestGameStatusFromUint8
(
t
*
testing
.
T
)
{
for
_
,
status
:=
range
validGameStatuses
{
t
.
Run
(
fmt
.
Sprintf
(
"Valid Game Status %v"
,
status
),
func
(
t
*
testing
.
T
)
{
parsed
,
err
:=
GameStatusFromUint8
(
uint8
(
status
))
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
status
,
parsed
)
})
}
t
.
Run
(
"Invalid"
,
func
(
t
*
testing
.
T
)
{
status
,
err
:=
GameStatusFromUint8
(
3
)
require
.
Error
(
t
,
err
)
require
.
Equal
(
t
,
GameStatus
(
3
),
status
)
})
}
func
TestNewPreimageOracleData
(
t
*
testing
.
T
)
{
t
.
Run
(
"LocalData"
,
func
(
t
*
testing
.
T
)
{
data
:=
NewPreimageOracleData
([]
byte
{
1
,
2
,
3
},
[]
byte
{
4
,
5
,
6
},
7
)
...
...
op-challenger/flags/flags.go
View file @
a145e096
...
...
@@ -109,6 +109,12 @@ var (
EnvVars
:
prefixEnvVars
(
"CANNON_SNAPSHOT_FREQ"
),
Value
:
config
.
DefaultCannonSnapshotFreq
,
}
GameWindowFlag
=
&
cli
.
DurationFlag
{
Name
:
"game-window"
,
Usage
:
"The time window which the challenger will look for games to progress."
,
EnvVars
:
prefixEnvVars
(
"GAME_WINDOW"
),
Value
:
config
.
DefaultGameWindow
,
}
)
// requiredFlags are checked by [CheckRequired]
...
...
@@ -132,6 +138,7 @@ var optionalFlags = []cli.Flag{
CannonDatadirFlag
,
CannonL2Flag
,
CannonSnapshotFreqFlag
,
GameWindowFlag
,
}
func
init
()
{
...
...
@@ -222,6 +229,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) {
TraceType
:
traceTypeFlag
,
GameFactoryAddress
:
gameFactoryAddress
,
GameAllowlist
:
allowedGames
,
GameWindow
:
ctx
.
Duration
(
GameWindowFlag
.
Name
),
AlphabetTrace
:
ctx
.
String
(
AlphabetFlag
.
Name
),
CannonNetwork
:
ctx
.
String
(
CannonNetworkFlag
.
Name
),
CannonRollupConfigPath
:
ctx
.
String
(
CannonRollupConfigFlag
.
Name
),
...
...
package.json
View file @
a145e096
...
...
@@ -68,7 +68,7 @@
"
markdownlint-cli2
"
:
"
0.4.0
"
,
"
mkdirp
"
:
"
^1.0.4
"
,
"
mocha
"
:
"
^10.2.0
"
,
"
nx
"
:
"
16.7.
2
"
,
"
nx
"
:
"
16.7.
3
"
,
"
nyc
"
:
"
^15.1.0
"
,
"
patch-package
"
:
"
^8.0.0
"
,
"
prettier
"
:
"
^2.8.0
"
,
...
...
packages/contracts-bedrock/package.json
View file @
a145e096
...
...
@@ -41,7 +41,7 @@
"lint"
:
"pnpm lint:fix && pnpm lint:check"
},
"devDependencies"
:
{
"@typescript-eslint/eslint-plugin"
:
"^
6.4
.0"
,
"@typescript-eslint/eslint-plugin"
:
"^
5.62
.0"
,
"@typescript-eslint/parser"
:
"^6.4.0"
,
"tsx"
:
"^3.12.7"
,
"typescript"
:
"^5.1.6"
...
...
pnpm-lock.yaml
View file @
a145e096
This diff is collapsed.
Click to expand it.
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