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
0c0cf54b
Unverified
Commit
0c0cf54b
authored
Apr 11, 2023
by
OptimismBot
Committed by
GitHub
Apr 11, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #5411 from ethereum-optimism/aj/fpp-l1-fetcher
op-program: Implement oracle based L1 fetcher
parents
536340c4
b54be593
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
607 additions
and
44 deletions
+607
-44
client.go
op-program/client/l1/client.go
+69
-0
client_test.go
op-program/client/l1/client_test.go
+210
-0
oracle.go
op-program/client/l1/oracle.go
+18
-0
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
+67
-0
fetcher_test.go
op-program/host/l1/fetcher_test.go
+160
-0
l1.go
op-program/host/l1/l1.go
+7
-1
No files found.
op-program/client/l1/client.go
0 → 100644
View file @
0c0cf54b
package
l1
import
(
"context"
"errors"
"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
=
ethereum
.
NotFound
ErrUnknownLabel
=
errors
.
New
(
"unknown label"
)
)
type
OracleL1Client
struct
{
oracle
Oracle
head
eth
.
L1BlockRef
}
func
NewOracleL1Client
(
logger
log
.
Logger
,
oracle
Oracle
,
l1Head
common
.
Hash
)
*
OracleL1Client
{
head
:=
eth
.
InfoToL1BlockRef
(
oracle
.
HeaderByBlockHash
(
l1Head
))
logger
.
Info
(
"L1 head loaded"
,
"hash"
,
head
.
Hash
,
"number"
,
head
.
Number
)
return
&
OracleL1Client
{
oracle
:
oracle
,
head
:
head
,
}
}
func
(
o
OracleL1Client
)
L1BlockRefByLabel
(
ctx
context
.
Context
,
label
eth
.
BlockLabel
)
(
eth
.
L1BlockRef
,
error
)
{
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
)
}
block
:=
o
.
head
for
block
.
Number
>
number
{
block
=
eth
.
InfoToL1BlockRef
(
o
.
oracle
.
HeaderByBlockHash
(
block
.
ParentHash
))
}
return
block
,
nil
}
func
(
o
OracleL1Client
)
L1BlockRefByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
eth
.
L1BlockRef
,
error
)
{
return
eth
.
InfoToL1BlockRef
(
o
.
oracle
.
HeaderByBlockHash
(
hash
)),
nil
}
func
(
o
OracleL1Client
)
InfoByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
eth
.
BlockInfo
,
error
)
{
return
o
.
oracle
.
HeaderByBlockHash
(
hash
),
nil
}
func
(
o
OracleL1Client
)
FetchReceipts
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
,
error
)
{
info
,
rcpts
:=
o
.
oracle
.
ReceiptsByBlockHash
(
blockHash
)
return
info
,
rcpts
,
nil
}
func
(
o
OracleL1Client
)
InfoAndTxsByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
,
error
)
{
info
,
txs
:=
o
.
oracle
.
TransactionsByBlockHash
(
hash
)
return
info
,
txs
,
nil
}
op-program/client/l1/client_test.go
0 → 100644
View file @
0c0cf54b
package
l1
import
(
"context"
"math/big"
"testing"
"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"
)
var
_
derive
.
L1Fetcher
=
(
*
OracleL1Client
)(
nil
)
var
head
=
blockNum
(
1000
)
func
TestInfoByHash
(
t
*
testing
.
T
)
{
client
,
oracle
:=
newClient
(
t
)
hash
:=
common
.
HexToHash
(
"0xAABBCC"
)
expected
:=
&
sources
.
HeaderInfo
{}
oracle
.
blocks
[
hash
]
=
expected
info
,
err
:=
client
.
InfoByHash
(
context
.
Background
(),
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expected
,
info
)
}
func
TestL1BlockRefByHash
(
t
*
testing
.
T
)
{
client
,
oracle
:=
newClient
(
t
)
hash
:=
common
.
HexToHash
(
"0xAABBCC"
)
header
:=
&
sources
.
HeaderInfo
{}
oracle
.
blocks
[
hash
]
=
header
expected
:=
eth
.
InfoToL1BlockRef
(
header
)
ref
,
err
:=
client
.
L1BlockRefByHash
(
context
.
Background
(),
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expected
,
ref
)
}
func
TestFetchReceipts
(
t
*
testing
.
T
)
{
client
,
oracle
:=
newClient
(
t
)
hash
:=
common
.
HexToHash
(
"0xAABBCC"
)
expectedInfo
:=
&
sources
.
HeaderInfo
{}
expectedReceipts
:=
types
.
Receipts
{
&
types
.
Receipt
{},
}
oracle
.
blocks
[
hash
]
=
expectedInfo
oracle
.
rcpts
[
hash
]
=
expectedReceipts
info
,
rcpts
,
err
:=
client
.
FetchReceipts
(
context
.
Background
(),
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expectedInfo
,
info
)
require
.
Equal
(
t
,
expectedReceipts
,
rcpts
)
}
func
TestInfoAndTxsByHash
(
t
*
testing
.
T
)
{
client
,
oracle
:=
newClient
(
t
)
hash
:=
common
.
HexToHash
(
"0xAABBCC"
)
expectedInfo
:=
&
sources
.
HeaderInfo
{}
expectedTxs
:=
types
.
Transactions
{
&
types
.
Transaction
{},
}
oracle
.
blocks
[
hash
]
=
expectedInfo
oracle
.
txs
[
hash
]
=
expectedTxs
info
,
txs
,
err
:=
client
.
InfoAndTxsByHash
(
context
.
Background
(),
hash
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expectedInfo
,
info
)
require
.
Equal
(
t
,
expectedTxs
,
txs
)
}
func
TestL1BlockRefByLabel
(
t
*
testing
.
T
)
{
t
.
Run
(
"Unsafe"
,
func
(
t
*
testing
.
T
)
{
client
,
_
:=
newClient
(
t
)
ref
,
err
:=
client
.
L1BlockRefByLabel
(
context
.
Background
(),
eth
.
Unsafe
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
eth
.
InfoToL1BlockRef
(
head
),
ref
)
})
t
.
Run
(
"Safe"
,
func
(
t
*
testing
.
T
)
{
client
,
_
:=
newClient
(
t
)
ref
,
err
:=
client
.
L1BlockRefByLabel
(
context
.
Background
(),
eth
.
Safe
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
eth
.
InfoToL1BlockRef
(
head
),
ref
)
})
t
.
Run
(
"Finalized"
,
func
(
t
*
testing
.
T
)
{
client
,
_
:=
newClient
(
t
)
ref
,
err
:=
client
.
L1BlockRefByLabel
(
context
.
Background
(),
eth
.
Finalized
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
eth
.
InfoToL1BlockRef
(
head
),
ref
)
})
t
.
Run
(
"UnknownLabel"
,
func
(
t
*
testing
.
T
)
{
client
,
_
:=
newClient
(
t
)
ref
,
err
:=
client
.
L1BlockRefByLabel
(
context
.
Background
(),
eth
.
BlockLabel
(
"unknown"
))
require
.
ErrorIs
(
t
,
err
,
ErrUnknownLabel
)
require
.
Equal
(
t
,
eth
.
L1BlockRef
{},
ref
)
})
}
func
TestL1BlockRefByNumber
(
t
*
testing
.
T
)
{
t
.
Run
(
"Head"
,
func
(
t
*
testing
.
T
)
{
client
,
_
:=
newClient
(
t
)
ref
,
err
:=
client
.
L1BlockRefByNumber
(
context
.
Background
(),
head
.
NumberU64
())
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
eth
.
InfoToL1BlockRef
(
head
),
ref
)
})
t
.
Run
(
"AfterHead"
,
func
(
t
*
testing
.
T
)
{
client
,
_
:=
newClient
(
t
)
ref
,
err
:=
client
.
L1BlockRefByNumber
(
context
.
Background
(),
head
.
NumberU64
()
+
1
)
// 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
)
{
client
,
oracle
:=
newClient
(
t
)
parent
:=
blockNum
(
head
.
NumberU64
()
-
1
)
oracle
.
blocks
[
parent
.
Hash
()]
=
parent
ref
,
err
:=
client
.
L1BlockRefByNumber
(
context
.
Background
(),
parent
.
NumberU64
())
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
eth
.
InfoToL1BlockRef
(
parent
),
ref
)
})
t
.
Run
(
"AncestorOfHead"
,
func
(
t
*
testing
.
T
)
{
client
,
oracle
:=
newClient
(
t
)
block
:=
head
blocks
:=
[]
eth
.
BlockInfo
{
block
}
for
i
:=
0
;
i
<
10
;
i
++
{
block
=
blockNum
(
block
.
NumberU64
()
-
1
)
oracle
.
blocks
[
block
.
Hash
()]
=
block
blocks
=
append
(
blocks
,
block
)
}
for
_
,
block
:=
range
blocks
{
ref
,
err
:=
client
.
L1BlockRefByNumber
(
context
.
Background
(),
block
.
NumberU64
())
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
eth
.
InfoToL1BlockRef
(
block
),
ref
)
}
})
}
func
newClient
(
t
*
testing
.
T
)
(
*
OracleL1Client
,
*
stubOracle
)
{
stub
:=
&
stubOracle
{
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
client
:=
NewOracleL1Client
(
testlog
.
Logger
(
t
,
log
.
LvlDebug
),
stub
,
head
.
Hash
())
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
{
parentNum
:=
num
-
1
return
&
testutils
.
MockBlockInfo
{
InfoHash
:
common
.
BytesToHash
(
big
.
NewInt
(
int64
(
num
))
.
Bytes
()),
InfoParentHash
:
common
.
BytesToHash
(
big
.
NewInt
(
int64
(
parentNum
))
.
Bytes
()),
InfoCoinbase
:
common
.
Address
{},
InfoRoot
:
common
.
Hash
{},
InfoNum
:
num
,
InfoTime
:
num
*
2
,
InfoMixDigest
:
[
32
]
byte
{},
InfoBaseFee
:
nil
,
InfoReceiptRoot
:
common
.
Hash
{},
InfoGasUsed
:
0
,
}
}
op-program/client/l1/oracle.go
0 → 100644
View file @
0c0cf54b
package
l1
import
(
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
type
Oracle
interface
{
// HeaderByBlockHash retrieves the block header with the given hash.
HeaderByBlockHash
(
blockHash
common
.
Hash
)
eth
.
BlockInfo
// TransactionsByBlockHash retrieves the transactions from the block with the given hash.
TransactionsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
)
// ReceiptsByBlockHash retrieves the receipts from the block with the given hash.
ReceiptsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
)
}
op-program/client/l2/engine_backend.go
View file @
0c0cf54b
...
...
@@ -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 @
0c0cf54b
...
...
@@ -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 @
0c0cf54b
...
...
@@ -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 @
0c0cf54b
...
...
@@ -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
()
require
.
ErrorIs
(
t
,
err
,
ErrInvalidL2Head
)
})
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 @
0c0cf54b
...
...
@@ -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
0 → 100644
View file @
0c0cf54b
package
l1
import
(
"context"
"fmt"
"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
{
InfoByHash
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
error
)
InfoAndTxsByHash
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
,
error
)
FetchReceipts
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
,
error
)
}
type
FetchingL1Oracle
struct
{
ctx
context
.
Context
logger
log
.
Logger
source
Source
}
func
NewFetchingL1Oracle
(
ctx
context
.
Context
,
logger
log
.
Logger
,
source
Source
)
*
FetchingL1Oracle
{
return
&
FetchingL1Oracle
{
ctx
:
ctx
,
logger
:
logger
,
source
:
source
,
}
}
func
(
o
FetchingL1Oracle
)
HeaderByBlockHash
(
blockHash
common
.
Hash
)
eth
.
BlockInfo
{
o
.
logger
.
Trace
(
"HeaderByBlockHash"
,
"hash"
,
blockHash
)
info
,
err
:=
o
.
source
.
InfoByHash
(
o
.
ctx
,
blockHash
)
if
err
!=
nil
{
panic
(
fmt
.
Errorf
(
"retrieve block %s: %w"
,
blockHash
,
err
))
}
if
info
==
nil
{
panic
(
fmt
.
Errorf
(
"unknown block: %s"
,
blockHash
))
}
return
info
}
func
(
o
FetchingL1Oracle
)
TransactionsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
)
{
o
.
logger
.
Trace
(
"TransactionsByBlockHash"
,
"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
))
}
if
info
==
nil
||
txs
==
nil
{
panic
(
fmt
.
Errorf
(
"unknown block: %s"
,
blockHash
))
}
return
info
,
txs
}
func
(
o
FetchingL1Oracle
)
ReceiptsByBlockHash
(
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
)
{
o
.
logger
.
Trace
(
"ReceiptsByBlockHash"
,
"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
))
}
if
info
==
nil
||
rcpts
==
nil
{
panic
(
fmt
.
Errorf
(
"unknown block: %s"
,
blockHash
))
}
return
info
,
rcpts
}
op-program/host/l1/fetcher_test.go
0 → 100644
View file @
0c0cf54b
package
l1
import
(
"context"
"errors"
"fmt"
"testing"
"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"
)
// Needs to implement the Oracle interface
var
_
cll1
.
Oracle
=
(
*
FetchingL1Oracle
)(
nil
)
// Want to be able to use an L1Client as the data source
var
_
Source
=
(
*
sources
.
L1Client
)(
nil
)
func
TestHeaderByHash
(
t
*
testing
.
T
)
{
t
.
Run
(
"Success"
,
func
(
t
*
testing
.
T
)
{
expected
:=
&
sources
.
HeaderInfo
{}
source
:=
&
stubSource
{
nextInfo
:
expected
}
oracle
:=
newFetchingOracle
(
t
,
source
)
actual
:=
oracle
.
HeaderByBlockHash
(
expected
.
Hash
())
require
.
Equal
(
t
,
expected
,
actual
)
})
t
.
Run
(
"UnknownBlock"
,
func
(
t
*
testing
.
T
)
{
oracle
:=
newFetchingOracle
(
t
,
&
stubSource
{})
hash
:=
common
.
HexToHash
(
"0x4455"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"unknown block: %s"
,
hash
)
.
Error
(),
func
()
{
oracle
.
HeaderByBlockHash
(
hash
)
})
})
t
.
Run
(
"Error"
,
func
(
t
*
testing
.
T
)
{
err
:=
errors
.
New
(
"kaboom"
)
source
:=
&
stubSource
{
nextErr
:
err
}
oracle
:=
newFetchingOracle
(
t
,
source
)
hash
:=
common
.
HexToHash
(
"0x8888"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"retrieve block %s: %w"
,
hash
,
err
)
.
Error
(),
func
()
{
oracle
.
HeaderByBlockHash
(
hash
)
})
})
}
func
TestTransactionsByHash
(
t
*
testing
.
T
)
{
t
.
Run
(
"Success"
,
func
(
t
*
testing
.
T
)
{
expectedInfo
:=
&
sources
.
HeaderInfo
{}
expectedTxs
:=
types
.
Transactions
{
&
types
.
Transaction
{},
}
source
:=
&
stubSource
{
nextInfo
:
expectedInfo
,
nextTxs
:
expectedTxs
}
oracle
:=
newFetchingOracle
(
t
,
source
)
info
,
txs
:=
oracle
.
TransactionsByBlockHash
(
expectedInfo
.
Hash
())
require
.
Equal
(
t
,
expectedInfo
,
info
)
require
.
Equal
(
t
,
expectedTxs
,
txs
)
})
t
.
Run
(
"UnknownBlock_NoInfo"
,
func
(
t
*
testing
.
T
)
{
oracle
:=
newFetchingOracle
(
t
,
&
stubSource
{})
hash
:=
common
.
HexToHash
(
"0x4455"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"unknown block: %s"
,
hash
)
.
Error
(),
func
()
{
oracle
.
TransactionsByBlockHash
(
hash
)
})
})
t
.
Run
(
"UnknownBlock_NoTxs"
,
func
(
t
*
testing
.
T
)
{
oracle
:=
newFetchingOracle
(
t
,
&
stubSource
{
nextInfo
:
&
sources
.
HeaderInfo
{}})
hash
:=
common
.
HexToHash
(
"0x4455"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"unknown block: %s"
,
hash
)
.
Error
(),
func
()
{
oracle
.
TransactionsByBlockHash
(
hash
)
})
})
t
.
Run
(
"Error"
,
func
(
t
*
testing
.
T
)
{
err
:=
errors
.
New
(
"kaboom"
)
source
:=
&
stubSource
{
nextErr
:
err
}
oracle
:=
newFetchingOracle
(
t
,
source
)
hash
:=
common
.
HexToHash
(
"0x8888"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"retrieve transactions for block %s: %w"
,
hash
,
err
)
.
Error
(),
func
()
{
oracle
.
TransactionsByBlockHash
(
hash
)
})
})
}
func
TestReceiptsByHash
(
t
*
testing
.
T
)
{
t
.
Run
(
"Success"
,
func
(
t
*
testing
.
T
)
{
expectedInfo
:=
&
sources
.
HeaderInfo
{}
expectedRcpts
:=
types
.
Receipts
{
&
types
.
Receipt
{},
}
source
:=
&
stubSource
{
nextInfo
:
expectedInfo
,
nextRcpts
:
expectedRcpts
}
oracle
:=
newFetchingOracle
(
t
,
source
)
info
,
rcpts
:=
oracle
.
ReceiptsByBlockHash
(
expectedInfo
.
Hash
())
require
.
Equal
(
t
,
expectedInfo
,
info
)
require
.
Equal
(
t
,
expectedRcpts
,
rcpts
)
})
t
.
Run
(
"UnknownBlock_NoInfo"
,
func
(
t
*
testing
.
T
)
{
oracle
:=
newFetchingOracle
(
t
,
&
stubSource
{})
hash
:=
common
.
HexToHash
(
"0x4455"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"unknown block: %s"
,
hash
)
.
Error
(),
func
()
{
oracle
.
ReceiptsByBlockHash
(
hash
)
})
})
t
.
Run
(
"UnknownBlock_NoTxs"
,
func
(
t
*
testing
.
T
)
{
oracle
:=
newFetchingOracle
(
t
,
&
stubSource
{
nextInfo
:
&
sources
.
HeaderInfo
{}})
hash
:=
common
.
HexToHash
(
"0x4455"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"unknown block: %s"
,
hash
)
.
Error
(),
func
()
{
oracle
.
ReceiptsByBlockHash
(
hash
)
})
})
t
.
Run
(
"Error"
,
func
(
t
*
testing
.
T
)
{
err
:=
errors
.
New
(
"kaboom"
)
source
:=
&
stubSource
{
nextErr
:
err
}
oracle
:=
newFetchingOracle
(
t
,
source
)
hash
:=
common
.
HexToHash
(
"0x8888"
)
require
.
PanicsWithError
(
t
,
fmt
.
Errorf
(
"retrieve receipts for block %s: %w"
,
hash
,
err
)
.
Error
(),
func
()
{
oracle
.
ReceiptsByBlockHash
(
hash
)
})
})
}
func
newFetchingOracle
(
t
*
testing
.
T
,
source
Source
)
*
FetchingL1Oracle
{
return
NewFetchingL1Oracle
(
context
.
Background
(),
testlog
.
Logger
(
t
,
log
.
LvlDebug
),
source
)
}
type
stubSource
struct
{
nextInfo
eth
.
BlockInfo
nextTxs
types
.
Transactions
nextRcpts
types
.
Receipts
nextErr
error
}
func
(
s
stubSource
)
InfoByHash
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
error
)
{
return
s
.
nextInfo
,
s
.
nextErr
}
func
(
s
stubSource
)
InfoAndTxsByHash
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Transactions
,
error
)
{
return
s
.
nextInfo
,
s
.
nextTxs
,
s
.
nextErr
}
func
(
s
stubSource
)
FetchReceipts
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
,
error
)
{
return
s
.
nextInfo
,
s
.
nextRcpts
,
s
.
nextErr
}
op-program/host/l1/l1.go
View file @
0c0cf54b
...
...
@@ -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