Commit 50564d43 authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

op-deployer: Support forking live chains (#12918)

parent ae78b73d
...@@ -53,15 +53,7 @@ func (c *CheatCodesPrecompile) CreateSelectFork_84d52b7a(urlOrAlias string, txHa ...@@ -53,15 +53,7 @@ func (c *CheatCodesPrecompile) CreateSelectFork_84d52b7a(urlOrAlias string, txHa
// createSelectFork implements vm.createSelectFork: // createSelectFork implements vm.createSelectFork:
// https://book.getfoundry.sh/cheatcodes/create-select-fork // https://book.getfoundry.sh/cheatcodes/create-select-fork
func (c *CheatCodesPrecompile) createSelectFork(opts ...ForkOption) (*big.Int, error) { func (c *CheatCodesPrecompile) createSelectFork(opts ...ForkOption) (*big.Int, error) {
src, err := c.h.onFork(opts...) return c.h.CreateSelectFork(opts...)
if err != nil {
return nil, fmt.Errorf("failed to setup fork source: %w", err)
}
id, err := c.h.state.CreateSelectFork(src)
if err != nil {
return nil, fmt.Errorf("failed to create-select fork: %w", err)
}
return id.U256().ToBig(), nil
} }
// ActiveFork implements vm.activeFork: // ActiveFork implements vm.activeFork:
......
...@@ -53,7 +53,9 @@ func NewForkDB(source ForkSource) *ForkDB { ...@@ -53,7 +53,9 @@ func NewForkDB(source ForkSource) *ForkDB {
// fakeRoot is just a marker; every account we load into the fork-db has this storage-root. // fakeRoot is just a marker; every account we load into the fork-db has this storage-root.
// When opening a storage-trie, we sanity-check we have this root, or an empty trie. // When opening a storage-trie, we sanity-check we have this root, or an empty trie.
// And then just return the same global trie view for storage reads/writes. // And then just return the same global trie view for storage reads/writes.
var fakeRoot = common.Hash{0: 42} // It needs to be set to EmptyRootHash to avoid contract collision errors when
// deploying contracts, since Geth checks the storage root prior to deployment.
var fakeRoot = types.EmptyRootHash
func (f *ForkDB) OpenTrie(root common.Hash) (state.Trie, error) { func (f *ForkDB) OpenTrie(root common.Hash) (state.Trie, error) {
if f.active.stateRoot != root { if f.active.stateRoot != root {
......
...@@ -54,8 +54,6 @@ func NewForkableState(base VMStateDB) *ForkableState { ...@@ -54,8 +54,6 @@ func NewForkableState(base VMStateDB) *ForkableState {
addresses.DefaultSenderAddr: ForkID{}, addresses.DefaultSenderAddr: ForkID{},
addresses.VMAddr: ForkID{}, addresses.VMAddr: ForkID{},
addresses.ConsoleAddr: ForkID{}, addresses.ConsoleAddr: ForkID{},
addresses.ScriptDeployer: ForkID{},
addresses.ForgeDeployer: ForkID{},
}, },
fallback: base, fallback: base,
idCounter: 0, idCounter: 0,
...@@ -194,11 +192,27 @@ func (fst *ForkableState) MakePersistent(addr common.Address) { ...@@ -194,11 +192,27 @@ func (fst *ForkableState) MakePersistent(addr common.Address) {
fst.persistent[addr] = fst.activeFork fst.persistent[addr] = fst.activeFork
} }
// MakeExcluded excludes an account from forking. This is useful for things like scripts, which
// should always use the fallback state.
func (fst *ForkableState) MakeExcluded(addr common.Address) {
fst.persistent[addr] = ForkID{}
}
// RevokePersistent is like vm.revokePersistent, it undoes a previous vm.makePersistent. // RevokePersistent is like vm.revokePersistent, it undoes a previous vm.makePersistent.
func (fst *ForkableState) RevokePersistent(addr common.Address) { func (fst *ForkableState) RevokePersistent(addr common.Address) {
delete(fst.persistent, addr) delete(fst.persistent, addr)
} }
// RevokeExcluded undoes MakeExcluded. It will panic if the account was marked as
// persistent in a different fork.
func (fst *ForkableState) RevokeExcluded(addr common.Address) {
forkID, ok := fst.persistent[addr]
if ok && forkID != (ForkID{}) {
panic(fmt.Sprintf("cannot revoke excluded account %s since it was made persistent in fork %q", addr, forkID))
}
delete(fst.persistent, addr)
}
// IsPersistent is like vm.isPersistent, it checks if an account persists across forks. // IsPersistent is like vm.isPersistent, it checks if an account persists across forks.
func (fst *ForkableState) IsPersistent(addr common.Address) bool { func (fst *ForkableState) IsPersistent(addr common.Address) bool {
_, ok := fst.persistent[addr] _, ok := fst.persistent[addr]
......
...@@ -9,7 +9,6 @@ import ( ...@@ -9,7 +9,6 @@ import (
"math/big" "math/big"
"github.com/ethereum-optimism/optimism/op-chain-ops/script/addresses" "github.com/ethereum-optimism/optimism/op-chain-ops/script/addresses"
"github.com/holiman/uint256" "github.com/holiman/uint256"
"github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi"
...@@ -850,3 +849,15 @@ func (h *Host) RememberOnLabel(label, srcFile, contract string) error { ...@@ -850,3 +849,15 @@ func (h *Host) RememberOnLabel(label, srcFile, contract string) error {
}) })
return nil return nil
} }
func (h *Host) CreateSelectFork(opts ...ForkOption) (*big.Int, error) {
src, err := h.onFork(opts...)
if err != nil {
return nil, fmt.Errorf("failed to setup fork source: %w", err)
}
id, err := h.state.CreateSelectFork(src)
if err != nil {
return nil, fmt.Errorf("failed to create-select fork: %w", err)
}
return id.U256().ToBig(), nil
}
...@@ -282,8 +282,8 @@ func TestForkingScript(t *testing.T) { ...@@ -282,8 +282,8 @@ func TestForkingScript(t *testing.T) {
addr, err := h.LoadContract("ScriptExample.s.sol", "ForkTester") addr, err := h.LoadContract("ScriptExample.s.sol", "ForkTester")
require.NoError(t, err) require.NoError(t, err)
h.AllowCheatcodes(addr) h.AllowCheatcodes(addr)
// Make this script persistent so it doesn't call the fork RPC. // Make this script excluded so it doesn't call the fork RPC.
h.state.MakePersistent(addr) h.state.MakeExcluded(addr)
t.Logf("allowing %s to access cheatcodes", addr) t.Logf("allowing %s to access cheatcodes", addr)
input := bytes4("run()") input := bytes4("run()")
......
...@@ -34,7 +34,7 @@ func WithScript[B any](h *Host, name string, contract string) (b *B, cleanup fun ...@@ -34,7 +34,7 @@ func WithScript[B any](h *Host, name string, contract string) (b *B, cleanup fun
addr := crypto.CreateAddress(deployer, deployNonce) addr := crypto.CreateAddress(deployer, deployNonce)
h.Label(addr, contract) h.Label(addr, contract)
h.AllowCheatcodes(addr) // before constructor execution, give our script cheatcode access h.AllowCheatcodes(addr) // before constructor execution, give our script cheatcode access
h.state.MakePersistent(addr) // scripts are persistent across forks h.state.MakeExcluded(addr) // scripts are persistent across forks
// init bindings (with ABI check) // init bindings (with ABI check)
bindings, err := MakeBindings[B](h.ScriptBackendFn(addr), func(abiDef string) bool { bindings, err := MakeBindings[B](h.ScriptBackendFn(addr), func(abiDef string) bool {
......
...@@ -7,11 +7,15 @@ import ( ...@@ -7,11 +7,15 @@ import (
"math/big" "math/big"
"strings" "strings"
"github.com/ethereum-optimism/optimism/op-chain-ops/foundry"
"github.com/ethereum-optimism/optimism/op-chain-ops/script"
"github.com/ethereum-optimism/optimism/op-chain-ops/script/forking"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/env" "github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
"github.com/ethereum-optimism/optimism/op-chain-ops/foundry"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -104,50 +108,43 @@ func Apply(ctx context.Context, cfg ApplyConfig) error { ...@@ -104,50 +108,43 @@ func Apply(ctx context.Context, cfg ApplyConfig) error {
return fmt.Errorf("failed to read state: %w", err) return fmt.Errorf("failed to read state: %w", err)
} }
var l1Client *ethclient.Client if err := ApplyPipeline(ctx, ApplyPipelineOpts{
var deployer common.Address L1RPCUrl: cfg.L1RPCUrl,
var bcaster broadcaster.Broadcaster DeployerPrivateKey: cfg.privateKeyECDSA,
var startingNonce uint64 Intent: intent,
if intent.DeploymentStrategy == state.DeploymentStrategyLive { State: st,
if err := cfg.CheckLive(); err != nil { Logger: cfg.Logger,
return fmt.Errorf("invalid config for apply: %w", err) StateWriter: pipeline.WorkdirStateWriter(cfg.Workdir),
} }); err != nil {
return 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) return nil
if err != nil { }
return fmt.Errorf("failed to get chain ID: %w", err)
}
signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(cfg.privateKeyECDSA, chainID)) type pipelineStage struct {
deployer = crypto.PubkeyToAddress(cfg.privateKeyECDSA.PublicKey) name string
apply func() error
}
bcaster, err = broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{ type ApplyPipelineOpts struct {
Logger: cfg.Logger, L1RPCUrl string
ChainID: new(big.Int).SetUint64(intent.L1ChainID), DeployerPrivateKey *ecdsa.PrivateKey
Client: l1Client, Intent *state.Intent
Signer: signer, State *state.State
From: deployer, Logger log.Logger
}) StateWriter pipeline.StateWriter
if err != nil { }
return fmt.Errorf("failed to create broadcaster: %w", err)
}
startingNonce, err = l1Client.NonceAt(ctx, deployer, nil) func ApplyPipeline(
if err != nil { ctx context.Context,
return fmt.Errorf("failed to get starting nonce: %w", err) opts ApplyPipelineOpts,
} ) error {
} else { intent := opts.Intent
deployer = common.Address{0x01} st := opts.State
bcaster = broadcaster.NoopBroadcaster()
}
progressor := func(curr, total int64) { progressor := func(curr, total int64) {
cfg.Logger.Info("artifacts download progress", "current", curr, "total", total) opts.Logger.Info("artifacts download progress", "current", curr, "total", total)
} }
l1ArtifactsFS, cleanupL1, err := artifacts.Download(ctx, intent.L1ContractsLocator, progressor) l1ArtifactsFS, cleanupL1, err := artifacts.Download(ctx, intent.L1ContractsLocator, progressor)
...@@ -156,7 +153,7 @@ func Apply(ctx context.Context, cfg ApplyConfig) error { ...@@ -156,7 +153,7 @@ func Apply(ctx context.Context, cfg ApplyConfig) error {
} }
defer func() { defer func() {
if err := cleanupL1(); err != nil { if err := cleanupL1(); err != nil {
cfg.Logger.Warn("failed to clean up L1 artifacts", "err", err) opts.Logger.Warn("failed to clean up L1 artifacts", "err", err)
} }
}() }()
...@@ -166,7 +163,7 @@ func Apply(ctx context.Context, cfg ApplyConfig) error { ...@@ -166,7 +163,7 @@ func Apply(ctx context.Context, cfg ApplyConfig) error {
} }
defer func() { defer func() {
if err := cleanupL2(); err != nil { if err := cleanupL2(); err != nil {
cfg.Logger.Warn("failed to clean up L2 artifacts", "err", err) opts.Logger.Warn("failed to clean up L2 artifacts", "err", err)
} }
}() }()
...@@ -175,52 +172,101 @@ func Apply(ctx context.Context, cfg ApplyConfig) error { ...@@ -175,52 +172,101 @@ func Apply(ctx context.Context, cfg ApplyConfig) error {
L2: l2ArtifactsFS, L2: l2ArtifactsFS,
} }
l1Host, err := env.DefaultScriptHost(bcaster, cfg.Logger, deployer, bundle.L1, startingNonce) var deployer common.Address
var bcaster broadcaster.Broadcaster
var l1Client *ethclient.Client
var l1Host *script.Host
if intent.DeploymentStrategy == state.DeploymentStrategyLive {
l1RPC, err := rpc.Dial(opts.L1RPCUrl)
if err != nil {
return fmt.Errorf("failed to connect to L1 RPC: %w", err)
}
l1Client = ethclient.NewClient(l1RPC)
chainID, err := l1Client.ChainID(ctx)
if err != nil {
return fmt.Errorf("failed to get chain ID: %w", err)
}
signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(opts.DeployerPrivateKey, chainID))
deployer = crypto.PubkeyToAddress(opts.DeployerPrivateKey.PublicKey)
bcaster, err = broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{
Logger: opts.Logger,
ChainID: new(big.Int).SetUint64(intent.L1ChainID),
Client: l1Client,
Signer: signer,
From: deployer,
})
if err != nil {
return fmt.Errorf("failed to create broadcaster: %w", err)
}
l1Host, err = env.DefaultScriptHost(
bcaster,
opts.Logger,
deployer,
bundle.L1,
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
}),
)
if err != nil { if err != nil {
return fmt.Errorf("failed to create L1 script host: %w", err) return fmt.Errorf("failed to create L1 script host: %w", err)
} }
env := &pipeline.Env{ latest, err := l1Client.HeaderByNumber(ctx, nil)
StateWriter: pipeline.WorkdirStateWriter(cfg.Workdir), 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)
}
} else {
deployer = common.Address{0x01}
bcaster = broadcaster.NoopBroadcaster()
l1Host, err = env.DefaultScriptHost(
bcaster,
opts.Logger,
deployer,
bundle.L1,
)
if err != nil {
return fmt.Errorf("failed to create L1 script host: %w", err)
}
}
pEnv := &pipeline.Env{
StateWriter: opts.StateWriter,
L1ScriptHost: l1Host, L1ScriptHost: l1Host,
L1Client: l1Client, L1Client: l1Client,
Logger: cfg.Logger, Logger: opts.Logger,
Broadcaster: bcaster, Broadcaster: bcaster,
Deployer: deployer, Deployer: deployer,
} }
if err := ApplyPipeline(ctx, env, bundle, intent, st); err != nil {
return err
}
return nil
}
type pipelineStage struct {
name string
apply func() error
}
func ApplyPipeline(
ctx context.Context,
env *pipeline.Env,
bundle pipeline.ArtifactsBundle,
intent *state.Intent,
st *state.State,
) error {
pline := []pipelineStage{ pline := []pipelineStage{
{"init", func() error { {"init", func() error {
if intent.DeploymentStrategy == state.DeploymentStrategyLive { if intent.DeploymentStrategy == state.DeploymentStrategyLive {
return pipeline.InitLiveStrategy(ctx, env, intent, st) return pipeline.InitLiveStrategy(ctx, pEnv, intent, st)
} else { } else {
return pipeline.InitGenesisStrategy(env, intent, st) return pipeline.InitGenesisStrategy(pEnv, intent, st)
} }
}}, }},
{"deploy-superchain", func() error { {"deploy-superchain", func() error {
return pipeline.DeploySuperchain(env, intent, st) return pipeline.DeploySuperchain(pEnv, intent, st)
}}, }},
{"deploy-implementations", func() error { {"deploy-implementations", func() error {
return pipeline.DeployImplementations(env, intent, st) return pipeline.DeployImplementations(pEnv, intent, st)
}}, }},
} }
...@@ -230,21 +276,17 @@ func ApplyPipeline( ...@@ -230,21 +276,17 @@ func ApplyPipeline(
pline = append(pline, pipelineStage{ pline = append(pline, pipelineStage{
fmt.Sprintf("deploy-opchain-%s", chainID.Hex()), fmt.Sprintf("deploy-opchain-%s", chainID.Hex()),
func() error { func() error {
if intent.DeploymentStrategy == state.DeploymentStrategyLive { return pipeline.DeployOPChain(pEnv, intent, st, chainID)
return pipeline.DeployOPChainLiveStrategy(ctx, env, bundle, intent, st, chainID)
} else {
return pipeline.DeployOPChainGenesisStrategy(env, intent, st, chainID)
}
}, },
}, pipelineStage{ }, pipelineStage{
fmt.Sprintf("deploy-alt-da-%s", chainID.Hex()), fmt.Sprintf("deploy-alt-da-%s", chainID.Hex()),
func() error { func() error {
return pipeline.DeployAltDA(env, intent, st, chainID) return pipeline.DeployAltDA(pEnv, intent, st, chainID)
}, },
}, pipelineStage{ }, pipelineStage{
fmt.Sprintf("generate-l2-genesis-%s", chainID.Hex()), fmt.Sprintf("generate-l2-genesis-%s", chainID.Hex()),
func() error { func() error {
return pipeline.GenerateL2Genesis(env, intent, bundle, st, chainID) return pipeline.GenerateL2Genesis(pEnv, intent, bundle, st, chainID)
}, },
}) })
} }
...@@ -257,9 +299,9 @@ func ApplyPipeline( ...@@ -257,9 +299,9 @@ func ApplyPipeline(
fmt.Sprintf("set-start-block-%s", chainID.Hex()), fmt.Sprintf("set-start-block-%s", chainID.Hex()),
func() error { func() error {
if intent.DeploymentStrategy == state.DeploymentStrategyLive { if intent.DeploymentStrategy == state.DeploymentStrategyLive {
return pipeline.SetStartBlockLiveStrategy(ctx, env, st, chainID) return pipeline.SetStartBlockLiveStrategy(ctx, pEnv, st, chainID)
} else { } else {
return pipeline.SetStartBlockGenesisStrategy(env, st, chainID) return pipeline.SetStartBlockGenesisStrategy(pEnv, st, chainID)
} }
}, },
}) })
...@@ -271,23 +313,27 @@ func ApplyPipeline( ...@@ -271,23 +313,27 @@ func ApplyPipeline(
if err := stage.apply(); err != nil { if err := stage.apply(); err != nil {
return fmt.Errorf("error in pipeline stage apply: %w", err) return fmt.Errorf("error in pipeline stage apply: %w", err)
} }
dump, err := env.L1ScriptHost.StateDump()
if intent.DeploymentStrategy == state.DeploymentStrategyGenesis {
dump, err := pEnv.L1ScriptHost.StateDump()
if err != nil { if err != nil {
return fmt.Errorf("failed to dump state: %w", err) return fmt.Errorf("failed to dump state: %w", err)
} }
st.L1StateDump = &state.GzipData[foundry.ForgeAllocs]{ st.L1StateDump = &state.GzipData[foundry.ForgeAllocs]{
Data: dump, Data: dump,
} }
if _, err := env.Broadcaster.Broadcast(ctx); err != nil { }
if _, err := pEnv.Broadcaster.Broadcast(ctx); err != nil {
return fmt.Errorf("failed to broadcast stage %s: %w", stage.name, err) return fmt.Errorf("failed to broadcast stage %s: %w", stage.name, err)
} }
if err := env.StateWriter.WriteState(st); err != nil { if err := pEnv.StateWriter.WriteState(st); err != nil {
return fmt.Errorf("failed to write state: %w", err) return fmt.Errorf("failed to write state: %w", err)
} }
} }
st.AppliedIntent = intent st.AppliedIntent = intent
if err := env.StateWriter.WriteState(st); err != nil { if err := pEnv.StateWriter.WriteState(st); err != nil {
return fmt.Errorf("failed to write state: %w", err) return fmt.Errorf("failed to write state: %w", err)
} }
......
...@@ -159,11 +159,11 @@ func DelayedWETH(ctx context.Context, cfg DelayedWETHConfig) error { ...@@ -159,11 +159,11 @@ func DelayedWETH(ctx context.Context, cfg DelayedWETHConfig) error {
lgr, lgr,
chainDeployer, chainDeployer,
artifactsFS, artifactsFS,
nonce,
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to create script host: %w", err) return fmt.Errorf("failed to create script host: %w", err)
} }
host.SetNonce(chainDeployer, nonce)
var release string var release string
if cfg.ArtifactsLocator.IsTag() { if cfg.ArtifactsLocator.IsTag() {
......
...@@ -162,11 +162,11 @@ func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error { ...@@ -162,11 +162,11 @@ func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error {
lgr, lgr,
chainDeployer, chainDeployer,
artifactsFS, artifactsFS,
nonce,
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to create script host: %w", err) return fmt.Errorf("failed to create script host: %w", err)
} }
host.SetNonce(chainDeployer, nonce)
var release string var release string
if cfg.ArtifactsLocator.IsTag() { if cfg.ArtifactsLocator.IsTag() {
......
...@@ -157,11 +157,11 @@ func MIPS(ctx context.Context, cfg MIPSConfig) error { ...@@ -157,11 +157,11 @@ func MIPS(ctx context.Context, cfg MIPSConfig) error {
lgr, lgr,
chainDeployer, chainDeployer,
artifactsFS, artifactsFS,
nonce,
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to create script host: %w", err) return fmt.Errorf("failed to create script host: %w", err)
} }
host.SetNonce(chainDeployer, nonce)
var release string var release string
if cfg.ArtifactsLocator.IsTag() { if cfg.ArtifactsLocator.IsTag() {
......
...@@ -193,11 +193,11 @@ func OPCM(ctx context.Context, cfg OPCMConfig) error { ...@@ -193,11 +193,11 @@ func OPCM(ctx context.Context, cfg OPCMConfig) error {
lgr, lgr,
chainDeployer, chainDeployer,
artifactsFS, artifactsFS,
nonce,
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to create script host: %w", err) return fmt.Errorf("failed to create script host: %w", err)
} }
host.SetNonce(chainDeployer, nonce)
var release string var release string
if cfg.ArtifactsLocator.IsTag() { if cfg.ArtifactsLocator.IsTag() {
......
...@@ -72,7 +72,6 @@ func L2SemversCLI(cliCtx *cli.Context) error { ...@@ -72,7 +72,6 @@ func L2SemversCLI(cliCtx *cli.Context) error {
l, l,
common.Address{19: 0x01}, common.Address{19: 0x01},
artifactsFS, artifactsFS,
0,
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to create script host: %w", err) return fmt.Errorf("failed to create script host: %w", err)
......
...@@ -21,7 +21,6 @@ func TestDeployAltDA(t *testing.T) { ...@@ -21,7 +21,6 @@ func TestDeployAltDA(t *testing.T) {
testlog.Logger(t, log.LevelInfo), testlog.Logger(t, log.LevelInfo),
common.Address{'D'}, common.Address{'D'},
artifacts, artifacts,
0,
) )
require.NoError(t, err) require.NoError(t, err)
......
...@@ -22,7 +22,6 @@ func TestDeployDelayedWETH(t *testing.T) { ...@@ -22,7 +22,6 @@ func TestDeployDelayedWETH(t *testing.T) {
testlog.Logger(t, log.LevelInfo), testlog.Logger(t, log.LevelInfo),
common.Address{'D'}, common.Address{'D'},
artifacts, artifacts,
0,
) )
require.NoError(t, err) require.NoError(t, err)
......
[
{
"type": "function",
"name": "decodeOutput",
"inputs": [],
"outputs": [
{
"name": "output",
"indexed": false,
"type": "tuple",
"components": [
{
"name": "opChainProxyAdmin",
"type": "address"
},
{
"name": "addressManager",
"type": "address"
},
{
"name": "l1ERC721BridgeProxy",
"type": "address"
},
{
"name": "systemConfigProxy",
"type": "address"
},
{
"name": "optimismMintableERC20FactoryProxy",
"type": "address"
},
{
"name": "l1StandardBridgeProxy",
"type": "address"
},
{
"name": "l1CrossDomainMessengerProxy",
"type": "address"
},
{
"name": "optimismPortalProxy",
"type": "address"
},
{
"name": "disputeGameFactoryProxy",
"type": "address"
},
{
"name": "anchorStateRegistryProxy",
"type": "address"
},
{
"name": "anchorStateRegistryImpl",
"type": "address"
},
{
"name": "faultDisputeGame",
"type": "address",
"internalType": "contract FaultDisputeGame"
},
{
"name": "permissionedDisputeGame",
"type": "address"
},
{
"name": "delayedWETHPermissionedGameProxy",
"type": "address"
},
{
"name": "delayedWETHPermissionlessGameProxy",
"type": "address"
}
]
}
]
}
]
\ No newline at end of file
...@@ -21,7 +21,6 @@ func TestDeployDisputeGame(t *testing.T) { ...@@ -21,7 +21,6 @@ func TestDeployDisputeGame(t *testing.T) {
testlog.Logger(t, log.LevelInfo), testlog.Logger(t, log.LevelInfo),
common.Address{'D'}, common.Address{'D'},
artifacts, artifacts,
0,
) )
require.NoError(t, err) require.NoError(t, err)
......
...@@ -20,7 +20,6 @@ func TestDeployMIPS(t *testing.T) { ...@@ -20,7 +20,6 @@ func TestDeployMIPS(t *testing.T) {
testlog.Logger(t, log.LevelInfo), testlog.Logger(t, log.LevelInfo),
common.Address{'D'}, common.Address{'D'},
artifacts, artifacts,
0,
) )
require.NoError(t, err) require.NoError(t, err)
......
This diff is collapsed.
...@@ -23,7 +23,6 @@ type Env struct { ...@@ -23,7 +23,6 @@ type Env struct {
L1ScriptHost *script.Host L1ScriptHost *script.Host
L1Client *ethclient.Client L1Client *ethclient.Client
Broadcaster broadcaster.Broadcaster Broadcaster broadcaster.Broadcaster
Host *script.Host
Deployer common.Address Deployer common.Address
Logger log.Logger Logger log.Logger
} }
......
...@@ -58,8 +58,6 @@ func DeployImplementations(env *Env, intent *state.Intent, st *state.State) erro ...@@ -58,8 +58,6 @@ func DeployImplementations(env *Env, intent *state.Intent, st *state.State) erro
return fmt.Errorf("error merging proof params from overrides: %w", err) return fmt.Errorf("error merging proof params from overrides: %w", err)
} }
env.L1ScriptHost.ImportState(st.L1StateDump.Data)
dio, err := opcm.DeployImplementations( dio, err := opcm.DeployImplementations(
env.L1ScriptHost, env.L1ScriptHost,
opcm.DeployImplementationsInput{ opcm.DeployImplementationsInput{
......
...@@ -3,7 +3,7 @@ package pipeline ...@@ -3,7 +3,7 @@ package pipeline
import ( import (
"fmt" "fmt"
env2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" "github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
"github.com/ethereum-optimism/optimism/op-chain-ops/foundry" "github.com/ethereum-optimism/optimism/op-chain-ops/foundry"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
...@@ -13,8 +13,8 @@ import ( ...@@ -13,8 +13,8 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
func GenerateL2Genesis(env *Env, intent *state.Intent, bundle ArtifactsBundle, st *state.State, chainID common.Hash) error { func GenerateL2Genesis(pEnv *Env, intent *state.Intent, bundle ArtifactsBundle, st *state.State, chainID common.Hash) error {
lgr := env.Logger.New("stage", "generate-l2-genesis") lgr := pEnv.Logger.New("stage", "generate-l2-genesis")
thisIntent, err := intent.Chain(chainID) thisIntent, err := intent.Chain(chainID)
if err != nil { if err != nil {
...@@ -38,12 +38,11 @@ func GenerateL2Genesis(env *Env, intent *state.Intent, bundle ArtifactsBundle, s ...@@ -38,12 +38,11 @@ func GenerateL2Genesis(env *Env, intent *state.Intent, bundle ArtifactsBundle, s
return fmt.Errorf("failed to combine L2 init config: %w", err) return fmt.Errorf("failed to combine L2 init config: %w", err)
} }
host, err := env2.DefaultScriptHost( host, err := env.DefaultScriptHost(
broadcaster.NoopBroadcaster(), broadcaster.NoopBroadcaster(),
env.Logger, pEnv.Logger,
env.Deployer, pEnv.Deployer,
bundle.L2, bundle.L2,
0,
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to create L2 script host: %w", err) return fmt.Errorf("failed to create L2 script host: %w", err)
...@@ -60,7 +59,7 @@ func GenerateL2Genesis(env *Env, intent *state.Intent, bundle ArtifactsBundle, s ...@@ -60,7 +59,7 @@ func GenerateL2Genesis(env *Env, intent *state.Intent, bundle ArtifactsBundle, s
return fmt.Errorf("failed to call L2Genesis script: %w", err) return fmt.Errorf("failed to call L2Genesis script: %w", err)
} }
host.Wipe(env.Deployer) host.Wipe(pEnv.Deployer)
dump, err := host.StateDump() dump, err := host.StateDump()
if err != nil { if err != nil {
......
...@@ -172,7 +172,7 @@ func SystemOwnerAddrFor(chainID uint64) (common.Address, error) { ...@@ -172,7 +172,7 @@ func SystemOwnerAddrFor(chainID uint64) (common.Address, error) {
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":
return url.Parse(standardArtifactsURL("ee07c78c3d8d4cd8f7a933c050f5afeebaa281b57b226cc6f092b19de2a8d61f")) return url.Parse(standardArtifactsURL("3a27c6dc0cb61b36feaac26def98c64b4a48ec8f5c5ba6965e8ae3157606043c"))
case "op-contracts/v1.7.0-beta.1+l2-contracts": case "op-contracts/v1.7.0-beta.1+l2-contracts":
return url.Parse(standardArtifactsURL("b0fb1f6f674519d637cff39a22187a5993d7f81a6d7b7be6507a0b50a5e38597")) return url.Parse(standardArtifactsURL("b0fb1f6f674519d637cff39a22187a5993d7f81a6d7b7be6507a0b50a5e38597"))
default: default:
......
...@@ -16,7 +16,7 @@ func DefaultScriptHost( ...@@ -16,7 +16,7 @@ func DefaultScriptHost(
lgr log.Logger, lgr log.Logger,
deployer common.Address, deployer common.Address,
artifacts foundry.StatDirFs, artifacts foundry.StatDirFs,
startingNonce uint64, additionalOpts ...script.HostOption,
) (*script.Host, error) { ) (*script.Host, error) {
scriptCtx := script.DefaultContext scriptCtx := script.DefaultContext
scriptCtx.Sender = deployer scriptCtx.Sender = deployer
...@@ -26,16 +26,16 @@ func DefaultScriptHost( ...@@ -26,16 +26,16 @@ func DefaultScriptHost(
&foundry.ArtifactsFS{FS: artifacts}, &foundry.ArtifactsFS{FS: artifacts},
nil, nil,
scriptCtx, scriptCtx,
append([]script.HostOption{
script.WithBroadcastHook(bcaster.Hook), script.WithBroadcastHook(bcaster.Hook),
script.WithIsolatedBroadcasts(), script.WithIsolatedBroadcasts(),
script.WithCreate2Deployer(), script.WithCreate2Deployer(),
}, additionalOpts...)...,
) )
if err := h.EnableCheats(); err != nil { if err := h.EnableCheats(); err != nil {
return nil, fmt.Errorf("failed to enable cheats: %w", err) return nil, fmt.Errorf("failed to enable cheats: %w", err)
} }
h.SetNonce(deployer, startingNonce)
return h, nil return h, nil
} }
...@@ -235,7 +235,7 @@ contract DeployOPChainOutput is BaseDeployIO { ...@@ -235,7 +235,7 @@ contract DeployOPChainOutput is BaseDeployIO {
IDelayedWETH internal _delayedWETHPermissionedGameProxy; IDelayedWETH internal _delayedWETHPermissionedGameProxy;
IDelayedWETH internal _delayedWETHPermissionlessGameProxy; IDelayedWETH internal _delayedWETHPermissionlessGameProxy;
function set(bytes4 _sel, address _addr) public { function set(bytes4 _sel, address _addr) public virtual {
require(_addr != address(0), "DeployOPChainOutput: cannot set zero address"); require(_addr != address(0), "DeployOPChainOutput: cannot set zero address");
// forgefmt: disable-start // forgefmt: disable-start
if (_sel == this.opChainProxyAdmin.selector) _opChainProxyAdmin = IProxyAdmin(_addr) ; if (_sel == this.opChainProxyAdmin.selector) _opChainProxyAdmin = IProxyAdmin(_addr) ;
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol";
import { IProxy } from "src/universal/interfaces/IProxy.sol";
import { Script } from "forge-std/Script.sol";
import { DeployUtils } from "scripts/libraries/DeployUtils.sol";
import { DeployOPChainOutput } from "scripts/deploy/DeployOPChain.s.sol";
import { IMIPS } from "src/cannon/interfaces/IMIPS.sol";
import { OPContractsManager } from "src/L1/OPContractsManager.sol";
import { IAddressManager } from "src/legacy/interfaces/IAddressManager.sol";
import { IStaticL1ChugSplashProxy } from "src/legacy/interfaces/IL1ChugSplashProxy.sol";
contract ReadImplementationAddressesInput is DeployOPChainOutput {
OPContractsManager internal _opcmProxy;
string internal _release;
function set(bytes4 _sel, address _addr) public override {
require(_addr != address(0), "ReadImplementationAddressesInput: cannot set zero address");
if (_sel == this.opcmProxy.selector) _opcmProxy = OPContractsManager(_addr);
else if (_sel == this.addressManager.selector) _addressManager = IAddressManager(_addr);
else super.set(_sel, _addr);
}
function set(bytes4 _sel, string memory _val) public {
if (_sel == this.release.selector) _release = _val;
else revert("ReadImplementationAddressesInput: unknown selector");
}
function opcmProxy() public view returns (OPContractsManager) {
DeployUtils.assertValidContractAddress(address(_opcmProxy));
return _opcmProxy;
}
function release() public view returns (string memory) {
require(bytes(_release).length != 0, "ReadImplementationAddressesInput: release not set");
return _release;
}
}
contract ReadImplementationAddressesOutput is BaseDeployIO {
address internal _delayedWETH;
address internal _optimismPortal;
address internal _systemConfig;
address internal _l1CrossDomainMessenger;
address internal _l1ERC721Bridge;
address internal _l1StandardBridge;
address internal _optimismMintableERC20Factory;
address internal _disputeGameFactory;
address internal _mipsSingleton;
address internal _preimageOracleSingleton;
function set(bytes4 _sel, address _addr) public {
require(_addr != address(0), "ReadImplementationAddressesOutput: cannot set zero address");
if (_sel == this.delayedWETH.selector) _delayedWETH = _addr;
else if (_sel == this.optimismPortal.selector) _optimismPortal = _addr;
else if (_sel == this.systemConfig.selector) _systemConfig = _addr;
else if (_sel == this.l1CrossDomainMessenger.selector) _l1CrossDomainMessenger = _addr;
else if (_sel == this.l1ERC721Bridge.selector) _l1ERC721Bridge = _addr;
else if (_sel == this.l1StandardBridge.selector) _l1StandardBridge = _addr;
else if (_sel == this.optimismMintableERC20Factory.selector) _optimismMintableERC20Factory = _addr;
else if (_sel == this.disputeGameFactory.selector) _disputeGameFactory = _addr;
else if (_sel == this.mipsSingleton.selector) _mipsSingleton = _addr;
else if (_sel == this.preimageOracleSingleton.selector) _preimageOracleSingleton = _addr;
else revert("ReadImplementationAddressesOutput: unknown selector");
}
function delayedWETH() public view returns (address) {
require(_delayedWETH != address(0), "ReadImplementationAddressesOutput: delayedWETH not set");
return _delayedWETH;
}
function optimismPortal() public view returns (address) {
require(_optimismPortal != address(0), "ReadImplementationAddressesOutput: optimismPortal not set");
return _optimismPortal;
}
function systemConfig() public view returns (address) {
require(_systemConfig != address(0), "ReadImplementationAddressesOutput: systemConfig not set");
return _systemConfig;
}
function l1CrossDomainMessenger() public view returns (address) {
require(
_l1CrossDomainMessenger != address(0), "ReadImplementationAddressesOutput: l1CrossDomainMessenger not set"
);
return _l1CrossDomainMessenger;
}
function l1ERC721Bridge() public view returns (address) {
require(_l1ERC721Bridge != address(0), "ReadImplementationAddressesOutput: l1ERC721Bridge not set");
return _l1ERC721Bridge;
}
function l1StandardBridge() public view returns (address) {
require(_l1StandardBridge != address(0), "ReadImplementationAddressesOutput: l1StandardBridge not set");
return _l1StandardBridge;
}
function optimismMintableERC20Factory() public view returns (address) {
require(
_optimismMintableERC20Factory != address(0),
"ReadImplementationAddressesOutput: optimismMintableERC20Factory not set"
);
return _optimismMintableERC20Factory;
}
function disputeGameFactory() public view returns (address) {
require(_disputeGameFactory != address(0), "ReadImplementationAddressesOutput: disputeGameFactory not set");
return _disputeGameFactory;
}
function mipsSingleton() public view returns (address) {
require(_mipsSingleton != address(0), "ReadImplementationAddressesOutput: mipsSingleton not set");
return _mipsSingleton;
}
function preimageOracleSingleton() public view returns (address) {
require(
_preimageOracleSingleton != address(0), "ReadImplementationAddressesOutput: preimageOracleSingleton not set"
);
return _preimageOracleSingleton;
}
}
contract ReadImplementationAddresses is Script {
function run(ReadImplementationAddressesInput _rii, ReadImplementationAddressesOutput _rio) public {
address[6] memory eip1967Proxies = [
address(_rii.delayedWETHPermissionedGameProxy()),
address(_rii.optimismPortalProxy()),
address(_rii.systemConfigProxy()),
address(_rii.l1ERC721BridgeProxy()),
address(_rii.optimismMintableERC20FactoryProxy()),
address(_rii.disputeGameFactoryProxy())
];
bytes4[6] memory sels = [
_rio.delayedWETH.selector,
_rio.optimismPortal.selector,
_rio.systemConfig.selector,
_rio.l1ERC721Bridge.selector,
_rio.optimismMintableERC20Factory.selector,
_rio.disputeGameFactory.selector
];
for (uint256 i = 0; i < eip1967Proxies.length; i++) {
IProxy proxy = IProxy(payable(eip1967Proxies[i]));
vm.prank(address(0));
_rio.set(sels[i], proxy.implementation());
}
vm.prank(address(0));
address l1SBImpl = IStaticL1ChugSplashProxy(address(_rii.l1StandardBridgeProxy())).getImplementation();
vm.prank(address(0));
_rio.set(_rio.l1StandardBridge.selector, l1SBImpl);
(address mipsLogic,) = _rii.opcmProxy().implementations(_rii.release(), "MIPS");
_rio.set(_rio.mipsSingleton.selector, mipsLogic);
IAddressManager am = _rii.addressManager();
_rio.set(_rio.l1CrossDomainMessenger.selector, am.getAddress("OVM_L1CrossDomainMessenger"));
address preimageOracle = address(IMIPS(mipsLogic).oracle());
_rio.set(_rio.preimageOracleSingleton.selector, preimageOracle);
}
}
...@@ -44,7 +44,11 @@ else ...@@ -44,7 +44,11 @@ else
tar="tar" tar="tar"
fi fi
"$tar" -czf "$archive_name" artifacts forge-artifacts cache rm -f COMMIT
commit=$(git rev-parse HEAD)
echo "$commit" > COMMIT
"$tar" -czf "$archive_name" artifacts forge-artifacts cache COMMIT
du -sh "$archive_name" | awk '{$1=$1};1' # trim leading whitespace du -sh "$archive_name" | awk '{$1=$1};1' # trim leading whitespace
echoerr "> Done." echoerr "> Done."
...@@ -53,3 +57,4 @@ gcloud storage cp "$archive_name" "gs://$DEPLOY_BUCKET/$archive_name" ...@@ -53,3 +57,4 @@ gcloud storage cp "$archive_name" "gs://$DEPLOY_BUCKET/$archive_name"
echoerr "> Done." echoerr "> Done."
rm "$archive_name" rm "$archive_name"
rm COMMIT
\ No newline at end of file
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