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
b6a28df8
Unverified
Commit
b6a28df8
authored
Apr 25, 2023
by
inphi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
op-program: Bootstrap program via local oracle
parent
13d2bccf
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
109 additions
and
159 deletions
+109
-159
boot.go
op-program/client/boot.go
+43
-48
boot_test.go
op-program/client/boot_test.go
+36
-35
env.go
op-program/client/env.go
+0
-1
program.go
op-program/client/program.go
+6
-10
host.go
op-program/host/host.go
+5
-42
local.go
op-program/host/kvstore/local.go
+13
-17
local_test.go
op-program/host/kvstore/local_test.go
+6
-6
No files found.
op-program/client/boot.go
View file @
b6a28df8
...
...
@@ -3,70 +3,65 @@ package client
import
(
"encoding/binary"
"encoding/json"
"fmt"
"io"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-program/preimage"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params"
)
const
(
L1HeadLocalIndex
preimage
.
LocalIndexKey
=
iota
+
1
L2HeadLocalIndex
L2ClaimLocalIndex
L2ClaimBlockNumberLocalIndex
L2ChainConfigLocalIndex
RollupConfigLocalIndex
)
type
BootInfo
struct
{
// TODO(CLI-XXX): The rollup config will be hardcoded. It's configurable for testing purposes.
Rollup
*
rollup
.
Config
`json:"rollup"`
L2ChainConfig
*
params
.
ChainConfig
`json:"l2_chain_config"`
L1Head
common
.
Hash
`json:"l1_head"`
L2Head
common
.
Hash
`json:"l2_head"`
L2Claim
common
.
Hash
`json:"l2_claim"`
L2ClaimBlockNumber
uint64
`json:"l2_claim_block_number"`
L1Head
common
.
Hash
L2Head
common
.
Hash
L2Claim
common
.
Hash
L2ClaimBlockNumber
uint64
L2ChainConfig
*
params
.
ChainConfig
RollupConfig
*
rollup
.
Config
}
type
BootstrapOracleWriter
struct
{
w
io
.
Writer
type
oracleClient
interface
{
Get
(
key
preimage
.
Key
)
[]
byte
}
func
NewBootstrapOracleWriter
(
w
io
.
Writer
)
*
BootstrapOracleWriter
{
r
eturn
&
BootstrapOracleWriter
{
w
:
w
}
type
BootstrapClient
struct
{
r
oracleClient
}
func
(
bw
*
BootstrapOracleWriter
)
WriteBootInfo
(
info
*
BootInfo
)
error
{
// TODO(CLI-3751): Bootstrap from local oracle
payload
,
err
:=
json
.
Marshal
(
info
)
if
err
!=
nil
{
return
err
}
var
b
[]
byte
b
=
binary
.
BigEndian
.
AppendUint32
(
b
,
uint32
(
len
(
payload
)))
b
=
append
(
b
,
payload
...
)
_
,
err
=
bw
.
w
.
Write
(
b
)
return
err
func
NewBootstrapClient
(
r
oracleClient
)
*
BootstrapClient
{
return
&
BootstrapClient
{
r
:
r
}
}
type
BootstrapOracleReader
struct
{
r
io
.
Reader
}
func
NewBootstrapOracleReader
(
r
io
.
Reader
)
*
BootstrapOracleReader
{
return
&
BootstrapOracleReader
{
r
:
r
}
}
func
(
br
*
BootstrapOracleReader
)
BootInfo
()
(
*
BootInfo
,
error
)
{
var
length
uint32
if
err
:=
binary
.
Read
(
br
.
r
,
binary
.
BigEndian
,
&
length
);
err
!=
nil
{
if
err
==
io
.
EOF
{
return
nil
,
io
.
EOF
}
return
nil
,
fmt
.
Errorf
(
"failed to read bootinfo length prefix: %w"
,
err
)
}
payload
:=
make
([]
byte
,
length
)
if
length
>
0
{
if
_
,
err
:=
io
.
ReadFull
(
br
.
r
,
payload
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"failed to read bootinfo data (length %d): %w"
,
length
,
err
)
func
(
br
*
BootstrapClient
)
BootInfo
()
*
BootInfo
{
l1Head
:=
common
.
BytesToHash
(
br
.
r
.
Get
(
L1HeadLocalIndex
))
l2Head
:=
common
.
BytesToHash
(
br
.
r
.
Get
(
L2HeadLocalIndex
))
l2Claim
:=
common
.
BytesToHash
(
br
.
r
.
Get
(
L2ClaimLocalIndex
))
l2ClaimBlockNumber
:=
binary
.
BigEndian
.
Uint64
(
br
.
r
.
Get
(
L2ClaimBlockNumberLocalIndex
))
l2ChainConfig
:=
new
(
params
.
ChainConfig
)
err
:=
json
.
Unmarshal
(
br
.
r
.
Get
(
L2ChainConfigLocalIndex
),
&
l2ChainConfig
)
if
err
!=
nil
{
panic
(
"failed to bootstrap l2ChainConfig"
)
}
rollupConfig
:=
new
(
rollup
.
Config
)
err
=
json
.
Unmarshal
(
br
.
r
.
Get
(
RollupConfigLocalIndex
),
rollupConfig
)
if
err
!=
nil
{
panic
(
"failed to bootstrap rollup config"
)
}
var
bootInfo
BootInfo
if
err
:=
json
.
Unmarshal
(
payload
,
&
bootInfo
);
err
!=
nil
{
return
nil
,
err
return
&
BootInfo
{
L1Head
:
l1Head
,
L2Head
:
l2Head
,
L2Claim
:
l2Claim
,
L2ClaimBlockNumber
:
l2ClaimBlockNumber
,
L2ChainConfig
:
l2ChainConfig
,
RollupConfig
:
rollupConfig
,
}
return
&
bootInfo
,
nil
}
op-program/client/boot_test.go
View file @
b6a28df8
package
client
import
(
"io"
"encoding/binary"
"encoding/json"
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-program/preimage"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
)
func
TestBootstrapOracle
(
t
*
testing
.
T
)
{
r
,
w
:=
io
.
Pipe
()
br
:=
NewBootstrapOracleReader
(
r
)
bw
:=
NewBootstrapOracleWriter
(
w
)
bootInfo
:=
BootInfo
{
Rollup
:
new
(
rollup
.
Config
),
L2ChainConfig
:
new
(
params
.
ChainConfig
),
L1Head
:
common
.
HexToHash
(
"0xffffa"
),
L2Head
:
common
.
HexToHash
(
"0xffffb"
),
L2Claim
:
common
.
HexToHash
(
"0xffffc"
),
func
TestBootstrapClient
(
t
*
testing
.
T
)
{
bootInfo
:=
&
BootInfo
{
L1Head
:
common
.
HexToHash
(
"0x1111"
),
L2Head
:
common
.
HexToHash
(
"0x2222"
),
L2Claim
:
common
.
HexToHash
(
"0x3333"
),
L2ClaimBlockNumber
:
1
,
L2ChainConfig
:
params
.
GoerliChainConfig
,
RollupConfig
:
&
chaincfg
.
Goerli
,
}
mockOracle
:=
&
mockBoostrapOracle
{
bootInfo
}
readBootInfo
:=
NewBootstrapClient
(
mockOracle
)
.
BootInfo
()
require
.
EqualValues
(
t
,
bootInfo
,
readBootInfo
)
}
go
func
()
{
err
:=
bw
.
WriteBootInfo
(
&
bootInfo
)
require
.
NoError
(
t
,
err
)
}()
type
result
struct
{
bootInnfo
*
BootInfo
err
error
}
read
:=
make
(
chan
result
)
go
func
()
{
readBootInfo
,
err
:=
br
.
BootInfo
()
read
<-
result
{
readBootInfo
,
err
}
close
(
read
)
}()
type
mockBoostrapOracle
struct
{
b
*
BootInfo
}
select
{
case
<-
time
.
After
(
time
.
Second
*
30
)
:
t
.
Error
(
"timeout waiting for bootstrap oracle"
)
case
r
:=
<-
read
:
require
.
NoError
(
t
,
r
.
err
)
require
.
Equal
(
t
,
bootInfo
,
*
r
.
bootInnfo
)
func
(
o
*
mockBoostrapOracle
)
Get
(
key
preimage
.
Key
)
[]
byte
{
switch
key
.
PreimageKey
()
{
case
L1HeadLocalIndex
.
PreimageKey
()
:
return
o
.
b
.
L1Head
[
:
]
case
L2HeadLocalIndex
.
PreimageKey
()
:
return
o
.
b
.
L2Head
[
:
]
case
L2ClaimLocalIndex
.
PreimageKey
()
:
return
o
.
b
.
L2Claim
[
:
]
case
L2ClaimBlockNumberLocalIndex
.
PreimageKey
()
:
return
binary
.
BigEndian
.
AppendUint64
(
nil
,
o
.
b
.
L2ClaimBlockNumber
)
case
L2ChainConfigLocalIndex
.
PreimageKey
()
:
b
,
_
:=
json
.
Marshal
(
o
.
b
.
L2ChainConfig
)
return
b
case
RollupConfigLocalIndex
.
PreimageKey
()
:
b
,
_
:=
json
.
Marshal
(
o
.
b
.
RollupConfig
)
return
b
default
:
panic
(
"unknown key"
)
}
}
op-program/client/env.go
View file @
b6a28df8
...
...
@@ -6,6 +6,5 @@ const (
HClientWFd
PClientRFd
PClientWFd
BootRFd
// TODO(CLI-3751): remove
MaxFd
)
op-program/client/program.go
View file @
b6a28df8
...
...
@@ -26,8 +26,7 @@ func Main(logger log.Logger) {
log
.
Info
(
"Starting fault proof program client"
)
preimageOracle
:=
CreatePreimageChannel
()
preimageHinter
:=
CreateHinterChannel
()
bootOracle
:=
os
.
NewFile
(
BootRFd
,
"bootR"
)
err
:=
RunProgram
(
logger
,
bootOracle
,
preimageOracle
,
preimageHinter
)
err
:=
RunProgram
(
logger
,
preimageOracle
,
preimageHinter
)
if
err
!=
nil
{
log
.
Error
(
"Program failed"
,
"err"
,
err
)
os
.
Exit
(
1
)
...
...
@@ -37,21 +36,18 @@ func Main(logger log.Logger) {
}
// RunProgram executes the Program, while attached to an IO based pre-image oracle, to be served by a host.
func
RunProgram
(
logger
log
.
Logger
,
bootOracle
io
.
Reader
,
preimageOracle
io
.
ReadWriter
,
preimageHinter
io
.
ReadWriter
)
error
{
bootReader
:=
NewBootstrapOracleReader
(
bootOracle
)
bootInfo
,
err
:=
bootReader
.
BootInfo
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to read boot info: %w"
,
err
)
}
logger
.
Debug
(
"Loaded boot info"
,
"bootInfo"
,
bootInfo
)
func
RunProgram
(
logger
log
.
Logger
,
preimageOracle
io
.
ReadWriter
,
preimageHinter
io
.
ReadWriter
)
error
{
pClient
:=
preimage
.
NewOracleClient
(
preimageOracle
)
hClient
:=
preimage
.
NewHintWriter
(
preimageHinter
)
l1PreimageOracle
:=
l1
.
NewPreimageOracle
(
pClient
,
hClient
)
l2PreimageOracle
:=
l2
.
NewPreimageOracle
(
pClient
,
hClient
)
bootInfo
:=
NewBootstrapClient
(
pClient
)
.
BootInfo
()
logger
.
Info
(
"Program Bootstrapped"
,
"bootInfo"
,
bootInfo
)
return
runDerivation
(
logger
,
bootInfo
.
Rollup
,
bootInfo
.
Rollup
Config
,
bootInfo
.
L2ChainConfig
,
bootInfo
.
L1Head
,
bootInfo
.
L2Head
,
...
...
op-program/host/host.go
View file @
b6a28df8
...
...
@@ -79,7 +79,6 @@ func FaultProofProgram(logger log.Logger, cfg *config.Config) error {
}
}
// TODO(CLI-3751: Load local preimages
localPreimageSource
:=
kvstore
.
NewLocalPreimageSource
(
cfg
)
splitter
:=
kvstore
.
NewPreimageSourceSplitter
(
localPreimageSource
.
Get
,
getPreimage
)
...
...
@@ -101,20 +100,14 @@ func FaultProofProgram(logger log.Logger, cfg *config.Config) error {
hHost
:=
preimage
.
NewHintReader
(
hHostRW
)
routeHints
(
logger
,
hHost
,
hinter
)
bootClientR
,
bootHostW
,
err
:=
os
.
Pipe
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to create boot info pipe: %w"
,
err
)
}
var
cmd
*
exec
.
Cmd
if
cfg
.
Detached
{
cmd
=
exec
.
Command
(
os
.
Args
[
0
],
os
.
Args
[
1
:
]
...
)
cmd
=
exec
.
Command
Context
(
ctx
,
os
.
Args
[
0
],
os
.
Args
[
1
:
]
...
)
cmd
.
ExtraFiles
=
make
([]
*
os
.
File
,
cl
.
MaxFd
-
3
)
// not including stdin, stdout and stderr
cmd
.
ExtraFiles
[
cl
.
HClientRFd
-
3
]
=
hClientRW
.
Reader
()
cmd
.
ExtraFiles
[
cl
.
HClientWFd
-
3
]
=
hClientRW
.
Writer
()
cmd
.
ExtraFiles
[
cl
.
PClientRFd
-
3
]
=
pClientRW
.
Reader
()
cmd
.
ExtraFiles
[
cl
.
PClientWFd
-
3
]
=
pClientRW
.
Writer
()
cmd
.
ExtraFiles
[
cl
.
BootRFd
-
3
]
=
bootClientR
cmd
.
Stdout
=
os
.
Stdout
// for debugging
cmd
.
Stderr
=
os
.
Stderr
// for debugging
cmd
.
Env
=
append
(
os
.
Environ
(),
fmt
.
Sprintf
(
"%s=true"
,
opProgramChildEnvName
))
...
...
@@ -123,33 +116,13 @@ func FaultProofProgram(logger log.Logger, cfg *config.Config) error {
if
err
!=
nil
{
return
fmt
.
Errorf
(
"program cmd failed to start: %w"
,
err
)
}
}
bootInfo
:=
cl
.
BootInfo
{
Rollup
:
cfg
.
Rollup
,
L2ChainConfig
:
cfg
.
L2ChainConfig
,
L1Head
:
cfg
.
L1Head
,
L2Head
:
cfg
.
L2Head
,
L2Claim
:
cfg
.
L2Claim
,
L2ClaimBlockNumber
:
cfg
.
L2ClaimBlockNumber
,
}
// Spawn a goroutine to write the boot info to avoid blocking this host's goroutine
// if we're running in detached mode
bootInitErrorCh
:=
initializeBootInfoAsync
(
&
bootInfo
,
bootHostW
)
if
!
cfg
.
Detached
{
return
cl
.
RunProgram
(
logger
,
bootClientR
,
pClientRW
,
hClientRW
)
}
if
err
:=
<-
bootInitErrorCh
;
err
!=
nil
{
// return early as a detached client is blocked waiting for the boot info
return
fmt
.
Errorf
(
"failed to write boot info: %w"
,
err
)
}
if
cfg
.
Detached
{
err
:=
cmd
.
Wait
()
if
err
!=
nil
{
if
err
:=
cmd
.
Wait
();
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to wait for child program: %w"
,
err
)
}
}
return
nil
}
else
{
return
cl
.
RunProgram
(
logger
,
pClientRW
,
hClientRW
)
}
}
func
makePrefetcher
(
ctx
context
.
Context
,
logger
log
.
Logger
,
kv
kvstore
.
KV
,
cfg
*
config
.
Config
)
(
*
prefetcher
.
Prefetcher
,
error
)
{
...
...
@@ -179,16 +152,6 @@ func makePrefetcher(ctx context.Context, logger log.Logger, kv kvstore.KV, cfg *
return
prefetcher
.
NewPrefetcher
(
logger
,
l1Cl
,
l2DebugCl
,
kv
),
nil
}
func
initializeBootInfoAsync
(
bootInfo
*
cl
.
BootInfo
,
bootOracle
*
os
.
File
)
<-
chan
error
{
bootWriteErr
:=
make
(
chan
error
,
1
)
go
func
()
{
bootOracleWriter
:=
cl
.
NewBootstrapOracleWriter
(
bootOracle
)
bootWriteErr
<-
bootOracleWriter
.
WriteBootInfo
(
bootInfo
)
close
(
bootWriteErr
)
}()
return
bootWriteErr
}
func
routeHints
(
logger
log
.
Logger
,
hintReader
*
preimage
.
HintReader
,
hinter
func
(
hint
string
)
error
)
{
go
func
()
{
for
{
...
...
op-program/host/kvstore/local.go
View file @
b6a28df8
...
...
@@ -4,8 +4,8 @@ import (
"encoding/binary"
"encoding/json"
"github.com/ethereum-optimism/optimism/op-program/client"
"github.com/ethereum-optimism/optimism/op-program/host/config"
"github.com/ethereum-optimism/optimism/op-program/preimage"
"github.com/ethereum/go-ethereum/common"
)
...
...
@@ -17,32 +17,28 @@ func NewLocalPreimageSource(config *config.Config) *LocalPreimageSource {
return
&
LocalPreimageSource
{
config
}
}
func
localKey
(
num
int64
)
common
.
Hash
{
return
preimage
.
LocalIndexKey
(
num
)
.
PreimageKey
()
}
var
(
L1HeadKey
=
localKey
(
1
)
L2HeadKey
=
localKey
(
2
)
L2ClaimKey
=
localKey
(
3
)
L2ClaimBlockNumberKey
=
localKey
(
4
)
L2ChainConfigKey
=
localKey
(
5
)
RollupKey
=
localKey
(
6
)
l1HeadKey
=
client
.
L1HeadLocalIndex
.
PreimageKey
(
)
l2HeadKey
=
client
.
L2HeadLocalIndex
.
PreimageKey
(
)
l2ClaimKey
=
client
.
L2ClaimLocalIndex
.
PreimageKey
(
)
l2ClaimBlockNumberKey
=
client
.
L2ClaimBlockNumberLocalIndex
.
PreimageKey
(
)
l2ChainConfigKey
=
client
.
L2ChainConfigLocalIndex
.
PreimageKey
(
)
rollupKey
=
client
.
RollupConfigLocalIndex
.
PreimageKey
(
)
)
func
(
s
*
LocalPreimageSource
)
Get
(
key
common
.
Hash
)
([]
byte
,
error
)
{
switch
key
{
case
L
1HeadKey
:
case
l
1HeadKey
:
return
s
.
config
.
L1Head
.
Bytes
(),
nil
case
L
2HeadKey
:
case
l
2HeadKey
:
return
s
.
config
.
L2Head
.
Bytes
(),
nil
case
L
2ClaimKey
:
case
l
2ClaimKey
:
return
s
.
config
.
L2Claim
.
Bytes
(),
nil
case
L
2ClaimBlockNumberKey
:
case
l
2ClaimBlockNumberKey
:
return
binary
.
BigEndian
.
AppendUint64
(
nil
,
s
.
config
.
L2ClaimBlockNumber
),
nil
case
L
2ChainConfigKey
:
case
l
2ChainConfigKey
:
return
json
.
Marshal
(
s
.
config
.
L2ChainConfig
)
case
R
ollupKey
:
case
r
ollupKey
:
return
json
.
Marshal
(
s
.
config
.
Rollup
)
default
:
return
nil
,
ErrNotFound
...
...
op-program/host/kvstore/local_test.go
View file @
b6a28df8
...
...
@@ -28,12 +28,12 @@ func TestLocalPreimageSource(t *testing.T) {
key
common
.
Hash
expected
[]
byte
}{
{
"L1Head"
,
L
1HeadKey
,
cfg
.
L1Head
.
Bytes
()},
{
"L2Head"
,
L
2HeadKey
,
cfg
.
L2Head
.
Bytes
()},
{
"L2Claim"
,
L
2ClaimKey
,
cfg
.
L2Claim
.
Bytes
()},
{
"L2ClaimBlockNumber"
,
L
2ClaimBlockNumberKey
,
binary
.
BigEndian
.
AppendUint64
(
nil
,
cfg
.
L2ClaimBlockNumber
)},
{
"Rollup"
,
R
ollupKey
,
asJson
(
t
,
cfg
.
Rollup
)},
{
"ChainConfig"
,
L
2ChainConfigKey
,
asJson
(
t
,
cfg
.
L2ChainConfig
)},
{
"L1Head"
,
l
1HeadKey
,
cfg
.
L1Head
.
Bytes
()},
{
"L2Head"
,
l
2HeadKey
,
cfg
.
L2Head
.
Bytes
()},
{
"L2Claim"
,
l
2ClaimKey
,
cfg
.
L2Claim
.
Bytes
()},
{
"L2ClaimBlockNumber"
,
l
2ClaimBlockNumberKey
,
binary
.
BigEndian
.
AppendUint64
(
nil
,
cfg
.
L2ClaimBlockNumber
)},
{
"Rollup"
,
r
ollupKey
,
asJson
(
t
,
cfg
.
Rollup
)},
{
"ChainConfig"
,
l
2ChainConfigKey
,
asJson
(
t
,
cfg
.
L2ChainConfig
)},
{
"Unknown"
,
preimage
.
LocalIndexKey
(
1000
)
.
PreimageKey
(),
nil
},
}
for
_
,
test
:=
range
tests
{
...
...
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