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

Adm NNS cmds #2403

Merged
merged 2 commits into from
Jun 24, 2023
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ Changelog for NeoFS Node

### Added
- Embedded Neo contracts in `contracts` dir (#2391)
- `dump-names` command for adm
- `renew-domain` command for adm

### Fixed

Expand Down
33 changes: 21 additions & 12 deletions cmd/neofs-adm/internal/modules/morph/dump_hashes.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,20 +269,29 @@ func fillContractExpiration(cmd *cobra.Command, c Client, infos []contractDumpIn
if err != nil {
continue // OK for NNS itself, for example.
}
elems := props.Value().([]stackitem.MapElement)
for _, e := range elems {
k, err := e.Key.TryBytes()
if err != nil {
continue
}
exp, err := expirationFromProperties(props)
if err != nil {
continue // Should be there, but who knows.
}
infos[i].expiration = exp
}
}

func expirationFromProperties(props *stackitem.Map) (int64, error) {
elems := props.Value().([]stackitem.MapElement)
for _, e := range elems {
k, err := e.Key.TryBytes()
if err != nil {
continue
}

if string(k) == "expiration" {
v, err := e.Value.TryInteger()
if err != nil || !v.IsInt64() {
continue
}
infos[i].expiration = v.Int64()
if string(k) == "expiration" {
v, err := e.Value.TryInteger()
if err != nil || !v.IsInt64() {
continue
}
return v.Int64(), nil
}
}
return 0, errors.New("not found")
}
90 changes: 90 additions & 0 deletions cmd/neofs-adm/internal/modules/morph/dump_names.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package morph

import (
"bytes"
"fmt"
"sort"
"strings"
"text/tabwriter"
"time"

"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep11"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

const (
nameDomainFlag = "domain"
)

type nameExp struct {
name string
exp int64
}

func dumpNames(cmd *cobra.Command, _ []string) error {
c, err := getN3Client(viper.GetViper())
if err != nil {
return fmt.Errorf("can't create N3 client: %w", err)
}
cs, err := c.GetContractStateByID(1) // NNS.
if err != nil {
return err
}
var n11r = nep11.NewNonDivisibleReader(invoker.New(c, nil), cs.Hash)
tokIter, err := n11r.Tokens()
if err != nil {
return err
}
zone, _ := cmd.Flags().GetString(nameDomainFlag)
var res = make([]nameExp, 0)
for toks, err := tokIter.Next(10); len(toks) != 0 && err == nil; toks, err = tokIter.Next(10) {
for i := range toks {
var name = string(toks[i])
if zone != "" && name != zone && !strings.HasSuffix(name, "."+zone) {
continue
}
props, err := n11r.Properties(toks[i])
if err != nil {
cmd.PrintErrf("Error getting properties for %s: %v\n", name, err)
continue
}
exp, err := expirationFromProperties(props)
if err != nil {
cmd.PrintErrf("Error getting expiration from properties for %s: %v\n", name, err)
continue
}
res = append(res, nameExp{name: name, exp: exp})
}
}

sort.Slice(res, func(i, j int) bool {
var (
iParts = strings.Split(res[i].name, ".")
jParts = strings.Split(res[j].name, ".")
)
if len(iParts) != len(jParts) {
return len(iParts) < len(jParts)
}
for k := len(iParts) - 1; k >= 0; k-- {
var c = strings.Compare(iParts[k], jParts[k])
if c != 0 {
return c == -1
}
}
return false
})

buf := bytes.NewBuffer(nil)
tw := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0)
for i := range res {
_, _ = tw.Write([]byte(fmt.Sprintf("%s\t%s\n",
res[i].name, time.UnixMilli(res[i].exp).String())))
}
_ = tw.Flush()

cmd.Print(buf.String())

return nil
}
73 changes: 73 additions & 0 deletions cmd/neofs-adm/internal/modules/morph/renew_domain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package morph

import (
"errors"
"strings"

"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep11"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

const (
recursiveFlag = "recursive"
)

func renewDomain(cmd *cobra.Command, _ []string) error {
dom, err := cmd.Flags().GetString(nameDomainFlag)
if err != nil {
return err
}
recursive, _ := cmd.Flags().GetBool(recursiveFlag)
wCtx, err := newInitializeContext(cmd, viper.GetViper())
if err != nil {
return err
}
defer wCtx.close()
nns, err := wCtx.Client.GetContractStateByID(1)
if err != nil {
return err
}
var domains = make([]string, 0, 1)
if recursive {
var n11r = nep11.NewNonDivisibleReader(wCtx.ReadOnlyInvoker, nns.Hash)
tokIter, err := n11r.Tokens()
if err != nil {
return err
}
for toks, err := tokIter.Next(10); len(toks) != 0 && err == nil; toks, err = tokIter.Next(10) {
for i := range toks {
var name = string(toks[i])
if name != dom && !strings.HasSuffix(name, "."+dom) {
continue
}
domains = append(domains, name)
}
}
} else {
avail, err := unwrap.Bool(wCtx.ReadOnlyInvoker.Call(nns.Hash, "isAvailable"))
if err == nil && avail {
return errors.New("domain is not registered or expired")
}
domains = append(domains, dom)
}

bw := io.NewBufBinWriter()
for i := range domains {
emit.AppCall(bw.BinWriter, nns.Hash, "renew", callflag.All, domains[i])
if bw.Err != nil {
return bw.Err
}
// Default registration price is 10 GAS, adding more domains
// into the script makes test execution to fail.
if err := wCtx.sendConsensusTx(bw.Bytes()); err != nil {
return err
}
bw.Reset()
}
return wCtx.awaitTx()
}
29 changes: 29 additions & 0 deletions cmd/neofs-adm/internal/modules/morph/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,15 @@ var (
RunE: dumpContractHashes,
}

dumpNamesCmd = &cobra.Command{
Use: "dump-names",
Short: "Dump known registred NNS names and expirations",
PreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag))
},
RunE: dumpNames,
}

dumpNetworkConfigCmd = &cobra.Command{
Use: "dump-config",
Short: "Dump NeoFS network config",
Expand Down Expand Up @@ -199,6 +208,16 @@ var (
RunE: dumpContainers,
}

renewDomainCmd = &cobra.Command{
Use: "renew-domain",
Short: "Renew NNS domain",
PreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag))
_ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag))
},
RunE: renewDomain,
}

restoreContainersCmd = &cobra.Command{
Use: "restore-containers",
Short: "Restore NeoFS containers from file",
Expand Down Expand Up @@ -271,6 +290,10 @@ func init() {
dumpContractHashesCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint")
dumpContractHashesCmd.Flags().String(customZoneFlag, "", "Custom zone to search.")

RootCmd.AddCommand(dumpNamesCmd)
dumpNamesCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint")
dumpNamesCmd.Flags().StringP(nameDomainFlag, "d", "", "Filter by domain")

RootCmd.AddCommand(dumpNetworkConfigCmd)
dumpNetworkConfigCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint")

Expand All @@ -297,6 +320,12 @@ func init() {
dumpContainersCmd.Flags().String(containerContractFlag, "", "Container contract hash (for networks without NNS)")
dumpContainersCmd.Flags().StringSlice(containerIDsFlag, nil, "Containers to dump")

RootCmd.AddCommand(renewDomainCmd)
renewDomainCmd.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir")
renewDomainCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint")
renewDomainCmd.Flags().StringP(nameDomainFlag, "d", "", "Domain")
renewDomainCmd.Flags().BoolP(recursiveFlag, "u", false, "Recursive (renew all subdomain as well)")

RootCmd.AddCommand(restoreContainersCmd)
restoreContainersCmd.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir")
restoreContainersCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint")
Expand Down
4 changes: 4 additions & 0 deletions docs/cli-adm.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,15 @@ credentials: # passwords for consensus node / alphabet wallets

#### Network maintenance

- `dump-names` allows to walk through NNS names and see their expirations.

- `set-config` add/update configuration values in the Netmap contract.

- `force-new-epoch` increments NeoFS epoch number and executes new epoch
handlers in NeoFS nodes.

- `renew-domain` updates expiration date of the given domain for one year.

- `refill-gas` transfers sidechain GAS to the specified wallet.

- `update-contracts` updates contracts to a new version.
Expand Down