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)),
......
...@@ -141,10 +141,10 @@ func displayWarning() error { ...@@ -141,10 +141,10 @@ func displayWarning() error {
####################### WARNING! WARNING WARNING! ####################### ####################### WARNING! WARNING WARNING! #######################
You are deploying a tagged release to a chain with no pre-deployed OPCM. You are deploying a tagged release to a chain with no pre-deployed OPCM.
The contracts you are deploying may not be audited, or match a governance The contracts you are deploying may not be audited, or match a governance
approved release. approved release.
USE OF THIS DEPLOYMENT IS NOT RECOMMENDED FOR PRODUCTION. USE AT YOUR OWN USE OF THIS DEPLOYMENT IS NOT RECOMMENDED FOR PRODUCTION. USE AT YOUR OWN
RISK. BUGS OR LOSS OF FUNDS MAY OCCUR. WE HOPE YOU KNOW WHAT YOU ARE RISK. BUGS OR LOSS OF FUNDS MAY OCCUR. WE HOPE YOU KNOW WHAT YOU ARE
DOING. DOING.
......
...@@ -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"`
SuperchainRoles *SuperchainRoles `json:"superchainRoles" toml:"superchainRoles,omitempty"`
FundDevAccounts bool `json:"fundDevAccounts" toml:"fundDevAccounts"`
UseInterop bool `json:"useInterop" toml:"useInterop"`
L1ContractsLocator *artifacts.Locator `json:"l1ContractsLocator" toml:"l1ContractsLocator"`
L2ContractsLocator *artifacts.Locator `json:"l2ContractsLocator" toml:"l2ContractsLocator"`
Chains []*ChainIntent `json:"chains" toml:"chains"`
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")
L1ChainID uint64 `json:"l1ChainID" toml:"l1ChainID"` func (s *SuperchainRoles) CheckNoZeroAddresses() error {
val := reflect.ValueOf(*s)
typ := reflect.TypeOf(*s)
SuperchainRoles *SuperchainRoles `json:"superchainRoles" toml:"superchainRoles,omitempty"` // 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
}
FundDevAccounts bool `json:"fundDevAccounts" toml:"fundDevAccounts"` func (c *Intent) L1ChainIDBig() *big.Int {
return big.NewInt(int64(c.L1ChainID))
}
UseInterop bool `json:"useInterop" toml:"useInterop"` func (c *Intent) validateCustomConfig() error {
if c.L1ContractsLocator == nil ||
(c.L1ContractsLocator.Tag == "" && c.L1ContractsLocator.URL == &url.URL{}) {
return ErrL1ContractsLocatorUndefined
}
if c.L2ContractsLocator == nil ||
(c.L2ContractsLocator.Tag == "" && c.L2ContractsLocator.URL == &url.URL{}) {
return ErrL2ContractsLocatorUndefined
}
L1ContractsLocator *artifacts.Locator `json:"l1ContractsLocator" toml:"l1ContractsLocator"` if err := c.SuperchainRoles.CheckNoZeroAddresses(); err != nil {
return err
}
L2ContractsLocator *artifacts.Locator `json:"l2ContractsLocator" toml:"l2ContractsLocator"` if len(c.Chains) == 0 {
return errors.New("must define at least one l2 chain")
}
Chains []*ChainIntent `json:"chains" toml:"chains"` for _, chain := range c.Chains {
if err := chain.Check(); err != nil {
return err
}
}
GlobalDeployOverrides map[string]any `json:"globalDeployOverrides" toml:"globalDeployOverrides"` return nil
} }
func (c *Intent) L1ChainIDBig() *big.Int { func (c *Intent) validateStrictConfig() error {
return big.NewInt(int64(c.L1ChainID)) 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
} }
func (c *Intent) Check() error { // Ensures the following:
if c.DeploymentStrategy != DeploymentStrategyLive && c.DeploymentStrategy != DeploymentStrategyGenesis { // 1. no zero-values for non-standard fields (user should have populated these)
return fmt.Errorf("deploymentStrategy must be 'live' or 'local'") // 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 {
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
}
if chain.Eip1559DenominatorCanyon != standard.Eip1559DenominatorCanyon ||
chain.Eip1559Denominator != standard.Eip1559Denominator ||
chain.Eip1559Elasticity != standard.Eip1559Elasticity {
return fmt.Errorf("%w: chainId=%s", ErrNonStandardValue, chain.ID)
}
}
return 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 { if c.L1ChainID == 0 {
return fmt.Errorf("l1ChainID must be set") return fmt.Errorf("l1ChainID cannot be 0")
}
if err := c.DeploymentStrategy.Check(); err != nil {
return err
} }
if c.L1ContractsLocator == nil { if c.L1ContractsLocator == nil {
return errors.New("l1ContractsLocator must be set") return ErrL1ContractsLocatorUndefined
} }
if c.L2ContractsLocator == nil { if c.L2ContractsLocator == nil {
return errors.New("l2ContractsLocator must be set") return ErrL2ContractsLocatorUndefined
} }
var err error var err error
if c.L1ContractsLocator.IsTag() { switch c.ConfigType {
err = c.checkL1Prod() case IntentConfigTypeStandard:
} else { err = c.validateStandardValues()
err = c.checkL1Dev() 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 { if err != nil {
return err return fmt.Errorf("failed to validate intent-config-type=%s: %w", c.ConfigType, err)
}
if c.L2ContractsLocator.IsTag() {
if err := c.checkL2Prod(); err != nil {
return 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"` case IntentConfigTypeStandard:
return NewIntentStandard(deploymentStrategy, l1ChainId, l2ChainIds)
Eip1559Denominator uint64 `json:"eip1559Denominator" toml:"eip1559Denominator"` case IntentConfigTypeStandardOverrides:
return NewIntentStandardOverrides(deploymentStrategy, l1ChainId, l2ChainIds)
Eip1559Elasticity uint64 `json:"eip1559Elasticity" toml:"eip1559Elasticity"` case IntentConfigTypeStrict:
return NewIntentStrict(deploymentStrategy, l1ChainId, l2ChainIds)
Roles ChainRoles `json:"roles" toml:"roles"` case IntentConfigTypeStrictOverrides:
return NewIntentStrictOverrides(deploymentStrategy, l1ChainId, l2ChainIds)
DeployOverrides map[string]any `json:"deployOverrides" toml:"deployOverrides"` default:
return Intent{}, fmt.Errorf("intent config type not supported")
DangerousAltDAConfig genesis.AltDADeployConfig `json:"dangerousAltDAConfig,omitempty" toml:"dangerousAltDAConfig,omitempty"` }
} }
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
if c.Roles.UnsafeBlockSigner == emptyAddress { return intent, nil
return fmt.Errorf("unsafeBlockSigner must be set") }
// Same as NewIntentStandard, but also sets l2 Challenger and L1ProxyAdminOwner
// 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