Commit c8f4b3a0 authored by Sam Stokes's avatar Sam Stokes Committed by GitHub

op-deployer: add intent-config-type (#12970)

* op-deployer: add config-intent-type

* op-deployer: revert name change of GasLimit

* op-deployer: add Intent.setStandardValues and Intent.validateStandardValues

* op-deployer: improve standard intent-config err messages

* op-deployr: chain intent custom err types

* op-deployer: add unit test for inent.validateStandardValues

* linter fix

* add intent-config-type custom

* add intent-config-type strict

* add intent-config-type standard-overrides,strict-overrides

* refactor intent.ConfigType validation methods, add intent NewIntent* funcs

* add TestValidateCustomValues, refactor contract tag check

* remove duplicate chainIntent.Check() code

* fix SuperchainRoles.ProxyAdminOwner for standard chains
parent 91099581
...@@ -141,6 +141,9 @@ func ApplyPipeline( ...@@ -141,6 +141,9 @@ func ApplyPipeline(
opts ApplyPipelineOpts, opts ApplyPipelineOpts,
) error { ) error {
intent := opts.Intent intent := opts.Intent
if err := intent.Check(); err != nil {
return err
}
st := opts.State st := opts.State
progressor := func(curr, total int64) { progressor := func(curr, total int64) {
......
...@@ -70,11 +70,7 @@ func (a *Locator) MarshalText() ([]byte, error) { ...@@ -70,11 +70,7 @@ func (a *Locator) MarshalText() ([]byte, error) {
return []byte(a.URL.String()), nil return []byte(a.URL.String()), nil
} }
if a.Tag != "" {
return []byte("tag://" + a.Tag), nil return []byte("tag://" + a.Tag), nil
}
return nil, fmt.Errorf("no URL, path or tag set")
} }
func (a *Locator) IsTag() bool { func (a *Locator) IsTag() bool {
......
...@@ -20,6 +20,7 @@ const ( ...@@ -20,6 +20,7 @@ const (
OutdirFlagName = "outdir" OutdirFlagName = "outdir"
PrivateKeyFlagName = "private-key" PrivateKeyFlagName = "private-key"
DeploymentStrategyFlagName = "deployment-strategy" DeploymentStrategyFlagName = "deployment-strategy"
IntentConfigTypeFlagName = "intent-config-type"
) )
var ( var (
...@@ -35,7 +36,7 @@ var ( ...@@ -35,7 +36,7 @@ var (
Name: L1ChainIDFlagName, Name: L1ChainIDFlagName,
Usage: "Chain ID of the L1 chain.", Usage: "Chain ID of the L1 chain.",
EnvVars: PrefixEnvVar("L1_CHAIN_ID"), EnvVars: PrefixEnvVar("L1_CHAIN_ID"),
Value: 900, Value: 11155111,
} }
L2ChainIDsFlag = &cli.StringFlag{ L2ChainIDsFlag = &cli.StringFlag{
Name: L2ChainIDsFlagName, Name: L2ChainIDsFlagName,
...@@ -62,6 +63,17 @@ var ( ...@@ -62,6 +63,17 @@ var (
EnvVars: PrefixEnvVar("DEPLOYMENT_STRATEGY"), EnvVars: PrefixEnvVar("DEPLOYMENT_STRATEGY"),
Value: string(state.DeploymentStrategyLive), Value: string(state.DeploymentStrategyLive),
} }
IntentConfigTypeFlag = &cli.StringFlag{
Name: IntentConfigTypeFlagName,
Usage: fmt.Sprintf("Intent config type to use. Options: %s (default), %s, %s, %s, %s",
state.IntentConfigTypeStandard,
state.IntentConfigTypeCustom,
state.IntentConfigTypeStrict,
state.IntentConfigTypeStandardOverrides,
state.IntentConfigTypeStrictOverrides),
EnvVars: PrefixEnvVar("INTENT_CONFIG_TYPE"),
Value: string(state.IntentConfigTypeStandard),
}
) )
var GlobalFlags = append([]cli.Flag{}, oplog.CLIFlags(EnvVarPrefix)...) var GlobalFlags = append([]cli.Flag{}, oplog.CLIFlags(EnvVarPrefix)...)
...@@ -71,6 +83,7 @@ var InitFlags = []cli.Flag{ ...@@ -71,6 +83,7 @@ var InitFlags = []cli.Flag{
L2ChainIDsFlag, L2ChainIDsFlag,
WorkdirFlag, WorkdirFlag,
DeploymentStrategyFlag, DeploymentStrategyFlag,
IntentConfigTypeFlag,
} }
var ApplyFlags = []cli.Flag{ var ApplyFlags = []cli.Flag{
......
...@@ -7,19 +7,17 @@ import ( ...@@ -7,19 +7,17 @@ import (
"path" "path"
"strings" "strings"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state"
op_service "github.com/ethereum-optimism/optimism/op-service" op_service "github.com/ethereum-optimism/optimism/op-service"
"github.com/ethereum-optimism/optimism/op-chain-ops/devkeys"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
type InitConfig struct { type InitConfig struct {
DeploymentStrategy state.DeploymentStrategy DeploymentStrategy state.DeploymentStrategy
IntentConfigType state.IntentConfigType
L1ChainID uint64 L1ChainID uint64
Outdir string Outdir string
L2ChainIDs []common.Hash L2ChainIDs []common.Hash
...@@ -51,6 +49,7 @@ func InitCLI() func(ctx *cli.Context) error { ...@@ -51,6 +49,7 @@ func InitCLI() func(ctx *cli.Context) error {
l1ChainID := ctx.Uint64(L1ChainIDFlagName) l1ChainID := ctx.Uint64(L1ChainIDFlagName)
outdir := ctx.String(OutdirFlagName) outdir := ctx.String(OutdirFlagName)
l2ChainIDsRaw := ctx.String(L2ChainIDsFlagName) l2ChainIDsRaw := ctx.String(L2ChainIDsFlagName)
intentConfigType := ctx.String(IntentConfigTypeFlagName)
if len(l2ChainIDsRaw) == 0 { if len(l2ChainIDsRaw) == 0 {
return fmt.Errorf("must specify at least one L2 chain ID") return fmt.Errorf("must specify at least one L2 chain ID")
...@@ -68,6 +67,7 @@ func InitCLI() func(ctx *cli.Context) error { ...@@ -68,6 +67,7 @@ func InitCLI() func(ctx *cli.Context) error {
err := Init(InitConfig{ err := Init(InitConfig{
DeploymentStrategy: state.DeploymentStrategy(deploymentStrategy), DeploymentStrategy: state.DeploymentStrategy(deploymentStrategy),
IntentConfigType: state.IntentConfigType(intentConfigType),
L1ChainID: l1ChainID, L1ChainID: l1ChainID,
Outdir: outdir, Outdir: outdir,
L2ChainIDs: l2ChainIDs, L2ChainIDs: l2ChainIDs,
...@@ -86,55 +86,12 @@ func Init(cfg InitConfig) error { ...@@ -86,55 +86,12 @@ func Init(cfg InitConfig) error {
return fmt.Errorf("invalid config for init: %w", err) return fmt.Errorf("invalid config for init: %w", err)
} }
intent := &state.Intent{ intent, err := state.NewIntent(cfg.IntentConfigType, cfg.DeploymentStrategy, cfg.L1ChainID, cfg.L2ChainIDs)
DeploymentStrategy: cfg.DeploymentStrategy,
L1ChainID: cfg.L1ChainID,
FundDevAccounts: true,
L1ContractsLocator: artifacts.DefaultL1ContractsLocator,
L2ContractsLocator: artifacts.DefaultL2ContractsLocator,
}
l1ChainIDBig := intent.L1ChainIDBig()
dk, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic)
if err != nil { if err != nil {
return fmt.Errorf("failed to create dev keys: %w", err) return err
}
addrFor := func(key devkeys.Key) common.Address {
// The error below should never happen, so panic if it does.
addr, err := dk.Address(key)
if err != nil {
panic(err)
}
return addr
}
intent.SuperchainRoles = &state.SuperchainRoles{
ProxyAdminOwner: addrFor(devkeys.L1ProxyAdminOwnerRole.Key(l1ChainIDBig)),
ProtocolVersionsOwner: addrFor(devkeys.SuperchainProtocolVersionsOwner.Key(l1ChainIDBig)),
Guardian: addrFor(devkeys.SuperchainConfigGuardianKey.Key(l1ChainIDBig)),
}
for _, l2ChainID := range cfg.L2ChainIDs {
l2ChainIDBig := l2ChainID.Big()
intent.Chains = append(intent.Chains, &state.ChainIntent{
ID: l2ChainID,
BaseFeeVaultRecipient: addrFor(devkeys.BaseFeeVaultRecipientRole.Key(l2ChainIDBig)),
L1FeeVaultRecipient: addrFor(devkeys.L1FeeVaultRecipientRole.Key(l2ChainIDBig)),
SequencerFeeVaultRecipient: addrFor(devkeys.SequencerFeeVaultRecipientRole.Key(l2ChainIDBig)),
Eip1559Denominator: 50,
Eip1559Elasticity: 6,
Roles: state.ChainRoles{
L1ProxyAdminOwner: addrFor(devkeys.L1ProxyAdminOwnerRole.Key(l2ChainIDBig)),
L2ProxyAdminOwner: addrFor(devkeys.L2ProxyAdminOwnerRole.Key(l2ChainIDBig)),
SystemConfigOwner: addrFor(devkeys.SystemConfigOwner.Key(l2ChainIDBig)),
UnsafeBlockSigner: addrFor(devkeys.SequencerP2PRole.Key(l2ChainIDBig)),
Batcher: addrFor(devkeys.BatcherRole.Key(l2ChainIDBig)),
Proposer: addrFor(devkeys.ProposerRole.Key(l2ChainIDBig)),
Challenger: addrFor(devkeys.ChallengerRole.Key(l2ChainIDBig)),
},
})
} }
intent.DeploymentStrategy = cfg.DeploymentStrategy
intent.ConfigType = cfg.IntentConfigType
st := &state.State{ st := &state.State{
Version: 1, Version: 1,
......
...@@ -714,6 +714,7 @@ func newIntent( ...@@ -714,6 +714,7 @@ func newIntent(
l2Loc *artifacts.Locator, l2Loc *artifacts.Locator,
) (*state.Intent, *state.State) { ) (*state.Intent, *state.State) {
intent := &state.Intent{ intent := &state.Intent{
ConfigType: state.IntentConfigTypeCustom,
DeploymentStrategy: state.DeploymentStrategyLive, DeploymentStrategy: state.DeploymentStrategyLive,
L1ChainID: l1ChainID.Uint64(), L1ChainID: l1ChainID.Uint64(),
SuperchainRoles: &state.SuperchainRoles{ SuperchainRoles: &state.SuperchainRoles{
...@@ -740,8 +741,9 @@ func newChainIntent(t *testing.T, dk *devkeys.MnemonicDevKeys, l1ChainID *big.In ...@@ -740,8 +741,9 @@ func newChainIntent(t *testing.T, dk *devkeys.MnemonicDevKeys, l1ChainID *big.In
BaseFeeVaultRecipient: addrFor(t, dk, devkeys.BaseFeeVaultRecipientRole.Key(l1ChainID)), BaseFeeVaultRecipient: addrFor(t, dk, devkeys.BaseFeeVaultRecipientRole.Key(l1ChainID)),
L1FeeVaultRecipient: addrFor(t, dk, devkeys.L1FeeVaultRecipientRole.Key(l1ChainID)), L1FeeVaultRecipient: addrFor(t, dk, devkeys.L1FeeVaultRecipientRole.Key(l1ChainID)),
SequencerFeeVaultRecipient: addrFor(t, dk, devkeys.SequencerFeeVaultRecipientRole.Key(l1ChainID)), SequencerFeeVaultRecipient: addrFor(t, dk, devkeys.SequencerFeeVaultRecipientRole.Key(l1ChainID)),
Eip1559Denominator: 50, Eip1559DenominatorCanyon: standard.Eip1559DenominatorCanyon,
Eip1559Elasticity: 6, Eip1559Denominator: standard.Eip1559Denominator,
Eip1559Elasticity: standard.Eip1559Elasticity,
Roles: state.ChainRoles{ Roles: state.ChainRoles{
L1ProxyAdminOwner: addrFor(t, dk, devkeys.L2ProxyAdminOwnerRole.Key(l1ChainID)), L1ProxyAdminOwner: addrFor(t, dk, devkeys.L2ProxyAdminOwnerRole.Key(l1ChainID)),
L2ProxyAdminOwner: addrFor(t, dk, devkeys.L2ProxyAdminOwnerRole.Key(l1ChainID)), L2ProxyAdminOwner: addrFor(t, dk, devkeys.L2ProxyAdminOwnerRole.Key(l1ChainID)),
......
...@@ -26,6 +26,9 @@ const ( ...@@ -26,6 +26,9 @@ const (
DisputeSplitDepth uint64 = 30 DisputeSplitDepth uint64 = 30
DisputeClockExtension uint64 = 10800 DisputeClockExtension uint64 = 10800
DisputeMaxClockDuration uint64 = 302400 DisputeMaxClockDuration uint64 = 302400
Eip1559DenominatorCanyon uint64 = 250
Eip1559Denominator uint64 = 50
Eip1559Elasticity uint64 = 6
ContractsV160Tag = "op-contracts/v1.6.0" ContractsV160Tag = "op-contracts/v1.6.0"
ContractsV170Beta1L2Tag = "op-contracts/v1.7.0-beta.1+l2-contracts" ContractsV170Beta1L2Tag = "op-contracts/v1.7.0-beta.1+l2-contracts"
...@@ -97,6 +100,28 @@ func L1VersionsFor(chainID uint64) (L1Versions, error) { ...@@ -97,6 +100,28 @@ func L1VersionsFor(chainID uint64) (L1Versions, error) {
} }
} }
func GuardianAddressFor(chainID uint64) (common.Address, error) {
switch chainID {
case 1:
return common.HexToAddress("0x09f7150D8c019BeF34450d6920f6B3608ceFdAf2"), nil
case 11155111:
return common.HexToAddress("0x7a50f00e8D05b95F98fE38d8BeE366a7324dCf7E"), nil
default:
return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID)
}
}
func ChallengerAddressFor(chainID uint64) (common.Address, error) {
switch chainID {
case 1:
return common.HexToAddress("0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A"), nil
case 11155111:
return common.HexToAddress("0xfd1D2e729aE8eEe2E146c033bf4400fE75284301"), nil
default:
return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID)
}
}
func SuperchainFor(chainID uint64) (*superchain.Superchain, error) { func SuperchainFor(chainID uint64) (*superchain.Superchain, error) {
switch chainID { switch chainID {
case 1: case 1:
...@@ -115,7 +140,7 @@ func ChainNameFor(chainID uint64) (string, error) { ...@@ -115,7 +140,7 @@ func ChainNameFor(chainID uint64) (string, error) {
case 11155111: case 11155111:
return "sepolia", nil return "sepolia", nil
default: default:
return "", fmt.Errorf("unrecognized chain ID: %d", chainID) return "", fmt.Errorf("unrecognized l1 chain ID: %d", chainID)
} }
} }
...@@ -173,6 +198,17 @@ func SystemOwnerAddrFor(chainID uint64) (common.Address, error) { ...@@ -173,6 +198,17 @@ func SystemOwnerAddrFor(chainID uint64) (common.Address, error) {
} }
} }
func L1ProxyAdminOwner(chainID uint64) (common.Address, error) {
switch chainID {
case 1:
return common.HexToAddress("0x5a0Aae59D09fccBdDb6C6CcEB07B7279367C3d2A"), nil
case 11155111:
return common.HexToAddress("0x1Eb2fFc903729a0F03966B917003800b145F56E2"), nil
default:
return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID)
}
}
func ArtifactsURLForTag(tag string) (*url.URL, error) { func ArtifactsURLForTag(tag string) (*url.URL, error) {
switch tag { switch tag {
case "op-contracts/v1.6.0": case "op-contracts/v1.6.0":
......
package state
import (
"fmt"
"reflect"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum/go-ethereum/common"
)
type ChainIntent struct {
ID common.Hash `json:"id" toml:"id"`
BaseFeeVaultRecipient common.Address `json:"baseFeeVaultRecipient" toml:"baseFeeVaultRecipient"`
L1FeeVaultRecipient common.Address `json:"l1FeeVaultRecipient" toml:"l1FeeVaultRecipient"`
SequencerFeeVaultRecipient common.Address `json:"sequencerFeeVaultRecipient" toml:"sequencerFeeVaultRecipient"`
Eip1559DenominatorCanyon uint64 `json:"eip1559DenominatorCanyon" toml:"eip1559DenominatorCanyon"`
Eip1559Denominator uint64 `json:"eip1559Denominator" toml:"eip1559Denominator"`
Eip1559Elasticity uint64 `json:"eip1559Elasticity" toml:"eip1559Elasticity"`
Roles ChainRoles `json:"roles" toml:"roles"`
DeployOverrides map[string]any `json:"deployOverrides" toml:"deployOverrides"`
DangerousAltDAConfig genesis.AltDADeployConfig `json:"dangerousAltDAConfig,omitempty" toml:"dangerousAltDAConfig,omitempty"`
}
type ChainRoles struct {
L1ProxyAdminOwner common.Address `json:"l1ProxyAdminOwner" toml:"l1ProxyAdminOwner"`
L2ProxyAdminOwner common.Address `json:"l2ProxyAdminOwner" toml:"l2ProxyAdminOwner"`
SystemConfigOwner common.Address `json:"systemConfigOwner" toml:"systemConfigOwner"`
UnsafeBlockSigner common.Address `json:"unsafeBlockSigner" toml:"unsafeBlockSigner"`
Batcher common.Address `json:"batcher" toml:"batcher"`
Proposer common.Address `json:"proposer" toml:"proposer"`
Challenger common.Address `json:"challenger" toml:"challenger"`
}
var ErrChainRoleZeroAddress = fmt.Errorf("ChainRole is set to zero address")
var ErrFeeVaultZeroAddress = fmt.Errorf("chain has a fee vault set to zero address")
var ErrNonStandardValue = fmt.Errorf("chain contains non-standard config value")
var ErrEip1559ZeroValue = fmt.Errorf("eip1559 param is set to zero value")
func (c *ChainIntent) Check() error {
if c.ID == emptyHash {
return fmt.Errorf("id must be set")
}
if err := c.Roles.CheckNoZeroAddresses(); err != nil {
return err
}
if c.Eip1559DenominatorCanyon == 0 ||
c.Eip1559Denominator == 0 ||
c.Eip1559Elasticity == 0 {
return fmt.Errorf("%w: chainId=%s", ErrEip1559ZeroValue, c.ID)
}
if c.BaseFeeVaultRecipient == emptyAddress ||
c.L1FeeVaultRecipient == emptyAddress ||
c.SequencerFeeVaultRecipient == emptyAddress {
return fmt.Errorf("%w: chainId=%s", ErrFeeVaultZeroAddress, c.ID)
}
if c.DangerousAltDAConfig.UseAltDA {
return c.DangerousAltDAConfig.Check(nil)
}
return nil
}
// Returns an error if any fields in ChainRoles is set to common.Address{}
func (cr *ChainRoles) CheckNoZeroAddresses() error {
val := reflect.ValueOf(*cr)
typ := reflect.TypeOf(*cr)
// Iterate through all the fields
for i := 0; i < val.NumField(); i++ {
fieldValue := val.Field(i)
fieldName := typ.Field(i).Name
if fieldValue.Interface() == (common.Address{}) {
return fmt.Errorf("%w: %s", ErrChainRoleZeroAddress, fieldName)
}
}
return nil
}
...@@ -4,8 +4,8 @@ import ( ...@@ -4,8 +4,8 @@ import (
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"net/url"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis" "reflect"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
...@@ -32,63 +32,191 @@ func (d DeploymentStrategy) Check() error { ...@@ -32,63 +32,191 @@ func (d DeploymentStrategy) Check() error {
} }
} }
type IntentConfigType string
const (
IntentConfigTypeStandard IntentConfigType = "standard"
IntentConfigTypeCustom IntentConfigType = "custom"
IntentConfigTypeStrict IntentConfigType = "strict"
IntentConfigTypeStandardOverrides IntentConfigType = "standard-overrides"
IntentConfigTypeStrictOverrides IntentConfigType = "strict-overrides"
)
var emptyAddress common.Address var emptyAddress common.Address
var emptyHash common.Hash
type Intent struct { type Intent struct {
DeploymentStrategy DeploymentStrategy `json:"deploymentStrategy" toml:"deploymentStrategy"` DeploymentStrategy DeploymentStrategy `json:"deploymentStrategy" toml:"deploymentStrategy"`
ConfigType IntentConfigType `json:"configType" toml:"configType"`
L1ChainID uint64 `json:"l1ChainID" toml:"l1ChainID"` L1ChainID uint64 `json:"l1ChainID" toml:"l1ChainID"`
SuperchainRoles *SuperchainRoles `json:"superchainRoles" toml:"superchainRoles,omitempty"` SuperchainRoles *SuperchainRoles `json:"superchainRoles" toml:"superchainRoles,omitempty"`
FundDevAccounts bool `json:"fundDevAccounts" toml:"fundDevAccounts"` FundDevAccounts bool `json:"fundDevAccounts" toml:"fundDevAccounts"`
UseInterop bool `json:"useInterop" toml:"useInterop"` UseInterop bool `json:"useInterop" toml:"useInterop"`
L1ContractsLocator *artifacts.Locator `json:"l1ContractsLocator" toml:"l1ContractsLocator"` L1ContractsLocator *artifacts.Locator `json:"l1ContractsLocator" toml:"l1ContractsLocator"`
L2ContractsLocator *artifacts.Locator `json:"l2ContractsLocator" toml:"l2ContractsLocator"` L2ContractsLocator *artifacts.Locator `json:"l2ContractsLocator" toml:"l2ContractsLocator"`
Chains []*ChainIntent `json:"chains" toml:"chains"` Chains []*ChainIntent `json:"chains" toml:"chains"`
GlobalDeployOverrides map[string]any `json:"globalDeployOverrides" toml:"globalDeployOverrides"` GlobalDeployOverrides map[string]any `json:"globalDeployOverrides" toml:"globalDeployOverrides"`
} }
type SuperchainRoles struct {
ProxyAdminOwner common.Address `json:"proxyAdminOwner" toml:"proxyAdminOwner"`
ProtocolVersionsOwner common.Address `json:"protocolVersionsOwner" toml:"protocolVersionsOwner"`
Guardian common.Address `json:"guardian" toml:"guardian"`
}
var ErrSuperchainRoleZeroAddress = errors.New("SuperchainRole is set to zero address")
var ErrL1ContractsLocatorUndefined = errors.New("L1ContractsLocator undefined")
var ErrL2ContractsLocatorUndefined = errors.New("L2ContractsLocator undefined")
func (s *SuperchainRoles) CheckNoZeroAddresses() error {
val := reflect.ValueOf(*s)
typ := reflect.TypeOf(*s)
// Iterate through all the fields
for i := 0; i < val.NumField(); i++ {
fieldValue := val.Field(i)
fieldName := typ.Field(i).Name
if fieldValue.Interface() == (common.Address{}) {
return fmt.Errorf("%w: %s", ErrSuperchainRoleZeroAddress, fieldName)
}
}
return nil
}
func (c *Intent) L1ChainIDBig() *big.Int { func (c *Intent) L1ChainIDBig() *big.Int {
return big.NewInt(int64(c.L1ChainID)) return big.NewInt(int64(c.L1ChainID))
} }
func (c *Intent) Check() error { func (c *Intent) validateCustomConfig() error {
if c.DeploymentStrategy != DeploymentStrategyLive && c.DeploymentStrategy != DeploymentStrategyGenesis { if c.L1ContractsLocator == nil ||
return fmt.Errorf("deploymentStrategy must be 'live' or 'local'") (c.L1ContractsLocator.Tag == "" && c.L1ContractsLocator.URL == &url.URL{}) {
return ErrL1ContractsLocatorUndefined
}
if c.L2ContractsLocator == nil ||
(c.L2ContractsLocator.Tag == "" && c.L2ContractsLocator.URL == &url.URL{}) {
return ErrL2ContractsLocatorUndefined
} }
if c.L1ChainID == 0 { if err := c.SuperchainRoles.CheckNoZeroAddresses(); err != nil {
return fmt.Errorf("l1ChainID must be set") return err
} }
if c.L1ContractsLocator == nil { if len(c.Chains) == 0 {
return errors.New("l1ContractsLocator must be set") return errors.New("must define at least one l2 chain")
} }
if c.L2ContractsLocator == nil { for _, chain := range c.Chains {
return errors.New("l2ContractsLocator must be set") if err := chain.Check(); err != nil {
return err
}
} }
var err error return nil
if c.L1ContractsLocator.IsTag() { }
err = c.checkL1Prod()
} else { func (c *Intent) validateStrictConfig() error {
err = c.checkL1Dev() if err := c.validateStandardValues(); err != nil {
return err
} }
challenger, _ := standard.ChallengerAddressFor(c.L1ChainID)
l1ProxyAdminOwner, _ := standard.L1ProxyAdminOwner(c.L1ChainID)
for chainIndex := range c.Chains {
if c.Chains[chainIndex].Roles.Challenger != challenger {
return fmt.Errorf("invalid challenger address for chain: %s", c.Chains[chainIndex].ID)
}
if c.Chains[chainIndex].Roles.L1ProxyAdminOwner != l1ProxyAdminOwner {
return fmt.Errorf("invalid l1ProxyAdminOwner address for chain: %s", c.Chains[chainIndex].ID)
}
}
return nil
}
// Ensures the following:
// 1. no zero-values for non-standard fields (user should have populated these)
// 2. no non-standard values for standard fields (user should not have changed these)
func (c *Intent) validateStandardValues() error {
if err := c.checkL1Prod(); err != nil {
return err
}
if err := c.checkL2Prod(); err != nil {
return err
}
standardSuperchainRoles, err := getStandardSuperchainRoles(c.L1ChainID)
if err != nil { if err != nil {
return fmt.Errorf("error getting standard superchain roles: %w", err)
}
if *c.SuperchainRoles != *standardSuperchainRoles {
return fmt.Errorf("SuperchainRoles does not match standard value")
}
for _, chain := range c.Chains {
if err := chain.Check(); err != nil {
return err return err
} }
if chain.Eip1559DenominatorCanyon != standard.Eip1559DenominatorCanyon ||
chain.Eip1559Denominator != standard.Eip1559Denominator ||
chain.Eip1559Elasticity != standard.Eip1559Elasticity {
return fmt.Errorf("%w: chainId=%s", ErrNonStandardValue, chain.ID)
}
}
if c.L2ContractsLocator.IsTag() { return nil
if err := c.checkL2Prod(); err != nil { }
func getStandardSuperchainRoles(l1ChainId uint64) (*SuperchainRoles, error) {
superCfg, err := standard.SuperchainFor(l1ChainId)
if err != nil {
return nil, fmt.Errorf("error getting superchain config: %w", err)
}
proxyAdminOwner, _ := standard.L1ProxyAdminOwner(l1ChainId)
guardian, _ := standard.GuardianAddressFor(l1ChainId)
superchainRoles := &SuperchainRoles{
ProxyAdminOwner: proxyAdminOwner,
ProtocolVersionsOwner: common.Address(*superCfg.Config.ProtocolVersionsAddr),
Guardian: guardian,
}
return superchainRoles, nil
}
func (c *Intent) Check() error {
if c.L1ChainID == 0 {
return fmt.Errorf("l1ChainID cannot be 0")
}
if err := c.DeploymentStrategy.Check(); err != nil {
return err return err
} }
if c.L1ContractsLocator == nil {
return ErrL1ContractsLocatorUndefined
}
if c.L2ContractsLocator == nil {
return ErrL2ContractsLocatorUndefined
}
var err error
switch c.ConfigType {
case IntentConfigTypeStandard:
err = c.validateStandardValues()
case IntentConfigTypeCustom:
err = c.validateCustomConfig()
case IntentConfigTypeStrict:
err = c.validateStrictConfig()
case IntentConfigTypeStandardOverrides, IntentConfigTypeStrictOverrides:
err = c.validateCustomConfig()
default:
return fmt.Errorf("intent-config-type unsupported: %s", c.ConfigType)
}
if err != nil {
return fmt.Errorf("failed to validate intent-config-type=%s: %w", c.ConfigType, err)
} }
return nil return nil
...@@ -121,100 +249,113 @@ func (c *Intent) checkL1Prod() error { ...@@ -121,100 +249,113 @@ func (c *Intent) checkL1Prod() error {
return nil return nil
} }
func (c *Intent) checkL1Dev() error {
if c.SuperchainRoles.ProxyAdminOwner == emptyAddress {
return fmt.Errorf("proxyAdminOwner must be set")
}
if c.SuperchainRoles.ProtocolVersionsOwner == emptyAddress {
c.SuperchainRoles.ProtocolVersionsOwner = c.SuperchainRoles.ProxyAdminOwner
}
if c.SuperchainRoles.Guardian == emptyAddress {
c.SuperchainRoles.Guardian = c.SuperchainRoles.ProxyAdminOwner
}
return nil
}
func (c *Intent) checkL2Prod() error { func (c *Intent) checkL2Prod() error {
_, err := standard.ArtifactsURLForTag(c.L2ContractsLocator.Tag) _, err := standard.ArtifactsURLForTag(c.L2ContractsLocator.Tag)
return err return err
} }
type SuperchainRoles struct { func NewIntent(configType IntentConfigType, deploymentStrategy DeploymentStrategy, l1ChainId uint64, l2ChainIds []common.Hash) (Intent, error) {
ProxyAdminOwner common.Address `json:"proxyAdminOwner" toml:"proxyAdminOwner"` switch configType {
case IntentConfigTypeCustom:
ProtocolVersionsOwner common.Address `json:"protocolVersionsOwner" toml:"protocolVersionsOwner"` return NewIntentCustom(deploymentStrategy, l1ChainId, l2ChainIds)
Guardian common.Address `json:"guardian" toml:"guardian"`
}
type ChainIntent struct {
ID common.Hash `json:"id" toml:"id"`
BaseFeeVaultRecipient common.Address `json:"baseFeeVaultRecipient" toml:"baseFeeVaultRecipient"`
L1FeeVaultRecipient common.Address `json:"l1FeeVaultRecipient" toml:"l1FeeVaultRecipient"`
SequencerFeeVaultRecipient common.Address `json:"sequencerFeeVaultRecipient" toml:"sequencerFeeVaultRecipient"`
Eip1559Denominator uint64 `json:"eip1559Denominator" toml:"eip1559Denominator"` case IntentConfigTypeStandard:
return NewIntentStandard(deploymentStrategy, l1ChainId, l2ChainIds)
Eip1559Elasticity uint64 `json:"eip1559Elasticity" toml:"eip1559Elasticity"` case IntentConfigTypeStandardOverrides:
return NewIntentStandardOverrides(deploymentStrategy, l1ChainId, l2ChainIds)
Roles ChainRoles `json:"roles" toml:"roles"` case IntentConfigTypeStrict:
return NewIntentStrict(deploymentStrategy, l1ChainId, l2ChainIds)
DeployOverrides map[string]any `json:"deployOverrides" toml:"deployOverrides"` case IntentConfigTypeStrictOverrides:
return NewIntentStrictOverrides(deploymentStrategy, l1ChainId, l2ChainIds)
DangerousAltDAConfig genesis.AltDADeployConfig `json:"dangerousAltDAConfig,omitempty" toml:"dangerousAltDAConfig,omitempty"` default:
return Intent{}, fmt.Errorf("intent config type not supported")
}
} }
type ChainRoles struct { // Sets all Intent fields to their zero value with the expectation that the
L1ProxyAdminOwner common.Address `json:"l1ProxyAdminOwner" toml:"l1ProxyAdminOwner"` // user will populate the values before running 'apply'
func NewIntentCustom(deploymentStrategy DeploymentStrategy, l1ChainId uint64, l2ChainIds []common.Hash) (Intent, error) {
L2ProxyAdminOwner common.Address `json:"l2ProxyAdminOwner" toml:"l2ProxyAdminOwner"` intent := Intent{
DeploymentStrategy: deploymentStrategy,
SystemConfigOwner common.Address `json:"systemConfigOwner" toml:"systemConfigOwner"` ConfigType: IntentConfigTypeCustom,
L1ChainID: l1ChainId,
UnsafeBlockSigner common.Address `json:"unsafeBlockSigner" toml:"unsafeBlockSigner"` L1ContractsLocator: &artifacts.Locator{URL: &url.URL{}},
L2ContractsLocator: &artifacts.Locator{URL: &url.URL{}},
Batcher common.Address `json:"batcher" toml:"batcher"` SuperchainRoles: &SuperchainRoles{},
}
Proposer common.Address `json:"proposer" toml:"proposer"`
Challenger common.Address `json:"challenger" toml:"challenger"` for _, l2ChainID := range l2ChainIds {
intent.Chains = append(intent.Chains, &ChainIntent{
ID: l2ChainID,
})
}
return intent, nil
} }
func (c *ChainIntent) Check() error { func NewIntentStandard(deploymentStrategy DeploymentStrategy, l1ChainId uint64, l2ChainIds []common.Hash) (Intent, error) {
var emptyHash common.Hash intent := Intent{
if c.ID == emptyHash { DeploymentStrategy: deploymentStrategy,
return fmt.Errorf("id must be set") ConfigType: IntentConfigTypeStandard,
L1ChainID: l1ChainId,
L1ContractsLocator: artifacts.DefaultL1ContractsLocator,
L2ContractsLocator: artifacts.DefaultL2ContractsLocator,
} }
if c.Roles.L1ProxyAdminOwner == emptyAddress { superchainRoles, err := getStandardSuperchainRoles(l1ChainId)
return fmt.Errorf("proxyAdminOwner must be set") if err != nil {
return Intent{}, fmt.Errorf("error getting standard superchain roles: %w", err)
} }
intent.SuperchainRoles = superchainRoles
if c.Roles.SystemConfigOwner == emptyAddress {
c.Roles.SystemConfigOwner = c.Roles.L1ProxyAdminOwner for _, l2ChainID := range l2ChainIds {
intent.Chains = append(intent.Chains, &ChainIntent{
ID: l2ChainID,
Eip1559DenominatorCanyon: standard.Eip1559DenominatorCanyon,
Eip1559Denominator: standard.Eip1559Denominator,
Eip1559Elasticity: standard.Eip1559Elasticity,
})
} }
return intent, nil
}
if c.Roles.L2ProxyAdminOwner == emptyAddress { func NewIntentStandardOverrides(deploymentStrategy DeploymentStrategy, l1ChainId uint64, l2ChainIds []common.Hash) (Intent, error) {
return fmt.Errorf("l2ProxyAdminOwner must be set") intent, err := NewIntentStandard(deploymentStrategy, l1ChainId, l2ChainIds)
if err != nil {
return Intent{}, err
} }
intent.ConfigType = IntentConfigTypeStandardOverrides
return intent, nil
}
if c.Roles.UnsafeBlockSigner == emptyAddress { // Same as NewIntentStandard, but also sets l2 Challenger and L1ProxyAdminOwner
return fmt.Errorf("unsafeBlockSigner must be set") // addresses to standard values
func NewIntentStrict(deploymentStrategy DeploymentStrategy, l1ChainId uint64, l2ChainIds []common.Hash) (Intent, error) {
intent, err := NewIntentStandard(deploymentStrategy, l1ChainId, l2ChainIds)
if err != nil {
return Intent{}, err
} }
intent.ConfigType = IntentConfigTypeStrict
if c.Roles.Batcher == emptyAddress { challenger, _ := standard.ChallengerAddressFor(l1ChainId)
return fmt.Errorf("batcher must be set") l1ProxyAdminOwner, _ := standard.ManagerOwnerAddrFor(l1ChainId)
for chainIndex := range intent.Chains {
intent.Chains[chainIndex].Roles.Challenger = challenger
intent.Chains[chainIndex].Roles.L1ProxyAdminOwner = l1ProxyAdminOwner
} }
return intent, nil
}
if c.DangerousAltDAConfig.UseAltDA { func NewIntentStrictOverrides(deploymentStrategy DeploymentStrategy, l1ChainId uint64, l2ChainIds []common.Hash) (Intent, error) {
return c.DangerousAltDAConfig.Check(nil) intent, err := NewIntentStrict(deploymentStrategy, l1ChainId, l2ChainIds)
if err != nil {
return Intent{}, err
} }
intent.ConfigType = IntentConfigTypeStrictOverrides
return nil return intent, nil
} }
package state
import (
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
func TestValidateStandardValues(t *testing.T) {
intent, err := NewIntentStandard(DeploymentStrategyLive, 1, []common.Hash{common.HexToHash("0x336")})
require.NoError(t, err)
err = intent.Check()
require.Error(t, err)
require.ErrorIs(t, err, ErrChainRoleZeroAddress)
setChainRoles(&intent)
err = intent.Check()
require.Error(t, err)
require.ErrorIs(t, err, ErrFeeVaultZeroAddress)
setFeeAddresses(&intent)
err = intent.Check()
require.NoError(t, err)
intent.Chains[0].Eip1559Denominator = 3 // set to non-standard value
err = intent.Check()
require.Error(t, err)
require.ErrorIs(t, err, ErrNonStandardValue)
}
func TestValidateCustomValues(t *testing.T) {
intent, err := NewIntentCustom(DeploymentStrategyLive, 1, []common.Hash{common.HexToHash("0x336")})
require.NoError(t, err)
err = intent.Check()
require.Error(t, err)
require.ErrorIs(t, err, ErrSuperchainRoleZeroAddress)
setSuperchainRoles(&intent)
err = intent.Check()
require.Error(t, err)
require.ErrorIs(t, err, ErrChainRoleZeroAddress)
setChainRoles(&intent)
err = intent.Check()
require.Error(t, err)
require.ErrorIs(t, err, ErrEip1559ZeroValue)
setEip1559Params(&intent)
err = intent.Check()
require.Error(t, err)
require.ErrorIs(t, err, ErrFeeVaultZeroAddress)
setFeeAddresses(&intent)
err = intent.Check()
require.NoError(t, err)
}
func setSuperchainRoles(intent *Intent) {
intent.SuperchainRoles = &SuperchainRoles{
ProxyAdminOwner: common.HexToAddress("0xa"),
ProtocolVersionsOwner: common.HexToAddress("0xb"),
Guardian: common.HexToAddress("0xc"),
}
}
func setEip1559Params(intent *Intent) {
intent.Chains[0].Eip1559Denominator = 5000
intent.Chains[0].Eip1559DenominatorCanyon = 5000
intent.Chains[0].Eip1559Elasticity = 5000
}
func setChainRoles(intent *Intent) {
intent.Chains[0].Roles.L1ProxyAdminOwner = common.HexToAddress("0x01")
intent.Chains[0].Roles.L2ProxyAdminOwner = common.HexToAddress("0x02")
intent.Chains[0].Roles.SystemConfigOwner = common.HexToAddress("0x03")
intent.Chains[0].Roles.UnsafeBlockSigner = common.HexToAddress("0x04")
intent.Chains[0].Roles.Batcher = common.HexToAddress("0x05")
intent.Chains[0].Roles.Proposer = common.HexToAddress("0x06")
intent.Chains[0].Roles.Challenger = common.HexToAddress("0x07")
}
func setFeeAddresses(intent *Intent) {
intent.Chains[0].BaseFeeVaultRecipient = common.HexToAddress("0x08")
intent.Chains[0].L1FeeVaultRecipient = common.HexToAddress("0x09")
intent.Chains[0].SequencerFeeVaultRecipient = common.HexToAddress("0x0A")
}
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