Commit 8f7ac67a authored by Roberto Bayardo's avatar Roberto Bayardo

add a bool config option for enabling governance

parent d19ebe01
...@@ -50,16 +50,13 @@ var ( ...@@ -50,16 +50,13 @@ var (
func IsProxied(predeployAddr common.Address) bool { func IsProxied(predeployAddr common.Address) bool {
switch predeployAddr { switch predeployAddr {
case LegacyERC20ETHAddr: case LegacyERC20ETHAddr:
return false
case WETH9Addr: case WETH9Addr:
return false
case GovernanceTokenAddr: case GovernanceTokenAddr:
return false
case ProxyAdminAddr: case ProxyAdminAddr:
return false
default: default:
return true return true
} }
return false
} }
// IsDeprecated returns true for predeploys we should skip in post-bedrock genesis generation // IsDeprecated returns true for predeploys we should skip in post-bedrock genesis generation
......
...@@ -113,6 +113,8 @@ type DeployConfig struct { ...@@ -113,6 +113,8 @@ type DeployConfig struct {
GasPriceOracleOverhead uint64 `json:"gasPriceOracleOverhead"` GasPriceOracleOverhead uint64 `json:"gasPriceOracleOverhead"`
// The initial value of the gas scalar // The initial value of the gas scalar
GasPriceOracleScalar uint64 `json:"gasPriceOracleScalar"` GasPriceOracleScalar uint64 `json:"gasPriceOracleScalar"`
// Whether or not include governance token predeploy
EnableGovernance bool `json:"enableGovernance"`
// The ERC20 symbol of the GovernanceToken // The ERC20 symbol of the GovernanceToken
GovernanceTokenSymbol string `json:"governanceTokenSymbol"` GovernanceTokenSymbol string `json:"governanceTokenSymbol"`
// The ERC20 name of the GovernanceToken // The ERC20 name of the GovernanceToken
...@@ -240,15 +242,16 @@ func (d *DeployConfig) Check() error { ...@@ -240,15 +242,16 @@ func (d *DeployConfig) Check() error {
if d.L2GenesisBlockBaseFeePerGas == nil { if d.L2GenesisBlockBaseFeePerGas == nil {
return fmt.Errorf("%w: L2 genesis block base fee per gas cannot be nil", ErrInvalidDeployConfig) return fmt.Errorf("%w: L2 genesis block base fee per gas cannot be nil", ErrInvalidDeployConfig)
} }
if d.GovernanceTokenName != "" { if d.EnableGovernance {
if d.GovernanceTokenName == "" {
return fmt.Errorf("%w: GovernanceToken.name cannot be empty", ErrInvalidDeployConfig)
}
if d.GovernanceTokenSymbol == "" { if d.GovernanceTokenSymbol == "" {
return fmt.Errorf("%w: GovernanceToken.symbol cannot be empty", ErrInvalidDeployConfig) return fmt.Errorf("%w: GovernanceToken.symbol cannot be empty", ErrInvalidDeployConfig)
} }
if d.GovernanceTokenOwner == (common.Address{}) { if d.GovernanceTokenOwner == (common.Address{}) {
return fmt.Errorf("%w: GovernanceToken owner cannot be address(0)", ErrInvalidDeployConfig) return fmt.Errorf("%w: GovernanceToken owner cannot be address(0)", ErrInvalidDeployConfig)
} }
} else if d.GovernanceTokenSymbol != "" || d.GovernanceTokenOwner != (common.Address{}) {
return fmt.Errorf("%w: Governance token fields must be either all specified or all empty", ErrInvalidDeployConfig)
} }
return nil return nil
} }
...@@ -493,7 +496,7 @@ func NewL2StorageConfig(config *DeployConfig, block *types.Block) (state.Storage ...@@ -493,7 +496,7 @@ func NewL2StorageConfig(config *DeployConfig, block *types.Block) (state.Storage
"symbol": "WETH", "symbol": "WETH",
"decimals": 18, "decimals": 18,
} }
if len(config.GovernanceTokenName) != 0 { if config.EnableGovernance {
storage["GovernanceToken"] = state.StorageValues{ storage["GovernanceToken"] = state.StorageValues{
"_name": config.GovernanceTokenName, "_name": config.GovernanceTokenName,
"_symbol": config.GovernanceTokenSymbol, "_symbol": config.GovernanceTokenSymbol,
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys" "github.com/ethereum-optimism/optimism/op-bindings/predeploys"
...@@ -56,7 +57,20 @@ func BuildL2DeveloperGenesis(config *DeployConfig, l1StartBlock *types.Block) (* ...@@ -56,7 +57,20 @@ func BuildL2DeveloperGenesis(config *DeployConfig, l1StartBlock *types.Block) (*
} }
// BuildL2MainnetGenesis will build an L2 Genesis suitable for a Superchain mainnet that does not // BuildL2MainnetGenesis will build an L2 Genesis suitable for a Superchain mainnet that does not
// require a pre-bedrock migration & supports optional governance token predeploy. // require a pre-bedrock migration & supports optional governance token predeploy. Details:
//
// - Creates proxies for predeploys in the address space:
// [0x4200000000000000000000000000000000000000, 0x4200000000000000000000000000000000000800)
//
// - All predeploy proxies owned by the ProxyAdmin
//
// - Predeploys as per the spec except for no LegacyERC20ETH predeploy at
// 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000
//
// - optional governance token at 0x4200000000000000000000000000000000000042 if
// config.EnableGovernance is true (& otherwise a no-impl proxy remains at this address)
//
// - no accounts are pre-funded
func BuildL2MainnetGenesis(config *DeployConfig, l1StartBlock *types.Block) (*core.Genesis, error) { func BuildL2MainnetGenesis(config *DeployConfig, l1StartBlock *types.Block) (*core.Genesis, error) {
genspec, err := NewL2Genesis(config, l1StartBlock) genspec, err := NewL2Genesis(config, l1StartBlock)
if err != nil { if err != nil {
...@@ -101,8 +115,9 @@ func BuildL2MainnetGenesis(config *DeployConfig, l1StartBlock *types.Block) (*co ...@@ -101,8 +115,9 @@ func BuildL2MainnetGenesis(config *DeployConfig, l1StartBlock *types.Block) (*co
if predeploys.IsDeprecated(addr) { if predeploys.IsDeprecated(addr) {
continue continue
} }
if addr == predeploys.GovernanceTokenAddr && storage["GovernanceToken"] == nil { if addr == predeploys.GovernanceTokenAddr && !config.EnableGovernance {
// there is no governance token configured, so skip the governance token predeploy // there is no governance token configured, so skip the governance token predeploy
log.Warn("Governance is not enabled, skipping governance token predeploy.")
continue continue
} }
codeAddr := addr codeAddr := addr
...@@ -112,8 +127,10 @@ func BuildL2MainnetGenesis(config *DeployConfig, l1StartBlock *types.Block) (*co ...@@ -112,8 +127,10 @@ func BuildL2MainnetGenesis(config *DeployConfig, l1StartBlock *types.Block) (*co
return nil, fmt.Errorf("error converting to code namespace: %w", err) return nil, fmt.Errorf("error converting to code namespace: %w", err)
} }
db.CreateAccount(codeAddr) db.CreateAccount(codeAddr)
db.SetState(addr, ImplementationSlot, codeAddr.Hash())
} else {
db.DeleteState(addr, AdminSlot)
} }
db.SetState(addr, ImplementationSlot, codeAddr.Hash())
if err := setupPredeploy(db, deployResults, storage, name, addr, codeAddr); err != nil { if err := setupPredeploy(db, deployResults, storage, name, addr, codeAddr); err != nil {
return nil, err return nil, err
} }
......
...@@ -45,7 +45,7 @@ func TestBuildL2DeveloperGenesis(t *testing.T) { ...@@ -45,7 +45,7 @@ func TestBuildL2DeveloperGenesis(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
require.NotNil(t, gen) require.NotNil(t, gen)
depB, err := bindings.GetDeployedBytecode("Proxy") proxyBytecode, err := bindings.GetDeployedBytecode("Proxy")
require.NoError(t, err) require.NoError(t, err)
for name, address := range predeploys.Predeploys { for name, address := range predeploys.Predeploys {
...@@ -60,9 +60,9 @@ func TestBuildL2DeveloperGenesis(t *testing.T) { ...@@ -60,9 +60,9 @@ func TestBuildL2DeveloperGenesis(t *testing.T) {
} }
adminSlot, ok := account.Storage[genesis.AdminSlot] adminSlot, ok := account.Storage[genesis.AdminSlot]
require.Equal(t, true, ok) require.Equal(t, true, ok, name)
require.Equal(t, predeploys.ProxyAdminAddr.Hash(), adminSlot) require.Equal(t, predeploys.ProxyAdminAddr.Hash(), adminSlot)
require.Equal(t, depB, account.Code) require.Equal(t, proxyBytecode, account.Code)
} }
require.Equal(t, 2343, len(gen.Alloc)) require.Equal(t, 2343, len(gen.Alloc))
...@@ -94,9 +94,13 @@ func TestBuildL2DeveloperGenesisDevAccountsFunding(t *testing.T) { ...@@ -94,9 +94,13 @@ func TestBuildL2DeveloperGenesisDevAccountsFunding(t *testing.T) {
require.Equal(t, 2321, len(gen.Alloc)) require.Equal(t, 2321, len(gen.Alloc))
} }
func TestBuildL2MainnetGenesis(t *testing.T) { // Tests the BuildL2MainnetGenesis factory. enableGovernance is used to override enableGovernance
// config option. When false, the test confirms the governance token predeploy address instead
// holds a proxy contract.
func testBuildL2Genesis(t *testing.T, enableGovernance bool) {
config, err := genesis.NewDeployConfig("./testdata/test-deploy-config-devnet-l1.json") config, err := genesis.NewDeployConfig("./testdata/test-deploy-config-devnet-l1.json")
require.Nil(t, err) require.Nil(t, err)
config.EnableGovernance = enableGovernance
backend := backends.NewSimulatedBackend( backend := backends.NewSimulatedBackend(
core.GenesisAlloc{ core.GenesisAlloc{
...@@ -111,34 +115,34 @@ func TestBuildL2MainnetGenesis(t *testing.T) { ...@@ -111,34 +115,34 @@ func TestBuildL2MainnetGenesis(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
require.NotNil(t, gen) require.NotNil(t, gen)
depB, err := bindings.GetDeployedBytecode("Proxy") proxyBytecode, err := bindings.GetDeployedBytecode("Proxy")
require.NoError(t, err) require.NoError(t, err)
for name, predeploy := range predeploys.Predeploys { for name, predeploy := range predeploys.Predeploys {
addr := *predeploy addr := *predeploy
if predeploys.IsDeprecated(addr) {
continue
}
account, ok := gen.Alloc[addr] account, ok := gen.Alloc[addr]
if predeploys.IsDeprecated(addr) && !predeploys.IsProxied(addr) { if predeploys.IsDeprecated(addr) && !predeploys.IsProxied(addr) {
// deprecated, non-proxied predeploys should have no account
require.Equal(t, false, ok, name) require.Equal(t, false, ok, name)
continue continue
} }
require.Equal(t, true, ok, name) require.Equal(t, true, ok, name)
require.Greater(t, len(account.Code), 0) require.Greater(t, len(account.Code), 0)
if !predeploys.IsProxied(addr) {
continue
}
adminSlot, ok := account.Storage[genesis.AdminSlot] adminSlot, ok := account.Storage[genesis.AdminSlot]
require.Equal(t, true, ok) isProxy := predeploys.IsProxied(addr) ||
require.Equal(t, predeploys.ProxyAdminAddr.Hash(), adminSlot) (!enableGovernance && addr == predeploys.GovernanceTokenAddr)
require.Equal(t, depB, account.Code) if isProxy {
require.Equal(t, true, ok, name)
require.Equal(t, predeploys.ProxyAdminAddr.Hash(), adminSlot)
require.Equal(t, proxyBytecode, account.Code)
} else {
require.Equal(t, false, ok, name)
require.NotEqual(t, proxyBytecode, account.Code, name)
}
} }
require.Equal(t, 2063, len(gen.Alloc)) // TODO: confirm 2063 is correct! require.Equal(t, 2063, len(gen.Alloc))
if writeFile { if writeFile {
file, _ := json.MarshalIndent(gen, "", " ") file, _ := json.MarshalIndent(gen, "", " ")
...@@ -146,57 +150,10 @@ func TestBuildL2MainnetGenesis(t *testing.T) { ...@@ -146,57 +150,10 @@ func TestBuildL2MainnetGenesis(t *testing.T) {
} }
} }
// Same test as TestBuildL2MainnetGenesis, only we blow away the governance token config and func TestBuildL2MainnetGenesis(t *testing.T) {
// confirm the governance predeploy doesn't exist (or more precisely, there's an unused proxy testBuildL2Genesis(t, true)
// contract at its address instead). }
func TestBuildL2MainnetNoGovernanceGenesis(t *testing.T) {
config, err := genesis.NewDeployConfig("./testdata/test-deploy-config-devnet-l1.json")
require.Nil(t, err)
config.GovernanceTokenSymbol = ""
config.GovernanceTokenName = ""
config.GovernanceTokenOwner = common.Address{}
backend := backends.NewSimulatedBackend(
core.GenesisAlloc{
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)},
},
15000000,
)
block, err := backend.BlockByNumber(context.Background(), common.Big0)
require.NoError(t, err)
gen, err := genesis.BuildL2MainnetGenesis(config, block)
require.Nil(t, err)
require.NotNil(t, gen)
depB, err := bindings.GetDeployedBytecode("Proxy")
require.NoError(t, err)
for name, predeploy := range predeploys.Predeploys {
addr := *predeploy
account, ok := gen.Alloc[addr]
if predeploys.IsDeprecated(addr) && !predeploys.IsProxied(addr) {
require.Equal(t, false, ok, name)
continue
}
require.Equal(t, true, ok, name)
require.Greater(t, len(account.Code), 0)
if !predeploys.IsProxied(addr) && addr != predeploys.GovernanceTokenAddr {
continue
}
adminSlot, ok := account.Storage[genesis.AdminSlot]
require.Equal(t, true, ok)
require.Equal(t, predeploys.ProxyAdminAddr.Hash(), adminSlot)
require.Equal(t, depB, account.Code)
}
require.Equal(t, 2063, len(gen.Alloc)) // TODO: confirm 2063 is correct!
if writeFile { func TestBuildL2MainnetNoGovernanceGenesis(t *testing.T) {
file, _ := json.MarshalIndent(gen, "", " ") testBuildL2Genesis(t, false)
_ = os.WriteFile("genesis.json", file, 0644)
}
} }
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
"deploymentWaitConfirmations": 1, "deploymentWaitConfirmations": 1,
"fundDevAccounts": true, "fundDevAccounts": true,
"enableGovernance": true,
"governanceTokenSymbol": "OP", "governanceTokenSymbol": "OP",
"governanceTokenName": "Optimism", "governanceTokenName": "Optimism",
"governanceTokenOwner": "0x0000000000000000000000000000000000000333" "governanceTokenOwner": "0x0000000000000000000000000000000000000333"
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
"proxyAdminOwner": "0x0000000000000000000000000000000000000222", "proxyAdminOwner": "0x0000000000000000000000000000000000000222",
"gasPriceOracleOverhead": 2100, "gasPriceOracleOverhead": 2100,
"gasPriceOracleScalar": 1000000, "gasPriceOracleScalar": 1000000,
"enableGovernance": true,
"governanceTokenSymbol": "OP", "governanceTokenSymbol": "OP",
"governanceTokenName": "Optimism", "governanceTokenName": "Optimism",
"governanceTokenOwner": "0x0000000000000000000000000000000000000333", "governanceTokenOwner": "0x0000000000000000000000000000000000000333",
......
...@@ -226,6 +226,15 @@ func (db *MemoryStateDB) SetState(addr common.Address, key, value common.Hash) { ...@@ -226,6 +226,15 @@ func (db *MemoryStateDB) SetState(addr common.Address, key, value common.Hash) {
db.genesis.Alloc[addr] = account db.genesis.Alloc[addr] = account
} }
func (db *MemoryStateDB) DeleteState(addr common.Address, key common.Hash) {
account, ok := db.genesis.Alloc[addr]
if !ok {
panic(fmt.Sprintf("%s not in state", addr))
}
delete(account.Storage, key)
db.genesis.Alloc[addr] = account
}
func (db *MemoryStateDB) Suicide(common.Address) bool { func (db *MemoryStateDB) Suicide(common.Address) bool {
panic("Suicide unimplemented") panic("Suicide unimplemented")
} }
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
"l2GenesisBlockBaseFeePerGas": "0x3B9ACA00", "l2GenesisBlockBaseFeePerGas": "0x3B9ACA00",
"gasPriceOracleOverhead": 2100, "gasPriceOracleOverhead": 2100,
"gasPriceOracleScalar": 1000000, "gasPriceOracleScalar": 1000000,
"enableGovernance": true,
"governanceTokenSymbol": "OP", "governanceTokenSymbol": "OP",
"governanceTokenName": "Optimism", "governanceTokenName": "Optimism",
"governanceTokenOwner": "0xBcd4042DE499D14e55001CcbB24a551F3b954096", "governanceTokenOwner": "0xBcd4042DE499D14e55001CcbB24a551F3b954096",
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
"gasPriceOracleOverhead": 2100, "gasPriceOracleOverhead": 2100,
"gasPriceOracleScalar": 1000000, "gasPriceOracleScalar": 1000000,
"enableGovernance": true,
"governanceTokenSymbol": "OP", "governanceTokenSymbol": "OP",
"governanceTokenName": "Optimism", "governanceTokenName": "Optimism",
"governanceTokenOwner": "ADMIN", "governanceTokenOwner": "ADMIN",
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
"proxyAdminOwner": "0x62790eFcB3a5f3A5D398F95B47930A9Addd83807", "proxyAdminOwner": "0x62790eFcB3a5f3A5D398F95B47930A9Addd83807",
"enableGovernance": true,
"governanceTokenName": "Optimism", "governanceTokenName": "Optimism",
"governanceTokenSymbol": "OP", "governanceTokenSymbol": "OP",
"governanceTokenOwner": "0x038a8825A3C3B0c08d52Cc76E5E361953Cf6Dc76", "governanceTokenOwner": "0x038a8825A3C3B0c08d52Cc76E5E361953Cf6Dc76",
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
"gasPriceOracleOverhead": 2100, "gasPriceOracleOverhead": 2100,
"gasPriceOracleScalar": 1000000, "gasPriceOracleScalar": 1000000,
"enableGovernance": true,
"governanceTokenSymbol": "OP", "governanceTokenSymbol": "OP",
"governanceTokenName": "Optimism", "governanceTokenName": "Optimism",
"governanceTokenOwner": "0x038a8825A3C3B0c08d52Cc76E5E361953Cf6Dc76", "governanceTokenOwner": "0x038a8825A3C3B0c08d52Cc76E5E361953Cf6Dc76",
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
"baseFeeVaultWithdrawalNetwork": 0, "baseFeeVaultWithdrawalNetwork": 0,
"l1FeeVaultWithdrawalNetwork": 0, "l1FeeVaultWithdrawalNetwork": 0,
"sequencerFeeVaultWithdrawalNetwork": 0, "sequencerFeeVaultWithdrawalNetwork": 0,
"enableGovernance": true,
"governanceTokenName": "Optimism", "governanceTokenName": "Optimism",
"governanceTokenSymbol": "OP", "governanceTokenSymbol": "OP",
"governanceTokenOwner": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", "governanceTokenOwner": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc",
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
"l1FeeVaultWithdrawalNetwork": 0, "l1FeeVaultWithdrawalNetwork": 0,
"sequencerFeeVaultWithdrawalNetwork": 0, "sequencerFeeVaultWithdrawalNetwork": 0,
"enableGovernance": true,
"governanceTokenName": "Optimism", "governanceTokenName": "Optimism",
"governanceTokenSymbol": "OP", "governanceTokenSymbol": "OP",
"governanceTokenOwner": "0x858F0751ef8B4067f0d2668C076BDB50a8549fbF", "governanceTokenOwner": "0x858F0751ef8B4067f0d2668C076BDB50a8549fbF",
......
...@@ -37,6 +37,7 @@ const config: DeployConfig = { ...@@ -37,6 +37,7 @@ const config: DeployConfig = {
l1FeeVaultWithdrawalNetwork: 0, l1FeeVaultWithdrawalNetwork: 0,
sequencerFeeVaultWithdrawalNetwork: 0, sequencerFeeVaultWithdrawalNetwork: 0,
enableGovernance: true,
governanceTokenName: 'Optimism', governanceTokenName: 'Optimism',
governanceTokenSymbol: 'OP', governanceTokenSymbol: 'OP',
governanceTokenOwner: '0x90F79bf6EB2c4f870365E785982E1f101E93b906', governanceTokenOwner: '0x90F79bf6EB2c4f870365E785982E1f101E93b906',
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
"baseFeeVaultWithdrawalNetwork": 0, "baseFeeVaultWithdrawalNetwork": 0,
"l1FeeVaultWithdrawalNetwork": 0, "l1FeeVaultWithdrawalNetwork": 0,
"sequencerFeeVaultWithdrawalNetwork": 0, "sequencerFeeVaultWithdrawalNetwork": 0,
"enableGovernance": true,
"governanceTokenName": "Optimism", "governanceTokenName": "Optimism",
"governanceTokenSymbol": "OP", "governanceTokenSymbol": "OP",
"governanceTokenOwner": "0x5C4e7Ba1E219E47948e6e3F55019A647bA501005", "governanceTokenOwner": "0x5C4e7Ba1E219E47948e6e3F55019A647bA501005",
......
...@@ -110,6 +110,11 @@ interface RequiredDeployConfig { ...@@ -110,6 +110,11 @@ interface RequiredDeployConfig {
*/ */
l2OutputOracleChallenger: string l2OutputOracleChallenger: string
/**
* Whether to enable governance token predeploy.
*/
enableGovernance: boolean
/** /**
* ERC20 symbol used for the L2 GovernanceToken. * ERC20 symbol used for the L2 GovernanceToken.
*/ */
...@@ -414,6 +419,10 @@ export const deployConfigSpec: { ...@@ -414,6 +419,10 @@ export const deployConfigSpec: {
type: 'number', type: 'number',
default: 1_000_000, default: 1_000_000,
}, },
enableGovernance: {
type: 'boolean',
default: false,
},
governanceTokenSymbol: { governanceTokenSymbol: {
type: 'string', type: 'string',
}, },
......
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