Skip to content
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

Feat/added toml supersim config closes #104 #295

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ go.work.sum
/main
dist/
cache/

# Ignore customized configuration files
*.toml
!*.toml.template
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,44 @@ brew install ethereum-optimism/tap/supersim

Download the executable for your platform from the [GitHub releases page](https://github.com/ethereum-optimism/supersim/releases).

### 3. Start `supersim` in vanilla mode
### 3. Configure `supersim` (Optional)

#### Option 1: Use the .toml.template File
The configuration file for Supersim is provided as a `.toml.template` file. This ensures you can start with a pre-defined setup while allowing you to customize it to your needs.

#### Copy the .toml.template file to .toml:
Rename the template file to remove the `.template` extension. Use the following command:
```sh
cp config.toml.template config.toml
```
#### Edit the .toml File:
Open `config.toml` in your preferred text editor (e.g., VS Code, Vim, or Nano) and customize the parameters to suit your setup. For example:
```toml
# Supersim Configuration File Example

# L1 instance settings
# Host address for the L1 instance
# Default: "127.0.0.1"
l1.host = "0.0.0.0"

# Listening port for the L1 instance. `0` binds to any available port
# Default: 8545
l1.port = 3000
```

Save the file.


#### Option 2: Configure via CLI
Supersim can also be configured directly via the CLI without editing a configuration file. For example, you can specify the required parameters when starting Supersim:
```sh
supersim --l1.host "0.0.0.0" --l1.port 3000 --l2.host "0.0.0.0" --l2.starting.port 3001

```



### 4. Start `supersim` in vanilla mode

```sh
supersim
Expand Down
33 changes: 33 additions & 0 deletions config.toml.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Title = "Supersim Configuration"
Desc = "Configuration for the Supersim application."


# Admin server settings
admin_port = 8420 # Listening port for the admin server (Default: 8420)

# Interoperability settings
interop_autorelay = false # Automatically relay messages sent to the L2ToL2CrossDomainMessenger (Default: false)
interop_delay = 0 # Delay before relaying messages sent to the L2ToL2CrossDomainMessenger (Default: 0)

# L1 instance settings
l1_host = "127.0.0.1" # Host address for the L1 instance (Default: "127.0.0.1")
l1_port = 8545 # Listening port for the L1 instance. `0` binds to any available port (Default: 8545)

# L2 instance settings
l2_host = "127.0.0.1" # Host address for L2 instances (Default: "127.0.0.1")
l2_starting_port = 9545 # Starting port to increment from for L2 chains. `0` binds each chain to any available port (Default: 9545)

# Logging settings
log_color = false # Color the log output if in terminal mode (Default: false)
log_format = "text" # Format the log output. Supported formats: 'text', 'terminal', 'logfmt', 'json', 'json-pretty' (Default: "text")
log_level = "INFO" # The lowest log level that will be output (Default: "INFO")
log_pid = false # Show pid in the log (Default: false)
logs_directory = "" # Directory to store logs

[commands]

[fork]
# l1_fork_height = 0 # L1 height to fork the superchain (bounds L2 time). `0` for latest
# chains = ["automata", "base"] # Chains to fork in the superchain
# network = "mainnet" # Superchain network. Options: sepolia-dev-0, mainnet, sepolia
# interop_enabled = true
130 changes: 112 additions & 18 deletions config/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package config

import (
"fmt"
"os"
"strings"

opservice "github.com/ethereum-optimism/optimism/op-service"
"github.com/pelletier/go-toml/v2"

"net"
"regexp"
Expand Down Expand Up @@ -154,32 +156,40 @@ type CLIConfig struct {
L2Host string
}

func ReadCLIConfig(ctx *cli.Context) (*CLIConfig, error) {
cfg := &CLIConfig{
AdminPort: ctx.Uint64(AdminPortFlagName),
type ForkTOMLConfig struct {
L1ForkHeight uint64 `toml:"l1_fork_height"`
Network string `toml:"network"`
Chains []string `toml:"chains"`

L1Port: ctx.Uint64(L1PortFlagName),
L2StartingPort: ctx.Uint64(L2StartingPortFlagName),
InteropEnabled bool `toml:"interop_enabled"`
}

InteropAutoRelay: ctx.Bool(InteropAutoRelayFlagName),
InteropDelay: ctx.Uint64(InteropDelayFlagName),
type TOMLConfig struct {
AdminPort uint64 `toml:"admin_port"`

LogsDirectory: ctx.String(LogsDirectoryFlagName),
L1Port uint64 `toml:"l1_port"`
L2StartingPort uint64 `toml:"l2_starting_port"`

L1Host: ctx.String(L1HostFlagName),
L2Host: ctx.String(L2HostFlagName),
}
InteropAutoRelay bool `toml:"interop_autorelay"`
InteropDelay uint64 `toml:"interop_delay"`

if ctx.Command.Name == ForkCommandName {
cfg.ForkConfig = &ForkCLIConfig{
L1ForkHeight: ctx.Uint64(L1ForkHeightFlagName),
Network: ctx.String(NetworkFlagName),
Chains: ctx.StringSlice(ChainsFlagName),
LogsDirectory string `toml:"logs_directory"`

InteropEnabled: ctx.Bool(InteropEnabledFlagName),
}
ForkConfig *ForkTOMLConfig `toml:"fork"`

L1Host string `toml:"l1_host"`
L2Host string `toml:"l2_host"`
}

func ReadCLIConfig(ctx *cli.Context) (*CLIConfig, error) {
cfg := &CLIConfig{}

if err := readTOMLConfig(cfg); err != nil {
return nil, err
}

populateFromCLIContext(cfg, ctx)

return cfg, cfg.Check()
}

Expand Down Expand Up @@ -244,3 +254,87 @@ func validateHost(host string) error {

return nil
}

func readTOMLConfig(cfg *CLIConfig) error {
tomlCfgFile := "config.toml"
if _, err := os.Stat(tomlCfgFile); err == nil {
content, err := os.ReadFile(tomlCfgFile)
if err != nil {
return fmt.Errorf("failed to read TOML config: %w", err)
}

var tomlCfg TOMLConfig
if err := toml.Unmarshal(content, &tomlCfg); err != nil {
return fmt.Errorf("error parsing TOML: %v", err)
}

cfg.AdminPort = tomlCfg.AdminPort
cfg.L1Port = tomlCfg.L1Port
cfg.L2StartingPort = tomlCfg.L2StartingPort
cfg.InteropAutoRelay = tomlCfg.InteropAutoRelay
cfg.InteropDelay = tomlCfg.InteropDelay
cfg.LogsDirectory = tomlCfg.LogsDirectory
cfg.L1Host = tomlCfg.L1Host
cfg.L2Host = tomlCfg.L2Host

if tomlCfg.ForkConfig != nil {
cfg.ForkConfig = &ForkCLIConfig{}
if tomlCfg.ForkConfig.L1ForkHeight != 0 {
cfg.ForkConfig.L1ForkHeight = tomlCfg.ForkConfig.L1ForkHeight
}
if len(tomlCfg.ForkConfig.Chains) > 0 {
cfg.ForkConfig.Chains = tomlCfg.ForkConfig.Chains
}
if tomlCfg.ForkConfig.Network != "" {
cfg.ForkConfig.Network = tomlCfg.ForkConfig.Network
}
if tomlCfg.ForkConfig.InteropEnabled {
cfg.ForkConfig.InteropEnabled = tomlCfg.ForkConfig.InteropEnabled
}

if cfg.ForkConfig.L1ForkHeight == 0 && len(cfg.ForkConfig.Chains) == 0 && cfg.ForkConfig.Network == "" {
cfg.ForkConfig = nil
}
}
} else if !os.IsNotExist(err) {
return fmt.Errorf("error checking TOML config file: %w", err)
}

return nil
}

func populateFromCLIContext(cfg *CLIConfig, ctx *cli.Context) {
if cfg.AdminPort == 0 {
cfg.AdminPort = ctx.Uint64(AdminPortFlagName)
}
if cfg.L1Port == 0 {
cfg.L1Port = ctx.Uint64(L1PortFlagName)
}
if cfg.L2StartingPort == 0 {
cfg.L2StartingPort = ctx.Uint64(L2StartingPortFlagName)
}
if !cfg.InteropAutoRelay {
cfg.InteropAutoRelay = ctx.Bool(InteropAutoRelayFlagName)
}
if cfg.InteropDelay == 0 {
cfg.InteropDelay = ctx.Uint64(InteropDelayFlagName)
}
if cfg.LogsDirectory == "" {
cfg.LogsDirectory = ctx.String(LogsDirectoryFlagName)
}
if cfg.L1Host == "" {
cfg.L1Host = ctx.String(L1HostFlagName)
}
if cfg.L2Host == "" {
cfg.L2Host = ctx.String(L2HostFlagName)
}

if ctx.Command.Name == ForkCommandName {
cfg.ForkConfig = &ForkCLIConfig{
L1ForkHeight: ctx.Uint64(L1ForkHeightFlagName),
Network: ctx.String(NetworkFlagName),
Chains: ctx.StringSlice(ChainsFlagName),
InteropEnabled: ctx.Bool(InteropEnabledFlagName),
}
}
}
69 changes: 69 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package config

import (
"os"
"path/filepath"
"testing"

"github.com/urfave/cli/v2"
)

func TestReadCLIConfig(t *testing.T) {
cwd, err := os.Getwd()
if err != nil {
t.Fatalf("unable to determine executable path: %v", err)
}

cfgPath := filepath.Join(cwd, "config.toml")

tomlContent := `
admin_port = 8420
l1_port = 8545
l2_starting_port = 9545
interop_autorelay = true
interop_delay = 0
logs_directory = "/var/logs"
l1_host = "127.0.0.1"
l2_host = "127.0.0.1"
`

tmpFile, err := os.Create(cfgPath)
if err != nil {
t.Fatalf("failed to create config.toml file: %v", err)
}
defer os.Remove(cfgPath)

if _, err := tmpFile.WriteString(tomlContent); err != nil {
t.Fatalf("failed to write to config.toml file: %v", err)
}
tmpFile.Close()

ctx := cli.NewContext(nil, nil, nil)

cfg, err := ReadCLIConfig(ctx)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

if cfg.AdminPort != 8420 {
t.Errorf("expected AdminPort to be 8420, got %d", cfg.AdminPort)
}
if cfg.L1Port != 8545 {
t.Errorf("expected L1Port to be 8545, got %d", cfg.L1Port)
}
if cfg.L2StartingPort != 9545 {
t.Errorf("expected L2StartingPort to be 9545, got %d", cfg.L2StartingPort)
}
if cfg.InteropAutoRelay != true {
t.Errorf("expected InteropAutoRelay to be true, got %v", cfg.InteropAutoRelay)
}
if cfg.LogsDirectory != "/var/logs" {
t.Errorf("expected LogsDirectory to be '/var/logs', got '%s'", cfg.LogsDirectory)
}
if cfg.L1Host != "127.0.0.1" {
t.Errorf("expected L1Host to be '127.0.0.1', got '%s'", cfg.L1Host)
}
if cfg.L2Host != "127.0.0.1" {
t.Errorf("expected L2Host to be '127.0.0.1', got '%s'", cfg.L2Host)
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@ github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
Expand Down