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(cmd): Support non-interactive network add-local and paratime add #279

Merged
merged 1 commit into from
Sep 10, 2024
Merged
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
144 changes: 90 additions & 54 deletions cmd/network/add_local.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,67 +5,103 @@ import (
"fmt"

"github.com/spf13/cobra"
flag "github.com/spf13/pflag"

"github.com/oasisprotocol/oasis-sdk/client-sdk/go/config"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/connection"

"github.com/oasisprotocol/cli/cmd/common"
cliConfig "github.com/oasisprotocol/cli/config"
)

var addLocalCmd = &cobra.Command{
Use: "add-local <name> <rpc-endpoint>",
Short: "Add a new local network",
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
cfg := cliConfig.Global()
name, rpc := args[0], args[1]

net := config.Network{
RPC: rpc,
}
// Validate initial network configuration early.
cobra.CheckErr(config.ValidateIdentifier(name))
if !net.IsLocalRPC() {
cobra.CheckErr(fmt.Errorf("rpc-endpoint '%s' is not local", rpc))
}

// Connect to the network and query the chain context.
ctx := context.Background()
conn, err := connection.ConnectNoVerify(ctx, &net)
cobra.CheckErr(err)

chainContext, err := conn.Consensus().GetChainContext(ctx)
cobra.CheckErr(err)
net.ChainContext = chainContext
cobra.CheckErr(net.Validate())

// With a very high probability, the user is going to be
// adding a local endpoint for an existing network, so try
// to clone config details from any of the hardcoded
// defaults.
var clonedDefault bool
for _, defaultNet := range config.DefaultNetworks.All {
if defaultNet.ChainContext != chainContext {
continue
var (
symbol string
numDecimals uint
description string

addLocalCmd = &cobra.Command{
Use: "add-local <name> <rpc-endpoint>",
Short: "Add a new local network",
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
cfg := cliConfig.Global()
name, rpc := args[0], args[1]

net := config.Network{
RPC: rpc,
}
// Validate initial network configuration early.
cobra.CheckErr(config.ValidateIdentifier(name))
if !net.IsLocalRPC() {
cobra.CheckErr(fmt.Errorf("rpc-endpoint '%s' is not local", rpc))
}

// Connect to the network and query the chain context.
ctx := context.Background()
conn, err := connection.ConnectNoVerify(ctx, &net)
cobra.CheckErr(err)

chainContext, err := conn.Consensus().GetChainContext(ctx)
cobra.CheckErr(err)
net.ChainContext = chainContext
cobra.CheckErr(net.Validate())

// With a very high probability, the user is going to be
// adding a local endpoint for an existing network, so try
// to clone config details from any of the hardcoded
// defaults.
var clonedDefault bool
for _, defaultNet := range config.DefaultNetworks.All {
if defaultNet.ChainContext != chainContext {
continue
}

// Yep.
net.Denomination = defaultNet.Denomination
net.ParaTimes = defaultNet.ParaTimes
clonedDefault = true
break
}

if symbol != "" {
net.Denomination.Symbol = symbol
}

if numDecimals != 0 {
net.Denomination.Decimals = uint8(numDecimals)
}

if description != "" {
net.Description = description
}

// Yep.
net.Denomination = defaultNet.Denomination
net.ParaTimes = defaultNet.ParaTimes
clonedDefault = true
break
}

// If we failed to crib details from a hardcoded config,
// ask the user.
if !clonedDefault {
networkDetailsFromSurvey(&net)
}

err = cfg.Networks.Add(name, &net)
cobra.CheckErr(err)

err = cfg.Save()
cobra.CheckErr(err)
},
// If we failed to crib details from a hardcoded config,
// and user did not set -y flag ask the user.
if !clonedDefault && !common.GetAnswerYes() {
networkDetailsFromSurvey(&net)
}

err = cfg.Networks.Add(name, &net)
cobra.CheckErr(err)

err = cfg.Save()
cobra.CheckErr(err)
},
}
)

func init() {
addLocalCmd.Flags().AddFlagSet(common.AnswerYesFlag)

symbolFlag := flag.NewFlagSet("", flag.ContinueOnError)
symbolFlag.StringVar(&symbol, "symbol", "", "network's symbol")
addLocalCmd.Flags().AddFlagSet(symbolFlag)

numDecimalsFlag := flag.NewFlagSet("", flag.ContinueOnError)
numDecimalsFlag.UintVar(&numDecimals, "num-decimals", 0, "network's number of decimals")
addLocalCmd.Flags().AddFlagSet(numDecimalsFlag)

descriptionFlag := flag.NewFlagSet("", flag.ContinueOnError)
descriptionFlag.StringVar(&description, "description", "", "network's description")
addLocalCmd.Flags().AddFlagSet(descriptionFlag)
}
174 changes: 110 additions & 64 deletions cmd/paratime/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,75 +5,121 @@ import (

"github.com/AlecAivazis/survey/v2"
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"

"github.com/oasisprotocol/oasis-sdk/client-sdk/go/config"

"github.com/oasisprotocol/cli/cmd/common"
cliConfig "github.com/oasisprotocol/cli/config"
)

var addCmd = &cobra.Command{
Use: "add <network> <name> <id>",
Short: "Add a new ParaTime",
Args: cobra.ExactArgs(3),
Run: func(cmd *cobra.Command, args []string) {
cfg := cliConfig.Global()
network, name, id := args[0], args[1], args[2]

net, exists := cfg.Networks.All[network]
if !exists {
cobra.CheckErr(fmt.Errorf("network '%s' does not exist", network))
}

pt := config.ParaTime{
ID: id,
}
// Validate initial paratime configuration early.
cobra.CheckErr(config.ValidateIdentifier(name))
cobra.CheckErr(pt.Validate())

// Ask user for some additional parameters.
questions := []*survey.Question{
{
Name: "description",
Prompt: &survey.Input{Message: "Description:"},
},
{
Name: "symbol",
Prompt: &survey.Input{
Message: "Denomination symbol:",
Default: net.Denomination.Symbol,
},
},
{
Name: "decimals",
Prompt: &survey.Input{
Message: "Denomination decimal places:",
Default: fmt.Sprintf("%d", net.Denomination.Decimals),
var (
symbol string
numDecimals uint
description string

addCmd = &cobra.Command{
Use: "add <network> <name> <id>",
Short: "Add a new ParaTime",
Args: cobra.ExactArgs(3),
Run: func(cmd *cobra.Command, args []string) {
cfg := cliConfig.Global()
network, name, id := args[0], args[1], args[2]

net, exists := cfg.Networks.All[network]
if !exists {
cobra.CheckErr(fmt.Errorf("network '%s' does not exist", network))
}

pt := config.ParaTime{
ID: id,
}
// Validate initial paratime configuration early.
cobra.CheckErr(config.ValidateIdentifier(name))
cobra.CheckErr(pt.Validate())

paratimeInfo := struct {
Description string
Symbol string
Decimals uint8
}{
Symbol: net.Denomination.Symbol,
Decimals: net.Denomination.Decimals,
}

if symbol != "" {
paratimeInfo.Symbol = symbol
}

if numDecimals != 0 {
paratimeInfo.Decimals = uint8(numDecimals)
}

if description != "" {
paratimeInfo.Description = description
}

if !common.GetAnswerYes() {
// Ask user for some additional parameters.
questions := []*survey.Question{
{
Name: "description",
Prompt: &survey.Input{
Message: "Description:",
Default: paratimeInfo.Description,
},
},
amela marked this conversation as resolved.
Show resolved Hide resolved
{
Name: "symbol",
Prompt: &survey.Input{
Message: "Denomination symbol:",
Default: paratimeInfo.Symbol,
},
},
{
Name: "decimals",
Prompt: &survey.Input{
Message: "Denomination decimal places:",
Default: fmt.Sprintf("%d", paratimeInfo.Decimals),
},
Validate: survey.Required,
},
}

err := survey.Ask(questions, &paratimeInfo)
cobra.CheckErr(err)
}

pt.Description = paratimeInfo.Description
pt.Denominations = map[string]*config.DenominationInfo{
config.NativeDenominationKey: {
Symbol: paratimeInfo.Symbol,
Decimals: paratimeInfo.Decimals,
},
Validate: survey.Required,
},
}
answers := struct {
Description string
Symbol string
Decimals uint8
}{}
err := survey.Ask(questions, &answers)
cobra.CheckErr(err)

pt.Description = answers.Description
pt.Denominations = map[string]*config.DenominationInfo{
config.NativeDenominationKey: {
Symbol: answers.Symbol,
Decimals: answers.Decimals,
},
}
pt.ConsensusDenomination = config.NativeDenominationKey // TODO: Make this configurable.

err = net.ParaTimes.Add(name, &pt)
cobra.CheckErr(err)

err = cfg.Save()
cobra.CheckErr(err)
},
}
pt.ConsensusDenomination = config.NativeDenominationKey // TODO: Make this configurable.

err := net.ParaTimes.Add(name, &pt)
cobra.CheckErr(err)

err = cfg.Save()
cobra.CheckErr(err)
},
}
)

func init() {
addCmd.Flags().AddFlagSet(common.AnswerYesFlag)

symbolFlag := flag.NewFlagSet("", flag.ContinueOnError)
symbolFlag.StringVar(&symbol, "symbol", "", "paratime's symbol")
addCmd.Flags().AddFlagSet(symbolFlag)

numDecimalsFlag := flag.NewFlagSet("", flag.ContinueOnError)
numDecimalsFlag.UintVar(&numDecimals, "num-decimals", 0, "paratime's number of decimals")
addCmd.Flags().AddFlagSet(numDecimalsFlag)

descriptionFlag := flag.NewFlagSet("", flag.ContinueOnError)
descriptionFlag.StringVar(&description, "description", "", "paratime's description")
addCmd.Flags().AddFlagSet(descriptionFlag)
}
16 changes: 13 additions & 3 deletions docs/network.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,23 @@ For Unix sockets, use:

`network add-local <name> <rpc-endpoint>` command can be used if you are
running `oasis-node` on your local machine. In this case, Oasis CLI will
autodetect the native token symbol and decimal places, the chain domain
separation context and registered ParaTimes.
autodetect the chain domain separation context. For the Oasis Mainnet and
Testnet chains, the native token symbol, the number of decimal places and
registered ParaTimes will automatically be predefined. Otherwise, the Oasis CLI
will ask you to enter them.

```
```shell
oasis network add-local testnet_local unix:/node_testnet/data/internal.sock
```

To override the defaults, you can pass `--num-decimals`, `--symbol` and
`--description` parameters. This is especially useful, if you are running the
command in a [non-interactive mode](account.md#y):

```shell
oasis network add-local testnet_local unix:/node_testnet/data/internal.sock --num-decimals 9 --symbol TEST --description "Work machine - Localnet" -y
```

## List Networks {#list}

Invoke `network list` to list all configured networks.
Expand Down
7 changes: 7 additions & 0 deletions docs/paratime.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ oasis paratime add testnet sapphire2 0000000000000000000000000000000000000000000
? Denomination decimal places: 18
```

You can also enable [non-interactive mode](account.md#y) and pass
`--num-decimals`, `--symbol` and `--description` parameters directly:

```shell
oasis paratime add testnet sapphire2 000000000000000000000000000000000000000000000000a6d1e3ebf60dff6d --num-decimals 18 --symbol TEST --description "Testnet Sapphire 2" -y
```

:::danger Decimal places of the native and ParaTime token may differ!

Emerald and Sapphire use **18 decimals** for compatibility with
Expand Down
Loading