Skip to content

feat(cli): start devnet and info #862

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 10 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ repos:
language: script
entry: .pre-commit/run_regexp.sh
types: [ file, go ]
exclude: "(_test.go|contracts/bindings/.*|explorer/db/ent/mutation.go)"
exclude: "(_test.go|contracts/bindings/.*|explorer/db/ent|scripts/)"

- id: run-goversion
name: run-goversion
Expand Down
1 change: 1 addition & 0 deletions .pre-commit/run_regexp.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ function check() {
check 'Log messages must be capitalised' 'log\.(Error|Warn|Info|Debug)\(ctx, "[[:lower:]]' && exit 1
check 'Error messages must not be capitalised' 'errors\.(New|Wrap)\((err, )?"[[:upper:]]' && exit 1
check 'Rather add secrets to baseline with "make secrets-baseline"' 'pragma: allowlist secret' && exit 1
check 'See Go Guidelines for correct error wrapping' '%w' && exit 1

true
17 changes: 4 additions & 13 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,6 @@
"line_number": 15
}
],
"cli/cmd/devnet.go": [
{
"type": "Secret Keyword",
"filename": "cli/cmd/devnet.go",
"hashed_secret": "0738417b55905d283958aad3214022b2cf393911",
"is_verified": false,
"line_number": 26
}
],
"e2e/app/agent/prometheus.go": [
{
"type": "Secret Keyword",
Expand Down Expand Up @@ -220,21 +211,21 @@
"filename": "e2e/app/setup.go",
"hashed_secret": "55abc9109d5ea8a77be16bf3c76b4b199b524b12",
"is_verified": false,
"line_number": 355
"line_number": 362
},
{
"type": "Secret Keyword",
"filename": "e2e/app/setup.go",
"hashed_secret": "da57af224108e98e24d1e2a86221121990fa6478",
"is_verified": false,
"line_number": 384
"line_number": 391
},
{
"type": "Secret Keyword",
"filename": "e2e/app/setup.go",
"hashed_secret": "b11b6052ab454c167964c5b836faf0053a711b90",
"is_verified": false,
"line_number": 428
"line_number": 435
}
],
"e2e/manifests/staging.toml": [
Expand Down Expand Up @@ -887,5 +878,5 @@
}
]
},
"generated_at": "2024-04-16T14:08:35Z"
"generated_at": "2024-04-18T08:03:31Z"
}
155 changes: 142 additions & 13 deletions cli/cmd/devnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,31 @@ package cmd

import (
"context"
"encoding/json"
"fmt"
"math/big"
"strings"
"os"
"path/filepath"
"time"

"github.com/omni-network/omni/contracts/bindings"
"github.com/omni-network/omni/e2e/app"
"github.com/omni-network/omni/e2e/manifests"
"github.com/omni-network/omni/lib/anvil"
"github.com/omni-network/omni/lib/buildinfo"
"github.com/omni-network/omni/lib/errors"
"github.com/omni-network/omni/lib/ethclient"
"github.com/omni-network/omni/lib/ethclient/ethbackend"
"github.com/omni-network/omni/lib/log"
"github.com/omni-network/omni/lib/netconf"
"github.com/omni-network/omni/lib/txmgr"

"github.com/ethereum/go-ethereum/common"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"

"github.com/spf13/cobra"
)

const (
// privKeyHex0 of pre-funded anvil account 0.
privKeyHex0 = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
)

func newDevnetCmds() *cobra.Command {
cmd := &cobra.Command{
Use: "devnet",
Expand All @@ -36,6 +37,8 @@ func newDevnetCmds() *cobra.Command {
cmd.AddCommand(
newDevnetFundCmd(),
newDevnetAVSAllow(),
newDevnetStartCmd(),
newDevnetInfoCmd(),
)

return cmd
Expand Down Expand Up @@ -75,6 +78,128 @@ func newDevnetAVSAllow() *cobra.Command {
return cmd
}

func newDevnetStartCmd() *cobra.Command {
return &cobra.Command{
Use: "start",
Short: "Build and deploy a local docker compose devnet with 2 anvil nodes and a halo node",
RunE: func(cmd *cobra.Command, args []string) error {
return deployDevnet(cmd.Context())
},
}
}

func newDevnetInfoCmd() *cobra.Command {
return &cobra.Command{
Use: "info",
Short: "Display portal addresses and RPC URLs for the deployed devnet",
RunE: func(cmd *cobra.Command, args []string) error {
return printDevnetInfo()
},
}
}

func printDevnetInfo() error {
// Read the actual devnet external network.json.
// It contains correct portal addrs and external (localhost) RPCs.
network, err := loadDevnetNetwork()
if err != nil {
return errors.Wrap(err, "load internal network")
}

type info struct {
ChainID uint64 `json:"chain_id"`
ChainName string `json:"chain_name"`
PortalAddress common.Address `json:"portal_address"`
RPCURL string `json:"rpc_url"`
}

var infos []info
for _, chain := range network.EVMChains() {
infos = append(infos, info{
ChainID: chain.ID,
ChainName: chain.Name,
PortalAddress: chain.PortalAddress,
RPCURL: chain.RPCURL,
})
}

// Marshal and print the final combined JSON output
jsonOutput, err := json.MarshalIndent(infos, "", " ")
if err != nil {
return errors.Wrap(err, "marshal infos")
}
fmt.Println(string(jsonOutput))

return nil
}

func devnetDefinition(ctx context.Context) (app.Definition, error) {
manifestFile, err := writeTempFile(manifests.Devnet0())
if err != nil {
return app.Definition{}, err
}

defCfg := app.DefaultDefinitionConfig(ctx)
defCfg.ManifestFile = manifestFile
defCfg.OmniImgTag = buildinfo.Version()

def, err := app.MakeDefinition(ctx, defCfg, "devnet")
if err != nil {
return app.Definition{}, err
}

def.Testnet.Dir, err = devnetDir()
if err != nil {
return app.Definition{}, err
}

return def, nil
}

func loadDevnetNetwork() (netconf.Network, error) {
devnetPath, err := devnetDir()
if err != nil {
return netconf.Network{}, err
}

networkFile := filepath.Join(devnetPath, "network.json")

if _, err := os.Stat(networkFile); os.IsNotExist(err) {
return netconf.Network{}, &cliError{
Msg: "failed to load ~/.omni/devnet/network.json",
Suggest: "Have you run `omni devnet start` yet?",
}
}

return netconf.Load(networkFile)
}

// deployDevnet initializes and deploys the devnet network using the e2e app.
func deployDevnet(ctx context.Context) error {
def, err := devnetDefinition(ctx)
if err != nil {
return err
}

_, err = app.Deploy(ctx, def, app.DefaultDeployConfig())

return errors.Wrap(err, "deploy devnet")
}

func writeTempFile(content []byte) (string, error) {
f, err := os.CreateTemp("", "")
if err != nil {
return "", errors.Wrap(err, "create temp file")
}
defer f.Close()

if _, err := f.Write(content); err != nil {
return "", errors.Wrap(err, "write temp manifest")
}

return f.Name(), nil
}

type devnetAllowConfig struct {
OperatorAddr string
RPCURL string
Expand Down Expand Up @@ -177,20 +302,24 @@ func devnetBackend(ctx context.Context, rpcURL string) (common.Address, *ethback
return common.Address{}, nil, errors.Wrap(err, "get chain id")
}

funderPrivKey, err := ethcrypto.HexToECDSA(strings.TrimPrefix(privKeyHex0, "0x"))
if err != nil {
return common.Address{}, nil, errors.Wrap(err, "parse private key")
}

backend, err := ethbackend.NewBackend("", chainID.Uint64(), time.Second, ethCl)
if err != nil {
return common.Address{}, nil, errors.Wrap(err, "create backend")
}

funderAddr, err := backend.AddAccount(funderPrivKey)
funderAddr, err := backend.AddAccount(anvil.DevPrivateKey0())
if err != nil {
return common.Address{}, nil, errors.Wrap(err, "add account")
}

return funderAddr, backend, nil
}

func devnetDir() (string, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
return "", errors.Wrap(err, "user home dir")
}

return filepath.Join(homeDir, ".omni", "devnet"), nil
}
6 changes: 3 additions & 3 deletions e2e/app/definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ type DefinitionConfig struct {
}

// DefaultDefinitionConfig returns a default configuration for a Definition.
func DefaultDefinitionConfig() DefinitionConfig {
func DefaultDefinitionConfig(ctx context.Context) DefinitionConfig {
defaultTag := "main"
if out, err := exec.CommandOutput(context.Background(), "git", "rev-parse", "--short=7", "HEAD"); err == nil {
if out, err := exec.CommandOutput(ctx, "git", "rev-parse", "--short=7", "HEAD"); err == nil {
defaultTag = strings.TrimSpace(string(out))
}

Expand Down Expand Up @@ -302,7 +302,7 @@ func noNodesTestnet(manifest e2e.Manifest, file string, ifd e2e.InfrastructureDa

_, ipNet, err := net.ParseCIDR(ifd.Network)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("invalid IP network address %q", ifd.Network))
return nil, errors.Wrap(err, "parse network ip", "network", ifd.Network)
}

testnet := &e2e.Testnet{
Expand Down
1 change: 1 addition & 0 deletions e2e/app/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ func StartMonitoringReceipts(ctx context.Context, def Definition) func() error {
}

func MonitorCursors(ctx context.Context, portals map[uint64]netman.Portal, network netconf.Network) error {
network.EthereumChain()
for _, dest := range network.EVMChains() {
for _, src := range network.EVMChains() {
if src.ID == dest.ID {
Expand Down
7 changes: 7 additions & 0 deletions e2e/app/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ func Setup(ctx context.Context, def Definition, depCfg DeployConfig) error {
}
}

// Write an external network.json in base testnet dir.
// This allows for easy connecting or querying of the network
extNetwork := externalNetwork(def)
if err := netconf.Save(ctx, extNetwork, filepath.Join(def.Testnet.Dir, "network.json")); err != nil {
return errors.Wrap(err, "write network config")
}

if def.Testnet.Prometheus {
if err := agent.WriteConfig(ctx, def.Testnet, def.Cfg.AgentSecrets); err != nil {
return errors.Wrap(err, "write prom config")
Expand Down
3 changes: 2 additions & 1 deletion e2e/cmd/cmd.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"context"
"log/slog"
"regexp"

Expand All @@ -24,7 +25,7 @@ func New() *cobra.Command {
logCfg.Level = slog.LevelDebug.String()
logCfg.Color = log.ColorForce

defCfg := app.DefaultDefinitionConfig()
defCfg := app.DefaultDefinitionConfig(context.Background())

var def app.Definition

Expand Down
8 changes: 8 additions & 0 deletions e2e/manifests/devnet0.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Devnet0 is a tiny devnet. Only a single validator and two anvils.
# This is aimed at local dev environments.

network = "devnet"
anvil_chains = ["mock_l1", "mock_rollup"]
avs_target = "mock_l1"

[node.validator01]
2 changes: 1 addition & 1 deletion e2e/manifests/devnet1.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Devnet1 is the smallest devnet possible. It only a single validator.
# Devnet1 is the simple multi-validator devnet. It contains 2 validators.
network = "devnet"
anvil_chains = ["mock_l1", "mock_rollup"]
avs_target = "mock_l1"
Expand Down
12 changes: 12 additions & 0 deletions e2e/manifests/static.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package manifests

import (
_ "embed"
)

//go:embed devnet0.toml
var devnet0 []byte

func Devnet0() []byte {
return devnet0
}