Commit bd30275b authored by Diederik Loerakker's avatar Diederik Loerakker Committed by GitHub

feat(contracts-bedrock,sdk): deploy config typing, hivenet (#3187)

* feat(contracts-bedrock,sdk): deploy config typing, hivenet

* bedrock: op-batcher,op-node,op-proposer flags consistency

* contracts-bedrock: hardhat deploy config review feedback

* contracts-bedrock: lint fixes

* contracts-bedrock: fix chain IDs in deploy configs

* ops-bedrock: remove l1 genesis timestamp env var
Co-authored-by: default avatarMatthew Slipper <me@matthewslipper.com>
Co-authored-by: default avatarmergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
parent a095d544
......@@ -4,7 +4,7 @@ import (
"github.com/urfave/cli"
)
const envVarPrefix = "BATCH_SUBMITTER_"
const envVarPrefix = "OP_BATCHER_"
func prefixEnvVar(name string) string {
return envVarPrefix + name
......@@ -17,19 +17,19 @@ var (
Name: "l1-eth-rpc",
Usage: "HTTP provider URL for L1",
Required: true,
EnvVar: "L1_ETH_RPC",
EnvVar: prefixEnvVar("L1_ETH_RPC"),
}
L2EthRpcFlag = cli.StringFlag{
Name: "l2-eth-rpc",
Usage: "HTTP provider URL for L2 execution engine",
Required: true,
EnvVar: "L2_ETH_RPC",
EnvVar: prefixEnvVar("L2_ETH_RPC"),
}
RollupRpcFlag = cli.StringFlag{
Name: "rollup-rpc",
Usage: "HTTP provider URL for Rollup node",
Required: true,
EnvVar: "ROLLUP_RPC",
EnvVar: prefixEnvVar("ROLLUP_RPC"),
}
MinL1TxSizeBytesFlag = cli.Uint64Flag{
Name: "min-l1-tx-size-bytes",
......@@ -105,13 +105,13 @@ var (
/* Optional Flags */
LogLevelFlag = cli.StringFlag{
Name: "log-level",
Name: "log.level",
Usage: "The lowest log level that will be output",
Value: "info",
EnvVar: prefixEnvVar("LOG_LEVEL"),
}
LogTerminalFlag = cli.BoolFlag{
Name: "log-terminal",
Name: "log.terminal",
Usage: "If true, outputs logs in terminal format, otherwise prints " +
"in JSON format.",
EnvVar: prefixEnvVar("LOG_TERMINAL"),
......
......@@ -8,7 +8,7 @@ import (
// Flags
const envVarPrefix = "ROLLUP_NODE_"
const envVarPrefix = "OP_NODE_"
func prefixEnvVar(name string) string {
return envVarPrefix + name
......
......@@ -45,9 +45,9 @@ type Config struct {
// Note: below addresses are part of the block-derivation process,
// and required to be the same network-wide to stay in consensus.
// L2 address receiving all L2 transaction fees
// L2 address used to send all priority fees to, also known as the coinbase address in the block.
FeeRecipientAddress common.Address `json:"fee_recipient_address"`
// L1 address that batches are sent to
// L1 address that batches are sent to.
BatchInboxAddress common.Address `json:"batch_inbox_address"`
// Acceptable batch-sender address
BatchSenderAddress common.Address `json:"batch_sender_address"`
......
......@@ -4,7 +4,7 @@ import (
"github.com/urfave/cli"
)
const envVarPrefix = "OUTPUT_SUBMITTER_"
const envVarPrefix = "OP_PROPOSER_"
func prefixEnvVar(name string) string {
return envVarPrefix + name
......@@ -17,25 +17,25 @@ var (
Name: "l1-eth-rpc",
Usage: "HTTP provider URL for L1",
Required: true,
EnvVar: "L1_ETH_RPC",
EnvVar: prefixEnvVar("L1_ETH_RPC"),
}
L2EthRpcFlag = cli.StringFlag{
Name: "l2-eth-rpc",
Usage: "HTTP provider URL for L2",
Required: true,
EnvVar: "L2_ETH_RPC",
EnvVar: prefixEnvVar("L2_ETH_RPC"),
}
RollupRpcFlag = cli.StringFlag{
Name: "rollup-rpc",
Usage: "HTTP provider URL for the rollup node",
Required: true,
EnvVar: "ROLLUP_RPC",
EnvVar: prefixEnvVar("ROLLUP_RPC"),
}
L2OOAddressFlag = cli.StringFlag{
Name: "l2oo-address",
Usage: "Address of the L2OutputOracle contract",
Required: true,
EnvVar: "L2OO_ADDRESS",
EnvVar: prefixEnvVar("L2OO_ADDRESS"),
}
PollIntervalFlag = cli.DurationFlag{
Name: "poll-interval",
......@@ -87,13 +87,13 @@ var (
/* Optional Flags */
LogLevelFlag = cli.StringFlag{
Name: "log-level",
Name: "log.level",
Usage: "The lowest log level that will be output",
Value: "info",
EnvVar: prefixEnvVar("LOG_LEVEL"),
}
LogTerminalFlag = cli.BoolFlag{
Name: "log-terminal",
Name: "log.terminal",
Usage: "If true, outputs logs in terminal format, otherwise prints " +
"in JSON format.",
EnvVar: prefixEnvVar("LOG_TERMINAL"),
......
......@@ -57,20 +57,13 @@ function wait_up {
mkdir -p ./.devnet
if [ ! -f ./.devnet/rollup.json ]; then
L1_GENESIS_TIMESTAMP=$(date +%s | xargs printf "0x%x")
else
L1_GENESIS_TIMESTAMP=$(jq '.timestamp' < .devnet/genesis-l1.json)
fi
# Regenerate the L1 genesis file if necessary. The existence of the genesis
# file is used to determine if we need to recreate the devnet's state folder.
if [ ! -f ./.devnet/genesis-l1.json ]; then
echo "Regenerating L1 genesis."
(
cd $CONTRACTS_BEDROCK
L1_GENESIS_TIMESTAMP=$L1_GENESIS_TIMESTAMP npx hardhat genesis-l1 \
--outfile genesis-l1.json
npx hardhat --network $NETWORK genesis-l1 --outfile genesis-l1.json
mv genesis-l1.json ../../.devnet/genesis-l1.json
)
fi
......@@ -89,7 +82,7 @@ if [ ! -d $CONTRACTS_BEDROCK/deployments/$NETWORK ]; then
(
echo "Deploying contracts."
cd $CONTRACTS_BEDROCK
L1_GENESIS_TIMESTAMP=$L1_GENESIS_TIMESTAMP yarn hardhat --network $NETWORK deploy
yarn hardhat --network $NETWORK deploy
)
else
echo "Contracts already deployed, skipping."
......@@ -99,7 +92,7 @@ if [ ! -f ./.devnet/genesis-l2.json ]; then
(
echo "Creating L2 genesis file."
cd $CONTRACTS_BEDROCK
L1_GENESIS_TIMESTAMP=$L1_GENESIS_TIMESTAMP npx hardhat --network $NETWORK genesis-l2
npx hardhat --network $NETWORK genesis-l2
mv genesis.json ../../.devnet/genesis-l2.json
echo "Created L2 genesis."
)
......@@ -120,7 +113,7 @@ if [ ! -f ./.devnet/rollup.json ]; then
(
echo "Building rollup config..."
cd $CONTRACTS_BEDROCK
L1_GENESIS_TIMESTAMP=$L1_GENESIS_TIMESTAMP npx hardhat --network $NETWORK rollup-config
npx hardhat --network $NETWORK rollup-config
mv rollup.json ../../.devnet/rollup.json
)
else
......
......@@ -87,18 +87,18 @@ services:
ports:
- "6062:6060"
environment:
L1_ETH_RPC: http://l1:8545
L2_ETH_RPC: http://l2:8545
ROLLUP_RPC: http://op-node:8545
OUTPUT_SUBMITTER_POLL_INTERVAL: 1s
OUTPUT_SUBMITTER_NUM_CONFIRMATIONS: 1
OUTPUT_SUBMITTER_SAFE_ABORT_NONCE_TOO_LOW_COUNT: 3
OUTPUT_SUBMITTER_RESUBMISSION_TIMEOUT: 30s
OUTPUT_SUBMITTER_MNEMONIC: test test test test test test test test test test test junk
OUTPUT_SUBMITTER_L2_OUTPUT_HD_PATH: "m/44'/60'/0'/0/1"
OUTPUT_SUBMITTER_LOG_TERMINAL: "true"
L2OO_ADDRESS: "${L2OO_ADDRESS}"
OUTPUT_SUBMITTER_PPROF_ENABLED: "true"
OP_PROPOSER_L1_ETH_RPC: http://l1:8545
OP_PROPOSER_L2_ETH_RPC: http://l2:8545
OP_PROPOSER_ROLLUP_RPC: http://op-node:8545
OP_PROPOSER_POLL_INTERVAL: 1s
OP_PROPOSER_NUM_CONFIRMATIONS: 1
OP_PROPOSER_SAFE_ABORT_NONCE_TOO_LOW_COUNT: 3
OP_PROPOSER_RESUBMISSION_TIMEOUT: 30s
OP_PROPOSER_MNEMONIC: test test test test test test test test test test test junk
OP_PROPOSER_L2_OUTPUT_HD_PATH: "m/44'/60'/0'/0/1"
OP_PROPOSER_LOG_TERMINAL: "true"
OP_PROPOSER_L2OO_ADDRESS: "${L2OO_ADDRESS}"
OP_PROPOSER_PPROF_ENABLED: "true"
op-batcher:
depends_on:
......@@ -111,22 +111,22 @@ services:
ports:
- "6061:6060"
environment:
L1_ETH_RPC: http://l1:8545
L2_ETH_RPC: http://l2:8545
ROLLUP_RPC: http://op-node:8545
BATCH_SUBMITTER_MIN_L1_TX_SIZE_BYTES: 1
BATCH_SUBMITTER_MAX_L1_TX_SIZE_BYTES: 120000
BATCH_SUBMITTER_CHANNEL_TIMEOUT: 40
BATCH_SUBMITTER_POLL_INTERVAL: 1s
BATCH_SUBMITTER_NUM_CONFIRMATIONS: 1
BATCH_SUBMITTER_SAFE_ABORT_NONCE_TOO_LOW_COUNT: 3
BATCH_SUBMITTER_RESUBMISSION_TIMEOUT: 30s
BATCH_SUBMITTER_MNEMONIC: test test test test test test test test test test test junk
BATCH_SUBMITTER_SEQUENCER_HD_PATH: "m/44'/60'/0'/0/2"
BATCH_SUBMITTER_SEQUENCER_GENESIS_HASH: "${SEQUENCER_GENESIS_HASH}"
BATCH_SUBMITTER_SEQUENCER_BATCH_INBOX_ADDRESS: "${SEQUENCER_BATCH_INBOX_ADDRESS}"
BATCH_SUBMITTER_LOG_TERMINAL: "true"
BATCH_SUBMITTER_PPROF_ENABLED: "true"
OP_BATCHER_L1_ETH_RPC: http://l1:8545
OP_BATCHER_L2_ETH_RPC: http://l2:8545
OP_BATCHER_ROLLUP_RPC: http://op-node:8545
OP_BATCHER_MIN_L1_TX_SIZE_BYTES: 1
OP_BATCHER_MAX_L1_TX_SIZE_BYTES: 120000
OP_BATCHER_CHANNEL_TIMEOUT: 40
OP_BATCHER_POLL_INTERVAL: 1s
OP_BATCHER_NUM_CONFIRMATIONS: 1
OP_BATCHER_SAFE_ABORT_NONCE_TOO_LOW_COUNT: 3
OP_BATCHER_RESUBMISSION_TIMEOUT: 30s
OP_BATCHER_MNEMONIC: test test test test test test test test test test test junk
OP_BATCHER_SEQUENCER_HD_PATH: "m/44'/60'/0'/0/2"
OP_BATCHER_SEQUENCER_GENESIS_HASH: "${SEQUENCER_GENESIS_HASH}"
OP_BATCHER_SEQUENCER_BATCH_INBOX_ADDRESS: "${SEQUENCER_BATCH_INBOX_ADDRESS}"
OP_BATCHER_LOG_TERMINAL: "true"
OP_BATCHER_PPROF_ENABLED: "true"
stateviz:
build:
......
......@@ -113,7 +113,7 @@ contract L2OutputOracle is OwnableUpgradeable, Semver {
* @param _historicalTotalBlocks Number of blocks preceding this L2 chain.
* @param _startingBlockNumber The number of the first L2 block.
* @param _startingTimestamp The timestamp of the first L2 block.
* @param _l2BlockTime The timestamp of the first L2 block.
* @param _l2BlockTime The time per L2 block, in seconds.
* @param _proposer The address of the proposer.
* @param _owner The address of the owner.
*/
......
import { ethers } from 'ethers'
const { env } = process
const l1GenesisTimestamp =
typeof env.L1_GENESIS_TIMESTAMP === 'string'
? ethers.BigNumber.from(env.L1_GENESIS_TIMESTAMP).toNumber()
: Math.floor(Date.now() / 1000)
const config = {
submissionInterval: 20,
genesisOutput: ethers.constants.HashZero,
historicalBlocks: 0,
// general
l1StartingBlockTag: 'earliest',
startingBlockNumber: 0,
l1ChainID: 900,
l2ChainID: 901,
l2BlockTime: 2,
l1GenesisTimestamp,
sequencerAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
l2CrossDomainMessengerOwner: ethers.constants.AddressZero,
gasPriceOracleOwner: ethers.constants.AddressZero,
gasPriceOracleOverhead: 2100,
gasPriceOracleScalar: 1000000,
gasPriceOracleDecimals: 6,
// rollup
maxSequencerDrift: 100,
sequencerWindowSize: 4,
channelTimeout: 40,
p2pSequencerAddress: '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc',
optimismL2FeeRecipient: '0xd9c09e21b57c98e58a80552c170989b426766aa7',
batchInboxAddress: '0xff00000000000000000000000000000000000000',
batchSenderAddress: '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
l1BlockInitialNumber: 0,
l1BlockInitialTimestamp: 0,
l1BlockInitialBasefee: 10,
l1BlockInitialHash: ethers.constants.HashZero,
l1BlockInitialSequenceNumber: 0,
// output oracle
l2OutputOracleSubmissionInterval: 20,
l2OutputOracleStartingTimestamp: -1, // based on L1 starting tag instead
l2OutputOracleProposer: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
l2OutputOracleOwner: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
proxyAdmin: '0x829BD824B016326A401d083B33D092293333A830',
genesisBlockExtradata: ethers.utils.hexConcat([
ethers.constants.HashZero,
'0xca062b0fd91172d89bcd4bb084ac4e21972cc467',
ethers.utils.hexZeroPad('0x', 65),
]),
genesisBlockGasLimit: ethers.BigNumber.from(15000000).toHexString(),
// l1
l1BlockTime: 15,
cliqueSignerAddress: '0xca062b0fd91172d89bcd4bb084ac4e21972cc467',
genesisBlockChainid: 901,
fundDevAccounts: true,
// l2
optimismBaseFeeRecipient: '0xBcd4042DE499D14e55001CcbB24a551F3b954096',
optimismL1FeeRecipient: '0x71bE63f3384f5fb98995898A86B02Fb2426c5788',
proxyAdmin: '0x829BD824B016326A401d083B33D092293333A830',
fundDevAccounts: true,
p2pSequencerAddress: '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc',
// deploying
deploymentWaitConfirmations: 1,
maxSequencerDrift: 100,
sequencerWindowSize: 4,
channelTimeout: 40,
outputOracleOwner: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
optimismL2FeeRecipient: '0xd9c09e21b57c98e58a80552c170989b426766aa7',
batchSenderAddress: '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
}
export default config
import { ethers } from 'ethers'
const sequencerAddress = '0x6c23a0dcdfc44b7a57bed148de598895e398d984'
const l1StartingBlockTag =
'0xafce66a0a2446856112e4069b275ad32b1f4a607888f9c4c59eddf9be81f8670'
const config = {
submissionInterval: 6,
genesisOutput: ethers.constants.HashZero,
historicalBlocks: 0,
startingBlockNumber: 0,
l2BlockTime: 2,
// general
l1StartingBlockTag,
sequencerAddress,
l2CrossDomainMessengerOwner: ethers.constants.AddressZero,
gasPriceOracleOwner: ethers.constants.AddressZero,
gasPriceOracleOverhead: 2100,
gasPriceOracleScalar: 1000000,
gasPriceOracleDecimals: 6,
l1BlockInitialNumber: 0,
l1BlockInitialTimestamp: 0,
l1BlockInitialBasefee: 10,
l1BlockInitialHash: ethers.constants.HashZero,
l1BlockInitialSequenceNumber: 0,
genesisBlockExtradata: ethers.utils.hexConcat([
ethers.constants.HashZero,
sequencerAddress,
ethers.utils.hexZeroPad('0x', 65),
]),
genesisBlockGasLimit: ethers.BigNumber.from(15000000).toHexString(),
genesisBlockChainid: 111,
fundDevAccounts: true,
p2pSequencerAddress: '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc',
deploymentWaitConfirmations: 1,
l1ChainID: 5,
l2ChainID: 111,
l2BlockTime: 2,
// rollup
maxSequencerDrift: 1000,
sequencerWindowSize: 120,
channelTimeout: 120,
p2pSequencerAddress: '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc',
optimismL2FeeRecipient: '0x26862c200bd48c19f39d9e1cd88a3b439611d911',
batchInboxAddress: '0xff00000000000000000000000000000000000002',
batchSenderAddress: '0xa11d2b908470e17923fff184d48269bebbd9b2a5',
proxyAdmin: '0xe584e1b833ca80020130b1b69f84f90479076168',
// output oracle
l2OutputOracleSubmissionInterval: 6,
l2OutputOracleStartingTimestamp: -1, // based on L1 starting tag instead
l2OutputOracleProposer: '0x6c23a0dcdfc44b7a57bed148de598895e398d984',
l2OutputOracleOwner: '0x6925b8704ff96dee942623d6fb5e946ef5884b63',
// l2
optimismBaseFeeRecipient: '0xf116a24056b647e3211d095c667e951536cdebaa',
optimismL1FeeRecipient: '0xc731837b696ca3d9720d23336925368ceaa58f83',
optimismL2FeeRecipient: '0x26862c200bd48c19f39d9e1cd88a3b439611d911',
outputOracleOwner: '0x6925b8704ff96dee942623d6fb5e946ef5884b63',
batchSenderAddress: '0xa11d2b908470e17923fff184d48269bebbd9b2a5',
proxyAdmin: '0xe584e1b833ca80020130b1b69f84f90479076168',
fundDevAccounts: true,
// deploying
deploymentWaitConfirmations: 1,
}
export default config
import { ethers } from 'ethers'
const { env } = process
const l1GenesisTimestamp =
typeof env.L1_GENESIS_TIMESTAMP === 'string'
? ethers.BigNumber.from(env.L1_GENESIS_TIMESTAMP).toNumber()
: Math.floor(Date.now() / 1000)
const config = {
submissionInterval: 6,
genesisOutput: ethers.constants.HashZero,
historicalBlocks: 0,
startingBlockNumber: 0,
// general
l1StartingBlockTag: 'earliest',
l1ChainID: 900,
l2ChainID: 901,
l2BlockTime: 2,
l1GenesisTimestamp,
sequencerAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
// rollup
maxSequencerDrift: 10,
sequencerWindowSize: 4,
channelTimeout: 40,
outputOracleOwner: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
p2pSequencerAddress: '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc',
optimismL2FeeRecipient: '0xd9c09e21b57c98e58a80552c170989b426766aa7',
batchInboxAddress: '0xff00000000000000000000000000000000000000',
batchSenderAddress: '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
// output oracle
l2OutputOracleSubmissionInterval: 6,
l2OutputOracleStartingTimestamp: -1, // based on L1 starting tag instead
l2OutputOracleProposer: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
l2OutputOracleOwner: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
// l1: all defaults
// l2
proxyAdmin: 0x0000000000000000000000000000000000000000,
fundDevAccounts: true,
// deploying
deploymentWaitConfirmations: 1,
}
export default config
......@@ -10,10 +10,16 @@ const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre
let deployL2StartingTimestamp = deployConfig.l2OutputOracleStartingTimestamp
if (deployL2StartingTimestamp < 0) {
const l1 = hre.ethers.provider
const l1StartingBlock = await l1.getBlock(deployConfig.l1StartingBlockTag)
if (l1StartingBlock === null) {
throw new Error(`Cannot fetch block tag ${deployConfig.l1StartingBlockTag}`)
throw new Error(
`Cannot fetch block tag ${deployConfig.l1StartingBlockTag}`
)
}
deployL2StartingTimestamp = l1StartingBlock.timestamp
}
await deploy('L2OutputOracleProxy', {
......@@ -27,14 +33,14 @@ const deployFn: DeployFunction = async (hre) => {
await deploy('L2OutputOracle', {
from: deployer,
args: [
deployConfig.submissionInterval,
deployConfig.genesisOutput,
deployConfig.historicalBlocks,
deployConfig.startingBlockNumber,
l1StartingBlock.timestamp,
deployConfig.l2OutputOracleSubmissionInterval,
deployConfig.l2OutputOracleGenesisL2Output,
deployConfig.l2OutputOracleHistoricalTotalBlocks,
deployConfig.l2OutputOracleStartingBlockNumber,
deployL2StartingTimestamp,
deployConfig.l2BlockTime,
deployConfig.sequencerAddress,
deployConfig.outputOracleOwner,
deployConfig.l2OutputOracleProposer,
deployConfig.l2OutputOracleOwner,
],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
......@@ -54,34 +60,44 @@ const deployFn: DeployFunction = async (hre) => {
L2OutputOracle.interface.encodeFunctionData(
'initialize(bytes32,uint256,address,address)',
[
deployConfig.genesisOutput,
deployConfig.startingBlockNumber,
deployConfig.sequencerAddress,
deployConfig.outputOracleOwner,
deployConfig.l2OutputOracleGenesisL2Output,
deployConfig.l2OutputOracleStartingBlockNumber,
deployConfig.l2OutputOracleProposer,
deployConfig.l2OutputOracleOwner,
]
)
)
await tx.wait()
const submissionInterval = await L2OutputOracle.SUBMISSION_INTERVAL()
if (!submissionInterval.eq(BigNumber.from(deployConfig.submissionInterval))) {
if (
!submissionInterval.eq(
BigNumber.from(deployConfig.l2OutputOracleSubmissionInterval)
)
) {
throw new Error('submission internal misconfigured')
}
const historicalBlocks = await L2OutputOracle.HISTORICAL_TOTAL_BLOCKS()
if (!historicalBlocks.eq(BigNumber.from(deployConfig.historicalBlocks))) {
if (
!historicalBlocks.eq(
BigNumber.from(deployConfig.l2OutputOracleHistoricalTotalBlocks)
)
) {
throw new Error('historal total blocks misconfigured')
}
const startingBlockNumber = await L2OutputOracle.STARTING_BLOCK_NUMBER()
if (
!startingBlockNumber.eq(BigNumber.from(deployConfig.startingBlockNumber))
!startingBlockNumber.eq(
BigNumber.from(deployConfig.l2OutputOracleStartingBlockNumber)
)
) {
throw new Error('starting block number misconfigured')
}
const startingTimestamp = await L2OutputOracle.STARTING_TIMESTAMP()
if (!startingTimestamp.eq(BigNumber.from(l1StartingBlock.timestamp))) {
if (!startingTimestamp.eq(BigNumber.from(deployL2StartingTimestamp))) {
throw new Error('starting timestamp misconfigured')
}
const l2BlockTime = await L2OutputOracle.L2_BLOCK_TIME()
......
......@@ -35,6 +35,11 @@ const config: HardhatUserConfig = {
'ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
],
},
hivenet: {
chainId: Number(process.env.CHAIN_ID),
url: process.env.L1_RPC || '',
accounts: [process.env.PRIVATE_KEY_DEPLOYER || ethers.constants.HashZero],
},
goerli: {
chainId: 5,
url: process.env.L1_RPC || '',
......@@ -60,27 +65,272 @@ const config: HardhatUserConfig = {
},
},
deployConfigSpec: {
submissionInterval: {
// To anchor the rollup at for L1 genesis.
// The L2 genesis script uses this to fill the storage of the L1Block info predeploy.
// The rollup config script uses this to fill the L1 genesis info for the rollup.
// The Output oracle deploy script may use it if the L2 starting timestamp is undefined,
// assuming the L2 genesis is set up with this.
l1StartingBlockTag: {
type: 'string',
},
// Required to identify the L1 network and verify and create L1 signatures.
// Part of L1 genesis config.
// "l1_chain_id" in rollup config.
l1ChainID: {
type: 'number',
},
// Required to identify the L2 network and create p2p signatures unique for this chain.
// Part of L2 genesis config.
// "l2_chain_id" in rollup config.
l2ChainID: {
type: 'number',
},
// Seconds per L2 block.
//
// The Output oracle deploy script uses this.
//
// "block_time" in rollup config.
l2BlockTime: {
type: 'number',
},
genesisOutput: {
// Rollup config parameters. These must ONLY be used by the rollup config script.
// For scripts, use the optimism_rollupConfig RPC method to retrieve the rollup config dynamically.
// -------------------------------------------------
// Sequencer batches may not be more than MaxSequencerDrift seconds after
// the L1 timestamp of the sequencing window end.
//
// Note: When L1 has many 1 second consecutive blocks, and L2 grows at fixed 2 seconds,
// the L2 time may still grow beyond this difference.
//
// "max_sequencer_drift" in rollup config.
maxSequencerDrift: {
type: 'number',
},
// Number of epochs (L1 blocks) per sequencing window.
// "seq_window_size" in rollup config.
sequencerWindowSize: {
type: 'number',
},
// Number of seconds (w.r.t. L1 time) that a frame can be valid when included in L1
// "channel_timeout" in rollup config.
channelTimeout: {
type: 'number',
},
// Address of the key the sequencer uses to sign blocks on the P2P layer
// "p2p_sequencer_address" in rollup config.
p2pSequencerAddress: {
type: 'address',
},
// L2 address used to send all priority fees to, also known as the coinbase address in the block.
// "fee_recipient_address" in rollup config.
optimismL2FeeRecipient: {
type: 'address',
},
// L1 address that batches are sent to.
// "batch_inbox_address" in rollup config.
batchInboxAddress: {
type: 'address',
},
// Acceptable batch-sender address, to filter transactions going into the batchInboxAddress on L1 for data.
// Warning: this address is hardcoded now, but is intended to become governed via L1.
// It may not be part of the rollup config in the near future, and instead be part of a L1 contract deployment.
// "batch_sender_address" in rollup config.
batchSenderAddress: {
type: 'address',
},
// L1 Deposit Contract Address. Not part of the deploy config.
// This is derived from the Portal contract deployment (warning: use proxy address).
// "deposit_contract_address" in the rollup config.
// L2 Output oracle deployment parameters.
// -------------------------------------------------
// uint256 - Interval in blocks at which checkpoints must be submitted.
l2OutputOracleSubmissionInterval: {
type: 'number',
},
// bytes32 - The initial L2 output of the L2 chain.
l2OutputOracleGenesisL2Output: {
type: 'string',
default: ethers.constants.HashZero,
},
historicalBlocks: {
// uint256 - Number of blocks preceding this L2 chain.
l2OutputOracleHistoricalTotalBlocks: {
type: 'number',
default: 0,
},
// uint256 - The number of the first L2 block.
l2OutputOracleStartingBlockNumber: {
type: 'number',
default: 0,
},
sequencerAddress: {
// Starting time stamp is optional, if it is configured with a negative
// the deploy config user needs to fall back to the timestamp
// of the L1 block that the rollup anchors at (genesis L1).
//
// Note that if you let it fall back to this L1 timestamp, then the L2
// must have a matching timestamp in the block at height l2OutputOracleStartingBlockNumber.
//
// uint256 - The timestamp of the first L2 block.
l2OutputOracleStartingTimestamp: {
type: 'number',
},
// l2OutputOracleL2BlockTime:
// Read from the global l2BlockTime
//
// uint256 - The time per L2 block, in seconds.
// address - The address of the proposer.
l2OutputOracleProposer: {
type: 'address',
},
outputOracleOwner: {
// address - The address of the owner.
l2OutputOracleOwner: {
type: 'address',
},
l1StartingBlockTag: {
// Optional L1 genesis block values. These must ONLY be used by the L1 genesis config script.
// Not all deployments may create a new L1 chain, but instead attach to an existing L1 chain, like Goerli.
// -------------------------------------------------
l1BlockTime: {
type: 'number',
default: 15,
},
l1GenesisBlockNonce: {
type: 'string', // uint64
default: '0x0',
},
// l1GenesisBlockTimestamp: not part of deploy config, configured with parameter to genesis task instead.
// l1GenesisBlockExtraData: not configurable, used for clique singer data. See cliqueSignerAddress instead.
cliqueSignerAddress: {
type: 'address',
default: ethers.constants.AddressZero,
},
l1GenesisBlockGasLimit: {
type: 'string',
default: ethers.BigNumber.from(15_000_000).toHexString(),
},
l1GenesisBlockDifficulty: {
type: 'string', // uint256
default: '0x1',
},
l1GenesisBlockMixHash: {
type: 'string', // bytes32
default: ethers.constants.HashZero,
},
l1GenesisBlockCoinbase: {
type: 'address',
default: ethers.constants.AddressZero,
},
// l1GenesisBlockAlloc: the storage tree is not configurable with deploy-config.
l1GenesisBlockNumber: {
type: 'string', // uint64
default: '0x0',
},
l1GenesisBlockGasUsed: {
type: 'string', // uint64
default: '0x0',
},
l1GenesisBlockParentHash: {
type: 'string', // bytes32
default: ethers.constants.HashZero,
},
l1GenesisBlockBaseFeePerGas: {
type: 'string', // uint256
default: ethers.BigNumber.from(1000_000_000).toHexString(), // 1 gwei
},
// Optional L2 genesis block values. These must ONLY be used by the L2 genesis config script.
// -------------------------------------------------
l2GenesisBlockNonce: {
type: 'string', // uint64
default: '0x0',
},
// l2GenesisBlockTimestamp: configured dynamically, based on the timestamp of l1StartingBlockTag.
l2GenesisBlockExtraData: {
type: 'string', // important: in the case of L2, which uses post-Merge Ethereum rules, this must be <= 32 bytes.
default: ethers.constants.HashZero,
},
l2GenesisBlockGasLimit: {
type: 'string',
default: ethers.BigNumber.from(15_000_000).toHexString(),
},
l2GenesisBlockDifficulty: {
type: 'string', // uint256
default: '0x1',
},
l2GenesisBlockMixHash: {
type: 'string', // bytes32
default: ethers.constants.HashZero,
},
l2GenesisBlockCoinbase: {
type: 'address',
default: ethers.constants.AddressZero,
},
// l2GenesisBlockAlloc: the storage tree is not configurable with deploy-config.
l2GenesisBlockNumber: {
type: 'string', // uint64
default: '0x0',
},
l2GenesisBlockGasUsed: {
type: 'string', // uint64
default: '0x0',
},
l2GenesisBlockParentHash: {
type: 'string', // bytes32
default: ethers.constants.HashZero,
},
l2GenesisBlockBaseFeePerGas: {
type: 'string', // uint256
default: ethers.BigNumber.from(1000_000_000).toHexString(), // 1 gwei
},
// L2 chain configuration values
optimismBaseFeeRecipient: {
type: 'address',
default: ethers.constants.AddressZero,
},
optimismL1FeeRecipient: {
type: 'address',
default: ethers.constants.AddressZero,
},
// L2 predeploy variables
l2CrossDomainMessengerOwner: {
type: 'address',
default: ethers.constants.AddressZero,
},
gasPriceOracleOwner: {
type: 'address',
default: ethers.constants.AddressZero,
},
gasPriceOracleOverhead: {
type: 'number',
default: 2100,
},
gasPriceOracleScalar: {
type: 'number',
default: 1000_000,
},
gasPriceOracleDecimals: {
type: 'number',
default: 6,
},
proxyAdmin: {
type: 'address',
// no default, important to get right.
},
fundDevAccounts: {
type: 'boolean',
default: false,
},
deploymentWaitConfirmations: {
type: 'number',
default: 1,
},
},
external: {
......
import fs from 'fs'
import { ethers } from 'ethers'
import { task } from 'hardhat/config'
import { task, types } from 'hardhat/config'
import { Genesis, State } from '@eth-optimism/core-utils'
import '@eth-optimism/hardhat-deploy-config'
......@@ -11,10 +11,21 @@ task('genesis-l1', 'create a genesis config')
'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)
......@@ -61,18 +72,12 @@ task('genesis-l1', 'create a genesis config')
}
}
const timestamp = hre.deployConfig.l1GenesisTimestamp
if (timestamp === undefined) {
throw new Error('Must configure starting block timestamp')
}
const genesis: Genesis = {
config: {
chainId: 900,
chainId: deployConfig.l1ChainID,
homesteadBlock: 0,
eip150Block: 0,
eip150Hash:
'0x0000000000000000000000000000000000000000000000000000000000000000',
eip150Hash: ethers.constants.HashZero,
eip155Block: 0,
eip158Block: 0,
byzantiumBlock: 0,
......@@ -83,20 +88,26 @@ task('genesis-l1', 'create a genesis config')
berlinBlock: 0,
londonBlock: 0,
clique: {
period: 15,
period: deployConfig.l1BlockTime,
epoch: 30000,
},
},
nonce: '0x0',
timestamp: ethers.BigNumber.from(timestamp).toHexString(),
extraData:
'0x0000000000000000000000000000000000000000000000000000000000000000ca062b0fd91172d89bcd4bb084ac4e21972cc4670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
gasLimit: ethers.BigNumber.from(15_000_000).toHexString(),
difficulty: '0x1',
mixHash:
'0x0000000000000000000000000000000000000000000000000000000000000000',
coinbase: '0x0000000000000000000000000000000000000000',
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))
......
......@@ -210,6 +210,17 @@ task('genesis-l2', 'create a genesis config')
const l1 = new ethers.providers.StaticJsonRpcProvider(args.l1RpcUrl)
const l1StartingBlock = await l1.getBlock(deployConfig.l1StartingBlockTag)
if (l1StartingBlock === null) {
throw new Error(
`Cannot fetch block tag ${deployConfig.l1StartingBlockTag}`
)
}
if (l1StartingBlock === null) {
console.log(`Unable to fetch L1 block that rollup starts at`)
}
// Use the addresses of the proxies here instead of the implementations
// Be backwards compatible
let ProxyL1CrossDomainMessenger = await hre.deployments.getOrNull(
......@@ -255,11 +266,11 @@ task('genesis-l2', 'create a genesis config')
l1FeeWallet: ethers.constants.AddressZero,
},
L1Block: {
number: deployConfig.l1BlockInitialNumber,
timestamp: deployConfig.l1BlockInitialTimestamp,
basefee: deployConfig.l1BlockInitialBasefee,
hash: deployConfig.l1BlockInitialHash,
sequenceNumber: deployConfig.l1BlockInitialSequenceNumber,
number: l1StartingBlock.number,
timestamp: l1StartingBlock.timestamp,
basefee: l1StartingBlock.baseFeePerGas,
hash: l1StartingBlock.hash,
sequenceNumber: 0,
},
LegacyERC20ETH: {
bridge: predeploys.L2StandardBridge,
......@@ -462,24 +473,14 @@ task('genesis-l2', 'create a genesis config')
}
}
const l1StartingBlock = await l1.getBlock(deployConfig.l1StartingBlockTag)
if (l1StartingBlock === null) {
throw new Error(
`Cannot fetch block tag ${deployConfig.l1StartingBlockTag}`
)
}
if (l1StartingBlock === null) {
console.log(`Unable to fetch L1 starting timestamp`)
}
const startingTimestamp = l1StartingBlock?.timestamp || 0
const genesis: OptimismGenesis = {
config: {
chainId: deployConfig.genesisBlockChainid,
chainId: deployConfig.l2ChainID,
homesteadBlock: 0,
eip150Block: 0,
eip150Hash: ethers.constants.HashZero,
eip155Block: 0,
eip158Block: 0,
byzantiumBlock: 0,
......@@ -496,11 +497,17 @@ task('genesis-l2', 'create a genesis config')
l1FeeRecipient: deployConfig.optimismL1FeeRecipient,
},
},
nonce: '0x1234',
difficulty: '0x1',
nonce: deployConfig.l2GenesisBlockNonce,
timestamp: ethers.BigNumber.from(startingTimestamp).toHexString(),
gasLimit: deployConfig.genesisBlockGasLimit,
extraData: deployConfig.genesisBlockExtradata,
extraData: deployConfig.l2GenesisBlockExtraData,
gasLimit: deployConfig.l2GenesisBlockGasLimit,
difficulty: deployConfig.l2GenesisBlockDifficulty,
mixHash: deployConfig.l2GenesisBlockMixHash,
coinbase: deployConfig.l2GenesisBlockCoinbase,
number: deployConfig.l2GenesisBlockNumber,
gasUsed: deployConfig.l2GenesisBlockGasUsed,
parentHash: deployConfig.l2GenesisBlockParentHash,
baseFeePerGas: deployConfig.l2GenesisBlockBaseFeePerGas,
alloc,
}
......
......@@ -7,13 +7,13 @@ task('rekey', 'Generates a new set of keys for a test network').setAction(
const mnemonic = bip39.generateMnemonic()
const pathPrefix = "m/44'/60'/0'/0"
const labels = [
'sequencerAddress',
'l2OutputOracleProposer',
'proxyAdmin',
'optimismBaseFeeRecipient',
'optimismL1FeeRecipient',
'optimismL2FeeRecipient',
'p2pSequencerAddress',
'outputOracleOwner',
'l2OutputOracleOwner',
'batchSenderAddress',
]
......
......@@ -20,7 +20,21 @@ task('rollup-config', 'create a genesis config')
const l1 = new ethers.providers.StaticJsonRpcProvider(args.l1RpcUrl)
const l2 = new ethers.providers.StaticJsonRpcProvider(args.l2RpcUrl)
const l2Genesis = await l2.getBlock('earliest')
// sanity check our RPC connections
const l1ChainID = await getChainId(l1)
if (l1ChainID !== deployConfig.l1ChainID) {
throw new Error(
`connected to L1 RPC ${args.l1RpcUrl} yielded chain ID ${l1ChainID} but expected ${deployConfig.l1ChainID}`
)
}
const l2ChainID = await getChainId(l2)
if (l2ChainID !== deployConfig.l2ChainID) {
throw new Error(
`connected to L2 RPC ${args.l2RpcUrl} yielded chain ID ${l2ChainID} but expected ${deployConfig.l2ChainID}`
)
}
const l2GenesisBlock = await l2.getBlock('earliest')
const portal = await hre.deployments.get('OptimismPortalProxy')
const l1StartingBlock = await l1.getBlock(deployConfig.l1StartingBlockTag)
......@@ -37,8 +51,8 @@ task('rollup-config', 'create a genesis config')
number: l1StartingBlock.number,
},
l2: {
hash: l2Genesis.hash,
number: 0,
hash: l2GenesisBlock.hash,
number: l2GenesisBlock.number,
},
l2_time: l1StartingBlock.timestamp,
},
......@@ -47,12 +61,12 @@ task('rollup-config', 'create a genesis config')
seq_window_size: deployConfig.sequencerWindowSize,
channel_timeout: deployConfig.channelTimeout,
l1_chain_id: await getChainId(l1),
l2_chain_id: await getChainId(l2),
l1_chain_id: deployConfig.l1ChainID,
l2_chain_id: deployConfig.l2ChainID,
p2p_sequencer_address: deployConfig.p2pSequencerAddress,
fee_recipient_address: deployConfig.optimismL2FeeRecipient,
batch_inbox_address: '0xff00000000000000000000000000000000000002',
batch_inbox_address: deployConfig.batchInboxAddress,
batch_sender_address: deployConfig.batchSenderAddress,
deposit_contract_address: portal.address,
}
......
......@@ -60,6 +60,7 @@ export interface Genesis {
gasUsed?: string
parentHash?: string
extraData: string
baseFeePerGas?: string
alloc: State
}
......
import { HardhatUserConfig } from 'hardhat/types'
import { ethers } from 'ethers'
import '@nomiclabs/hardhat-ethers'
import '@nomiclabs/hardhat-waffle'
......@@ -20,6 +21,10 @@ const config: HardhatUserConfig = {
'ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
],
},
hivenet: {
url: process.env.L1_RPC || '',
accounts: [process.env.PRIVATE_KEY_DEPLOYER || ethers.constants.HashZero],
},
},
external: {
contracts: [
......@@ -28,6 +33,7 @@ const config: HardhatUserConfig = {
},
],
deployments: {
hivenet: ['../contracts-bedrock/deployments/hivenet'],
devnetL1: ['../contracts-bedrock/deployments/devnetL1'],
goerli: ['../contracts-bedrock/deployments/goerli'],
},
......
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