Skip to content

ops: integrate op-fetcher #951

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Apr 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
6180c24
ops: integrate op-fetcher
bitwiseguy Mar 26, 2025
1fb9527
use L1ProxyAdminOwner instead of OpChainProxyAdminOwner
bitwiseguy Mar 28, 2025
f472fa9
use cmd/codegen to wrap fetch_onchain and codegen_syncer
bitwiseguy Mar 31, 2025
9118442
revert .gitignore change
bitwiseguy Mar 31, 2025
265cff2
refactor CodegenSyncer and fix all ops tests
bitwiseguy Apr 1, 2025
8723cc0
fetch_onchain: remove unnecessary abstractions
bitwiseguy Apr 1, 2025
2794955
add tests for new helper functions
bitwiseguy Apr 1, 2025
ca63963
circleci: add daily-codegen-sync job
bitwiseguy Apr 1, 2025
54db0c9
UpdateChainList handle new chain addition
bitwiseguy Apr 2, 2025
e09c55f
update op-fetcher import: use pointer for FaultProofsStatus
bitwiseguy Apr 2, 2025
a6e0002
go mod tidy
bitwiseguy Apr 3, 2025
483cce9
codegen: chain-ids flag is optional comma separated list
bitwiseguy Apr 3, 2025
b75b286
remove unused helper function
bitwiseguy Apr 3, 2025
ae6f5f7
circleci: update check-codegen job
bitwiseguy Apr 4, 2025
d65be4c
circleci: fix codegen-sync-all reference
bitwiseguy Apr 4, 2025
01efaad
transform op-fetcher proofs struct to unique chainList struct
bitwiseguy Apr 4, 2025
8b1f49c
remove 'just codegen' (needs args now)
bitwiseguy Apr 4, 2025
4f28a0d
circleci: remove daily codegen-sync-all
bitwiseguy Apr 6, 2025
ec4c61f
rebase and revert unnecessary changes
bitwiseguy Apr 7, 2025
d1269fb
simplify zero-address comparison
bitwiseguy Apr 7, 2025
98664bb
pass context from cli handler instead of creating one in helpers
bitwiseguy Apr 7, 2025
3e4923c
use uint64 for chainId everywhere except cli handlers
bitwiseguy Apr 7, 2025
a324dd2
remove unused FindChainConfig. Add FindChainConfigs tests
bitwiseguy Apr 7, 2025
dacb7a6
add FS helpers for chainList, CHAINS.md files
bitwiseguy Apr 7, 2025
e7b55db
remove hardcoded SuperchainIds map
bitwiseguy Apr 8, 2025
de46b1a
remove FindChainConfigs, add Superchain field to DiskChainConfig
bitwiseguy Apr 8, 2025
cc359d0
use helper to encapsulate common ChecksummedAddress Unmarshal code
bitwiseguy Apr 8, 2025
957c5d3
add paths.EnsureDir helper
bitwiseguy Apr 8, 2025
6d3195b
codegen: add optional superchains flag
bitwiseguy Apr 8, 2025
1cb2245
mise: add yq (for usage in ci)
bitwiseguy Apr 9, 2025
f903fa2
cleanup log messages
bitwiseguy Apr 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 70 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,74 @@ jobs:
cd ops
go run ./cmd/print_staging_report/main.go

check-codegen:
circleci_ip_ranges: true
docker:
- image: <<pipeline.parameters.default_docker_image>>
steps:
- utils/checkout-with-mise
- run:
name: check-codegen-for-changed-chains
command: |
set -e

# Get list of changed files
CHANGED_FILES=$(git diff --name-only origin/main... | grep "^superchain/configs/.*\.toml$" || true)
if [ -z "$CHANGED_FILES" ]; then
echo "No .toml files changed in superchain/configs, skipping codegen check"
exit 0
fi

# Extract chain_ids from changed .toml files
CHAIN_IDS=""
CHAIN_ID_COUNT=0
CHANGED_FILE_COUNT=0

for file in $CHANGED_FILES; do
CHANGED_FILE_COUNT=$((CHANGED_FILE_COUNT + 1))
# Use yq to extract chain_id from TOML
CHAIN_ID=$(yq -p=toml -o=json '.chain_id' "$file" | grep -v "null" | tr -d '"')

if [ -n "$CHAIN_ID" ]; then
if [ -z "$CHAIN_IDS" ]; then
CHAIN_IDS="$CHAIN_ID"
else
CHAIN_IDS="$CHAIN_IDS,$CHAIN_ID"
fi
CHAIN_ID_COUNT=$((CHAIN_ID_COUNT + 1))
echo "Found chain_id $CHAIN_ID in $file"
fi
done
echo "Found $CHAIN_ID_COUNT chain_ids in $CHANGED_FILE_COUNT files"

cd ops
if [ "$CHAIN_ID_COUNT" -ne "$CHANGED_FILE_COUNT" ] && [ "$CHANGED_FILE_COUNT" -gt 0 ]; then
# This accounts for changes to superchain.toml files
echo "Running codegen for all chains\n"
go run ./cmd/codegen \
--l1-rpc-urls="<< pipeline.parameters.sepolia_rpc_url >>,<< pipeline.parameters.mainnet_rpc_url >>"
else
echo "Running codegen for the following chain_ids: $CHAIN_IDS\n"
go run ./cmd/codegen \
--l1-rpc-urls="<< pipeline.parameters.sepolia_rpc_url >>,<< pipeline.parameters.mainnet_rpc_url >>" \
--chain-ids="$CHAIN_IDS"
fi

if [ -n "$(git status --porcelain)" ] ; then
echo "\n❌ Changes detected after running codegen. Run the following command locally and commit the changes:\n"
echo "go run ./cmd/codegen \\"
# Show the appropriate command flags based on which mode was run
if [ "$CHAIN_ID_COUNT" -ne "$CHANGED_FILE_COUNT" ] && [ "$CHANGED_FILE_COUNT" -gt 0 ]; then
echo " --l1-rpc-urls=\"<urls>\""
else
echo " --l1-rpc-urls=\"<urls>\" \\"
echo " --chain-ids=\"$CHAIN_IDS\""
fi
exit 1
else
echo "\n✅ All codegen files are up to date"
fi

workflows:
main:
jobs:
Expand All @@ -136,13 +204,12 @@ workflows:
- run-tool:
name: check-genesis-integrity
tool: check_genesis_integrity
- run-tool:
- check-codegen:
name: check-codegen
tool: codegen
check_diff: true
- run-tool:
name: check-staging-synced
tool: sync_staging
args: --l1-rpc-urls="<< pipeline.parameters.sepolia_rpc_url >>,<< pipeline.parameters.mainnet_rpc_url >>"
check_diff: true
- check-staging-empty:
name: check-staging-empty
Expand All @@ -155,4 +222,3 @@ workflows:
tool: check_chainlist
- run-staging-report:
name: run-staging-report

2 changes: 0 additions & 2 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ print-staging-report: (_run_ops_bin 'print_staging_report')

check-genesis-integrity: (_run_ops_bin 'check_genesis_integrity')

codegen: (_run_ops_bin 'codegen')

create-config SHORTNAME FILENAME:
@just _run_ops_bin "create_config" "--shortname {{SHORTNAME}} --state-filename $(realpath {{FILENAME}})"

Expand Down
1 change: 1 addition & 0 deletions mise.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Core dependencies
go = "1.23.1"
just = "1.37.0"
yq = "4.44.5"

# Go dependencies
"go:gotest.tools/gotestsum" = "1.12.0"
Expand Down
89 changes: 83 additions & 6 deletions ops/cmd/codegen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,105 @@ package main
import (
"fmt"
"os"
"strconv"
"strings"

"github.com/ethereum-optimism/optimism/op-fetcher/pkg/fetcher/fetch/script"
"github.com/ethereum-optimism/superchain-registry/ops/internal/config"
"github.com/ethereum-optimism/superchain-registry/ops/internal/manage"
"github.com/ethereum-optimism/superchain-registry/ops/internal/output"
"github.com/ethereum-optimism/superchain-registry/ops/internal/paths"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"
)

var (
L1RPCURLsFlag = &cli.StringFlag{
Name: "l1-rpc-urls",
Usage: "comma-separated list of L1 RPC URLs (only need multiple if fetching from multiple superchains)",
EnvVars: []string{"L1_RPC_URLS"},
Required: true,
}
ChainIDFlag = &cli.StringFlag{
Name: "chain-ids",
Usage: "comma-separated list of l2 chainIds to update (optional, fetches all chains if not provided)",
}
SuperchainsFlag = &cli.StringFlag{
Name: "superchains",
Usage: "comma-separated list of superchains to update (cannot provide both chain-ids and superchains flags, default to all superchains if not provided)",
}
)

func main() {
if err := mainErr(); err != nil {
output.WriteNotOK("application error: %v", err)
app := &cli.App{
Name: "codegen",
Usage: "uses op-fetcher to fetch onchain config data for chain(s) in the superchain-registry, then propagates the data to codegen files",
Flags: []cli.Flag{
L1RPCURLsFlag,
ChainIDFlag,
SuperchainsFlag,
},
Action: CodegenCLI,
}
if err := app.Run(os.Args); err != nil {
output.WriteStderr("%v", err)
os.Exit(1)
}
}

func mainErr() error {
func CodegenCLI(cliCtx *cli.Context) error {
l1RpcUrls := strings.Split(cliCtx.String("l1-rpc-urls"), ",")
chainIdStr := cliCtx.String("chain-ids")
superchainsStr := cliCtx.String("superchains")
if chainIdStr != "" && superchainsStr != "" {
return fmt.Errorf("cannot provide both chain-ids and superchains flags")
}

var superchains []config.Superchain
if superchainsStr != "" {
superchainStrs := strings.Split(superchainsStr, ",")
for _, superchainStr := range superchainStrs {
superchainStr = strings.TrimSpace(superchainStr)
superchain, err := config.ParseSuperchain(superchainStr)
if err != nil {
return err
}
superchains = append(superchains, superchain)
}
}

var chainIds []uint64
if chainIdStr != "" {
chainIdStrs := strings.Split(chainIdStr, ",")
// Convert each string to uint64
for _, idStr := range chainIdStrs {
idStr = strings.TrimSpace(idStr)
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
return fmt.Errorf("invalid chain ID '%s': %w", idStr, err)
}
chainIds = append(chainIds, id)
}
}

lgr := log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, false))
wd, err := paths.FindRepoRoot()
if err != nil {
return fmt.Errorf("failed to get working directory: %w", err)
}

if err := manage.GenAllCode(wd); err != nil {
return fmt.Errorf("error generating code: %w", err)
var onchainCfgs map[uint64]script.ChainConfig
ctx := cliCtx.Context
onchainCfgs, err = manage.FetchChains(ctx, lgr, wd, l1RpcUrls, chainIds, superchains)
if err != nil {
return fmt.Errorf("error fetching onchain configs: %w", err)
}
syncer, err := manage.NewCodegenSyncer(lgr, wd, onchainCfgs)
if err != nil {
return fmt.Errorf("error creating codegen syncer: %w", err)
}
if err := syncer.SyncAll(); err != nil {
return fmt.Errorf("error syncing codegen: %w", err)
}

return nil
}
25 changes: 23 additions & 2 deletions ops/cmd/sync_staging/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import (
"fmt"
"os"
"path"
"strings"

"github.com/ethereum-optimism/superchain-registry/ops/internal/config"
"github.com/ethereum-optimism/superchain-registry/ops/internal/manage"
"github.com/ethereum-optimism/superchain-registry/ops/internal/output"
"github.com/ethereum-optimism/superchain-registry/ops/internal/paths"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"
)

Expand All @@ -21,6 +24,11 @@ var (
Name: "preserve-input",
Usage: "Skip cleanup of staging directory.",
}
FlagL1RPCURLs = &cli.StringFlag{
Name: "l1-rpc-urls",
Usage: "Comma-separated list of L1 RPC URLs",
Required: true,
}
)

func main() {
Expand All @@ -30,6 +38,7 @@ func main() {
Flags: []cli.Flag{
FlagCheck,
FlagPreserveInput,
FlagL1RPCURLs,
},
Action: action,
}
Expand Down Expand Up @@ -96,8 +105,20 @@ func action(cliCtx *cli.Context) error {

output.WriteOK("wrote genesis files")

if err := manage.GenAllCode(wd); err != nil {
return fmt.Errorf("failed to generate code: %w", err)
// Codegen
lgr := log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, false))
l1RpcUrls := strings.Split(cliCtx.String("l1-rpc-urls"), ",")
ctx := cliCtx.Context
onchainCfgs, err := manage.FetchChains(ctx, lgr, wd, l1RpcUrls, []uint64{chainCfg.ChainID}, []config.Superchain{})
if err != nil {
return fmt.Errorf("error fetching onchain configs: %w", err)
}
syncer, err := manage.NewCodegenSyncer(lgr, wd, onchainCfgs)
if err != nil {
return fmt.Errorf("error creating codegen syncer: %w", err)
}
if err := syncer.SyncAll(); err != nil {
return fmt.Errorf("error syncing codegen: %w", err)
}

if !noCleanup {
Expand Down
4 changes: 2 additions & 2 deletions ops/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.23.1

require (
github.com/BurntSushi/toml v1.4.0
github.com/ethereum-optimism/optimism v1.13.1-0.20250402215013-5391bf29692d
github.com/ethereum-optimism/optimism v1.12.3-0.20250402215013-5391bf29692d
github.com/ethereum/go-ethereum v1.15.3
github.com/lmittmann/w3 v0.17.8
github.com/stretchr/testify v1.10.0
Expand All @@ -15,6 +15,7 @@ require (
github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20250314162817-2c60e5723c64
github.com/google/go-github/v68 v68.0.0
github.com/klauspost/compress v1.18.0
golang.org/x/sync v0.10.0
)

require (
Expand Down Expand Up @@ -74,7 +75,6 @@ require (
github.com/yusufpapurcu/wmi v1.2.3 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/time v0.10.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions ops/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v1.101503.2-rc.5.0.20250401164435-02dfe8692a3c h1:2uU1Jx+wuqGtWR/qsZrmB+jfR+/hslowPS11bvBAda4=
github.com/ethereum-optimism/op-geth v1.101503.2-rc.5.0.20250401164435-02dfe8692a3c/go.mod h1:QUo3fn+45vWqJWzJW+rIzRHUV7NmhhHLPdI87mAn1M8=
github.com/ethereum-optimism/optimism v1.13.1-0.20250402215013-5391bf29692d h1:SWUqPFKjoh3WfAG2HaKNjwkwzxJ3Jm/ssvYQAF6AbY0=
github.com/ethereum-optimism/optimism v1.13.1-0.20250402215013-5391bf29692d/go.mod h1:Pf1bUvfjbot5RyCmsfPKFR0kcBCT/HZvSlISRtB1+KE=
github.com/ethereum-optimism/optimism v1.12.3-0.20250402215013-5391bf29692d h1:UGWjnYcPm7e0AOWZGyKhgBj+67oq8ZRrJYYu4Kfh7uw=
github.com/ethereum-optimism/optimism v1.12.3-0.20250402215013-5391bf29692d/go.mod h1:Pf1bUvfjbot5RyCmsfPKFR0kcBCT/HZvSlISRtB1+KE=
github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20250314162817-2c60e5723c64 h1:teDhU4h4ryaE8rSBl+vJJiwKHjxdnnHPkKZ9iNr2R8k=
github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20250314162817-2c60e5723c64/go.mod h1:NZ816PzLU1TLv1RdAvYAb6KWOj4Zm5aInT0YpDVml2Y=
github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=
Expand Down
57 changes: 41 additions & 16 deletions ops/internal/config/address.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"encoding/json"
"fmt"

"github.com/ethereum/go-ethereum/common"
Expand All @@ -19,20 +20,7 @@ func (a *ChecksummedAddress) UnmarshalTOML(data any) error {
return fmt.Errorf("expected a string, got %T", data)
}

if len(dataStr) != 42 {
return fmt.Errorf("invalid address: %s", dataStr)
}

if !common.IsHexAddress(dataStr) {
return fmt.Errorf("invalid address: %s", dataStr)
}

addr := common.HexToAddress(dataStr)
if addr.Hex() != dataStr {
return fmt.Errorf("invalid checksummed address: %s", dataStr)
}
*a = ChecksummedAddress(addr)
return nil
return a.parseAddress(dataStr)
}

func (a ChecksummedAddress) MarshalTOML() ([]byte, error) {
Expand All @@ -43,6 +31,43 @@ func (a ChecksummedAddress) String() string {
return common.Address(a).Hex()
}

func (a ChecksummedAddress) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`"%s"`, common.Address(a).Hex())), nil
func (a *ChecksummedAddress) UnmarshalJSON(data []byte) error {
var dataStr string
if err := json.Unmarshal(data, &dataStr); err != nil {
return fmt.Errorf("failed to unmarshal ChecksummedAddress: %w", err)
}

return a.parseAddress(dataStr)
}

func (a *ChecksummedAddress) MarshalJSON() ([]byte, error) {
if common.Address(*a) == (common.Address{}) {
// Return null for zero addresses so it doesn't pollute the json output
return []byte("null"), nil
}
return []byte(fmt.Sprintf(`"%s"`, common.Address(*a).Hex())), nil
}

// Helper function for validating and parsing Ethereum addresses
func (a *ChecksummedAddress) parseAddress(addrStr string) error {
// Validate length
if len(addrStr) != 42 {
return fmt.Errorf("invalid address length: %s", addrStr)
}

// Validate hex format
if !common.IsHexAddress(addrStr) {
return fmt.Errorf("invalid hex address: %s", addrStr)
}

// Convert to checksummed address
addr := common.HexToAddress(addrStr)

// Validate that the address is properly checksummed
if addr.Hex() != addrStr {
return fmt.Errorf("invalid checksummed address: %s", addrStr)
}

*a = ChecksummedAddress(addr)
return nil
}
Loading