From 818f8a3c4f8b52e724d6330336f77df0a1383bfb Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 23 Jun 2023 14:36:34 +0300 Subject: [PATCH 1/2] adm: add dump-names command $ ./bin/neofs-adm morph dump-names -r https://rpc5.morph.t5.fs.neo.org:51331 -d neofs neofs 2023-07-18 19:01:01.326 +0300 MSK alphabet0.neofs 2023-07-18 19:01:16.974 +0300 MSK alphabet1.neofs 2023-07-18 19:01:16.974 +0300 MSK alphabet2.neofs 2023-07-18 19:01:16.974 +0300 MSK alphabet3.neofs 2023-07-18 19:01:16.974 +0300 MSK alphabet4.neofs 2023-07-18 19:01:16.974 +0300 MSK alphabet5.neofs 2023-07-18 19:01:16.974 +0300 MSK alphabet6.neofs 2023-07-18 19:01:16.974 +0300 MSK audit.neofs 2023-07-18 19:01:16.974 +0300 MSK balance.neofs 2023-07-18 19:01:16.974 +0300 MSK container.neofs 2023-07-18 19:01:16.974 +0300 MSK group.neofs 2023-07-18 19:01:16.974 +0300 MSK neofsid.neofs 2023-07-18 19:01:16.974 +0300 MSK netmap.neofs 2023-07-18 19:01:16.974 +0300 MSK proxy.neofs 2023-07-18 19:01:16.974 +0300 MSK reputation.neofs 2023-07-18 19:01:16.974 +0300 MSK subnet.neofs 2023-07-18 19:01:16.974 +0300 MSK Signed-off-by: Roman Khimov --- CHANGELOG.md | 1 + .../internal/modules/morph/dump_hashes.go | 33 ++++--- .../internal/modules/morph/dump_names.go | 90 +++++++++++++++++++ cmd/neofs-adm/internal/modules/morph/root.go | 13 +++ docs/cli-adm.md | 2 + 5 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 cmd/neofs-adm/internal/modules/morph/dump_names.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 11a682281b..62cca7fff8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Changelog for NeoFS Node ### Added - Embedded Neo contracts in `contracts` dir (#2391) +- `dump-names` command for adm ### Fixed diff --git a/cmd/neofs-adm/internal/modules/morph/dump_hashes.go b/cmd/neofs-adm/internal/modules/morph/dump_hashes.go index 3378d8a967..139cd7c950 100644 --- a/cmd/neofs-adm/internal/modules/morph/dump_hashes.go +++ b/cmd/neofs-adm/internal/modules/morph/dump_hashes.go @@ -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") } diff --git a/cmd/neofs-adm/internal/modules/morph/dump_names.go b/cmd/neofs-adm/internal/modules/morph/dump_names.go new file mode 100644 index 0000000000..00b07b6267 --- /dev/null +++ b/cmd/neofs-adm/internal/modules/morph/dump_names.go @@ -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 +} diff --git a/cmd/neofs-adm/internal/modules/morph/root.go b/cmd/neofs-adm/internal/modules/morph/root.go index a33a99ef76..94f51c9a27 100644 --- a/cmd/neofs-adm/internal/modules/morph/root.go +++ b/cmd/neofs-adm/internal/modules/morph/root.go @@ -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", @@ -271,6 +280,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") diff --git a/docs/cli-adm.md b/docs/cli-adm.md index a80d114e23..c898ca02e2 100644 --- a/docs/cli-adm.md +++ b/docs/cli-adm.md @@ -70,6 +70,8 @@ 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 From b4cd3c3f8669e30f1349901744ef7689f6eac634 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 23 Jun 2023 15:51:04 +0300 Subject: [PATCH 2/2] adm: add renew-domain command It's a kludge until we have some proper management node-side, but domains must be renewed for the system to work. Signed-off-by: Roman Khimov --- CHANGELOG.md | 1 + .../internal/modules/morph/renew_domain.go | 73 +++++++++++++++++++ cmd/neofs-adm/internal/modules/morph/root.go | 16 ++++ docs/cli-adm.md | 2 + 4 files changed, 92 insertions(+) create mode 100644 cmd/neofs-adm/internal/modules/morph/renew_domain.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 62cca7fff8..1f3a827bd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Changelog for NeoFS Node ### Added - Embedded Neo contracts in `contracts` dir (#2391) - `dump-names` command for adm +- `renew-domain` command for adm ### Fixed diff --git a/cmd/neofs-adm/internal/modules/morph/renew_domain.go b/cmd/neofs-adm/internal/modules/morph/renew_domain.go new file mode 100644 index 0000000000..dfbb073ad1 --- /dev/null +++ b/cmd/neofs-adm/internal/modules/morph/renew_domain.go @@ -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() +} diff --git a/cmd/neofs-adm/internal/modules/morph/root.go b/cmd/neofs-adm/internal/modules/morph/root.go index 94f51c9a27..057390e33a 100644 --- a/cmd/neofs-adm/internal/modules/morph/root.go +++ b/cmd/neofs-adm/internal/modules/morph/root.go @@ -208,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", @@ -310,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") diff --git a/docs/cli-adm.md b/docs/cli-adm.md index c898ca02e2..e94e9c1dbe 100644 --- a/docs/cli-adm.md +++ b/docs/cli-adm.md @@ -77,6 +77,8 @@ credentials: # passwords for consensus node / alphabet wallets - `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.