Commit c05aca35 authored by Blaine Malone's avatar Blaine Malone Committed by GitHub

opcm: exposing preimage oracle and mips singletons via DeployOPChain.s.sol (#12521)

* opcm: exposing preimage oracle and mips singletons via DeployOPChain.s.sol

* fix: new approach using opcm to grab mips singleton.

* fix: small cleanup to contracts.go.

* fix: more error checking

* fix: semgrep fix.

* fix: small rename
parent 7bd0370c
......@@ -32,8 +32,8 @@ func (c *Contract) getAddress(ctx context.Context, name string) (common.Address,
return c.callContractMethod(ctx, name, abi.Arguments{})
}
// Used to call getAddress(string) on legacy ResolvedDelegateProxy contract
func (c *Contract) GetAddressByName(ctx context.Context, name string) (common.Address, error) {
// Used to call getAddress(string) on legacy AddressManager contract
func (c *Contract) GetAddressByNameViaAddressManager(ctx context.Context, name string) (common.Address, error) {
inputs := abi.Arguments{
abi.Argument{
Name: "_name",
......@@ -44,6 +44,61 @@ func (c *Contract) GetAddressByName(ctx context.Context, name string) (common.Ad
return c.callContractMethod(ctx, "getAddress", inputs, name)
}
func (c *Contract) GenericAddressGetter(ctx context.Context, functionName string) (common.Address, error) {
return c.callContractMethod(ctx, functionName, abi.Arguments{})
}
// GetImplementation retrieves the Implementation struct for a given release and contract name.
func (c *Contract) GetOPCMImplementationAddress(ctx context.Context, release, contractName string) (common.Address, error) {
methodName := "implementations"
method := abi.NewMethod(
methodName,
methodName,
abi.Function,
"view",
true,
false,
abi.Arguments{
{Name: "release", Type: mustType("string")},
{Name: "contractName", Type: mustType("string")},
},
abi.Arguments{
{Name: "logic", Type: mustType("address")},
{Name: "initializer", Type: mustType("bytes4")},
},
)
calldata, err := method.Inputs.Pack(release, contractName)
if err != nil {
return common.Address{}, fmt.Errorf("failed to pack inputs: %w", err)
}
msg := ethereum.CallMsg{
To: &c.addr,
Data: append(bytes.Clone(method.ID), calldata...),
}
result, err := c.client.CallContract(ctx, msg, nil)
if err != nil {
return common.Address{}, fmt.Errorf("failed to call contract: %w", err)
}
out, err := method.Outputs.Unpack(result)
if err != nil {
return common.Address{}, fmt.Errorf("failed to unpack result: %w", err)
}
if len(out) != 2 {
return common.Address{}, fmt.Errorf("unexpected output length: %d", len(out))
}
logic, ok := out[0].(common.Address)
if !ok {
return common.Address{}, fmt.Errorf("unexpected type for logic: %T", out[0])
}
return logic, nil
}
func (c *Contract) callContractMethod(ctx context.Context, methodName string, inputs abi.Arguments, args ...interface{}) (common.Address, error) {
method := abi.NewMethod(
methodName,
......
......@@ -3,6 +3,7 @@ package pipeline
import (
"context"
"encoding/hex"
"errors"
"fmt"
"math/big"
......@@ -18,7 +19,7 @@ import (
func DeployOPChain(ctx context.Context, env *Env, bundle ArtifactsBundle, intent *state2.Intent, st *state2.State, chainID common.Hash) error {
lgr := env.Logger.New("stage", "deploy-opchain")
if !shouldDeployOPChain(intent, st, chainID) {
if !shouldDeployOPChain(st, chainID) {
lgr.Info("opchain deployment not needed")
return nil
}
......@@ -30,6 +31,8 @@ func DeployOPChain(ctx context.Context, env *Env, bundle ArtifactsBundle, intent
return fmt.Errorf("failed to get chain intent: %w", err)
}
opcmProxyAddress := st.ImplementationsDeployment.OpcmProxyAddress
input := opcm.DeployOPChainInput{
OpChainProxyAdminOwner: thisIntent.Roles.ProxyAdminOwner,
SystemConfigOwner: thisIntent.Roles.SystemConfigOwner,
......@@ -40,7 +43,7 @@ func DeployOPChain(ctx context.Context, env *Env, bundle ArtifactsBundle, intent
BasefeeScalar: 1368,
BlobBaseFeeScalar: 801949,
L2ChainId: chainID.Big(),
OpcmProxy: st.ImplementationsDeployment.OpcmProxyAddress,
OpcmProxy: opcmProxyAddress,
SaltMixer: st.Create2Salt.String(), // passing through salt generated at state initialization
GasLimit: 60_000_000,
DisputeGameType: 1, // PERMISSIONED_CANNON Game Type
......@@ -52,7 +55,7 @@ func DeployOPChain(ctx context.Context, env *Env, bundle ArtifactsBundle, intent
}
var dco opcm.DeployOPChainOutput
lgr.Info("deploying using existing OPCM", "address", st.ImplementationsDeployment.OpcmProxyAddress.Hex())
lgr.Info("deploying using existing OPCM", "address", opcmProxyAddress.Hex())
bcaster, err := broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{
Logger: lgr,
ChainID: big.NewInt(int64(intent.L1ChainID)),
......@@ -94,7 +97,22 @@ func DeployOPChain(ctx context.Context, env *Env, bundle ArtifactsBundle, intent
DelayedWETHPermissionlessGameProxyAddress: dco.DelayedWETHPermissionlessGameProxy,
})
block, err := env.L1Client.BlockByNumber(ctx, nil)
err = conditionallySetImplementationAddresses(ctx, env.L1Client, intent, st, dco, opcmProxyAddress)
if err != nil {
return fmt.Errorf("failed to set implementation addresses: %w", err)
}
return nil
}
// Only try to set the implementation addresses if we reused existing implementations from a release tag.
// The reason why these addresses could be empty is because only DeployOPChain.s.sol is invoked as part of the pipeline.
func conditionallySetImplementationAddresses(ctx context.Context, client *ethclient.Client, intent *state2.Intent, st *state.State, dco opcm.DeployOPChainOutput, opcmProxyAddress common.Address) error {
if !intent.L1ContractsLocator.IsTag() {
return nil
}
block, err := client.BlockByNumber(ctx, nil)
if err != nil {
return fmt.Errorf("failed to get latest block by number: %w", err)
}
......@@ -102,36 +120,37 @@ func DeployOPChain(ctx context.Context, env *Env, bundle ArtifactsBundle, intent
errCh := make(chan error, 8)
// If any of the implementations addresses (excluding OpcmProxy) are empty,
// we need to set them using the implementation address read from their corresponding proxy.
// The reason these might be empty is because we're only invoking DeployOPChain.s.sol as part of the pipeline.
// TODO: Need to initialize 'mipsSingletonAddress' and 'preimageOracleSingletonAddress'
setImplementationAddressTasks := []func(){
func() {
setEIP1967ImplementationAddress(ctx, env.L1Client, errCh, dco.DelayedWETHPermissionedGameProxy, currentBlockHash, &st.ImplementationsDeployment.DelayedWETHImplAddress)
setEIP1967ImplementationAddress(ctx, client, errCh, dco.DelayedWETHPermissionedGameProxy, currentBlockHash, &st.ImplementationsDeployment.DelayedWETHImplAddress)
},
func() {
setEIP1967ImplementationAddress(ctx, env.L1Client, errCh, dco.OptimismPortalProxy, currentBlockHash, &st.ImplementationsDeployment.OptimismPortalImplAddress)
setEIP1967ImplementationAddress(ctx, client, errCh, dco.OptimismPortalProxy, currentBlockHash, &st.ImplementationsDeployment.OptimismPortalImplAddress)
},
func() {
setEIP1967ImplementationAddress(ctx, env.L1Client, errCh, dco.SystemConfigProxy, currentBlockHash, &st.ImplementationsDeployment.SystemConfigImplAddress)
setEIP1967ImplementationAddress(ctx, client, errCh, dco.SystemConfigProxy, currentBlockHash, &st.ImplementationsDeployment.SystemConfigImplAddress)
},
func() {
setRDPImplementationAddress(ctx, env.L1Client, errCh, dco.AddressManager, &st.ImplementationsDeployment.L1CrossDomainMessengerImplAddress)
setRDPImplementationAddress(ctx, client, errCh, dco.AddressManager, &st.ImplementationsDeployment.L1CrossDomainMessengerImplAddress, "OVM_L1CrossDomainMessenger")
},
func() {
setEIP1967ImplementationAddress(ctx, env.L1Client, errCh, dco.L1ERC721BridgeProxy, currentBlockHash, &st.ImplementationsDeployment.L1ERC721BridgeImplAddress)
setEIP1967ImplementationAddress(ctx, client, errCh, dco.L1ERC721BridgeProxy, currentBlockHash, &st.ImplementationsDeployment.L1ERC721BridgeImplAddress)
},
func() {
setEIP1967ImplementationAddress(ctx, env.L1Client, errCh, dco.L1StandardBridgeProxy, currentBlockHash, &st.ImplementationsDeployment.L1StandardBridgeImplAddress)
setEIP1967ImplementationAddress(ctx, client, errCh, dco.L1StandardBridgeProxy, currentBlockHash, &st.ImplementationsDeployment.L1StandardBridgeImplAddress)
},
func() {
setEIP1967ImplementationAddress(ctx, env.L1Client, errCh, dco.OptimismMintableERC20FactoryProxy, currentBlockHash, &st.ImplementationsDeployment.OptimismMintableERC20FactoryImplAddress)
setEIP1967ImplementationAddress(ctx, client, errCh, dco.OptimismMintableERC20FactoryProxy, currentBlockHash, &st.ImplementationsDeployment.OptimismMintableERC20FactoryImplAddress)
},
func() {
setEIP1967ImplementationAddress(ctx, env.L1Client, errCh, dco.DisputeGameFactoryProxy, currentBlockHash, &st.ImplementationsDeployment.DisputeGameFactoryImplAddress)
setEIP1967ImplementationAddress(ctx, client, errCh, dco.DisputeGameFactoryProxy, currentBlockHash, &st.ImplementationsDeployment.DisputeGameFactoryImplAddress)
},
func() {
setMipsSingletonAddress(ctx, client, intent.L1ContractsLocator, errCh, opcmProxyAddress, &st.ImplementationsDeployment.MipsSingletonAddress)
setPreimageOracleAddress(ctx, client, errCh, st.ImplementationsDeployment.MipsSingletonAddress, &st.ImplementationsDeployment.PreimageOracleSingletonAddress)
},
}
for _, task := range setImplementationAddressTasks {
go task()
}
......@@ -147,17 +166,42 @@ func DeployOPChain(ctx context.Context, env *Env, bundle ArtifactsBundle, intent
return fmt.Errorf("failed to set implementation addresses: %w", lastTaskErr)
}
fmt.Printf("st.ImplementationsDeployment: %+v\n", st.ImplementationsDeployment)
return nil
}
func setRDPImplementationAddress(ctx context.Context, client *ethclient.Client, errCh chan error, addressManager common.Address, implAddress *common.Address) {
func setMipsSingletonAddress(ctx context.Context, client *ethclient.Client, l1ArtifactsLocator *opcm.ArtifactsLocator, errCh chan error, opcmProxyAddress common.Address, singletonAddress *common.Address) {
if !l1ArtifactsLocator.IsTag() {
errCh <- errors.New("L1 contracts locator is not a tag, cannot set MIPS singleton address")
return
}
opcmContract := opcm.NewContract(opcmProxyAddress, client)
mipsSingletonAddress, err := opcmContract.GetOPCMImplementationAddress(ctx, l1ArtifactsLocator.Tag, "MIPS")
if err == nil {
*singletonAddress = mipsSingletonAddress
}
errCh <- err
}
func setPreimageOracleAddress(ctx context.Context, client *ethclient.Client, errCh chan error, mipsSingletonAddress common.Address, preimageOracleAddress *common.Address) {
opcmContract := opcm.NewContract(mipsSingletonAddress, client)
preimageOracle, err := opcmContract.GenericAddressGetter(ctx, "oracle")
if err == nil {
*preimageOracleAddress = preimageOracle
}
errCh <- err
}
func setRDPImplementationAddress(ctx context.Context, client *ethclient.Client, errCh chan error, addressManager common.Address, implAddress *common.Address, getNameArg string) {
if *implAddress != (common.Address{}) {
errCh <- nil
return
}
contract := opcm.NewContract(addressManager, client)
address, err := contract.GetAddressByName(ctx, "OVM_L1CrossDomainMessenger")
addressManagerContract := opcm.NewContract(addressManager, client)
address, err := addressManagerContract.GetAddressByNameViaAddressManager(ctx, getNameArg)
if err == nil {
*implAddress = address
}
......@@ -177,7 +221,7 @@ func setEIP1967ImplementationAddress(ctx context.Context, client *ethclient.Clie
errCh <- err
}
func shouldDeployOPChain(intent *state.Intent, st *state.State, chainID common.Hash) bool {
func shouldDeployOPChain(st *state.State, chainID common.Hash) bool {
for _, chain := range st.Chains {
if chain.ID == chainID {
return false
......
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