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
b1c9be0b
Unverified
Commit
b1c9be0b
authored
Apr 11, 2023
by
Adrian Sutton
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
op-program: Wire in L1 oracle
parent
bc37c15e
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
124 additions
and
77 deletions
+124
-77
client.go
op-program/client/l1/client.go
+13
-14
client_test.go
op-program/client/l1/client_test.go
+6
-2
engine_backend.go
op-program/client/l2/engine_backend.go
+1
-0
main_test.go
op-program/host/cmd/main_test.go
+24
-4
config.go
op-program/host/config/config.go
+14
-3
config_test.go
op-program/host/config/config_test.go
+23
-31
flags.go
op-program/host/flags/flags.go
+14
-5
fetcher.go
op-program/host/l1/fetcher.go
+7
-1
fetcher_test.go
op-program/host/l1/fetcher_test.go
+15
-16
l1.go
op-program/host/l1/l1.go
+7
-1
No files found.
op-program/client/l1/client.go
View file @
b1c9be0b
...
...
@@ -6,12 +6,14 @@ import (
"fmt"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
)
var
(
ErrNotFound
=
e
rrors
.
New
(
"not found"
)
ErrNotFound
=
e
thereum
.
NotFound
ErrUnknownLabel
=
errors
.
New
(
"unknown label"
)
)
...
...
@@ -20,8 +22,9 @@ type OracleL1Client struct {
head
eth
.
L1BlockRef
}
func
NewOracleL1Client
(
oracle
Oracle
,
l1Head
common
.
Hash
)
*
OracleL1Client
{
func
NewOracleL1Client
(
logger
log
.
Logger
,
oracle
Oracle
,
l1Head
common
.
Hash
)
*
OracleL1Client
{
head
:=
eth
.
InfoToL1BlockRef
(
oracle
.
HeaderByHash
(
l1Head
))
logger
.
Info
(
"L1 head loaded"
,
"hash"
,
head
.
Hash
,
"number"
,
head
.
Number
)
return
&
OracleL1Client
{
oracle
:
oracle
,
head
:
head
,
...
...
@@ -29,26 +32,22 @@ func NewOracleL1Client(oracle Oracle, l1Head common.Hash) *OracleL1Client {
}
func
(
o
OracleL1Client
)
L1BlockRefByLabel
(
ctx
context
.
Context
,
label
eth
.
BlockLabel
)
(
eth
.
L1BlockRef
,
error
)
{
switch
label
{
case
eth
.
Unsafe
:
return
o
.
head
,
nil
case
eth
.
Safe
:
return
o
.
head
,
nil
case
eth
.
Finalized
:
return
o
.
head
,
nil
}
if
label
!=
eth
.
Unsafe
&&
label
!=
eth
.
Safe
&&
label
!=
eth
.
Finalized
{
return
eth
.
L1BlockRef
{},
fmt
.
Errorf
(
"%w: %s"
,
ErrUnknownLabel
,
label
)
}
// The L1 head is pre-agreed and unchanging so it can be used for all of unsafe, safe and finalized
return
o
.
head
,
nil
}
func
(
o
OracleL1Client
)
L1BlockRefByNumber
(
ctx
context
.
Context
,
number
uint64
)
(
eth
.
L1BlockRef
,
error
)
{
if
number
>
o
.
head
.
Number
{
return
eth
.
L1BlockRef
{},
fmt
.
Errorf
(
"%w: block number %d"
,
ErrNotFound
,
number
)
}
head
:=
o
.
head
for
head
.
Number
>
number
{
head
=
eth
.
InfoToL1BlockRef
(
o
.
oracle
.
HeaderByHash
(
head
.
ParentHash
))
block
:=
o
.
head
for
block
.
Number
>
number
{
block
=
eth
.
InfoToL1BlockRef
(
o
.
oracle
.
HeaderByHash
(
block
.
ParentHash
))
}
return
head
,
nil
return
block
,
nil
}
func
(
o
OracleL1Client
)
L1BlockRefByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
eth
.
L1BlockRef
,
error
)
{
...
...
op-program/client/l1/client_test.go
View file @
b1c9be0b
...
...
@@ -8,9 +8,12 @@ import (
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)
...
...
@@ -110,7 +113,8 @@ func TestL1BlockRefByNumber(t *testing.T) {
t
.
Run
(
"AfterHead"
,
func
(
t
*
testing
.
T
)
{
client
,
_
:=
newClient
(
t
)
ref
,
err
:=
client
.
L1BlockRefByNumber
(
context
.
Background
(),
head
.
NumberU64
()
+
1
)
require
.
ErrorIs
(
t
,
err
,
ErrNotFound
)
// Must be ethereum.NotFound error so the derivation pipeline knows it has gone past the chain head
require
.
ErrorIs
(
t
,
err
,
ethereum
.
NotFound
)
require
.
Equal
(
t
,
eth
.
L1BlockRef
{},
ref
)
})
t
.
Run
(
"ParentOfHead"
,
func
(
t
*
testing
.
T
)
{
...
...
@@ -148,7 +152,7 @@ func newClient(t *testing.T) (*OracleL1Client, *stubOracle) {
rcpts
:
make
(
map
[
common
.
Hash
]
types
.
Receipts
),
}
stub
.
blocks
[
head
.
Hash
()]
=
head
client
:=
NewOracleL1Client
(
stub
,
head
.
Hash
())
client
:=
NewOracleL1Client
(
testlog
.
Logger
(
t
,
log
.
LvlDebug
),
stub
,
head
.
Hash
())
return
client
,
stub
}
...
...
op-program/client/l2/engine_backend.go
View file @
b1c9be0b
...
...
@@ -39,6 +39,7 @@ func NewOracleBackedL2Chain(logger log.Logger, oracle Oracle, chainCfg *params.C
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"loading l2 head: %w"
,
err
)
}
logger
.
Info
(
"Loaded L2 head"
,
"hash"
,
head
.
Hash
(),
"number"
,
head
.
Number
())
return
&
OracleBackedL2Chain
{
log
:
logger
,
oracle
:
oracle
,
...
...
op-program/host/cmd/main_test.go
View file @
b1c9be0b
...
...
@@ -13,7 +13,9 @@ import (
"github.com/stretchr/testify/require"
)
var
l2HeadValue
=
"0x6303578b1fa9480389c51bbcef6fe045bb877da39740819e9eb5f36f94949bd0"
// Use HexToHash(...).Hex() to ensure the strings are the correct length for a hash
var
l1HeadValue
=
common
.
HexToHash
(
"0x111111"
)
.
Hex
()
var
l2HeadValue
=
common
.
HexToHash
(
"0x222222"
)
.
Hex
()
func
TestLogLevel
(
t
*
testing
.
T
)
{
t
.
Run
(
"RejectInvalid"
,
func
(
t
*
testing
.
T
)
{
...
...
@@ -32,7 +34,8 @@ func TestLogLevel(t *testing.T) {
func
TestDefaultCLIOptionsMatchDefaultConfig
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
addRequiredArgs
())
require
.
Equal
(
t
,
config
.
NewConfig
(
&
chaincfg
.
Goerli
,
"genesis.json"
,
common
.
HexToHash
(
l2HeadValue
)),
cfg
)
defaultCfg
:=
config
.
NewConfig
(
&
chaincfg
.
Goerli
,
"genesis.json"
,
common
.
HexToHash
(
l1HeadValue
),
common
.
HexToHash
(
l2HeadValue
))
require
.
Equal
(
t
,
defaultCfg
,
cfg
)
}
func
TestNetwork
(
t
*
testing
.
T
)
{
...
...
@@ -102,6 +105,21 @@ func TestL2Head(t *testing.T) {
})
}
func
TestL1Head
(
t
*
testing
.
T
)
{
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
"flag l1.head is required"
,
addRequiredArgsExcept
(
"--l1.head"
))
})
t
.
Run
(
"Valid"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
configForArgs
(
t
,
replaceRequiredArg
(
"--l1.head"
,
l1HeadValue
))
require
.
Equal
(
t
,
common
.
HexToHash
(
l1HeadValue
),
cfg
.
L1Head
)
})
t
.
Run
(
"Invalid"
,
func
(
t
*
testing
.
T
)
{
verifyArgsInvalid
(
t
,
config
.
ErrInvalidL1Head
.
Error
(),
replaceRequiredArg
(
"--l1.head"
,
"something"
))
})
}
func
TestL1
(
t
*
testing
.
T
)
{
expected
:=
"https://example.com:8545"
cfg
:=
configForArgs
(
t
,
addRequiredArgs
(
"--l1"
,
expected
))
...
...
@@ -149,7 +167,8 @@ func TestL1RPCKind(t *testing.T) {
// Offline support will be added later, but for now it just bails out with an error
func
TestOfflineModeNotSupported
(
t
*
testing
.
T
)
{
logger
:=
log
.
New
()
err
:=
FaultProofProgram
(
logger
,
config
.
NewConfig
(
&
chaincfg
.
Goerli
,
"genesis.json"
,
common
.
HexToHash
(
l2HeadValue
)))
cfg
:=
config
.
NewConfig
(
&
chaincfg
.
Goerli
,
"genesis.json"
,
common
.
HexToHash
(
l1HeadValue
),
common
.
HexToHash
(
l2HeadValue
))
err
:=
FaultProofProgram
(
logger
,
cfg
)
require
.
ErrorContains
(
t
,
err
,
"offline mode not supported"
)
}
...
...
@@ -199,8 +218,9 @@ func replaceRequiredArg(name string, value string) []string {
func
requiredArgs
()
map
[
string
]
string
{
return
map
[
string
]
string
{
"--network"
:
"goerli"
,
"--l
2.genesis"
:
"genesis.json"
,
"--l
1.head"
:
l1HeadValue
,
"--l2.head"
:
l2HeadValue
,
"--l2.genesis"
:
"genesis.json"
,
}
}
...
...
op-program/host/config/config.go
View file @
b1c9be0b
...
...
@@ -14,6 +14,7 @@ import (
var
(
ErrMissingRollupConfig
=
errors
.
New
(
"missing rollup config"
)
ErrMissingL2Genesis
=
errors
.
New
(
"missing l2 genesis"
)
ErrInvalidL1Head
=
errors
.
New
(
"invalid l1 head"
)
ErrInvalidL2Head
=
errors
.
New
(
"invalid l2 head"
)
ErrL1AndL2Inconsistent
=
errors
.
New
(
"l1 and l2 options must be specified together or both omitted"
)
)
...
...
@@ -22,6 +23,7 @@ type Config struct {
Rollup
*
rollup
.
Config
L2URL
string
L2GenesisPath
string
L1Head
common
.
Hash
L2Head
common
.
Hash
L1URL
string
L1TrustRPC
bool
...
...
@@ -35,12 +37,15 @@ func (c *Config) Check() error {
if
err
:=
c
.
Rollup
.
Check
();
err
!=
nil
{
return
err
}
if
c
.
L
2GenesisPath
==
""
{
return
Err
MissingL2Genesis
if
c
.
L
1Head
==
(
common
.
Hash
{})
{
return
Err
InvalidL1Head
}
if
c
.
L2Head
==
(
common
.
Hash
{})
{
return
ErrInvalidL2Head
}
if
c
.
L2GenesisPath
==
""
{
return
ErrMissingL2Genesis
}
if
(
c
.
L1URL
!=
""
)
!=
(
c
.
L2URL
!=
""
)
{
return
ErrL1AndL2Inconsistent
}
...
...
@@ -52,10 +57,11 @@ func (c *Config) FetchingEnabled() bool {
}
// NewConfig creates a Config with all optional values set to the CLI default value
func
NewConfig
(
rollupCfg
*
rollup
.
Config
,
l2GenesisPath
string
,
l2Head
common
.
Hash
)
*
Config
{
func
NewConfig
(
rollupCfg
*
rollup
.
Config
,
l2GenesisPath
string
,
l
1Head
common
.
Hash
,
l
2Head
common
.
Hash
)
*
Config
{
return
&
Config
{
Rollup
:
rollupCfg
,
L2GenesisPath
:
l2GenesisPath
,
L1Head
:
l1Head
,
L2Head
:
l2Head
,
L1RPCKind
:
sources
.
RPCKindBasic
,
}
...
...
@@ -73,11 +79,16 @@ func NewConfigFromCLI(ctx *cli.Context) (*Config, error) {
if
l2Head
==
(
common
.
Hash
{})
{
return
nil
,
ErrInvalidL2Head
}
l1Head
:=
common
.
HexToHash
(
ctx
.
GlobalString
(
flags
.
L1Head
.
Name
))
if
l1Head
==
(
common
.
Hash
{})
{
return
nil
,
ErrInvalidL1Head
}
return
&
Config
{
Rollup
:
rollupCfg
,
L2URL
:
ctx
.
GlobalString
(
flags
.
L2NodeAddr
.
Name
),
L2GenesisPath
:
ctx
.
GlobalString
(
flags
.
L2GenesisPath
.
Name
),
L2Head
:
l2Head
,
L1Head
:
l1Head
,
L1URL
:
ctx
.
GlobalString
(
flags
.
L1NodeAddr
.
Name
),
L1TrustRPC
:
ctx
.
GlobalBool
(
flags
.
L1TrustRPC
.
Name
),
L1RPCKind
:
sources
.
RPCProviderKind
(
ctx
.
GlobalString
(
flags
.
L1RPCProviderKind
.
Name
)),
...
...
op-program/host/config/config_test.go
View file @
b1c9be0b
...
...
@@ -11,66 +11,58 @@ import (
var
validRollupConfig
=
&
chaincfg
.
Goerli
var
validL2GenesisPath
=
"genesis.json"
var
validL1Head
=
common
.
HexToHash
(
"0x112233889988FF"
)
var
validL2Head
=
common
.
HexToHash
(
"0x6303578b1fa9480389c51bbcef6fe045bb877da39740819e9eb5f36f94949bd0"
)
func
TestDefaultConfigIsValid
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
validRollupConfig
,
validL2GenesisPath
,
validL2Head
)
.
Check
()
err
:=
NewConfig
(
validRollupConfig
,
validL2GenesisPath
,
validL
1Head
,
validL
2Head
)
.
Check
()
require
.
NoError
(
t
,
err
)
}
func
TestRollupConfig
(
t
*
testing
.
T
)
{
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
nil
,
validL2GenesisPath
,
validL2Head
)
.
Check
()
err
:=
NewConfig
(
nil
,
validL2GenesisPath
,
validL
1Head
,
validL
2Head
)
.
Check
()
require
.
ErrorIs
(
t
,
err
,
ErrMissingRollupConfig
)
})
t
.
Run
(
"Invalid"
,
func
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
&
rollup
.
Config
{},
validL2GenesisPath
,
validL2Head
)
.
Check
()
err
:=
NewConfig
(
&
rollup
.
Config
{},
validL2GenesisPath
,
validL
1Head
,
validL
2Head
)
.
Check
()
require
.
ErrorIs
(
t
,
err
,
rollup
.
ErrBlockTimeZero
)
})
}
func
TestL2Genesis
(
t
*
testing
.
T
)
{
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
validRollupConfig
,
""
,
validL2Head
)
.
Check
()
require
.
ErrorIs
(
t
,
err
,
ErrMissingL2Genesis
)
})
t
.
Run
(
"Valid"
,
func
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
validRollupConfig
,
validL2GenesisPath
,
validL2Head
)
.
Check
()
require
.
NoError
(
t
,
err
)
})
func
TestL1HeadRequired
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
validRollupConfig
,
validL2GenesisPath
,
common
.
Hash
{},
validL2Head
)
.
Check
()
require
.
ErrorIs
(
t
,
err
,
ErrInvalidL1Head
)
}
func
TestL2Head
(
t
*
testing
.
T
)
{
t
.
Run
(
"Required"
,
func
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
validRollupConfig
,
validL2GenesisPath
,
common
.
Hash
{})
.
Check
()
func
TestL2HeadRequired
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
validRollupConfig
,
validL2GenesisPath
,
validL1Head
,
common
.
Hash
{})
.
Check
()
require
.
ErrorIs
(
t
,
err
,
ErrInvalidL2Head
)
})
}
t
.
Run
(
"Valid"
,
func
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
validRollupConfig
,
validL2GenesisPath
,
validL2Head
)
.
Check
()
require
.
NoError
(
t
,
err
)
})
func
TestL2GenesisRequired
(
t
*
testing
.
T
)
{
err
:=
NewConfig
(
validRollupConfig
,
""
,
validL1Head
,
validL2Head
)
.
Check
()
require
.
ErrorIs
(
t
,
err
,
ErrMissingL2Genesis
)
}
func
TestFetchingArgConsistency
(
t
*
testing
.
T
)
{
t
.
Run
(
"RequireL2WhenL1Set"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL2Head
)
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL
1Head
,
validL
2Head
)
cfg
.
L1URL
=
"https://example.com:1234"
require
.
ErrorIs
(
t
,
cfg
.
Check
(),
ErrL1AndL2Inconsistent
)
})
t
.
Run
(
"RequireL1WhenL2Set"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL2Head
)
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL
1Head
,
validL
2Head
)
cfg
.
L2URL
=
"https://example.com:1234"
require
.
ErrorIs
(
t
,
cfg
.
Check
(),
ErrL1AndL2Inconsistent
)
})
t
.
Run
(
"AllowNeitherSet"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL2Head
)
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL
1Head
,
validL
2Head
)
require
.
NoError
(
t
,
cfg
.
Check
())
})
t
.
Run
(
"AllowBothSet"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL2Head
)
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL
1Head
,
validL
2Head
)
cfg
.
L1URL
=
"https://example.com:1234"
cfg
.
L2URL
=
"https://example.com:4678"
require
.
NoError
(
t
,
cfg
.
Check
())
...
...
@@ -79,30 +71,30 @@ func TestFetchingArgConsistency(t *testing.T) {
func
TestFetchingEnabled
(
t
*
testing
.
T
)
{
t
.
Run
(
"FetchingNotEnabledWhenNoFetcherUrlsSpecified"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL2Head
)
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL
1Head
,
validL
2Head
)
require
.
False
(
t
,
cfg
.
FetchingEnabled
(),
"Should not enable fetching when node URL not supplied"
)
})
t
.
Run
(
"FetchingEnabledWhenFetcherUrlsSpecified"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL2Head
)
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL
1Head
,
validL
2Head
)
cfg
.
L2URL
=
"https://example.com:1234"
require
.
False
(
t
,
cfg
.
FetchingEnabled
(),
"Should not enable fetching when node URL not supplied"
)
})
t
.
Run
(
"FetchingNotEnabledWhenNoL1UrlSpecified"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL2Head
)
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL
1Head
,
validL
2Head
)
cfg
.
L2URL
=
"https://example.com:1234"
require
.
False
(
t
,
cfg
.
FetchingEnabled
(),
"Should not enable L1 fetching when L1 node URL not supplied"
)
})
t
.
Run
(
"FetchingNotEnabledWhenNoL2UrlSpecified"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL2Head
)
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL
1Head
,
validL
2Head
)
cfg
.
L1URL
=
"https://example.com:1234"
require
.
False
(
t
,
cfg
.
FetchingEnabled
(),
"Should not enable L2 fetching when L2 node URL not supplied"
)
})
t
.
Run
(
"FetchingEnabledWhenBothFetcherUrlsSpecified"
,
func
(
t
*
testing
.
T
)
{
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL2Head
)
cfg
:=
NewConfig
(
&
chaincfg
.
Beta1
,
validL2GenesisPath
,
validL
1Head
,
validL
2Head
)
cfg
.
L1URL
=
"https://example.com:1234"
cfg
.
L2URL
=
"https://example.com:5678"
require
.
True
(
t
,
cfg
.
FetchingEnabled
(),
"Should enable fetching when node URL supplied"
)
...
...
op-program/host/flags/flags.go
View file @
b1c9be0b
...
...
@@ -31,16 +31,21 @@ var (
Usage
:
"Address of L2 JSON-RPC endpoint to use (eth and debug namespace required)"
,
EnvVar
:
service
.
PrefixEnvVar
(
envVarPrefix
,
"L2_RPC"
),
}
L
2GenesisPath
=
cli
.
StringFlag
{
Name
:
"l
2.genesis
"
,
Usage
:
"
Path to the op-geth genesis file
"
,
EnvVar
:
service
.
PrefixEnvVar
(
envVarPrefix
,
"L
2_GENESIS
"
),
L
1Head
=
cli
.
StringFlag
{
Name
:
"l
1.head
"
,
Usage
:
"
Hash of the L1 head block. Derivation stops after this block is processed.
"
,
EnvVar
:
service
.
PrefixEnvVar
(
envVarPrefix
,
"L
1_HEAD
"
),
}
L2Head
=
cli
.
StringFlag
{
Name
:
"l2.head"
,
Usage
:
"Hash of the agreed L2 block to start derivation from"
,
EnvVar
:
service
.
PrefixEnvVar
(
envVarPrefix
,
"L2_HEAD"
),
}
L2GenesisPath
=
cli
.
StringFlag
{
Name
:
"l2.genesis"
,
Usage
:
"Path to the op-geth genesis file"
,
EnvVar
:
service
.
PrefixEnvVar
(
envVarPrefix
,
"L2_GENESIS"
),
}
L1NodeAddr
=
cli
.
StringFlag
{
Name
:
"l1"
,
Usage
:
"Address of L1 JSON-RPC endpoint to use (eth namespace required)"
,
...
...
@@ -70,8 +75,9 @@ var programFlags = []cli.Flag{
RollupConfig
,
Network
,
L2NodeAddr
,
L
2GenesisPath
,
L
1Head
,
L2Head
,
L2GenesisPath
,
L1NodeAddr
,
L1TrustRPC
,
L1RPCProviderKind
,
...
...
@@ -97,5 +103,8 @@ func CheckRequired(ctx *cli.Context) error {
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
}
op-program/host/l1/fetcher.go
View file @
b1c9be0b
...
...
@@ -7,6 +7,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
)
type
Source
interface
{
...
...
@@ -17,17 +18,20 @@ type Source interface {
type
FetchingL1Oracle
struct
{
ctx
context
.
Context
logger
log
.
Logger
source
Source
}
func
NewFetchingL1Oracle
(
ctx
context
.
Context
,
source
Source
)
*
FetchingL1Oracle
{
func
NewFetchingL1Oracle
(
ctx
context
.
Context
,
logger
log
.
Logger
,
source
Source
)
*
FetchingL1Oracle
{
return
&
FetchingL1Oracle
{
ctx
:
ctx
,
logger
:
logger
,
source
:
source
,
}
}
func
(
o
FetchingL1Oracle
)
HeaderByHash
(
blockHash
common
.
Hash
)
eth
.
BlockInfo
{
o
.
logger
.
Trace
(
"HeaderByHash"
,
"hash"
,
blockHash
)
info
,
err
:=
o
.
source
.
InfoByHash
(
o
.
ctx
,
blockHash
)
if
err
!=
nil
{
panic
(
fmt
.
Errorf
(
"retrieve block %s: %w"
,
blockHash
,
err
))
...
...
@@ -39,6 +43,7 @@ func (o FetchingL1Oracle) HeaderByHash(blockHash common.Hash) eth.BlockInfo {
}
func
(
o
FetchingL1Oracle
)
TransactionsByHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
)
{
o
.
logger
.
Trace
(
"TransactionsByHash"
,
"hash"
,
blockHash
)
info
,
txs
,
err
:=
o
.
source
.
InfoAndTxsByHash
(
o
.
ctx
,
blockHash
)
if
err
!=
nil
{
panic
(
fmt
.
Errorf
(
"retrieve transactions for block %s: %w"
,
blockHash
,
err
))
...
...
@@ -50,6 +55,7 @@ func (o FetchingL1Oracle) TransactionsByHash(blockHash common.Hash) (eth.BlockIn
}
func
(
o
FetchingL1Oracle
)
ReceiptsByHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
)
{
o
.
logger
.
Trace
(
"ReceiptsByHash"
,
"hash"
,
blockHash
)
info
,
rcpts
,
err
:=
o
.
source
.
FetchReceipts
(
o
.
ctx
,
blockHash
)
if
err
!=
nil
{
panic
(
fmt
.
Errorf
(
"retrieve receipts for block %s: %w"
,
blockHash
,
err
))
...
...
op-program/host/l1/fetcher_test.go
View file @
b1c9be0b
...
...
@@ -8,9 +8,11 @@ import (
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-node/testlog"
cll1
"github.com/ethereum-optimism/optimism/op-program/client/l1"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)
...
...
@@ -24,14 +26,14 @@ func TestHeaderByHash(t *testing.T) {
t
.
Run
(
"Success"
,
func
(
t
*
testing
.
T
)
{
expected
:=
&
sources
.
HeaderInfo
{}
source
:=
&
stubSource
{
nextInfo
:
expected
}
oracle
:=
newFetchingOracle
(
source
)
oracle
:=
newFetchingOracle
(
t
,
source
)
actual
:=
oracle
.
HeaderByHash
(
expected
.
Hash
())
require
.
Equal
(
t
,
expected
,
actual
)
})
t
.
Run
(
"UnknownBlock"
,
func
(
t
*
testing
.
T
)
{
oracle
:=
newFetchingOracle
(
&
stubSource
{})
oracle
:=
newFetchingOracle
(
t
,
&
stubSource
{})
hash
:=
common
.
HexToHash
(
"0x4455"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"unknown block: %s"
,
hash
)
.
Error
(),
func
()
{
oracle
.
HeaderByHash
(
hash
)
...
...
@@ -41,7 +43,7 @@ func TestHeaderByHash(t *testing.T) {
t
.
Run
(
"Error"
,
func
(
t
*
testing
.
T
)
{
err
:=
errors
.
New
(
"kaboom"
)
source
:=
&
stubSource
{
nextErr
:
err
}
oracle
:=
newFetchingOracle
(
source
)
oracle
:=
newFetchingOracle
(
t
,
source
)
hash
:=
common
.
HexToHash
(
"0x8888"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"retrieve block %s: %w"
,
hash
,
err
)
.
Error
(),
func
()
{
...
...
@@ -57,7 +59,7 @@ func TestTransactionsByHash(t *testing.T) {
&
types
.
Transaction
{},
}
source
:=
&
stubSource
{
nextInfo
:
expectedInfo
,
nextTxs
:
expectedTxs
}
oracle
:=
newFetchingOracle
(
source
)
oracle
:=
newFetchingOracle
(
t
,
source
)
info
,
txs
:=
oracle
.
TransactionsByHash
(
expectedInfo
.
Hash
())
require
.
Equal
(
t
,
expectedInfo
,
info
)
...
...
@@ -65,7 +67,7 @@ func TestTransactionsByHash(t *testing.T) {
})
t
.
Run
(
"UnknownBlock_NoInfo"
,
func
(
t
*
testing
.
T
)
{
oracle
:=
newFetchingOracle
(
&
stubSource
{})
oracle
:=
newFetchingOracle
(
t
,
&
stubSource
{})
hash
:=
common
.
HexToHash
(
"0x4455"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"unknown block: %s"
,
hash
)
.
Error
(),
func
()
{
oracle
.
TransactionsByHash
(
hash
)
...
...
@@ -73,7 +75,7 @@ func TestTransactionsByHash(t *testing.T) {
})
t
.
Run
(
"UnknownBlock_NoTxs"
,
func
(
t
*
testing
.
T
)
{
oracle
:=
newFetchingOracle
(
&
stubSource
{
nextInfo
:
&
sources
.
HeaderInfo
{}})
oracle
:=
newFetchingOracle
(
t
,
&
stubSource
{
nextInfo
:
&
sources
.
HeaderInfo
{}})
hash
:=
common
.
HexToHash
(
"0x4455"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"unknown block: %s"
,
hash
)
.
Error
(),
func
()
{
oracle
.
TransactionsByHash
(
hash
)
...
...
@@ -83,7 +85,7 @@ func TestTransactionsByHash(t *testing.T) {
t
.
Run
(
"Error"
,
func
(
t
*
testing
.
T
)
{
err
:=
errors
.
New
(
"kaboom"
)
source
:=
&
stubSource
{
nextErr
:
err
}
oracle
:=
newFetchingOracle
(
source
)
oracle
:=
newFetchingOracle
(
t
,
source
)
hash
:=
common
.
HexToHash
(
"0x8888"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"retrieve transactions for block %s: %w"
,
hash
,
err
)
.
Error
(),
func
()
{
...
...
@@ -99,7 +101,7 @@ func TestReceiptsByHash(t *testing.T) {
&
types
.
Receipt
{},
}
source
:=
&
stubSource
{
nextInfo
:
expectedInfo
,
nextRcpts
:
expectedRcpts
}
oracle
:=
newFetchingOracle
(
source
)
oracle
:=
newFetchingOracle
(
t
,
source
)
info
,
rcpts
:=
oracle
.
ReceiptsByHash
(
expectedInfo
.
Hash
())
require
.
Equal
(
t
,
expectedInfo
,
info
)
...
...
@@ -107,7 +109,7 @@ func TestReceiptsByHash(t *testing.T) {
})
t
.
Run
(
"UnknownBlock_NoInfo"
,
func
(
t
*
testing
.
T
)
{
oracle
:=
newFetchingOracle
(
&
stubSource
{})
oracle
:=
newFetchingOracle
(
t
,
&
stubSource
{})
hash
:=
common
.
HexToHash
(
"0x4455"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"unknown block: %s"
,
hash
)
.
Error
(),
func
()
{
oracle
.
ReceiptsByHash
(
hash
)
...
...
@@ -115,7 +117,7 @@ func TestReceiptsByHash(t *testing.T) {
})
t
.
Run
(
"UnknownBlock_NoTxs"
,
func
(
t
*
testing
.
T
)
{
oracle
:=
newFetchingOracle
(
&
stubSource
{
nextInfo
:
&
sources
.
HeaderInfo
{}})
oracle
:=
newFetchingOracle
(
t
,
&
stubSource
{
nextInfo
:
&
sources
.
HeaderInfo
{}})
hash
:=
common
.
HexToHash
(
"0x4455"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"unknown block: %s"
,
hash
)
.
Error
(),
func
()
{
oracle
.
ReceiptsByHash
(
hash
)
...
...
@@ -125,7 +127,7 @@ func TestReceiptsByHash(t *testing.T) {
t
.
Run
(
"Error"
,
func
(
t
*
testing
.
T
)
{
err
:=
errors
.
New
(
"kaboom"
)
source
:=
&
stubSource
{
nextErr
:
err
}
oracle
:=
newFetchingOracle
(
source
)
oracle
:=
newFetchingOracle
(
t
,
source
)
hash
:=
common
.
HexToHash
(
"0x8888"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"retrieve receipts for block %s: %w"
,
hash
,
err
)
.
Error
(),
func
()
{
...
...
@@ -134,11 +136,8 @@ func TestReceiptsByHash(t *testing.T) {
})
}
func
newFetchingOracle
(
source
Source
)
*
FetchingL1Oracle
{
return
&
FetchingL1Oracle
{
ctx
:
context
.
Background
(),
source
:
source
,
}
func
newFetchingOracle
(
t
*
testing
.
T
,
source
Source
)
*
FetchingL1Oracle
{
return
NewFetchingL1Oracle
(
context
.
Background
(),
testlog
.
Logger
(
t
,
log
.
LvlDebug
),
source
)
}
type
stubSource
struct
{
...
...
op-program/host/l1/l1.go
View file @
b1c9be0b
...
...
@@ -6,6 +6,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/client"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/sources"
cll1
"github.com/ethereum-optimism/optimism/op-program/client/l1"
"github.com/ethereum-optimism/optimism/op-program/host/config"
"github.com/ethereum/go-ethereum/log"
)
...
...
@@ -16,5 +17,10 @@ func NewFetchingL1(ctx context.Context, logger log.Logger, cfg *config.Config) (
return
nil
,
err
}
return
sources
.
NewL1Client
(
rpc
,
logger
,
nil
,
sources
.
L1ClientDefaultConfig
(
cfg
.
Rollup
,
cfg
.
L1TrustRPC
,
cfg
.
L1RPCKind
))
source
,
err
:=
sources
.
NewL1Client
(
rpc
,
logger
,
nil
,
sources
.
L1ClientDefaultConfig
(
cfg
.
Rollup
,
cfg
.
L1TrustRPC
,
cfg
.
L1RPCKind
))
if
err
!=
nil
{
return
nil
,
err
}
oracle
:=
NewFetchingL1Oracle
(
ctx
,
logger
,
source
)
return
cll1
.
NewOracleL1Client
(
logger
,
oracle
,
cfg
.
L1Head
),
err
}
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