Skip to content

Commit

Permalink
op-deployer: Refactor semver inspector, add L2 genesis test (#12946)
Browse files Browse the repository at this point in the history
- Refactor the semver inspector so that it can be called from outside the CLI
- Adds a a canonical L2 genesis file for v1.6.0, and a unit test to assert that new chains deployed using v1.6.0 have the right L2 genesis.
  • Loading branch information
mslipper authored Nov 18, 2024
1 parent f6810a4 commit f94151b
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 54 deletions.
16 changes: 16 additions & 0 deletions op-deployer/pkg/deployer/artifacts/locator.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,22 @@ var DefaultL2ContractsLocator = &Locator{
Tag: standard.DefaultL2ContractsTag,
}

func NewLocatorFromTag(tag string) (*Locator, error) {
loc := new(Locator)
if err := loc.UnmarshalText([]byte("tag://" + tag)); err != nil {
return nil, fmt.Errorf("failed to unmarshal tag: %w", err)
}
return loc, nil
}

func MustNewLocatorFromTag(tag string) *Locator {
loc, err := NewLocatorFromTag(tag)
if err != nil {
panic(err)
}
return loc
}

type Locator struct {
URL *url.URL
Tag string
Expand Down
164 changes: 112 additions & 52 deletions op-deployer/pkg/deployer/inspect/semvers.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import (
"regexp"
"time"

"github.com/ethereum-optimism/optimism/op-chain-ops/foundry"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state"
"github.com/ethereum/go-ethereum/log"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
Expand All @@ -25,8 +29,6 @@ import (
"github.com/urfave/cli/v2"
)

var versionSelector = []byte{0x54, 0xfd, 0x4d, 0x50}

func L2SemversCLI(cliCtx *cli.Context) error {
cliCfg, err := readConfig(cliCtx)
if err != nil {
Expand Down Expand Up @@ -67,92 +69,150 @@ func L2SemversCLI(cliCtx *cli.Context) error {
}
}()

ps, err := L2Semvers(L2SemversConfig{
Lgr: l,
Artifacts: artifactsFS,
ChainState: chainState,
})
if err != nil {
return fmt.Errorf("failed to get L2 semvers: %w", err)
}

if err := jsonutil.WriteJSON(ps, ioutil.ToStdOutOrFileOrNoop(cliCfg.Outfile, 0o666)); err != nil {
return fmt.Errorf("failed to write rollup config: %w", err)
}

return nil
}

type L2SemversConfig struct {
Lgr log.Logger
Artifacts foundry.StatDirFs
ChainState *state.ChainState
}

type L2PredeploySemvers struct {
L2ToL1MessagePasser string
DeployerWhitelist string
WETH string
L2CrossDomainMessenger string
L2StandardBridge string
SequencerFeeVault string
OptimismMintableERC20Factory string
L1BlockNumber string
GasPriceOracle string
L1Block string
LegacyMessagePasser string
L2ERC721Bridge string
OptimismMintableERC721Factory string
BaseFeeVault string
L1FeeVault string
SchemaRegistry string
EAS string
CrossL2Inbox string
L2toL2CrossDomainMessenger string
SuperchainWETH string
ETHLiquidity string
SuperchainTokenBridge string
OptimismMintableERC20 string
OptimismMintableERC721 string
}

func L2Semvers(cfg L2SemversConfig) (*L2PredeploySemvers, error) {
l := cfg.Lgr
artifactsFS := cfg.Artifacts
chainState := cfg.ChainState

host, err := env.DefaultScriptHost(
broadcaster.NoopBroadcaster(),
l,
common.Address{19: 0x01},
artifactsFS,
)
if err != nil {
return fmt.Errorf("failed to create script host: %w", err)
return nil, fmt.Errorf("failed to create script host: %w", err)
}
host.ImportState(chainState.Allocs.Data)

addr := common.Address{19: 0x01}

type contractToCheck struct {
Address common.Address
Name string
Address common.Address
FieldPtr *string
Name string
}

contractsOutput := make(map[string]string)
var ps L2PredeploySemvers

// The gov token and the proxy admin do not have semvers.
contracts := []contractToCheck{
{predeploys.L2ToL1MessagePasserAddr, "L2ToL1MessagePasser"},
{predeploys.DeployerWhitelistAddr, "DeployerWhitelist"},
{predeploys.WETHAddr, "WETH"},
{predeploys.L2CrossDomainMessengerAddr, "L2CrossDomainMessenger"},
{predeploys.L2StandardBridgeAddr, "L2StandardBridge"},
{predeploys.SequencerFeeVaultAddr, "SequencerFeeVault"},
{predeploys.OptimismMintableERC20FactoryAddr, "OptimismMintableERC20Factory"},
{predeploys.L1BlockNumberAddr, "L1BlockNumber"},
{predeploys.GasPriceOracleAddr, "GasPriceOracle"},
{predeploys.L1BlockAddr, "L1Block"},
{predeploys.LegacyMessagePasserAddr, "LegacyMessagePasser"},
{predeploys.L2ERC721BridgeAddr, "L2ERC721Bridge"},
{predeploys.OptimismMintableERC721FactoryAddr, "OptimismMintableERC721Factory"},
{predeploys.BaseFeeVaultAddr, "BaseFeeVault"},
{predeploys.L1FeeVaultAddr, "L1FeeVault"},
{predeploys.SchemaRegistryAddr, "SchemaRegistry"},
{predeploys.EASAddr, "EAS"},
{predeploys.WETHAddr, "WETH"},
{predeploys.L2ToL1MessagePasserAddr, &ps.L2ToL1MessagePasser, "L2ToL1MessagePasser"},
{predeploys.DeployerWhitelistAddr, &ps.DeployerWhitelist, "DeployerWhitelist"},
{predeploys.WETHAddr, &ps.WETH, "WETH"},
{predeploys.L2CrossDomainMessengerAddr, &ps.L2CrossDomainMessenger, "L2CrossDomainMessenger"},
{predeploys.L2StandardBridgeAddr, &ps.L2StandardBridge, "L2StandardBridge"},
{predeploys.SequencerFeeVaultAddr, &ps.SequencerFeeVault, "SequencerFeeVault"},
{predeploys.OptimismMintableERC20FactoryAddr, &ps.OptimismMintableERC20Factory, "OptimismMintableERC20Factory"},
{predeploys.L1BlockNumberAddr, &ps.L1BlockNumber, "L1BlockNumber"},
{predeploys.GasPriceOracleAddr, &ps.GasPriceOracle, "GasPriceOracle"},
{predeploys.L1BlockAddr, &ps.L1Block, "L1Block"},
{predeploys.LegacyMessagePasserAddr, &ps.LegacyMessagePasser, "LegacyMessagePasser"},
{predeploys.L2ERC721BridgeAddr, &ps.L2ERC721Bridge, "L2ERC721Bridge"},
{predeploys.OptimismMintableERC721FactoryAddr, &ps.OptimismMintableERC721Factory, "OptimismMintableERC721Factory"},
{predeploys.BaseFeeVaultAddr, &ps.BaseFeeVault, "BaseFeeVault"},
{predeploys.L1FeeVaultAddr, &ps.L1FeeVault, "L1FeeVault"},
{predeploys.SchemaRegistryAddr, &ps.SchemaRegistry, "SchemaRegistry"},
{predeploys.EASAddr, &ps.EAS, "EAS"},
}
for _, contract := range contracts {
data, _, err := host.Call(
addr,
contract.Address,
bytes.Clone(versionSelector),
1_000_000_000,
uint256.NewInt(0),
)
semver, err := ReadSemver(host, contract.Address)
if err != nil {
return fmt.Errorf("failed to call version on %s: %w", contract.Name, err)
}

// The second 32 bytes contain the length of the string
length := new(big.Int).SetBytes(data[32:64]).Int64()
// Start of the string data (after offset and length)
stringStart := 64
stringEnd := int64(stringStart) + length

// Bounds check
if stringEnd > int64(len(data)) {
return fmt.Errorf("string data out of bounds")
return nil, fmt.Errorf("failed to read semver for %s: %w", contract.Name, err)
}

contractsOutput[contract.Name] = string(data[stringStart:stringEnd])
*contract.FieldPtr = semver
}

erc20Semver, err := findSemverBytecode(host, predeploys.OptimismMintableERC20FactoryAddr)
if err == nil {
contractsOutput["OptimismMintableERC20"] = erc20Semver
ps.OptimismMintableERC20 = erc20Semver
} else {
l.Warn("failed to find semver for OptimismMintableERC20", "err", err)
}

erc721Semver, err := findSemverBytecode(host, predeploys.OptimismMintableERC721FactoryAddr)
if err == nil {
contractsOutput["OptimismMintableERC721"] = erc721Semver
ps.OptimismMintableERC721 = erc721Semver
} else {
l.Warn("failed to find semver for OptimismMintableERC721", "err", err)
}

if err := jsonutil.WriteJSON(contractsOutput, ioutil.ToStdOutOrFileOrNoop(cliCfg.Outfile, 0o666)); err != nil {
return fmt.Errorf("failed to write rollup config: %w", err)
return &ps, nil
}

var versionSelector = []byte{0x54, 0xfd, 0x4d, 0x50}

func ReadSemver(host *script.Host, addr common.Address) (string, error) {
data, _, err := host.Call(
common.Address{19: 0x01},
addr,
bytes.Clone(versionSelector),
1_000_000_000,
uint256.NewInt(0),
)
if err != nil {
return "", fmt.Errorf("failed to call version on %s: %w", addr, err)
}

return nil
// The second 32 bytes contain the length of the string
length := new(big.Int).SetBytes(data[32:64]).Int64()
// Start of the string data (after offset and length)
stringStart := 64
stringEnd := int64(stringStart) + length

// Bounds check
if stringEnd > int64(len(data)) {
return "", fmt.Errorf("string data out of bounds")
}

return string(data[stringStart:stringEnd]), nil
}

const patternLen = 24
Expand Down
Loading

0 comments on commit f94151b

Please sign in to comment.