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
111f3f3a
Unverified
Commit
111f3f3a
authored
Nov 13, 2023
by
Mark Tyneway
Committed by
GitHub
Nov 13, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #8116 from ethereum-optimism/ctb/load-allocs-setup
op-node,contracts-bedrock: setup `loadAllocs` usage
parents
2088e2e7
713d950a
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
235 additions
and
73 deletions
+235
-73
cmd.go
op-node/cmd/genesis/cmd.go
+170
-71
.gitignore
packages/contracts-bedrock/.gitignore
+3
-1
package.json
packages/contracts-bedrock/package.json
+1
-1
generate-l2-genesis.sh
packages/contracts-bedrock/scripts/generate-l2-genesis.sh
+34
-0
block.json
packages/contracts-bedrock/test/mocks/block.json
+27
-0
No files found.
op-node/cmd/genesis/cmd.go
View file @
111f3f3a
...
...
@@ -11,6 +11,7 @@ import (
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
...
...
@@ -21,29 +22,69 @@ import (
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
)
var
Subcommands
=
cli
.
Commands
{
{
Name
:
"l1"
,
Usage
:
"Generates a L1 genesis state file"
,
Flags
:
[]
cli
.
Flag
{
&
cli
.
StringFlag
{
var
(
l1RPCFlag
=
&
cli
.
StringFlag
{
Name
:
"l1-rpc"
,
Usage
:
"RPC URL for an Ethereum L1 node. Cannot be used with --l1-starting-block"
,
}
l1StartingBlockFlag
=
&
cli
.
PathFlag
{
Name
:
"l1-starting-block"
,
Usage
:
"Path to a JSON file containing the L1 starting block. Overrides the need for using an L1 RPC to fetch the block. Cannot be used with --l1-rpc"
,
}
deployConfigFlag
=
&
cli
.
PathFlag
{
Name
:
"deploy-config"
,
Usage
:
"Path to deploy config file"
,
Required
:
true
,
},
&
cli
.
StringFlag
{
}
deploymentDirFlag
=
&
cli
.
PathFlag
{
Name
:
"deployment-dir"
,
Usage
:
"Path to network deployment directory. Cannot be used with --l1-deployments"
,
}
l1DeploymentsFlag
=
&
cli
.
PathFlag
{
Name
:
"l1-deployments"
,
Usage
:
"Path to L1 deployments JSON file. Cannot be used with --deployment-dir"
,
}
outfileL2Flag
=
&
cli
.
PathFlag
{
Name
:
"outfile.l2"
,
Usage
:
"Path to L2 genesis output file"
,
}
outfileRollupFlag
=
&
cli
.
PathFlag
{
Name
:
"outfile.rollup"
,
Usage
:
"Path to rollup output file"
,
}
l1AllocsFlag
=
&
cli
.
StringFlag
{
Name
:
"l1-allocs"
,
Usage
:
"Path to L1 genesis state dump"
,
},
&
cli
.
StringFlag
{
Name
:
"l1-deployments"
,
Usage
:
"Path to L1 deployments file"
,
},
&
cli
.
StringFlag
{
}
outfileL1Flag
=
&
cli
.
StringFlag
{
Name
:
"outfile.l1"
,
Usage
:
"Path to L1 genesis output file"
,
},
},
}
l1Flags
=
[]
cli
.
Flag
{
deployConfigFlag
,
l1AllocsFlag
,
l1DeploymentsFlag
,
outfileL1Flag
,
}
l2Flags
=
[]
cli
.
Flag
{
l1RPCFlag
,
l1StartingBlockFlag
,
deployConfigFlag
,
deploymentDirFlag
,
l1DeploymentsFlag
,
outfileL2Flag
,
outfileRollupFlag
,
}
)
var
Subcommands
=
cli
.
Commands
{
{
Name
:
"l1"
,
Usage
:
"Generates a L1 genesis state file"
,
Flags
:
l1Flags
,
Action
:
func
(
ctx
*
cli
.
Context
)
error
{
deployConfig
:=
ctx
.
String
(
"deploy-config"
)
config
,
err
:=
genesis
.
NewDeployConfig
(
deployConfig
)
...
...
@@ -85,7 +126,7 @@ var Subcommands = cli.Commands{
return
err
}
return
write
Genesis
File
(
ctx
.
String
(
"outfile.l1"
),
l1Genesis
)
return
write
JSON
File
(
ctx
.
String
(
"outfile.l1"
),
l1Genesis
)
},
},
{
...
...
@@ -93,44 +134,20 @@ var Subcommands = cli.Commands{
Usage
:
"Generates an L2 genesis file and rollup config suitable for a deployed network"
,
Description
:
"Generating the L2 genesis depends on knowledge of L1 contract addresses for the bridge to be secure. "
+
"A deploy config and either a deployment directory or an L1 deployments file are used to create the L2 genesis. "
+
"The deploy directory and L1 deployments file are generated by the L1 contract deployments."
,
Flags
:
[]
cli
.
Flag
{
&
cli
.
StringFlag
{
Name
:
"l1-rpc"
,
Usage
:
"L1 RPC URL"
,
},
&
cli
.
StringFlag
{
Name
:
"deploy-config"
,
Usage
:
"Path to deploy config file"
,
Required
:
true
,
},
&
cli
.
StringFlag
{
Name
:
"deployment-dir"
,
Usage
:
"Path to network deployment directory. Cannot be used with --l1-deployments"
,
},
&
cli
.
StringFlag
{
Name
:
"l1-deployments"
,
Usage
:
"Path to L1 deployments JSON file. Cannot be used with --deployment-dir"
,
},
&
cli
.
StringFlag
{
Name
:
"outfile.l2"
,
Usage
:
"Path to L2 genesis output file"
,
},
&
cli
.
StringFlag
{
Name
:
"outfile.rollup"
,
Usage
:
"Path to rollup output file"
,
},
},
"The deploy directory and L1 deployments file are generated by the L1 contract deployments. "
+
"An L1 starting block is necessary, it can either be fetched dynamically using config in the deploy config "
+
"or it can be provided as a JSON file."
,
Flags
:
l2Flags
,
Action
:
func
(
ctx
*
cli
.
Context
)
error
{
deployConfig
:=
ctx
.
String
(
"deploy-config"
)
deployConfig
:=
ctx
.
Path
(
"deploy-config"
)
log
.
Info
(
"Deploy config"
,
"path"
,
deployConfig
)
config
,
err
:=
genesis
.
NewDeployConfig
(
deployConfig
)
if
err
!=
nil
{
return
err
}
deployDir
:=
ctx
.
String
(
"deployment-dir"
)
l1Deployments
:=
ctx
.
String
(
"l1-deployments"
)
deployDir
:=
ctx
.
Path
(
"deployment-dir"
)
l1Deployments
:=
ctx
.
Path
(
"l1-deployments"
)
if
deployDir
!=
""
&&
l1Deployments
!=
""
{
return
errors
.
New
(
"cannot specify both --deployment-dir and --l1-deployments"
)
...
...
@@ -139,6 +156,16 @@ var Subcommands = cli.Commands{
return
errors
.
New
(
"must specify either --deployment-dir or --l1-deployments"
)
}
l1StartBlockPath
:=
ctx
.
Path
(
"l1-starting-block"
)
l1RPC
:=
ctx
.
String
(
"l1-rpc"
)
if
l1StartBlockPath
==
""
&&
l1RPC
==
""
{
return
errors
.
New
(
"must specify either --l1-starting-block or --l1-rpc"
)
}
if
l1StartBlockPath
!=
""
&&
l1RPC
!=
""
{
return
errors
.
New
(
"cannot specify both --l1-starting-block and --l1-rpc"
)
}
if
deployDir
!=
""
{
log
.
Info
(
"Deployment directory"
,
"path"
,
deployDir
)
depPath
,
network
:=
filepath
.
Split
(
deployDir
)
...
...
@@ -154,31 +181,49 @@ var Subcommands = cli.Commands{
}
if
l1Deployments
!=
""
{
log
.
Info
(
"L1 deployments"
,
"path"
,
l1Deployments
)
deployments
,
err
:=
genesis
.
NewL1Deployments
(
l1Deployments
)
if
err
!=
nil
{
return
err
return
fmt
.
Errorf
(
"cannot read L1 deployments at %s: %w"
,
l1Deployments
,
err
)
}
config
.
SetDeployments
(
deployments
)
}
client
,
err
:=
ethclient
.
Dial
(
ctx
.
String
(
"l1-rpc"
))
var
l1StartBlock
*
types
.
Block
if
l1StartBlockPath
!=
""
{
if
l1StartBlock
,
err
=
readBlockJSON
(
l1StartBlockPath
);
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot read L1 starting block at %s: %w"
,
l1StartBlockPath
,
err
)
}
}
if
l1RPC
!=
""
{
client
,
err
:=
ethclient
.
Dial
(
l1RPC
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot dial %s: %w"
,
ctx
.
String
(
"l1-rpc"
)
,
err
)
return
fmt
.
Errorf
(
"cannot dial %s: %w"
,
l1RPC
,
err
)
}
var
l1StartBlock
*
types
.
Block
if
config
.
L1StartingBlockTag
==
nil
{
l1StartBlock
,
err
=
client
.
BlockByNumber
(
context
.
Background
(),
nil
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot fetch latest block: %w"
,
err
)
}
tag
:=
rpc
.
BlockNumberOrHashWithHash
(
l1StartBlock
.
Hash
(),
true
)
config
.
L1StartingBlockTag
=
(
*
genesis
.
MarshalableRPCBlockNumberOrHash
)(
&
tag
)
}
else
if
config
.
L1StartingBlockTag
.
BlockHash
!=
nil
{
l1StartBlock
,
err
=
client
.
BlockByHash
(
context
.
Background
(),
*
config
.
L1StartingBlockTag
.
BlockHash
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot fetch block by hash: %w"
,
err
)
}
}
else
if
config
.
L1StartingBlockTag
.
BlockNumber
!=
nil
{
l1StartBlock
,
err
=
client
.
BlockByNumber
(
context
.
Background
(),
big
.
NewInt
(
config
.
L1StartingBlockTag
.
BlockNumber
.
Int64
()))
}
if
err
!=
nil
{
return
fmt
.
Errorf
(
"error getting l1 start block: %w"
,
err
)
return
fmt
.
Errorf
(
"cannot fetch block by number: %w"
,
err
)
}
}
}
// Ensure that there is a starting L1 block
if
l1StartBlock
==
nil
{
return
errors
.
New
(
"no starting L1 block"
)
}
// Sanity check the config. Do this after filling in the L1StartingBlockTag
...
...
@@ -204,16 +249,18 @@ var Subcommands = cli.Commands{
return
fmt
.
Errorf
(
"generated rollup config does not pass validation: %w"
,
err
)
}
if
err
:=
write
Genesis
File
(
ctx
.
String
(
"outfile.l2"
),
l2Genesis
);
err
!=
nil
{
if
err
:=
write
JSON
File
(
ctx
.
String
(
"outfile.l2"
),
l2Genesis
);
err
!=
nil
{
return
err
}
return
write
Genesis
File
(
ctx
.
String
(
"outfile.rollup"
),
rollupConfig
)
return
write
JSON
File
(
ctx
.
String
(
"outfile.rollup"
),
rollupConfig
)
},
},
}
func
writeGenesisFile
(
outfile
string
,
input
any
)
error
{
f
,
err
:=
os
.
OpenFile
(
outfile
,
os
.
O_WRONLY
|
os
.
O_CREATE
|
os
.
O_TRUNC
,
0
o755
)
// writeJSONFile will write a JSON file to disk at the given path
// containing the JSON serialized input value.
func
writeJSONFile
(
outfile
string
,
input
any
)
error
{
f
,
err
:=
os
.
OpenFile
(
outfile
,
os
.
O_WRONLY
|
os
.
O_CREATE
|
os
.
O_TRUNC
,
0
o644
)
if
err
!=
nil
{
return
err
}
...
...
@@ -223,3 +270,55 @@ func writeGenesisFile(outfile string, input any) error {
enc
.
SetIndent
(
""
,
" "
)
return
enc
.
Encode
(
input
)
}
// rpcBlock represents the JSON serialization of a block from an Ethereum RPC.
type
rpcBlock
struct
{
Hash
common
.
Hash
`json:"hash"`
Transactions
[]
rpcTransaction
`json:"transactions"`
UncleHashes
[]
common
.
Hash
`json:"uncles"`
Withdrawals
[]
*
types
.
Withdrawal
`json:"withdrawals,omitempty"`
}
// rpcTransaction represents the JSON serialization of a transaction from an Ethereum RPC.
type
rpcTransaction
struct
{
tx
*
types
.
Transaction
txExtraInfo
}
// txExtraInfo includes extra information about a transaction that is returned from
// and Ethereum RPC endpoint.
type
txExtraInfo
struct
{
BlockNumber
*
string
`json:"blockNumber,omitempty"`
BlockHash
*
common
.
Hash
`json:"blockHash,omitempty"`
From
*
common
.
Address
`json:"from,omitempty"`
}
// readBlockJSON will read a JSON file from disk containing a serialized block.
// This logic can break if the block format changes but there is no modular way
// to turn a block into JSON in go-ethereum.
func
readBlockJSON
(
path
string
)
(
*
types
.
Block
,
error
)
{
raw
,
err
:=
os
.
ReadFile
(
path
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"block file at %s not found: %w"
,
path
,
err
)
}
var
header
types
.
Header
if
err
:=
json
.
Unmarshal
(
raw
,
&
header
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"cannot unmarshal block: %w"
,
err
)
}
var
body
rpcBlock
if
err
:=
json
.
Unmarshal
(
raw
,
&
body
);
err
!=
nil
{
return
nil
,
err
}
if
len
(
body
.
UncleHashes
)
>
0
{
return
nil
,
fmt
.
Errorf
(
"cannot unmarshal block with uncles"
)
}
txs
:=
make
([]
*
types
.
Transaction
,
len
(
body
.
Transactions
))
for
i
,
tx
:=
range
body
.
Transactions
{
txs
[
i
]
=
tx
.
tx
}
return
types
.
NewBlockWithHeader
(
&
header
)
.
WithBody
(
txs
,
nil
)
.
WithWithdrawals
(
body
.
Withdrawals
),
nil
}
packages/contracts-bedrock/.gitignore
View file @
111f3f3a
...
...
@@ -3,12 +3,14 @@ artifacts
forge-artifacts
cache
broadcast
typechain
# Metrics
coverage.out
.resource-metering.csv
# Testing State
.testdata
# Scripts
scripts/go-ffi/go-ffi
...
...
packages/contracts-bedrock/package.json
View file @
111f3f3a
...
...
@@ -29,7 +29,7 @@
"validate-spacers"
:
"pnpm build && pnpm validate-spacers:no-build"
,
"slither"
:
"./scripts/slither.sh"
,
"slither:triage"
:
"TRIAGE_MODE=1 ./scripts/slither.sh"
,
"clean"
:
"rm -rf ./artifacts ./forge-artifacts ./cache ./tsconfig.tsbuildinfo ./tsconfig.build.tsbuildinfo ./scripts/go-ffi/go-ffi"
,
"clean"
:
"rm -rf ./artifacts ./forge-artifacts ./cache ./tsconfig.tsbuildinfo ./tsconfig.build.tsbuildinfo ./scripts/go-ffi/go-ffi
./.testdata
"
,
"preinstall"
:
"npx only-allow pnpm"
,
"pre-pr:no-build"
:
"pnpm gas-snapshot:no-build && pnpm storage-snapshot && pnpm semver-lock && pnpm autogen:invariant-docs && pnpm lint && pnpm bindings:go"
,
"pre-pr"
:
"pnpm clean && pnpm build:go-ffi && pnpm build && pnpm pre-pr:no-build"
,
...
...
packages/contracts-bedrock/scripts/generate-l2-genesis.sh
0 → 100755
View file @
111f3f3a
#!/usr/bin/env bash
# Create a L2 genesis.json suitable for the solidity tests to
# ingest using `vm.loadAllocs(string)`.
# This script depends on the relative path to the op-node from
# contracts-bedrock
SCRIPTS_DIR
=
"
$(
cd
"
$(
dirname
"
${
BASH_SOURCE
[0]
}
"
)
"
>
/dev/null
&&
pwd
)
"
CONTRACTS_DIR
=
"
$(
realpath
"
$SCRIPTS_DIR
/.."
)
"
MONOREPO_BASE
=
"
$(
realpath
"
$CONTRACTS_DIR
/../.."
)
"
DEPLOY_ARTIFACT
=
"
$CONTRACTS_DIR
/deployments/hardhat/.deploy"
OP_NODE
=
"
$MONOREPO_BASE
/op-node/cmd/main.go"
L1_STARTING_BLOCK_PATH
=
"
$CONTRACTS_DIR
/test/mocks/block.json"
TESTDATA_DIR
=
"
$CONTRACTS_DIR
/.testdata"
OUTFILE_L2
=
"
$TESTDATA_DIR
/genesis.json"
OUTFILE_ROLLUP
=
"
$TESTDATA_DIR
/rollup.json"
OUTFILE_ALLOC
=
"
$TESTDATA_DIR
/alloc.json"
if
[
!
-f
"
$DEPLOY_ARTIFACT
"
]
;
then
forge script
$CONTRACTS_DIR
/scripts/Deploy.s.sol:Deploy 2>&1 /dev/null
fi
if
[
!
-d
"
$TESTDATA_DIR
"
]
;
then
mkdir
-p
"
$TESTDATA_DIR
"
go run
$OP_NODE
genesis l2
\
--deploy-config
"
$CONTRACTS_DIR
/deploy-config/hardhat.json"
\
--l1-deployments
"
$DEPLOY_ARTIFACT
"
\
--l1-starting-block
"
$L1_STARTING_BLOCK_PATH
"
\
--outfile
.l2
"
$OUTFILE_L2
"
\
--outfile
.rollup
"
$OUTFILE_ROLLUP
"
>
/dev/null 2>&1
fi
packages/contracts-bedrock/test/mocks/block.json
0 → 100644
View file @
111f3f3a
{
"hash"
:
"0xfd3c5e25a80f54a53c58bd3ad8c076dc1c0cdbd44ec2164d2d2b8cc50481cb78"
,
"parentHash"
:
"0x0000000000000000000000000000000000000000000000000000000000000000"
,
"sha3Uncles"
:
"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
,
"miner"
:
"0x0000000000000000000000000000000000000000"
,
"stateRoot"
:
"0x0000000000000000000000000000000000000000000000000000000000000000"
,
"transactionsRoot"
:
"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
,
"receiptsRoot"
:
"0x0000000000000000000000000000000000000000000000000000000000000000"
,
"number"
:
"0x0"
,
"gasUsed"
:
"0x0"
,
"gasLimit"
:
"0x1c9c380"
,
"extraData"
:
"0x"
,
"logsBloom"
:
"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
,
"timestamp"
:
"0x654caabb"
,
"difficulty"
:
"0x0"
,
"totalDifficulty"
:
"0x0"
,
"sealFields"
:
[
"0x0000000000000000000000000000000000000000000000000000000000000000"
,
"0x0000000000000000"
],
"uncles"
:
[],
"transactions"
:
[],
"size"
:
"0x202"
,
"mixHash"
:
"0x0000000000000000000000000000000000000000000000000000000000000000"
,
"nonce"
:
"0x0000000000000000"
,
"baseFeePerGas"
:
"0x3b9aca00"
}
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