From c324fd1ba4442b152ca13a581ce1f40794d580ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matev=C5=BE=20Jekovec?= Date: Fri, 10 Nov 2023 19:02:52 +0100 Subject: [PATCH 1/2] feat: Add account entity init subcommand --- cmd/account/entity.go | 52 +++++++++++++++++++++++++++++++++++++++ cmd/common/selector.go | 9 +++++-- cmd/common/transaction.go | 10 ++++++-- 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/cmd/account/entity.go b/cmd/account/entity.go index 0f9751d3..393b5010 100644 --- a/cmd/account/entity.go +++ b/cmd/account/entity.go @@ -8,6 +8,8 @@ import ( "github.com/spf13/cobra" + "github.com/oasisprotocol/oasis-core/go/common/cbor" + "github.com/oasisprotocol/oasis-core/go/common/crypto/signature" "github.com/oasisprotocol/oasis-core/go/common/entity" registry "github.com/oasisprotocol/oasis-core/go/registry/api" "github.com/oasisprotocol/oasis-sdk/client-sdk/go/connection" @@ -17,11 +19,56 @@ import ( ) var ( + entityOutputFile string + entityCmd = &cobra.Command{ Use: "entity", Short: "Entity management in the network's registry", } + entityInitCmd = &cobra.Command{ + Use: "init", + Short: "Init an empty entity file", + Run: func(cmd *cobra.Command, args []string) { + cfg := cliConfig.Global() + npa := common.GetNPASelection(cfg) + + if npa.Account == nil { + cobra.CheckErr("no accounts configured in your wallet") + } + + // Load the account and ensure it corresponds to the entity. + acc := common.LoadAccount(cfg, npa.AccountName) + signer := acc.ConsensusSigner() + if signer == nil { + cobra.CheckErr(fmt.Errorf("account '%s' does not support signing consensus transactions", npa.AccountName)) + } + + descriptor := entity.Entity{ + Versioned: cbor.NewVersioned(entity.LatestDescriptorVersion), + ID: signer.Public(), + Nodes: []signature.PublicKey{}, + } + + // Marshal to JSON, add explicit "nodes" field to hint user. + descriptorStr, err := json.Marshal(descriptor) + cobra.CheckErr(err) + var rawJSON map[string]interface{} + err = json.Unmarshal(descriptorStr, &rawJSON) + cobra.CheckErr(err) + rawJSON["nodes"] = []string{} + descriptorStr, err = common.PrettyJSONMarshal(rawJSON) + cobra.CheckErr(err) + + if entityOutputFile == "" { + fmt.Printf("%s\n", descriptorStr) + } else { + err = os.WriteFile(entityOutputFile, descriptorStr, 0o644) //nolint: gosec + cobra.CheckErr(err) + } + }, + } + entityRegisterCmd = &cobra.Command{ Use: "register ", Short: "Register or update account entity in registry", @@ -118,12 +165,17 @@ var ( ) func init() { + entityInitCmd.Flags().StringVarP(&entityOutputFile, "output-file", "o", "", "output entity descriptor into specified JSON file") + entityInitCmd.Flags().AddFlagSet(common.AccountFlag) + entityInitCmd.Flags().AddFlagSet(common.YesFlag) + entityRegisterCmd.Flags().AddFlagSet(common.SelectorNAFlags) entityRegisterCmd.Flags().AddFlagSet(common.TxFlags) entityDeregisterCmd.Flags().AddFlagSet(common.SelectorNAFlags) entityDeregisterCmd.Flags().AddFlagSet(common.TxFlags) + entityCmd.AddCommand(entityInitCmd) entityCmd.AddCommand(entityRegisterCmd) entityCmd.AddCommand(entityDeregisterCmd) } diff --git a/cmd/common/selector.go b/cmd/common/selector.go index 84f1fac8..19d680f6 100644 --- a/cmd/common/selector.go +++ b/cmd/common/selector.go @@ -23,6 +23,8 @@ var ( ) var ( + // AccountFlag corresponds to the --account selector flag. + AccountFlag *flag.FlagSet // SelectorFlags contains the common selector flags for network/ParaTime/wallet. SelectorFlags *flag.FlagSet // SelectorNPFlags contains the common selector flags for network/ParaTime. @@ -103,11 +105,14 @@ func (npa *NPASelection) PrettyPrintNetwork() (out string) { } func init() { + AccountFlag = flag.NewFlagSet("", flag.ContinueOnError) + AccountFlag.StringVar(&selectedAccount, "account", "", "explicitly set account to use") + SelectorFlags = flag.NewFlagSet("", flag.ContinueOnError) SelectorFlags.StringVar(&selectedNetwork, "network", "", "explicitly set network to use") SelectorFlags.StringVar(&selectedParaTime, "paratime", "", "explicitly set ParaTime to use") SelectorFlags.BoolVar(&noParaTime, "no-paratime", false, "explicitly set that no ParaTime should be used") - SelectorFlags.StringVar(&selectedAccount, "account", "", "explicitly set account to use") + SelectorFlags.AddFlagSet(AccountFlag) SelectorNPFlags = flag.NewFlagSet("", flag.ContinueOnError) SelectorNPFlags.StringVar(&selectedNetwork, "network", "", "explicitly set network to use") @@ -116,7 +121,7 @@ func init() { SelectorNAFlags = flag.NewFlagSet("", flag.ContinueOnError) SelectorNAFlags.StringVar(&selectedNetwork, "network", "", "explicitly set network to use") - SelectorNAFlags.StringVar(&selectedAccount, "account", "", "explicitly set account to use") + SelectorNAFlags.AddFlagSet(AccountFlag) SelectorNFlags = flag.NewFlagSet("", flag.ContinueOnError) SelectorNFlags.StringVar(&selectedNetwork, "network", "", "explicitly set network to use") diff --git a/cmd/common/transaction.go b/cmd/common/transaction.go index 1afff7b0..5c1ea383 100644 --- a/cmd/common/transaction.go +++ b/cmd/common/transaction.go @@ -50,6 +50,9 @@ const ( ) var ( + // YesFlag corresponds to the yes-to-all flag. + YesFlag *flag.FlagSet + // TxFlags contains the common consensus transaction flags. TxFlags *flag.FlagSet @@ -564,13 +567,16 @@ func WaitForEvent( } func init() { + YesFlag = flag.NewFlagSet("", flag.ContinueOnError) + YesFlag.BoolVarP(&txYes, "yes", "y", false, "answer yes to all questions") + RuntimeTxFlags = flag.NewFlagSet("", flag.ContinueOnError) RuntimeTxFlags.BoolVar(&txOffline, "offline", false, "do not perform any operations requiring network access") RuntimeTxFlags.Uint64Var(&txNonce, "nonce", invalidNonce, "override nonce to use") RuntimeTxFlags.Uint64Var(&txGasLimit, "gas-limit", invalidGasLimit, "override gas limit to use (disable estimation)") RuntimeTxFlags.StringVar(&txGasPrice, "gas-price", "", "override gas price to use") RuntimeTxFlags.BoolVar(&txEncrypted, "encrypted", false, "encrypt transaction call data (requires online mode)") - RuntimeTxFlags.BoolVarP(&txYes, "yes", "y", false, "answer yes to all questions") + RuntimeTxFlags.AddFlagSet(YesFlag) RuntimeTxFlags.BoolVar(&txUnsigned, "unsigned", false, "do not sign transaction") RuntimeTxFlags.StringVar(&txFormat, "format", "json", "transaction output format (for offline/unsigned modes) [json, cbor]") RuntimeTxFlags.StringVarP(&txOutputFile, "output-file", "o", "", "output transaction into specified file instead of broadcasting") @@ -580,7 +586,7 @@ func init() { TxFlags.Uint64Var(&txNonce, "nonce", invalidNonce, "override nonce to use") TxFlags.Uint64Var(&txGasLimit, "gas-limit", invalidGasLimit, "override gas limit to use (disable estimation)") TxFlags.StringVar(&txGasPrice, "gas-price", "", "override gas price to use") - TxFlags.BoolVarP(&txYes, "yes", "y", false, "answer yes to all questions") + TxFlags.AddFlagSet(YesFlag) TxFlags.BoolVar(&txUnsigned, "unsigned", false, "do not sign transaction") TxFlags.StringVar(&txFormat, "format", "json", "transaction output format (for offline/unsigned modes) [json, cbor]") TxFlags.StringVarP(&txOutputFile, "output-file", "o", "", "output transaction into specified file instead of broadcasting") From 40cc5bdeb88babd0bd3abce221efd3eff5d3acfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matev=C5=BE=20Jekovec?= Date: Fri, 10 Nov 2023 19:59:18 +0100 Subject: [PATCH 2/2] feat: Add account entity init docs and examples --- docs/account.md | 23 +++++++++++++++++++ examples/account/allow-paratime.y.out | 2 +- examples/account/allow.y.out | 2 +- .../account/amend-commission-schedule.y.out | 2 +- examples/account/burn.y.out | 2 +- examples/account/delegate.y.out | 2 +- examples/account/entity-deregister.y.out | 2 +- examples/account/entity-init-o.y.in | 1 + examples/account/entity-init-o.y.out | 0 examples/account/entity-init.in.static | 1 + examples/account/entity-init.out.static | 5 ++++ examples/account/entity-register.y.out | 2 +- examples/account/node-unfreeze.y.out | 2 +- examples/account/show.out | 2 +- examples/account/undelegate.y.out | 2 +- 15 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 examples/account/entity-init-o.y.in create mode 100644 examples/account/entity-init-o.y.out create mode 100644 examples/account/entity-init.in.static create mode 100644 examples/account/entity-init.out.static diff --git a/docs/account.md b/docs/account.md index 653deba9..e7acc667 100644 --- a/docs/account.md +++ b/docs/account.md @@ -519,6 +519,29 @@ transaction. ### Entity Management {#entity} +#### Initialize Entity {#entity-init} + +When setting up a validator node for the first time, you will need to provide +the path to the file containing your entity descriptor as well as register it in +the network registry. Use `account entity init` to generate the entity +descriptor file containing the public key of the selected account. + +![code shell](../examples/account/entity-init.in.static) + +![code json](../examples/account/entity-init.out.static) + +By default, the file content will be printed to the standard output. You can use +`-o` parameter to store it to a file, for example: + +![code shell](../examples/account/entity-init-o.y.in) + +:::info + +[Account](#account) selector is available for the +`account entity init` command. + +::: + #### Register your Entity {#entity-register} In order for validators to become part of the validator set and/or the compute diff --git a/examples/account/allow-paratime.y.out b/examples/account/allow-paratime.y.out index 2d5dba9b..78fc3e01 100644 --- a/examples/account/allow-paratime.y.out +++ b/examples/account/allow-paratime.y.out @@ -3,7 +3,7 @@ Method: staking.Allow Body: Beneficiary: oasis1qqczuf3x6glkgjuf0xgtcpjjw95r3crf7y2323xd Amount change: +10.0 TEST -Nonce: 1 +Nonce: 2 Fee: Amount: 0.0 TEST Gas limit: 1278 diff --git a/examples/account/allow.y.out b/examples/account/allow.y.out index ad0138ab..3cad3244 100644 --- a/examples/account/allow.y.out +++ b/examples/account/allow.y.out @@ -3,7 +3,7 @@ Method: staking.Allow Body: Beneficiary: oasis1qpl4axynedmdrrgrg7dpw3yxc4a8crevr5dkuksl Amount change: +10.0 TEST -Nonce: 1 +Nonce: 2 Fee: Amount: 0.0 TEST Gas limit: 1278 diff --git a/examples/account/amend-commission-schedule.y.out b/examples/account/amend-commission-schedule.y.out index 52742acd..b8ae9911 100644 --- a/examples/account/amend-commission-schedule.y.out +++ b/examples/account/amend-commission-schedule.y.out @@ -12,7 +12,7 @@ Body: (2) start: epoch 335000 minimum rate: 0.9% maximum rate: 1.9% -Nonce: 1 +Nonce: 2 Fee: Amount: 0.0 TEST Gas limit: 1361 diff --git a/examples/account/burn.y.out b/examples/account/burn.y.out index 4b7a3ce5..ff1b1e5b 100644 --- a/examples/account/burn.y.out +++ b/examples/account/burn.y.out @@ -2,7 +2,7 @@ You are about to sign the following transaction: Method: staking.Burn Body: Amount: 2.5 TEST -Nonce: 1 +Nonce: 2 Fee: Amount: 0.0 TEST Gas limit: 1235 diff --git a/examples/account/delegate.y.out b/examples/account/delegate.y.out index a1963865..e099a20a 100644 --- a/examples/account/delegate.y.out +++ b/examples/account/delegate.y.out @@ -3,7 +3,7 @@ Method: staking.AddEscrow Body: To: oasis1qpkl3vykn9mf4xcq9eevmey4ffrzf0ajtcpvd7sk Amount: 20.0 TEST -Nonce: 1 +Nonce: 2 Fee: Amount: 0.0 TEST Gas limit: 1271 diff --git a/examples/account/entity-deregister.y.out b/examples/account/entity-deregister.y.out index 08c90a3f..6a96808e 100644 --- a/examples/account/entity-deregister.y.out +++ b/examples/account/entity-deregister.y.out @@ -2,7 +2,7 @@ You are about to sign the following transaction: Method: registry.DeregisterEntity Body: {} -Nonce: 1 +Nonce: 2 Fee: Amount: 0.0 TEST Gas limit: 1231 diff --git a/examples/account/entity-init-o.y.in b/examples/account/entity-init-o.y.in new file mode 100644 index 00000000..5611e88e --- /dev/null +++ b/examples/account/entity-init-o.y.in @@ -0,0 +1 @@ +oasis account entity init -o entity.json diff --git a/examples/account/entity-init-o.y.out b/examples/account/entity-init-o.y.out new file mode 100644 index 00000000..e69de29b diff --git a/examples/account/entity-init.in.static b/examples/account/entity-init.in.static new file mode 100644 index 00000000..981c224c --- /dev/null +++ b/examples/account/entity-init.in.static @@ -0,0 +1 @@ +oasis account entity init diff --git a/examples/account/entity-init.out.static b/examples/account/entity-init.out.static new file mode 100644 index 00000000..7f10c096 --- /dev/null +++ b/examples/account/entity-init.out.static @@ -0,0 +1,5 @@ +{ + "id": "Bx6gOixnxy15tCs09ua5DcKyX9uo2Forb32O6Hyjoc8=", + "nodes": [], + "v": 2 +} diff --git a/examples/account/entity-register.y.out b/examples/account/entity-register.y.out index 99840c84..ea9103db 100644 --- a/examples/account/entity-register.y.out +++ b/examples/account/entity-register.y.out @@ -16,7 +16,7 @@ Body: "signature": "DAwn+N8hKmQMbZda/fFJSEgErDAAdebXLfIPOpqUkJowJLUAL+nfrUMz5SVkKc0TnqQOavoSAVFz1yoRJ3QuBA==" } } -Nonce: 1 +Nonce: 2 Fee: Amount: 0.0 TEST Gas limit: 2471 diff --git a/examples/account/node-unfreeze.y.out b/examples/account/node-unfreeze.y.out index 0c0b0a96..00538de2 100644 --- a/examples/account/node-unfreeze.y.out +++ b/examples/account/node-unfreeze.y.out @@ -4,7 +4,7 @@ Body: { "node_id": "fasTG3pMOwLfFA7JX3R8Kxw1zFflqeY6NP/cpjcFu5I=" } -Nonce: 1 +Nonce: 2 Fee: Amount: 0.0 TEST Gas limit: 1274 diff --git a/examples/account/show.out b/examples/account/show.out index 1b694939..3a80d6f5 100644 --- a/examples/account/show.out +++ b/examples/account/show.out @@ -1,7 +1,7 @@ Address: oasis1qp87hflmelnpqhzcqcw8rhzakq4elj7jzv090p3e === CONSENSUS LAYER (testnet) === - Nonce: 1 + Nonce: 2 Total: 0.0 TEST Available: 0.0 TEST diff --git a/examples/account/undelegate.y.out b/examples/account/undelegate.y.out index 0dd2ad31..dac2cc32 100644 --- a/examples/account/undelegate.y.out +++ b/examples/account/undelegate.y.out @@ -3,7 +3,7 @@ Method: staking.ReclaimEscrow Body: From: oasis1qpkl3vykn9mf4xcq9eevmey4ffrzf0ajtcpvd7sk Shares: 20000000000 -Nonce: 1 +Nonce: 2 Fee: Amount: 0.0 TEST Gas limit: 1275