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
d6dd6eb9
Unverified
Commit
d6dd6eb9
authored
Apr 18, 2023
by
Adrian Sutton
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
op-e2e: Add e2e test for op-program
parent
6818a0c6
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
254 additions
and
129 deletions
+254
-129
setup.go
op-e2e/setup.go
+11
-3
system_fpp_test.go
op-e2e/system_fpp_test.go
+106
-0
main.go
op-program/host/cmd/main.go
+4
-126
host.go
op-program/host/host.go
+133
-0
No files found.
op-e2e/setup.go
View file @
d6dd6eb9
...
@@ -233,6 +233,10 @@ type System struct {
...
@@ -233,6 +233,10 @@ type System struct {
Mocknet
mocknet
.
Mocknet
Mocknet
mocknet
.
Mocknet
}
}
func
(
sys
*
System
)
NodeEndpoint
(
name
string
)
string
{
return
selectEndpoint
(
sys
.
Nodes
[
name
])
}
func
(
sys
*
System
)
Close
()
{
func
(
sys
*
System
)
Close
()
{
if
sys
.
L2OutputSubmitter
!=
nil
{
if
sys
.
L2OutputSubmitter
!=
nil
{
sys
.
L2OutputSubmitter
.
Stop
()
sys
.
L2OutputSubmitter
.
Stop
()
...
@@ -619,13 +623,17 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
...
@@ -619,13 +623,17 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
return
sys
,
nil
return
sys
,
nil
}
}
func
configureL1
(
rollupNodeCfg
*
rollupNode
.
Config
,
l1Node
*
node
.
Node
)
{
func
selectEndpoint
(
node
*
node
.
Node
)
string
{
l1EndpointConfig
:=
l1Node
.
WSEndpoint
()
useHTTP
:=
os
.
Getenv
(
"OP_E2E_USE_HTTP"
)
==
"true"
useHTTP
:=
os
.
Getenv
(
"OP_E2E_USE_HTTP"
)
==
"true"
if
useHTTP
{
if
useHTTP
{
log
.
Info
(
"using HTTP client"
)
log
.
Info
(
"using HTTP client"
)
l1EndpointConfig
=
l1N
ode
.
HTTPEndpoint
()
return
n
ode
.
HTTPEndpoint
()
}
}
return
node
.
WSEndpoint
()
}
func
configureL1
(
rollupNodeCfg
*
rollupNode
.
Config
,
l1Node
*
node
.
Node
)
{
l1EndpointConfig
:=
selectEndpoint
(
l1Node
)
rollupNodeCfg
.
L1
=
&
rollupNode
.
L1EndpointConfig
{
rollupNodeCfg
.
L1
=
&
rollupNode
.
L1EndpointConfig
{
L1NodeAddr
:
l1EndpointConfig
,
L1NodeAddr
:
l1EndpointConfig
,
L1TrustRPC
:
false
,
L1TrustRPC
:
false
,
...
...
op-e2e/system_fpp_test.go
0 → 100644
View file @
d6dd6eb9
package
op_e2e
import
(
"context"
"math/big"
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-node/client"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-node/testlog"
opp
"github.com/ethereum-optimism/optimism/op-program/host"
oppconf
"github.com/ethereum-optimism/optimism/op-program/host/config"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/require"
)
func
TestVerifyL2OutputRoot
(
t
*
testing
.
T
)
{
parallel
(
t
)
ctx
:=
context
.
Background
()
cfg
:=
DefaultSystemConfig
(
t
)
// We don't need a verifier - just the sequencer is enough
delete
(
cfg
.
Nodes
,
"verifier"
)
sys
,
err
:=
cfg
.
Start
()
require
.
Nil
(
t
,
err
,
"Error starting up system"
)
defer
sys
.
Close
()
log
:=
testlog
.
Logger
(
t
,
log
.
LvlInfo
)
log
.
Info
(
"genesis"
,
"l2"
,
sys
.
RollupConfig
.
Genesis
.
L2
,
"l1"
,
sys
.
RollupConfig
.
Genesis
.
L1
,
"l2_time"
,
sys
.
RollupConfig
.
Genesis
.
L2Time
)
l1Client
:=
sys
.
Clients
[
"l1"
]
l2Seq
:=
sys
.
Clients
[
"sequencer"
]
rollupRPCClient
,
err
:=
rpc
.
DialContext
(
context
.
Background
(),
sys
.
RollupNodes
[
"sequencer"
]
.
HTTPEndpoint
())
require
.
Nil
(
t
,
err
)
rollupClient
:=
sources
.
NewRollupClient
(
client
.
NewBaseRPCClient
(
rollupRPCClient
))
// TODO (CLI-3855): Actually perform some tx to set up a more complex chain.
// Wait for the safe head to reach block 10
require
.
NoError
(
t
,
waitForSafeHead
(
ctx
,
10
,
rollupClient
))
// Use block 5 as the agreed starting block on L2
l2AgreedBlock
,
err
:=
l2Seq
.
BlockByNumber
(
ctx
,
big
.
NewInt
(
5
))
require
.
NoError
(
t
,
err
,
"could not retrieve l2 genesis"
)
l2Head
:=
l2AgreedBlock
.
Hash
()
// Agreed starting L2 block
// Get the expected output at block 10
l2ClaimBlockNumber
:=
uint64
(
10
)
l2Output
,
err
:=
rollupClient
.
OutputAtBlock
(
ctx
,
l2ClaimBlockNumber
)
require
.
NoError
(
t
,
err
,
"could not get expected output"
)
l2Claim
:=
l2Output
.
OutputRoot
// Find the current L1 head
l1BlockNumber
,
err
:=
l1Client
.
BlockNumber
(
ctx
)
require
.
NoError
(
t
,
err
,
"get l1 head block number"
)
l1HeadBlock
,
err
:=
l1Client
.
BlockByNumber
(
ctx
,
new
(
big
.
Int
)
.
SetUint64
(
l1BlockNumber
))
require
.
NoError
(
t
,
err
,
"get l1 head block"
)
l1Head
:=
l1HeadBlock
.
Hash
()
preimageDir
:=
t
.
TempDir
()
fppConfig
:=
oppconf
.
NewConfig
(
sys
.
RollupConfig
,
sys
.
L2GenesisCfg
.
Config
,
l1Head
,
l2Head
,
common
.
Hash
(
l2Claim
),
l2ClaimBlockNumber
)
fppConfig
.
L1URL
=
sys
.
NodeEndpoint
(
"l1"
)
fppConfig
.
L2URL
=
sys
.
NodeEndpoint
(
"sequencer"
)
fppConfig
.
DataDir
=
preimageDir
// Check the FPP confirms the expected output
t
.
Log
(
"Running fault proof in fetching mode"
)
err
=
opp
.
FaultProofProgram
(
log
,
fppConfig
)
require
.
NoError
(
t
,
err
)
// Shutdown the nodes from the actual chain. Should now be able to run using only the pre-fetched data.
for
_
,
node
:=
range
sys
.
Nodes
{
require
.
NoError
(
t
,
node
.
Close
())
}
t
.
Log
(
"Running fault proof in offline mode"
)
// Should be able to rerun in offline mode using the pre-fetched images
fppConfig
.
L1URL
=
""
fppConfig
.
L2URL
=
""
err
=
opp
.
FaultProofProgram
(
log
,
fppConfig
)
require
.
NoError
(
t
,
err
)
// Check that a fault is detected if we provide an incorrect claim
t
.
Log
(
"Running fault proof with invalid claim"
)
fppConfig
.
L2Claim
=
common
.
Hash
{
0xaa
}
err
=
opp
.
FaultProofProgram
(
log
,
fppConfig
)
require
.
ErrorIs
(
t
,
err
,
opp
.
ErrClaimNotValid
)
}
func
waitForSafeHead
(
ctx
context
.
Context
,
safeBlockNum
uint64
,
rollupClient
*
sources
.
RollupClient
)
error
{
ctx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
30
*
time
.
Second
)
defer
cancel
()
for
{
seqStatus
,
err
:=
rollupClient
.
SyncStatus
(
ctx
)
if
err
!=
nil
{
return
err
}
if
seqStatus
.
SafeL2
.
Number
>=
safeBlockNum
{
return
nil
}
}
}
op-program/host/cmd/main.go
View file @
d6dd6eb9
package
main
package
main
import
(
import
(
"context"
"errors"
"fmt"
"fmt"
"io"
"os"
"os"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-program/host"
"github.com/ethereum-optimism/optimism/op-node/client"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/sources"
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"
"github.com/ethereum-optimism/optimism/op-program/host/flags"
"github.com/ethereum-optimism/optimism/op-program/host/flags"
"github.com/ethereum-optimism/optimism/op-program/host/kvstore"
"github.com/ethereum-optimism/optimism/op-program/host/l1"
"github.com/ethereum-optimism/optimism/op-program/host/l2"
"github.com/ethereum-optimism/optimism/op-program/host/prefetcher"
"github.com/ethereum-optimism/optimism/op-program/host/version"
"github.com/ethereum-optimism/optimism/op-program/host/version"
"github.com/ethereum-optimism/optimism/op-program/preimage"
oplog
"github.com/ethereum-optimism/optimism/op-service/log"
oplog
"github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli"
"github.com/urfave/cli"
)
)
...
@@ -46,15 +33,13 @@ var VersionWithMeta = func() string {
...
@@ -46,15 +33,13 @@ 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
,
host
.
FaultProofProgram
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Crit
(
"Application failed"
,
"message"
,
err
)
log
.
Crit
(
"Application failed"
,
"message"
,
err
)
}
else
{
log
.
Info
(
"Claim successfully verified"
)
}
}
}
}
...
@@ -99,110 +84,3 @@ func setupLogging(ctx *cli.Context) (log.Logger, error) {
...
@@ -99,110 +84,3 @@ func setupLogging(ctx *cli.Context) (log.Logger, error) {
logger
:=
oplog
.
NewLogger
(
logCfg
)
logger
:=
oplog
.
NewLogger
(
logCfg
)
return
logger
,
nil
return
logger
,
nil
}
}
type
L2Source
struct
{
*
sources
.
L2Client
*
sources
.
DebugClient
}
// FaultProofProgram is the programmatic entry-point for the fault proof program
func
FaultProofProgram
(
logger
log
.
Logger
,
cfg
*
config
.
Config
)
error
{
if
err
:=
cfg
.
Check
();
err
!=
nil
{
return
fmt
.
Errorf
(
"invalid config: %w"
,
err
)
}
cfg
.
Rollup
.
LogDescription
(
logger
,
chaincfg
.
L2ChainIDToNetworkName
)
ctx
:=
context
.
Background
()
var
kv
kvstore
.
KV
if
cfg
.
DataDir
==
""
{
logger
.
Info
(
"Using in-memory storage"
)
kv
=
kvstore
.
NewMemKV
()
}
else
{
logger
.
Info
(
"Creating disk storage"
,
"datadir"
,
cfg
.
DataDir
)
if
err
:=
os
.
MkdirAll
(
cfg
.
DataDir
,
0755
);
err
!=
nil
{
return
fmt
.
Errorf
(
"creating datadir: %w"
,
err
)
}
kv
=
kvstore
.
NewDiskKV
(
cfg
.
DataDir
)
}
var
preimageOracle
preimage
.
OracleFn
var
hinter
preimage
.
HinterFn
if
cfg
.
FetchingEnabled
()
{
logger
.
Info
(
"Connecting to L1 node"
,
"l1"
,
cfg
.
L1URL
)
l1RPC
,
err
:=
client
.
NewRPC
(
ctx
,
logger
,
cfg
.
L1URL
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to setup L1 RPC: %w"
,
err
)
}
logger
.
Info
(
"Connecting to L2 node"
,
"l2"
,
cfg
.
L2URL
)
l2RPC
,
err
:=
client
.
NewRPC
(
ctx
,
logger
,
cfg
.
L2URL
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to setup L2 RPC: %w"
,
err
)
}
l1ClCfg
:=
sources
.
L1ClientDefaultConfig
(
cfg
.
Rollup
,
cfg
.
L1TrustRPC
,
cfg
.
L1RPCKind
)
l2ClCfg
:=
sources
.
L2ClientDefaultConfig
(
cfg
.
Rollup
,
true
)
l1Cl
,
err
:=
sources
.
NewL1Client
(
l1RPC
,
logger
,
nil
,
l1ClCfg
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to create L1 client: %w"
,
err
)
}
l2Cl
,
err
:=
sources
.
NewL2Client
(
l2RPC
,
logger
,
nil
,
l2ClCfg
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to create L2 client: %w"
,
err
)
}
l2DebugCl
:=
&
L2Source
{
L2Client
:
l2Cl
,
DebugClient
:
sources
.
NewDebugClient
(
l2RPC
.
CallContext
)}
logger
.
Info
(
"Setting up pre-fetcher"
)
prefetch
:=
prefetcher
.
NewPrefetcher
(
l1Cl
,
l2DebugCl
,
kv
)
preimageOracle
=
asOracleFn
(
func
(
key
common
.
Hash
)
([]
byte
,
error
)
{
return
prefetch
.
GetPreimage
(
ctx
,
key
)
})
hinter
=
asHinter
(
prefetch
.
Hint
)
}
else
{
logger
.
Info
(
"Using offline mode. All required pre-images must be pre-populated."
)
preimageOracle
=
asOracleFn
(
kv
.
Get
)
hinter
=
func
(
v
preimage
.
Hint
)
{
logger
.
Debug
(
"ignoring prefetch hint"
,
"hint"
,
v
)
}
}
l1Source
:=
l1
.
NewSource
(
logger
,
preimageOracle
,
hinter
,
cfg
.
L1Head
)
l2Source
,
err
:=
l2
.
NewEngine
(
logger
,
preimageOracle
,
hinter
,
cfg
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"connect l2 oracle: %w"
,
err
)
}
logger
.
Info
(
"Starting derivation"
)
d
:=
cldr
.
NewDriver
(
logger
,
cfg
.
Rollup
,
l1Source
,
l2Source
,
cfg
.
L2ClaimBlockNumber
)
for
{
if
err
=
d
.
Step
(
ctx
);
errors
.
Is
(
err
,
io
.
EOF
)
{
break
}
else
if
err
!=
nil
{
return
err
}
}
claim
:=
cfg
.
L2Claim
if
!
d
.
ValidateClaim
(
eth
.
Bytes32
(
claim
))
{
return
ErrClaimNotValid
}
return
nil
}
func
asOracleFn
(
getter
func
(
key
common
.
Hash
)
([]
byte
,
error
))
preimage
.
OracleFn
{
return
func
(
key
preimage
.
Key
)
[]
byte
{
pre
,
err
:=
getter
(
key
.
PreimageKey
())
if
err
!=
nil
{
panic
(
fmt
.
Errorf
(
"preimage unavailable for key %v: %w"
,
key
,
err
))
}
return
pre
}
}
func
asHinter
(
hint
func
(
hint
string
)
error
)
preimage
.
HinterFn
{
return
func
(
v
preimage
.
Hint
)
{
err
:=
hint
(
v
.
Hint
())
if
err
!=
nil
{
panic
(
fmt
.
Errorf
(
"hint rejected %v: %w"
,
v
,
err
))
}
}
}
op-program/host/host.go
0 → 100644
View file @
d6dd6eb9
package
host
import
(
"context"
"errors"
"fmt"
"io"
"os"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/client"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/sources"
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/kvstore"
"github.com/ethereum-optimism/optimism/op-program/host/l1"
"github.com/ethereum-optimism/optimism/op-program/host/l2"
"github.com/ethereum-optimism/optimism/op-program/host/prefetcher"
"github.com/ethereum-optimism/optimism/op-program/preimage"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
)
var
(
ErrClaimNotValid
=
errors
.
New
(
"invalid claim"
)
)
type
L2Source
struct
{
*
sources
.
L2Client
*
sources
.
DebugClient
}
// FaultProofProgram is the programmatic entry-point for the fault proof program
func
FaultProofProgram
(
logger
log
.
Logger
,
cfg
*
config
.
Config
)
error
{
if
err
:=
cfg
.
Check
();
err
!=
nil
{
return
fmt
.
Errorf
(
"invalid config: %w"
,
err
)
}
cfg
.
Rollup
.
LogDescription
(
logger
,
chaincfg
.
L2ChainIDToNetworkName
)
ctx
:=
context
.
Background
()
var
kv
kvstore
.
KV
if
cfg
.
DataDir
==
""
{
logger
.
Info
(
"Using in-memory storage"
)
kv
=
kvstore
.
NewMemKV
()
}
else
{
logger
.
Info
(
"Creating disk storage"
,
"datadir"
,
cfg
.
DataDir
)
if
err
:=
os
.
MkdirAll
(
cfg
.
DataDir
,
0755
);
err
!=
nil
{
return
fmt
.
Errorf
(
"creating datadir: %w"
,
err
)
}
kv
=
kvstore
.
NewDiskKV
(
cfg
.
DataDir
)
}
var
preimageOracle
preimage
.
OracleFn
var
hinter
preimage
.
HinterFn
if
cfg
.
FetchingEnabled
()
{
logger
.
Info
(
"Connecting to L1 node"
,
"l1"
,
cfg
.
L1URL
)
l1RPC
,
err
:=
client
.
NewRPC
(
ctx
,
logger
,
cfg
.
L1URL
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to setup L1 RPC: %w"
,
err
)
}
logger
.
Info
(
"Connecting to L2 node"
,
"l2"
,
cfg
.
L2URL
)
l2RPC
,
err
:=
client
.
NewRPC
(
ctx
,
logger
,
cfg
.
L2URL
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to setup L2 RPC: %w"
,
err
)
}
l1ClCfg
:=
sources
.
L1ClientDefaultConfig
(
cfg
.
Rollup
,
cfg
.
L1TrustRPC
,
cfg
.
L1RPCKind
)
l2ClCfg
:=
sources
.
L2ClientDefaultConfig
(
cfg
.
Rollup
,
true
)
l1Cl
,
err
:=
sources
.
NewL1Client
(
l1RPC
,
logger
,
nil
,
l1ClCfg
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to create L1 client: %w"
,
err
)
}
l2Cl
,
err
:=
sources
.
NewL2Client
(
l2RPC
,
logger
,
nil
,
l2ClCfg
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to create L2 client: %w"
,
err
)
}
l2DebugCl
:=
&
L2Source
{
L2Client
:
l2Cl
,
DebugClient
:
sources
.
NewDebugClient
(
l2RPC
.
CallContext
)}
logger
.
Info
(
"Setting up pre-fetcher"
)
prefetch
:=
prefetcher
.
NewPrefetcher
(
l1Cl
,
l2DebugCl
,
kv
)
preimageOracle
=
asOracleFn
(
func
(
key
common
.
Hash
)
([]
byte
,
error
)
{
return
prefetch
.
GetPreimage
(
ctx
,
key
)
})
hinter
=
asHinter
(
prefetch
.
Hint
)
}
else
{
logger
.
Info
(
"Using offline mode. All required pre-images must be pre-populated."
)
preimageOracle
=
asOracleFn
(
kv
.
Get
)
hinter
=
func
(
v
preimage
.
Hint
)
{
logger
.
Debug
(
"ignoring prefetch hint"
,
"hint"
,
v
)
}
}
l1Source
:=
l1
.
NewSource
(
logger
,
preimageOracle
,
hinter
,
cfg
.
L1Head
)
l2Source
,
err
:=
l2
.
NewEngine
(
logger
,
preimageOracle
,
hinter
,
cfg
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"connect l2 oracle: %w"
,
err
)
}
logger
.
Info
(
"Starting derivation"
)
d
:=
cldr
.
NewDriver
(
logger
,
cfg
.
Rollup
,
l1Source
,
l2Source
,
cfg
.
L2ClaimBlockNumber
)
for
{
if
err
=
d
.
Step
(
ctx
);
errors
.
Is
(
err
,
io
.
EOF
)
{
break
}
else
if
err
!=
nil
{
return
err
}
}
if
!
d
.
ValidateClaim
(
eth
.
Bytes32
(
cfg
.
L2Claim
))
{
return
ErrClaimNotValid
}
return
nil
}
func
asOracleFn
(
getter
func
(
key
common
.
Hash
)
([]
byte
,
error
))
preimage
.
OracleFn
{
return
func
(
key
preimage
.
Key
)
[]
byte
{
pre
,
err
:=
getter
(
key
.
PreimageKey
())
if
err
!=
nil
{
panic
(
fmt
.
Errorf
(
"preimage unavailable for key %v: %w"
,
key
,
err
))
}
return
pre
}
}
func
asHinter
(
hint
func
(
hint
string
)
error
)
preimage
.
HinterFn
{
return
func
(
v
preimage
.
Hint
)
{
err
:=
hint
(
v
.
Hint
())
if
err
!=
nil
{
panic
(
fmt
.
Errorf
(
"hint rejected %v: %w"
,
v
,
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