Commit 5e151113 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

op-node: L1 genesis generation (#3298)

* op-chain-ops: some cleanup and modularization

* op-node: add `op-node genesis devnet-l1` command

* contracts-bedrock: delete L1 genesis hh task

* ops-bedrock: use new go based L1 genesis generation

* genesis: clean up L1 genesis creation

* Update setters.go
Co-authored-by: default avatarMatthew Slipper <me@matthewslipper.com>
Co-authored-by: default avatarmergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
parent 5dbef78a
...@@ -82,17 +82,7 @@ func NewL2Genesis(config *DeployConfig, chain ethereum.ChainReader) (*core.Genes ...@@ -82,17 +82,7 @@ func NewL2Genesis(config *DeployConfig, chain ethereum.ChainReader) (*core.Genes
GasUsed: config.L2GenesisBlockGasUsed, GasUsed: config.L2GenesisBlockGasUsed,
ParentHash: config.L2GenesisBlockParentHash, ParentHash: config.L2GenesisBlockParentHash,
BaseFee: baseFee, BaseFee: baseFee,
Alloc: map[common.Address]core.GenesisAccount{ Alloc: map[common.Address]core.GenesisAccount{},
common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover
common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256
common.BytesToAddress([]byte{3}): {Balance: big.NewInt(1)}, // RIPEMD
common.BytesToAddress([]byte{4}): {Balance: big.NewInt(1)}, // Identity
common.BytesToAddress([]byte{5}): {Balance: big.NewInt(1)}, // ModExp
common.BytesToAddress([]byte{6}): {Balance: big.NewInt(1)}, // ECAdd
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
},
}, nil }, nil
} }
...@@ -141,16 +131,6 @@ func NewL1Genesis(config *DeployConfig) (*core.Genesis, error) { ...@@ -141,16 +131,6 @@ func NewL1Genesis(config *DeployConfig) (*core.Genesis, error) {
GasUsed: config.L1GenesisBlockGasUsed, GasUsed: config.L1GenesisBlockGasUsed,
ParentHash: config.L1GenesisBlockParentHash, ParentHash: config.L1GenesisBlockParentHash,
BaseFee: baseFee, BaseFee: baseFee,
Alloc: map[common.Address]core.GenesisAccount{ Alloc: map[common.Address]core.GenesisAccount{},
common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover
common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256
common.BytesToAddress([]byte{3}): {Balance: big.NewInt(1)}, // RIPEMD
common.BytesToAddress([]byte{4}): {Balance: big.NewInt(1)}, // Identity
common.BytesToAddress([]byte{5}): {Balance: big.NewInt(1)}, // ModExp
common.BytesToAddress([]byte{6}): {Balance: big.NewInt(1)}, // ECAdd
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
},
}, nil }, nil
} }
package genesis package genesis
import ( import (
"github.com/ethereum-optimism/optimism/op-chain-ops/hardhat"
"github.com/ethereum-optimism/optimism/op-chain-ops/state" "github.com/ethereum-optimism/optimism/op-chain-ops/state"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
) )
// TODO(tynes): need bindings for all of the L1 contracts // TODO(tynes): need bindings for all of the L1 contracts to be able
func BuildL1DeveloperGenesis(hh *hardhat.Hardhat, config *DeployConfig) (*core.Genesis, error) { // to create a genesis file with the L1 contracts predeployed.
// This would speed up testing as deployments take time when
// running tests.
func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) {
genesis, err := NewL1Genesis(config) genesis, err := NewL1Genesis(config)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -16,6 +18,7 @@ func BuildL1DeveloperGenesis(hh *hardhat.Hardhat, config *DeployConfig) (*core.G ...@@ -16,6 +18,7 @@ func BuildL1DeveloperGenesis(hh *hardhat.Hardhat, config *DeployConfig) (*core.G
db := state.NewMemoryStateDB(genesis) db := state.NewMemoryStateDB(genesis)
FundDevAccounts(db) FundDevAccounts(db)
SetPrecompileBalances(db)
return db.Genesis(), nil return db.Genesis(), nil
} }
...@@ -19,6 +19,7 @@ func BuildOptimismDeveloperGenesis(hh *hardhat.Hardhat, config *DeployConfig, ch ...@@ -19,6 +19,7 @@ func BuildOptimismDeveloperGenesis(hh *hardhat.Hardhat, config *DeployConfig, ch
db := state.NewMemoryStateDB(genspec) db := state.NewMemoryStateDB(genspec)
FundDevAccounts(db) FundDevAccounts(db)
SetPrecompileBalances(db)
return BuildOptimismGenesis(db, hh, config, chain) return BuildOptimismGenesis(db, hh, config, chain)
} }
......
...@@ -147,3 +147,14 @@ func MigrateDepositHashes(hh *hardhat.Hardhat, db vm.StateDB) error { ...@@ -147,3 +147,14 @@ func MigrateDepositHashes(hh *hardhat.Hardhat, db vm.StateDB) error {
}) })
return nil return nil
} }
// SetPrecompileBalances will set a single wei at each precompile address.
// This is an optimization to make calling them cheaper. This should only
// be used for devnets.
func SetPrecompileBalances(db vm.StateDB) {
for i := 0; i < 256; i++ {
addr := common.BytesToAddress([]byte{byte(i)})
db.CreateAccount(addr)
db.AddBalance(addr, common.Big1)
}
}
...@@ -19,7 +19,7 @@ import ( ...@@ -19,7 +19,7 @@ import (
var Subcommands = cli.Commands{ var Subcommands = cli.Commands{
{ {
Name: "devnet-l2", Name: "devnet-l2",
Usage: "Initialized a new devnet genesis file", Usage: "Initialized a new L2 devnet genesis file",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: "artifacts", Name: "artifacts",
...@@ -89,6 +89,54 @@ var Subcommands = cli.Commands{ ...@@ -89,6 +89,54 @@ var Subcommands = cli.Commands{
return err return err
} }
outfile := ctx.String("outfile")
if outfile == "" {
fmt.Println(string(file))
} else {
if err := os.WriteFile(outfile, file, 0644); err != nil {
return err
}
}
return nil
},
},
{
Name: "devnet-l1",
Usage: "Initialized a new L1 devnet genesis file",
Flags: []cli.Flag{
cli.StringFlag{
Name: "network",
Usage: "Name of hardhat deploy network",
},
cli.StringFlag{
Name: "deploy-config",
Usage: "Path to hardhat deploy config directory",
},
cli.StringFlag{
Name: "outfile",
Usage: "Path to file to write output to",
},
},
Action: func(ctx *cli.Context) error {
network := ctx.String("network")
deployConfigDirectory := ctx.String("deploy-config")
deployConfig := filepath.Join(deployConfigDirectory, network+".json")
config, err := genesis.NewDeployConfig(deployConfig)
if err != nil {
return err
}
gen, err := genesis.BuildL1DeveloperGenesis(config)
if err != nil {
return err
}
file, err := json.MarshalIndent(gen, "", " ")
if err != nil {
return err
}
outfile := ctx.String("outfile") outfile := ctx.String("outfile")
if outfile == "" { if outfile == "" {
fmt.Println(string(file)) fmt.Println(string(file))
......
...@@ -32,11 +32,11 @@ set -eu ...@@ -32,11 +32,11 @@ set -eu
L1_URL="http://localhost:8545" L1_URL="http://localhost:8545"
L2_URL="http://localhost:9545" L2_URL="http://localhost:9545"
OP_NODE=op-node OP_NODE="$PWD/op-node"
CONTRACTS_BEDROCK=$PWD/packages/contracts-bedrock CONTRACTS_BEDROCK="$PWD/packages/contracts-bedrock"
CONTRACTS_GOVERNANCE=$PWD/packages/contracts-governance CONTRACTS_GOVERNANCE="$PWD/packages/contracts-governance"
NETWORK=devnetL1 NETWORK=devnetL1
DEVNET=$PWD/.devnet DEVNET="$PWD/.devnet"
# Helper method that waits for a given URL to be up. Can't use # Helper method that waits for a given URL to be up. Can't use
# cURL's built-in retry logic because connection reset errors # cURL's built-in retry logic because connection reset errors
...@@ -65,9 +65,11 @@ mkdir -p ./.devnet ...@@ -65,9 +65,11 @@ mkdir -p ./.devnet
if [ ! -f $DEVNET/genesis-l1.json ]; then if [ ! -f $DEVNET/genesis-l1.json ]; then
echo "Regenerating L1 genesis." echo "Regenerating L1 genesis."
( (
cd $CONTRACTS_BEDROCK cd "$OP_NODE"
npx hardhat --network $NETWORK genesis-l1 --outfile genesis-l1.json go run cmd/main.go genesis devnet-l1 \
mv genesis-l1.json $DEVNET/genesis-l1.json --network $NETWORK \
--deploy-config $CONTRACTS_BEDROCK/deploy-config \
--outfile $DEVNET/genesis-l1.json
) )
fi fi
...@@ -81,27 +83,27 @@ fi ...@@ -81,27 +83,27 @@ fi
) )
# Deploy contracts using Hardhat. # Deploy contracts using Hardhat.
if [ ! -d $CONTRACTS_BEDROCK/deployments/$NETWORK ]; then if [ ! -d "$CONTRACTS_BEDROCK/deployments/$NETWORK" ]; then
( (
echo "Deploying contracts." echo "Deploying contracts."
cd $CONTRACTS_BEDROCK cd "$CONTRACTS_BEDROCK"
yarn hardhat --network $NETWORK deploy yarn hardhat --network $NETWORK deploy
) )
else else
echo "Contracts already deployed, skipping." echo "Contracts already deployed, skipping."
fi fi
if [ ! -f $DEVNET/genesis-l2.json ]; then if [ ! -f "$DEVNET/genesis-l2.json" ]; then
( (
echo "Creating L2 genesis file." echo "Creating L2 genesis file."
cd $OP_NODE cd "$OP_NODE"
go run cmd/main.go genesis devnet-l2 \ go run cmd/main.go genesis devnet-l2 \
--artifacts $CONTRACTS_BEDROCK/artifacts,$CONTRACTS_GOVERNANCE/artifacts \ --artifacts "$CONTRACTS_BEDROCK/artifacts,$CONTRACTS_GOVERNANCE/artifacts" \
--network $NETWORK \ --network $NETWORK \
--deployments $CONTRACTS_BEDROCK/deployments \ --deployments "$CONTRACTS_BEDROCK/deployments" \
--deploy-config $CONTRACTS_BEDROCK/deploy-config \ --deploy-config "$CONTRACTS_BEDROCK/deploy-config" \
--rpc-url http://localhost:8545 \ --rpc-url http://localhost:8545 \
--outfile $DEVNET/genesis-l2.json --outfile "$DEVNET/genesis-l2.json"
echo "Created L2 genesis." echo "Created L2 genesis."
) )
else else
...@@ -117,18 +119,18 @@ fi ...@@ -117,18 +119,18 @@ fi
) )
# Start putting together the rollup config. # Start putting together the rollup config.
if [ ! -f $DEVNET/rollup.json ]; then if [ ! -f "$DEVNET/rollup.json" ]; then
( (
echo "Building rollup config..." echo "Building rollup config..."
cd $CONTRACTS_BEDROCK cd "$CONTRACTS_BEDROCK"
npx hardhat --network $NETWORK rollup-config npx hardhat --network $NETWORK rollup-config
mv rollup.json $DEVNET/rollup.json mv rollup.json "$DEVNET/rollup.json"
) )
else else
echo "Rollup config already exists" echo "Rollup config already exists"
fi fi
L2OO_ADDRESS=$(jq -r .address < $CONTRACTS_BEDROCK/deployments/$NETWORK/L2OutputOracleProxy.json) L2OO_ADDRESS=$(jq -r .address < "$CONTRACTS_BEDROCK/deployments/$NETWORK/L2OutputOracleProxy.json")
SEQUENCER_GENESIS_HASH="$(jq -r '.l2.hash' < $DEVNET/rollup.json)" SEQUENCER_GENESIS_HASH="$(jq -r '.l2.hash' < $DEVNET/rollup.json)"
SEQUENCER_BATCH_INBOX_ADDRESS="$(cat $DEVNET/rollup.json | jq -r '.batch_inbox_address')" SEQUENCER_BATCH_INBOX_ADDRESS="$(cat $DEVNET/rollup.json | jq -r '.batch_inbox_address')"
......
import fs from 'fs'
import { ethers } from 'ethers'
import { task, types } from 'hardhat/config'
import { Genesis, State } from '@eth-optimism/core-utils'
import '@eth-optimism/hardhat-deploy-config'
task('genesis-l1', 'create a genesis config')
.addOptionalParam(
'outfile',
'The file to write the output JSON to',
'genesis.json'
)
.addOptionalParam(
'l1GenesisBlockTimestamp',
'Timestamp to embed in L1 genesis block, current time will be used if the timestamp is zero',
0,
types.int
)
.setAction(async (args, hre) => {
const { deployConfig } = hre
const alloc: State = {}
const l1GenesisBlockTimestamp =
args.l1GenesisBlockTimestamp === 0
? Math.floor(Date.now() / 1000)
: args.l1GenesisBlockTimestamp
// Give each predeploy a single wei
for (let i = 0; i <= 0xff; i++) {
const buf = Buffer.alloc(2)
buf.writeUInt16BE(i, 0)
const addr = ethers.utils.hexConcat([
'0x000000000000000000000000000000000000',
ethers.utils.hexZeroPad(buf, 2),
])
alloc[addr] = {
balance: '0x1',
}
}
const accounts = [
'0x14dC79964da2C08b23698B3D3cc7Ca32193d9955',
'0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65',
'0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec',
'0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f',
'0x2546BcD3c84621e976D8185a91A922aE77ECEc30',
'0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
'0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
'0x71bE63f3384f5fb98995898A86B02Fb2426c5788',
'0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199',
'0x90F79bf6EB2c4f870365E785982E1f101E93b906',
'0x976EA74026E726554dB657fA54763abd0C3a0aa9',
'0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc',
'0xBcd4042DE499D14e55001CcbB24a551F3b954096',
'0xFABB0ac9d68B0B445fB7357272Ff202C5651694a',
'0xa0Ee7A142d267C1f36714E4a8F75612F20a79720',
'0xbDA5747bFD65F08deb54cb465eB87D40e51B197E',
'0xcd3B766CCDd6AE721141F452C550Ca635964ce71',
'0xdD2FD4581271e230360230F9337D5c0430Bf44C0',
'0xdF3e18d64BC6A983f673Ab319CCaE4f1a57C7097',
'0xde3829a23df1479438622a08a116e8eb3f620bb5',
'0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
]
for (const account of accounts) {
alloc[ethers.utils.getAddress(account)] = {
balance:
'0x200000000000000000000000000000000000000000000000000000000000000',
}
}
const genesis: Genesis = {
config: {
chainId: deployConfig.l1ChainID,
homesteadBlock: 0,
eip150Block: 0,
eip150Hash: ethers.constants.HashZero,
eip155Block: 0,
eip158Block: 0,
byzantiumBlock: 0,
constantinopleBlock: 0,
petersburgBlock: 0,
istanbulBlock: 0,
muirGlacierBlock: 0,
berlinBlock: 0,
londonBlock: 0,
clique: {
period: deployConfig.l1BlockTime,
epoch: 30000,
},
},
nonce: deployConfig.l1GenesisBlockNonce,
timestamp: ethers.BigNumber.from(l1GenesisBlockTimestamp).toHexString(),
extraData: ethers.utils.hexConcat([
ethers.constants.HashZero,
deployConfig.cliqueSignerAddress,
ethers.utils.hexZeroPad('0x', 65),
]),
gasLimit: deployConfig.l1GenesisBlockGasLimit,
difficulty: deployConfig.l1GenesisBlockDifficulty,
mixHash: deployConfig.l1GenesisBlockMixHash,
coinbase: deployConfig.l1GenesisBlockCoinbase,
alloc,
number: deployConfig.l1GenesisBlockNumber,
gasUsed: deployConfig.l1GenesisBlockGasUsed,
parentHash: deployConfig.l1GenesisBlockParentHash,
baseFeePerGas: deployConfig.l1GenesisBlockBaseFeePerGas,
}
fs.writeFileSync(args.outfile, JSON.stringify(genesis, null, 2))
})
import './genesis-l1'
import './deposits' import './deposits'
import './rekey' import './rekey'
import './rollup-config' import './rollup-config'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment