diff --git a/.circleci/config.yml b/.circleci/config.yml index 352af3da77..552b6e409f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -218,6 +218,22 @@ jobs: branch_pattern: optimism event: fail template: basic_fail_1 + check-sr-diff: + docker: + - image: cimg/go:<> + steps: + - checkout + - run: + name: install dasel + command: go install github.com/tomwright/dasel/v2/cmd/dasel@v2.8.1 + - run: + name: install jq + command: sudo apt-get install jq + - run: + name: generate artifact and check diff + command: | + bash ./sync-superchain.sh + git diff --exit-code workflows: main: @@ -235,6 +251,8 @@ workflows: docker_tags: <> context: - oplabs-gcr + - check-sr-diff: + name: Check superchain registry bundle diff release: jobs: - hold: diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 7903e134a6..567d62b39c 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -73,6 +73,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/superchain" "github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb/hashdb" "github.com/ethereum/go-ethereum/triedb/pathdb" @@ -159,7 +160,7 @@ var ( Name: "op-network", Aliases: []string{"beta.op-network"}, Usage: "Select a pre-configured OP-Stack network (warning: op-mainnet and op-goerli require special sync," + - " datadir is recommended), options: " + strings.Join(params.OPStackChainNames(), ", "), + " datadir is recommended), options: " + strings.Join(superchain.ChainNames(), ", "), Category: flags.EthCategory, } @@ -2314,7 +2315,7 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis { genesis = core.DefaultSepoliaGenesisBlock() case ctx.IsSet(OPNetworkFlag.Name): name := ctx.String(OPNetworkFlag.Name) - ch, err := params.OPStackChainIDByName(name) + ch, err := superchain.ChainIDByName(name) if err != nil { Fatalf("failed to load OP-Stack chain %q: %v", name, err) } diff --git a/consensus/misc/create2deployer.bin b/consensus/misc/create2deployer.bin new file mode 100644 index 0000000000..b434099828 Binary files /dev/null and b/consensus/misc/create2deployer.bin differ diff --git a/consensus/misc/create2deployer.go b/consensus/misc/create2deployer.go index 27c87a4a8c..dbbb26594c 100644 --- a/consensus/misc/create2deployer.go +++ b/consensus/misc/create2deployer.go @@ -1,10 +1,11 @@ package misc import ( - "github.com/ethereum-optimism/superchain-registry/superchain" + _ "embed" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) @@ -18,14 +19,15 @@ import ( var create2DeployerAddress = common.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2") var create2DeployerCodeHash = common.HexToHash("0xb0550b5b431e30d38000efb7107aaa0ade03d48a7198a140edda9d27134468b2") + +//go:embed create2deployer.bin var create2DeployerCode []byte func init() { - code, err := superchain.LoadContractBytecode(superchain.Hash(create2DeployerCodeHash)) - if err != nil { - panic(err) + testCodeHash := crypto.Keccak256Hash(create2DeployerCode) + if testCodeHash != create2DeployerCodeHash { + panic("create2deployer hash and code mismatch") } - create2DeployerCode = code } func EnsureCreate2Deployer(c *params.ChainConfig, timestamp uint64, db vm.StateDB) { diff --git a/core/genesis.go b/core/genesis.go index eccdd232fa..09c7a74aa5 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -24,8 +24,6 @@ import ( "math/big" "strings" - "github.com/ethereum-optimism/superchain-registry/superchain" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" @@ -38,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/superchain" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb/pathdb" @@ -306,13 +305,26 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g // If applying the superchain-registry to a known OP-Stack chain, // then override the local chain-config with that from the registry. if overrides != nil && overrides.ApplySuperchainUpgrades && config.IsOptimism() && config.ChainID != nil && config.ChainID.IsUint64() { - if _, ok := superchain.OPChains[config.ChainID.Uint64()]; ok { - conf, err := params.LoadOPStackChainConfig(config.ChainID.Uint64()) + getChainConfig := func() (*params.ChainConfig, error) { + chain, err := superchain.GetChain(config.ChainID.Uint64()) + if err != nil { + return nil, err + } + chainConf, err := chain.Config() if err != nil { - log.Warn("failed to load chain config from superchain-registry, skipping override", "err", err, "chain_id", config.ChainID) - } else { - *config = *conf + return nil, err } + genConf, err := params.LoadOPStackChainConfig(chainConf) + if err != nil { + return nil, err + } + return genConf, err + } + + if genConf, err := getChainConfig(); err == nil { + *config = *genConf + } else { + log.Warn("failed to load chain config from superchain-registry, skipping override", "err", err, "chain_id", config.ChainID) } } if overrides != nil && overrides.OverrideCancun != nil { diff --git a/core/superchain.go b/core/superchain.go index f1849ae731..bdc7157183 100644 --- a/core/superchain.go +++ b/core/superchain.go @@ -1,28 +1,33 @@ package core import ( + _ "embed" + "encoding/json" "fmt" - "math/big" - "github.com/ethereum-optimism/superchain-registry/superchain" + "github.com/ethereum/go-ethereum/superchain" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" ) func LoadOPStackGenesis(chainID uint64) (*Genesis, error) { - chConfig, ok := superchain.OPChains[chainID] - if !ok { - return nil, fmt.Errorf("unknown chain ID: %d", chainID) + chain, err := superchain.GetChain(chainID) + if err != nil { + return nil, fmt.Errorf("error getting superchain: %w", err) + } + + chConfig, err := chain.Config() + if err != nil { + return nil, fmt.Errorf("error getting chain config from superchain: %w", err) } - cfg, err := params.LoadOPStackChainConfig(chainID) + cfg, err := params.LoadOPStackChainConfig(chConfig) if err != nil { return nil, fmt.Errorf("failed to load params.ChainConfig for chain %d: %w", chainID, err) } - gen, err := superchain.LoadGenesis(chainID) + gen, err := readSuperchainGenesis(chain) if err != nil { return nil, fmt.Errorf("failed to load genesis definition for chain %d: %w", chainID, err) } @@ -33,56 +38,29 @@ func LoadOPStackGenesis(chainID uint64) (*Genesis, error) { Timestamp: gen.Timestamp, ExtraData: gen.ExtraData, GasLimit: gen.GasLimit, - Difficulty: (*big.Int)(gen.Difficulty), - Mixhash: common.Hash(gen.Mixhash), - Coinbase: common.Address(gen.Coinbase), - Alloc: make(types.GenesisAlloc), + Difficulty: gen.Difficulty, + Mixhash: gen.Mixhash, + Coinbase: gen.Coinbase, + Alloc: gen.Alloc, Number: gen.Number, GasUsed: gen.GasUsed, - ParentHash: common.Hash(gen.ParentHash), - BaseFee: (*big.Int)(gen.BaseFee), + ParentHash: gen.ParentHash, + BaseFee: gen.BaseFee, ExcessBlobGas: gen.ExcessBlobGas, BlobGasUsed: gen.BlobGasUsed, } - for addr, acc := range gen.Alloc { - var code []byte - if acc.CodeHash != ([32]byte{}) { - dat, err := superchain.LoadContractBytecode(acc.CodeHash) - if err != nil { - return nil, fmt.Errorf("failed to load bytecode %s of address %s in chain %d: %w", acc.CodeHash, addr, chainID, err) - } - code = dat - } - var storage map[common.Hash]common.Hash - if len(acc.Storage) > 0 { - storage = make(map[common.Hash]common.Hash) - for k, v := range acc.Storage { - storage[common.Hash(k)] = common.Hash(v) - } - } - bal := common.Big0 - if acc.Balance != nil { - bal = (*big.Int)(acc.Balance) - } - genesis.Alloc[common.Address(addr)] = GenesisAccount{ - Code: code, - Storage: storage, - Balance: bal, - Nonce: acc.Nonce, - } - } if gen.StateHash != nil { if len(gen.Alloc) > 0 { return nil, fmt.Errorf("chain definition unexpectedly contains both allocation (%d) and state-hash %s", len(gen.Alloc), *gen.StateHash) } - genesis.StateHash = (*common.Hash)(gen.StateHash) + genesis.StateHash = gen.StateHash genesis.Alloc = nil } genesisBlock := genesis.ToBlock() genesisBlockHash := genesisBlock.Hash() - expectedHash := common.Hash([32]byte(chConfig.Genesis.L2.Hash)) + expectedHash := chConfig.Genesis.L2.Hash // Verify we correctly produced the genesis config by recomputing the genesis-block-hash, // and check the genesis matches the chain genesis definition. @@ -99,3 +77,15 @@ func LoadOPStackGenesis(chainID uint64) (*Genesis, error) { } return genesis, nil } + +func readSuperchainGenesis(chain *superchain.Chain) (*Genesis, error) { + genData, err := chain.GenesisData() + if err != nil { + return nil, fmt.Errorf("error getting genesis data from superchain: %w", err) + } + gen := new(Genesis) + if err := json.Unmarshal(genData, gen); err != nil { + return nil, fmt.Errorf("failed to unmarshal genesis data: %w", err) + } + return gen, nil +} diff --git a/core/superchain_test.go b/core/superchain_test.go index 66303019a7..592f51e4d6 100644 --- a/core/superchain_test.go +++ b/core/superchain_test.go @@ -1,21 +1,24 @@ package core import ( + "fmt" "testing" - "github.com/ethereum-optimism/superchain-registry/superchain" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/superchain" "github.com/ethereum/go-ethereum/triedb" ) func TestOPStackGenesis(t *testing.T) { - for id := range superchain.OPChains { - _, err := LoadOPStackGenesis(id) - if err != nil { - t.Error(err) - } + for id, cfg := range superchain.Chains { + t.Run(fmt.Sprintf("chain-%s", cfg.Name), func(t *testing.T) { + t.Parallel() + _, err := LoadOPStackGenesis(id) + if err != nil { + t.Error(err) + } + }) } } diff --git a/go.mod b/go.mod index 3901571dde..013716447e 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ toolchain go1.22.7 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 + github.com/BurntSushi/toml v1.4.0 github.com/Microsoft/go-winio v0.6.2 github.com/VictoriaMetrics/fastcache v1.12.2 github.com/aws/aws-sdk-go-v2 v1.21.2 @@ -23,7 +24,6 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 - github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20250115145553-996c7aba6565 github.com/ethereum/c-kzg-4844 v1.0.0 github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 github.com/fatih/color v1.16.0 @@ -48,6 +48,7 @@ require ( github.com/jackpal/go-nat-pmp v1.0.2 github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 + github.com/klauspost/compress v1.17.11 github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-isatty v0.0.20 @@ -80,7 +81,6 @@ require ( require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect - github.com/BurntSushi/toml v1.4.0 // indirect github.com/DataDog/zstd v1.5.6-0.20230824185856-869dae002e5e // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 // indirect @@ -118,7 +118,6 @@ require ( github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kilic/bls12-381 v0.1.0 // indirect - github.com/klauspost/compress v1.16.0 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect diff --git a/go.sum b/go.sum index 2894939717..330d3a3203 100644 --- a/go.sum +++ b/go.sum @@ -167,8 +167,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20250115145553-996c7aba6565 h1:jhMVWUohS71nsNg8Q8d7DatiGpPocvUNGr/zP8a+79A= -github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20250115145553-996c7aba6565/go.mod h1:9feO8jcL5OZ1tvRjEfNAHz4Aggvd6373l+ZxmZZAyZs= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A= @@ -347,8 +345,8 @@ github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4 github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= -github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= diff --git a/params/superchain.go b/params/superchain.go index 989c26fc34..da9c77e553 100644 --- a/params/superchain.go +++ b/params/superchain.go @@ -4,52 +4,30 @@ import ( "encoding/binary" "fmt" "math/big" - "sort" "strings" - "github.com/ethereum-optimism/superchain-registry/superchain" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/superchain" ) var OPStackSupport = ProtocolVersionV0{Build: [8]byte{}, Major: 9, Minor: 0, Patch: 0, PreRelease: 0}.Encode() func init() { - for id, ch := range superchain.OPChains { + for id, ch := range superchain.Chains { NetworkNames[fmt.Sprintf("%d", id)] = ch.Name } } -func OPStackChainIDByName(name string) (uint64, error) { - for id, ch := range superchain.OPChains { - if ch.Chain+"-"+ch.Superchain == name { - return id, nil - } - } - return 0, fmt.Errorf("unknown chain %q", name) -} - -func OPStackChainNames() (out []string) { - for _, ch := range superchain.OPChains { - out = append(out, ch.Chain+"-"+ch.Superchain) - } - sort.Strings(out) - return -} - // uint64ptr is a weird helper to allow 1-line constant pointer creation. func uint64ptr(n uint64) *uint64 { return &n } -func LoadOPStackChainConfig(chainID uint64) (*ChainConfig, error) { - chConfig, ok := superchain.OPChains[chainID] - if !ok { - return nil, fmt.Errorf("unknown chain ID: %d", chainID) - } - +func LoadOPStackChainConfig(chConfig *superchain.ChainConfig) (*ChainConfig, error) { + hardforks := chConfig.Hardforks genesisActivation := uint64(0) out := &ChainConfig{ - ChainID: new(big.Int).SetUint64(chainID), + ChainID: new(big.Int).SetUint64(chConfig.ChainID), HomesteadBlock: common.Big0, DAOForkBlock: nil, DAOForkSupport: false, @@ -66,16 +44,16 @@ func LoadOPStackChainConfig(chainID uint64) (*ChainConfig, error) { ArrowGlacierBlock: common.Big0, GrayGlacierBlock: common.Big0, MergeNetsplitBlock: common.Big0, - ShanghaiTime: chConfig.CanyonTime, // Shanghai activates with Canyon - CancunTime: chConfig.EcotoneTime, // Cancun activates with Ecotone + ShanghaiTime: hardforks.CanyonTime, // Shanghai activates with Canyon + CancunTime: hardforks.EcotoneTime, // Cancun activates with Ecotone PragueTime: nil, BedrockBlock: common.Big0, RegolithTime: &genesisActivation, - CanyonTime: chConfig.CanyonTime, - EcotoneTime: chConfig.EcotoneTime, - FjordTime: chConfig.FjordTime, - GraniteTime: chConfig.GraniteTime, - HoloceneTime: chConfig.HoloceneTime, + CanyonTime: hardforks.CanyonTime, + EcotoneTime: hardforks.EcotoneTime, + FjordTime: hardforks.FjordTime, + GraniteTime: hardforks.GraniteTime, + HoloceneTime: hardforks.HoloceneTime, TerminalTotalDifficulty: common.Big0, Ethash: nil, Clique: nil, @@ -92,7 +70,7 @@ func LoadOPStackChainConfig(chainID uint64) (*ChainConfig, error) { } // special overrides for OP-Stack chains with pre-Regolith upgrade history - switch chainID { + switch chConfig.ChainID { case OPMainnetChainID: out.BerlinBlock = big.NewInt(3950000) out.LondonBlock = big.NewInt(105235063) diff --git a/superchain/chain.go b/superchain/chain.go new file mode 100644 index 0000000000..6b86e348e2 --- /dev/null +++ b/superchain/chain.go @@ -0,0 +1,138 @@ +package superchain + +import ( + "archive/zip" + "bytes" + _ "embed" + "encoding/json" + "fmt" + "io" + "path" + "sort" + "sync" + + "github.com/BurntSushi/toml" + "github.com/klauspost/compress/zstd" +) + +//go:embed superchain-configs.zip +var configData []byte + +var configDataReader *zip.Reader + +var genesisZstdDict []byte + +var Chains = make(map[uint64]*Chain) + +var idsByName = make(map[string]uint64) + +func ChainIDByName(name string) (uint64, error) { + id, ok := idsByName[name] + if !ok { + return 0, fmt.Errorf("unknown chain %q", name) + } + return id, nil +} + +func ChainNames() []string { + var out []string + for _, ch := range Chains { + out = append(out, ch.Name+"-"+ch.Network) + } + sort.Strings(out) + return out +} + +func GetChain(chainID uint64) (*Chain, error) { + chain, ok := Chains[chainID] + if !ok { + return nil, fmt.Errorf("unknown chain ID: %d", chainID) + } + return chain, nil +} + +type Chain struct { + Name string `json:"name"` + Network string `json:"network"` + + config *ChainConfig + genesis []byte + + initOnce sync.Once + err error +} + +func (c *Chain) Config() (*ChainConfig, error) { + c.initOnce.Do(c.populate) + return c.config, c.err +} + +func (c *Chain) GenesisData() ([]byte, error) { + c.initOnce.Do(c.populate) + return c.genesis, c.err +} + +func (c *Chain) populate() { + genesisFile, err := configDataReader.Open(path.Join("genesis", c.Network, c.Name+".json.zst")) + if err != nil { + c.err = fmt.Errorf("error opening compressed genesis file %s/%s: %w", c.Network, c.Name, err) + return + } + defer genesisFile.Close() + zstdR, err := zstd.NewReader(genesisFile, zstd.WithDecoderDicts(genesisZstdDict)) + if err != nil { + c.err = fmt.Errorf("error creating zstd reader for %s/%s: %w", c.Network, c.Name, err) + return + } + defer zstdR.Close() + + out, err := io.ReadAll(zstdR) + if err != nil { + c.err = fmt.Errorf("error reading genesis file for %s/%s: %w", c.Network, c.Name, err) + return + } + c.genesis = out + + configFile, err := configDataReader.Open(path.Join("configs", c.Network, c.Name+".toml")) + if err != nil { + c.err = fmt.Errorf("error opening chain config file %s/%s: %w", c.Network, c.Name, err) + return + } + defer configFile.Close() + + var cfg ChainConfig + if _, err := toml.NewDecoder(configFile).Decode(&cfg); err != nil { + c.err = fmt.Errorf("error decoding chain config file %s/%s: %w", c.Network, c.Name, err) + return + } + c.config = &cfg +} + +func init() { + var err error + configDataReader, err = zip.NewReader(bytes.NewReader(configData), int64(len(configData))) + if err != nil { + panic(fmt.Errorf("opening zip reader: %w", err)) + } + dictR, err := configDataReader.Open("dictionary") + if err != nil { + panic(fmt.Errorf("error opening dictionary: %w", err)) + } + defer dictR.Close() + genesisZstdDict, err = io.ReadAll(dictR) + if err != nil { + panic(fmt.Errorf("error reading dictionary: %w", err)) + } + chainFile, err := configDataReader.Open("chains.json") + if err != nil { + panic(fmt.Errorf("error opening chains file: %w", err)) + } + defer chainFile.Close() + if err := json.NewDecoder(chainFile).Decode(&Chains); err != nil { + panic(fmt.Errorf("error decoding chains file: %w", err)) + } + + for chainID, chain := range Chains { + idsByName[chain.Name+"-"+chain.Network] = chainID + } +} diff --git a/superchain/superchain-configs.zip b/superchain/superchain-configs.zip new file mode 100644 index 0000000000..d9897e62d4 Binary files /dev/null and b/superchain/superchain-configs.zip differ diff --git a/superchain/types.go b/superchain/types.go new file mode 100644 index 0000000000..a4d7261188 --- /dev/null +++ b/superchain/types.go @@ -0,0 +1,109 @@ +package superchain + +import ( + "github.com/ethereum/go-ethereum/common" +) + +type ChainConfig struct { + Name string `toml:"name"` + PublicRPC string `toml:"public_rpc"` + SequencerRPC string `toml:"sequencer_rpc"` + Explorer string `toml:"explorer"` + SuperchainLevel int `toml:"superchain_level"` + GovernedByOptimism bool `toml:"governed_by_optimism"` + SuperchainTime *uint64 `toml:"superchain_time"` + DataAvailabilityType string `toml:"data_availability_type"` + DeploymentTxHash *common.Hash `toml:"deployment_tx_hash"` + + ChainID uint64 `toml:"chain_id"` + BatchInboxAddr common.Address `toml:"batch_inbox_addr"` + BlockTime uint64 `toml:"block_time"` + SeqWindowSize uint64 `toml:"seq_window_size"` + MaxSequencerDrift uint64 `toml:"max_sequencer_drift"` + GasPayingToken *common.Address `toml:"gas_paying_token"` + Hardforks HardforkConfig `toml:"hardforks"` + Optimism *OptimismConfig `toml:"optimism,omitempty" json:"optimism,omitempty"` + + AltDA *AltDAConfig `toml:"alt_da,omitempty" json:"alt_da,omitempty"` + + Genesis GenesisConfig `toml:"genesis" json:"genesis"` + + Roles RolesConfig `toml:"roles"` + + Addresses AddressesConfig `toml:"addresses"` +} + +type HardforkConfig struct { + CanyonTime *uint64 `toml:"canyon_time"` + DeltaTime *uint64 `toml:"delta_time"` + EcotoneTime *uint64 `toml:"ecotone_time"` + FjordTime *uint64 `toml:"fjord_time"` + GraniteTime *uint64 `toml:"granite_time"` + HoloceneTime *uint64 `toml:"holocene_time"` + IsthmusTime *uint64 `toml:"isthmus_time"` +} + +type OptimismConfig struct { + EIP1559Elasticity uint64 `toml:"eip1559_elasticity"` + EIP1559Denominator uint64 `toml:"eip1559_denominator"` + EIP1559DenominatorCanyon *uint64 `toml:"eip1559_denominator_canyon"` +} + +type AltDAConfig struct { + DaChallengeContractAddress common.Address `toml:"da_challenge_contract_address"` + DaChallengeWindow uint64 `toml:"da_challenge_window"` + DaResolveWindow uint64 `toml:"da_resolve_window"` + DaCommitmentType string `toml:"da_commitment_type"` +} + +type GenesisConfig struct { + L2Time uint64 `toml:"l2_time"` + L1 GenesisRef `toml:"l1"` + L2 GenesisRef `toml:"l2"` + SystemConfig SystemConfig `toml:"system_config"` +} + +type GenesisRef struct { + Hash common.Hash `toml:"hash"` + Number uint64 `toml:"number"` +} + +type SystemConfig struct { + BatcherAddr common.Address `json:"batcherAddr" toml:"batcherAddress"` + Overhead common.Hash `json:"overhead" toml:"overhead"` + Scalar common.Hash `json:"scalar" toml:"scalar"` + GasLimit uint64 `json:"gasLimit" toml:"gasLimit"` + BaseFeeScalar *uint64 `json:"baseFeeScalar,omitempty" toml:"baseFeeScalar,omitempty"` + BlobBaseFeeScalar *uint64 `json:"blobBaseFeeScalar,omitempty" toml:"blobBaseFeeScalar,omitempty"` +} + +type RolesConfig struct { + SystemConfigOwner *common.Address `json:"SystemConfigOwner" toml:"SystemConfigOwner"` + ProxyAdminOwner *common.Address `json:"ProxyAdminOwner" toml:"ProxyAdminOwner"` + Guardian *common.Address `json:"Guardian" toml:"Guardian"` + Challenger *common.Address `json:"Challenger" toml:"Challenger"` + Proposer *common.Address `json:"Proposer,omitempty" toml:"Proposer,omitempty"` + UnsafeBlockSigner *common.Address `json:"UnsafeBlockSigner,omitempty" toml:"UnsafeBlockSigner,omitempty"` + BatchSubmitter *common.Address `json:"BatchSubmitter" toml:"BatchSubmitter"` +} + +type AddressesConfig struct { + AddressManager *common.Address `toml:"AddressManager,omitempty" json:"AddressManager,omitempty"` + L1CrossDomainMessengerProxy *common.Address `toml:"L1CrossDomainMessengerProxy,omitempty" json:"L1CrossDomainMessengerProxy,omitempty"` + L1ERC721BridgeProxy *common.Address `toml:"L1ERC721BridgeProxy,omitempty" json:"L1ERC721BridgeProxy,omitempty"` + L1StandardBridgeProxy *common.Address `toml:"L1StandardBridgeProxy,omitempty" json:"L1StandardBridgeProxy,omitempty"` + L2OutputOracleProxy *common.Address `toml:"L2OutputOracleProxy,omitempty" json:"L2OutputOracleProxy,omitempty"` + OptimismMintableERC20FactoryProxy *common.Address `toml:"OptimismMintableERC20FactoryProxy,omitempty" json:"OptimismMintableERC20FactoryProxy,omitempty"` + OptimismPortalProxy *common.Address `toml:"OptimismPortalProxy,omitempty" json:"OptimismPortalProxy,omitempty"` + SystemConfigProxy *common.Address `toml:"SystemConfigProxy,omitempty" json:"SystemConfigProxy,omitempty"` + ProxyAdmin *common.Address `toml:"ProxyAdmin,omitempty" json:"ProxyAdmin,omitempty"` + SuperchainConfig *common.Address `toml:"SuperchainConfig,omitempty" json:"SuperchainConfig,omitempty"` + AnchorStateRegistryProxy *common.Address `toml:"AnchorStateRegistryProxy,omitempty" json:"AnchorStateRegistryProxy,omitempty"` + DelayedWETHProxy *common.Address `toml:"DelayedWETHProxy,omitempty" json:"DelayedWETHProxy,omitempty"` + DisputeGameFactoryProxy *common.Address `toml:"DisputeGameFactoryProxy,omitempty" json:"DisputeGameFactoryProxy,omitempty"` + FaultDisputeGame *common.Address `toml:"FaultDisputeGame,omitempty" json:"FaultDisputeGame,omitempty"` + MIPS *common.Address `toml:"MIPS,omitempty" json:"MIPS,omitempty"` + PermissionedDisputeGame *common.Address `toml:"PermissionedDisputeGame,omitempty" json:"PermissionedDisputeGame,omitempty"` + PreimageOracle *common.Address `toml:"PreimageOracle,omitempty" json:"PreimageOracle,omitempty"` + DAChallengeAddress *common.Address `toml:"DAChallengeAddress,omitempty" json:"DAChallengeAddress,omitempty"` +} diff --git a/sync-superchain.sh b/sync-superchain.sh new file mode 100644 index 0000000000..04ee3f5106 --- /dev/null +++ b/sync-superchain.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +# This script is used to sync superchain configs in the registry with OP Geth. + +set -euo pipefail + +# Constants +REGISTRY_COMMIT="9596f616b9bd07b7823e23aac72ae4621805653d" +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +repodir=$(mktemp -d) +workdir=$(mktemp -d) + +# Clone the registry +echo "Cloning SR..." +cd "$repodir" +git clone --no-checkout --depth 1 --shallow-submodules https://github.com/ethereum-optimism/superchain-registry.git +cd "$repodir/superchain-registry" +git fetch --depth 1 origin "$REGISTRY_COMMIT" +git checkout "$REGISTRY_COMMIT" + +echo "Copying configs..." +cp -r superchain/configs "$workdir/configs" +cp -r superchain/extra/genesis "$workdir/genesis" +cp -r superchain/extra/dictionary "$workdir/dictionary" + +cd "$workdir" +echo "Using $workdir as workdir..." + +# Create a simple mapping of chain id -> config name to make looking up chains by their ID easier. +echo "Generating index of configs..." + +echo "{}" > chains.json + +# Function to process each network directory +process_network_dir() { + local network_dir="$1" + local network_name=$(basename "$network_dir") + + echo "Processing chains in $network_name superchain..." + + # Find all TOML files in the network directory + find "$network_dir" -type f -name "*.toml" | LC_ALL=C sort | while read -r toml_file; do + if [[ "$toml_file" == "configs/$network_name/superchain.toml" ]]; then + continue + fi + + echo "Processing $toml_file..." + # Extract chain_id from TOML file using dasel + chain_id=$(dasel -f "$toml_file" -r toml "chain_id" | tr -d '"') + + # Skip if chain_id is empty + if [ -z "$chain_id" ]; then + continue + fi + + # Create JSON object for this config + config_json=$(jq -n \ + --arg name "$(basename "${toml_file%.*}")" \ + --arg network "$network_name" \ + '{ + "name": $name, + "network": $network + }') + + # Add this config to the result JSON using the chain_id as the key + jq --argjson config "$config_json" \ + --arg chain_id "$chain_id" \ + '. + {($chain_id): $config}' chains.json > temp.json + mv temp.json chains.json + done +} + +# Process each network directory in configs +for network_dir in configs/*; do + if [ -d "$network_dir" ]; then + process_network_dir "$network_dir" + fi +done + +# Archive the genesis configs as a ZIP file. ZIP is used since it can be efficiently used as a filesystem. +echo "Archiving configs..." +echo "$REGISTRY_COMMIT" > COMMIT +# We need to normalize the lastmod dates and permissions to ensure the ZIP file is deterministic. +find . -exec touch -t 198001010000.00 {} + +chmod -R 755 ./* +files=$(find . -type f | LC_ALL=C sort) +echo -n "$files" | xargs zip -9 -oX --quiet superchain-configs.zip +zipinfo superchain-configs.zip +mv superchain-configs.zip "$SCRIPT_DIR/superchain/superchain-configs.zip" + +echo "Cleaning up..." +rm -rf "$repodir" +rm -rf "$workdir" + +echo "Done." \ No newline at end of file