synapsecns/sanguine

View on GitHub
services/scribe/cmd/commands.go

Summary

Maintainability
A
0 mins
Test Coverage
package cmd

// TODO update this to match new commands + migrate flags to config.
import (
    "github.com/synapsecns/sanguine/core/metrics"
    "github.com/synapsecns/sanguine/services/scribe/backend"
    "github.com/synapsecns/sanguine/services/scribe/service"
    // used to embed markdown.
    _ "embed"
    "fmt"

    markdown "github.com/MichaelMure/go-term-markdown"
    "github.com/hashicorp/consul/sdk/freeport"
    "github.com/jftuga/termsize"
    "github.com/synapsecns/sanguine/core"
    "github.com/synapsecns/sanguine/services/scribe/api"
    "github.com/synapsecns/sanguine/services/scribe/config"
    "github.com/synapsecns/sanguine/services/scribe/db"
    "github.com/urfave/cli/v2"
)

//go:embed cmd.md
var help string

// MaxConfirmations is the maximum number of confirmations.
var MaxConfirmations = 3

// infoCommand gets info about using the scribe service.
var infoCommand = &cli.Command{
    Name:        "info",
    Description: "learn how to use scribe cli",
    Action: func(c *cli.Context) error {
        fmt.Println(string(markdown.Render(help, termsize.Width(), 6)))
        return nil
    },
}

var configFlag = &cli.StringFlag{
    Name:      "config",
    Usage:     "--config /Users/synapsecns/config.yaml",
    TakesFile: true,
    Required:  true,
}

var portFlag = &cli.UintFlag{
    Name:  "port",
    Usage: "--port 5121",
    Value: 0,
}

var dbFlag = &cli.StringFlag{
    Name:     "db",
    Usage:    "--db <sqlite> or <mysql>",
    Value:    "sqlite",
    Required: true,
}

var pathFlag = &cli.StringFlag{
    Name:     "path",
    Usage:    "--path <path/to/database> or <database url>",
    Value:    "",
    Required: true,
}

func createScribeParameters(c *cli.Context) (eventDB db.EventDB, clients map[uint32][]backend.ScribeBackend, scribeConfig config.Config, err error) {
    scribeConfig, err = config.DecodeConfig(core.ExpandOrReturnPath(c.String(configFlag.Name)))
    if err != nil {
        return nil, nil, scribeConfig, fmt.Errorf("could not decode config: %w", err)
    }

    eventDB, err = api.InitDB(c.Context, c.String(dbFlag.Name), c.String(pathFlag.Name), metrics.Get(), c.Bool(skipMigrationFlag.Name))
    if err != nil {
        return nil, nil, scribeConfig, fmt.Errorf("could not initialize database: %w", err)
    }

    clients = make(map[uint32][]backend.ScribeBackend)
    for _, client := range scribeConfig.Chains {
        for confNum := 1; confNum <= MaxConfirmations; confNum++ {
            backendClient, err := backend.DialBackend(c.Context, fmt.Sprintf("%s/%d/rpc/%d", scribeConfig.RPCURL, confNum, client.ChainID), metrics.Get())
            if err != nil {
                return nil, nil, scribeConfig, fmt.Errorf("could not start client for %s", fmt.Sprintf("%s/1/rpc/%d", scribeConfig.RPCURL, client.ChainID))
            }
            clients[client.ChainID] = append(clients[client.ChainID], backendClient)
        }
    }

    return eventDB, clients, scribeConfig, nil
}

var scribeCommand = &cli.Command{
    // TODO: rename this command to indexer
    Name:        "scribe",
    Description: "scribe runs the scribe, livefilling across all specified chains",
    Flags:       []cli.Flag{configFlag, dbFlag, pathFlag},
    Action: func(c *cli.Context) error {
        db, clients, decodeConfig, err := createScribeParameters(c)
        if err != nil {
            return err
        }
        scribe, err := service.NewScribe(db, clients, decodeConfig, metrics.Get())
        if err != nil {
            return fmt.Errorf("could not create scribe: %w", err)
        }
        err = scribe.Start(c.Context)
        if err != nil {
            return fmt.Errorf("could not start scribe: %w", err)
        }
        return nil
    },
}

var serverCommand = &cli.Command{
    Name:        "server",
    Description: "starts a graphql server",
    Flags:       []cli.Flag{portFlag, dbFlag, pathFlag, omniRPCFlag, skipMigrationServerFlag},
    Action: func(c *cli.Context) error {
        err := api.Start(c.Context, api.Config{
            Port:           uint16(c.Uint(portFlag.Name)),
            Database:       c.String(dbFlag.Name),
            Path:           c.String(pathFlag.Name),
            OmniRPCURL:     c.String(omniRPCFlag.Name),
            SkipMigrations: c.Bool(skipMigrationServerFlag.Name),
        }, metrics.Get())
        if err != nil {
            return fmt.Errorf("could not start server: %w", err)
        }

        return nil
    },
}

var omniRPCFlag = &cli.StringFlag{
    Name:     "omnirpc",
    Usage:    "--omnirpc https://omnirpc.url",
    Required: true,
}

var skipMigrationFlag = &cli.BoolFlag{
    Name:  "skip-migrations",
    Usage: "--skip-migrations",
    Value: false,
}

var skipMigrationServerFlag = &cli.BoolFlag{
    Name:     skipMigrationFlag.Name,
    Usage:    skipMigrationFlag.Usage,
    Required: skipMigrationFlag.Required,
    Value:    true,
}

var deploymentsPath = &cli.StringFlag{
    Name:     "deployments-dir",
    Usage:    "--deployments-dir /path/to/contracts/deployments",
    Required: true,
}

var confirmationsFlag = &cli.UintFlag{
    Name:  "confirmations",
    Value: 50,
}

var outputPathFlag = &cli.StringFlag{
    Name:      "output-path",
    TakesFile: true,
}

var skippedChainIdsFlag = &cli.IntSliceFlag{
    Name:  "skipped-chains",
    Usage: "--skipped-chains 1,2,3",
    // skip common testnets by default
    Value: cli.NewIntSlice(5, 335, 43113, 1666700000),
}

var generateCommand = &cli.Command{
    Name:        "generate",
    Description: "generates a config from a hardhat deployment folder",
    Flags: []cli.Flag{
        omniRPCFlag,
        deploymentsPath,
        confirmationsFlag,
        skippedChainIdsFlag,
        outputPathFlag,
    },
    Action: func(c *cli.Context) error {
        //nolint: wrapcheck
        return config.GenerateConfig(c.Context, c.String(omniRPCFlag.Name), core.ExpandOrReturnPath(c.String(deploymentsPath.Name)),
            core.ExpandOrReturnPath(c.String(outputPathFlag.Name)), c.IntSlice(skippedChainIdsFlag.Name), config.DefaultClientGenerator)
    },
}

func init() {
    ports, err := freeport.Take(1)
    if len(ports) > 0 && err != nil {
        portFlag.Value = uint(ports[0])
    }
}