From 5a366f007dfe1ef9d54f8492ba0b49f4745984d9 Mon Sep 17 00:00:00 2001 From: blockchaindevsh Date: Mon, 13 Jan 2025 16:38:05 +0800 Subject: [PATCH 1/5] init --- .../deploy/UpgradeAnchorStateRegistry.s.sol | 261 ++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 packages/contracts-bedrock/scripts/deploy/UpgradeAnchorStateRegistry.s.sol diff --git a/packages/contracts-bedrock/scripts/deploy/UpgradeAnchorStateRegistry.s.sol b/packages/contracts-bedrock/scripts/deploy/UpgradeAnchorStateRegistry.s.sol new file mode 100644 index 000000000000..e2afb940b1ce --- /dev/null +++ b/packages/contracts-bedrock/scripts/deploy/UpgradeAnchorStateRegistry.s.sol @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +// Forge +import {Script} from "forge-std/Script.sol"; + +// Scripts +import {BaseDeployIO} from "scripts/deploy/BaseDeployIO.sol"; +import {DeployUtils} from "scripts/libraries/DeployUtils.sol"; + +// Libraries +import {GameType, Hash} from "src/dispute/lib/Types.sol"; +// Contracts +import {StorageSetter} from "src/universal/StorageSetter.sol"; + +// Interfaces +import {IAnchorStateRegistry} from "interfaces/dispute/IAnchorStateRegistry.sol"; +import {IDisputeGameFactory} from "interfaces/dispute/IDisputeGameFactory.sol"; +import {IAnchorStateRegistry} from "interfaces/dispute/IAnchorStateRegistry.sol"; +import {IProxyAdmin} from "interfaces/universal/IProxyAdmin.sol"; +import {ISuperchainConfig} from "interfaces/L1/ISuperchainConfig.sol"; + +/// @title UpgradeAnchorStateRegistryInput +contract UpgradeAnchorStateRegistryInput is BaseDeployIO { + IDisputeGameFactory _disputeGameFactoryProxy; + IProxyAdmin internal _opChainProxyAdmin; + IAnchorStateRegistry internal _anchorStateRegistryProxy; + ISuperchainConfig internal _superchainConfig; + bytes internal _startingAnchorRoots; + + function set(bytes4 _sel, address _value) public { + if (_sel == this.disputeGameFactoryProxy.selector) { + require( + _value != address(0), + "UpgradeAnchorStateRegistryInput: disputeGameFactoryProxy cannot be zero address" + ); + _disputeGameFactoryProxy = IDisputeGameFactory(_value); + } else if (_sel == this.opChainProxyAdmin.selector) { + require( + _value != address(0), + "UpgradeAnchorStateRegistryInput: opChainProxyAdmin cannot be zero address" + ); + _opChainProxyAdmin = IProxyAdmin(_value); + } else if (_sel == this.anchorStateRegistryProxy.selector) { + require( + _value != address(0), + "UpgradeAnchorStateRegistryInput: anchorStateRegistryProxy cannot be zero address" + ); + _anchorStateRegistryProxy = IAnchorStateRegistry(_value); + } else if (_sel == this.superchainConfig.selector) { + require( + _value != address(0), + "UpgradeAnchorStateRegistryInput: superchainConfig cannot be zero address" + ); + _superchainConfig = ISuperchainConfig(_value); + } else { + revert( + "UpgradeAnchorStateRegistryInput: unknown selector for address" + ); + } + } + + function set(bytes4 _sel, bytes memory _value) public { + if (_sel == this.startingAnchorRoots.selector) { + require( + _value.length > 0, + "UpgradeAnchorStateRegistryInput: startingAnchorRoots cannot be empty bytes" + ); + _startingAnchorRoots = _value; + } else { + revert( + "UpgradeAnchorStateRegistryInput: unknown selector for bytes" + ); + } + } + + function opChainProxyAdmin() public view returns (IProxyAdmin) { + DeployUtils.assertValidContractAddress(address(_opChainProxyAdmin)); + return _opChainProxyAdmin; + } + + function disputeGameFactoryProxy() + public + view + returns (IDisputeGameFactory) + { + DeployUtils.assertValidContractAddress( + address(_disputeGameFactoryProxy) + ); + return _disputeGameFactoryProxy; + } + + function anchorStateRegistryProxy() public view returns (address) { + DeployUtils.assertValidContractAddress( + address(_anchorStateRegistryProxy) + ); + return address(_anchorStateRegistryProxy); + } + + function superchainConfig() public view returns (ISuperchainConfig) { + DeployUtils.assertValidContractAddress(address(_superchainConfig)); + return _superchainConfig; + } + + function startingAnchorRoots() public view returns (bytes memory) { + require( + _startingAnchorRoots.length > 0, + "UpgradeAnchorStateRegistryInput: startingAnchorRoots not set" + ); + return _startingAnchorRoots; + } +} + +/// @title UpgradeAnchorStateRegistryOutput +contract UpgradeAnchorStateRegistryOutput is BaseDeployIO { + IAnchorStateRegistry internal _anchorStateRegistryImpl; + StorageSetter internal _storageSetter; + + function set(bytes4 _sel, address _value) public { + if (_sel == this.anchorStateRegistryImpl.selector) { + require( + _value != address(0), + "UpgradeAnchorStateRegistryOutput: anchorStateRegistryImpl cannot be zero address" + ); + _anchorStateRegistryImpl = IAnchorStateRegistry(_value); + } else if (_sel == this.storageSetter.selector) { + require( + _value != address(0), + "UpgradeAnchorStateRegistryOutput: storageSetter cannot be zero address" + ); + _storageSetter = StorageSetter(_value); + } else { + revert("UpgradeAnchorStateRegistryOutput: unknown selector"); + } + } + + function anchorStateRegistryImpl() public view returns (address) { + DeployUtils.assertValidContractAddress( + address(_anchorStateRegistryImpl) + ); + return address(_anchorStateRegistryImpl); + } + + function storageSetter() public view returns (address) { + DeployUtils.assertValidContractAddress(address(_storageSetter)); + return address(_storageSetter); + } + function checkOutput(UpgradeAnchorStateRegistryInput _input) public view { + IAnchorStateRegistry.StartingAnchorRoot[] + memory startingAnchorRoots = abi.decode( + _input.startingAnchorRoots(), + (IAnchorStateRegistry.StartingAnchorRoot[]) + ); + (Hash root, uint256 l2BlockNumber) = IAnchorStateRegistry( + _input.anchorStateRegistryProxy() + ).anchors(startingAnchorRoots[0].gameType); + require( + Hash.unwrap(root) == + Hash.unwrap(startingAnchorRoots[0].outputRoot.root), + "UpgradeAnchorStateRegistryOutput: root mismatch" + ); + require( + l2BlockNumber == startingAnchorRoots[0].outputRoot.l2BlockNumber, + "UpgradeAnchorStateRegistryOutput: l2BlockNumber mismatch" + ); + } +} + +/// @title UpgradeAnchorStateRegistry +contract UpgradeAnchorStateRegistry is Script { + function run( + UpgradeAnchorStateRegistryInput _input, + UpgradeAnchorStateRegistryOutput _output + ) public { + upgradeAnchorStateRegistryImpl(_input, _output); + _output.checkOutput(_input); + } + + function upgradeAnchorStateRegistryImpl( + UpgradeAnchorStateRegistryInput _input, + UpgradeAnchorStateRegistryOutput _output + ) internal { + _output.set( + _output.anchorStateRegistryImpl.selector, + DeployUtils.create1({ + _name: "AnchorStateRegistry", + _args: abi.encode(_input.disputeGameFactoryProxy()) + }) + ); + + _output.set( + _output.storageSetter.selector, + DeployUtils.create1({_name: "StorageSetter", _args: ""}) + ); + + bytes memory data; + data = encodeStorageSetterZeroOutInitializedSlot(); + upgradeAndCall( + _input.opChainProxyAdmin(), + _input.anchorStateRegistryProxy(), + _output.storageSetter(), + data + ); + data = encodeAnchorStateRegistryInitializer(_input); + upgradeAndCall( + _input.opChainProxyAdmin(), + _input.anchorStateRegistryProxy(), + _output.anchorStateRegistryImpl(), + data + ); + } + + function encodeStorageSetterZeroOutInitializedSlot() + internal + pure + returns (bytes memory) + { + return + abi.encodeWithSelector( + bytes4(keccak256("setBytes32(bytes32,bytes32)")), + 0, + 0 + ); + } + + function encodeAnchorStateRegistryInitializer( + UpgradeAnchorStateRegistryInput _input + ) internal view virtual returns (bytes memory) { + // this line fails in the op-deployer tests because it is not passing in any data + IAnchorStateRegistry.StartingAnchorRoot[] + memory startingAnchorRoots = abi.decode( + _input.startingAnchorRoots(), + (IAnchorStateRegistry.StartingAnchorRoot[]) + ); + return + abi.encodeWithSelector( + IAnchorStateRegistry.initialize.selector, + startingAnchorRoots, + _input.superchainConfig() + ); + } + + /// @notice Makes an external call to the target to initialize the proxy with the specified data. + /// First performs safety checks to ensure the target, implementation, and proxy admin are valid. + function upgradeAndCall( + IProxyAdmin _proxyAdmin, + address _target, + address _implementation, + bytes memory _data + ) internal { + DeployUtils.assertValidContractAddress(address(_proxyAdmin)); + DeployUtils.assertValidContractAddress(_target); + DeployUtils.assertValidContractAddress(_implementation); + + _proxyAdmin.upgradeAndCall( + payable(address(_target)), + _implementation, + _data + ); + } +} From 650f2552f9b2052f9b30cf3fcc87c6066dcc3404 Mon Sep 17 00:00:00 2001 From: blockchaindevsh Date: Mon, 13 Jan 2025 22:54:46 +0800 Subject: [PATCH 2/5] op-deployer integration --- op-deployer/cmd/op-deployer/main.go | 6 + op-deployer/pkg/deployer/opcm/upgrade_asr.go | 44 +++++ op-deployer/pkg/deployer/upgrade/asr.go | 174 +++++++++++++++++++ op-deployer/pkg/deployer/upgrade/flags.go | 24 +++ 4 files changed, 248 insertions(+) create mode 100644 op-deployer/pkg/deployer/opcm/upgrade_asr.go create mode 100644 op-deployer/pkg/deployer/upgrade/asr.go create mode 100644 op-deployer/pkg/deployer/upgrade/flags.go diff --git a/op-deployer/cmd/op-deployer/main.go b/op-deployer/cmd/op-deployer/main.go index 6c3b1fa0807d..b67bac2b2bbe 100644 --- a/op-deployer/cmd/op-deployer/main.go +++ b/op-deployer/cmd/op-deployer/main.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/bootstrap" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/inspect" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/upgrade" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/version" opservice "github.com/ethereum-optimism/optimism/op-service" @@ -52,6 +53,11 @@ func main() { Usage: "inspects the state of a deployment", Subcommands: inspect.Commands, }, + { + Name: "upgrade", + Usage: "upgrade contracts", + Subcommands: upgrade.Commands, + }, } app.Writer = os.Stdout app.ErrWriter = os.Stderr diff --git a/op-deployer/pkg/deployer/opcm/upgrade_asr.go b/op-deployer/pkg/deployer/opcm/upgrade_asr.go new file mode 100644 index 000000000000..74dcfb6c668c --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/upgrade_asr.go @@ -0,0 +1,44 @@ +package opcm + +import ( + "github.com/ethereum/go-ethereum/common" + + "github.com/ethereum-optimism/optimism/op-chain-ops/script" +) + +type UpgradeAnchorStateRegistryInput struct { + Release string + StandardVersionsToml string + VmAddress common.Address + GameKind string + GameType uint32 + AbsolutePrestate common.Hash + MaxGameDepth uint64 + SplitDepth uint64 + ClockExtension uint64 + MaxClockDuration uint64 + DelayedWethProxy common.Address + AnchorStateRegistryProxy common.Address + L2ChainId uint64 + Proposer common.Address + Challenger common.Address +} + +func (input *UpgradeAnchorStateRegistryInput) InputSet() bool { + return true +} + +type UpgradeAnchorStateRegistryOutput struct { + DisputeGameImpl common.Address +} + +func (output *UpgradeAnchorStateRegistryOutput) CheckOutput(input common.Address) error { + return nil +} + +func UpgradeAnchorStateRegistry( + host *script.Host, + input UpgradeAnchorStateRegistryInput, +) (UpgradeAnchorStateRegistryOutput, error) { + return RunBasicScript[UpgradeAnchorStateRegistryInput, UpgradeAnchorStateRegistryOutput](host, input, "UpgradeAnchorStateRegistry.s.sol", "UpgradeAnchorStateRegistry") +} diff --git a/op-deployer/pkg/deployer/upgrade/asr.go b/op-deployer/pkg/deployer/upgrade/asr.go new file mode 100644 index 000000000000..9f0956591fca --- /dev/null +++ b/op-deployer/pkg/deployer/upgrade/asr.go @@ -0,0 +1,174 @@ +package upgrade + +import ( + "context" + "crypto/ecdsa" + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/rpc" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/bootstrap" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/pipeline" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + 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/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + "github.com/urfave/cli/v2" +) + +type ASRConfig struct { + L1RPCUrl string + Workdir string + PrivateKey string + Logger log.Logger + ArtifactsLocator *artifacts.Locator + + privateKeyECDSA *ecdsa.PrivateKey +} + +func (a *ASRConfig) Check() error { + if a.L1RPCUrl == "" { + return fmt.Errorf("l1-rpc-url must be specified") + } + if a.Workdir == "" { + return fmt.Errorf("workdir must be specified") + } + + if a.PrivateKey != "" { + privECDSA, err := crypto.HexToECDSA(strings.TrimPrefix(a.PrivateKey, "0x")) + if err != nil { + return fmt.Errorf("failed to parse private key: %w", err) + } + a.privateKeyECDSA = privECDSA + } + + if a.Logger == nil { + return fmt.Errorf("logger must be specified") + } + + return nil +} + +func ASRCLI(cliCtx *cli.Context) error { + logCfg := oplog.ReadCLIConfig(cliCtx) + l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg) + oplog.SetGlobalLogHandler(l.Handler()) + + l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName) + workdir := cliCtx.String(deployer.WorkdirFlagName) + privateKey := cliCtx.String(deployer.PrivateKeyFlagName) + artifactsURLStr := cliCtx.String(bootstrap.ArtifactsLocatorFlagName) + artifactsLocator := new(artifacts.Locator) + if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil { + return fmt.Errorf("failed to parse artifacts URL: %w", err) + } + + ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context) + + return ASR(ctx, ASRConfig{ + L1RPCUrl: l1RPCUrl, + Workdir: workdir, + PrivateKey: privateKey, + ArtifactsLocator: artifactsLocator, + Logger: l, + }) +} + +func ASR(ctx context.Context, cfg ASRConfig) error { + if err := cfg.Check(); err != nil { + return fmt.Errorf("invalid config for ASR: %w", err) + } + + lgr := cfg.Logger + progressor := func(curr, total int64) { + lgr.Info("artifacts download progress", "current", curr, "total", total) + } + + artifactsFS, cleanup, err := artifacts.Download(ctx, cfg.ArtifactsLocator, 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) + } + l1Rpc, err := rpc.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) + } + signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(cfg.privateKeyECDSA, chainID)) + chainDeployer := crypto.PubkeyToAddress(cfg.privateKeyECDSA.PublicKey) + bcaster, err := broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{ + Logger: lgr, + ChainID: chainID, + Client: l1Client, + Signer: signer, + From: chainDeployer, + }) + if err != nil { + return fmt.Errorf("failed to create broadcaster: %w", err) + } + + host, err := env.DefaultForkedScriptHost( + ctx, + bcaster, + lgr, + chainDeployer, + artifactsFS, + l1Rpc, + ) + if err != nil { + return fmt.Errorf("failed to create L1 script host: %w", err) + } + + var release string + if cfg.ArtifactsLocator.IsTag() { + release = cfg.ArtifactsLocator.Tag + } else { + release = "dev" + } + + lgr.Info("upgrading AnchorStateRegistry implementation", "release", release) + + st, err := pipeline.ReadState(cfg.Workdir) + if err != nil { + return fmt.Errorf("failed to read state: %w", err) + } + + output, err := opcm.UpgradeAnchorStateRegistry(host) + if err != nil { + return fmt.Errorf("error upgrading AnchorStateRegistry implementation: %w", err) + } + + if _, err := bcaster.Broadcast(ctx); err != nil { + return fmt.Errorf("failed to broadcast: %w", err) + } + + lgr.Info("upgraded AnchorStateRegistry implementation") + + if err := jsonutil.WriteJSON(output, ioutil.ToStdOut()); err != nil { + return fmt.Errorf("failed to write output: %w", err) + } + return nil +} diff --git a/op-deployer/pkg/deployer/upgrade/flags.go b/op-deployer/pkg/deployer/upgrade/flags.go new file mode 100644 index 000000000000..2040025eb5de --- /dev/null +++ b/op-deployer/pkg/deployer/upgrade/flags.go @@ -0,0 +1,24 @@ +package upgrade + +import ( + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/bootstrap" + "github.com/ethereum-optimism/optimism/op-service/cliapp" + "github.com/urfave/cli/v2" +) + +var ASRFlags = []cli.Flag{ + deployer.L1RPCURLFlag, + deployer.WorkdirFlag, + deployer.PrivateKeyFlag, + bootstrap.ArtifactsLocatorFlag, +} + +var Commands = []*cli.Command{ + { + Name: "asr", + Usage: "Upgrade ASR implementation.", + Flags: cliapp.ProtectFlags(ASRFlags), + Action: ASRCLI, + }, +} From c5eb254f819fe127d694d1875f466676d93ac210 Mon Sep 17 00:00:00 2001 From: blockchaindevsh Date: Tue, 14 Jan 2025 20:44:02 +0800 Subject: [PATCH 3/5] rust-foundry style upgrade script --- .../deploy/UpgradeAnchorStateRegistry.s.sol | 286 +++++++----------- 1 file changed, 108 insertions(+), 178 deletions(-) diff --git a/packages/contracts-bedrock/scripts/deploy/UpgradeAnchorStateRegistry.s.sol b/packages/contracts-bedrock/scripts/deploy/UpgradeAnchorStateRegistry.s.sol index e2afb940b1ce..5bbaff26a72e 100644 --- a/packages/contracts-bedrock/scripts/deploy/UpgradeAnchorStateRegistry.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/UpgradeAnchorStateRegistry.s.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.15; // Forge import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; // Scripts -import {BaseDeployIO} from "scripts/deploy/BaseDeployIO.sol"; import {DeployUtils} from "scripts/libraries/DeployUtils.sol"; // Libraries -import {GameType, Hash} from "src/dispute/lib/Types.sol"; +import {GameType, Hash, OutputRoot} from "src/dispute/lib/Types.sol"; // Contracts import {StorageSetter} from "src/universal/StorageSetter.sol"; @@ -20,192 +20,81 @@ import {IAnchorStateRegistry} from "interfaces/dispute/IAnchorStateRegistry.sol" import {IProxyAdmin} from "interfaces/universal/IProxyAdmin.sol"; import {ISuperchainConfig} from "interfaces/L1/ISuperchainConfig.sol"; -/// @title UpgradeAnchorStateRegistryInput -contract UpgradeAnchorStateRegistryInput is BaseDeployIO { - IDisputeGameFactory _disputeGameFactoryProxy; - IProxyAdmin internal _opChainProxyAdmin; - IAnchorStateRegistry internal _anchorStateRegistryProxy; - ISuperchainConfig internal _superchainConfig; - bytes internal _startingAnchorRoots; - - function set(bytes4 _sel, address _value) public { - if (_sel == this.disputeGameFactoryProxy.selector) { - require( - _value != address(0), - "UpgradeAnchorStateRegistryInput: disputeGameFactoryProxy cannot be zero address" - ); - _disputeGameFactoryProxy = IDisputeGameFactory(_value); - } else if (_sel == this.opChainProxyAdmin.selector) { - require( - _value != address(0), - "UpgradeAnchorStateRegistryInput: opChainProxyAdmin cannot be zero address" - ); - _opChainProxyAdmin = IProxyAdmin(_value); - } else if (_sel == this.anchorStateRegistryProxy.selector) { - require( - _value != address(0), - "UpgradeAnchorStateRegistryInput: anchorStateRegistryProxy cannot be zero address" - ); - _anchorStateRegistryProxy = IAnchorStateRegistry(_value); - } else if (_sel == this.superchainConfig.selector) { - require( - _value != address(0), - "UpgradeAnchorStateRegistryInput: superchainConfig cannot be zero address" - ); - _superchainConfig = ISuperchainConfig(_value); - } else { - revert( - "UpgradeAnchorStateRegistryInput: unknown selector for address" - ); - } - } - - function set(bytes4 _sel, bytes memory _value) public { - if (_sel == this.startingAnchorRoots.selector) { - require( - _value.length > 0, - "UpgradeAnchorStateRegistryInput: startingAnchorRoots cannot be empty bytes" - ); - _startingAnchorRoots = _value; - } else { - revert( - "UpgradeAnchorStateRegistryInput: unknown selector for bytes" - ); - } - } - - function opChainProxyAdmin() public view returns (IProxyAdmin) { - DeployUtils.assertValidContractAddress(address(_opChainProxyAdmin)); - return _opChainProxyAdmin; - } - - function disputeGameFactoryProxy() - public - view - returns (IDisputeGameFactory) - { - DeployUtils.assertValidContractAddress( - address(_disputeGameFactoryProxy) - ); - return _disputeGameFactoryProxy; - } - - function anchorStateRegistryProxy() public view returns (address) { - DeployUtils.assertValidContractAddress( - address(_anchorStateRegistryProxy) - ); - return address(_anchorStateRegistryProxy); - } - - function superchainConfig() public view returns (ISuperchainConfig) { - DeployUtils.assertValidContractAddress(address(_superchainConfig)); - return _superchainConfig; - } - - function startingAnchorRoots() public view returns (bytes memory) { - require( - _startingAnchorRoots.length > 0, - "UpgradeAnchorStateRegistryInput: startingAnchorRoots not set" - ); - return _startingAnchorRoots; - } -} - -/// @title UpgradeAnchorStateRegistryOutput -contract UpgradeAnchorStateRegistryOutput is BaseDeployIO { - IAnchorStateRegistry internal _anchorStateRegistryImpl; - StorageSetter internal _storageSetter; - - function set(bytes4 _sel, address _value) public { - if (_sel == this.anchorStateRegistryImpl.selector) { - require( - _value != address(0), - "UpgradeAnchorStateRegistryOutput: anchorStateRegistryImpl cannot be zero address" - ); - _anchorStateRegistryImpl = IAnchorStateRegistry(_value); - } else if (_sel == this.storageSetter.selector) { - require( - _value != address(0), - "UpgradeAnchorStateRegistryOutput: storageSetter cannot be zero address" - ); - _storageSetter = StorageSetter(_value); - } else { - revert("UpgradeAnchorStateRegistryOutput: unknown selector"); - } - } - - function anchorStateRegistryImpl() public view returns (address) { - DeployUtils.assertValidContractAddress( - address(_anchorStateRegistryImpl) - ); - return address(_anchorStateRegistryImpl); - } - - function storageSetter() public view returns (address) { - DeployUtils.assertValidContractAddress(address(_storageSetter)); - return address(_storageSetter); - } - function checkOutput(UpgradeAnchorStateRegistryInput _input) public view { - IAnchorStateRegistry.StartingAnchorRoot[] - memory startingAnchorRoots = abi.decode( - _input.startingAnchorRoots(), - (IAnchorStateRegistry.StartingAnchorRoot[]) - ); - (Hash root, uint256 l2BlockNumber) = IAnchorStateRegistry( - _input.anchorStateRegistryProxy() - ).anchors(startingAnchorRoots[0].gameType); - require( - Hash.unwrap(root) == - Hash.unwrap(startingAnchorRoots[0].outputRoot.root), - "UpgradeAnchorStateRegistryOutput: root mismatch" - ); - require( - l2BlockNumber == startingAnchorRoots[0].outputRoot.l2BlockNumber, - "UpgradeAnchorStateRegistryOutput: l2BlockNumber mismatch" - ); - } -} - /// @title UpgradeAnchorStateRegistry contract UpgradeAnchorStateRegistry is Script { function run( - UpgradeAnchorStateRegistryInput _input, - UpgradeAnchorStateRegistryOutput _output + address _disputeGameFactoryProxy, + address _opChainProxyAdmin, + address _anchorStateRegistryProxy, + address _superchainConfig, + uint32 _type, + uint256 _l2BlockNumber, + bytes32 _outputRoot ) public { - upgradeAnchorStateRegistryImpl(_input, _output); - _output.checkOutput(_input); + console.log("_disputeGameFactoryProxy: %s", _disputeGameFactoryProxy); + console.log("_opChainProxyAdmin: %s", _opChainProxyAdmin); + console.log("_anchorStateRegistryProxy: %s", _anchorStateRegistryProxy); + console.log("_superchainConfig: %s", _superchainConfig); + console.log("_type: %s", _type); + console.log("_l2BlockNumber: %s", _l2BlockNumber); + console.log("_outputRoot: %s", bytes32ToHex(_outputRoot)); + + vm.startBroadcast(); + upgradeAnchorStateRegistryImpl( + IDisputeGameFactory(_disputeGameFactoryProxy), + IProxyAdmin(_opChainProxyAdmin), + IAnchorStateRegistry(_anchorStateRegistryProxy), + ISuperchainConfig(_superchainConfig), + GameType.wrap(_type), + _l2BlockNumber, + Hash.wrap(_outputRoot) + ); + vm.stopBroadcast(); + checkOutput( + IAnchorStateRegistry(_anchorStateRegistryProxy), + GameType.wrap(_type), + _l2BlockNumber, + Hash.wrap(_outputRoot) + ); } function upgradeAnchorStateRegistryImpl( - UpgradeAnchorStateRegistryInput _input, - UpgradeAnchorStateRegistryOutput _output + IDisputeGameFactory _disputeGameFactoryProxy, + IProxyAdmin _opChainProxyAdmin, + IAnchorStateRegistry _anchorStateRegistryProxy, + ISuperchainConfig _superchainConfig, + GameType _type, + uint256 _l2BlockNumber, + Hash _outputRoot ) internal { - _output.set( - _output.anchorStateRegistryImpl.selector, - DeployUtils.create1({ - _name: "AnchorStateRegistry", - _args: abi.encode(_input.disputeGameFactoryProxy()) - }) - ); + address anchorStateRegistryImpl = DeployUtils.create1({ + _name: "AnchorStateRegistry", + _args: abi.encode(_disputeGameFactoryProxy) + }); - _output.set( - _output.storageSetter.selector, - DeployUtils.create1({_name: "StorageSetter", _args: ""}) - ); + address storageSetter = DeployUtils.create1({ + _name: "StorageSetter", + _args: "" + }); bytes memory data; data = encodeStorageSetterZeroOutInitializedSlot(); upgradeAndCall( - _input.opChainProxyAdmin(), - _input.anchorStateRegistryProxy(), - _output.storageSetter(), + _opChainProxyAdmin, + address(_anchorStateRegistryProxy), + storageSetter, data ); - data = encodeAnchorStateRegistryInitializer(_input); + data = encodeAnchorStateRegistryInitializer( + _type, + _l2BlockNumber, + _outputRoot, + _superchainConfig + ); upgradeAndCall( - _input.opChainProxyAdmin(), - _input.anchorStateRegistryProxy(), - _output.anchorStateRegistryImpl(), + _opChainProxyAdmin, + address(_anchorStateRegistryProxy), + anchorStateRegistryImpl, data ); } @@ -224,19 +113,27 @@ contract UpgradeAnchorStateRegistry is Script { } function encodeAnchorStateRegistryInitializer( - UpgradeAnchorStateRegistryInput _input + GameType _type, + uint256 _l2BlockNumber, + Hash _outputRoot, + ISuperchainConfig _superchainConfig ) internal view virtual returns (bytes memory) { - // this line fails in the op-deployer tests because it is not passing in any data IAnchorStateRegistry.StartingAnchorRoot[] - memory startingAnchorRoots = abi.decode( - _input.startingAnchorRoots(), - (IAnchorStateRegistry.StartingAnchorRoot[]) + memory startingAnchorRoots = new IAnchorStateRegistry.StartingAnchorRoot[]( + 1 ); + startingAnchorRoots[0] = IAnchorStateRegistry.StartingAnchorRoot({ + gameType: _type, + outputRoot: OutputRoot({ + root: _outputRoot, + l2BlockNumber: _l2BlockNumber + }) + }); return abi.encodeWithSelector( IAnchorStateRegistry.initialize.selector, startingAnchorRoots, - _input.superchainConfig() + _superchainConfig ); } @@ -258,4 +155,37 @@ contract UpgradeAnchorStateRegistry is Script { _data ); } + + function checkOutput( + IAnchorStateRegistry _anchorStateRegistryProxy, + GameType _type, + uint256 _l2BlockNumber, + Hash _outputRoot + ) public view { + (Hash root, uint256 l2BlockNumber) = IAnchorStateRegistry( + _anchorStateRegistryProxy + ).anchors(_type); + require( + Hash.unwrap(root) == Hash.unwrap(_outputRoot), + "UpgradeAnchorStateRegistryOutput: root mismatch" + ); + require( + l2BlockNumber == _l2BlockNumber, + "UpgradeAnchorStateRegistryOutput: l2BlockNumber mismatch" + ); + } + + function bytes32ToHex(bytes32 data) internal pure returns (string memory) { + bytes memory result = new bytes(64); + for (uint256 i = 0; i < 32; i++) { + uint8 byteValue = uint8(data[i]); + result[i * 2] = toHexChar(byteValue / 16); + result[i * 2 + 1] = toHexChar(byteValue % 16); + } + return string(result); + } + + function toHexChar(uint8 b) internal pure returns (bytes1) { + return b < 10 ? bytes1(b + 0x30) : bytes1(b + 0x57); + } } From 36e4334e39b59e28b410d879314cebeb9736266c Mon Sep 17 00:00:00 2001 From: blockchaindevsh Date: Tue, 14 Jan 2025 20:44:56 +0800 Subject: [PATCH 4/5] Revert "op-deployer integration" This reverts commit 650f2552f9b2052f9b30cf3fcc87c6066dcc3404. --- op-deployer/cmd/op-deployer/main.go | 6 - op-deployer/pkg/deployer/opcm/upgrade_asr.go | 44 ----- op-deployer/pkg/deployer/upgrade/asr.go | 174 ------------------- op-deployer/pkg/deployer/upgrade/flags.go | 24 --- 4 files changed, 248 deletions(-) delete mode 100644 op-deployer/pkg/deployer/opcm/upgrade_asr.go delete mode 100644 op-deployer/pkg/deployer/upgrade/asr.go delete mode 100644 op-deployer/pkg/deployer/upgrade/flags.go diff --git a/op-deployer/cmd/op-deployer/main.go b/op-deployer/cmd/op-deployer/main.go index b67bac2b2bbe..6c3b1fa0807d 100644 --- a/op-deployer/cmd/op-deployer/main.go +++ b/op-deployer/cmd/op-deployer/main.go @@ -7,7 +7,6 @@ import ( "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/bootstrap" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/inspect" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/upgrade" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/version" opservice "github.com/ethereum-optimism/optimism/op-service" @@ -53,11 +52,6 @@ func main() { Usage: "inspects the state of a deployment", Subcommands: inspect.Commands, }, - { - Name: "upgrade", - Usage: "upgrade contracts", - Subcommands: upgrade.Commands, - }, } app.Writer = os.Stdout app.ErrWriter = os.Stderr diff --git a/op-deployer/pkg/deployer/opcm/upgrade_asr.go b/op-deployer/pkg/deployer/opcm/upgrade_asr.go deleted file mode 100644 index 74dcfb6c668c..000000000000 --- a/op-deployer/pkg/deployer/opcm/upgrade_asr.go +++ /dev/null @@ -1,44 +0,0 @@ -package opcm - -import ( - "github.com/ethereum/go-ethereum/common" - - "github.com/ethereum-optimism/optimism/op-chain-ops/script" -) - -type UpgradeAnchorStateRegistryInput struct { - Release string - StandardVersionsToml string - VmAddress common.Address - GameKind string - GameType uint32 - AbsolutePrestate common.Hash - MaxGameDepth uint64 - SplitDepth uint64 - ClockExtension uint64 - MaxClockDuration uint64 - DelayedWethProxy common.Address - AnchorStateRegistryProxy common.Address - L2ChainId uint64 - Proposer common.Address - Challenger common.Address -} - -func (input *UpgradeAnchorStateRegistryInput) InputSet() bool { - return true -} - -type UpgradeAnchorStateRegistryOutput struct { - DisputeGameImpl common.Address -} - -func (output *UpgradeAnchorStateRegistryOutput) CheckOutput(input common.Address) error { - return nil -} - -func UpgradeAnchorStateRegistry( - host *script.Host, - input UpgradeAnchorStateRegistryInput, -) (UpgradeAnchorStateRegistryOutput, error) { - return RunBasicScript[UpgradeAnchorStateRegistryInput, UpgradeAnchorStateRegistryOutput](host, input, "UpgradeAnchorStateRegistry.s.sol", "UpgradeAnchorStateRegistry") -} diff --git a/op-deployer/pkg/deployer/upgrade/asr.go b/op-deployer/pkg/deployer/upgrade/asr.go deleted file mode 100644 index 9f0956591fca..000000000000 --- a/op-deployer/pkg/deployer/upgrade/asr.go +++ /dev/null @@ -1,174 +0,0 @@ -package upgrade - -import ( - "context" - "crypto/ecdsa" - "fmt" - "strings" - - "github.com/ethereum/go-ethereum/rpc" - - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/bootstrap" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/pipeline" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" - 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/crypto" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/log" - "github.com/urfave/cli/v2" -) - -type ASRConfig struct { - L1RPCUrl string - Workdir string - PrivateKey string - Logger log.Logger - ArtifactsLocator *artifacts.Locator - - privateKeyECDSA *ecdsa.PrivateKey -} - -func (a *ASRConfig) Check() error { - if a.L1RPCUrl == "" { - return fmt.Errorf("l1-rpc-url must be specified") - } - if a.Workdir == "" { - return fmt.Errorf("workdir must be specified") - } - - if a.PrivateKey != "" { - privECDSA, err := crypto.HexToECDSA(strings.TrimPrefix(a.PrivateKey, "0x")) - if err != nil { - return fmt.Errorf("failed to parse private key: %w", err) - } - a.privateKeyECDSA = privECDSA - } - - if a.Logger == nil { - return fmt.Errorf("logger must be specified") - } - - return nil -} - -func ASRCLI(cliCtx *cli.Context) error { - logCfg := oplog.ReadCLIConfig(cliCtx) - l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg) - oplog.SetGlobalLogHandler(l.Handler()) - - l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName) - workdir := cliCtx.String(deployer.WorkdirFlagName) - privateKey := cliCtx.String(deployer.PrivateKeyFlagName) - artifactsURLStr := cliCtx.String(bootstrap.ArtifactsLocatorFlagName) - artifactsLocator := new(artifacts.Locator) - if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil { - return fmt.Errorf("failed to parse artifacts URL: %w", err) - } - - ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context) - - return ASR(ctx, ASRConfig{ - L1RPCUrl: l1RPCUrl, - Workdir: workdir, - PrivateKey: privateKey, - ArtifactsLocator: artifactsLocator, - Logger: l, - }) -} - -func ASR(ctx context.Context, cfg ASRConfig) error { - if err := cfg.Check(); err != nil { - return fmt.Errorf("invalid config for ASR: %w", err) - } - - lgr := cfg.Logger - progressor := func(curr, total int64) { - lgr.Info("artifacts download progress", "current", curr, "total", total) - } - - artifactsFS, cleanup, err := artifacts.Download(ctx, cfg.ArtifactsLocator, 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) - } - l1Rpc, err := rpc.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) - } - signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(cfg.privateKeyECDSA, chainID)) - chainDeployer := crypto.PubkeyToAddress(cfg.privateKeyECDSA.PublicKey) - bcaster, err := broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{ - Logger: lgr, - ChainID: chainID, - Client: l1Client, - Signer: signer, - From: chainDeployer, - }) - if err != nil { - return fmt.Errorf("failed to create broadcaster: %w", err) - } - - host, err := env.DefaultForkedScriptHost( - ctx, - bcaster, - lgr, - chainDeployer, - artifactsFS, - l1Rpc, - ) - if err != nil { - return fmt.Errorf("failed to create L1 script host: %w", err) - } - - var release string - if cfg.ArtifactsLocator.IsTag() { - release = cfg.ArtifactsLocator.Tag - } else { - release = "dev" - } - - lgr.Info("upgrading AnchorStateRegistry implementation", "release", release) - - st, err := pipeline.ReadState(cfg.Workdir) - if err != nil { - return fmt.Errorf("failed to read state: %w", err) - } - - output, err := opcm.UpgradeAnchorStateRegistry(host) - if err != nil { - return fmt.Errorf("error upgrading AnchorStateRegistry implementation: %w", err) - } - - if _, err := bcaster.Broadcast(ctx); err != nil { - return fmt.Errorf("failed to broadcast: %w", err) - } - - lgr.Info("upgraded AnchorStateRegistry implementation") - - if err := jsonutil.WriteJSON(output, ioutil.ToStdOut()); err != nil { - return fmt.Errorf("failed to write output: %w", err) - } - return nil -} diff --git a/op-deployer/pkg/deployer/upgrade/flags.go b/op-deployer/pkg/deployer/upgrade/flags.go deleted file mode 100644 index 2040025eb5de..000000000000 --- a/op-deployer/pkg/deployer/upgrade/flags.go +++ /dev/null @@ -1,24 +0,0 @@ -package upgrade - -import ( - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/bootstrap" - "github.com/ethereum-optimism/optimism/op-service/cliapp" - "github.com/urfave/cli/v2" -) - -var ASRFlags = []cli.Flag{ - deployer.L1RPCURLFlag, - deployer.WorkdirFlag, - deployer.PrivateKeyFlag, - bootstrap.ArtifactsLocatorFlag, -} - -var Commands = []*cli.Command{ - { - Name: "asr", - Usage: "Upgrade ASR implementation.", - Flags: cliapp.ProtectFlags(ASRFlags), - Action: ASRCLI, - }, -} From 03a3303d60b2959a3566c369d70ed736eb898473 Mon Sep 17 00:00:00 2001 From: blockchaindevsh Date: Wed, 15 Jan 2025 12:56:13 +0800 Subject: [PATCH 5/5] reuse StorageSetter if provided --- .../deploy/UpgradeAnchorStateRegistry.s.sol | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/contracts-bedrock/scripts/deploy/UpgradeAnchorStateRegistry.s.sol b/packages/contracts-bedrock/scripts/deploy/UpgradeAnchorStateRegistry.s.sol index 5bbaff26a72e..560769c659bc 100644 --- a/packages/contracts-bedrock/scripts/deploy/UpgradeAnchorStateRegistry.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/UpgradeAnchorStateRegistry.s.sol @@ -27,6 +27,7 @@ contract UpgradeAnchorStateRegistry is Script { address _opChainProxyAdmin, address _anchorStateRegistryProxy, address _superchainConfig, + address _storageSetter, uint32 _type, uint256 _l2BlockNumber, bytes32 _outputRoot @@ -35,6 +36,7 @@ contract UpgradeAnchorStateRegistry is Script { console.log("_opChainProxyAdmin: %s", _opChainProxyAdmin); console.log("_anchorStateRegistryProxy: %s", _anchorStateRegistryProxy); console.log("_superchainConfig: %s", _superchainConfig); + console.log("_storageSetter: %s", _storageSetter); console.log("_type: %s", _type); console.log("_l2BlockNumber: %s", _l2BlockNumber); console.log("_outputRoot: %s", bytes32ToHex(_outputRoot)); @@ -45,6 +47,7 @@ contract UpgradeAnchorStateRegistry is Script { IProxyAdmin(_opChainProxyAdmin), IAnchorStateRegistry(_anchorStateRegistryProxy), ISuperchainConfig(_superchainConfig), + _storageSetter, GameType.wrap(_type), _l2BlockNumber, Hash.wrap(_outputRoot) @@ -63,6 +66,7 @@ contract UpgradeAnchorStateRegistry is Script { IProxyAdmin _opChainProxyAdmin, IAnchorStateRegistry _anchorStateRegistryProxy, ISuperchainConfig _superchainConfig, + address _storageSetter, GameType _type, uint256 _l2BlockNumber, Hash _outputRoot @@ -72,17 +76,19 @@ contract UpgradeAnchorStateRegistry is Script { _args: abi.encode(_disputeGameFactoryProxy) }); - address storageSetter = DeployUtils.create1({ - _name: "StorageSetter", - _args: "" - }); + if (_storageSetter == address(0)) { + _storageSetter = DeployUtils.create1({ + _name: "StorageSetter", + _args: "" + }); + } bytes memory data; data = encodeStorageSetterZeroOutInitializedSlot(); upgradeAndCall( _opChainProxyAdmin, address(_anchorStateRegistryProxy), - storageSetter, + _storageSetter, data ); data = encodeAnchorStateRegistryInitializer(