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
fb96cf4a
Unverified
Commit
fb96cf4a
authored
Apr 13, 2023
by
mergify[bot]
Committed by
GitHub
Apr 13, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into op-program-kv-store-2
parents
27c144d9
01aceee5
Changes
32
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
32 changed files
with
811 additions
and
202 deletions
+811
-202
systemconfig.go
op-bindings/bindings/systemconfig.go
+1
-1
systemconfig_more.go
op-bindings/bindings/systemconfig_more.go
+1
-1
blocktime_test.go
op-e2e/actions/blocktime_test.go
+3
-3
api.go
op-node/node/api.go
+1
-7
output_root.go
op-node/rollup/output_root.go
+10
-0
batching.go
op-node/sources/batching.go
+24
-4
batching_test.go
op-node/sources/batching_test.go
+81
-7
receipts.go
op-node/sources/receipts.go
+1
-0
driver.go
op-program/client/driver/driver.go
+22
-5
driver_test.go
op-program/client/driver/driver_test.go
+30
-0
cache.go
op-program/client/l1/cache.go
+63
-0
cache_test.go
op-program/client/l1/cache_test.go
+71
-0
client.go
op-program/client/l1/client.go
+6
-6
client_test.go
op-program/client/l1/client_test.go
+1
-43
stub_oracle_test.go
op-program/client/l1/stub_oracle_test.go
+54
-0
cache.go
op-program/client/l2/cache.go
+60
-0
cache_test.go
op-program/client/l2/cache_test.go
+67
-0
db_test.go
op-program/client/l2/db_test.go
+0
-48
engine.go
op-program/client/l2/engine.go
+22
-8
engine_backend_test.go
op-program/client/l2/engine_backend_test.go
+1
-26
stub_oracle_test.go
op-program/client/l2/stub_oracle_test.go
+94
-0
main.go
op-program/host/cmd/main.go
+9
-1
main_test.go
op-program/host/cmd/main_test.go
+24
-2
config.go
op-program/host/config/config.go
+12
-1
config_test.go
op-program/host/config/config_test.go
+41
-17
flags.go
op-program/host/flags/flags.go
+16
-11
fetcher.go
op-program/host/l1/fetcher.go
+3
-3
l1.go
op-program/host/l1/l1.go
+1
-1
l2.go
op-program/host/l2/l2.go
+3
-3
SystemConfig.sol
packages/contracts-bedrock/contracts/L1/SystemConfig.sol
+3
-3
OptimismPortal.t.sol
...ges/contracts-bedrock/contracts/test/OptimismPortal.t.sol
+85
-0
SystemConfig.t.sol
packages/contracts-bedrock/contracts/test/SystemConfig.t.sol
+1
-1
No files found.
op-bindings/bindings/systemconfig.go
View file @
fb96cf4a
This diff is collapsed.
Click to expand it.
op-bindings/bindings/systemconfig_more.go
View file @
fb96cf4a
This diff is collapsed.
Click to expand it.
op-e2e/actions/blocktime_test.go
View file @
fb96cf4a
...
@@ -28,12 +28,11 @@ func TestBatchInLastPossibleBlocks(gt *testing.T) {
...
@@ -28,12 +28,11 @@ func TestBatchInLastPossibleBlocks(gt *testing.T) {
signer
:=
types
.
LatestSigner
(
sd
.
L2Cfg
.
Config
)
signer
:=
types
.
LatestSigner
(
sd
.
L2Cfg
.
Config
)
cl
:=
sequencerEngine
.
EthClient
()
cl
:=
sequencerEngine
.
EthClient
()
aliceNonce
:=
uint64
(
0
)
// manual nonce management to avoid geth pending-tx nonce non-determinism flakiness
aliceTx
:=
func
()
{
aliceTx
:=
func
()
{
n
,
err
:=
cl
.
PendingNonceAt
(
t
.
Ctx
(),
dp
.
Addresses
.
Alice
)
require
.
NoError
(
t
,
err
)
tx
:=
types
.
MustSignNewTx
(
dp
.
Secrets
.
Alice
,
signer
,
&
types
.
DynamicFeeTx
{
tx
:=
types
.
MustSignNewTx
(
dp
.
Secrets
.
Alice
,
signer
,
&
types
.
DynamicFeeTx
{
ChainID
:
sd
.
L2Cfg
.
Config
.
ChainID
,
ChainID
:
sd
.
L2Cfg
.
Config
.
ChainID
,
Nonce
:
n
,
Nonce
:
aliceNonce
,
GasTipCap
:
big
.
NewInt
(
2
*
params
.
GWei
),
GasTipCap
:
big
.
NewInt
(
2
*
params
.
GWei
),
GasFeeCap
:
new
(
big
.
Int
)
.
Add
(
miner
.
l1Chain
.
CurrentBlock
()
.
BaseFee
,
big
.
NewInt
(
2
*
params
.
GWei
)),
GasFeeCap
:
new
(
big
.
Int
)
.
Add
(
miner
.
l1Chain
.
CurrentBlock
()
.
BaseFee
,
big
.
NewInt
(
2
*
params
.
GWei
)),
Gas
:
params
.
TxGas
,
Gas
:
params
.
TxGas
,
...
@@ -41,6 +40,7 @@ func TestBatchInLastPossibleBlocks(gt *testing.T) {
...
@@ -41,6 +40,7 @@ func TestBatchInLastPossibleBlocks(gt *testing.T) {
Value
:
e2eutils
.
Ether
(
2
),
Value
:
e2eutils
.
Ether
(
2
),
})
})
require
.
NoError
(
gt
,
cl
.
SendTransaction
(
t
.
Ctx
(),
tx
))
require
.
NoError
(
gt
,
cl
.
SendTransaction
(
t
.
Ctx
(),
tx
))
aliceNonce
+=
1
}
}
makeL2BlockWithAliceTx
:=
func
()
{
makeL2BlockWithAliceTx
:=
func
()
{
aliceTx
()
aliceTx
()
...
...
op-node/node/api.go
View file @
fb96cf4a
...
@@ -9,7 +9,6 @@ import (
...
@@ -9,7 +9,6 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup"
...
@@ -115,12 +114,7 @@ func (n *nodeAPI) OutputAtBlock(ctx context.Context, number hexutil.Uint64) (*et
...
@@ -115,12 +114,7 @@ func (n *nodeAPI) OutputAtBlock(ctx context.Context, number hexutil.Uint64) (*et
}
}
var
l2OutputRootVersion
eth
.
Bytes32
// it's zero for now
var
l2OutputRootVersion
eth
.
Bytes32
// it's zero for now
l2OutputRoot
,
err
:=
rollup
.
ComputeL2OutputRoot
(
&
bindings
.
TypesOutputRootProof
{
l2OutputRoot
,
err
:=
rollup
.
ComputeL2OutputRootV0
(
head
,
proof
.
StorageHash
)
Version
:
l2OutputRootVersion
,
StateRoot
:
head
.
Root
(),
MessagePasserStorageRoot
:
proof
.
StorageHash
,
LatestBlockhash
:
head
.
Hash
(),
})
if
err
!=
nil
{
if
err
!=
nil
{
n
.
log
.
Error
(
"Error computing L2 output root, nil ptr passed to hashing function"
)
n
.
log
.
Error
(
"Error computing L2 output root, nil ptr passed to hashing function"
)
return
nil
,
err
return
nil
,
err
...
...
op-node/rollup/output_root.go
View file @
fb96cf4a
...
@@ -24,3 +24,13 @@ func ComputeL2OutputRoot(proofElements *bindings.TypesOutputRootProof) (eth.Byte
...
@@ -24,3 +24,13 @@ func ComputeL2OutputRoot(proofElements *bindings.TypesOutputRootProof) (eth.Byte
)
)
return
eth
.
Bytes32
(
digest
),
nil
return
eth
.
Bytes32
(
digest
),
nil
}
}
func
ComputeL2OutputRootV0
(
block
eth
.
BlockInfo
,
storageRoot
[
32
]
byte
)
(
eth
.
Bytes32
,
error
)
{
var
l2OutputRootVersion
eth
.
Bytes32
// it's zero for now
return
ComputeL2OutputRoot
(
&
bindings
.
TypesOutputRootProof
{
Version
:
l2OutputRootVersion
,
StateRoot
:
block
.
Root
(),
MessagePasserStorageRoot
:
storageRoot
,
LatestBlockhash
:
block
.
Hash
(),
})
}
op-node/sources/batching.go
View file @
fb96cf4a
...
@@ -24,6 +24,7 @@ type IterativeBatchCall[K any, V any] struct {
...
@@ -24,6 +24,7 @@ type IterativeBatchCall[K any, V any] struct {
makeRequest
func
(
K
)
(
V
,
rpc
.
BatchElem
)
makeRequest
func
(
K
)
(
V
,
rpc
.
BatchElem
)
getBatch
BatchCallContextFn
getBatch
BatchCallContextFn
getSingle
CallContextFn
requestsValues
[]
V
requestsValues
[]
V
scheduled
chan
rpc
.
BatchElem
scheduled
chan
rpc
.
BatchElem
...
@@ -35,6 +36,7 @@ func NewIterativeBatchCall[K any, V any](
...
@@ -35,6 +36,7 @@ func NewIterativeBatchCall[K any, V any](
requestsKeys
[]
K
,
requestsKeys
[]
K
,
makeRequest
func
(
K
)
(
V
,
rpc
.
BatchElem
),
makeRequest
func
(
K
)
(
V
,
rpc
.
BatchElem
),
getBatch
BatchCallContextFn
,
getBatch
BatchCallContextFn
,
getSingle
CallContextFn
,
batchSize
int
)
*
IterativeBatchCall
[
K
,
V
]
{
batchSize
int
)
*
IterativeBatchCall
[
K
,
V
]
{
if
len
(
requestsKeys
)
<
batchSize
{
if
len
(
requestsKeys
)
<
batchSize
{
...
@@ -47,6 +49,7 @@ func NewIterativeBatchCall[K any, V any](
...
@@ -47,6 +49,7 @@ func NewIterativeBatchCall[K any, V any](
out
:=
&
IterativeBatchCall
[
K
,
V
]{
out
:=
&
IterativeBatchCall
[
K
,
V
]{
completed
:
0
,
completed
:
0
,
getBatch
:
getBatch
,
getBatch
:
getBatch
,
getSingle
:
getSingle
,
requestsKeys
:
requestsKeys
,
requestsKeys
:
requestsKeys
,
batchSize
:
batchSize
,
batchSize
:
batchSize
,
makeRequest
:
makeRequest
,
makeRequest
:
makeRequest
,
...
@@ -84,6 +87,11 @@ func (ibc *IterativeBatchCall[K, V]) Fetch(ctx context.Context) error {
...
@@ -84,6 +87,11 @@ func (ibc *IterativeBatchCall[K, V]) Fetch(ctx context.Context) error {
ibc
.
resetLock
.
RLock
()
ibc
.
resetLock
.
RLock
()
defer
ibc
.
resetLock
.
RUnlock
()
defer
ibc
.
resetLock
.
RUnlock
()
// return early if context is Done
if
ctx
.
Err
()
!=
nil
{
return
ctx
.
Err
()
}
// collect a batch from the requests channel
// collect a batch from the requests channel
batch
:=
make
([]
rpc
.
BatchElem
,
0
,
ibc
.
batchSize
)
batch
:=
make
([]
rpc
.
BatchElem
,
0
,
ibc
.
batchSize
)
// wait for first element
// wait for first element
...
@@ -119,12 +127,24 @@ func (ibc *IterativeBatchCall[K, V]) Fetch(ctx context.Context) error {
...
@@ -119,12 +127,24 @@ func (ibc *IterativeBatchCall[K, V]) Fetch(ctx context.Context) error {
break
break
}
}
if
len
(
batch
)
==
0
{
return
nil
}
if
ibc
.
batchSize
==
1
{
first
:=
batch
[
0
]
if
err
:=
ibc
.
getSingle
(
ctx
,
&
first
.
Result
,
first
.
Method
,
first
.
Args
...
);
err
!=
nil
{
ibc
.
scheduled
<-
first
return
err
}
}
else
{
if
err
:=
ibc
.
getBatch
(
ctx
,
batch
);
err
!=
nil
{
if
err
:=
ibc
.
getBatch
(
ctx
,
batch
);
err
!=
nil
{
for
_
,
r
:=
range
batch
{
for
_
,
r
:=
range
batch
{
ibc
.
scheduled
<-
r
ibc
.
scheduled
<-
r
}
}
return
fmt
.
Errorf
(
"failed batch-retrieval: %w"
,
err
)
return
fmt
.
Errorf
(
"failed batch-retrieval: %w"
,
err
)
}
}
}
var
result
error
var
result
error
for
_
,
elem
:=
range
batch
{
for
_
,
elem
:=
range
batch
{
if
elem
.
Error
!=
nil
{
if
elem
.
Error
!=
nil
{
...
...
op-node/sources/batching_test.go
View file @
fb96cf4a
...
@@ -35,6 +35,7 @@ type batchTestCase struct {
...
@@ -35,6 +35,7 @@ type batchTestCase struct {
batchSize
int
batchSize
int
batchCalls
[]
batchCall
batchCalls
[]
batchCall
singleCalls
[]
elemCall
mock
.
Mock
mock
.
Mock
}
}
...
@@ -53,7 +54,14 @@ func (tc *batchTestCase) GetBatch(ctx context.Context, b []rpc.BatchElem) error
...
@@ -53,7 +54,14 @@ func (tc *batchTestCase) GetBatch(ctx context.Context, b []rpc.BatchElem) error
if
ctx
.
Err
()
!=
nil
{
if
ctx
.
Err
()
!=
nil
{
return
ctx
.
Err
()
return
ctx
.
Err
()
}
}
return
tc
.
Mock
.
MethodCalled
(
"get"
,
b
)
.
Get
(
0
)
.
([]
error
)[
0
]
return
tc
.
Mock
.
MethodCalled
(
"getBatch"
,
b
)
.
Get
(
0
)
.
([]
error
)[
0
]
}
func
(
tc
*
batchTestCase
)
GetSingle
(
ctx
context
.
Context
,
result
any
,
method
string
,
args
...
any
)
error
{
if
ctx
.
Err
()
!=
nil
{
return
ctx
.
Err
()
}
return
tc
.
Mock
.
MethodCalled
(
"getSingle"
,
(
*
(
result
.
(
*
interface
{})))
.
(
*
string
),
method
,
args
[
0
])
.
Get
(
0
)
.
([]
error
)[
0
]
}
}
var
mockErr
=
errors
.
New
(
"mockErr"
)
var
mockErr
=
errors
.
New
(
"mockErr"
)
...
@@ -64,7 +72,7 @@ func (tc *batchTestCase) Run(t *testing.T) {
...
@@ -64,7 +72,7 @@ func (tc *batchTestCase) Run(t *testing.T) {
keys
[
i
]
=
i
keys
[
i
]
=
i
}
}
make
Mock
:=
func
(
bci
int
,
bc
batchCall
)
func
(
args
mock
.
Arguments
)
{
make
BatchMock
:=
func
(
bc
batchCall
)
func
(
args
mock
.
Arguments
)
{
return
func
(
args
mock
.
Arguments
)
{
return
func
(
args
mock
.
Arguments
)
{
batch
:=
args
[
0
]
.
([]
rpc
.
BatchElem
)
batch
:=
args
[
0
]
.
([]
rpc
.
BatchElem
)
for
i
,
elem
:=
range
batch
{
for
i
,
elem
:=
range
batch
{
...
@@ -83,7 +91,7 @@ func (tc *batchTestCase) Run(t *testing.T) {
...
@@ -83,7 +91,7 @@ func (tc *batchTestCase) Run(t *testing.T) {
}
}
}
}
// mock all the results of the batch calls
// mock all the results of the batch calls
for
bci
,
bc
:=
range
tc
.
batchCalls
{
for
_
,
bc
:=
range
tc
.
batchCalls
{
var
batch
[]
rpc
.
BatchElem
var
batch
[]
rpc
.
BatchElem
for
_
,
elem
:=
range
bc
.
elems
{
for
_
,
elem
:=
range
bc
.
elems
{
batch
=
append
(
batch
,
rpc
.
BatchElem
{
batch
=
append
(
batch
,
rpc
.
BatchElem
{
...
@@ -94,10 +102,30 @@ func (tc *batchTestCase) Run(t *testing.T) {
...
@@ -94,10 +102,30 @@ func (tc *batchTestCase) Run(t *testing.T) {
})
})
}
}
if
len
(
bc
.
elems
)
>
0
{
if
len
(
bc
.
elems
)
>
0
{
tc
.
On
(
"get"
,
batch
)
.
Once
()
.
Run
(
makeMock
(
bci
,
bc
))
.
Return
([]
error
{
bc
.
rpcErr
})
// wrap to preserve nil as type of error
tc
.
On
(
"getBatch"
,
batch
)
.
Once
()
.
Run
(
makeBatchMock
(
bc
))
.
Return
([]
error
{
bc
.
rpcErr
})
// wrap to preserve nil as type of error
}
}
makeSingleMock
:=
func
(
ec
elemCall
)
func
(
args
mock
.
Arguments
)
{
return
func
(
args
mock
.
Arguments
)
{
result
:=
args
[
0
]
.
(
*
string
)
id
:=
args
[
2
]
.
(
int
)
require
.
Equal
(
t
,
ec
.
id
,
id
,
"element should match expected element"
)
if
ec
.
err
{
*
result
=
""
}
else
{
*
result
=
fmt
.
Sprintf
(
"mock result id %d"
,
id
)
}
}
}
// mock the results of unbatched calls
for
_
,
ec
:=
range
tc
.
singleCalls
{
var
ret
error
if
ec
.
err
{
ret
=
mockErr
}
}
tc
.
On
(
"getSingle"
,
new
(
string
),
"testing_foobar"
,
ec
.
id
)
.
Once
()
.
Run
(
makeSingleMock
(
ec
))
.
Return
([]
error
{
ret
})
}
}
iter
:=
NewIterativeBatchCall
[
int
,
*
string
](
keys
,
makeTestRequest
,
tc
.
GetBatch
,
tc
.
batchSize
)
iter
:=
NewIterativeBatchCall
[
int
,
*
string
](
keys
,
makeTestRequest
,
tc
.
GetBatch
,
tc
.
GetSingle
,
tc
.
batchSize
)
for
i
,
bc
:=
range
tc
.
batchCalls
{
for
i
,
bc
:=
range
tc
.
batchCalls
{
ctx
:=
context
.
Background
()
ctx
:=
context
.
Background
()
if
bc
.
makeCtx
!=
nil
{
if
bc
.
makeCtx
!=
nil
{
...
@@ -116,6 +144,20 @@ func (tc *batchTestCase) Run(t *testing.T) {
...
@@ -116,6 +144,20 @@ func (tc *batchTestCase) Run(t *testing.T) {
}
}
}
}
}
}
for
i
,
ec
:=
range
tc
.
singleCalls
{
ctx
:=
context
.
Background
()
err
:=
iter
.
Fetch
(
ctx
)
if
err
==
io
.
EOF
{
require
.
Equal
(
t
,
i
,
len
(
tc
.
singleCalls
)
-
1
,
"EOF only on last call"
)
}
else
{
require
.
False
(
t
,
iter
.
Complete
())
if
ec
.
err
{
require
.
Error
(
t
,
err
)
}
else
{
require
.
NoError
(
t
,
err
)
}
}
}
require
.
True
(
t
,
iter
.
Complete
(),
"batch iter should be complete after the expected calls"
)
require
.
True
(
t
,
iter
.
Complete
(),
"batch iter should be complete after the expected calls"
)
out
,
err
:=
iter
.
Result
()
out
,
err
:=
iter
.
Result
()
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
...
@@ -154,6 +196,37 @@ func TestFetchBatched(t *testing.T) {
...
@@ -154,6 +196,37 @@ func TestFetchBatched(t *testing.T) {
},
},
},
},
},
},
{
name
:
"single element"
,
items
:
1
,
batchSize
:
4
,
singleCalls
:
[]
elemCall
{
{
id
:
0
,
err
:
false
},
},
},
{
name
:
"unbatched"
,
items
:
4
,
batchSize
:
1
,
singleCalls
:
[]
elemCall
{
{
id
:
0
,
err
:
false
},
{
id
:
1
,
err
:
false
},
{
id
:
2
,
err
:
false
},
{
id
:
3
,
err
:
false
},
},
},
{
name
:
"unbatched with retry"
,
items
:
4
,
batchSize
:
1
,
singleCalls
:
[]
elemCall
{
{
id
:
0
,
err
:
false
},
{
id
:
1
,
err
:
true
},
{
id
:
2
,
err
:
false
},
{
id
:
3
,
err
:
false
},
{
id
:
1
,
err
:
false
},
},
},
{
{
name
:
"split"
,
name
:
"split"
,
items
:
5
,
items
:
5
,
...
@@ -240,7 +313,7 @@ func TestFetchBatched(t *testing.T) {
...
@@ -240,7 +313,7 @@ func TestFetchBatched(t *testing.T) {
},
},
{
{
name
:
"context timeout"
,
name
:
"context timeout"
,
items
:
1
,
items
:
2
,
batchSize
:
3
,
batchSize
:
3
,
batchCalls
:
[]
batchCall
{
batchCalls
:
[]
batchCall
{
{
{
...
@@ -255,6 +328,7 @@ func TestFetchBatched(t *testing.T) {
...
@@ -255,6 +328,7 @@ func TestFetchBatched(t *testing.T) {
{
{
elems
:
[]
elemCall
{
elems
:
[]
elemCall
{
{
id
:
0
,
err
:
false
},
{
id
:
0
,
err
:
false
},
{
id
:
1
,
err
:
false
},
},
},
err
:
""
,
err
:
""
,
},
},
...
...
op-node/sources/receipts.go
View file @
fb96cf4a
...
@@ -373,6 +373,7 @@ func (job *receiptsFetchingJob) runFetcher(ctx context.Context) error {
...
@@ -373,6 +373,7 @@ func (job *receiptsFetchingJob) runFetcher(ctx context.Context) error {
job
.
txHashes
,
job
.
txHashes
,
makeReceiptRequest
,
makeReceiptRequest
,
job
.
client
.
BatchCallContext
,
job
.
client
.
BatchCallContext
,
job
.
client
.
CallContext
,
job
.
maxBatchSize
,
job
.
maxBatchSize
,
)
)
}
}
...
...
op-program/client/driver/driver.go
View file @
fb96cf4a
...
@@ -18,17 +18,24 @@ type Derivation interface {
...
@@ -18,17 +18,24 @@ type Derivation interface {
SafeL2Head
()
eth
.
L2BlockRef
SafeL2Head
()
eth
.
L2BlockRef
}
}
type
L2Source
interface
{
derive
.
Engine
L2OutputRoot
()
(
eth
.
Bytes32
,
error
)
}
type
Driver
struct
{
type
Driver
struct
{
logger
log
.
Logger
logger
log
.
Logger
pipeline
Derivation
pipeline
Derivation
l2OutputRoot
func
()
(
eth
.
Bytes32
,
error
)
}
}
func
NewDriver
(
logger
log
.
Logger
,
cfg
*
rollup
.
Config
,
l1Source
derive
.
L1Fetcher
,
l2Source
derive
.
Engin
e
)
*
Driver
{
func
NewDriver
(
logger
log
.
Logger
,
cfg
*
rollup
.
Config
,
l1Source
derive
.
L1Fetcher
,
l2Source
L2Sourc
e
)
*
Driver
{
pipeline
:=
derive
.
NewDerivationPipeline
(
logger
,
cfg
,
l1Source
,
l2Source
,
metrics
.
NoopMetrics
)
pipeline
:=
derive
.
NewDerivationPipeline
(
logger
,
cfg
,
l1Source
,
l2Source
,
metrics
.
NoopMetrics
)
pipeline
.
Reset
()
pipeline
.
Reset
()
return
&
Driver
{
return
&
Driver
{
logger
:
logger
,
logger
:
logger
,
pipeline
:
pipeline
,
pipeline
:
pipeline
,
l2OutputRoot
:
l2Source
.
L2OutputRoot
,
}
}
}
}
...
@@ -51,3 +58,13 @@ func (d *Driver) Step(ctx context.Context) error {
...
@@ -51,3 +58,13 @@ func (d *Driver) Step(ctx context.Context) error {
func
(
d
*
Driver
)
SafeHead
()
eth
.
L2BlockRef
{
func
(
d
*
Driver
)
SafeHead
()
eth
.
L2BlockRef
{
return
d
.
pipeline
.
SafeL2Head
()
return
d
.
pipeline
.
SafeL2Head
()
}
}
func
(
d
*
Driver
)
ValidateClaim
(
claimedOutputRoot
eth
.
Bytes32
)
bool
{
outputRoot
,
err
:=
d
.
l2OutputRoot
()
if
err
!=
nil
{
d
.
logger
.
Info
(
"Failed to calculate L2 output root"
,
"err"
,
err
)
return
false
}
d
.
logger
.
Info
(
"Derivation complete"
,
"head"
,
d
.
SafeHead
(),
"output"
,
outputRoot
,
"claim"
,
claimedOutputRoot
)
return
claimedOutputRoot
==
outputRoot
}
op-program/client/driver/driver_test.go
View file @
fb96cf4a
...
@@ -45,6 +45,36 @@ func TestNoError(t *testing.T) {
...
@@ -45,6 +45,36 @@ func TestNoError(t *testing.T) {
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
}
}
func
TestValidateClaim
(
t
*
testing
.
T
)
{
t
.
Run
(
"Valid"
,
func
(
t
*
testing
.
T
)
{
driver
:=
createDriver
(
t
,
io
.
EOF
)
expected
:=
eth
.
Bytes32
{
0x11
}
driver
.
l2OutputRoot
=
func
()
(
eth
.
Bytes32
,
error
)
{
return
expected
,
nil
}
valid
:=
driver
.
ValidateClaim
(
expected
)
require
.
True
(
t
,
valid
)
})
t
.
Run
(
"Invalid"
,
func
(
t
*
testing
.
T
)
{
driver
:=
createDriver
(
t
,
io
.
EOF
)
driver
.
l2OutputRoot
=
func
()
(
eth
.
Bytes32
,
error
)
{
return
eth
.
Bytes32
{
0x22
},
nil
}
valid
:=
driver
.
ValidateClaim
(
eth
.
Bytes32
{
0x11
})
require
.
False
(
t
,
valid
)
})
t
.
Run
(
"Error"
,
func
(
t
*
testing
.
T
)
{
driver
:=
createDriver
(
t
,
io
.
EOF
)
driver
.
l2OutputRoot
=
func
()
(
eth
.
Bytes32
,
error
)
{
return
eth
.
Bytes32
{},
errors
.
New
(
"boom"
)
}
valid
:=
driver
.
ValidateClaim
(
eth
.
Bytes32
{
0x11
})
require
.
False
(
t
,
valid
)
})
}
func
createDriver
(
t
*
testing
.
T
,
derivationResult
error
)
*
Driver
{
func
createDriver
(
t
*
testing
.
T
,
derivationResult
error
)
*
Driver
{
derivation
:=
&
stubDerivation
{
nextErr
:
derivationResult
}
derivation
:=
&
stubDerivation
{
nextErr
:
derivationResult
}
return
&
Driver
{
return
&
Driver
{
...
...
op-program/client/l1/cache.go
0 → 100644
View file @
fb96cf4a
package
l1
import
(
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/hashicorp/golang-lru/v2/simplelru"
)
// Cache size is quite high as retrieving data from the pre-image oracle can be quite expensive
const
cacheSize
=
2000
// CachingOracle is an implementation of Oracle that delegates to another implementation, adding caching of all results
type
CachingOracle
struct
{
oracle
Oracle
blocks
*
simplelru
.
LRU
[
common
.
Hash
,
eth
.
BlockInfo
]
txs
*
simplelru
.
LRU
[
common
.
Hash
,
types
.
Transactions
]
rcpts
*
simplelru
.
LRU
[
common
.
Hash
,
types
.
Receipts
]
}
func
NewCachingOracle
(
oracle
Oracle
)
*
CachingOracle
{
blockLRU
,
_
:=
simplelru
.
NewLRU
[
common
.
Hash
,
eth
.
BlockInfo
](
cacheSize
,
nil
)
txsLRU
,
_
:=
simplelru
.
NewLRU
[
common
.
Hash
,
types
.
Transactions
](
cacheSize
,
nil
)
rcptsLRU
,
_
:=
simplelru
.
NewLRU
[
common
.
Hash
,
types
.
Receipts
](
cacheSize
,
nil
)
return
&
CachingOracle
{
oracle
:
oracle
,
blocks
:
blockLRU
,
txs
:
txsLRU
,
rcpts
:
rcptsLRU
,
}
}
func
(
o
*
CachingOracle
)
HeaderByBlockHash
(
blockHash
common
.
Hash
)
eth
.
BlockInfo
{
block
,
ok
:=
o
.
blocks
.
Get
(
blockHash
)
if
ok
{
return
block
}
block
=
o
.
oracle
.
HeaderByBlockHash
(
blockHash
)
o
.
blocks
.
Add
(
blockHash
,
block
)
return
block
}
func
(
o
*
CachingOracle
)
TransactionsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
)
{
txs
,
ok
:=
o
.
txs
.
Get
(
blockHash
)
if
ok
{
return
o
.
HeaderByBlockHash
(
blockHash
),
txs
}
block
,
txs
:=
o
.
oracle
.
TransactionsByBlockHash
(
blockHash
)
o
.
blocks
.
Add
(
blockHash
,
block
)
o
.
txs
.
Add
(
blockHash
,
txs
)
return
block
,
txs
}
func
(
o
*
CachingOracle
)
ReceiptsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
)
{
rcpts
,
ok
:=
o
.
rcpts
.
Get
(
blockHash
)
if
ok
{
return
o
.
HeaderByBlockHash
(
blockHash
),
rcpts
}
block
,
rcpts
:=
o
.
oracle
.
ReceiptsByBlockHash
(
blockHash
)
o
.
blocks
.
Add
(
blockHash
,
block
)
o
.
rcpts
.
Add
(
blockHash
,
rcpts
)
return
block
,
rcpts
}
op-program/client/l1/cache_test.go
0 → 100644
View file @
fb96cf4a
package
l1
import
(
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/stretchr/testify/require"
)
// Should implement Oracle
var
_
Oracle
=
(
*
CachingOracle
)(
nil
)
func
TestCachingOracle_HeaderByBlockHash
(
t
*
testing
.
T
)
{
rng
:=
rand
.
New
(
rand
.
NewSource
(
1
))
stub
:=
newStubOracle
(
t
)
oracle
:=
NewCachingOracle
(
stub
)
block
:=
testutils
.
RandomBlockInfo
(
rng
)
// Initial call retrieves from the stub
stub
.
blocks
[
block
.
Hash
()]
=
block
result
:=
oracle
.
HeaderByBlockHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
result
)
// Later calls should retrieve from cache
delete
(
stub
.
blocks
,
block
.
Hash
())
result
=
oracle
.
HeaderByBlockHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
result
)
}
func
TestCachingOracle_TransactionsByBlockHash
(
t
*
testing
.
T
)
{
rng
:=
rand
.
New
(
rand
.
NewSource
(
1
))
stub
:=
newStubOracle
(
t
)
oracle
:=
NewCachingOracle
(
stub
)
block
,
_
:=
testutils
.
RandomBlock
(
rng
,
3
)
// Initial call retrieves from the stub
stub
.
blocks
[
block
.
Hash
()]
=
block
stub
.
txs
[
block
.
Hash
()]
=
block
.
Transactions
()
actualBlock
,
actualTxs
:=
oracle
.
TransactionsByBlockHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
actualBlock
)
require
.
Equal
(
t
,
block
.
Transactions
(),
actualTxs
)
// Later calls should retrieve from cache
delete
(
stub
.
blocks
,
block
.
Hash
())
delete
(
stub
.
txs
,
block
.
Hash
())
actualBlock
,
actualTxs
=
oracle
.
TransactionsByBlockHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
actualBlock
)
require
.
Equal
(
t
,
block
.
Transactions
(),
actualTxs
)
}
func
TestCachingOracle_ReceiptsByBlockHash
(
t
*
testing
.
T
)
{
rng
:=
rand
.
New
(
rand
.
NewSource
(
1
))
stub
:=
newStubOracle
(
t
)
oracle
:=
NewCachingOracle
(
stub
)
block
,
rcpts
:=
testutils
.
RandomBlock
(
rng
,
3
)
// Initial call retrieves from the stub
stub
.
blocks
[
block
.
Hash
()]
=
block
stub
.
rcpts
[
block
.
Hash
()]
=
rcpts
actualBlock
,
actualRcpts
:=
oracle
.
ReceiptsByBlockHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
actualBlock
)
require
.
EqualValues
(
t
,
rcpts
,
actualRcpts
)
// Later calls should retrieve from cache
delete
(
stub
.
blocks
,
block
.
Hash
())
delete
(
stub
.
rcpts
,
block
.
Hash
())
actualBlock
,
actualRcpts
=
oracle
.
ReceiptsByBlockHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
actualBlock
)
require
.
EqualValues
(
t
,
rcpts
,
actualRcpts
)
}
op-program/client/l1/client.go
View file @
fb96cf4a
...
@@ -31,7 +31,7 @@ func NewOracleL1Client(logger log.Logger, oracle Oracle, l1Head common.Hash) *Or
...
@@ -31,7 +31,7 @@ func NewOracleL1Client(logger log.Logger, oracle Oracle, l1Head common.Hash) *Or
}
}
}
}
func
(
o
OracleL1Client
)
L1BlockRefByLabel
(
ctx
context
.
Context
,
label
eth
.
BlockLabel
)
(
eth
.
L1BlockRef
,
error
)
{
func
(
o
*
OracleL1Client
)
L1BlockRefByLabel
(
ctx
context
.
Context
,
label
eth
.
BlockLabel
)
(
eth
.
L1BlockRef
,
error
)
{
if
label
!=
eth
.
Unsafe
&&
label
!=
eth
.
Safe
&&
label
!=
eth
.
Finalized
{
if
label
!=
eth
.
Unsafe
&&
label
!=
eth
.
Safe
&&
label
!=
eth
.
Finalized
{
return
eth
.
L1BlockRef
{},
fmt
.
Errorf
(
"%w: %s"
,
ErrUnknownLabel
,
label
)
return
eth
.
L1BlockRef
{},
fmt
.
Errorf
(
"%w: %s"
,
ErrUnknownLabel
,
label
)
}
}
...
@@ -39,7 +39,7 @@ func (o OracleL1Client) L1BlockRefByLabel(ctx context.Context, label eth.BlockLa
...
@@ -39,7 +39,7 @@ func (o OracleL1Client) L1BlockRefByLabel(ctx context.Context, label eth.BlockLa
return
o
.
head
,
nil
return
o
.
head
,
nil
}
}
func
(
o
OracleL1Client
)
L1BlockRefByNumber
(
ctx
context
.
Context
,
number
uint64
)
(
eth
.
L1BlockRef
,
error
)
{
func
(
o
*
OracleL1Client
)
L1BlockRefByNumber
(
ctx
context
.
Context
,
number
uint64
)
(
eth
.
L1BlockRef
,
error
)
{
if
number
>
o
.
head
.
Number
{
if
number
>
o
.
head
.
Number
{
return
eth
.
L1BlockRef
{},
fmt
.
Errorf
(
"%w: block number %d"
,
ErrNotFound
,
number
)
return
eth
.
L1BlockRef
{},
fmt
.
Errorf
(
"%w: block number %d"
,
ErrNotFound
,
number
)
}
}
...
@@ -50,20 +50,20 @@ func (o OracleL1Client) L1BlockRefByNumber(ctx context.Context, number uint64) (
...
@@ -50,20 +50,20 @@ func (o OracleL1Client) L1BlockRefByNumber(ctx context.Context, number uint64) (
return
block
,
nil
return
block
,
nil
}
}
func
(
o
OracleL1Client
)
L1BlockRefByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
eth
.
L1BlockRef
,
error
)
{
func
(
o
*
OracleL1Client
)
L1BlockRefByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
eth
.
L1BlockRef
,
error
)
{
return
eth
.
InfoToL1BlockRef
(
o
.
oracle
.
HeaderByBlockHash
(
hash
)),
nil
return
eth
.
InfoToL1BlockRef
(
o
.
oracle
.
HeaderByBlockHash
(
hash
)),
nil
}
}
func
(
o
OracleL1Client
)
InfoByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
eth
.
BlockInfo
,
error
)
{
func
(
o
*
OracleL1Client
)
InfoByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
eth
.
BlockInfo
,
error
)
{
return
o
.
oracle
.
HeaderByBlockHash
(
hash
),
nil
return
o
.
oracle
.
HeaderByBlockHash
(
hash
),
nil
}
}
func
(
o
OracleL1Client
)
FetchReceipts
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
,
error
)
{
func
(
o
*
OracleL1Client
)
FetchReceipts
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
,
error
)
{
info
,
rcpts
:=
o
.
oracle
.
ReceiptsByBlockHash
(
blockHash
)
info
,
rcpts
:=
o
.
oracle
.
ReceiptsByBlockHash
(
blockHash
)
return
info
,
rcpts
,
nil
return
info
,
rcpts
,
nil
}
}
func
(
o
OracleL1Client
)
InfoAndTxsByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
,
error
)
{
func
(
o
*
OracleL1Client
)
InfoAndTxsByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
,
error
)
{
info
,
txs
:=
o
.
oracle
.
TransactionsByBlockHash
(
hash
)
info
,
txs
:=
o
.
oracle
.
TransactionsByBlockHash
(
hash
)
return
info
,
txs
,
nil
return
info
,
txs
,
nil
}
}
op-program/client/l1/client_test.go
View file @
fb96cf4a
...
@@ -145,54 +145,12 @@ func TestL1BlockRefByNumber(t *testing.T) {
...
@@ -145,54 +145,12 @@ func TestL1BlockRefByNumber(t *testing.T) {
}
}
func
newClient
(
t
*
testing
.
T
)
(
*
OracleL1Client
,
*
stubOracle
)
{
func
newClient
(
t
*
testing
.
T
)
(
*
OracleL1Client
,
*
stubOracle
)
{
stub
:=
&
stubOracle
{
stub
:=
newStubOracle
(
t
)
t
:
t
,
blocks
:
make
(
map
[
common
.
Hash
]
eth
.
BlockInfo
),
txs
:
make
(
map
[
common
.
Hash
]
types
.
Transactions
),
rcpts
:
make
(
map
[
common
.
Hash
]
types
.
Receipts
),
}
stub
.
blocks
[
head
.
Hash
()]
=
head
stub
.
blocks
[
head
.
Hash
()]
=
head
client
:=
NewOracleL1Client
(
testlog
.
Logger
(
t
,
log
.
LvlDebug
),
stub
,
head
.
Hash
())
client
:=
NewOracleL1Client
(
testlog
.
Logger
(
t
,
log
.
LvlDebug
),
stub
,
head
.
Hash
())
return
client
,
stub
return
client
,
stub
}
}
type
stubOracle
struct
{
t
*
testing
.
T
// blocks maps block hash to eth.BlockInfo
blocks
map
[
common
.
Hash
]
eth
.
BlockInfo
// txs maps block hash to transactions
txs
map
[
common
.
Hash
]
types
.
Transactions
// rcpts maps Block hash to receipts
rcpts
map
[
common
.
Hash
]
types
.
Receipts
}
func
(
o
stubOracle
)
HeaderByBlockHash
(
blockHash
common
.
Hash
)
eth
.
BlockInfo
{
info
,
ok
:=
o
.
blocks
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"unknown block %s"
,
blockHash
)
}
return
info
}
func
(
o
stubOracle
)
TransactionsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
)
{
txs
,
ok
:=
o
.
txs
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"unknown txs %s"
,
blockHash
)
}
return
o
.
HeaderByBlockHash
(
blockHash
),
txs
}
func
(
o
stubOracle
)
ReceiptsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
)
{
rcpts
,
ok
:=
o
.
rcpts
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"unknown rcpts %s"
,
blockHash
)
}
return
o
.
HeaderByBlockHash
(
blockHash
),
rcpts
}
func
blockNum
(
num
uint64
)
eth
.
BlockInfo
{
func
blockNum
(
num
uint64
)
eth
.
BlockInfo
{
parentNum
:=
num
-
1
parentNum
:=
num
-
1
return
&
testutils
.
MockBlockInfo
{
return
&
testutils
.
MockBlockInfo
{
...
...
op-program/client/l1/stub_oracle_test.go
0 → 100644
View file @
fb96cf4a
package
l1
import
(
"testing"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
type
stubOracle
struct
{
t
*
testing
.
T
// blocks maps block hash to eth.BlockInfo
blocks
map
[
common
.
Hash
]
eth
.
BlockInfo
// txs maps block hash to transactions
txs
map
[
common
.
Hash
]
types
.
Transactions
// rcpts maps Block hash to receipts
rcpts
map
[
common
.
Hash
]
types
.
Receipts
}
func
newStubOracle
(
t
*
testing
.
T
)
*
stubOracle
{
return
&
stubOracle
{
t
:
t
,
blocks
:
make
(
map
[
common
.
Hash
]
eth
.
BlockInfo
),
txs
:
make
(
map
[
common
.
Hash
]
types
.
Transactions
),
rcpts
:
make
(
map
[
common
.
Hash
]
types
.
Receipts
),
}
}
func
(
o
stubOracle
)
HeaderByBlockHash
(
blockHash
common
.
Hash
)
eth
.
BlockInfo
{
info
,
ok
:=
o
.
blocks
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"unknown block %s"
,
blockHash
)
}
return
info
}
func
(
o
stubOracle
)
TransactionsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
)
{
txs
,
ok
:=
o
.
txs
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"unknown txs %s"
,
blockHash
)
}
return
o
.
HeaderByBlockHash
(
blockHash
),
txs
}
func
(
o
stubOracle
)
ReceiptsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
)
{
rcpts
,
ok
:=
o
.
rcpts
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"unknown rcpts %s"
,
blockHash
)
}
return
o
.
HeaderByBlockHash
(
blockHash
),
rcpts
}
op-program/client/l2/cache.go
0 → 100644
View file @
fb96cf4a
package
l2
import
(
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/hashicorp/golang-lru/v2/simplelru"
)
const
blockCacheSize
=
2
_000
const
nodeCacheSize
=
100
_000
const
codeCacheSize
=
10
_000
type
CachingOracle
struct
{
oracle
Oracle
blocks
*
simplelru
.
LRU
[
common
.
Hash
,
*
types
.
Block
]
nodes
*
simplelru
.
LRU
[
common
.
Hash
,
[]
byte
]
codes
*
simplelru
.
LRU
[
common
.
Hash
,
[]
byte
]
}
func
NewCachingOracle
(
oracle
Oracle
)
*
CachingOracle
{
blockLRU
,
_
:=
simplelru
.
NewLRU
[
common
.
Hash
,
*
types
.
Block
](
blockCacheSize
,
nil
)
nodeLRU
,
_
:=
simplelru
.
NewLRU
[
common
.
Hash
,
[]
byte
](
nodeCacheSize
,
nil
)
codeLRU
,
_
:=
simplelru
.
NewLRU
[
common
.
Hash
,
[]
byte
](
codeCacheSize
,
nil
)
return
&
CachingOracle
{
oracle
:
oracle
,
blocks
:
blockLRU
,
nodes
:
nodeLRU
,
codes
:
codeLRU
,
}
}
func
(
o
*
CachingOracle
)
NodeByHash
(
nodeHash
common
.
Hash
)
[]
byte
{
node
,
ok
:=
o
.
nodes
.
Get
(
nodeHash
)
if
ok
{
return
node
}
node
=
o
.
oracle
.
NodeByHash
(
nodeHash
)
o
.
nodes
.
Add
(
nodeHash
,
node
)
return
node
}
func
(
o
*
CachingOracle
)
CodeByHash
(
codeHash
common
.
Hash
)
[]
byte
{
code
,
ok
:=
o
.
codes
.
Get
(
codeHash
)
if
ok
{
return
code
}
code
=
o
.
oracle
.
CodeByHash
(
codeHash
)
o
.
codes
.
Add
(
codeHash
,
code
)
return
code
}
func
(
o
*
CachingOracle
)
BlockByHash
(
blockHash
common
.
Hash
)
*
types
.
Block
{
block
,
ok
:=
o
.
blocks
.
Get
(
blockHash
)
if
ok
{
return
block
}
block
=
o
.
oracle
.
BlockByHash
(
blockHash
)
o
.
blocks
.
Add
(
blockHash
,
block
)
return
block
}
op-program/client/l2/cache_test.go
0 → 100644
View file @
fb96cf4a
package
l2
import
(
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
// Should be an Oracle implementation
var
_
Oracle
=
(
*
CachingOracle
)(
nil
)
func
TestBlockByHash
(
t
*
testing
.
T
)
{
stub
,
_
:=
newStubOracle
(
t
)
oracle
:=
NewCachingOracle
(
stub
)
rng
:=
rand
.
New
(
rand
.
NewSource
(
1
))
block
,
_
:=
testutils
.
RandomBlock
(
rng
,
1
)
// Initial call retrieves from the stub
stub
.
blocks
[
block
.
Hash
()]
=
block
actual
:=
oracle
.
BlockByHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
actual
)
// Later calls should retrieve from cache
delete
(
stub
.
blocks
,
block
.
Hash
())
actual
=
oracle
.
BlockByHash
(
block
.
Hash
())
require
.
Equal
(
t
,
block
,
actual
)
}
func
TestNodeByHash
(
t
*
testing
.
T
)
{
stub
,
stateStub
:=
newStubOracle
(
t
)
oracle
:=
NewCachingOracle
(
stub
)
node
:=
[]
byte
{
12
,
3
,
4
}
hash
:=
common
.
Hash
{
0xaa
}
// Initial call retrieves from the stub
stateStub
.
data
[
hash
]
=
node
actual
:=
oracle
.
NodeByHash
(
hash
)
require
.
Equal
(
t
,
node
,
actual
)
// Later calls should retrieve from cache
delete
(
stateStub
.
data
,
hash
)
actual
=
oracle
.
NodeByHash
(
hash
)
require
.
Equal
(
t
,
node
,
actual
)
}
func
TestCodeByHash
(
t
*
testing
.
T
)
{
stub
,
stateStub
:=
newStubOracle
(
t
)
oracle
:=
NewCachingOracle
(
stub
)
node
:=
[]
byte
{
12
,
3
,
4
}
hash
:=
common
.
Hash
{
0xaa
}
// Initial call retrieves from the stub
stateStub
.
code
[
hash
]
=
node
actual
:=
oracle
.
CodeByHash
(
hash
)
require
.
Equal
(
t
,
node
,
actual
)
// Later calls should retrieve from cache
delete
(
stateStub
.
code
,
hash
)
actual
=
oracle
.
CodeByHash
(
hash
)
require
.
Equal
(
t
,
node
,
actual
)
}
op-program/client/l2/db_test.go
View file @
fb96cf4a
...
@@ -194,51 +194,3 @@ func assertStateDataAvailable(t *testing.T, db ethdb.KeyValueStore, l2Genesis *c
...
@@ -194,51 +194,3 @@ func assertStateDataAvailable(t *testing.T, db ethdb.KeyValueStore, l2Genesis *c
require
.
Nil
(
t
,
statedb
.
GetCode
(
unknownAccount
),
"unset account code"
)
require
.
Nil
(
t
,
statedb
.
GetCode
(
unknownAccount
),
"unset account code"
)
require
.
Equal
(
t
,
common
.
Hash
{},
statedb
.
GetCodeHash
(
unknownAccount
),
"unset account code hash"
)
require
.
Equal
(
t
,
common
.
Hash
{},
statedb
.
GetCodeHash
(
unknownAccount
),
"unset account code hash"
)
}
}
func
newStubStateOracle
(
t
*
testing
.
T
)
*
stubStateOracle
{
return
&
stubStateOracle
{
t
:
t
,
data
:
make
(
map
[
common
.
Hash
][]
byte
),
code
:
make
(
map
[
common
.
Hash
][]
byte
),
}
}
type
stubStateOracle
struct
{
t
*
testing
.
T
data
map
[
common
.
Hash
][]
byte
code
map
[
common
.
Hash
][]
byte
}
func
(
o
*
stubStateOracle
)
NodeByHash
(
nodeHash
common
.
Hash
)
[]
byte
{
data
,
ok
:=
o
.
data
[
nodeHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"no value for node %v"
,
nodeHash
)
}
return
data
}
func
(
o
*
stubStateOracle
)
CodeByHash
(
hash
common
.
Hash
)
[]
byte
{
data
,
ok
:=
o
.
code
[
hash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"no value for code %v"
,
hash
)
}
return
data
}
// kvStateOracle loads data from a source ethdb.KeyValueStore
type
kvStateOracle
struct
{
t
*
testing
.
T
source
ethdb
.
KeyValueStore
}
func
(
o
*
kvStateOracle
)
NodeByHash
(
nodeHash
common
.
Hash
)
[]
byte
{
val
,
err
:=
o
.
source
.
Get
(
nodeHash
.
Bytes
())
if
err
!=
nil
{
o
.
t
.
Fatalf
(
"error retrieving node %v: %v"
,
nodeHash
,
err
)
}
return
val
}
func
(
o
*
kvStateOracle
)
CodeByHash
(
hash
common
.
Hash
)
[]
byte
{
return
rawdb
.
ReadCode
(
o
.
source
,
hash
)
}
op-program/client/l2/engine.go
View file @
fb96cf4a
...
@@ -5,6 +5,7 @@ import (
...
@@ -5,6 +5,7 @@ import (
"errors"
"errors"
"fmt"
"fmt"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
...
@@ -33,19 +34,32 @@ func NewOracleEngine(rollupCfg *rollup.Config, logger log.Logger, backend engine
...
@@ -33,19 +34,32 @@ func NewOracleEngine(rollupCfg *rollup.Config, logger log.Logger, backend engine
}
}
}
}
func
(
o
OracleEngine
)
GetPayload
(
ctx
context
.
Context
,
payloadId
eth
.
PayloadID
)
(
*
eth
.
ExecutionPayload
,
error
)
{
func
(
o
*
OracleEngine
)
L2OutputRoot
()
(
eth
.
Bytes32
,
error
)
{
outBlock
:=
o
.
backend
.
CurrentHeader
()
stateDB
,
err
:=
o
.
backend
.
StateAt
(
outBlock
.
Root
)
if
err
!=
nil
{
return
eth
.
Bytes32
{},
fmt
.
Errorf
(
"failed to open L2 state db at block %s: %w"
,
outBlock
.
Hash
(),
err
)
}
withdrawalsTrie
,
err
:=
stateDB
.
StorageTrie
(
predeploys
.
L2ToL1MessagePasserAddr
)
if
err
!=
nil
{
return
eth
.
Bytes32
{},
fmt
.
Errorf
(
"withdrawals trie unavailable at block %v: %w"
,
outBlock
.
Hash
(),
err
)
}
return
rollup
.
ComputeL2OutputRootV0
(
eth
.
HeaderBlockInfo
(
outBlock
),
withdrawalsTrie
.
Hash
())
}
func
(
o
*
OracleEngine
)
GetPayload
(
ctx
context
.
Context
,
payloadId
eth
.
PayloadID
)
(
*
eth
.
ExecutionPayload
,
error
)
{
return
o
.
api
.
GetPayloadV1
(
ctx
,
payloadId
)
return
o
.
api
.
GetPayloadV1
(
ctx
,
payloadId
)
}
}
func
(
o
OracleEngine
)
ForkchoiceUpdate
(
ctx
context
.
Context
,
state
*
eth
.
ForkchoiceState
,
attr
*
eth
.
PayloadAttributes
)
(
*
eth
.
ForkchoiceUpdatedResult
,
error
)
{
func
(
o
*
OracleEngine
)
ForkchoiceUpdate
(
ctx
context
.
Context
,
state
*
eth
.
ForkchoiceState
,
attr
*
eth
.
PayloadAttributes
)
(
*
eth
.
ForkchoiceUpdatedResult
,
error
)
{
return
o
.
api
.
ForkchoiceUpdatedV1
(
ctx
,
state
,
attr
)
return
o
.
api
.
ForkchoiceUpdatedV1
(
ctx
,
state
,
attr
)
}
}
func
(
o
OracleEngine
)
NewPayload
(
ctx
context
.
Context
,
payload
*
eth
.
ExecutionPayload
)
(
*
eth
.
PayloadStatusV1
,
error
)
{
func
(
o
*
OracleEngine
)
NewPayload
(
ctx
context
.
Context
,
payload
*
eth
.
ExecutionPayload
)
(
*
eth
.
PayloadStatusV1
,
error
)
{
return
o
.
api
.
NewPayloadV1
(
ctx
,
payload
)
return
o
.
api
.
NewPayloadV1
(
ctx
,
payload
)
}
}
func
(
o
OracleEngine
)
PayloadByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
*
eth
.
ExecutionPayload
,
error
)
{
func
(
o
*
OracleEngine
)
PayloadByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
*
eth
.
ExecutionPayload
,
error
)
{
block
:=
o
.
backend
.
GetBlockByHash
(
hash
)
block
:=
o
.
backend
.
GetBlockByHash
(
hash
)
if
block
==
nil
{
if
block
==
nil
{
return
nil
,
ErrNotFound
return
nil
,
ErrNotFound
...
@@ -53,7 +67,7 @@ func (o OracleEngine) PayloadByHash(ctx context.Context, hash common.Hash) (*eth
...
@@ -53,7 +67,7 @@ func (o OracleEngine) PayloadByHash(ctx context.Context, hash common.Hash) (*eth
return
eth
.
BlockAsPayload
(
block
)
return
eth
.
BlockAsPayload
(
block
)
}
}
func
(
o
OracleEngine
)
PayloadByNumber
(
ctx
context
.
Context
,
n
uint64
)
(
*
eth
.
ExecutionPayload
,
error
)
{
func
(
o
*
OracleEngine
)
PayloadByNumber
(
ctx
context
.
Context
,
n
uint64
)
(
*
eth
.
ExecutionPayload
,
error
)
{
hash
:=
o
.
backend
.
GetCanonicalHash
(
n
)
hash
:=
o
.
backend
.
GetCanonicalHash
(
n
)
if
hash
==
(
common
.
Hash
{})
{
if
hash
==
(
common
.
Hash
{})
{
return
nil
,
ErrNotFound
return
nil
,
ErrNotFound
...
@@ -61,7 +75,7 @@ func (o OracleEngine) PayloadByNumber(ctx context.Context, n uint64) (*eth.Execu
...
@@ -61,7 +75,7 @@ func (o OracleEngine) PayloadByNumber(ctx context.Context, n uint64) (*eth.Execu
return
o
.
PayloadByHash
(
ctx
,
hash
)
return
o
.
PayloadByHash
(
ctx
,
hash
)
}
}
func
(
o
OracleEngine
)
L2BlockRefByLabel
(
ctx
context
.
Context
,
label
eth
.
BlockLabel
)
(
eth
.
L2BlockRef
,
error
)
{
func
(
o
*
OracleEngine
)
L2BlockRefByLabel
(
ctx
context
.
Context
,
label
eth
.
BlockLabel
)
(
eth
.
L2BlockRef
,
error
)
{
var
header
*
types
.
Header
var
header
*
types
.
Header
switch
label
{
switch
label
{
case
eth
.
Unsafe
:
case
eth
.
Unsafe
:
...
@@ -83,7 +97,7 @@ func (o OracleEngine) L2BlockRefByLabel(ctx context.Context, label eth.BlockLabe
...
@@ -83,7 +97,7 @@ func (o OracleEngine) L2BlockRefByLabel(ctx context.Context, label eth.BlockLabe
return
derive
.
L2BlockToBlockRef
(
block
,
&
o
.
rollupCfg
.
Genesis
)
return
derive
.
L2BlockToBlockRef
(
block
,
&
o
.
rollupCfg
.
Genesis
)
}
}
func
(
o
OracleEngine
)
L2BlockRefByHash
(
ctx
context
.
Context
,
l2Hash
common
.
Hash
)
(
eth
.
L2BlockRef
,
error
)
{
func
(
o
*
OracleEngine
)
L2BlockRefByHash
(
ctx
context
.
Context
,
l2Hash
common
.
Hash
)
(
eth
.
L2BlockRef
,
error
)
{
block
:=
o
.
backend
.
GetBlockByHash
(
l2Hash
)
block
:=
o
.
backend
.
GetBlockByHash
(
l2Hash
)
if
block
==
nil
{
if
block
==
nil
{
return
eth
.
L2BlockRef
{},
ErrNotFound
return
eth
.
L2BlockRef
{},
ErrNotFound
...
@@ -91,7 +105,7 @@ func (o OracleEngine) L2BlockRefByHash(ctx context.Context, l2Hash common.Hash)
...
@@ -91,7 +105,7 @@ func (o OracleEngine) L2BlockRefByHash(ctx context.Context, l2Hash common.Hash)
return
derive
.
L2BlockToBlockRef
(
block
,
&
o
.
rollupCfg
.
Genesis
)
return
derive
.
L2BlockToBlockRef
(
block
,
&
o
.
rollupCfg
.
Genesis
)
}
}
func
(
o
OracleEngine
)
SystemConfigByL2Hash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
eth
.
SystemConfig
,
error
)
{
func
(
o
*
OracleEngine
)
SystemConfigByL2Hash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
eth
.
SystemConfig
,
error
)
{
payload
,
err
:=
o
.
PayloadByHash
(
ctx
,
hash
)
payload
,
err
:=
o
.
PayloadByHash
(
ctx
,
hash
)
if
err
!=
nil
{
if
err
!=
nil
{
return
eth
.
SystemConfig
{},
err
return
eth
.
SystemConfig
{},
err
...
...
op-program/client/l2/engine_backend_test.go
View file @
fb96cf4a
...
@@ -14,7 +14,6 @@ import (
...
@@ -14,7 +14,6 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/require"
...
@@ -168,7 +167,7 @@ func setupOracle(t *testing.T, blockCount int, headBlockNumber int) (*params.Cha
...
@@ -168,7 +167,7 @@ func setupOracle(t *testing.T, blockCount int, headBlockNumber int) (*params.Cha
genesisBlock
:=
l2Genesis
.
MustCommit
(
db
)
genesisBlock
:=
l2Genesis
.
MustCommit
(
db
)
blocks
,
_
:=
core
.
GenerateChain
(
chainCfg
,
genesisBlock
,
consensus
,
db
,
blockCount
,
func
(
i
int
,
gen
*
core
.
BlockGen
)
{})
blocks
,
_
:=
core
.
GenerateChain
(
chainCfg
,
genesisBlock
,
consensus
,
db
,
blockCount
,
func
(
i
int
,
gen
*
core
.
BlockGen
)
{})
blocks
=
append
([]
*
types
.
Block
{
genesisBlock
},
blocks
...
)
blocks
=
append
([]
*
types
.
Block
{
genesisBlock
},
blocks
...
)
oracle
:=
newStub
BlockOracle
(
t
,
blocks
[
:
headBlockNumber
+
1
],
db
)
oracle
:=
newStub
OracleWithBlocks
(
t
,
blocks
[
:
headBlockNumber
+
1
],
db
)
return
chainCfg
,
blocks
,
oracle
return
chainCfg
,
blocks
,
oracle
}
}
...
@@ -195,30 +194,6 @@ func createBlock(t *testing.T, chain *OracleBackedL2Chain) *types.Block {
...
@@ -195,30 +194,6 @@ func createBlock(t *testing.T, chain *OracleBackedL2Chain) *types.Block {
return
blocks
[
0
]
return
blocks
[
0
]
}
}
type
stubBlockOracle
struct
{
blocks
map
[
common
.
Hash
]
*
types
.
Block
kvStateOracle
}
func
newStubBlockOracle
(
t
*
testing
.
T
,
chain
[]
*
types
.
Block
,
db
ethdb
.
Database
)
*
stubBlockOracle
{
blocks
:=
make
(
map
[
common
.
Hash
]
*
types
.
Block
,
len
(
chain
))
for
_
,
block
:=
range
chain
{
blocks
[
block
.
Hash
()]
=
block
}
return
&
stubBlockOracle
{
blocks
:
blocks
,
kvStateOracle
:
kvStateOracle
{
t
:
t
,
source
:
db
},
}
}
func
(
o
stubBlockOracle
)
BlockByHash
(
blockHash
common
.
Hash
)
*
types
.
Block
{
block
,
ok
:=
o
.
blocks
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"requested unknown block %s"
,
blockHash
)
}
return
block
}
func
TestEngineAPITests
(
t
*
testing
.
T
)
{
func
TestEngineAPITests
(
t
*
testing
.
T
)
{
test
.
RunEngineAPITests
(
t
,
func
(
t
*
testing
.
T
)
engineapi
.
EngineBackend
{
test
.
RunEngineAPITests
(
t
,
func
(
t
*
testing
.
T
)
engineapi
.
EngineBackend
{
_
,
chain
:=
setupOracleBackedChain
(
t
,
0
)
_
,
chain
:=
setupOracleBackedChain
(
t
,
0
)
...
...
op-program/client/l2/stub_oracle_test.go
0 → 100644
View file @
fb96cf4a
package
l2
import
(
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
)
type
stubBlockOracle
struct
{
t
*
testing
.
T
blocks
map
[
common
.
Hash
]
*
types
.
Block
StateOracle
}
func
newStubOracle
(
t
*
testing
.
T
)
(
*
stubBlockOracle
,
*
stubStateOracle
)
{
stateOracle
:=
newStubStateOracle
(
t
)
blockOracle
:=
stubBlockOracle
{
t
:
t
,
blocks
:
make
(
map
[
common
.
Hash
]
*
types
.
Block
),
StateOracle
:
stateOracle
,
}
return
&
blockOracle
,
stateOracle
}
func
newStubOracleWithBlocks
(
t
*
testing
.
T
,
chain
[]
*
types
.
Block
,
db
ethdb
.
Database
)
*
stubBlockOracle
{
blocks
:=
make
(
map
[
common
.
Hash
]
*
types
.
Block
,
len
(
chain
))
for
_
,
block
:=
range
chain
{
blocks
[
block
.
Hash
()]
=
block
}
return
&
stubBlockOracle
{
blocks
:
blocks
,
StateOracle
:
&
kvStateOracle
{
t
:
t
,
source
:
db
},
}
}
func
(
o
stubBlockOracle
)
BlockByHash
(
blockHash
common
.
Hash
)
*
types
.
Block
{
block
,
ok
:=
o
.
blocks
[
blockHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"requested unknown block %s"
,
blockHash
)
}
return
block
}
// kvStateOracle loads data from a source ethdb.KeyValueStore
type
kvStateOracle
struct
{
t
*
testing
.
T
source
ethdb
.
KeyValueStore
}
func
(
o
*
kvStateOracle
)
NodeByHash
(
nodeHash
common
.
Hash
)
[]
byte
{
val
,
err
:=
o
.
source
.
Get
(
nodeHash
.
Bytes
())
if
err
!=
nil
{
o
.
t
.
Fatalf
(
"error retrieving node %v: %v"
,
nodeHash
,
err
)
}
return
val
}
func
(
o
*
kvStateOracle
)
CodeByHash
(
hash
common
.
Hash
)
[]
byte
{
return
rawdb
.
ReadCode
(
o
.
source
,
hash
)
}
func
newStubStateOracle
(
t
*
testing
.
T
)
*
stubStateOracle
{
return
&
stubStateOracle
{
t
:
t
,
data
:
make
(
map
[
common
.
Hash
][]
byte
),
code
:
make
(
map
[
common
.
Hash
][]
byte
),
}
}
// Stub StateOracle implementation that reads from simple maps
type
stubStateOracle
struct
{
t
*
testing
.
T
data
map
[
common
.
Hash
][]
byte
code
map
[
common
.
Hash
][]
byte
}
func
(
o
*
stubStateOracle
)
NodeByHash
(
nodeHash
common
.
Hash
)
[]
byte
{
data
,
ok
:=
o
.
data
[
nodeHash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"no value for node %v"
,
nodeHash
)
}
return
data
}
func
(
o
*
stubStateOracle
)
CodeByHash
(
hash
common
.
Hash
)
[]
byte
{
data
,
ok
:=
o
.
code
[
hash
]
if
!
ok
{
o
.
t
.
Fatalf
(
"no value for code %v"
,
hash
)
}
return
data
}
op-program/host/cmd/main.go
View file @
fb96cf4a
...
@@ -9,6 +9,7 @@ import (
...
@@ -9,6 +9,7 @@ import (
"time"
"time"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
cldr
"github.com/ethereum-optimism/optimism/op-program/client/driver"
cldr
"github.com/ethereum-optimism/optimism/op-program/client/driver"
"github.com/ethereum-optimism/optimism/op-program/host/config"
"github.com/ethereum-optimism/optimism/op-program/host/config"
...
@@ -41,6 +42,10 @@ var VersionWithMeta = func() string {
...
@@ -41,6 +42,10 @@ var VersionWithMeta = func() string {
return
v
return
v
}()
}()
var
(
ErrClaimNotValid
=
errors
.
New
(
"invalid claim"
)
)
func
main
()
{
func
main
()
{
args
:=
os
.
Args
args
:=
os
.
Args
err
:=
run
(
args
,
FaultProofProgram
)
err
:=
run
(
args
,
FaultProofProgram
)
...
@@ -124,6 +129,9 @@ func FaultProofProgram(logger log.Logger, cfg *config.Config) error {
...
@@ -124,6 +129,9 @@ func FaultProofProgram(logger log.Logger, cfg *config.Config) error {
return
err
return
err
}
}
}
}
logger
.
Info
(
"Derivation complete"
,
"head"
,
d
.
SafeHead
())
claim
:=
cfg
.
L2Claim
if
!
d
.
ValidateClaim
(
eth
.
Bytes32
(
claim
))
{
return
ErrClaimNotValid
}
return
nil
return
nil
}
}
op-program/host/cmd/main_test.go
View file @
fb96cf4a
...
@@ -16,6 +16,7 @@ import (
...
@@ -16,6 +16,7 @@ import (
// Use HexToHash(...).Hex() to ensure the strings are the correct length for a hash
// Use HexToHash(...).Hex() to ensure the strings are the correct length for a hash
var
l1HeadValue
=
common
.
HexToHash
(
"0x111111"
)
.
Hex
()
var
l1HeadValue
=
common
.
HexToHash
(
"0x111111"
)
.
Hex
()
var
l2HeadValue
=
common
.
HexToHash
(
"0x222222"
)
.
Hex
()
var
l2HeadValue
=
common
.
HexToHash
(
"0x222222"
)
.
Hex
()
var
l2ClaimValue
=
common
.
HexToHash
(
"0x333333"
)
.
Hex
()
func
TestLogLevel
(
t
*
testing
.
T
)
{
func
TestLogLevel
(
t
*
testing
.
T
)
{
t
.
Run
(
"RejectInvalid"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"RejectInvalid"
,
func
(
t
*
testing
.
T
)
{
...
@@ -34,7 +35,12 @@ func TestLogLevel(t *testing.T) {
...
@@ -34,7 +35,12 @@ func TestLogLevel(t *testing.T) {
func
TestDefaultCLIOptionsMatchDefaultConfig
(
t
*
testing
.
T
)
{
func
TestDefaultCLIOptionsMatchDefaultConfig
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgs
())
cfg
:=
configForArgs
(
t
,
addRequiredArgs
())
defaultCfg
:=
config
.
NewConfig
(
&
chaincfg
.
Goerli
,
"genesis.json"
,
common
.
HexToHash
(
l1HeadValue
),
common
.
HexToHash
(
l2HeadValue
))
defaultCfg
:=
config
.
NewConfig
(
&
chaincfg
.
Goerli
,
"genesis.json"
,
common
.
HexToHash
(
l1HeadValue
),
common
.
HexToHash
(
l2HeadValue
),
common
.
HexToHash
(
l2ClaimValue
))
require
.
Equal
(
t
,
defaultCfg
,
cfg
)
require
.
Equal
(
t
,
defaultCfg
,
cfg
)
}
}
...
@@ -167,11 +173,26 @@ func TestL1RPCKind(t *testing.T) {
...
@@ -167,11 +173,26 @@ func TestL1RPCKind(t *testing.T) {
// Offline support will be added later, but for now it just bails out with an error
// Offline support will be added later, but for now it just bails out with an error
func
TestOfflineModeNotSupported
(
t
*
testing
.
T
)
{
func
TestOfflineModeNotSupported
(
t
*
testing
.
T
)
{
logger
:=
log
.
New
()
logger
:=
log
.
New
()
cfg
:=
config
.
NewConfig
(
&
chaincfg
.
Goerli
,
"genesis.json"
,
common
.
HexToHash
(
l1HeadValue
),
common
.
HexToHash
(
l2HeadValue
))
cfg
:=
config
.
NewConfig
(
&
chaincfg
.
Goerli
,
"genesis.json"
,
common
.
HexToHash
(
l1HeadValue
),
common
.
HexToHash
(
l2HeadValue
)
,
common
.
HexToHash
(
l2ClaimValue
)
)
err
:=
FaultProofProgram
(
logger
,
cfg
)
err
:=
FaultProofProgram
(
logger
,
cfg
)
require
.
ErrorContains
(
t
,
err
,
"offline mode not supported"
)
require
.
ErrorContains
(
t
,
err
,
"offline mode not supported"
)
}
}
func
TestL2Claim
(
t
*
testing
.
T
)
{
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"flag l2.claim is required"
,
addRequiredArgsExcept
(
"--l2.claim"
))
})
t
.
Run
(
"Valid"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
replaceRequiredArg
(
"--l2.claim"
,
l2ClaimValue
))
require
.
EqualValues
(
t
,
common
.
HexToHash
(
l2ClaimValue
),
cfg
.
L2Claim
)
})
t
.
Run
(
"Invalid"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
config
.
ErrInvalidL2Claim
.
Error
(),
replaceRequiredArg
(
"--l2.claim"
,
"something"
))
})
}
func
verifyArgsInvalid
(
t
*
testing
.
T
,
messageContains
string
,
cliArgs
[]
string
)
{
func
verifyArgsInvalid
(
t
*
testing
.
T
,
messageContains
string
,
cliArgs
[]
string
)
{
_
,
_
,
err
:=
runWithArgs
(
cliArgs
)
_
,
_
,
err
:=
runWithArgs
(
cliArgs
)
require
.
ErrorContains
(
t
,
err
,
messageContains
)
require
.
ErrorContains
(
t
,
err
,
messageContains
)
...
@@ -220,6 +241,7 @@ func requiredArgs() map[string]string {
...
@@ -220,6 +241,7 @@ func requiredArgs() map[string]string {
"--network"
:
"goerli"
,
"--network"
:
"goerli"
,
"--l1.head"
:
l1HeadValue
,
"--l1.head"
:
l1HeadValue
,
"--l2.head"
:
l2HeadValue
,
"--l2.head"
:
l2HeadValue
,
"--l2.claim"
:
l2ClaimValue
,
"--l2.genesis"
:
"genesis.json"
,
"--l2.genesis"
:
"genesis.json"
,
}
}
}
}
...
...
op-program/host/config/config.go
View file @
fb96cf4a
...
@@ -17,6 +17,7 @@ var (
...
@@ -17,6 +17,7 @@ var (
ErrInvalidL1Head
=
errors
.
New
(
"invalid l1 head"
)
ErrInvalidL1Head
=
errors
.
New
(
"invalid l1 head"
)
ErrInvalidL2Head
=
errors
.
New
(
"invalid l2 head"
)
ErrInvalidL2Head
=
errors
.
New
(
"invalid l2 head"
)
ErrL1AndL2Inconsistent
=
errors
.
New
(
"l1 and l2 options must be specified together or both omitted"
)
ErrL1AndL2Inconsistent
=
errors
.
New
(
"l1 and l2 options must be specified together or both omitted"
)
ErrInvalidL2Claim
=
errors
.
New
(
"invalid l2 claim"
)
)
)
type
Config
struct
{
type
Config
struct
{
...
@@ -25,6 +26,7 @@ type Config struct {
...
@@ -25,6 +26,7 @@ type Config struct {
L2GenesisPath
string
L2GenesisPath
string
L1Head
common
.
Hash
L1Head
common
.
Hash
L2Head
common
.
Hash
L2Head
common
.
Hash
L2Claim
common
.
Hash
L1URL
string
L1URL
string
L1TrustRPC
bool
L1TrustRPC
bool
L1RPCKind
sources
.
RPCProviderKind
L1RPCKind
sources
.
RPCProviderKind
...
@@ -43,6 +45,9 @@ func (c *Config) Check() error {
...
@@ -43,6 +45,9 @@ func (c *Config) Check() error {
if
c
.
L2Head
==
(
common
.
Hash
{})
{
if
c
.
L2Head
==
(
common
.
Hash
{})
{
return
ErrInvalidL2Head
return
ErrInvalidL2Head
}
}
if
c
.
L2Claim
==
(
common
.
Hash
{})
{
return
ErrInvalidL2Claim
}
if
c
.
L2GenesisPath
==
""
{
if
c
.
L2GenesisPath
==
""
{
return
ErrMissingL2Genesis
return
ErrMissingL2Genesis
}
}
...
@@ -57,12 +62,13 @@ func (c *Config) FetchingEnabled() bool {
...
@@ -57,12 +62,13 @@ func (c *Config) FetchingEnabled() bool {
}
}
// NewConfig creates a Config with all optional values set to the CLI default value
// NewConfig creates a Config with all optional values set to the CLI default value
func
NewConfig
(
rollupCfg
*
rollup
.
Config
,
l2GenesisPath
string
,
l1Head
common
.
Hash
,
l2Head
common
.
Hash
)
*
Config
{
func
NewConfig
(
rollupCfg
*
rollup
.
Config
,
l2GenesisPath
string
,
l1Head
common
.
Hash
,
l2Head
common
.
Hash
,
l2Claim
common
.
Hash
)
*
Config
{
return
&
Config
{
return
&
Config
{
Rollup
:
rollupCfg
,
Rollup
:
rollupCfg
,
L2GenesisPath
:
l2GenesisPath
,
L2GenesisPath
:
l2GenesisPath
,
L1Head
:
l1Head
,
L1Head
:
l1Head
,
L2Head
:
l2Head
,
L2Head
:
l2Head
,
L2Claim
:
l2Claim
,
L1RPCKind
:
sources
.
RPCKindBasic
,
L1RPCKind
:
sources
.
RPCKindBasic
,
}
}
}
}
...
@@ -79,6 +85,10 @@ func NewConfigFromCLI(ctx *cli.Context) (*Config, error) {
...
@@ -79,6 +85,10 @@ func NewConfigFromCLI(ctx *cli.Context) (*Config, error) {
if
l2Head
==
(
common
.
Hash
{})
{
if
l2Head
==
(
common
.
Hash
{})
{
return
nil
,
ErrInvalidL2Head
return
nil
,
ErrInvalidL2Head
}
}
l2Claim
:=
common
.
HexToHash
(
ctx
.
GlobalString
(
flags
.
L2Claim
.
Name
))
if
l2Claim
==
(
common
.
Hash
{})
{
return
nil
,
ErrInvalidL2Claim
}
l1Head
:=
common
.
HexToHash
(
ctx
.
GlobalString
(
flags
.
L1Head
.
Name
))
l1Head
:=
common
.
HexToHash
(
ctx
.
GlobalString
(
flags
.
L1Head
.
Name
))
if
l1Head
==
(
common
.
Hash
{})
{
if
l1Head
==
(
common
.
Hash
{})
{
return
nil
,
ErrInvalidL1Head
return
nil
,
ErrInvalidL1Head
...
@@ -88,6 +98,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*Config, error) {
...
@@ -88,6 +98,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*Config, error) {
L2URL
:
ctx
.
GlobalString
(
flags
.
L2NodeAddr
.
Name
),
L2URL
:
ctx
.
GlobalString
(
flags
.
L2NodeAddr
.
Name
),
L2GenesisPath
:
ctx
.
GlobalString
(
flags
.
L2GenesisPath
.
Name
),
L2GenesisPath
:
ctx
.
GlobalString
(
flags
.
L2GenesisPath
.
Name
),
L2Head
:
l2Head
,
L2Head
:
l2Head
,
L2Claim
:
l2Claim
,
L1Head
:
l1Head
,
L1Head
:
l1Head
,
L1URL
:
ctx
.
GlobalString
(
flags
.
L1NodeAddr
.
Name
),
L1URL
:
ctx
.
GlobalString
(
flags
.
L1NodeAddr
.
Name
),
L1TrustRPC
:
ctx
.
GlobalBool
(
flags
.
L1TrustRPC
.
Name
),
L1TrustRPC
:
ctx
.
GlobalBool
(
flags
.
L1TrustRPC
.
Name
),
...
...
op-program/host/config/config_test.go
View file @
fb96cf4a
...
@@ -11,58 +11,78 @@ import (
...
@@ -11,58 +11,78 @@ import (
var
validRollupConfig
=
&
chaincfg
.
Goerli
var
validRollupConfig
=
&
chaincfg
.
Goerli
var
validL2GenesisPath
=
"genesis.json"
var
validL2GenesisPath
=
"genesis.json"
var
validL1Head
=
common
.
HexToHash
(
"0x112233889988FF"
)
var
validL1Head
=
common
.
Hash
{
0xaa
}
var
validL2Head
=
common
.
HexToHash
(
"0x6303578b1fa9480389c51bbcef6fe045bb877da39740819e9eb5f36f94949bd0"
)
var
validL2Head
=
common
.
Hash
{
0xbb
}
var
validL2Claim
=
common
.
Hash
{
0xcc
}
func
TestDefaultConfigIsValid
(
t
*
testing
.
T
)
{
func
TestDefaultConfigIsValid
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
validRollupConfig
,
validL2GenesisPath
,
validL1Head
,
validL2Head
)
.
Check
()
err
:=
validConfig
(
)
.
Check
()
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
}
}
func
TestRollupConfig
(
t
*
testing
.
T
)
{
func
TestRollupConfig
(
t
*
testing
.
T
)
{
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
nil
,
validL2GenesisPath
,
validL1Head
,
validL2Head
)
.
Check
()
config
:=
validConfig
()
config
.
Rollup
=
nil
err
:=
config
.
Check
()
require
.
ErrorIs
(
t
,
err
,
ErrMissingRollupConfig
)
require
.
ErrorIs
(
t
,
err
,
ErrMissingRollupConfig
)
})
})
t
.
Run
(
"Invalid"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"Invalid"
,
func
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
&
rollup
.
Config
{},
validL2GenesisPath
,
validL1Head
,
validL2Head
)
.
Check
()
config
:=
validConfig
()
config
.
Rollup
=
&
rollup
.
Config
{}
err
:=
config
.
Check
()
require
.
ErrorIs
(
t
,
err
,
rollup
.
ErrBlockTimeZero
)
require
.
ErrorIs
(
t
,
err
,
rollup
.
ErrBlockTimeZero
)
})
})
}
}
func
TestL1HeadRequired
(
t
*
testing
.
T
)
{
func
TestL1HeadRequired
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
validRollupConfig
,
validL2GenesisPath
,
common
.
Hash
{},
validL2Head
)
.
Check
()
config
:=
validConfig
()
config
.
L1Head
=
common
.
Hash
{}
err
:=
config
.
Check
()
require
.
ErrorIs
(
t
,
err
,
ErrInvalidL1Head
)
require
.
ErrorIs
(
t
,
err
,
ErrInvalidL1Head
)
}
}
func
TestL2HeadRequired
(
t
*
testing
.
T
)
{
func
TestL2HeadRequired
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
validRollupConfig
,
validL2GenesisPath
,
validL1Head
,
common
.
Hash
{})
.
Check
()
config
:=
validConfig
()
config
.
L2Head
=
common
.
Hash
{}
err
:=
config
.
Check
()
require
.
ErrorIs
(
t
,
err
,
ErrInvalidL2Head
)
require
.
ErrorIs
(
t
,
err
,
ErrInvalidL2Head
)
}
}
func
TestL2ClaimRequired
(
t
*
testing
.
T
)
{
config
:=
validConfig
()
config
.
L2Claim
=
common
.
Hash
{}
err
:=
config
.
Check
()
require
.
ErrorIs
(
t
,
err
,
ErrInvalidL2Claim
)
}
func
TestL2GenesisRequired
(
t
*
testing
.
T
)
{
func
TestL2GenesisRequired
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
validRollupConfig
,
""
,
validL1Head
,
validL2Head
)
.
Check
()
config
:=
validConfig
()
config
.
L2GenesisPath
=
""
err
:=
config
.
Check
()
require
.
ErrorIs
(
t
,
err
,
ErrMissingL2Genesis
)
require
.
ErrorIs
(
t
,
err
,
ErrMissingL2Genesis
)
}
}
func
TestFetchingArgConsistency
(
t
*
testing
.
T
)
{
func
TestFetchingArgConsistency
(
t
*
testing
.
T
)
{
t
.
Run
(
"RequireL2WhenL1Set"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"RequireL2WhenL1Set"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL1Head
,
validL2Head
)
cfg
:=
validConfig
(
)
cfg
.
L1URL
=
"https://example.com:1234"
cfg
.
L1URL
=
"https://example.com:1234"
require
.
ErrorIs
(
t
,
cfg
.
Check
(),
ErrL1AndL2Inconsistent
)
require
.
ErrorIs
(
t
,
cfg
.
Check
(),
ErrL1AndL2Inconsistent
)
})
})
t
.
Run
(
"RequireL1WhenL2Set"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"RequireL1WhenL2Set"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL1Head
,
validL2Head
)
cfg
:=
validConfig
(
)
cfg
.
L2URL
=
"https://example.com:1234"
cfg
.
L2URL
=
"https://example.com:1234"
require
.
ErrorIs
(
t
,
cfg
.
Check
(),
ErrL1AndL2Inconsistent
)
require
.
ErrorIs
(
t
,
cfg
.
Check
(),
ErrL1AndL2Inconsistent
)
})
})
t
.
Run
(
"AllowNeitherSet"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"AllowNeitherSet"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL1Head
,
validL2Head
)
cfg
:=
validConfig
()
cfg
.
L1URL
=
""
cfg
.
L2URL
=
""
require
.
NoError
(
t
,
cfg
.
Check
())
require
.
NoError
(
t
,
cfg
.
Check
())
})
})
t
.
Run
(
"AllowBothSet"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"AllowBothSet"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL1Head
,
validL2Head
)
cfg
:=
validConfig
(
)
cfg
.
L1URL
=
"https://example.com:1234"
cfg
.
L1URL
=
"https://example.com:1234"
cfg
.
L2URL
=
"https://example.com:4678"
cfg
.
L2URL
=
"https://example.com:4678"
require
.
NoError
(
t
,
cfg
.
Check
())
require
.
NoError
(
t
,
cfg
.
Check
())
...
@@ -71,32 +91,36 @@ func TestFetchingArgConsistency(t *testing.T) {
...
@@ -71,32 +91,36 @@ func TestFetchingArgConsistency(t *testing.T) {
func
TestFetchingEnabled
(
t
*
testing
.
T
)
{
func
TestFetchingEnabled
(
t
*
testing
.
T
)
{
t
.
Run
(
"FetchingNotEnabledWhenNoFetcherUrlsSpecified"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"FetchingNotEnabledWhenNoFetcherUrlsSpecified"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL1Head
,
validL2Head
)
cfg
:=
validConfig
(
)
require
.
False
(
t
,
cfg
.
FetchingEnabled
(),
"Should not enable fetching when node URL not supplied"
)
require
.
False
(
t
,
cfg
.
FetchingEnabled
(),
"Should not enable fetching when node URL not supplied"
)
})
})
t
.
Run
(
"FetchingEnabledWhenFetcherUrlsSpecified"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"FetchingEnabledWhenFetcherUrlsSpecified"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL1Head
,
validL2Head
)
cfg
:=
validConfig
(
)
cfg
.
L2URL
=
"https://example.com:1234"
cfg
.
L2URL
=
"https://example.com:1234"
require
.
False
(
t
,
cfg
.
FetchingEnabled
(),
"Should not enable fetching when node URL not supplied"
)
require
.
False
(
t
,
cfg
.
FetchingEnabled
(),
"Should not enable fetching when node URL not supplied"
)
})
})
t
.
Run
(
"FetchingNotEnabledWhenNoL1UrlSpecified"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"FetchingNotEnabledWhenNoL1UrlSpecified"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL1Head
,
validL2Head
)
cfg
:=
validConfig
(
)
cfg
.
L2URL
=
"https://example.com:1234"
cfg
.
L2URL
=
"https://example.com:1234"
require
.
False
(
t
,
cfg
.
FetchingEnabled
(),
"Should not enable L1 fetching when L1 node URL not supplied"
)
require
.
False
(
t
,
cfg
.
FetchingEnabled
(),
"Should not enable L1 fetching when L1 node URL not supplied"
)
})
})
t
.
Run
(
"FetchingNotEnabledWhenNoL2UrlSpecified"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"FetchingNotEnabledWhenNoL2UrlSpecified"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL1Head
,
validL2Head
)
cfg
:=
validConfig
(
)
cfg
.
L1URL
=
"https://example.com:1234"
cfg
.
L1URL
=
"https://example.com:1234"
require
.
False
(
t
,
cfg
.
FetchingEnabled
(),
"Should not enable L2 fetching when L2 node URL not supplied"
)
require
.
False
(
t
,
cfg
.
FetchingEnabled
(),
"Should not enable L2 fetching when L2 node URL not supplied"
)
})
})
t
.
Run
(
"FetchingEnabledWhenBothFetcherUrlsSpecified"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"FetchingEnabledWhenBothFetcherUrlsSpecified"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL1Head
,
validL2Head
)
cfg
:=
validConfig
(
)
cfg
.
L1URL
=
"https://example.com:1234"
cfg
.
L1URL
=
"https://example.com:1234"
cfg
.
L2URL
=
"https://example.com:5678"
cfg
.
L2URL
=
"https://example.com:5678"
require
.
True
(
t
,
cfg
.
FetchingEnabled
(),
"Should enable fetching when node URL supplied"
)
require
.
True
(
t
,
cfg
.
FetchingEnabled
(),
"Should enable fetching when node URL supplied"
)
})
})
}
}
func
validConfig
()
*
Config
{
return
NewConfig
(
validRollupConfig
,
validL2GenesisPath
,
validL1Head
,
validL2Head
,
validL2Claim
)
}
op-program/host/flags/flags.go
View file @
fb96cf4a
...
@@ -41,6 +41,11 @@ var (
...
@@ -41,6 +41,11 @@ var (
Usage
:
"Hash of the agreed L2 block to start derivation from"
,
Usage
:
"Hash of the agreed L2 block to start derivation from"
,
EnvVar
:
service
.
PrefixEnvVar
(
envVarPrefix
,
"L2_HEAD"
),
EnvVar
:
service
.
PrefixEnvVar
(
envVarPrefix
,
"L2_HEAD"
),
}
}
L2Claim
=
cli
.
StringFlag
{
Name
:
"l2.claim"
,
Usage
:
"Claimed L2 output root to validate"
,
EnvVar
:
service
.
PrefixEnvVar
(
envVarPrefix
,
"L2_CLAIM"
),
}
L2GenesisPath
=
cli
.
StringFlag
{
L2GenesisPath
=
cli
.
StringFlag
{
Name
:
"l2.genesis"
,
Name
:
"l2.genesis"
,
Usage
:
"Path to the op-geth genesis file"
,
Usage
:
"Path to the op-geth genesis file"
,
...
@@ -71,13 +76,16 @@ var (
...
@@ -71,13 +76,16 @@ var (
// Flags contains the list of configuration options available to the binary.
// Flags contains the list of configuration options available to the binary.
var
Flags
[]
cli
.
Flag
var
Flags
[]
cli
.
Flag
var
requiredFlags
=
[]
cli
.
Flag
{
L1Head
,
L2Head
,
L2Claim
,
L2GenesisPath
,
}
var
programFlags
=
[]
cli
.
Flag
{
var
programFlags
=
[]
cli
.
Flag
{
RollupConfig
,
RollupConfig
,
Network
,
Network
,
L2NodeAddr
,
L2NodeAddr
,
L1Head
,
L2Head
,
L2GenesisPath
,
L1NodeAddr
,
L1NodeAddr
,
L1TrustRPC
,
L1TrustRPC
,
L1RPCProviderKind
,
L1RPCProviderKind
,
...
@@ -85,6 +93,7 @@ var programFlags = []cli.Flag{
...
@@ -85,6 +93,7 @@ var programFlags = []cli.Flag{
func
init
()
{
func
init
()
{
Flags
=
append
(
Flags
,
oplog
.
CLIFlags
(
envVarPrefix
)
...
)
Flags
=
append
(
Flags
,
oplog
.
CLIFlags
(
envVarPrefix
)
...
)
Flags
=
append
(
Flags
,
requiredFlags
...
)
Flags
=
append
(
Flags
,
programFlags
...
)
Flags
=
append
(
Flags
,
programFlags
...
)
}
}
...
@@ -97,14 +106,10 @@ func CheckRequired(ctx *cli.Context) error {
...
@@ -97,14 +106,10 @@ func CheckRequired(ctx *cli.Context) error {
if
rollupConfig
!=
""
&&
network
!=
""
{
if
rollupConfig
!=
""
&&
network
!=
""
{
return
fmt
.
Errorf
(
"cannot specify both %s and %s"
,
RollupConfig
.
Name
,
Network
.
Name
)
return
fmt
.
Errorf
(
"cannot specify both %s and %s"
,
RollupConfig
.
Name
,
Network
.
Name
)
}
}
if
ctx
.
GlobalString
(
L2GenesisPath
.
Name
)
==
""
{
for
_
,
flag
:=
range
requiredFlags
{
return
fmt
.
Errorf
(
"flag %s is required"
,
L2GenesisPath
.
Name
)
if
ctx
.
GlobalString
(
flag
.
GetName
())
==
""
{
}
return
fmt
.
Errorf
(
"flag %s is required"
,
flag
.
GetName
())
if
ctx
.
GlobalString
(
L2Head
.
Name
)
==
""
{
return
fmt
.
Errorf
(
"flag %s is required"
,
L2Head
.
Name
)
}
}
if
ctx
.
GlobalString
(
L1Head
.
Name
)
==
""
{
return
fmt
.
Errorf
(
"flag %s is required"
,
L1Head
.
Name
)
}
}
return
nil
return
nil
}
}
op-program/host/l1/fetcher.go
View file @
fb96cf4a
...
@@ -30,7 +30,7 @@ func NewFetchingL1Oracle(ctx context.Context, logger log.Logger, source Source)
...
@@ -30,7 +30,7 @@ func NewFetchingL1Oracle(ctx context.Context, logger log.Logger, source Source)
}
}
}
}
func
(
o
FetchingL1Oracle
)
HeaderByBlockHash
(
blockHash
common
.
Hash
)
eth
.
BlockInfo
{
func
(
o
*
FetchingL1Oracle
)
HeaderByBlockHash
(
blockHash
common
.
Hash
)
eth
.
BlockInfo
{
o
.
logger
.
Trace
(
"HeaderByBlockHash"
,
"hash"
,
blockHash
)
o
.
logger
.
Trace
(
"HeaderByBlockHash"
,
"hash"
,
blockHash
)
info
,
err
:=
o
.
source
.
InfoByHash
(
o
.
ctx
,
blockHash
)
info
,
err
:=
o
.
source
.
InfoByHash
(
o
.
ctx
,
blockHash
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -42,7 +42,7 @@ func (o FetchingL1Oracle) HeaderByBlockHash(blockHash common.Hash) eth.BlockInfo
...
@@ -42,7 +42,7 @@ func (o FetchingL1Oracle) HeaderByBlockHash(blockHash common.Hash) eth.BlockInfo
return
info
return
info
}
}
func
(
o
FetchingL1Oracle
)
TransactionsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
)
{
func
(
o
*
FetchingL1Oracle
)
TransactionsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
)
{
o
.
logger
.
Trace
(
"TransactionsByBlockHash"
,
"hash"
,
blockHash
)
o
.
logger
.
Trace
(
"TransactionsByBlockHash"
,
"hash"
,
blockHash
)
info
,
txs
,
err
:=
o
.
source
.
InfoAndTxsByHash
(
o
.
ctx
,
blockHash
)
info
,
txs
,
err
:=
o
.
source
.
InfoAndTxsByHash
(
o
.
ctx
,
blockHash
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -54,7 +54,7 @@ func (o FetchingL1Oracle) TransactionsByBlockHash(blockHash common.Hash) (eth.Bl
...
@@ -54,7 +54,7 @@ func (o FetchingL1Oracle) TransactionsByBlockHash(blockHash common.Hash) (eth.Bl
return
info
,
txs
return
info
,
txs
}
}
func
(
o
FetchingL1Oracle
)
ReceiptsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
)
{
func
(
o
*
FetchingL1Oracle
)
ReceiptsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
)
{
o
.
logger
.
Trace
(
"ReceiptsByBlockHash"
,
"hash"
,
blockHash
)
o
.
logger
.
Trace
(
"ReceiptsByBlockHash"
,
"hash"
,
blockHash
)
info
,
rcpts
,
err
:=
o
.
source
.
FetchReceipts
(
o
.
ctx
,
blockHash
)
info
,
rcpts
,
err
:=
o
.
source
.
FetchReceipts
(
o
.
ctx
,
blockHash
)
if
err
!=
nil
{
if
err
!=
nil
{
...
...
op-program/host/l1/l1.go
View file @
fb96cf4a
...
@@ -21,6 +21,6 @@ func NewFetchingL1(ctx context.Context, logger log.Logger, cfg *config.Config) (
...
@@ -21,6 +21,6 @@ func NewFetchingL1(ctx context.Context, logger log.Logger, cfg *config.Config) (
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
oracle
:=
NewFetchingL1Oracle
(
ctx
,
logger
,
source
)
oracle
:=
cll1
.
NewCachingOracle
(
NewFetchingL1Oracle
(
ctx
,
logger
,
source
)
)
return
cll1
.
NewOracleL1Client
(
logger
,
oracle
,
cfg
.
L1Head
),
err
return
cll1
.
NewOracleL1Client
(
logger
,
oracle
,
cfg
.
L1Head
),
err
}
}
op-program/host/l2/l2.go
View file @
fb96cf4a
...
@@ -6,7 +6,6 @@ import (
...
@@ -6,7 +6,6 @@ import (
"fmt"
"fmt"
"os"
"os"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
cll2
"github.com/ethereum-optimism/optimism/op-program/client/l2"
cll2
"github.com/ethereum-optimism/optimism/op-program/client/l2"
"github.com/ethereum-optimism/optimism/op-program/host/config"
"github.com/ethereum-optimism/optimism/op-program/host/config"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core"
...
@@ -14,15 +13,16 @@ import (
...
@@ -14,15 +13,16 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/params"
)
)
func
NewFetchingEngine
(
ctx
context
.
Context
,
logger
log
.
Logger
,
cfg
*
config
.
Config
)
(
derive
.
Engine
,
error
)
{
func
NewFetchingEngine
(
ctx
context
.
Context
,
logger
log
.
Logger
,
cfg
*
config
.
Config
)
(
*
cll2
.
Oracle
Engine
,
error
)
{
genesis
,
err
:=
loadL2Genesis
(
cfg
)
genesis
,
err
:=
loadL2Genesis
(
cfg
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
oracle
,
err
:=
NewFetchingL2Oracle
(
ctx
,
logger
,
cfg
.
L2URL
,
cfg
.
L2Head
)
fetcher
,
err
:=
NewFetchingL2Oracle
(
ctx
,
logger
,
cfg
.
L2URL
,
cfg
.
L2Head
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"connect l2 oracle: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"connect l2 oracle: %w"
,
err
)
}
}
oracle
:=
cll2
.
NewCachingOracle
(
fetcher
)
engineBackend
,
err
:=
cll2
.
NewOracleBackedL2Chain
(
logger
,
oracle
,
genesis
,
cfg
.
L2Head
)
engineBackend
,
err
:=
cll2
.
NewOracleBackedL2Chain
(
logger
,
oracle
,
genesis
,
cfg
.
L2Head
)
if
err
!=
nil
{
if
err
!=
nil
{
...
...
packages/contracts-bedrock/contracts/L1/SystemConfig.sol
View file @
fb96cf4a
...
@@ -80,7 +80,7 @@ contract SystemConfig is OwnableUpgradeable, Semver {
...
@@ -80,7 +80,7 @@ contract SystemConfig is OwnableUpgradeable, Semver {
event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data);
event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data);
/**
/**
* @custom:semver 1.
2
.0
* @custom:semver 1.
3
.0
*
*
* @param _owner Initial owner of the contract.
* @param _owner Initial owner of the contract.
* @param _overhead Initial overhead value.
* @param _overhead Initial overhead value.
...
@@ -98,7 +98,7 @@ contract SystemConfig is OwnableUpgradeable, Semver {
...
@@ -98,7 +98,7 @@ contract SystemConfig is OwnableUpgradeable, Semver {
uint64 _gasLimit,
uint64 _gasLimit,
address _unsafeBlockSigner,
address _unsafeBlockSigner,
ResourceMetering.ResourceConfig memory _config
ResourceMetering.ResourceConfig memory _config
) Semver(1,
2
, 0) {
) Semver(1,
3
, 0) {
initialize({
initialize({
_owner: _owner,
_owner: _owner,
_overhead: _overhead,
_overhead: _overhead,
...
@@ -270,7 +270,7 @@ contract SystemConfig is OwnableUpgradeable, Semver {
...
@@ -270,7 +270,7 @@ contract SystemConfig is OwnableUpgradeable, Semver {
"SystemConfig: min base fee must be less than max base"
"SystemConfig: min base fee must be less than max base"
);
);
// Base fee change denominator must be greater than 0.
// Base fee change denominator must be greater than 0.
require(_config.baseFeeMaxChangeDenominator >
0, "SystemConfig: denominator cannot be 0
");
require(_config.baseFeeMaxChangeDenominator >
1, "SystemConfig: denominator must be larger than 1
");
// Max resource limit plus system tx gas must be less than or equal to the L2 gas limit.
// Max resource limit plus system tx gas must be less than or equal to the L2 gas limit.
// The gas limit must be increased before these values can be increased.
// The gas limit must be increased before these values can be increased.
require(
require(
...
...
packages/contracts-bedrock/contracts/test/OptimismPortal.t.sol
View file @
fb96cf4a
...
@@ -1085,3 +1085,88 @@ contract OptimismPortalUpgradeable_Test is Portal_Initializer {
...
@@ -1085,3 +1085,88 @@ contract OptimismPortalUpgradeable_Test is Portal_Initializer {
assertEq(slot21Expected, slot21After);
assertEq(slot21Expected, slot21After);
}
}
}
}
/**
* @title OptimismPortalResourceFuzz_Test
* @dev Test various values of the resource metering config to ensure that deposits cannot be
* broken by changing the config.
*/
contract OptimismPortalResourceFuzz_Test is Portal_Initializer {
/**
* @dev The max gas limit observed throughout this test. Setting this too high can cause
* the test to take too long to run.
*/
uint256 constant MAX_GAS_LIMIT = 30_000_000;
/**
* @dev Test that various values of the resource metering config will not break deposits.
*/
function testFuzz_systemConfigDeposit_succeeds(
uint32 _maxResourceLimit,
uint8 _elasticityMultiplier,
uint8 _baseFeeMaxChangeDenominator,
uint32 _minimumBaseFee,
uint32 _systemTxMaxGas,
uint128 _maximumBaseFee,
uint64 _gasLimit,
uint64 _prevBoughtGas,
uint128 _prevBaseFee,
uint8 _blockDiff
) external {
// Get the set system gas limit
uint64 gasLimit = systemConfig.gasLimit();
// Bound resource config
_maxResourceLimit = uint32(bound(_maxResourceLimit, 21000, MAX_GAS_LIMIT / 8));
_gasLimit = uint64(bound( _gasLimit, 21000, _maxResourceLimit));
_prevBaseFee = uint128(bound(_prevBaseFee, 0, 5 gwei));
// Prevent values that would cause reverts
vm.assume(gasLimit >= _gasLimit);
vm.assume(_minimumBaseFee < _maximumBaseFee);
vm.assume(_baseFeeMaxChangeDenominator > 1);
vm.assume(uint256(_maxResourceLimit) + uint256(_systemTxMaxGas) <= gasLimit);
vm.assume(_elasticityMultiplier > 0);
vm.assume(
((_maxResourceLimit / _elasticityMultiplier) * _elasticityMultiplier) == _maxResourceLimit
);
_prevBoughtGas = uint64(bound(_prevBoughtGas, 0, _maxResourceLimit - _gasLimit));
_blockDiff = uint8(bound(_blockDiff, 0, 3));
// Create a resource config to mock the call to the system config with
ResourceMetering.ResourceConfig memory rcfg = ResourceMetering.ResourceConfig({
maxResourceLimit: _maxResourceLimit,
elasticityMultiplier: _elasticityMultiplier,
baseFeeMaxChangeDenominator: _baseFeeMaxChangeDenominator,
minimumBaseFee: _minimumBaseFee,
systemTxMaxGas: _systemTxMaxGas,
maximumBaseFee: _maximumBaseFee
});
vm.mockCall(
address(systemConfig),
abi.encodeWithSelector(systemConfig.resourceConfig.selector),
abi.encode(rcfg)
);
// Set the resource params
uint256 _prevBlockNum = block.number - _blockDiff;
vm.store(
address(op),
bytes32(uint256(1)),
bytes32((_prevBlockNum << 192) | (uint256(_prevBoughtGas) << 128) | _prevBaseFee)
);
// Ensure that the storage setting is correct
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = op.params();
assertEq(prevBaseFee, _prevBaseFee);
assertEq(prevBoughtGas, _prevBoughtGas);
assertEq(prevBlockNum, _prevBlockNum);
// Do a deposit, should not revert
op.depositTransaction{ gas: MAX_GAS_LIMIT }({
_to: address(0x20),
_value: 0x40,
_gasLimit: _gasLimit,
_isCreation: false,
_data: hex""
});
}
}
packages/contracts-bedrock/contracts/test/SystemConfig.t.sol
View file @
fb96cf4a
...
@@ -110,7 +110,7 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
...
@@ -110,7 +110,7 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
maximumBaseFee: 2 gwei
maximumBaseFee: 2 gwei
});
});
vm.prank(sysConf.owner());
vm.prank(sysConf.owner());
vm.expectRevert("SystemConfig: denominator
cannot be 0
");
vm.expectRevert("SystemConfig: denominator
must be larger than 1
");
sysConf.setResourceConfig(config);
sysConf.setResourceConfig(config);
}
}
...
...
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