From 2595d74edde02e92c07def87f0e5bec531fe1112 Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Thu, 18 Dec 2025 12:20:46 +0100 Subject: [PATCH 1/2] Move logic to functions in artifact generation --- playground/artifacts.go | 120 ++++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 55 deletions(-) diff --git a/playground/artifacts.go b/playground/artifacts.go index 94383bd..e39ede3 100644 --- a/playground/artifacts.go +++ b/playground/artifacts.go @@ -196,52 +196,17 @@ func (b *ArtifactsBuilder) Build() (*Artifacts, error) { gen.Config.DepositContractAddress = gethcommon.HexToAddress(config.DepositContractAddress) // add pre-funded accounts - prefundedBalance, _ := new(big.Int).SetString("10000000000000000000000", 16) - - for _, privStr := range b.getPrefundedAccounts() { - priv, err := getPrivKey(privStr) - if err != nil { - return nil, err - } - addr := ecrypto.PubkeyToAddress(priv.PublicKey) - gen.Alloc[addr] = types.Account{ - Balance: prefundedBalance, - Nonce: 1, - } + if err := appendPrefundedAccountsToAlloc(&gen.Alloc, b.getPrefundedAccounts()); err != nil { + return nil, err } // Apply Optimism pre-state { - var state struct { - L1StateDump string `json:"l1StateDump"` - } - if err := json.Unmarshal(opState, &state); err != nil { - return nil, fmt.Errorf("failed to unmarshal opState: %w", err) - } - - decoded, err := base64.StdEncoding.DecodeString(state.L1StateDump) - if err != nil { - return nil, fmt.Errorf("failed to decode opState: %w", err) - } - - // Create gzip reader from the base64 decoded data - gr, err := gzip.NewReader(bytes.NewReader(decoded)) + opAllocs, err := readOptimismL1Allocs() if err != nil { - return nil, fmt.Errorf("failed to create gzip reader: %w", err) - } - defer gr.Close() - - // Read and decode the contents - contents, err := io.ReadAll(gr) - if err != nil { - return nil, fmt.Errorf("failed to read opState: %w", err) - } - - var alloc types.GenesisAlloc - if err := json.Unmarshal(contents, &alloc); err != nil { - return nil, fmt.Errorf("failed to unmarshal opState: %w", err) + return nil, err } - maps.Copy(gen.Alloc, alloc) + maps.Copy(gen.Alloc, opAllocs) } block := gen.ToBlock() @@ -306,9 +271,16 @@ func (b *ArtifactsBuilder) Build() (*Artifacts, error) { } } + // Update the allocs to include the same prefunded accounts as the L1 genesis. + allocs := types.GenesisAlloc{} + if err := appendPrefundedAccountsToAlloc(&allocs, b.getPrefundedAccounts()); err != nil { + return nil, err + } + // override l2 genesis, make the timestamp start 2 seconds after the L1 genesis input := map[string]interface{}{ "timestamp": hexutil.Uint64(opTimestamp).String(), + "allocs": allocs, } if forkTime != nil { // We need to enable prague on the EL to enable the engine v4 calls @@ -318,21 +290,6 @@ func (b *ArtifactsBuilder) Build() (*Artifacts, error) { } } - // Update the allocs to include the same prefunded accounts as the L1 genesis. - allocs := make(map[string]interface{}) - input["alloc"] = allocs - for _, privStr := range b.getPrefundedAccounts() { - priv, err := getPrivKey(privStr) - if err != nil { - return nil, err - } - addr := ecrypto.PubkeyToAddress(priv.PublicKey) - allocs[addr.String()] = map[string]interface{}{ - "balance": "0x10000000000000000000000", - "nonce": "0x1", - } - } - newOpGenesis, err := overrideJSON(opGenesis, input) if err != nil { return nil, err @@ -769,3 +726,56 @@ func (o *output) GetEnodeAddr() *EnodeAddr { return &EnodeAddr{PrivKey: privKey, Artifact: fileName} } + +func readOptimismL1Allocs() (types.GenesisAlloc, error) { + var state struct { + L1StateDump string `json:"l1StateDump"` + } + if err := json.Unmarshal(opState, &state); err != nil { + return nil, fmt.Errorf("failed to unmarshal opState: %w", err) + } + + decoded, err := base64.StdEncoding.DecodeString(state.L1StateDump) + if err != nil { + return nil, fmt.Errorf("failed to decode opState: %w", err) + } + + // Create gzip reader from the base64 decoded data + gr, err := gzip.NewReader(bytes.NewReader(decoded)) + if err != nil { + return nil, fmt.Errorf("failed to create gzip reader: %w", err) + } + defer gr.Close() + + // Read and decode the contents + contents, err := io.ReadAll(gr) + if err != nil { + return nil, fmt.Errorf("failed to read opState: %w", err) + } + + var alloc types.GenesisAlloc + if err := json.Unmarshal(contents, &alloc); err != nil { + return nil, fmt.Errorf("failed to unmarshal opState: %w", err) + } + + return alloc, nil +} + +var ( + prefundedBalance, _ = new(big.Int).SetString("10000000000000000000000", 16) +) + +func appendPrefundedAccountsToAlloc(allocs *types.GenesisAlloc, privKeys []string) error { + for _, privStr := range privKeys { + priv, err := getPrivKey(privStr) + if err != nil { + return err + } + addr := ecrypto.PubkeyToAddress(priv.PublicKey) + (*allocs)[addr] = types.Account{ + Balance: prefundedBalance, + Nonce: 1, + } + } + return nil +} From 73fe70a6e7b8d8b8f6523ef9771b00acf110d0ec Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Thu, 18 Dec 2025 12:27:39 +0100 Subject: [PATCH 2/2] Remove the artifacts struct --- main.go | 19 ++++---- playground/artifacts.go | 84 ++++++++++++++++------------------- playground/components_test.go | 2 +- playground/manifest_test.go | 6 +-- 4 files changed, 52 insertions(+), 59 deletions(-) diff --git a/main.go b/main.go index e50569f..7571be6 100644 --- a/main.go +++ b/main.go @@ -225,12 +225,15 @@ func runIt(recipe playground.Recipe) error { overrides[parts[0]] = parts[1] } + out, err := playground.NewOutput(outputFlag) + if err != nil { + return err + } + builder := recipe.Artifacts() - builder.OutputDir(outputFlag) builder.GenesisDelay(genesisDelayFlag) builder.PrefundedAccounts(prefundedAccounts) - artifacts, err := builder.Build() - if err != nil { + if err := builder.Build(out); err != nil { return err } @@ -244,13 +247,13 @@ func runIt(recipe playground.Recipe) error { }, } - svcManager := playground.NewManifest(exCtx, artifacts.Out) + svcManager := playground.NewManifest(exCtx, out) recipe.Apply(svcManager) // generate the dot graph dotGraph := svcManager.GenerateDotGraph() - if err := artifacts.Out.WriteFile("graph.dot", dotGraph); err != nil { + if err := out.WriteFile("graph.dot", dotGraph); err != nil { return err } @@ -264,7 +267,7 @@ func runIt(recipe playground.Recipe) error { } if withPrometheus { - if err := playground.CreatePrometheusServices(svcManager, artifacts.Out); err != nil { + if err := playground.CreatePrometheusServices(svcManager, out); err != nil { return fmt.Errorf("failed to create prometheus services: %w", err) } } @@ -278,7 +281,7 @@ func runIt(recipe playground.Recipe) error { } cfg := &playground.RunnerConfig{ - Out: artifacts.Out, + Out: out, Manifest: svcManager, BindHostPortsLocally: !bindExternal, NetworkName: networkName, @@ -362,7 +365,7 @@ func runIt(recipe playground.Recipe) error { watchdogErr := make(chan error, 1) if watchdog { go func() { - if err := playground.RunWatchdog(artifacts.Out, svcManager.Services); err != nil { + if err := playground.RunWatchdog(out, svcManager.Services); err != nil { watchdogErr <- fmt.Errorf("watchdog failed: %w", err) } }() diff --git a/playground/artifacts.go b/playground/artifacts.go index e39ede3..a10f601 100644 --- a/playground/artifacts.go +++ b/playground/artifacts.go @@ -63,7 +63,6 @@ var clConfigContent []byte var queryReadyCheck []byte type ArtifactsBuilder struct { - outputDir string applyLatestL1Fork bool genesisDelay uint64 applyLatestL2Fork *uint64 @@ -74,7 +73,6 @@ type ArtifactsBuilder struct { func NewArtifactsBuilder() *ArtifactsBuilder { return &ArtifactsBuilder{ - outputDir: "", applyLatestL1Fork: false, genesisDelay: MinimumGenesisDelay, l1BlockTimeInSeconds: defaultL1BlockTimeSeconds, @@ -82,11 +80,6 @@ func NewArtifactsBuilder() *ArtifactsBuilder { } } -func (b *ArtifactsBuilder) OutputDir(outputDir string) *ArtifactsBuilder { - b.outputDir = outputDir - return b -} - func (b *ArtifactsBuilder) ApplyLatestL1Fork(applyLatestL1Fork bool) *ArtifactsBuilder { b.applyLatestL1Fork = applyLatestL1Fork return b @@ -138,32 +131,9 @@ func (b *ArtifactsBuilder) getPrefundedAccounts() []string { return staticPrefundedAccounts } -type Artifacts struct { - Out *output -} - -func (b *ArtifactsBuilder) Build() (*Artifacts, error) { +func (b *ArtifactsBuilder) Build(out *output) error { defer utils.StartTimer("artifacts.builder")() - homeDir, err := GetHomeDir() - if err != nil { - return nil, err - } - if b.outputDir == "" { - // Use the $HOMEDIR/devnet as the default output - b.outputDir = filepath.Join(homeDir, "devnet") - } - - out := &output{dst: b.outputDir, homeDir: homeDir} - - // check if the output directory exists - if out.Exists("") { - log.Printf("deleting existing output directory %s", b.outputDir) - if err := out.Remove(""); err != nil { - return nil, err - } - } - if b.genesisDelay < MinimumGenesisDelay { log.Printf("genesis delay must be at least %d seconds, using %d", MinimumGenesisDelay, MinimumGenesisDelay) b.genesisDelay = MinimumGenesisDelay @@ -182,10 +152,10 @@ func (b *ArtifactsBuilder) Build() (*Artifacts, error) { // load the config.yaml file clConfig, err := params.UnmarshalConfig([]byte(clConfigContentStr), nil) if err != nil { - return nil, err + return err } if err := params.SetActive(clConfig); err != nil { - return nil, err + return err } genesisTime := uint64(time.Now().Add(time.Duration(b.genesisDelay) * time.Second).Unix()) @@ -197,14 +167,14 @@ func (b *ArtifactsBuilder) Build() (*Artifacts, error) { // add pre-funded accounts if err := appendPrefundedAccountsToAlloc(&gen.Alloc, b.getPrefundedAccounts()); err != nil { - return nil, err + return err } // Apply Optimism pre-state { opAllocs, err := readOptimismL1Allocs() if err != nil { - return nil, err + return err } maps.Copy(gen.Alloc, opAllocs) } @@ -221,12 +191,12 @@ func (b *ArtifactsBuilder) Build() (*Artifacts, error) { priv, pub, err := interop.DeterministicallyGenerateKeys(0, 100) if err != nil { - return nil, err + return err } depositData, roots, err := interop.DepositDataFromKeysWithExecCreds(priv, pub, 100) if err != nil { - return nil, err + return err } opts := make([]interop.PremineGenesisOpt, 0) @@ -234,7 +204,7 @@ func (b *ArtifactsBuilder) Build() (*Artifacts, error) { state, err := interop.NewPreminedGenesis(context.Background(), genesisTime, 0, 100, v, block, opts...) if err != nil { - return nil, err + return err } err = out.WriteBatch(map[string]interface{}{ @@ -250,7 +220,7 @@ func (b *ArtifactsBuilder) Build() (*Artifacts, error) { "scripts/query.sh": queryReadyCheck, }) if err != nil { - return nil, err + return err } { @@ -274,7 +244,7 @@ func (b *ArtifactsBuilder) Build() (*Artifacts, error) { // Update the allocs to include the same prefunded accounts as the L1 genesis. allocs := types.GenesisAlloc{} if err := appendPrefundedAccountsToAlloc(&allocs, b.getPrefundedAccounts()); err != nil { - return nil, err + return err } // override l2 genesis, make the timestamp start 2 seconds after the L1 genesis @@ -292,13 +262,13 @@ func (b *ArtifactsBuilder) Build() (*Artifacts, error) { newOpGenesis, err := overrideJSON(opGenesis, input) if err != nil { - return nil, err + return err } // the hash of the genesis has changed beause of the timestamp so we need to account for that opGenesisBlock, err := toOpBlock(newOpGenesis) if err != nil { - return nil, fmt.Errorf("failed to convert opGenesis to block: %w", err) + return fmt.Errorf("failed to convert opGenesis to block: %w", err) } opGenesisHash := opGenesisBlock.Hash() @@ -329,18 +299,18 @@ func (b *ArtifactsBuilder) Build() (*Artifacts, error) { newOpRollup, err := overrideJSON(opRollupConfig, rollupInput) if err != nil { - return nil, err + return err } if err := out.WriteFile("l2-genesis.json", newOpGenesis); err != nil { - return nil, err + return err } if err := out.WriteFile("rollup.json", newOpRollup); err != nil { - return nil, err + return err } } - return &Artifacts{Out: out}, nil + return nil } type OpGenesisTmplInput struct { @@ -423,6 +393,28 @@ type output struct { enodeAddrSeq *big.Int } +func NewOutput(dst string) (*output, error) { + homeDir, err := GetHomeDir() + if err != nil { + return nil, err + } + if dst == "" { + // Use the $HOMEDIR/devnet as the default output + dst = filepath.Join(homeDir, "devnet") + } + + out := &output{dst: dst, homeDir: homeDir} + + // check if the output directory exists + if out.Exists("") { + if err := out.Remove(""); err != nil { + return nil, err + } + } + + return out, nil +} + func (o *output) AbsoluteDstPath() (string, error) { return filepath.Abs(o.dst) } diff --git a/playground/components_test.go b/playground/components_test.go index 8c114f6..70febbe 100644 --- a/playground/components_test.go +++ b/playground/components_test.go @@ -114,7 +114,7 @@ func (tt *testFramework) test(s ServiceGen, args []string) *Manifest { err := recipe.Flags().Parse(args) require.NoError(t, err) - _, err = recipe.Artifacts().OutputDir(e2eTestDir).Build() + err = recipe.Artifacts().Build(o) require.NoError(t, err) } diff --git a/playground/manifest_test.go b/playground/manifest_test.go index 2b4ac6e..8e8c613 100644 --- a/playground/manifest_test.go +++ b/playground/manifest_test.go @@ -63,14 +63,12 @@ func TestManifestWriteRead(t *testing.T) { out := newTestOutput(t) recipe := &L1Recipe{} - builder := recipe.Artifacts() - builder.OutputDir(out.dst) - artifacts, err := builder.Build() + err := builder.Build(out) assert.NoError(t, err) - manifest := NewManifest(&ExContext{Contender: &ContenderContext{}}, artifacts.Out) + manifest := NewManifest(&ExContext{Contender: &ContenderContext{}}, out) recipe.Apply(manifest) assert.NoError(t, manifest.SaveJson())