Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanups for production, add standard addresses #12169

Merged
merged 16 commits into from
Sep 27, 2024
7 changes: 7 additions & 0 deletions op-chain-ops/cmd/op-deployer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"os"

"github.com/ethereum-optimism/optimism/op-chain-ops/deployer/bootstrap"

"github.com/ethereum-optimism/optimism/op-chain-ops/deployer/version"
opservice "github.com/ethereum-optimism/optimism/op-service"

Expand Down Expand Up @@ -41,6 +43,11 @@ func main() {
Flags: cliapp.ProtectFlags(deployer.ApplyFlags),
Action: deployer.ApplyCLI(),
},
{
Name: "bootstrap",
Usage: "bootstraps global contract instances",
Subcommands: bootstrap.Commands,
},
{
Name: "inspect",
Usage: "inspects the state of a deployment",
Expand Down
206 changes: 206 additions & 0 deletions op-chain-ops/deployer/bootstrap/bootstrap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
package bootstrap

import (
"context"
"crypto/ecdsa"
"crypto/rand"
"fmt"
"math/big"
"strings"

"github.com/ethereum-optimism/optimism/op-chain-ops/deployer"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer/opcm"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer/pipeline"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer/state"
"github.com/ethereum-optimism/optimism/op-chain-ops/script"
opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
"github.com/ethereum-optimism/optimism/op-service/ctxinterrupt"
"github.com/ethereum-optimism/optimism/op-service/ioutil"
"github.com/ethereum-optimism/optimism/op-service/jsonutil"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"
)

type OPCMConfig struct {
L1RPCUrl string
PrivateKey string
Logger log.Logger
ArtifactsURL *state.ArtifactsURL
ContractsRelease string

privateKeyECDSA *ecdsa.PrivateKey
}

func (c *OPCMConfig) Check() error {
if c.L1RPCUrl == "" {
return fmt.Errorf("l1RPCUrl must be specified")
}

if c.PrivateKey == "" {
return fmt.Errorf("private key must be specified")
}

privECDSA, err := crypto.HexToECDSA(strings.TrimPrefix(c.PrivateKey, "0x"))
if err != nil {
return fmt.Errorf("failed to parse private key: %w", err)
}
c.privateKeyECDSA = privECDSA

if c.Logger == nil {
return fmt.Errorf("logger must be specified")
}

if c.ArtifactsURL == nil {
return fmt.Errorf("artifacts URL must be specified")
}

if c.ContractsRelease == "" {
return fmt.Errorf("contracts release must be specified")
}

return nil
}

func OPCMCLI(cliCtx *cli.Context) error {
logCfg := oplog.ReadCLIConfig(cliCtx)
l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg)
oplog.SetGlobalLogHandler(l.Handler())

l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName)
privateKey := cliCtx.String(deployer.PrivateKeyFlagName)
artifactsURLStr := cliCtx.String(ArtifactsURLFlagName)
artifactsURL := new(state.ArtifactsURL)
if err := artifactsURL.UnmarshalText([]byte(artifactsURLStr)); err != nil {
return fmt.Errorf("failed to parse artifacts URL: %w", err)
}
contractsRelease := cliCtx.String(ContractsReleaseFlagName)

ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context)

return OPCM(ctx, OPCMConfig{
L1RPCUrl: l1RPCUrl,
PrivateKey: privateKey,
Logger: l,
ArtifactsURL: artifactsURL,
ContractsRelease: contractsRelease,
})
}

func OPCM(ctx context.Context, cfg OPCMConfig) error {
if err := cfg.Check(); err != nil {
return fmt.Errorf("invalid config for OPCM: %w", err)
}

lgr := cfg.Logger
progressor := func(curr, total int64) {
lgr.Info("artifacts download progress", "current", curr, "total", total)
}

artifactsFS, cleanup, err := pipeline.DownloadArtifacts(ctx, cfg.ArtifactsURL, progressor)
if err != nil {
return fmt.Errorf("failed to download artifacts: %w", err)
}
defer func() {
if err := cleanup(); err != nil {
lgr.Warn("failed to clean up artifacts", "err", err)
}
}()

l1Client, err := ethclient.Dial(cfg.L1RPCUrl)
if err != nil {
return fmt.Errorf("failed to connect to L1 RPC: %w", err)
}

chainID, err := l1Client.ChainID(ctx)
if err != nil {
return fmt.Errorf("failed to get chain ID: %w", err)
}
chainIDU64 := chainID.Uint64()

superCfg, err := opcm.SuperchainFor(chainIDU64)
if err != nil {
return fmt.Errorf("error getting superchain config: %w", err)
}
standardVersionsTOML, err := opcm.StandardVersionsFor(chainIDU64)
if err != nil {
return fmt.Errorf("error getting standard versions TOML: %w", err)
}
opcmProxyOwnerAddr, err := opcm.ManagerOwnerAddrFor(chainIDU64)
if err != nil {
return fmt.Errorf("error getting superchain proxy admin: %w", err)
}

signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(cfg.privateKeyECDSA, chainID))
chainDeployer := crypto.PubkeyToAddress(cfg.privateKeyECDSA.PublicKey)

lgr.Info("deploying OPCM", "release", cfg.ContractsRelease)

var dio opcm.DeployImplementationsOutput
err = pipeline.CallScriptBroadcast(
ctx,
pipeline.CallScriptBroadcastOpts{
L1ChainID: chainID,
Logger: lgr,
ArtifactsFS: artifactsFS,
Deployer: chainDeployer,
Signer: signer,
Client: l1Client,
Broadcaster: pipeline.KeyedBroadcaster,
Handler: func(host *script.Host) error {
// We need to etch the Superchain addresses so that they have nonzero code
// and the checks in the OPCM constructor pass.
superchainConfigAddr := common.Address(*superCfg.Config.SuperchainConfigAddr)
protocolVersionsAddr := common.Address(*superCfg.Config.ProtocolVersionsAddr)
addresses := []common.Address{
superchainConfigAddr,
protocolVersionsAddr,
}
for _, addr := range addresses {
host.ImportAccount(addr, types.Account{
Code: []byte{0x00},
})
}

var salt common.Hash
_, err = rand.Read(salt[:])
if err != nil {
return fmt.Errorf("failed to generate CREATE2 salt: %w", err)
}

dio, err = opcm.DeployImplementations(
host,
opcm.DeployImplementationsInput{
Salt: salt,
WithdrawalDelaySeconds: big.NewInt(604800),
MinProposalSizeBytes: big.NewInt(126000),
ChallengePeriodSeconds: big.NewInt(86400),
ProofMaturityDelaySeconds: big.NewInt(604800),
DisputeGameFinalityDelaySeconds: big.NewInt(302400),
Release: cfg.ContractsRelease,
SuperchainConfigProxy: superchainConfigAddr,
ProtocolVersionsProxy: protocolVersionsAddr,
OpcmProxyOwner: opcmProxyOwnerAddr,
StandardVersionsToml: standardVersionsTOML,
UseInterop: false,
mslipper marked this conversation as resolved.
Show resolved Hide resolved
},
)
return err
},
},
)
if err != nil {
return fmt.Errorf("error deploying implementations: %w", err)
}

lgr.Info("deployed implementations")

if err := jsonutil.WriteJSON(dio, ioutil.ToStdOut()); err != nil {
return fmt.Errorf("failed to write output: %w", err)
}
return nil
}
41 changes: 41 additions & 0 deletions op-chain-ops/deployer/bootstrap/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package bootstrap

import (
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer"
"github.com/ethereum-optimism/optimism/op-service/cliapp"
"github.com/urfave/cli/v2"
)

const (
ArtifactsURLFlagName = "artifacts-url"
ContractsReleaseFlagName = "contracts-release"
)

var (
ArtifactsURLFlag = &cli.StringFlag{
Name: ArtifactsURLFlagName,
Usage: "URL to the artifacts directory.",
EnvVars: deployer.PrefixEnvVar("ARTIFACTS_URL"),
}
ContractsReleaseFlag = &cli.StringFlag{
Name: ContractsReleaseFlagName,
Usage: "Release of the contracts to deploy.",
EnvVars: deployer.PrefixEnvVar("CONTRACTS_RELEASE"),
}
)

var OPCMFlags = []cli.Flag{
deployer.L1RPCURLFlag,
deployer.PrivateKeyFlag,
ArtifactsURLFlag,
ContractsReleaseFlag,
}

var Commands = []*cli.Command{
{
Name: "opcm",
Usage: "Bootstrap an instance of OPCM.",
Flags: cliapp.ProtectFlags(OPCMFlags),
Action: OPCMCLI,
},
}
2 changes: 1 addition & 1 deletion op-chain-ops/deployer/broadcaster/keyed.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func NewKeyedBroadcaster(cfg KeyedBroadcasterOpts) (*KeyedBroadcaster, error) {
mgrCfg.FeeLimitMultiplier.Store(5)
mgrCfg.FeeLimitThreshold.Store(big.NewInt(100))
mgrCfg.MinTipCap.Store(minTipCap)
mgrCfg.MinTipCap.Store(minBaseFee)
mgrCfg.MinBaseFee.Store(minBaseFee)

txmLogger := log.NewLogger(log.DiscardHandler())
if cfg.TXManagerLogger != nil {
Expand Down
11 changes: 5 additions & 6 deletions op-chain-ops/deployer/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,27 @@ var (
L1ChainIDFlag = &cli.Uint64Flag{
Name: L1ChainIDFlagName,
Usage: "Chain ID of the L1 chain.",
EnvVars: prefixEnvVar("L1_CHAIN_ID"),
EnvVars: PrefixEnvVar("L1_CHAIN_ID"),
Value: 900,
}
L2ChainIDsFlag = &cli.StringFlag{
Name: L2ChainIDsFlagName,
Usage: "Comma-separated list of L2 chain IDs to deploy.",
EnvVars: prefixEnvVar("L2_CHAIN_IDS"),
EnvVars: PrefixEnvVar("L2_CHAIN_IDS"),
}
WorkdirFlag = &cli.StringFlag{
Name: WorkdirFlagName,
Usage: "Directory storing intent and stage. Defaults to the current directory.",
EnvVars: prefixEnvVar("WORKDIR"),
EnvVars: PrefixEnvVar("WORKDIR"),
Value: cwd(),
Aliases: []string{
OutdirFlagName,
},
}

PrivateKeyFlag = &cli.StringFlag{
Name: PrivateKeyFlagName,
Usage: "Private key of the deployer account.",
EnvVars: prefixEnvVar("PRIVATE_KEY"),
EnvVars: PrefixEnvVar("PRIVATE_KEY"),
}
)

Expand All @@ -69,7 +68,7 @@ var ApplyFlags = []cli.Flag{
PrivateKeyFlag,
}

func prefixEnvVar(name string) []string {
func PrefixEnvVar(name string) []string {
return op_service.PrefixEnvVar(EnvVarPrefix, name)
}

Expand Down
5 changes: 2 additions & 3 deletions op-chain-ops/deployer/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ func InitCLI() func(ctx *cli.Context) error {
outdir := ctx.String(OutdirFlagName)

l2ChainIDsRaw := ctx.String(L2ChainIDsFlagName)
l2ChainIDsStr := strings.Split(l2ChainIDsRaw, ",")
l2ChainIDs := make([]common.Hash, 0, len(l2ChainIDsStr))
l2ChainIDsStr := strings.Split(strings.TrimSpace(l2ChainIDsRaw), ",")
l2ChainIDs := make([]common.Hash, len(l2ChainIDsStr))
for _, idStr := range l2ChainIDsStr {
id, err := op_service.Parse256BitChainID(idStr)
if err != nil {
Expand All @@ -66,7 +66,6 @@ func Init(cfg InitConfig) error {

intent := &state.Intent{
L1ChainID: cfg.L1ChainID,
UseFaultProofs: true,
FundDevAccounts: true,
ContractsRelease: "dev",
}
Expand Down
2 changes: 0 additions & 2 deletions op-chain-ops/deployer/integration_test/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ func makeIntent(
ProtocolVersionsOwner: addrFor(devkeys.SuperchainDeployerKey.Key(l1ChainID)),
Guardian: addrFor(devkeys.SuperchainConfigGuardianKey.Key(l1ChainID)),
},
UseFaultProofs: true,
FundDevAccounts: true,
ContractArtifactsURL: (*state.ArtifactsURL)(artifactsURL),
ContractsRelease: "dev",
Expand Down Expand Up @@ -239,7 +238,6 @@ func validateOPChainDeployment(t *testing.T, ctx context.Context, l1Client *ethc
{"OptimismPortalProxyAddress", chainState.OptimismPortalProxyAddress},
{"DisputeGameFactoryProxyAddress", chainState.DisputeGameFactoryProxyAddress},
{"AnchorStateRegistryProxyAddress", chainState.AnchorStateRegistryProxyAddress},
{"AnchorStateRegistryImplAddress", chainState.AnchorStateRegistryImplAddress},
{"FaultDisputeGameAddress", chainState.FaultDisputeGameAddress},
{"PermissionedDisputeGameAddress", chainState.PermissionedDisputeGameAddress},
{"DelayedWETHPermissionedGameProxyAddress", chainState.DelayedWETHPermissionedGameProxyAddress},
Expand Down
2 changes: 1 addition & 1 deletion op-chain-ops/deployer/opcm/implementations.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type DeployImplementationsInput struct {
ProtocolVersionsProxy common.Address
UseInterop bool // if true, deploy Interop implementations

SuperchainProxyAdmin common.Address
OpcmProxyOwner common.Address
StandardVersionsToml string // contents of 'standard-versions-mainnet.toml' or 'standard-versions-sepolia.toml' file
}

Expand Down
2 changes: 2 additions & 0 deletions op-chain-ops/deployer/opcm/opchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ type opcmDeployInput struct {
BlobBasefeeScalar uint32
L2ChainId *big.Int
StartingAnchorRoots []byte
SaltMixer string
}

// decodeOutputABIJSON defines an ABI for a fake method called "decodeOutput" that returns the
Expand Down Expand Up @@ -241,6 +242,7 @@ func DeployOPChainRaw(
BlobBasefeeScalar: input.BlobBaseFeeScalar,
L2ChainId: input.L2ChainId,
StartingAnchorRoots: input.StartingAnchorRoots(),
SaltMixer: input.SaltMixer,
})
if err != nil {
return out, fmt.Errorf("failed to pack deploy input: %w", err)
Expand Down
Loading
Loading