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
b9dca1e6
Unverified
Commit
b9dca1e6
authored
Aug 24, 2023
by
mergify[bot]
Committed by
GitHub
Aug 24, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into 08-23-feat_indexer_update_Dockerfile_to_run_indexer_all
parents
2d527d6b
e77efb38
Changes
15
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
1599 additions
and
146 deletions
+1599
-146
batch.go
op-chain-ops/safe/batch.go
+298
-0
batch_file_test.go
op-chain-ops/safe/batch_file_test.go
+0
-29
batch_helpers.go
op-chain-ops/safe/batch_helpers.go
+209
-0
batch_test.go
op-chain-ops/safe/batch_test.go
+156
-0
deposit-tx.json
op-chain-ops/safe/testdata/deposit-tx.json
+56
-0
finalize-withdrawal-tx.json
op-chain-ops/safe/testdata/finalize-withdrawal-tx.json
+64
-0
portal-abi.json
op-chain-ops/safe/testdata/portal-abi.json
+560
-0
disk.go
op-challenger/fault/disk.go
+4
-6
monitor.go
op-challenger/fault/monitor.go
+20
-11
monitor_test.go
op-challenger/fault/monitor_test.go
+10
-10
helper.go
op-e2e/e2eutils/challenger/helper.go
+25
-5
faultproof_test.go
op-e2e/faultproof_test.go
+1
-1
getting-started.json
...ages/contracts-bedrock/deploy-config/getting-started.json
+1
-2
Deploy.s.sol
packages/contracts-bedrock/scripts/Deploy.s.sol
+1
-1
pnpm-lock.yaml
pnpm-lock.yaml
+194
-81
No files found.
op-chain-ops/safe/batch
_file
.go
→
op-chain-ops/safe/batch.go
View file @
b9dca1e6
...
...
@@ -4,46 +4,134 @@
package
safe
import
(
"bytes"
"encoding/json"
"fmt"
"math/big"
"strings"
"golang.org/x/exp/maps"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
)
// Batch
File
represents a Safe tx-builder transaction.
type
Batch
File
struct
{
// Batch represents a Safe tx-builder transaction.
type
Batch
struct
{
Version
string
`json:"version"`
ChainID
*
big
.
Int
`json:"chainId"`
CreatedAt
uint64
`json:"createdAt"`
Meta
Batch
FileMeta
`json:"meta"`
Meta
Batch
Meta
`json:"meta"`
Transactions
[]
BatchTransaction
`json:"transactions"`
}
// AddCall will add a call to the batch. After a series of calls are
// added to the batch, it can be serialized to JSON.
func
(
b
*
Batch
)
AddCall
(
to
common
.
Address
,
value
*
big
.
Int
,
sig
string
,
args
[]
any
,
iface
abi
.
ABI
)
error
{
// Attempt to pull out the signature from the top level methods.
// The abi package uses normalization that we do not want to be
// coupled to, so attempt to search for the raw name if the top
// level name is not found to handle overloading more gracefully.
method
,
ok
:=
iface
.
Methods
[
sig
]
if
!
ok
{
for
_
,
m
:=
range
iface
.
Methods
{
if
m
.
RawName
==
sig
||
m
.
Sig
==
sig
{
method
=
m
ok
=
true
}
}
}
if
!
ok
{
keys
:=
maps
.
Keys
(
iface
.
Methods
)
methods
:=
strings
.
Join
(
keys
,
","
)
return
fmt
.
Errorf
(
"%s not found in abi, options are %s"
,
sig
,
methods
)
}
if
len
(
args
)
!=
len
(
method
.
Inputs
)
{
return
fmt
.
Errorf
(
"requires %d inputs but got %d for %s"
,
len
(
method
.
Inputs
),
len
(
args
),
method
.
RawName
)
}
contractMethod
:=
ContractMethod
{
Name
:
method
.
RawName
,
Payable
:
method
.
Payable
,
}
inputValues
:=
make
(
map
[
string
]
string
)
contractInputs
:=
make
([]
ContractInput
,
0
)
for
i
,
input
:=
range
method
.
Inputs
{
contractInput
,
err
:=
createContractInput
(
input
,
contractInputs
)
if
err
!=
nil
{
return
err
}
contractMethod
.
Inputs
=
append
(
contractMethod
.
Inputs
,
contractInput
...
)
str
,
err
:=
stringifyArg
(
args
[
i
])
if
err
!=
nil
{
return
err
}
inputValues
[
input
.
Name
]
=
str
}
encoded
,
err
:=
method
.
Inputs
.
PackValues
(
args
)
if
err
!=
nil
{
return
err
}
data
:=
make
([]
byte
,
len
(
method
.
ID
)
+
len
(
encoded
))
copy
(
data
,
method
.
ID
)
copy
(
data
[
len
(
method
.
ID
)
:
],
encoded
)
batchTransaction
:=
BatchTransaction
{
To
:
to
,
Value
:
value
,
Method
:
contractMethod
,
Data
:
data
,
InputValues
:
inputValues
,
}
b
.
Transactions
=
append
(
b
.
Transactions
,
batchTransaction
)
return
nil
}
// Check will check the batch for errors
func
(
b
*
Batch
)
Check
()
error
{
for
_
,
tx
:=
range
b
.
Transactions
{
if
err
:=
tx
.
Check
();
err
!=
nil
{
return
err
}
}
return
nil
}
// bathcFileMarshaling is a helper type used for JSON marshaling.
type
batch
File
Marshaling
struct
{
type
batchMarshaling
struct
{
Version
string
`json:"version"`
ChainID
string
`json:"chainId"`
CreatedAt
uint64
`json:"createdAt"`
Meta
Batch
FileMeta
`json:"meta"`
Meta
Batch
Meta
`json:"meta"`
Transactions
[]
BatchTransaction
`json:"transactions"`
}
// MarshalJSON will marshal a Batch
File
to JSON.
func
(
b
*
Batch
File
)
MarshalJSON
()
([]
byte
,
error
)
{
return
json
.
Marshal
(
batchFile
Marshaling
{
// MarshalJSON will marshal a Batch to JSON.
func
(
b
*
Batch
)
MarshalJSON
()
([]
byte
,
error
)
{
batch
:=
batch
Marshaling
{
Version
:
b
.
Version
,
ChainID
:
b
.
ChainID
.
String
(),
CreatedAt
:
b
.
CreatedAt
,
Meta
:
b
.
Meta
,
Transactions
:
b
.
Transactions
,
})
}
if
b
.
ChainID
!=
nil
{
batch
.
ChainID
=
b
.
ChainID
.
String
()
}
return
json
.
Marshal
(
batch
)
}
// UnmarshalJSON will unmarshal a Batch
File
from JSON.
func
(
b
*
Batch
File
)
UnmarshalJSON
(
data
[]
byte
)
error
{
var
bf
batch
File
Marshaling
// UnmarshalJSON will unmarshal a Batch from JSON.
func
(
b
*
Batch
)
UnmarshalJSON
(
data
[]
byte
)
error
{
var
bf
batchMarshaling
if
err
:=
json
.
Unmarshal
(
data
,
&
bf
);
err
!=
nil
{
return
err
}
...
...
@@ -59,9 +147,9 @@ func (b *BatchFile) UnmarshalJSON(data []byte) error {
return
nil
}
// Batch
FileMeta contains metadata about a BatchFile
. Not all
// Batch
Meta contains metadata about a Batch
. Not all
// of the fields are required.
type
Batch
File
Meta
struct
{
type
BatchMeta
struct
{
TxBuilderVersion
string
`json:"txBuilderVersion,omitempty"`
Checksum
string
`json:"checksum,omitempty"`
CreatedFromSafeAddress
string
`json:"createdFromSafeAddress"`
...
...
@@ -79,6 +167,81 @@ type BatchTransaction struct {
InputValues
map
[
string
]
string
`json:"contractInputsValues"`
}
// Check will check the batch transaction for errors.
// An error is defined by:
// - incorrectly encoded calldata
// - mismatch in number of arguments
// It does not currently work on structs, will return no error if a "tuple"
// is used as an argument. Need to find a generic way to work with structs.
func
(
bt
*
BatchTransaction
)
Check
()
error
{
if
len
(
bt
.
Method
.
Inputs
)
!=
len
(
bt
.
InputValues
)
{
return
fmt
.
Errorf
(
"expected %d inputs but got %d"
,
len
(
bt
.
Method
.
Inputs
),
len
(
bt
.
InputValues
))
}
if
len
(
bt
.
Data
)
>
0
&&
bt
.
Method
.
Name
!=
"fallback"
{
if
len
(
bt
.
Data
)
<
4
{
return
fmt
.
Errorf
(
"must have at least 4 bytes of calldata, got %d"
,
len
(
bt
.
Data
))
}
sig
:=
bt
.
Signature
()
selector
:=
crypto
.
Keccak256
([]
byte
(
sig
))[
0
:
4
]
if
!
bytes
.
Equal
(
bt
.
Data
[
0
:
4
],
selector
)
{
return
fmt
.
Errorf
(
"data does not match signature"
)
}
// Check the calldata
values
:=
make
([]
any
,
len
(
bt
.
Method
.
Inputs
))
for
i
,
input
:=
range
bt
.
Method
.
Inputs
{
value
,
ok
:=
bt
.
InputValues
[
input
.
Name
]
if
!
ok
{
return
fmt
.
Errorf
(
"missing input %s"
,
input
.
Name
)
}
// Need to figure out better way to handle tuples in a generic way
if
input
.
Type
==
"tuple"
{
return
nil
}
arg
,
err
:=
unstringifyArg
(
value
,
input
.
Type
)
if
err
!=
nil
{
return
err
}
values
[
i
]
=
arg
}
calldata
,
err
:=
bt
.
Arguments
()
.
PackValues
(
values
)
if
err
!=
nil
{
return
err
}
if
!
bytes
.
Equal
(
bt
.
Data
[
4
:
],
calldata
)
{
return
fmt
.
Errorf
(
"calldata does not match inputs, expected %s, got %s"
,
hexutil
.
Encode
(
bt
.
Data
[
4
:
]),
hexutil
.
Encode
(
calldata
))
}
}
return
nil
}
// Signature returns the function signature of the batch transaction.
func
(
bt
*
BatchTransaction
)
Signature
()
string
{
types
:=
make
([]
string
,
len
(
bt
.
Method
.
Inputs
))
for
i
,
input
:=
range
bt
.
Method
.
Inputs
{
types
[
i
]
=
buildFunctionSignature
(
input
)
}
return
fmt
.
Sprintf
(
"%s(%s)"
,
bt
.
Method
.
Name
,
strings
.
Join
(
types
,
","
))
}
func
(
bt
*
BatchTransaction
)
Arguments
()
abi
.
Arguments
{
arguments
:=
make
(
abi
.
Arguments
,
len
(
bt
.
Method
.
Inputs
))
for
i
,
input
:=
range
bt
.
Method
.
Inputs
{
serialized
,
err
:=
json
.
Marshal
(
input
)
if
err
!=
nil
{
panic
(
err
)
}
var
arg
abi
.
Argument
if
err
:=
json
.
Unmarshal
(
serialized
,
&
arg
);
err
!=
nil
{
panic
(
err
)
}
arguments
[
i
]
=
arg
}
return
arguments
}
// UnmarshalJSON will unmarshal a BatchTransaction from JSON.
func
(
b
*
BatchTransaction
)
UnmarshalJSON
(
data
[]
byte
)
error
{
var
bt
batchTransactionMarshaling
...
...
@@ -87,6 +250,9 @@ func (b *BatchTransaction) UnmarshalJSON(data []byte) error {
}
b
.
To
=
common
.
HexToAddress
(
bt
.
To
)
b
.
Value
=
new
(
big
.
Int
)
.
SetUint64
(
bt
.
Value
)
if
bt
.
Data
!=
nil
{
b
.
Data
=
common
.
CopyBytes
(
*
bt
.
Data
)
}
b
.
Method
=
bt
.
Method
b
.
InputValues
=
bt
.
InputValues
return
nil
...
...
@@ -101,8 +267,8 @@ func (b *BatchTransaction) MarshalJSON() ([]byte, error) {
InputValues
:
b
.
InputValues
,
}
if
len
(
b
.
Data
)
!=
0
{
hex
:=
hexutil
.
Encode
(
b
.
Data
)
batch
.
Data
=
&
hex
data
:=
hexutil
.
Bytes
(
b
.
Data
)
batch
.
Data
=
&
data
}
return
json
.
Marshal
(
batch
)
}
...
...
@@ -111,7 +277,7 @@ func (b *BatchTransaction) MarshalJSON() ([]byte, error) {
type
batchTransactionMarshaling
struct
{
To
string
`json:"to"`
Value
uint64
`json:"value,string"`
Data
*
string
`json:"data"`
Data
*
hexutil
.
Bytes
`json:"data"`
Method
ContractMethod
`json:"contractMethod"`
InputValues
map
[
string
]
string
`json:"contractInputsValues"`
}
...
...
op-chain-ops/safe/batch_file_test.go
deleted
100644 → 0
View file @
2d527d6b
package
safe
import
(
"bytes"
"encoding/json"
"os"
"testing"
"github.com/stretchr/testify/require"
)
func
TestBatchFileJSONPrepareBedrock
(
t
*
testing
.
T
)
{
testBatchFileJSON
(
t
,
"testdata/batch-prepare-bedrock.json"
)
}
func
TestBatchFileJSONL2OO
(
t
*
testing
.
T
)
{
testBatchFileJSON
(
t
,
"testdata/l2-output-oracle.json"
)
}
func
testBatchFileJSON
(
t
*
testing
.
T
,
path
string
)
{
b
,
err
:=
os
.
ReadFile
(
path
)
require
.
NoError
(
t
,
err
)
dec
:=
json
.
NewDecoder
(
bytes
.
NewReader
(
b
))
decoded
:=
new
(
BatchFile
)
require
.
NoError
(
t
,
dec
.
Decode
(
decoded
))
data
,
err
:=
json
.
Marshal
(
decoded
)
require
.
NoError
(
t
,
err
)
require
.
JSONEq
(
t
,
string
(
b
),
string
(
data
))
}
op-chain-ops/safe/batch_helpers.go
0 → 100644
View file @
b9dca1e6
package
safe
import
(
"fmt"
"math/big"
"reflect"
"strconv"
"strings"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
// stringifyArg converts a Go type to a string that is representable by ABI.
// To do so, this function must be recursive to handle nested tuples.
func
stringifyArg
(
argument
any
)
(
string
,
error
)
{
switch
arg
:=
argument
.
(
type
)
{
case
common
.
Address
:
return
arg
.
String
(),
nil
case
*
common
.
Address
:
return
arg
.
String
(),
nil
case
*
big
.
Int
:
return
arg
.
String
(),
nil
case
big
.
Int
:
return
arg
.
String
(),
nil
case
bool
:
if
arg
{
return
"true"
,
nil
}
return
"false"
,
nil
case
int64
:
return
strconv
.
FormatInt
(
arg
,
10
),
nil
case
int32
:
return
strconv
.
FormatInt
(
int64
(
arg
),
10
),
nil
case
int16
:
return
strconv
.
FormatInt
(
int64
(
arg
),
10
),
nil
case
int8
:
return
strconv
.
FormatInt
(
int64
(
arg
),
10
),
nil
case
int
:
return
strconv
.
FormatInt
(
int64
(
arg
),
10
),
nil
case
uint64
:
return
strconv
.
FormatUint
(
uint64
(
arg
),
10
),
nil
case
uint32
:
return
strconv
.
FormatUint
(
uint64
(
arg
),
10
),
nil
case
uint16
:
return
strconv
.
FormatUint
(
uint64
(
arg
),
10
),
nil
case
uint8
:
return
strconv
.
FormatUint
(
uint64
(
arg
),
10
),
nil
case
uint
:
return
strconv
.
FormatUint
(
uint64
(
arg
),
10
),
nil
case
[]
byte
:
return
hexutil
.
Encode
(
arg
),
nil
case
[]
any
:
ret
:=
make
([]
string
,
len
(
arg
))
for
i
,
v
:=
range
arg
{
str
,
err
:=
stringifyArg
(
v
)
if
err
!=
nil
{
return
""
,
err
}
ret
[
i
]
=
str
}
return
"["
+
strings
.
Join
(
ret
,
","
)
+
"]"
,
nil
default
:
typ
:=
reflect
.
TypeOf
(
argument
)
if
typ
.
Kind
()
==
reflect
.
Ptr
{
typ
=
typ
.
Elem
()
}
if
typ
.
Kind
()
==
reflect
.
Struct
{
v
:=
reflect
.
ValueOf
(
argument
)
numField
:=
v
.
NumField
()
ret
:=
make
([]
string
,
numField
)
for
i
:=
0
;
i
<
numField
;
i
++
{
val
:=
v
.
Field
(
i
)
.
Interface
()
str
,
err
:=
stringifyArg
(
val
)
if
err
!=
nil
{
return
""
,
err
}
ret
[
i
]
=
str
}
return
"["
+
strings
.
Join
(
ret
,
","
)
+
"]"
,
nil
}
return
""
,
fmt
.
Errorf
(
"unknown type as argument: %T"
,
arg
)
}
}
// unstringifyArg converts a string to a Go type.
func
unstringifyArg
(
arg
string
,
typ
string
)
(
any
,
error
)
{
switch
typ
{
case
"address"
:
return
common
.
HexToAddress
(
arg
),
nil
case
"bool"
:
return
strconv
.
ParseBool
(
arg
)
case
"uint8"
:
val
,
err
:=
strconv
.
ParseUint
(
arg
,
10
,
8
)
return
uint8
(
val
),
err
case
"uint16"
:
val
,
err
:=
strconv
.
ParseUint
(
arg
,
10
,
16
)
return
uint16
(
val
),
err
case
"uint32"
:
val
,
err
:=
strconv
.
ParseUint
(
arg
,
10
,
32
)
return
uint32
(
val
),
err
case
"uint64"
:
val
,
err
:=
strconv
.
ParseUint
(
arg
,
10
,
64
)
return
val
,
err
case
"int8"
:
val
,
err
:=
strconv
.
ParseInt
(
arg
,
10
,
8
)
return
val
,
err
case
"int16"
:
val
,
err
:=
strconv
.
ParseInt
(
arg
,
10
,
16
)
return
val
,
err
case
"int32"
:
val
,
err
:=
strconv
.
ParseInt
(
arg
,
10
,
32
)
return
val
,
err
case
"int64"
:
val
,
err
:=
strconv
.
ParseInt
(
arg
,
10
,
64
)
return
val
,
err
case
"uint256"
,
"int256"
:
val
,
ok
:=
new
(
big
.
Int
)
.
SetString
(
arg
,
10
)
if
!
ok
{
return
nil
,
fmt
.
Errorf
(
"failed to parse %s as big.Int"
,
arg
)
}
return
val
,
nil
case
"string"
:
return
arg
,
nil
case
"bytes"
:
return
hexutil
.
Decode
(
arg
)
default
:
return
nil
,
fmt
.
Errorf
(
"unknown type: %s"
,
typ
)
}
}
// createContractInput converts an abi.Argument to one or more ContractInputs.
func
createContractInput
(
input
abi
.
Argument
,
inputs
[]
ContractInput
)
([]
ContractInput
,
error
)
{
inputType
,
err
:=
stringifyType
(
input
.
Type
)
if
err
!=
nil
{
return
nil
,
err
}
// TODO: could probably do better than string comparison?
internalType
:=
input
.
Type
.
String
()
if
inputType
==
"tuple"
{
internalType
=
input
.
Type
.
TupleRawName
}
components
:=
make
([]
ContractInput
,
0
)
for
i
,
elem
:=
range
input
.
Type
.
TupleElems
{
e
:=
*
elem
arg
:=
abi
.
Argument
{
Name
:
input
.
Type
.
TupleRawNames
[
i
],
Type
:
e
,
}
component
,
err
:=
createContractInput
(
arg
,
inputs
)
if
err
!=
nil
{
return
nil
,
err
}
components
=
append
(
components
,
component
...
)
}
contractInput
:=
ContractInput
{
InternalType
:
internalType
,
Name
:
input
.
Name
,
Type
:
inputType
,
Components
:
components
,
}
inputs
=
append
(
inputs
,
contractInput
)
return
inputs
,
nil
}
// stringifyType turns an abi.Type into a string
func
stringifyType
(
t
abi
.
Type
)
(
string
,
error
)
{
switch
t
.
T
{
case
abi
.
TupleTy
:
return
"tuple"
,
nil
case
abi
.
BoolTy
:
return
t
.
String
(),
nil
case
abi
.
AddressTy
:
return
t
.
String
(),
nil
case
abi
.
UintTy
:
return
t
.
String
(),
nil
case
abi
.
IntTy
:
return
t
.
String
(),
nil
case
abi
.
StringTy
:
return
t
.
String
(),
nil
case
abi
.
BytesTy
:
return
t
.
String
(),
nil
default
:
return
""
,
fmt
.
Errorf
(
"unknown type: %d"
,
t
.
T
)
}
}
// buildFunctionSignature builds a function signature from a ContractInput.
// It is recursive to handle tuples.
func
buildFunctionSignature
(
input
ContractInput
)
string
{
if
input
.
Type
==
"tuple"
{
types
:=
make
([]
string
,
len
(
input
.
Components
))
for
i
,
component
:=
range
input
.
Components
{
types
[
i
]
=
buildFunctionSignature
(
component
)
}
return
fmt
.
Sprintf
(
"(%s)"
,
strings
.
Join
(
types
,
","
))
}
return
input
.
InternalType
}
op-chain-ops/safe/batch_test.go
0 → 100644
View file @
b9dca1e6
package
safe
import
(
"bytes"
"encoding/json"
"errors"
"math/big"
"os"
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
func
TestBatchJSONPrepareBedrock
(
t
*
testing
.
T
)
{
testBatchJSON
(
t
,
"testdata/batch-prepare-bedrock.json"
)
}
func
TestBatchJSONL2OO
(
t
*
testing
.
T
)
{
testBatchJSON
(
t
,
"testdata/l2-output-oracle.json"
)
}
func
testBatchJSON
(
t
*
testing
.
T
,
path
string
)
{
b
,
err
:=
os
.
ReadFile
(
path
)
require
.
NoError
(
t
,
err
)
dec
:=
json
.
NewDecoder
(
bytes
.
NewReader
(
b
))
decoded
:=
new
(
Batch
)
require
.
NoError
(
t
,
dec
.
Decode
(
decoded
))
data
,
err
:=
json
.
Marshal
(
decoded
)
require
.
NoError
(
t
,
err
)
require
.
JSONEq
(
t
,
string
(
b
),
string
(
data
))
}
// TestBatchAddCallFinalizeWithdrawalTransaction ensures that structs can be serialized correctly.
func
TestBatchAddCallFinalizeWithdrawalTransaction
(
t
*
testing
.
T
)
{
file
,
err
:=
os
.
ReadFile
(
"testdata/portal-abi.json"
)
require
.
NoError
(
t
,
err
)
portalABI
,
err
:=
abi
.
JSON
(
bytes
.
NewReader
(
file
))
require
.
NoError
(
t
,
err
)
sig
:=
"finalizeWithdrawalTransaction"
argument
:=
[]
any
{
bindings
.
TypesWithdrawalTransaction
{
Nonce
:
big
.
NewInt
(
0
),
Sender
:
common
.
Address
{
19
:
0x01
},
Target
:
common
.
Address
{
19
:
0x02
},
Value
:
big
.
NewInt
(
1
),
GasLimit
:
big
.
NewInt
(
2
),
Data
:
[]
byte
{},
},
}
batch
:=
new
(
Batch
)
to
:=
common
.
Address
{
19
:
0x01
}
value
:=
big
.
NewInt
(
222
)
require
.
NoError
(
t
,
batch
.
AddCall
(
to
,
value
,
sig
,
argument
,
portalABI
))
require
.
NoError
(
t
,
batch
.
Check
())
require
.
Equal
(
t
,
batch
.
Transactions
[
0
]
.
Signature
(),
"finalizeWithdrawalTransaction((uint256,address,address,uint256,uint256,bytes))"
)
expected
,
err
:=
os
.
ReadFile
(
"testdata/finalize-withdrawal-tx.json"
)
require
.
NoError
(
t
,
err
)
serialized
,
err
:=
json
.
Marshal
(
batch
)
require
.
NoError
(
t
,
err
)
require
.
JSONEq
(
t
,
string
(
expected
),
string
(
serialized
))
}
// TestBatchAddCallDespostTransaction ensures that simple calls can be serialized correctly.
func
TestBatchAddCallDespositTransaction
(
t
*
testing
.
T
)
{
file
,
err
:=
os
.
ReadFile
(
"testdata/portal-abi.json"
)
require
.
NoError
(
t
,
err
)
portalABI
,
err
:=
abi
.
JSON
(
bytes
.
NewReader
(
file
))
require
.
NoError
(
t
,
err
)
batch
:=
new
(
Batch
)
to
:=
common
.
Address
{
19
:
0x01
}
value
:=
big
.
NewInt
(
222
)
sig
:=
"depositTransaction"
argument
:=
[]
any
{
common
.
Address
{
01
},
big
.
NewInt
(
2
),
uint64
(
100
),
false
,
[]
byte
{},
}
require
.
NoError
(
t
,
batch
.
AddCall
(
to
,
value
,
sig
,
argument
,
portalABI
))
require
.
NoError
(
t
,
batch
.
Check
())
require
.
Equal
(
t
,
batch
.
Transactions
[
0
]
.
Signature
(),
"depositTransaction(address,uint256,uint64,bool,bytes)"
)
expected
,
err
:=
os
.
ReadFile
(
"testdata/deposit-tx.json"
)
require
.
NoError
(
t
,
err
)
serialized
,
err
:=
json
.
Marshal
(
batch
)
require
.
NoError
(
t
,
err
)
require
.
JSONEq
(
t
,
string
(
expected
),
string
(
serialized
))
}
// TestBatchCheck checks for the various failure cases of Batch.Check
// as well as a simple check for a valid batch.
func
TestBatchCheck
(
t
*
testing
.
T
)
{
cases
:=
[]
struct
{
name
string
bt
BatchTransaction
err
error
}{
{
name
:
"bad-input-count"
,
bt
:
BatchTransaction
{
Method
:
ContractMethod
{},
InputValues
:
map
[
string
]
string
{
"foo"
:
"bar"
,
},
},
err
:
errors
.
New
(
"expected 0 inputs but got 1"
),
},
{
name
:
"bad-calldata-too-small"
,
bt
:
BatchTransaction
{
Data
:
[]
byte
{
0x01
},
},
err
:
errors
.
New
(
"must have at least 4 bytes of calldata, got 1"
),
},
{
name
:
"bad-calldata-mismatch"
,
bt
:
BatchTransaction
{
Data
:
[]
byte
{
0x01
,
0x02
,
0x03
,
0x04
},
Method
:
ContractMethod
{
Name
:
"foo"
,
},
},
err
:
errors
.
New
(
"data does not match signature"
),
},
{
name
:
"good-calldata"
,
bt
:
BatchTransaction
{
Data
:
[]
byte
{
0xc2
,
0x98
,
0x55
,
0x78
},
Method
:
ContractMethod
{
Name
:
"foo"
,
},
},
err
:
nil
,
},
}
for
_
,
tc
:=
range
cases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
require
.
Equal
(
t
,
tc
.
err
,
tc
.
bt
.
Check
())
})
}
}
op-chain-ops/safe/testdata/deposit-tx.json
0 → 100644
View file @
b9dca1e6
{
"version"
:
""
,
"chainId"
:
""
,
"createdAt"
:
0
,
"meta"
:
{
"createdFromSafeAddress"
:
""
,
"createdFromOwnerAddress"
:
""
,
"name"
:
""
,
"description"
:
""
},
"transactions"
:
[
{
"to"
:
"0x0000000000000000000000000000000000000001"
,
"value"
:
"222"
,
"data"
:
"0xe9e05c42000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000"
,
"contractMethod"
:
{
"inputs"
:
[
{
"internalType"
:
"address"
,
"name"
:
"_to"
,
"type"
:
"address"
},
{
"internalType"
:
"uint256"
,
"name"
:
"_value"
,
"type"
:
"uint256"
},
{
"internalType"
:
"uint64"
,
"name"
:
"_gasLimit"
,
"type"
:
"uint64"
},
{
"internalType"
:
"bool"
,
"name"
:
"_isCreation"
,
"type"
:
"bool"
},
{
"internalType"
:
"bytes"
,
"name"
:
"_data"
,
"type"
:
"bytes"
}
],
"name"
:
"depositTransaction"
,
"payable"
:
false
},
"contractInputsValues"
:
{
"_data"
:
"0x"
,
"_gasLimit"
:
"100"
,
"_isCreation"
:
"false"
,
"_to"
:
"0x0100000000000000000000000000000000000000"
,
"_value"
:
"2"
}
}
]
}
op-chain-ops/safe/testdata/finalize-withdrawal-tx.json
0 → 100644
View file @
b9dca1e6
{
"version"
:
""
,
"chainId"
:
""
,
"createdAt"
:
0
,
"meta"
:
{
"createdFromSafeAddress"
:
""
,
"createdFromOwnerAddress"
:
""
,
"name"
:
""
,
"description"
:
""
},
"transactions"
:
[
{
"to"
:
"0x0000000000000000000000000000000000000001"
,
"value"
:
"222"
,
"data"
:
"0x8c3152e900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000"
,
"contractMethod"
:
{
"inputs"
:
[
{
"internalType"
:
"TypesWithdrawalTransaction"
,
"name"
:
"_tx"
,
"type"
:
"tuple"
,
"components"
:
[
{
"internalType"
:
"uint256"
,
"name"
:
"nonce"
,
"type"
:
"uint256"
},
{
"internalType"
:
"address"
,
"name"
:
"sender"
,
"type"
:
"address"
},
{
"internalType"
:
"address"
,
"name"
:
"target"
,
"type"
:
"address"
},
{
"internalType"
:
"uint256"
,
"name"
:
"value"
,
"type"
:
"uint256"
},
{
"internalType"
:
"uint256"
,
"name"
:
"gasLimit"
,
"type"
:
"uint256"
},
{
"internalType"
:
"bytes"
,
"name"
:
"data"
,
"type"
:
"bytes"
}
]
}
],
"name"
:
"finalizeWithdrawalTransaction"
,
"payable"
:
false
},
"contractInputsValues"
:
{
"_tx"
:
"[0,0x0000000000000000000000000000000000000001,0x0000000000000000000000000000000000000002,1,2,0x]"
}
}
]
}
op-chain-ops/safe/testdata/portal-abi.json
0 → 100644
View file @
b9dca1e6
This diff is collapsed.
Click to expand it.
op-challenger/fault/disk.go
View file @
b9dca1e6
package
fault
import
(
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/hashicorp/go-multierror"
"golang.org/x/exp/slices"
)
...
...
@@ -31,7 +31,7 @@ func (d *diskManager) RemoveAllExcept(keep []common.Address) error {
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to list directory: %w"
,
err
)
}
var
result
error
var
errs
[]
error
for
_
,
entry
:=
range
entries
{
if
!
entry
.
IsDir
()
||
!
strings
.
HasPrefix
(
entry
.
Name
(),
gameDirPrefix
)
{
// Skip files and directories that don't have the game directory prefix.
...
...
@@ -49,9 +49,7 @@ func (d *diskManager) RemoveAllExcept(keep []common.Address) error {
// Preserve data for games we should keep.
continue
}
if
err
:=
os
.
RemoveAll
(
filepath
.
Join
(
d
.
datadir
,
entry
.
Name
()));
err
!=
nil
{
result
=
multierror
.
Append
(
result
,
err
)
}
errs
=
append
(
errs
,
os
.
RemoveAll
(
filepath
.
Join
(
d
.
datadir
,
entry
.
Name
())))
}
return
result
return
errors
.
Join
(
errs
...
)
}
op-challenger/fault/monitor.go
View file @
b9dca1e6
...
...
@@ -87,11 +87,7 @@ func (m *gameMonitor) minGameTimestamp() uint64 {
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
)
}
func
(
m
*
gameMonitor
)
progressGames
(
ctx
context
.
Context
,
blockNum
uint64
)
error
{
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
)
...
...
@@ -147,13 +143,26 @@ func (m *gameMonitor) fetchOrCreateGamePlayer(gameData FaultDisputeGame) (gamePl
func
(
m
*
gameMonitor
)
MonitorGames
(
ctx
context
.
Context
)
error
{
m
.
logger
.
Info
(
"Monitoring fault dispute games"
)
blockNum
:=
uint64
(
0
)
for
{
err
:=
m
.
progressGames
(
ctx
)
if
err
!=
nil
{
m
.
logger
.
Error
(
"Failed to progress games"
,
"err"
,
err
)
}
if
err
:=
m
.
clock
.
SleepCtx
(
ctx
,
300
*
time
.
Millisecond
);
err
!=
nil
{
return
err
select
{
case
<-
ctx
.
Done
()
:
return
ctx
.
Err
()
default
:
nextBlockNum
,
err
:=
m
.
fetchBlockNumber
(
ctx
)
if
err
!=
nil
{
m
.
logger
.
Error
(
"Failed to load current block number"
,
"err"
,
err
)
continue
}
if
nextBlockNum
>
blockNum
{
blockNum
=
nextBlockNum
if
err
:=
m
.
progressGames
(
ctx
,
nextBlockNum
);
err
!=
nil
{
m
.
logger
.
Error
(
"Failed to progress games"
,
"err"
,
err
)
}
}
if
err
:=
m
.
clock
.
SleepCtx
(
ctx
,
time
.
Second
);
err
!=
nil
{
return
err
}
}
}
}
op-challenger/fault/monitor_test.go
View file @
b9dca1e6
...
...
@@ -65,8 +65,7 @@ func TestMonitorCreateAndProgressGameAgents(t *testing.T) {
},
}
err
:=
monitor
.
progressGames
(
context
.
Background
())
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
monitor
.
progressGames
(
context
.
Background
(),
uint64
(
1
)))
require
.
Len
(
t
,
games
.
created
,
2
,
"should create game agents"
)
require
.
Contains
(
t
,
games
.
created
,
addr1
)
...
...
@@ -75,7 +74,7 @@ func TestMonitorCreateAndProgressGameAgents(t *testing.T) {
require
.
Equal
(
t
,
1
,
games
.
created
[
addr2
]
.
progressCount
)
// The stub will fail the test if a game is created with the same address multiple times
require
.
NoError
(
t
,
monitor
.
progressGames
(
context
.
Background
()),
"should only create games once"
)
require
.
NoError
(
t
,
monitor
.
progressGames
(
context
.
Background
()
,
uint64
(
2
)
),
"should only create games once"
)
require
.
Equal
(
t
,
2
,
games
.
created
[
addr1
]
.
progressCount
)
require
.
Equal
(
t
,
2
,
games
.
created
[
addr2
]
.
progressCount
)
}
...
...
@@ -96,8 +95,7 @@ func TestMonitorOnlyCreateSpecifiedGame(t *testing.T) {
},
}
err
:=
monitor
.
progressGames
(
context
.
Background
())
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
monitor
.
progressGames
(
context
.
Background
(),
uint64
(
1
)))
require
.
Len
(
t
,
games
.
created
,
1
,
"should only create allowed game"
)
require
.
Contains
(
t
,
games
.
created
,
addr2
)
...
...
@@ -122,14 +120,14 @@ func TestDeletePlayersWhenNoLongerInListOfGames(t *testing.T) {
}
source
.
games
=
allGames
require
.
NoError
(
t
,
monitor
.
progressGames
(
context
.
Background
()))
require
.
NoError
(
t
,
monitor
.
progressGames
(
context
.
Background
()
,
uint64
(
1
)
))
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
.
NoError
(
t
,
monitor
.
progressGames
(
context
.
Background
()
,
uint64
(
2
)
))
require
.
Len
(
t
,
games
.
created
,
2
)
require
.
Contains
(
t
,
games
.
created
,
addr1
)
require
.
Contains
(
t
,
games
.
created
,
addr2
)
...
...
@@ -139,7 +137,7 @@ func TestDeletePlayersWhenNoLongerInListOfGames(t *testing.T) {
// First game now reappears (inexplicably but usefully for our testing)
source
.
games
=
allGames
require
.
NoError
(
t
,
monitor
.
progressGames
(
context
.
Background
()))
require
.
NoError
(
t
,
monitor
.
progressGames
(
context
.
Background
()
,
uint64
(
3
)
))
// A new player is created for it because the original was deleted
require
.
Len
(
t
,
games
.
created
,
2
)
require
.
Contains
(
t
,
games
.
created
,
addr1
)
...
...
@@ -165,7 +163,7 @@ func TestCleanupResourcesOfCompletedGames(t *testing.T) {
},
}
err
:=
monitor
.
progressGames
(
context
.
Background
())
err
:=
monitor
.
progressGames
(
context
.
Background
()
,
uint64
(
1
)
)
require
.
NoError
(
t
,
err
)
require
.
Len
(
t
,
games
.
created
,
2
,
"should create game agents"
)
...
...
@@ -187,8 +185,10 @@ func setupMonitorTest(t *testing.T, allowedGames []common.Address) (*gameMonitor
t
:
t
,
created
:
make
(
map
[
common
.
Address
]
*
stubGame
),
}
i
:=
uint64
(
1
)
fetchBlockNum
:=
func
(
ctx
context
.
Context
)
(
uint64
,
error
)
{
return
1234
,
nil
i
++
return
i
,
nil
}
disk
:=
&
stubDiskManager
{
gameDirExists
:
make
(
map
[
common
.
Address
]
bool
),
...
...
op-e2e/e2eutils/challenger/helper.go
View file @
b9dca1e6
...
...
@@ -5,6 +5,7 @@ import (
"crypto/ecdsa"
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"testing"
...
...
@@ -13,6 +14,7 @@ import (
op_challenger
"github.com/ethereum-optimism/optimism/op-challenger"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
...
...
@@ -24,6 +26,7 @@ import (
type
Helper
struct
{
log
log
.
Logger
t
*
testing
.
T
require
*
require
.
Assertions
dir
string
cancel
func
()
...
...
@@ -108,6 +111,7 @@ func NewChallenger(t *testing.T, ctx context.Context, l1Endpoint string, name st
}()
return
&
Helper
{
log
:
log
,
t
:
t
,
require
:
require
.
New
(
t
),
dir
:
cfg
.
Datadir
,
cancel
:
cancel
,
...
...
@@ -171,11 +175,27 @@ func (h *Helper) VerifyGameDataExists(games ...GameAddr) {
}
}
func
(
h
*
Helper
)
VerifyNoGameDataExists
(
games
...
GameAddr
)
{
for
_
,
game
:=
range
games
{
addr
:=
game
.
Addr
()
h
.
require
.
NoDirExistsf
(
h
.
gameDataDir
(
addr
),
"should have data for game %v"
,
addr
)
}
func
(
h
*
Helper
)
WaitForGameDataDeletion
(
ctx
context
.
Context
,
games
...
GameAddr
)
{
ctx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
30
*
time
.
Second
)
defer
cancel
()
err
:=
wait
.
For
(
ctx
,
time
.
Second
,
func
()
(
bool
,
error
)
{
for
_
,
game
:=
range
games
{
addr
:=
game
.
Addr
()
dir
:=
h
.
gameDataDir
(
addr
)
_
,
err
:=
os
.
Stat
(
dir
)
if
errors
.
Is
(
err
,
os
.
ErrNotExist
)
{
// This game has been successfully deleted
continue
}
if
err
!=
nil
{
return
false
,
fmt
.
Errorf
(
"failed to check dir %v is deleted: %w"
,
dir
,
err
)
}
h
.
t
.
Errorf
(
"Game data directory %v not yet deleted"
,
dir
)
return
false
,
nil
}
return
true
,
nil
})
h
.
require
.
NoErrorf
(
err
,
"should have deleted game data directories"
)
}
func
(
h
*
Helper
)
gameDataDir
(
addr
common
.
Address
)
string
{
...
...
op-e2e/faultproof_test.go
View file @
b9dca1e6
...
...
@@ -102,7 +102,7 @@ func TestMultipleCannonGames(t *testing.T) {
game2
.
WaitForGameStatus
(
ctx
,
disputegame
.
StatusChallengerWins
)
// Check that the game directories are removed
challenger
.
VerifyNoGameDataExists
(
game1
,
game2
)
challenger
.
WaitForGameDataDeletion
(
ctx
,
game1
,
game2
)
}
func
TestResolveDisputeGame
(
t
*
testing
.
T
)
{
...
...
packages/contracts-bedrock/deploy-config/getting-started.json
View file @
b9dca1e6
{
"numDeployConfirmations"
:
1
,
"finalSystemOwner"
:
"ADMIN"
,
"portalGuardian"
:
"ADMIN"
,
...
...
@@ -9,6 +7,7 @@
"l1ChainID"
:
5
,
"l2ChainID"
:
42069
,
"l2BlockTime"
:
2
,
"l1BlockTime"
:
12
,
"maxSequencerDrift"
:
600
,
"sequencerWindowSize"
:
3600
,
...
...
packages/contracts-bedrock/scripts/Deploy.s.sol
View file @
b9dca1e6
...
...
@@ -2,7 +2,7 @@
pragma solidity ^0.8.0;
import { Script } from "forge-std/Script.sol";
import { Test } from "forge-std/Test.sol";
import { console2 as console } from "forge-std/console2.sol";
import { stdJson } from "forge-std/StdJson.sol";
...
...
pnpm-lock.yaml
View file @
b9dca1e6
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