Commit d3fbc576 authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

op-deployer: Update OPCM bootstrap command (#13238)

* op-deployer: Update OPCM bootstrap command

Updates the OPCM bootstrap command to allow bootstrapping Holocene.

* fix merge artifact
parent a5556262
build:
go build -o bin/op-deployer cmd/op-deployer/main.go
\ No newline at end of file
go build -o bin/op-deployer cmd/op-deployer/main.go
download-artifacts checksum outfile:
curl -o {{outfile}} -L https://storage.googleapis.com/oplabs-contract-artifacts/artifacts-v1-{{checksum}}.tar.gz
calculate-artifacts-hash checksum:
just download-artifacts {{checksum}} /tmp/artifact.tgz
sha256sum /tmp/artifact.tgz
rm /tmp/artifact.tgz
\ No newline at end of file
......@@ -6,8 +6,6 @@ import (
"fmt"
"strings"
"github.com/ethereum-optimism/optimism/op-chain-ops/script"
"github.com/ethereum-optimism/optimism/op-chain-ops/script/forking"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum/go-ethereum/common"
......@@ -145,35 +143,18 @@ func Asterisc(ctx context.Context, cfg AsteriscConfig) error {
return fmt.Errorf("failed to connect to L1 RPC: %w", err)
}
l1Host, err := env.DefaultScriptHost(
l1Host, err := env.DefaultForkedScriptHost(
ctx,
bcaster,
lgr,
chainDeployer,
artifactsFS,
script.WithForkHook(func(cfg *script.ForkConfig) (forking.ForkSource, error) {
src, err := forking.RPCSourceByNumber(cfg.URLOrAlias, l1RPC, *cfg.BlockNumber)
if err != nil {
return nil, fmt.Errorf("failed to create RPC fork source: %w", err)
}
return forking.Cache(src), nil
}),
l1RPC,
)
if err != nil {
return fmt.Errorf("failed to create script host: %w", err)
}
latest, err := l1Client.HeaderByNumber(ctx, nil)
if err != nil {
return fmt.Errorf("failed to get latest block: %w", err)
}
if _, err := l1Host.CreateSelectFork(
script.ForkWithURLOrAlias("main"),
script.ForkWithBlockNumberU256(latest.Number),
); err != nil {
return fmt.Errorf("failed to select fork: %w", err)
}
dgo, err := opcm.DeployAsterisc(
l1Host,
opcm.DeployAsteriscInput{
......
package bootstrap
import (
"errors"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
"github.com/ethereum-optimism/optimism/op-service/cliapp"
......@@ -30,6 +32,7 @@ const (
ProposerFlagName = "proposer"
ChallengerFlagName = "challenger"
PreimageOracleFlagName = "preimage-oracle"
ReleaseFlagName = "release"
)
var (
......@@ -153,18 +156,26 @@ var (
EnvVars: deployer.PrefixEnvVar("PREIMAGE_ORACLE"),
Value: common.Address{}.Hex(),
}
ReleaseFlag = &cli.StringFlag{
Name: ReleaseFlagName,
Usage: "Release to deploy.",
EnvVars: deployer.PrefixEnvVar("RELEASE"),
}
)
var OPCMFlags = []cli.Flag{
deployer.L1RPCURLFlag,
deployer.PrivateKeyFlag,
ArtifactsLocatorFlag,
ReleaseFlag,
}
var ImplementationsFlags = []cli.Flag{
MIPSVersionFlag,
WithdrawalDelaySecondsFlag,
MinProposalSizeBytesFlag,
ChallengePeriodSecondsFlag,
ProofMaturityDelaySecondsFlag,
DisputeGameFinalityDelaySecondsFlag,
MIPSVersionFlag,
}
var DelayedWETHFlags = []cli.Flag{
......@@ -212,6 +223,15 @@ var Commands = []*cli.Command{
Flags: cliapp.ProtectFlags(OPCMFlags),
Action: OPCMCLI,
},
{
Name: "implementations",
Usage: "Bootstraps implementations.",
Flags: cliapp.ProtectFlags(ImplementationsFlags),
Action: func(context *cli.Context) error {
return errors.New("not implemented yet")
},
Hidden: true,
},
{
Name: "delayedweth",
Usage: "Bootstrap an instance of DelayedWETH.",
......
This diff is collapsed.
package bootstrap
import (
"context"
"log/slog"
"os"
"strings"
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/retryproxy"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum-optimism/optimism/op-service/testutils/anvil"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/stretchr/testify/require"
)
var networks = []string{"mainnet", "sepolia"}
var versions = []string{"v1.8.0-rc.3"}
func TestOPCMLiveChain(t *testing.T) {
for _, network := range networks {
for _, version := range versions {
t.Run(network+"-"+version, func(t *testing.T) {
if version == "v1.8.0-rc.3" && network == "mainnet" {
t.Skip("v1.8.0-rc.3 not supported on mainnet yet")
}
envVar := strings.ToUpper(network) + "_RPC_URL"
rpcURL := os.Getenv(envVar)
require.NotEmpty(t, rpcURL, "must specify RPC url via %s env var", envVar)
testOPCMLiveChain(t, "op-contracts/"+version, rpcURL)
})
}
}
}
func testOPCMLiveChain(t *testing.T, version string, forkRPCURL string) {
t.Parallel()
if forkRPCURL == "" {
t.Skip("forkRPCURL not set")
}
lgr := testlog.Logger(t, slog.LevelDebug)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
retryProxy := retryproxy.New(lgr, forkRPCURL)
require.NoError(t, retryProxy.Start())
t.Cleanup(func() {
require.NoError(t, retryProxy.Stop())
})
runner, err := anvil.New(
retryProxy.Endpoint(),
lgr,
)
require.NoError(t, err)
require.NoError(t, runner.Start(ctx))
t.Cleanup(func() {
require.NoError(t, runner.Stop())
})
out, err := OPCM(ctx, OPCMConfig{
L1RPCUrl: runner.RPCUrl(),
PrivateKey: "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
Release: version,
Logger: lgr,
})
require.NoError(t, err)
require.NotEmpty(t, out.Opcm)
client, err := ethclient.Dial(runner.RPCUrl())
require.NoError(t, err)
code, err := client.CodeAt(ctx, out.Opcm, nil)
require.NoError(t, err)
require.NotEmpty(t, code)
}
package opcm
import (
"fmt"
"github.com/ethereum-optimism/optimism/op-chain-ops/script"
"github.com/ethereum/go-ethereum/common"
)
type DeployOPCMInput struct {
SuperchainConfig common.Address
ProtocolVersions common.Address
L1ContractsRelease string
AddressManagerBlueprint common.Address
ProxyBlueprint common.Address
ProxyAdminBlueprint common.Address
L1ChugSplashProxyBlueprint common.Address
ResolvedDelegateProxyBlueprint common.Address
AnchorStateRegistryBlueprint common.Address
PermissionedDisputeGame1Blueprint common.Address
PermissionedDisputeGame2Blueprint common.Address
L1ERC721BridgeImpl common.Address
OptimismPortalImpl common.Address
SystemConfigImpl common.Address
OptimismMintableERC20FactoryImpl common.Address
L1CrossDomainMessengerImpl common.Address
L1StandardBridgeImpl common.Address
DisputeGameFactoryImpl common.Address
DelayedWETHImpl common.Address
MipsImpl common.Address
}
type DeployOPCMOutput struct {
Opcm common.Address
}
func DeployOPCM(
host *script.Host,
input DeployOPCMInput,
) (DeployOPCMOutput, error) {
scriptFile := "DeployOPCM.s.sol"
contractName := "DeployOPCM"
out, err := RunBasicScript[DeployOPCMInput, DeployOPCMOutput](host, input, scriptFile, contractName)
if err != nil {
return DeployOPCMOutput{}, fmt.Errorf("failed to deploy OPCM: %w", err)
}
if err := host.RememberOnLabel("OPContractsManager", "OPContractsManager.sol", "OPContractsManager"); err != nil {
return DeployOPCMOutput{}, fmt.Errorf("failed to link OPContractsManager label: %w", err)
}
return out, nil
}
package opcm
import (
"fmt"
"github.com/ethereum-optimism/optimism/op-chain-ops/script"
"github.com/ethereum/go-ethereum/common"
)
type BasicScriptIO struct {
Run func(input, output common.Address) error
}
func RunBasicScript[I any, O any](
host *script.Host,
input I,
scriptFile string,
contractName string,
) (O, error) {
var output O
inputAddr := host.NewScriptAddress()
outputAddr := host.NewScriptAddress()
cleanupInput, err := script.WithPrecompileAtAddress[*I](host, inputAddr, &input)
if err != nil {
return output, fmt.Errorf("failed to insert input precompile: %w", err)
}
defer cleanupInput()
cleanupOutput, err := script.WithPrecompileAtAddress[*O](host, outputAddr, &output,
script.WithFieldSetter[*O])
if err != nil {
return output, fmt.Errorf("failed to insert output precompile: %w", err)
}
defer cleanupOutput()
deployScript, cleanupDeploy, err := script.WithScript[BasicScriptIO](host, scriptFile, contractName)
if err != nil {
return output, fmt.Errorf("failed to load %s script: %w", scriptFile, err)
}
defer cleanupDeploy()
if err := deployScript.Run(inputAddr, outputAddr); err != nil {
return output, fmt.Errorf("failed to run %s script: %w", scriptFile, err)
}
return output, nil
}
......@@ -5,6 +5,25 @@
# * proxied : specify a standard "implementation_address"
# * neither : specify neither a standard "address" nor "implementation_address"
# Holocene https://github.com/ethereum-optimism/optimism/releases/tag/op-contracts%2Fv1.8.0-rc.3
[releases."op-contracts/v1.8.0-rc.3"]
# Updated in this release
system_config = { version = "2.3.0", implementation_address = "0x33b83E4C305c908B2Fc181dDa36e230213058d7d" } # UPDATED IN THIS RELEASE
fault_dispute_game = { version = "1.3.1" } # UPDATED IN THIS RELEASE
permissioned_dispute_game = { version = "1.3.1" } # UPDATED IN THIS RELEASE
mips = { version = "1.2.1", address = "0x69470D6970Cd2A006b84B1d4d70179c892cFCE01" } # UPDATED IN THIS RELEASE
# Unchanged in this release
optimism_portal = { version = "3.10.0", implementation_address = "0x35028bae87d71cbc192d545d38f960ba30b4b233" }
anchor_state_registry = { version = "2.0.0" }
delayed_weth = { version = "1.1.0", implementation_address = "0x07f69b19532476c6cd03056d6bc3f1b110ab7538" }
dispute_game_factory = { version = "1.0.0", implementation_address = "0xa51bea7e4d34206c0bcb04a776292f2f19f0beec" }
preimage_oracle = { version = "1.1.2", address = "0x92240135b46fc1142dA181f550aE8f595B858854" }
l1_cross_domain_messenger = { version = "2.3.0", implementation_address = "0xD3494713A5cfaD3F5359379DfA074E2Ac8C6Fd65" }
l1_erc721_bridge = { version = "2.1.0", implementation_address = "0xae2af01232a6c4a4d3012c5ec5b1b35059caf10d" }
l1_standard_bridge = { version = "2.1.0", implementation_address = "0x64b5a5ed26dcb17370ff4d33a8d503f0fbd06cff" }
# l2_output_oracle -- This contract not used in fault proofs
optimism_mintable_erc20_factory = { version = "1.9.0", implementation_address = "0xe01efbeb1089d1d1db9c6c8b135c934c0734c846" }
# Fault Proofs https://github.com/ethereum-optimism/optimism/releases/tag/op-contracts%2Fv1.6.0
[releases."op-contracts/v1.6.0"]
optimism_portal = { version = "3.10.0", implementation_address = "0x35028bae87d71cbc192d545d38f960ba30b4b233" }
......@@ -20,4 +39,4 @@ l1_cross_domain_messenger = { version = "2.3.0", implementation_address = "0xD34
l1_erc721_bridge = { version = "2.1.0", implementation_address = "0xae2af01232a6c4a4d3012c5ec5b1b35059caf10d" }
l1_standard_bridge = { version = "2.1.0", implementation_address = "0x64b5a5ed26dcb17370ff4d33a8d503f0fbd06cff" }
# l2_output_oracle -- This contract not used in fault proofs
optimism_mintable_erc20_factory = { version = "1.9.0", implementation_address = "0xe01efbeb1089d1d1db9c6c8b135c934c0734c846" }
optimism_mintable_erc20_factory = { version = "1.9.0", implementation_address = "0xe01efbeb1089d1d1db9c6c8b135c934c0734c846" }
\ No newline at end of file
......@@ -78,6 +78,50 @@ type VersionRelease struct {
var _ embed.FS
type OPCMBlueprints struct {
AddressManager common.Address
Proxy common.Address
ProxyAdmin common.Address
L1ChugSplashProxy common.Address
ResolvedDelegateProxy common.Address
AnchorStateRegistry common.Address
PermissionedDisputeGame1 common.Address
PermissionedDisputeGame2 common.Address
}
var sepoliaBlueprints = OPCMBlueprints{
AddressManager: common.HexToAddress("0x3125a4cB2179E04203D3Eb2b5784aaef9FD64216"),
Proxy: common.HexToAddress("0xe650ADb86a0de96e2c434D0a52E7D5B70980D6f1"),
ProxyAdmin: common.HexToAddress("0x3AC6b88F6bC4A5038DB7718dE47a5ab1a9609319"),
L1ChugSplashProxy: common.HexToAddress("0x58770FC7ed304c43D2B70248914eb34A741cF411"),
ResolvedDelegateProxy: common.HexToAddress("0x0449adB72D489a137d476aB49c6b812161754fD3"),
AnchorStateRegistry: common.HexToAddress("0xB98095199437883b7661E0D58256060f3bc730a4"),
PermissionedDisputeGame1: common.HexToAddress("0xf72Ac5f164cC024DE09a2c249441715b69a16eAb"),
PermissionedDisputeGame2: common.HexToAddress("0x713dAC5A23728477547b484f9e0D751077E300a2"),
}
var mainnetBlueprints = OPCMBlueprints{
AddressManager: common.HexToAddress("0x29aA24714c06914d9689e933cae2293C569AfeEa"),
Proxy: common.HexToAddress("0x3626ebD458c7f34FD98789A373593fF2fc227bA0"),
ProxyAdmin: common.HexToAddress("0x7170678A5CFFb6872606d251B3CcdB27De962631"),
L1ChugSplashProxy: common.HexToAddress("0x538906C8B000D621fd11B7e8642f504dD8730837"),
ResolvedDelegateProxy: common.HexToAddress("0xF12bD34d6a1d26d230240ECEA761f77e2013926E"),
AnchorStateRegistry: common.HexToAddress("0xbA7Be2bEE016568274a4D1E6c852Bb9a99FaAB8B"),
PermissionedDisputeGame1: common.HexToAddress("0xb94bF6130Df8BD9a9eA45D8dD8C18957002d1986"),
PermissionedDisputeGame2: common.HexToAddress("0xe0a642B249CF6cbF0fF7b4dDf41443Ea7a5C8Cc8"),
}
func OPCMBlueprintsFor(chainID uint64) (OPCMBlueprints, error) {
switch chainID {
case 1:
return mainnetBlueprints, nil
case 11155111:
return sepoliaBlueprints, nil
default:
return OPCMBlueprints{}, fmt.Errorf("unsupported chain ID: %d", chainID)
}
}
func L1VersionsDataFor(chainID uint64) (string, error) {
switch chainID {
case 1:
......@@ -215,6 +259,8 @@ func ArtifactsURLForTag(tag string) (*url.URL, error) {
return url.Parse(standardArtifactsURL("e1f0c4020618c4a98972e7124c39686cab2e31d5d7846f9ce5e0d5eed0f5ff32"))
case "op-contracts/v1.7.0-beta.1+l2-contracts":
return url.Parse(standardArtifactsURL("b0fb1f6f674519d637cff39a22187a5993d7f81a6d7b7be6507a0b50a5e38597"))
case "op-contracts/v1.8.0-rc.3":
return url.Parse(standardArtifactsURL("3bcff2944953862596d5fd0125d166a04af2ba6426dc693983291d3cb86b2e2e"))
default:
return nil, fmt.Errorf("unsupported tag: %s", tag)
}
......@@ -226,6 +272,8 @@ func ArtifactsHashForTag(tag string) (common.Hash, error) {
return common.HexToHash("d20a930cc0ff204c2d93b7aa60755ec7859ba4f328b881f5090c6a6a2a86dcba"), nil
case "op-contracts/v1.7.0-beta.1+l2-contracts":
return common.HexToHash("9e3ad322ec9b2775d59143ce6874892f9b04781742c603ad59165159e90b00b9"), nil
case "op-contracts/v1.8.0-rc.3":
return common.HexToHash("7c133142165fbbdba28ced5d9a04af8bea68baf58b19a07cdd8ae531b01fbe9d"), nil
default:
return common.Hash{}, fmt.Errorf("unsupported tag: %s", tag)
}
......
package env
import (
"context"
"fmt"
"github.com/ethereum-optimism/optimism/op-chain-ops/script/forking"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
"github.com/ethereum-optimism/optimism/op-chain-ops/foundry"
......@@ -39,3 +44,48 @@ func DefaultScriptHost(
return h, nil
}
func DefaultForkedScriptHost(
ctx context.Context,
bcaster broadcaster.Broadcaster,
lgr log.Logger,
deployer common.Address,
artifacts foundry.StatDirFs,
forkRPC *rpc.Client,
additionalOpts ...script.HostOption,
) (*script.Host, error) {
h, err := DefaultScriptHost(
bcaster,
lgr,
deployer,
artifacts,
append([]script.HostOption{
script.WithForkHook(func(cfg *script.ForkConfig) (forking.ForkSource, error) {
src, err := forking.RPCSourceByNumber(cfg.URLOrAlias, forkRPC, *cfg.BlockNumber)
if err != nil {
return nil, fmt.Errorf("failed to create RPC fork source: %w", err)
}
return forking.Cache(src), nil
}),
}, additionalOpts...)...,
)
if err != nil {
return nil, fmt.Errorf("failed to create default script host: %w", err)
}
client := ethclient.NewClient(forkRPC)
latest, err := client.HeaderByNumber(ctx, nil)
if err != nil {
return nil, fmt.Errorf("failed to get latest block: %w", err)
}
if _, err := h.CreateSelectFork(
script.ForkWithURLOrAlias("main"),
script.ForkWithBlockNumberU256(latest.Number),
); err != nil {
return nil, fmt.Errorf("failed to select fork: %w", err)
}
return h, nil
}
......@@ -3,6 +3,7 @@ package retryproxy
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net"
......@@ -13,6 +14,10 @@ import (
"github.com/ethereum/go-ethereum/log"
)
type jsonRPCReq struct {
Method string `json:"method"`
}
var copyHeaders = []string{
"Content-Type",
}
......@@ -92,6 +97,8 @@ func (p *RetryProxy) Endpoint() string {
}
func (p *RetryProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
start := time.Now()
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
......@@ -138,7 +145,16 @@ func (p *RetryProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if _, err := io.Copy(w, bytes.NewReader(resBody)); err != nil {
p.lgr.Error("failed to copy response", "err", err)
http.Error(w, "failed to copy response", http.StatusInternalServerError)
return
}
var jReq jsonRPCReq
if err := json.Unmarshal(reqBody, &jReq); err != nil {
p.lgr.Warn("failed to unmarshal request", "err", err)
return
}
p.lgr.Debug("proxied request", "method", jReq.Method, "dur", time.Since(start))
}
func (p *RetryProxy) doProxyReq(ctx context.Context, body []byte) (*http.Response, error) {
......
......@@ -33,6 +33,10 @@ type Runner struct {
}
func New(l1RPCURL string, logger log.Logger) (*Runner, error) {
if _, err := exec.LookPath("anvil"); err != nil {
return nil, fmt.Errorf("anvil not found in PATH: %w", err)
}
proc := exec.Command(
"anvil",
"--fork-url", l1RPCURL,
......@@ -106,7 +110,7 @@ func (r *Runner) outputStream(stream io.ReadCloser) {
}
}
r.logger.Debug("[ANVIL] " + scanner.Text())
r.logger.Debug("[ANVIL] " + line)
}
}
......
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