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
554b0da2
Unverified
Commit
554b0da2
authored
Jul 25, 2023
by
mergify[bot]
Committed by
GitHub
Jul 25, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into aj/op-geth-1.12.0
parents
9f68e371
2eb8cee5
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
907 additions
and
176 deletions
+907
-176
config.yml
.circleci/config.yml
+13
-0
Makefile
cannon/Makefile
+13
-1
evm_test.go
cannon/mipsevm/evm_test.go
+82
-99
fuzz_evm_test.go
cannon/mipsevm/fuzz_evm_test.go
+501
-0
mips.go
cannon/mipsevm/mips.go
+17
-7
types.go
op-bindings/solc/types.go
+16
-1
config.go
op-chain-ops/genesis/config.go
+16
-0
config_test.go
op-chain-ops/genesis/config_test.go
+16
-0
main_test.go
op-challenger/cmd/main_test.go
+105
-29
config.go
op-challenger/config/config.go
+32
-15
config_test.go
op-challenger/config/config_test.go
+45
-18
flags.go
op-challenger/flags/flags.go
+33
-3
l1_miner.go
op-e2e/actions/l1_miner.go
+1
-1
l2_proposer.go
op-e2e/actions/l2_proposer.go
+12
-2
setup.go
op-e2e/e2eutils/setup.go
+5
-0
No files found.
.circleci/config.yml
View file @
554b0da2
...
...
@@ -861,6 +861,18 @@ jobs:
command
:
make fuzz
working_directory
:
op-chain-ops
fuzz-cannon
:
docker
:
-
image
:
us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest
steps
:
-
checkout
-
check-changed
:
patterns
:
cannon,packages/contracts-bedrock/contracts/cannon
-
run
:
name
:
Fuzz
command
:
make fuzz
working_directory
:
cannon
depcheck
:
docker
:
-
image
:
us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest
...
...
@@ -1415,6 +1427,7 @@ workflows:
-
go-mod-tidy
-
fuzz-op-node
-
fuzz-op-chain-ops
-
fuzz-cannon
-
bedrock-markdown
-
go-lint
:
name
:
op-batcher-lint
...
...
cannon/Makefile
View file @
554b0da2
...
...
@@ -23,8 +23,20 @@ test: elf
lint
:
golangci-lint run
-E
goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint
--timeout
5m
-e
"errors.As"
-e
"errors.Is"
fuzz
:
go
test
-run
NOTAREALTEST
-v
-fuzztime
10s
-fuzz
=
FuzzStateSyscallBrk ./mipsevm
go
test
-run
NOTAREALTEST
-v
-fuzztime
10s
-fuzz
=
FuzzStateSyscallClone ./mipsevm
go
test
-run
NOTAREALTEST
-v
-fuzztime
10s
-fuzz
=
FuzzStateSyscallMmap ./mipsevm
go
test
-run
NOTAREALTEST
-v
-fuzztime
10s
-fuzz
=
FuzzStateSyscallExitGroup ./mipsevm
go
test
-run
NOTAREALTEST
-v
-fuzztime
10s
-fuzz
=
FuzzStateSyscallFnctl ./mipsevm
go
test
-run
NOTAREALTEST
-v
-fuzztime
10s
-fuzz
=
FuzzStateHintRead ./mipsevm
go
test
-run
NOTAREALTEST
-v
-fuzztime
20s
-fuzz
=
FuzzStatePreimageRead ./mipsevm
go
test
-run
NOTAREALTEST
-v
-fuzztime
10s
-fuzz
=
FuzzStateHintWrite ./mipsevm
go
test
-run
NOTAREALTEST
-v
-fuzztime
20s
-fuzz
=
FuzzStatePreimageWrite ./mipsevm
.PHONY
:
\
cannon
\
clean
\
test
\
lint
lint
\
fuzz
cannon/mipsevm/evm_test.go
View file @
554b0da2
...
...
@@ -13,6 +13,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
...
...
@@ -21,7 +22,7 @@ import (
"github.com/ethereum-optimism/optimism/op-chain-ops/srcmap"
)
func
testContractsSetup
(
t
*
testing
.
T
)
(
*
Contracts
,
*
Addresses
)
{
func
testContractsSetup
(
t
require
.
Testing
T
)
(
*
Contracts
,
*
Addresses
)
{
contracts
,
err
:=
LoadContracts
()
require
.
NoError
(
t
,
err
)
...
...
@@ -48,6 +49,53 @@ func MarkdownTracer() vm.EVMLogger {
return
logger
.
NewMarkdownLogger
(
&
logger
.
Config
{},
os
.
Stdout
)
}
type
MIPSEVM
struct
{
env
*
vm
.
EVM
evmState
*
state
.
StateDB
addrs
*
Addresses
}
func
NewMIPSEVM
(
contracts
*
Contracts
,
addrs
*
Addresses
)
*
MIPSEVM
{
env
,
evmState
:=
NewEVMEnv
(
contracts
,
addrs
)
return
&
MIPSEVM
{
env
,
evmState
,
addrs
}
}
func
(
m
*
MIPSEVM
)
SetTracer
(
tracer
vm
.
EVMLogger
)
{
m
.
env
.
Config
.
Tracer
=
tracer
}
// Step is a pure function that computes the poststate from the VM state encoded in the StepWitness.
func
(
m
*
MIPSEVM
)
Step
(
t
*
testing
.
T
,
stepWitness
*
StepWitness
)
[]
byte
{
sender
:=
common
.
Address
{
0x13
,
0x37
}
startingGas
:=
uint64
(
30
_000_000
)
// we take a snapshot so we can clean up the state, and isolate the logs of this instruction run.
snap
:=
m
.
env
.
StateDB
.
Snapshot
()
if
stepWitness
.
HasPreimage
()
{
t
.
Logf
(
"reading preimage key %x at offset %d"
,
stepWitness
.
PreimageKey
,
stepWitness
.
PreimageOffset
)
poInput
,
err
:=
stepWitness
.
EncodePreimageOracleInput
()
require
.
NoError
(
t
,
err
,
"encode preimage oracle input"
)
_
,
leftOverGas
,
err
:=
m
.
env
.
Call
(
vm
.
AccountRef
(
m
.
addrs
.
Sender
),
m
.
addrs
.
Oracle
,
poInput
,
startingGas
,
big
.
NewInt
(
0
))
require
.
NoErrorf
(
t
,
err
,
"evm should not fail, took %d gas"
,
startingGas
-
leftOverGas
)
}
input
:=
stepWitness
.
EncodeStepInput
()
ret
,
leftOverGas
,
err
:=
m
.
env
.
Call
(
vm
.
AccountRef
(
sender
),
m
.
addrs
.
MIPS
,
input
,
startingGas
,
big
.
NewInt
(
0
))
require
.
NoError
(
t
,
err
,
"evm should not fail"
)
require
.
Len
(
t
,
ret
,
32
,
"expecting 32-byte state hash"
)
// remember state hash, to check it against state
postHash
:=
common
.
Hash
(
*
(
*
[
32
]
byte
)(
ret
))
logs
:=
m
.
evmState
.
Logs
()
require
.
Equal
(
t
,
1
,
len
(
logs
),
"expecting a log with post-state"
)
evmPost
:=
logs
[
0
]
.
Data
require
.
Equal
(
t
,
crypto
.
Keccak256Hash
(
evmPost
),
postHash
,
"logged state must be accurate"
)
m
.
env
.
StateDB
.
RevertToSnapshot
(
snap
)
t
.
Logf
(
"EVM step took %d gas, and returned stateHash %s"
,
startingGas
-
leftOverGas
,
postHash
)
return
evmPost
}
func
TestEVM
(
t
*
testing
.
T
)
{
testFiles
,
err
:=
os
.
ReadDir
(
"open_mips_tests/test/bin"
)
require
.
NoError
(
t
,
err
)
...
...
@@ -55,7 +103,6 @@ func TestEVM(t *testing.T) {
contracts
,
addrs
:=
testContractsSetup
(
t
)
var
tracer
vm
.
EVMLogger
// no-tracer by default, but see SourceMapTracer and MarkdownTracer
//tracer = SourceMapTracer(t, contracts, addrs)
sender
:=
common
.
Address
{
0x13
,
0x37
}
for
_
,
f
:=
range
testFiles
{
t
.
Run
(
f
.
Name
(),
func
(
t
*
testing
.
T
)
{
...
...
@@ -66,8 +113,8 @@ func TestEVM(t *testing.T) {
// Short-circuit early for exit_group.bin
exitGroup
:=
f
.
Name
()
==
"exit_group.bin"
e
nv
,
evmState
:=
NewEVMEnv
(
contracts
,
addrs
)
e
nv
.
Config
.
Tracer
=
tracer
e
vm
:=
NewMIPSEVM
(
contracts
,
addrs
)
e
vm
.
SetTracer
(
tracer
)
fn
:=
path
.
Join
(
"open_mips_tests/test/bin"
,
f
.
Name
())
programMem
,
err
:=
os
.
ReadFile
(
fn
)
...
...
@@ -79,58 +126,31 @@ func TestEVM(t *testing.T) {
// set the return address ($ra) to jump into when test completes
state
.
Registers
[
31
]
=
endAddr
us
:=
NewInstrumentedState
(
state
,
oracle
,
os
.
Stdout
,
os
.
Stderr
)
goState
:=
NewInstrumentedState
(
state
,
oracle
,
os
.
Stdout
,
os
.
Stderr
)
for
i
:=
0
;
i
<
1000
;
i
++
{
if
us
.
state
.
PC
==
endAddr
{
if
goState
.
state
.
PC
==
endAddr
{
break
}
if
exitGroup
&&
us
.
state
.
Exited
{
if
exitGroup
&&
goState
.
state
.
Exited
{
break
}
insn
:=
state
.
Memory
.
GetMemory
(
state
.
PC
)
t
.
Logf
(
"step: %4d pc: 0x%08x insn: 0x%08x"
,
state
.
Step
,
state
.
PC
,
insn
)
stepWitness
,
err
:=
us
.
Step
(
true
)
stepWitness
,
err
:=
goState
.
Step
(
true
)
require
.
NoError
(
t
,
err
)
input
:=
stepWitness
.
EncodeStepInput
()
startingGas
:=
uint64
(
30
_000_000
)
// we take a snapshot so we can clean up the state, and isolate the logs of this instruction run.
snap
:=
env
.
StateDB
.
Snapshot
()
// prepare pre-image oracle data, if any
if
stepWitness
.
HasPreimage
()
{
t
.
Logf
(
"reading preimage key %x at offset %d"
,
stepWitness
.
PreimageKey
,
stepWitness
.
PreimageOffset
)
poInput
,
err
:=
stepWitness
.
EncodePreimageOracleInput
()
require
.
NoError
(
t
,
err
,
"encode preimage oracle input"
)
_
,
leftOverGas
,
err
:=
env
.
Call
(
vm
.
AccountRef
(
addrs
.
Sender
),
addrs
.
Oracle
,
poInput
,
startingGas
,
big
.
NewInt
(
0
))
require
.
NoErrorf
(
t
,
err
,
"evm should not fail, took %d gas"
,
startingGas
-
leftOverGas
)
}
ret
,
leftOverGas
,
err
:=
env
.
Call
(
vm
.
AccountRef
(
sender
),
addrs
.
MIPS
,
input
,
startingGas
,
big
.
NewInt
(
0
))
require
.
NoError
(
t
,
err
,
"evm should not fail"
)
require
.
Len
(
t
,
ret
,
32
,
"expecting 32-byte state hash"
)
// remember state hash, to check it against state
postHash
:=
common
.
Hash
(
*
(
*
[
32
]
byte
)(
ret
))
logs
:=
evmState
.
Logs
()
require
.
Equal
(
t
,
1
,
len
(
logs
),
"expecting a log with post-state"
)
evmPost
:=
logs
[
0
]
.
Data
require
.
Equal
(
t
,
crypto
.
Keccak256Hash
(
evmPost
),
postHash
,
"logged state must be accurate"
)
env
.
StateDB
.
RevertToSnapshot
(
snap
)
t
.
Logf
(
"EVM step took %d gas, and returned stateHash %s"
,
startingGas
-
leftOverGas
,
postHash
)
evmPost
:=
evm
.
Step
(
t
,
stepWitness
)
// verify the post-state matches.
// TODO: maybe more readable to decode the evmPost state, and do attribute-wise comparison.
uniPost
:=
us
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
uni
Post
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
goPost
:=
goState
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
go
Post
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
"mipsevm produced different state than EVM"
)
}
if
exitGroup
{
require
.
NotEqual
(
t
,
uint32
(
endAddr
),
us
.
state
.
PC
,
"must not reach end"
)
require
.
True
(
t
,
us
.
state
.
Exited
,
"must set exited state"
)
require
.
Equal
(
t
,
uint8
(
1
),
us
.
state
.
ExitCode
,
"must exit with 1"
)
require
.
NotEqual
(
t
,
uint32
(
endAddr
),
goState
.
state
.
PC
,
"must not reach end"
)
require
.
True
(
t
,
goState
.
state
.
Exited
,
"must set exited state"
)
require
.
Equal
(
t
,
uint8
(
1
),
goState
.
state
.
ExitCode
,
"must exit with 1"
)
}
else
{
require
.
Equal
(
t
,
uint32
(
endAddr
),
state
.
PC
,
"must reach end"
)
// inspect test result
...
...
@@ -160,8 +180,8 @@ func TestEVMFault(t *testing.T) {
// set the return address ($ra) to jump into when test completes
state
.
Registers
[
31
]
=
endAddr
us
:=
NewInstrumentedState
(
state
,
nil
,
os
.
Stdout
,
os
.
Stderr
)
require
.
Panics
(
t
,
func
()
{
_
,
_
=
us
.
Step
(
true
)
},
"must panic on illegal instruction"
)
goState
:=
NewInstrumentedState
(
state
,
nil
,
os
.
Stdout
,
os
.
Stderr
)
require
.
Panics
(
t
,
func
()
{
_
,
_
=
goState
.
Step
(
true
)
},
"must panic on illegal instruction"
)
insnProof
:=
initialState
.
Memory
.
MerkleProof
(
0
)
stepWitness
:=
&
StepWitness
{
...
...
@@ -181,7 +201,6 @@ func TestHelloEVM(t *testing.T) {
contracts
,
addrs
:=
testContractsSetup
(
t
)
var
tracer
vm
.
EVMLogger
// no-tracer by default, but see SourceMapTracer and MarkdownTracer
//tracer = SourceMapTracer(t, contracts, addrs)
sender
:=
common
.
Address
{
0x13
,
0x37
}
elfProgram
,
err
:=
elf
.
Open
(
"../example/bin/hello.elf"
)
require
.
NoError
(
t
,
err
,
"open ELF file"
)
...
...
@@ -194,14 +213,11 @@ func TestHelloEVM(t *testing.T) {
require
.
NoError
(
t
,
PatchStack
(
state
),
"add initial stack"
)
var
stdOutBuf
,
stdErrBuf
bytes
.
Buffer
us
:=
NewInstrumentedState
(
state
,
nil
,
io
.
MultiWriter
(
&
stdOutBuf
,
os
.
Stdout
),
io
.
MultiWriter
(
&
stdErrBuf
,
os
.
Stderr
))
env
,
evmState
:=
NewEVMEnv
(
contracts
,
addrs
)
env
.
Config
.
Tracer
=
tracer
goState
:=
NewInstrumentedState
(
state
,
nil
,
io
.
MultiWriter
(
&
stdOutBuf
,
os
.
Stdout
),
io
.
MultiWriter
(
&
stdErrBuf
,
os
.
Stderr
))
start
:=
time
.
Now
()
for
i
:=
0
;
i
<
400
_000
;
i
++
{
if
us
.
state
.
Exited
{
if
goState
.
state
.
Exited
{
break
}
insn
:=
state
.
Memory
.
GetMemory
(
state
.
PC
)
...
...
@@ -209,30 +225,16 @@ func TestHelloEVM(t *testing.T) {
t
.
Logf
(
"step: %4d pc: 0x%08x insn: 0x%08x"
,
state
.
Step
,
state
.
PC
,
insn
)
}
stepWitness
,
err
:=
us
.
Step
(
true
)
require
.
NoError
(
t
,
err
)
input
:=
stepWitness
.
EncodeStepInput
()
startingGas
:=
uint64
(
30
_000_000
)
// we take a snapshot so we can clean up the state, and isolate the logs of this instruction run.
snap
:=
env
.
StateDB
.
Snapshot
()
ret
,
leftOverGas
,
err
:=
env
.
Call
(
vm
.
AccountRef
(
sender
),
addrs
.
MIPS
,
input
,
startingGas
,
big
.
NewInt
(
0
))
require
.
NoErrorf
(
t
,
err
,
"evm should not fail, took %d gas"
,
startingGas
-
leftOverGas
)
require
.
Len
(
t
,
ret
,
32
,
"expecting 32-byte state hash"
)
// remember state hash, to check it against state
postHash
:=
common
.
Hash
(
*
(
*
[
32
]
byte
)(
ret
))
logs
:=
evmState
.
Logs
()
require
.
Equal
(
t
,
1
,
len
(
logs
),
"expecting a log with post-state"
)
evmPost
:=
logs
[
0
]
.
Data
require
.
Equal
(
t
,
crypto
.
Keccak256Hash
(
evmPost
),
postHash
,
"logged state must be accurate"
)
env
.
StateDB
.
RevertToSnapshot
(
snap
)
//t.Logf("EVM step took %d gas, and returned stateHash %s", startingGas-leftOverGas, postHash)
evm
:=
NewMIPSEVM
(
contracts
,
addrs
)
evm
.
SetTracer
(
tracer
)
stepWitness
,
err
:=
goState
.
Step
(
true
)
require
.
NoError
(
t
,
err
)
evmPost
:=
evm
.
Step
(
t
,
stepWitness
)
// verify the post-state matches.
// TODO: maybe more readable to decode the evmPost state, and do attribute-wise comparison.
uniPost
:=
us
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
uni
Post
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
goPost
:=
goState
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
go
Post
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
"mipsevm produced different state than EVM"
)
}
end
:=
time
.
Now
()
...
...
@@ -264,13 +266,10 @@ func TestClaimEVM(t *testing.T) {
oracle
,
expectedStdOut
,
expectedStdErr
:=
claimTestOracle
(
t
)
var
stdOutBuf
,
stdErrBuf
bytes
.
Buffer
us
:=
NewInstrumentedState
(
state
,
oracle
,
io
.
MultiWriter
(
&
stdOutBuf
,
os
.
Stdout
),
io
.
MultiWriter
(
&
stdErrBuf
,
os
.
Stderr
))
env
,
evmState
:=
NewEVMEnv
(
contracts
,
addrs
)
env
.
Config
.
Tracer
=
tracer
goState
:=
NewInstrumentedState
(
state
,
oracle
,
io
.
MultiWriter
(
&
stdOutBuf
,
os
.
Stdout
),
io
.
MultiWriter
(
&
stdErrBuf
,
os
.
Stderr
))
for
i
:=
0
;
i
<
2000
_000
;
i
++
{
if
us
.
state
.
Exited
{
if
goState
.
state
.
Exited
{
break
}
...
...
@@ -279,32 +278,16 @@ func TestClaimEVM(t *testing.T) {
t
.
Logf
(
"step: %4d pc: 0x%08x insn: 0x%08x"
,
state
.
Step
,
state
.
PC
,
insn
)
}
stepWitness
,
err
:=
us
.
Step
(
true
)
stepWitness
,
err
:=
goState
.
Step
(
true
)
require
.
NoError
(
t
,
err
)
input
:=
stepWitness
.
EncodeStepInput
()
startingGas
:=
uint64
(
30
_000_000
)
// we take a snapshot so we can clean up the state, and isolate the logs of this instruction run.
snap
:=
env
.
StateDB
.
Snapshot
()
// prepare pre-image oracle data, if any
if
stepWitness
.
HasPreimage
()
{
poInput
,
err
:=
stepWitness
.
EncodePreimageOracleInput
()
require
.
NoError
(
t
,
err
,
"encode preimage oracle input"
)
_
,
leftOverGas
,
err
:=
env
.
Call
(
vm
.
AccountRef
(
addrs
.
Sender
),
addrs
.
Oracle
,
poInput
,
startingGas
,
big
.
NewInt
(
0
))
require
.
NoErrorf
(
t
,
err
,
"evm should not fail, took %d gas"
,
startingGas
-
leftOverGas
)
}
ret
,
leftOverGas
,
err
:=
env
.
Call
(
vm
.
AccountRef
(
addrs
.
Sender
),
addrs
.
MIPS
,
input
,
startingGas
,
big
.
NewInt
(
0
))
require
.
NoErrorf
(
t
,
err
,
"evm should not fail, took %d gas"
,
startingGas
-
leftOverGas
)
require
.
Len
(
t
,
ret
,
32
,
"expecting 32-byte state hash"
)
// remember state hash, to check it against state
postHash
:=
common
.
Hash
(
*
(
*
[
32
]
byte
)(
ret
))
logs
:=
evmState
.
Logs
()
require
.
Equal
(
t
,
1
,
len
(
logs
),
"expecting a log with post-state"
)
evmPost
:=
logs
[
0
]
.
Data
require
.
Equal
(
t
,
crypto
.
Keccak256Hash
(
evmPost
),
postHash
,
"logged state must be accurate"
)
env
.
StateDB
.
RevertToSnapshot
(
snap
)
evm
:=
NewMIPSEVM
(
contracts
,
addrs
)
evm
.
SetTracer
(
tracer
)
evmPost
:=
evm
.
Step
(
t
,
stepWitness
)
goPost
:=
goState
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
goPost
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
"mipsevm produced different state than EVM"
)
}
require
.
True
(
t
,
state
.
Exited
,
"must complete program"
)
...
...
cannon/mipsevm/fuzz_evm_test.go
0 → 100644
View file @
554b0da2
package
mipsevm
import
(
"os"
"testing"
preimage
"github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
)
const
syscallInsn
=
uint32
(
0x00
_00_00_0c
)
func
FuzzStateSyscallBrk
(
f
*
testing
.
F
)
{
contracts
,
addrs
:=
testContractsSetup
(
f
)
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
pc
uint32
,
step
uint64
,
preimageOffset
uint32
)
{
pc
=
pc
&
0xFF
_FF_FF_FC
// align PC
nextPC
:=
pc
+
4
state
:=
&
State
{
PC
:
pc
,
NextPC
:
nextPC
,
LO
:
0
,
HI
:
0
,
Heap
:
0
,
ExitCode
:
0
,
Exited
:
false
,
Memory
:
NewMemory
(),
Registers
:
[
32
]
uint32
{
2
:
sysBrk
},
Step
:
step
,
PreimageKey
:
common
.
Hash
{},
PreimageOffset
:
preimageOffset
,
}
state
.
Memory
.
SetMemory
(
pc
,
syscallInsn
)
preStateRoot
:=
state
.
Memory
.
MerkleRoot
()
expectedRegisters
:=
state
.
Registers
expectedRegisters
[
2
]
=
0x4000
_0000
goState
:=
NewInstrumentedState
(
state
,
nil
,
os
.
Stdout
,
os
.
Stderr
)
stepWitness
,
err
:=
goState
.
Step
(
true
)
require
.
NoError
(
t
,
err
)
require
.
False
(
t
,
stepWitness
.
HasPreimage
())
require
.
Equal
(
t
,
pc
+
4
,
state
.
PC
)
require
.
Equal
(
t
,
nextPC
+
4
,
state
.
NextPC
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
LO
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
HI
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
Heap
)
require
.
Equal
(
t
,
uint8
(
0
),
state
.
ExitCode
)
require
.
Equal
(
t
,
false
,
state
.
Exited
)
require
.
Equal
(
t
,
preStateRoot
,
state
.
Memory
.
MerkleRoot
())
require
.
Equal
(
t
,
expectedRegisters
,
state
.
Registers
)
require
.
Equal
(
t
,
step
+
1
,
state
.
Step
)
require
.
Equal
(
t
,
common
.
Hash
{},
state
.
PreimageKey
)
require
.
Equal
(
t
,
preimageOffset
,
state
.
PreimageOffset
)
evm
:=
NewMIPSEVM
(
contracts
,
addrs
)
evmPost
:=
evm
.
Step
(
t
,
stepWitness
)
goPost
:=
goState
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
goPost
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
"mipsevm produced different state than EVM"
)
})
}
func
FuzzStateSyscallClone
(
f
*
testing
.
F
)
{
contracts
,
addrs
:=
testContractsSetup
(
f
)
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
pc
uint32
,
step
uint64
,
preimageOffset
uint32
)
{
pc
=
pc
&
0xFF
_FF_FF_FC
// align PC
nextPC
:=
pc
+
4
state
:=
&
State
{
PC
:
pc
,
NextPC
:
nextPC
,
LO
:
0
,
HI
:
0
,
Heap
:
0
,
ExitCode
:
0
,
Exited
:
false
,
Memory
:
NewMemory
(),
Registers
:
[
32
]
uint32
{
2
:
sysClone
},
Step
:
step
,
PreimageOffset
:
preimageOffset
,
}
state
.
Memory
.
SetMemory
(
pc
,
syscallInsn
)
preStateRoot
:=
state
.
Memory
.
MerkleRoot
()
expectedRegisters
:=
state
.
Registers
expectedRegisters
[
2
]
=
0x1
goState
:=
NewInstrumentedState
(
state
,
nil
,
os
.
Stdout
,
os
.
Stderr
)
stepWitness
,
err
:=
goState
.
Step
(
true
)
require
.
NoError
(
t
,
err
)
require
.
False
(
t
,
stepWitness
.
HasPreimage
())
require
.
Equal
(
t
,
pc
+
4
,
state
.
PC
)
require
.
Equal
(
t
,
nextPC
+
4
,
state
.
NextPC
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
LO
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
HI
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
Heap
)
require
.
Equal
(
t
,
uint8
(
0
),
state
.
ExitCode
)
require
.
Equal
(
t
,
false
,
state
.
Exited
)
require
.
Equal
(
t
,
preStateRoot
,
state
.
Memory
.
MerkleRoot
())
require
.
Equal
(
t
,
expectedRegisters
,
state
.
Registers
)
require
.
Equal
(
t
,
step
+
1
,
state
.
Step
)
require
.
Equal
(
t
,
common
.
Hash
{},
state
.
PreimageKey
)
require
.
Equal
(
t
,
preimageOffset
,
state
.
PreimageOffset
)
evm
:=
NewMIPSEVM
(
contracts
,
addrs
)
evmPost
:=
evm
.
Step
(
t
,
stepWitness
)
goPost
:=
goState
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
goPost
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
"mipsevm produced different state than EVM"
)
})
}
func
FuzzStateSyscallMmap
(
f
*
testing
.
F
)
{
contracts
,
addrs
:=
testContractsSetup
(
f
)
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
addr
uint32
,
siz
uint32
,
heap
uint32
)
{
state
:=
&
State
{
PC
:
0
,
NextPC
:
4
,
LO
:
0
,
HI
:
0
,
Heap
:
heap
,
ExitCode
:
0
,
Exited
:
false
,
Memory
:
NewMemory
(),
Registers
:
[
32
]
uint32
{
2
:
sysMmap
,
4
:
addr
,
5
:
siz
},
Step
:
0
,
PreimageOffset
:
0
,
}
state
.
Memory
.
SetMemory
(
0
,
syscallInsn
)
preStateRoot
:=
state
.
Memory
.
MerkleRoot
()
preStateRegisters
:=
state
.
Registers
goState
:=
NewInstrumentedState
(
state
,
nil
,
os
.
Stdout
,
os
.
Stderr
)
stepWitness
,
err
:=
goState
.
Step
(
true
)
require
.
NoError
(
t
,
err
)
require
.
False
(
t
,
stepWitness
.
HasPreimage
())
require
.
Equal
(
t
,
uint32
(
4
),
state
.
PC
)
require
.
Equal
(
t
,
uint32
(
8
),
state
.
NextPC
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
LO
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
HI
)
require
.
Equal
(
t
,
uint8
(
0
),
state
.
ExitCode
)
require
.
Equal
(
t
,
false
,
state
.
Exited
)
require
.
Equal
(
t
,
preStateRoot
,
state
.
Memory
.
MerkleRoot
())
require
.
Equal
(
t
,
uint64
(
1
),
state
.
Step
)
require
.
Equal
(
t
,
common
.
Hash
{},
state
.
PreimageKey
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
PreimageOffset
)
if
addr
==
0
{
expectedRegisters
:=
preStateRegisters
expectedRegisters
[
2
]
=
heap
require
.
Equal
(
t
,
expectedRegisters
,
state
.
Registers
)
sizAlign
:=
siz
if
sizAlign
&
PageAddrMask
!=
0
{
// adjust size to align with page size
sizAlign
=
siz
+
PageSize
-
(
siz
&
PageAddrMask
)
}
require
.
Equal
(
t
,
uint32
(
heap
+
sizAlign
),
state
.
Heap
)
}
else
{
expectedRegisters
:=
preStateRegisters
expectedRegisters
[
2
]
=
addr
require
.
Equal
(
t
,
expectedRegisters
,
state
.
Registers
)
require
.
Equal
(
t
,
uint32
(
heap
),
state
.
Heap
)
}
evm
:=
NewMIPSEVM
(
contracts
,
addrs
)
evmPost
:=
evm
.
Step
(
t
,
stepWitness
)
goPost
:=
goState
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
goPost
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
"mipsevm produced different state than EVM"
)
})
}
func
FuzzStateSyscallExitGroup
(
f
*
testing
.
F
)
{
contracts
,
addrs
:=
testContractsSetup
(
f
)
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
exitCode
uint8
,
pc
uint32
,
step
uint64
)
{
pc
=
pc
&
0xFF
_FF_FF_FC
// align PC
nextPC
:=
pc
+
4
state
:=
&
State
{
PC
:
pc
,
NextPC
:
nextPC
,
LO
:
0
,
HI
:
0
,
Heap
:
0
,
ExitCode
:
0
,
Exited
:
false
,
Memory
:
NewMemory
(),
Registers
:
[
32
]
uint32
{
2
:
sysExitGroup
,
4
:
uint32
(
exitCode
)},
Step
:
step
,
PreimageOffset
:
0
,
}
state
.
Memory
.
SetMemory
(
pc
,
syscallInsn
)
preStateRoot
:=
state
.
Memory
.
MerkleRoot
()
preStateRegisters
:=
state
.
Registers
goState
:=
NewInstrumentedState
(
state
,
nil
,
os
.
Stdout
,
os
.
Stderr
)
stepWitness
,
err
:=
goState
.
Step
(
true
)
require
.
NoError
(
t
,
err
)
require
.
False
(
t
,
stepWitness
.
HasPreimage
())
require
.
Equal
(
t
,
pc
,
state
.
PC
)
require
.
Equal
(
t
,
nextPC
,
state
.
NextPC
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
LO
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
HI
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
Heap
)
require
.
Equal
(
t
,
uint8
(
exitCode
),
state
.
ExitCode
)
require
.
Equal
(
t
,
true
,
state
.
Exited
)
require
.
Equal
(
t
,
preStateRoot
,
state
.
Memory
.
MerkleRoot
())
require
.
Equal
(
t
,
preStateRegisters
,
state
.
Registers
)
require
.
Equal
(
t
,
step
+
1
,
state
.
Step
)
require
.
Equal
(
t
,
common
.
Hash
{},
state
.
PreimageKey
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
PreimageOffset
)
evm
:=
NewMIPSEVM
(
contracts
,
addrs
)
evmPost
:=
evm
.
Step
(
t
,
stepWitness
)
goPost
:=
goState
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
goPost
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
"mipsevm produced different state than EVM"
)
})
}
func
FuzzStateSyscallFnctl
(
f
*
testing
.
F
)
{
contracts
,
addrs
:=
testContractsSetup
(
f
)
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
fd
uint32
,
cmd
uint32
)
{
state
:=
&
State
{
PC
:
0
,
NextPC
:
4
,
LO
:
0
,
HI
:
0
,
Heap
:
0
,
ExitCode
:
0
,
Exited
:
false
,
Memory
:
NewMemory
(),
Registers
:
[
32
]
uint32
{
2
:
sysFcntl
,
4
:
fd
,
5
:
cmd
},
Step
:
0
,
PreimageOffset
:
0
,
}
state
.
Memory
.
SetMemory
(
0
,
syscallInsn
)
preStateRoot
:=
state
.
Memory
.
MerkleRoot
()
preStateRegisters
:=
state
.
Registers
goState
:=
NewInstrumentedState
(
state
,
nil
,
os
.
Stdout
,
os
.
Stderr
)
stepWitness
,
err
:=
goState
.
Step
(
true
)
require
.
NoError
(
t
,
err
)
require
.
False
(
t
,
stepWitness
.
HasPreimage
())
require
.
Equal
(
t
,
uint32
(
4
),
state
.
PC
)
require
.
Equal
(
t
,
uint32
(
8
),
state
.
NextPC
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
LO
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
HI
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
Heap
)
require
.
Equal
(
t
,
uint8
(
0
),
state
.
ExitCode
)
require
.
Equal
(
t
,
false
,
state
.
Exited
)
require
.
Equal
(
t
,
preStateRoot
,
state
.
Memory
.
MerkleRoot
())
require
.
Equal
(
t
,
uint64
(
1
),
state
.
Step
)
require
.
Equal
(
t
,
common
.
Hash
{},
state
.
PreimageKey
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
PreimageOffset
)
if
cmd
==
3
{
expectedRegisters
:=
preStateRegisters
switch
fd
{
case
fdStdin
,
fdPreimageRead
,
fdHintRead
:
expectedRegisters
[
2
]
=
0
case
fdStdout
,
fdStderr
,
fdPreimageWrite
,
fdHintWrite
:
expectedRegisters
[
2
]
=
1
default
:
expectedRegisters
[
2
]
=
0xFF
_FF_FF_FF
expectedRegisters
[
7
]
=
MipsEBADF
}
require
.
Equal
(
t
,
expectedRegisters
,
state
.
Registers
)
}
else
{
expectedRegisters
:=
preStateRegisters
expectedRegisters
[
2
]
=
0xFF
_FF_FF_FF
expectedRegisters
[
7
]
=
MipsEINVAL
require
.
Equal
(
t
,
expectedRegisters
,
state
.
Registers
)
}
evm
:=
NewMIPSEVM
(
contracts
,
addrs
)
evmPost
:=
evm
.
Step
(
t
,
stepWitness
)
goPost
:=
goState
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
goPost
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
"mipsevm produced different state than EVM"
)
})
}
func
FuzzStateHintRead
(
f
*
testing
.
F
)
{
contracts
,
addrs
:=
testContractsSetup
(
f
)
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
addr
uint32
,
count
uint32
)
{
preimageData
:=
[]
byte
(
"hello world"
)
state
:=
&
State
{
PC
:
0
,
NextPC
:
4
,
LO
:
0
,
HI
:
0
,
Heap
:
0
,
ExitCode
:
0
,
Exited
:
false
,
Memory
:
NewMemory
(),
Registers
:
[
32
]
uint32
{
2
:
sysRead
,
4
:
fdHintRead
,
5
:
addr
,
6
:
count
},
Step
:
0
,
PreimageKey
:
preimage
.
Keccak256Key
(
crypto
.
Keccak256Hash
(
preimageData
))
.
PreimageKey
(),
PreimageOffset
:
0
,
}
state
.
Memory
.
SetMemory
(
0
,
syscallInsn
)
preStatePreimageKey
:=
state
.
PreimageKey
preStateRoot
:=
state
.
Memory
.
MerkleRoot
()
expectedRegisters
:=
state
.
Registers
expectedRegisters
[
2
]
=
count
oracle
:=
staticOracle
(
t
,
preimageData
)
// only used for hinting
goState
:=
NewInstrumentedState
(
state
,
oracle
,
os
.
Stdout
,
os
.
Stderr
)
stepWitness
,
err
:=
goState
.
Step
(
true
)
require
.
NoError
(
t
,
err
)
require
.
False
(
t
,
stepWitness
.
HasPreimage
())
require
.
Equal
(
t
,
uint32
(
4
),
state
.
PC
)
require
.
Equal
(
t
,
uint32
(
8
),
state
.
NextPC
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
LO
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
HI
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
Heap
)
require
.
Equal
(
t
,
uint8
(
0
),
state
.
ExitCode
)
require
.
Equal
(
t
,
false
,
state
.
Exited
)
require
.
Equal
(
t
,
preStateRoot
,
state
.
Memory
.
MerkleRoot
())
require
.
Equal
(
t
,
uint64
(
1
),
state
.
Step
)
require
.
Equal
(
t
,
preStatePreimageKey
,
state
.
PreimageKey
)
evm
:=
NewMIPSEVM
(
contracts
,
addrs
)
evmPost
:=
evm
.
Step
(
t
,
stepWitness
)
goPost
:=
goState
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
goPost
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
"mipsevm produced different state than EVM"
)
})
}
func
FuzzStatePreimageRead
(
f
*
testing
.
F
)
{
contracts
,
addrs
:=
testContractsSetup
(
f
)
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
addr
uint32
,
count
uint32
,
preimageOffset
uint32
)
{
preimageData
:=
[]
byte
(
"hello world"
)
if
preimageOffset
>=
uint32
(
len
(
preimageData
))
{
t
.
SkipNow
()
}
state
:=
&
State
{
PC
:
0
,
NextPC
:
4
,
LO
:
0
,
HI
:
0
,
Heap
:
0
,
ExitCode
:
0
,
Exited
:
false
,
Memory
:
NewMemory
(),
Registers
:
[
32
]
uint32
{
2
:
sysRead
,
4
:
fdPreimageRead
,
5
:
addr
,
6
:
count
},
Step
:
0
,
PreimageKey
:
preimage
.
Keccak256Key
(
crypto
.
Keccak256Hash
(
preimageData
))
.
PreimageKey
(),
PreimageOffset
:
preimageOffset
,
}
state
.
Memory
.
SetMemory
(
0
,
syscallInsn
)
preStatePreimageKey
:=
state
.
PreimageKey
preStateRoot
:=
state
.
Memory
.
MerkleRoot
()
writeLen
:=
count
if
writeLen
>
4
{
writeLen
=
4
}
if
preimageOffset
+
writeLen
>
uint32
(
8
+
len
(
preimageData
))
{
writeLen
=
uint32
(
8
+
len
(
preimageData
))
-
preimageOffset
}
oracle
:=
staticOracle
(
t
,
preimageData
)
goState
:=
NewInstrumentedState
(
state
,
oracle
,
os
.
Stdout
,
os
.
Stderr
)
stepWitness
,
err
:=
goState
.
Step
(
true
)
require
.
NoError
(
t
,
err
)
require
.
True
(
t
,
stepWitness
.
HasPreimage
())
require
.
Equal
(
t
,
uint32
(
4
),
state
.
PC
)
require
.
Equal
(
t
,
uint32
(
8
),
state
.
NextPC
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
LO
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
HI
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
Heap
)
require
.
Equal
(
t
,
uint8
(
0
),
state
.
ExitCode
)
require
.
Equal
(
t
,
false
,
state
.
Exited
)
if
writeLen
>
0
{
// Memory may be unchanged if we're writing the first zero-valued 7 bytes of the pre-image.
//require.NotEqual(t, preStateRoot, state.Memory.MerkleRoot())
require
.
Greater
(
t
,
state
.
PreimageOffset
,
preimageOffset
)
}
else
{
require
.
Equal
(
t
,
preStateRoot
,
state
.
Memory
.
MerkleRoot
())
require
.
Equal
(
t
,
state
.
PreimageOffset
,
preimageOffset
)
}
require
.
Equal
(
t
,
uint64
(
1
),
state
.
Step
)
require
.
Equal
(
t
,
preStatePreimageKey
,
state
.
PreimageKey
)
evm
:=
NewMIPSEVM
(
contracts
,
addrs
)
evmPost
:=
evm
.
Step
(
t
,
stepWitness
)
goPost
:=
goState
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
goPost
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
"mipsevm produced different state than EVM"
)
})
}
func
FuzzStateHintWrite
(
f
*
testing
.
F
)
{
contracts
,
addrs
:=
testContractsSetup
(
f
)
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
addr
uint32
,
count
uint32
)
{
preimageData
:=
[]
byte
(
"hello world"
)
state
:=
&
State
{
PC
:
0
,
NextPC
:
4
,
LO
:
0
,
HI
:
0
,
Heap
:
0
,
ExitCode
:
0
,
Exited
:
false
,
Memory
:
NewMemory
(),
Registers
:
[
32
]
uint32
{
2
:
sysWrite
,
4
:
fdHintWrite
,
5
:
addr
,
6
:
count
},
Step
:
0
,
PreimageKey
:
preimage
.
Keccak256Key
(
crypto
.
Keccak256Hash
(
preimageData
))
.
PreimageKey
(),
PreimageOffset
:
0
,
// This is only used by mips.go. The reads a zeroed page-sized buffer when reading hint data from memory.
// We pre-allocate a buffer for the read hint data to be copied into.
LastHint
:
make
(
hexutil
.
Bytes
,
PageSize
),
}
state
.
Memory
.
SetMemory
(
0
,
syscallInsn
)
preStatePreimageKey
:=
state
.
PreimageKey
preStateRoot
:=
state
.
Memory
.
MerkleRoot
()
expectedRegisters
:=
state
.
Registers
expectedRegisters
[
2
]
=
count
oracle
:=
staticOracle
(
t
,
preimageData
)
// only used for hinting
goState
:=
NewInstrumentedState
(
state
,
oracle
,
os
.
Stdout
,
os
.
Stderr
)
stepWitness
,
err
:=
goState
.
Step
(
true
)
require
.
NoError
(
t
,
err
)
require
.
False
(
t
,
stepWitness
.
HasPreimage
())
require
.
Equal
(
t
,
uint32
(
4
),
state
.
PC
)
require
.
Equal
(
t
,
uint32
(
8
),
state
.
NextPC
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
LO
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
HI
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
Heap
)
require
.
Equal
(
t
,
uint8
(
0
),
state
.
ExitCode
)
require
.
Equal
(
t
,
false
,
state
.
Exited
)
require
.
Equal
(
t
,
preStateRoot
,
state
.
Memory
.
MerkleRoot
())
require
.
Equal
(
t
,
uint64
(
1
),
state
.
Step
)
require
.
Equal
(
t
,
preStatePreimageKey
,
state
.
PreimageKey
)
evm
:=
NewMIPSEVM
(
contracts
,
addrs
)
evmPost
:=
evm
.
Step
(
t
,
stepWitness
)
goPost
:=
goState
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
goPost
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
"mipsevm produced different state than EVM"
)
})
}
func
FuzzStatePreimageWrite
(
f
*
testing
.
F
)
{
contracts
,
addrs
:=
testContractsSetup
(
f
)
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
addr
uint32
,
count
uint32
)
{
preimageData
:=
[]
byte
(
"hello world"
)
state
:=
&
State
{
PC
:
0
,
NextPC
:
4
,
LO
:
0
,
HI
:
0
,
Heap
:
0
,
ExitCode
:
0
,
Exited
:
false
,
Memory
:
NewMemory
(),
Registers
:
[
32
]
uint32
{
2
:
sysWrite
,
4
:
fdPreimageWrite
,
5
:
addr
,
6
:
count
},
Step
:
0
,
PreimageKey
:
preimage
.
Keccak256Key
(
crypto
.
Keccak256Hash
(
preimageData
))
.
PreimageKey
(),
PreimageOffset
:
128
,
}
state
.
Memory
.
SetMemory
(
0
,
syscallInsn
)
preStateRoot
:=
state
.
Memory
.
MerkleRoot
()
expectedRegisters
:=
state
.
Registers
sz
:=
4
-
(
addr
&
0x3
)
if
sz
<
count
{
sz
=
count
}
expectedRegisters
[
2
]
=
sz
oracle
:=
staticOracle
(
t
,
preimageData
)
goState
:=
NewInstrumentedState
(
state
,
oracle
,
os
.
Stdout
,
os
.
Stderr
)
stepWitness
,
err
:=
goState
.
Step
(
true
)
require
.
NoError
(
t
,
err
)
require
.
False
(
t
,
stepWitness
.
HasPreimage
())
require
.
Equal
(
t
,
uint32
(
4
),
state
.
PC
)
require
.
Equal
(
t
,
uint32
(
8
),
state
.
NextPC
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
LO
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
HI
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
Heap
)
require
.
Equal
(
t
,
uint8
(
0
),
state
.
ExitCode
)
require
.
Equal
(
t
,
false
,
state
.
Exited
)
require
.
Equal
(
t
,
preStateRoot
,
state
.
Memory
.
MerkleRoot
())
require
.
Equal
(
t
,
uint64
(
1
),
state
.
Step
)
require
.
Equal
(
t
,
uint32
(
0
),
state
.
PreimageOffset
)
evm
:=
NewMIPSEVM
(
contracts
,
addrs
)
evmPost
:=
evm
.
Step
(
t
,
stepWitness
)
goPost
:=
goState
.
state
.
EncodeWitness
()
require
.
Equal
(
t
,
hexutil
.
Bytes
(
goPost
)
.
String
(),
hexutil
.
Bytes
(
evmPost
)
.
String
(),
"mipsevm produced different state than EVM"
)
})
}
cannon/mipsevm/mips.go
View file @
554b0da2
...
...
@@ -6,6 +6,16 @@ import (
"io"
)
const
(
sysMmap
=
4090
sysBrk
=
4045
sysClone
=
4120
sysExitGroup
=
4246
sysRead
=
4003
sysWrite
=
4004
sysFcntl
=
4055
)
func
(
m
*
InstrumentedState
)
readPreimage
(
key
[
32
]
byte
,
offset
uint32
)
(
dat
[
32
]
byte
,
datLen
uint32
)
{
preimage
:=
m
.
lastPreimage
if
key
!=
m
.
lastPreimageKey
{
...
...
@@ -43,7 +53,7 @@ func (m *InstrumentedState) handleSyscall() error {
//fmt.Printf("syscall: %d\n", syscallNum)
switch
syscallNum
{
case
4090
:
// mmap
case
sysMmap
:
sz
:=
a1
if
sz
&
PageAddrMask
!=
0
{
// adjust size to align with page size
sz
+=
PageSize
-
(
sz
&
PageAddrMask
)
...
...
@@ -56,15 +66,15 @@ func (m *InstrumentedState) handleSyscall() error {
v0
=
a0
//fmt.Printf("mmap hint 0x%x size 0x%x\n", v0, sz)
}
case
4045
:
// brk
case
sysBrk
:
v0
=
0x40000000
case
4120
:
// clone (not supported)
case
sysClone
:
// clone (not supported)
v0
=
1
case
4246
:
// exit_group
case
sysExitGroup
:
m
.
state
.
Exited
=
true
m
.
state
.
ExitCode
=
uint8
(
a0
)
return
nil
case
4003
:
// read
case
sysRead
:
// args: a0 = fd, a1 = addr, a2 = count
// returns: v0 = read, v1 = err code
switch
a0
{
...
...
@@ -98,7 +108,7 @@ func (m *InstrumentedState) handleSyscall() error {
v0
=
0xFFffFFff
v1
=
MipsEBADF
}
case
4004
:
// write
case
sysWrite
:
// args: a0 = fd, a1 = addr, a2 = count
// returns: v0 = written, v1 = err code
switch
a0
{
...
...
@@ -144,7 +154,7 @@ func (m *InstrumentedState) handleSyscall() error {
v0
=
0xFFffFFff
v1
=
MipsEBADF
}
case
4055
:
// fcntl
case
sysFcntl
:
// args: a0 = fd, a1 = cmd
if
a1
==
3
{
// F_GETFL: get file descriptor flags
switch
a0
{
...
...
op-bindings/solc/types.go
View file @
554b0da2
...
...
@@ -2,6 +2,7 @@ package solc
import
(
"encoding/json"
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi"
)
...
...
@@ -36,7 +37,8 @@ type CompilerOutput struct {
type
CompilerOutputContracts
map
[
string
]
CompilerOutputContract
// TODO(tynes): ignoring devdoc and userdoc for now
// CompilerOutputContract represents the solc compiler output for a contract.
// Ignoring some fields such as devdoc and userdoc.
type
CompilerOutputContract
struct
{
Abi
abi
.
ABI
`json:"abi"`
Evm
CompilerOutputEvm
`json:"evm"`
...
...
@@ -44,11 +46,24 @@ type CompilerOutputContract struct {
StorageLayout
StorageLayout
`json:"storageLayout"`
}
// StorageLayout represents the solc compilers output storage layout for
// a contract.
type
StorageLayout
struct
{
Storage
[]
StorageLayoutEntry
`json:"storage"`
Types
map
[
string
]
StorageLayoutType
`json:"types"`
}
// GetStorageLayoutEntry returns the StorageLayoutEntry where the label matches
// the provided name.
func
(
s
*
StorageLayout
)
GetStorageLayoutEntry
(
name
string
)
(
StorageLayoutEntry
,
error
)
{
for
_
,
entry
:=
range
s
.
Storage
{
if
entry
.
Label
==
name
{
return
entry
,
nil
}
}
return
StorageLayoutEntry
{},
fmt
.
Errorf
(
"%s not found"
,
name
)
}
type
StorageLayoutEntry
struct
{
AstId
uint
`json:"astId"`
Contract
string
`json:"contract"`
...
...
op-chain-ops/genesis/config.go
View file @
554b0da2
...
...
@@ -169,6 +169,22 @@ type DeployConfig struct {
FundDevAccounts
bool
`json:"fundDevAccounts"`
}
// Copy will deeply copy the DeployConfig. This does a JSON roundtrip to copy
// which makes it easier to maintain, we do not need efficiency in this case.
func
(
d
*
DeployConfig
)
Copy
()
*
DeployConfig
{
raw
,
err
:=
json
.
Marshal
(
d
)
if
err
!=
nil
{
panic
(
err
)
}
cpy
:=
DeployConfig
{}
if
err
=
json
.
Unmarshal
(
raw
,
&
cpy
);
err
!=
nil
{
panic
(
err
)
}
return
&
cpy
}
// Check will ensure that the config is sane and return an error when it is not
func
(
d
*
DeployConfig
)
Check
()
error
{
if
d
.
L1StartingBlockTag
==
nil
{
...
...
op-chain-ops/genesis/config_test.go
View file @
554b0da2
...
...
@@ -48,3 +48,19 @@ func TestRegolithTimeAsOffset(t *testing.T) {
config
:=
&
DeployConfig
{
L2GenesisRegolithTimeOffset
:
&
regolithOffset
}
require
.
Equal
(
t
,
uint64
(
1500
+
5000
),
*
config
.
RegolithTime
(
5000
))
}
// TestCopy will copy a DeployConfig and ensure that the copy is equal to the original.
func
TestCopy
(
t
*
testing
.
T
)
{
b
,
err
:=
os
.
ReadFile
(
"testdata/test-deploy-config-full.json"
)
require
.
NoError
(
t
,
err
)
decoded
:=
new
(
DeployConfig
)
require
.
NoError
(
t
,
json
.
NewDecoder
(
bytes
.
NewReader
(
b
))
.
Decode
(
decoded
))
cpy
:=
decoded
.
Copy
()
require
.
EqualValues
(
t
,
decoded
,
cpy
)
offset
:=
hexutil
.
Uint64
(
100
)
cpy
.
L2GenesisRegolithTimeOffset
=
&
offset
require
.
NotEqual
(
t
,
decoded
,
cpy
)
}
op-challenger/cmd/main_test.go
View file @
554b0da2
...
...
@@ -15,7 +15,10 @@ import (
var
(
l1EthRpc
=
"http://example.com:8545"
gameAddressValue
=
"0xaa00000000000000000000000000000000000000"
cannonBin
=
"./bin/cannon"
cannonPreState
=
"./pre.json"
cannonDatadir
=
"./test_data"
cannonL2
=
"http://example.com:9545"
alphabetTrace
=
"abcdefghijz"
agreeWithProposedOutput
=
"true"
gameDepth
=
"4"
...
...
@@ -23,13 +26,13 @@ var (
func
TestLogLevel
(
t
*
testing
.
T
)
{
t
.
Run
(
"RejectInvalid"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"unknown level: foo"
,
addRequiredArgs
(
"--log.level=foo"
))
verifyArgsInvalid
(
t
,
"unknown level: foo"
,
addRequiredArgs
(
config
.
TraceTypeAlphabet
,
"--log.level=foo"
))
})
for
_
,
lvl
:=
range
[]
string
{
"trace"
,
"debug"
,
"info"
,
"error"
,
"crit"
}
{
lvl
:=
lvl
t
.
Run
(
"AcceptValid_"
+
lvl
,
func
(
t
*
testing
.
T
)
{
logger
,
_
,
err
:=
runWithArgs
(
addRequiredArgs
(
"--log.level"
,
lvl
))
logger
,
_
,
err
:=
runWithArgs
(
addRequiredArgs
(
config
.
TraceTypeAlphabet
,
"--log.level"
,
lvl
))
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
logger
)
})
...
...
@@ -37,24 +40,29 @@ func TestLogLevel(t *testing.T) {
}
func
TestDefaultCLIOptionsMatchDefaultConfig
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgs
())
defaultCfg
:=
config
.
NewConfig
(
l1EthRpc
,
common
.
HexToAddress
(
gameAddressValue
),
config
.
TraceTypeAlphabet
,
alphabetTrace
,
cannonDatadir
,
true
,
4
)
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
config
.
TraceTypeAlphabet
))
defaultCfg
:=
config
.
NewConfig
(
l1EthRpc
,
common
.
HexToAddress
(
gameAddressValue
),
config
.
TraceTypeAlphabet
,
true
,
4
)
// Add in the extra CLI options required when using alphabet trace type
defaultCfg
.
AlphabetTrace
=
alphabetTrace
require
.
Equal
(
t
,
defaultCfg
,
cfg
)
}
func
TestDefaultConfigIsValid
(
t
*
testing
.
T
)
{
cfg
:=
config
.
NewConfig
(
l1EthRpc
,
common
.
HexToAddress
(
gameAddressValue
),
config
.
TraceTypeAlphabet
,
alphabetTrace
,
cannonDatadir
,
true
,
4
)
cfg
:=
config
.
NewConfig
(
l1EthRpc
,
common
.
HexToAddress
(
gameAddressValue
),
config
.
TraceTypeAlphabet
,
true
,
4
)
// Add in options that are required based on the specific trace type
// To avoid needing to specify unused options, these aren't included in the params for NewConfig
cfg
.
AlphabetTrace
=
alphabetTrace
require
.
NoError
(
t
,
cfg
.
Check
())
}
func
TestL1ETHRPCAddress
(
t
*
testing
.
T
)
{
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"flag l1-eth-rpc is required"
,
addRequiredArgsExcept
(
"--l1-eth-rpc"
))
verifyArgsInvalid
(
t
,
"flag l1-eth-rpc is required"
,
addRequiredArgsExcept
(
config
.
TraceTypeAlphabet
,
"--l1-eth-rpc"
))
})
t
.
Run
(
"Valid"
,
func
(
t
*
testing
.
T
)
{
url
:=
"http://example.com:8888"
cfg
:=
configForArgs
(
t
,
addRequiredArgsExcept
(
"--l1-eth-rpc"
,
"--l1-eth-rpc="
+
url
))
cfg
:=
configForArgs
(
t
,
addRequiredArgsExcept
(
config
.
TraceTypeAlphabet
,
"--l1-eth-rpc"
,
"--l1-eth-rpc="
+
url
))
require
.
Equal
(
t
,
url
,
cfg
.
L1EthRpc
)
require
.
Equal
(
t
,
url
,
cfg
.
TxMgrConfig
.
L1RPCURL
)
})
...
...
@@ -62,74 +70,134 @@ func TestL1ETHRPCAddress(t *testing.T) {
func
TestTraceType
(
t
*
testing
.
T
)
{
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"flag trace-type is required"
,
addRequiredArgsExcept
(
"--trace-type"
))
verifyArgsInvalid
(
t
,
"flag trace-type is required"
,
addRequiredArgsExcept
(
"
"
,
"
--trace-type"
))
})
for
_
,
traceType
:=
range
config
.
TraceTypes
{
traceType
:=
traceType
t
.
Run
(
"Valid_"
+
traceType
.
String
(),
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgs
Except
(
"--trace-type"
,
"--trace-type"
,
traceType
.
String
()
))
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
traceType
))
require
.
Equal
(
t
,
traceType
,
cfg
.
TraceType
)
})
}
t
.
Run
(
"Invalid"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"unknown trace type:
\"
foo
\"
"
,
addRequiredArgsExcept
(
"--trace-type"
,
"--trace-type=foo"
))
verifyArgsInvalid
(
t
,
"unknown trace type:
\"
foo
\"
"
,
addRequiredArgsExcept
(
config
.
TraceTypeAlphabet
,
"--trace-type"
,
"--trace-type=foo"
))
})
}
func
TestGameAddress
(
t
*
testing
.
T
)
{
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"flag game-address is required"
,
addRequiredArgsExcept
(
"--game-address"
))
verifyArgsInvalid
(
t
,
"flag game-address is required"
,
addRequiredArgsExcept
(
config
.
TraceTypeAlphabet
,
"--game-address"
))
})
t
.
Run
(
"Valid"
,
func
(
t
*
testing
.
T
)
{
addr
:=
common
.
Address
{
0xbb
,
0xcc
,
0xdd
}
cfg
:=
configForArgs
(
t
,
addRequiredArgsExcept
(
"--game-address"
,
"--game-address="
+
addr
.
Hex
()))
cfg
:=
configForArgs
(
t
,
addRequiredArgsExcept
(
config
.
TraceTypeAlphabet
,
"--game-address"
,
"--game-address="
+
addr
.
Hex
()))
require
.
Equal
(
t
,
addr
,
cfg
.
GameAddress
)
})
t
.
Run
(
"Invalid"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"invalid address: foo"
,
addRequiredArgsExcept
(
"--game-address"
,
"--game-address=foo"
))
verifyArgsInvalid
(
t
,
"invalid address: foo"
,
addRequiredArgsExcept
(
config
.
TraceTypeAlphabet
,
"--game-address"
,
"--game-address=foo"
))
})
}
func
TestTxManagerFlagsSupported
(
t
*
testing
.
T
)
{
// Not a comprehensive list of flags, just enough to sanity check the txmgr.CLIFlags were defined
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
"--"
+
txmgr
.
NumConfirmationsFlagName
,
"7"
))
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
config
.
TraceTypeAlphabet
,
"--"
+
txmgr
.
NumConfirmationsFlagName
,
"7"
))
require
.
Equal
(
t
,
uint64
(
7
),
cfg
.
TxMgrConfig
.
NumConfirmations
)
}
func
TestAgreeWithProposedOutput
(
t
*
testing
.
T
)
{
t
.
Run
(
"MustBeProvided"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"flag agree-with-proposed-output is required"
,
addRequiredArgsExcept
(
"--agree-with-proposed-output"
))
verifyArgsInvalid
(
t
,
"flag agree-with-proposed-output is required"
,
addRequiredArgsExcept
(
config
.
TraceTypeAlphabet
,
"--agree-with-proposed-output"
))
})
t
.
Run
(
"Enabled"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
"--agree-with-proposed-output"
))
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
config
.
TraceTypeAlphabet
,
"--agree-with-proposed-output"
))
require
.
True
(
t
,
cfg
.
AgreeWithProposedOutput
)
})
t
.
Run
(
"EnabledWithArg"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
"--agree-with-proposed-output=true"
))
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
config
.
TraceTypeAlphabet
,
"--agree-with-proposed-output=true"
))
require
.
True
(
t
,
cfg
.
AgreeWithProposedOutput
)
})
t
.
Run
(
"Disabled"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
"--agree-with-proposed-output=false"
))
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
config
.
TraceTypeAlphabet
,
"--agree-with-proposed-output=false"
))
require
.
False
(
t
,
cfg
.
AgreeWithProposedOutput
)
})
}
func
TestGameDepth
(
t
*
testing
.
T
)
{
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"flag game-depth is required"
,
addRequiredArgsExcept
(
"--game-depth"
))
verifyArgsInvalid
(
t
,
"flag game-depth is required"
,
addRequiredArgsExcept
(
config
.
TraceTypeAlphabet
,
"--game-depth"
))
})
t
.
Run
(
"Valid"
,
func
(
t
*
testing
.
T
)
{
value
:=
"4"
cfg
:=
configForArgs
(
t
,
addRequiredArgsExcept
(
"--game-depth"
,
"--game-depth="
+
value
))
cfg
:=
configForArgs
(
t
,
addRequiredArgsExcept
(
config
.
TraceTypeAlphabet
,
"--game-depth"
,
"--game-depth="
+
value
))
require
.
Equal
(
t
,
value
,
fmt
.
Sprint
(
cfg
.
GameDepth
))
})
}
func
TestCannonBin
(
t
*
testing
.
T
)
{
t
.
Run
(
"NotRequiredForAlphabetTrace"
,
func
(
t
*
testing
.
T
)
{
configForArgs
(
t
,
addRequiredArgsExcept
(
config
.
TraceTypeAlphabet
,
"--cannon-bin"
))
})
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"flag cannon-bin is required"
,
addRequiredArgsExcept
(
config
.
TraceTypeCannon
,
"--cannon-bin"
))
})
t
.
Run
(
"Valid"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgsExcept
(
config
.
TraceTypeCannon
,
"--cannon-bin"
,
"--cannon-bin=./cannon"
))
require
.
Equal
(
t
,
"./cannon"
,
cfg
.
CannonBin
)
})
}
func
TestCannonAbsolutePrestate
(
t
*
testing
.
T
)
{
t
.
Run
(
"NotRequiredForAlphabetTrace"
,
func
(
t
*
testing
.
T
)
{
configForArgs
(
t
,
addRequiredArgsExcept
(
config
.
TraceTypeAlphabet
,
"--cannon-prestate"
))
})
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"flag cannon-prestate is required"
,
addRequiredArgsExcept
(
config
.
TraceTypeCannon
,
"--cannon-prestate"
))
})
t
.
Run
(
"Valid"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgsExcept
(
config
.
TraceTypeCannon
,
"--cannon-prestate"
,
"--cannon-prestate=./pre.json"
))
require
.
Equal
(
t
,
"./pre.json"
,
cfg
.
CannonAbsolutePreState
)
})
}
func
TestCannonDataDir
(
t
*
testing
.
T
)
{
t
.
Run
(
"NotRequiredForAlphabetTrace"
,
func
(
t
*
testing
.
T
)
{
configForArgs
(
t
,
addRequiredArgsExcept
(
config
.
TraceTypeAlphabet
,
"--cannon-datadir"
))
})
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"flag cannon-datadir is required"
,
addRequiredArgsExcept
(
config
.
TraceTypeCannon
,
"--cannon-datadir"
))
})
t
.
Run
(
"Valid"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgsExcept
(
config
.
TraceTypeCannon
,
"--cannon-datadir"
,
"--cannon-datadir=/foo/bar/cannon"
))
require
.
Equal
(
t
,
"/foo/bar/cannon"
,
cfg
.
CannonDatadir
)
})
}
func
TestCannonL2
(
t
*
testing
.
T
)
{
t
.
Run
(
"NotRequiredForAlphabetTrace"
,
func
(
t
*
testing
.
T
)
{
configForArgs
(
t
,
addRequiredArgsExcept
(
config
.
TraceTypeAlphabet
,
"--cannon-l2"
))
})
t
.
Run
(
"RequiredForCannonTrace"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"flag cannon-l2 is required"
,
addRequiredArgsExcept
(
config
.
TraceTypeCannon
,
"--cannon-l2"
))
})
t
.
Run
(
"Valid"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
config
.
TraceTypeCannon
))
require
.
Equal
(
t
,
cannonL2
,
cfg
.
CannonL2
)
})
}
func
verifyArgsInvalid
(
t
*
testing
.
T
,
messageContains
string
,
cliArgs
[]
string
)
{
_
,
_
,
err
:=
runWithArgs
(
cliArgs
)
require
.
ErrorContains
(
t
,
err
,
messageContains
)
...
...
@@ -153,28 +221,36 @@ func runWithArgs(cliArgs []string) (log.Logger, config.Config, error) {
return
logger
,
*
cfg
,
err
}
func
addRequiredArgs
(
args
...
string
)
[]
string
{
req
:=
requiredArgs
()
func
addRequiredArgs
(
traceType
config
.
TraceType
,
args
...
string
)
[]
string
{
req
:=
requiredArgs
(
traceType
)
combined
:=
toArgList
(
req
)
return
append
(
combined
,
args
...
)
}
func
addRequiredArgsExcept
(
name
string
,
optionalArgs
...
string
)
[]
string
{
req
:=
requiredArgs
()
func
addRequiredArgsExcept
(
traceType
config
.
TraceType
,
name
string
,
optionalArgs
...
string
)
[]
string
{
req
:=
requiredArgs
(
traceType
)
delete
(
req
,
name
)
return
append
(
toArgList
(
req
),
optionalArgs
...
)
}
func
requiredArgs
()
map
[
string
]
string
{
return
map
[
string
]
string
{
func
requiredArgs
(
traceType
config
.
TraceType
)
map
[
string
]
string
{
args
:=
map
[
string
]
string
{
"--game-depth"
:
gameDepth
,
"--agree-with-proposed-output"
:
agreeWithProposedOutput
,
"--l1-eth-rpc"
:
l1EthRpc
,
"--game-address"
:
gameAddressValue
,
"--trace-type"
:
"alphabet"
,
"--alphabet"
:
alphabetTrace
,
"--cannon-datadir"
:
cannonDatadir
,
"--trace-type"
:
traceType
.
String
(),
}
switch
traceType
{
case
config
.
TraceTypeAlphabet
:
args
[
"--alphabet"
]
=
alphabetTrace
case
config
.
TraceTypeCannon
:
args
[
"--cannon-bin"
]
=
cannonBin
args
[
"--cannon-prestate"
]
=
cannonPreState
args
[
"--cannon-datadir"
]
=
cannonDatadir
args
[
"--cannon-l2"
]
=
cannonL2
}
return
args
}
func
toArgList
(
req
map
[
string
]
string
)
[]
string
{
...
...
op-challenger/config/config.go
View file @
554b0da2
...
...
@@ -9,11 +9,14 @@ import (
)
var
(
ErrMissingTraceType
=
errors
.
New
(
"missing trace type"
)
ErrMissingCannonDatadir
=
errors
.
New
(
"missing cannon datadir"
)
ErrMissingAlphabetTrace
=
errors
.
New
(
"missing alphabet trace"
)
ErrMissingL1EthRPC
=
errors
.
New
(
"missing l1 eth rpc url"
)
ErrMissingGameAddress
=
errors
.
New
(
"missing game address"
)
ErrMissingTraceType
=
errors
.
New
(
"missing trace type"
)
ErrMissingCannonDatadir
=
errors
.
New
(
"missing cannon datadir"
)
ErrMissingCannonL2
=
errors
.
New
(
"missing cannon L2"
)
ErrMissingCannonBin
=
errors
.
New
(
"missing cannon bin"
)
ErrMissingCannonAbsolutePreState
=
errors
.
New
(
"missing cannon absolute pre-state"
)
ErrMissingAlphabetTrace
=
errors
.
New
(
"missing alphabet trace"
)
ErrMissingL1EthRPC
=
errors
.
New
(
"missing l1 eth rpc url"
)
ErrMissingGameAddress
=
errors
.
New
(
"missing game address"
)
)
type
TraceType
string
...
...
@@ -56,9 +59,16 @@ type Config struct {
AgreeWithProposedOutput
bool
// Temporary config if we agree or disagree with the posted output
GameDepth
int
// Depth of the game tree
TraceType
TraceType
// Type of trace
AlphabetTrace
string
// String for the AlphabetTraceProvider
CannonDatadir
string
// Cannon Data Directory for the CannonTraceProvider
TraceType
TraceType
// Type of trace
// Specific to the alphabet trace provider
AlphabetTrace
string
// String for the AlphabetTraceProvider
// Specific to the cannon trace provider
CannonBin
string
// Path to the cannon executable to run when generating trace data
CannonAbsolutePreState
string
// File to load the absolute pre-state for Cannon traces from
CannonDatadir
string
// Cannon Data Directory
CannonL2
string
// L2 RPC Url
TxMgrConfig
txmgr
.
CLIConfig
}
...
...
@@ -67,8 +77,6 @@ func NewConfig(
l1EthRpc
string
,
gameAddress
common
.
Address
,
traceType
TraceType
,
alphabetTrace
string
,
cannonDatadir
string
,
agreeWithProposedOutput
bool
,
gameDepth
int
,
)
Config
{
...
...
@@ -79,9 +87,7 @@ func NewConfig(
AgreeWithProposedOutput
:
agreeWithProposedOutput
,
GameDepth
:
gameDepth
,
TraceType
:
traceType
,
AlphabetTrace
:
alphabetTrace
,
CannonDatadir
:
cannonDatadir
,
TraceType
:
traceType
,
TxMgrConfig
:
txmgr
.
NewCLIConfig
(
l1EthRpc
),
}
...
...
@@ -97,8 +103,19 @@ func (c Config) Check() error {
if
c
.
TraceType
==
""
{
return
ErrMissingTraceType
}
if
c
.
TraceType
==
TraceTypeCannon
&&
c
.
CannonDatadir
==
""
{
return
ErrMissingCannonDatadir
if
c
.
TraceType
==
TraceTypeCannon
{
if
c
.
CannonBin
==
""
{
return
ErrMissingCannonBin
}
if
c
.
CannonAbsolutePreState
==
""
{
return
ErrMissingCannonAbsolutePreState
}
if
c
.
CannonDatadir
==
""
{
return
ErrMissingCannonDatadir
}
if
c
.
CannonL2
==
""
{
return
ErrMissingCannonL2
}
}
if
c
.
TraceType
==
TraceTypeAlphabet
&&
c
.
AlphabetTrace
==
""
{
return
ErrMissingAlphabetTrace
...
...
op-challenger/config/config_test.go
View file @
554b0da2
...
...
@@ -9,23 +9,40 @@ import (
)
var
(
validL1EthRpc
=
"http://localhost:8545"
validGameAddress
=
common
.
HexToAddress
(
"0x7bdd3b028C4796eF0EAf07d11394d0d9d8c24139"
)
validAlphabetTrace
=
"abcdefgh"
validCannonDatadir
=
"/tmp/cannon"
agreeWithProposedOutput
=
true
gameDepth
=
4
validL1EthRpc
=
"http://localhost:8545"
validGameAddress
=
common
.
HexToAddress
(
"0x7bdd3b028C4796eF0EAf07d11394d0d9d8c24139"
)
validAlphabetTrace
=
"abcdefgh"
validCannonBin
=
"./bin/cannon"
validCannonAbsolutPreState
=
"pre.json"
validCannonDatadir
=
"/tmp/cannon"
validCannonL2
=
"http://localhost:9545"
agreeWithProposedOutput
=
true
gameDepth
=
4
)
func
validConfig
(
traceType
TraceType
)
Config
{
cfg
:=
NewConfig
(
validL1EthRpc
,
validGameAddress
,
traceType
,
validAlphabetTrace
,
validCannonDatadir
,
agreeWithProposedOutput
,
gameDepth
)
cfg
:=
NewConfig
(
validL1EthRpc
,
validGameAddress
,
traceType
,
agreeWithProposedOutput
,
gameDepth
)
switch
traceType
{
case
TraceTypeAlphabet
:
cfg
.
AlphabetTrace
=
validAlphabetTrace
case
TraceTypeCannon
:
cfg
.
CannonBin
=
validCannonBin
cfg
.
CannonAbsolutePreState
=
validCannonAbsolutPreState
cfg
.
CannonDatadir
=
validCannonDatadir
cfg
.
CannonL2
=
validCannonL2
}
return
cfg
}
// TestValidConfigIsValid checks that the config provided by validConfig is actually valid
func
TestValidConfigIsValid
(
t
*
testing
.
T
)
{
err
:=
validConfig
(
TraceTypeCannon
)
.
Check
()
require
.
NoError
(
t
,
err
)
for
_
,
traceType
:=
range
TraceTypes
{
traceType
:=
traceType
t
.
Run
(
traceType
.
String
(),
func
(
t
*
testing
.
T
)
{
err
:=
validConfig
(
traceType
)
.
Check
()
require
.
NoError
(
t
,
err
)
})
}
}
func
TestTxMgrConfig
(
t
*
testing
.
T
)
{
...
...
@@ -40,30 +57,40 @@ func TestL1EthRpcRequired(t *testing.T) {
config
:=
validConfig
(
TraceTypeCannon
)
config
.
L1EthRpc
=
""
require
.
ErrorIs
(
t
,
config
.
Check
(),
ErrMissingL1EthRPC
)
config
.
L1EthRpc
=
validL1EthRpc
require
.
NoError
(
t
,
config
.
Check
())
}
func
TestGameAddressRequired
(
t
*
testing
.
T
)
{
config
:=
validConfig
(
TraceTypeCannon
)
config
.
GameAddress
=
common
.
Address
{}
require
.
ErrorIs
(
t
,
config
.
Check
(),
ErrMissingGameAddress
)
config
.
GameAddress
=
validGameAddress
require
.
NoError
(
t
,
config
.
Check
())
}
func
TestAlphabetTraceRequired
(
t
*
testing
.
T
)
{
config
:=
validConfig
(
TraceTypeAlphabet
)
config
.
AlphabetTrace
=
""
require
.
ErrorIs
(
t
,
config
.
Check
(),
ErrMissingAlphabetTrace
)
config
.
AlphabetTrace
=
validAlphabetTrace
require
.
NoError
(
t
,
config
.
Check
())
}
func
TestCannonTraceRequired
(
t
*
testing
.
T
)
{
func
TestCannonBinRequired
(
t
*
testing
.
T
)
{
config
:=
validConfig
(
TraceTypeCannon
)
config
.
CannonBin
=
""
require
.
ErrorIs
(
t
,
config
.
Check
(),
ErrMissingCannonBin
)
}
func
TestCannonAbsolutePreStateRequired
(
t
*
testing
.
T
)
{
config
:=
validConfig
(
TraceTypeCannon
)
config
.
CannonAbsolutePreState
=
""
require
.
ErrorIs
(
t
,
config
.
Check
(),
ErrMissingCannonAbsolutePreState
)
}
func
TestCannonDatadirRequired
(
t
*
testing
.
T
)
{
config
:=
validConfig
(
TraceTypeCannon
)
config
.
CannonDatadir
=
""
require
.
ErrorIs
(
t
,
config
.
Check
(),
ErrMissingCannonDatadir
)
config
.
CannonDatadir
=
validCannonDatadir
require
.
NoError
(
t
,
config
.
Check
())
}
func
TestCannonL2Required
(
t
*
testing
.
T
)
{
config
:=
validConfig
(
TraceTypeCannon
)
config
.
CannonL2
=
""
require
.
ErrorIs
(
t
,
config
.
Check
(),
ErrMissingCannonL2
)
}
op-challenger/flags/flags.go
View file @
554b0da2
...
...
@@ -55,14 +55,29 @@ var (
// Optional Flags
AlphabetFlag
=
&
cli
.
StringFlag
{
Name
:
"alphabet"
,
Usage
:
"
Alphabet Trace (temporar
y)"
,
Usage
:
"
Correct Alphabet Trace (alphabet trace type onl
y)"
,
EnvVars
:
prefixEnvVars
(
"ALPHABET"
),
}
CannonBinFlag
=
&
cli
.
StringFlag
{
Name
:
"cannon-bin"
,
Usage
:
"Path to cannon executable to use when generating trace data (cannon trace type only)"
,
EnvVars
:
prefixEnvVars
(
"CANNON_BIN"
),
}
CannonPreStateFlag
=
&
cli
.
StringFlag
{
Name
:
"cannon-prestate"
,
Usage
:
"Path to absolute prestate to use when generating trace data (cannon trace type only)"
,
EnvVars
:
prefixEnvVars
(
"CANNON_PRESTATE"
),
}
CannonDatadirFlag
=
&
cli
.
StringFlag
{
Name
:
"cannon-datadir"
,
Usage
:
"
Cannon Data Directory
"
,
Usage
:
"
Directory to store data generated by cannon (cannon trace type only)
"
,
EnvVars
:
prefixEnvVars
(
"CANNON_DATADIR"
),
}
CannonL2Flag
=
&
cli
.
StringFlag
{
Name
:
"cannon-l2"
,
Usage
:
"L2 Address of L2 JSON-RPC endpoint to use (eth and debug namespace required) (cannon trace type only)"
,
EnvVars
:
prefixEnvVars
(
"CANNON_L2"
),
}
)
// requiredFlags are checked by [CheckRequired]
...
...
@@ -77,7 +92,10 @@ var requiredFlags = []cli.Flag{
// optionalFlags is a list of unchecked cli flags
var
optionalFlags
=
[]
cli
.
Flag
{
AlphabetFlag
,
CannonBinFlag
,
CannonPreStateFlag
,
CannonDatadirFlag
,
CannonL2Flag
,
}
func
init
()
{
...
...
@@ -99,8 +117,17 @@ func CheckRequired(ctx *cli.Context) error {
gameType
:=
config
.
TraceType
(
strings
.
ToLower
(
ctx
.
String
(
TraceTypeFlag
.
Name
)))
switch
gameType
{
case
config
.
TraceTypeCannon
:
if
!
ctx
.
IsSet
(
CannonBinFlag
.
Name
)
{
return
fmt
.
Errorf
(
"flag %s is required"
,
CannonBinFlag
.
Name
)
}
if
!
ctx
.
IsSet
(
CannonPreStateFlag
.
Name
)
{
return
fmt
.
Errorf
(
"flag %s is required"
,
CannonPreStateFlag
.
Name
)
}
if
!
ctx
.
IsSet
(
CannonDatadirFlag
.
Name
)
{
return
fmt
.
Errorf
(
"flag %s is required"
,
"cannon-datadir"
)
return
fmt
.
Errorf
(
"flag %s is required"
,
CannonDatadirFlag
.
Name
)
}
if
!
ctx
.
IsSet
(
CannonL2Flag
.
Name
)
{
return
fmt
.
Errorf
(
"flag %s is required"
,
CannonL2Flag
.
Name
)
}
case
config
.
TraceTypeAlphabet
:
if
!
ctx
.
IsSet
(
AlphabetFlag
.
Name
)
{
...
...
@@ -132,7 +159,10 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) {
TraceType
:
traceTypeFlag
,
GameAddress
:
dgfAddress
,
AlphabetTrace
:
ctx
.
String
(
AlphabetFlag
.
Name
),
CannonBin
:
ctx
.
String
(
CannonBinFlag
.
Name
),
CannonAbsolutePreState
:
ctx
.
String
(
CannonPreStateFlag
.
Name
),
CannonDatadir
:
ctx
.
String
(
CannonDatadirFlag
.
Name
),
CannonL2
:
ctx
.
String
(
CannonL2Flag
.
Name
),
AgreeWithProposedOutput
:
ctx
.
Bool
(
AgreeWithProposedOutputFlag
.
Name
),
GameDepth
:
ctx
.
Int
(
GameDepthFlag
.
Name
),
TxMgrConfig
:
txMgrConfig
,
...
...
op-e2e/actions/l1_miner.go
View file @
554b0da2
...
...
@@ -109,7 +109,7 @@ func (s *L1Miner) ActL1IncludeTx(from common.Address) Action {
func
(
s
*
L1Miner
)
IncludeTx
(
t
Testing
,
tx
*
types
.
Transaction
)
{
from
,
err
:=
s
.
l1Signer
.
Sender
(
tx
)
require
.
NoError
(
t
,
err
)
s
.
log
.
Info
(
"including tx"
,
"nonce"
,
tx
.
Nonce
(),
"from"
,
from
)
s
.
log
.
Info
(
"including tx"
,
"nonce"
,
tx
.
Nonce
(),
"from"
,
from
,
"to"
,
tx
.
To
()
)
if
tx
.
Gas
()
>
s
.
l1BuildingHeader
.
GasLimit
{
t
.
Fatalf
(
"tx consumes %d gas, more than available in L1 block %d"
,
tx
.
Gas
(),
s
.
l1BuildingHeader
.
GasLimit
)
}
...
...
op-e2e/actions/l2_proposer.go
View file @
554b0da2
...
...
@@ -7,6 +7,7 @@ import (
"time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
...
...
@@ -16,6 +17,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-proposer/metrics"
"github.com/ethereum-optimism/optimism/op-proposer/proposer"
...
...
@@ -32,6 +34,7 @@ type L2Proposer struct {
log
log
.
Logger
l1
*
ethclient
.
Client
driver
*
proposer
.
L2OutputSubmitter
contract
*
bindings
.
L2OutputOracleCaller
address
common
.
Address
privKey
*
ecdsa
.
PrivateKey
contractAddr
common
.
Address
...
...
@@ -56,7 +59,6 @@ func (f fakeTxMgr) Send(_ context.Context, _ txmgr.TxCandidate) (*types.Receipt,
}
func
NewL2Proposer
(
t
Testing
,
log
log
.
Logger
,
cfg
*
ProposerCfg
,
l1
*
ethclient
.
Client
,
rollupCl
*
sources
.
RollupClient
)
*
L2Proposer
{
proposerCfg
:=
proposer
.
Config
{
L2OutputOracleAddr
:
cfg
.
OutputOracleAddr
,
PollInterval
:
time
.
Second
,
...
...
@@ -70,12 +72,20 @@ func NewL2Proposer(t Testing, log log.Logger, cfg *ProposerCfg, l1 *ethclient.Cl
dr
,
err
:=
proposer
.
NewL2OutputSubmitter
(
proposerCfg
,
log
,
metrics
.
NoopMetrics
)
require
.
NoError
(
t
,
err
)
contract
,
err
:=
bindings
.
NewL2OutputOracleCaller
(
cfg
.
OutputOracleAddr
,
l1
)
require
.
NoError
(
t
,
err
)
address
:=
crypto
.
PubkeyToAddress
(
cfg
.
ProposerKey
.
PublicKey
)
proposer
,
err
:=
contract
.
PROPOSER
(
&
bind
.
CallOpts
{})
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
proposer
,
address
,
"PROPOSER must be the proposer's address"
)
return
&
L2Proposer
{
log
:
log
,
l1
:
l1
,
driver
:
dr
,
address
:
crypto
.
PubkeyToAddress
(
cfg
.
ProposerKey
.
PublicKey
),
contract
:
contract
,
address
:
address
,
privKey
:
cfg
.
ProposerKey
,
contractAddr
:
cfg
.
OutputOracleAddr
,
}
...
...
op-e2e/e2eutils/setup.go
View file @
554b0da2
...
...
@@ -231,6 +231,11 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *
SystemConfigProxy
:
predeploys
.
DevSystemConfigAddr
,
}
// Sanity check that the config is correct
require
.
Equal
(
t
,
deployParams
.
Secrets
.
Addresses
()
.
Batcher
,
deployParams
.
DeployConfig
.
BatchSenderAddress
)
require
.
Equal
(
t
,
deployParams
.
Secrets
.
Addresses
()
.
SequencerP2P
,
deployParams
.
DeployConfig
.
P2PSequencerAddress
)
require
.
Equal
(
t
,
deployParams
.
Secrets
.
Addresses
()
.
Proposer
,
deployParams
.
DeployConfig
.
L2OutputOracleProposer
)
return
&
SetupData
{
L1Cfg
:
l1Genesis
,
L2Cfg
:
l2Genesis
,
...
...
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