Skip to content

Commit

Permalink
Add relayer init CLI command. (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
dzmitryhil committed Dec 8, 2023
1 parent 5b61dc1 commit 6b5f004
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 65 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ make build-relayer
make build-relayer-docker
```

## Init relayer

### Init relayer default config

The relayer uses `relayer.yaml` for its work. The file contains all required setting which can be adjusted.
To init the default config call.

```bash
./coreumbridge-xrpl-relayer init
```

The command will generate the default `relayer.yaml` config in the `$HOME/.coreumbridge-xrpl-relayer`.
Optionally you can provide `--home` to set different home directory.

## Run relayer in docker

If relayer docker image is not built, build it.
Expand Down
154 changes: 154 additions & 0 deletions relayer/cmd/cli/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package cli

import (
"bufio"
"os"
"path"
"time"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/CoreumFoundation/coreumbridge-xrpl/relayer/logger"
"github.com/CoreumFoundation/coreumbridge-xrpl/relayer/runner"
)

const (
// DefaultHomeDir is default home for the relayer.
DefaultHomeDir = ".coreumbridge-xrpl-relayer"
// FlagHome is home flag.
FlagHome = "home"
// That key name is constant here temporary, we will take it from the relayer config later.
relayerKeyName = "coreumbridge-xrpl-relayer"
)

// InitCmd returns the init cmd.
func InitCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "init",
Short: "Initializes the relayer home with the default config.",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
home, err := getRelayerHome(cmd)
if err != nil {
return err
}
log, err := getConsoleLogger()
if err != nil {
return err
}
log.Info(ctx, "Generating default settings", logger.StringField("home", home))
if err = runner.InitConfig(home, runner.DefaultConfig()); err != nil {
return err
}
log.Info(ctx, "Settings are generated successfully")
return nil
},
}

addHomeFlag(cmd)

return cmd
}

// StartCmd returns the start cmd.
func StartCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "start",
Short: "Start relayer.",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
// scan helps to wait for any input infinitely and just then call the relayer. That handles
// the relayer restart in the container. Because after the restart the container is detached, relayer
// requests the keyring password and fail inanimately.
log, err := getConsoleLogger()
if err != nil {
return err
}
log.Info(ctx, "Press any key to start the relayer.")
input := bufio.NewScanner(os.Stdin)
input.Scan()

// that code is just for an example and will be replaced later
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return errors.Wrap(err, "failed to get client context")
}
keyRecord, err := clientCtx.Keyring.Key(relayerKeyName)
if err != nil {
return errors.Wrap(err, "failed to get key from keyring")
}
address, err := keyRecord.GetAddress()
if err != nil {
return errors.Wrap(err, "failed to get address from the key record")
}
for {
select {
case <-ctx.Done():
return nil
case <-time.After(time.Second):
log.Info(ctx, "Address from the keyring extracted.", logger.StringField("address", address.String()))
}
}
},
}
addKeyringFlags(cmd)

return cmd
}

// KeyringCmd returns cosmos keyring cmd inti with the correct keys home.
func KeyringCmd() *cobra.Command {
return keys.Commands(path.Join(DefaultHomeDir, "keys"))
}

func getRelayerHome(cmd *cobra.Command) (string, error) {
home, err := cmd.Flags().GetString(FlagHome)
if err != nil {
return "", errors.WithStack(err)
}
if home == "" || home == DefaultHomeDir {
home, err = getUserHomeDir(DefaultHomeDir)
if err != nil {
return "", err
}
}

return home, nil
}

func getUserHomeDir(subPath ...string) (string, error) {
dirname, err := os.UserHomeDir()
if err != nil {
return "", errors.Wrap(err, "failed to get user home dir")
}
for _, item := range subPath {
dirname = path.Join(dirname, item)
}

return dirname, nil
}

func addHomeFlag(cmd *cobra.Command) {
cmd.PersistentFlags().String(FlagHome, DefaultHomeDir, "Relayer home directory")
}

func addKeyringFlags(cmd *cobra.Command) {
cmd.PersistentFlags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)")
cmd.PersistentFlags().String(flags.FlagKeyringDir, path.Join(DefaultHomeDir, "keys"), "The client Keyring directory; if omitted, the default 'home' directory will be used")
}

// returns the console logger initialised with the default logger config but with set `console` format.
func getConsoleLogger() (*logger.ZapLogger, error) {
cfg := runner.DefaultConfig().LoggingConfig
cfg.Format = "console"
zapLogger, err := logger.NewZapLogger(logger.ZapLoggerConfig(cfg))
if err != nil {
return nil, err
}

return zapLogger, nil
}
37 changes: 37 additions & 0 deletions relayer/cmd/cli/cli_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package cli_test

import (
"context"
"fmt"
"path"
"testing"

"github.com/spf13/cobra"
"github.com/stretchr/testify/require"

"github.com/CoreumFoundation/coreumbridge-xrpl/relayer/cmd/cli"
"github.com/CoreumFoundation/coreumbridge-xrpl/relayer/runner"
)

func TestInitCmd(t *testing.T) {
configPath := path.Join(t.TempDir(), "config-path")
configFilePath := path.Join(configPath, runner.ConfigFileName)
require.NoFileExists(t, configFilePath)

args := []string{
fmt.Sprintf("--%s=%s", cli.FlagHome, configPath),
}
executeCmd(t, cli.InitCmd(), args...)
require.FileExists(t, configFilePath)
}

func executeCmd(t *testing.T, cmd *cobra.Command, args ...string) {
t.Helper()

cmd.SetArgs(args)
if err := cmd.ExecuteContext(context.Background()); err != nil {
require.NoError(t, err)
}

t.Logf("Command %s is executed successfully", cmd.Name())
}
66 changes: 4 additions & 62 deletions relayer/cmd/main.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,17 @@
package main

import (
"bufio"
"context"
"fmt"
"os"
"path"
"time"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/CoreumFoundation/coreum-tools/pkg/run"
coreumapp "github.com/CoreumFoundation/coreum/v3/app"
"github.com/CoreumFoundation/coreum/v3/pkg/config"
)

var defaultKeyringDir = path.Join(".coreumbridge-xrpl-relayer", "keys")

const (
// That key name is constant here temporary, we will take it from the relayer config later.
relayerKeyName = "coreumbridge-xrpl-relayer"
"github.com/CoreumFoundation/coreumbridge-xrpl/relayer/cmd/cli"
)

func main() {
Expand Down Expand Up @@ -52,55 +40,9 @@ func RootCmd(ctx context.Context) *cobra.Command {
}
cmd.SetContext(ctx)

cmd.AddCommand(StartCmd(ctx))
cmd.AddCommand(keys.Commands(defaultKeyringDir))

return cmd
}

// StartCmd returns the start cmd.
func StartCmd(ctx context.Context) *cobra.Command {
cmd := &cobra.Command{
Use: "start",
Short: "Start relayer.",
RunE: func(cmd *cobra.Command, args []string) error {
// scan helps to wait for any input infinitely and just then call the relayer. That handles
// the relayer restart in the container. Because after the restart the container is detached, relayer
// requests the keyring password and fail inanimately.
// TODO(dzmitryhil) replace to logger once we integrate the runner
fmt.Print("Press any key to start the relayer.")
input := bufio.NewScanner(os.Stdin)
input.Scan()

// that code is just for an example and will be replaced later
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return errors.Wrap(err, "failed to get client context")
}
keyRecord, err := clientCtx.Keyring.Key(relayerKeyName)
if err != nil {
return errors.Wrap(err, "failed to get key from keyring")
}
address, err := keyRecord.GetAddress()
if err != nil {
return errors.Wrap(err, "failed to get address from the key record")
}
for {
select {
case <-ctx.Done():
return nil
case <-time.After(time.Second):
fmt.Printf("Address from the keyring:%s\n", address.String())
}
}
},
}
addKeyringFlags(cmd)
cmd.AddCommand(cli.InitCmd())
cmd.AddCommand(cli.StartCmd())
cmd.AddCommand(cli.KeyringCmd())

return cmd
}

func addKeyringFlags(cmd *cobra.Command) {
cmd.PersistentFlags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)")
cmd.PersistentFlags().String(flags.FlagKeyringDir, defaultKeyringDir, "The client Keyring directory; if omitted, the default 'home' directory will be used")
}
12 changes: 9 additions & 3 deletions relayer/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ import (
)

const (
configVersion = "v1"
configFileName = "relayer.yaml"
configVersion = "v1"
// ConfigFileName is file name used for the relayer config.
ConfigFileName = "relayer.yaml"

defaultCoreumChainID = coreumchainconstant.ChainIDMain
)
Expand Down Expand Up @@ -360,6 +361,11 @@ func InitConfig(homePath string, cfg Config) error {
return errors.Errorf("failed to initi config, file already exists, path:%s", path)
}

err := os.MkdirAll(homePath, 0o700)
if err != nil {
return errors.Errorf("failed to create dirs by path:%s", path)
}

file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o600)
if err != nil {
return errors.Wrapf(err, "failed to create config file, path:%s", path)
Expand Down Expand Up @@ -398,7 +404,7 @@ func ReadConfig(homePath string) (Config, error) {
}

func buildFilePath(homePath string) string {
return filepath.Join(homePath, configFileName)
return filepath.Join(homePath, ConfigFileName)
}

func getGRPCClientConn(grpcURL string) (*grpc.ClientConn, error) {
Expand Down

0 comments on commit 6b5f004

Please sign in to comment.