diff --git a/CHANGELOG.md b/CHANGELOG.md index df1022d3d..3103208e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ Changelog for FrostFS Node - Prevent node process from killing by systemd when shutting down (#1465) - Restore subscriptions correctly on morph client switch (#2212) - Expired objects could be returned if not marked with GC yet (#2213) +- `neofs-adm morph dump-hashes` now properly iterates over custom domain (#2224) ### Removed ### Updated diff --git a/cmd/frostfs-adm/internal/modules/morph/dump_hashes.go b/cmd/frostfs-adm/internal/modules/morph/dump_hashes.go index 4b7d579d1..030542fb9 100644 --- a/cmd/frostfs-adm/internal/modules/morph/dump_hashes.go +++ b/cmd/frostfs-adm/internal/modules/morph/dump_hashes.go @@ -2,6 +2,7 @@ package morph import ( "bytes" + "errors" "fmt" "strings" "text/tabwriter" @@ -107,31 +108,30 @@ func dumpContractHashes(cmd *cobra.Command, _ []string) error { func dumpCustomZoneHashes(cmd *cobra.Command, nnsHash util.Uint160, zone string, c Client) error { const nnsMaxTokens = 100 - inv := invoker.New(c, nil) - arr, err := unwrap.Array(inv.CallAndExpandIterator(nnsHash, "tokens", nnsMaxTokens)) - if err != nil { - return fmt.Errorf("can't get a list of NNS domains: %w", err) - } + inv := invoker.New(c, nil) if !strings.HasPrefix(zone, ".") { zone = "." + zone } var infos []contractDumpInfo - for i := range arr { - bs, err := arr[i].TryBytes() + processItem := func(item stackitem.Item) { + bs, err := item.TryBytes() if err != nil { - continue + cmd.PrintErrf("Invalid NNS record: %v\n", err) + return } if !bytes.HasSuffix(bs, []byte(zone)) { - continue + // Related https://github.com/nspcc-dev/neofs-contract/issues/316. + return } h, err := nnsResolveHash(inv, nnsHash, string(bs)) if err != nil { - continue + cmd.PrintErrf("Could not resolve name %s: %v\n", string(bs), err) + return } infos = append(infos, contractDumpInfo{ @@ -140,6 +140,39 @@ func dumpCustomZoneHashes(cmd *cobra.Command, nnsHash util.Uint160, zone string, }) } + sessionID, iter, err := unwrap.SessionIterator(inv.Call(nnsHash, "tokens")) + if err != nil { + if errors.Is(err, unwrap.ErrNoSessionID) { + items, err := unwrap.Array(inv.CallAndExpandIterator(nnsHash, "tokens", nnsMaxTokens)) + if err != nil { + return fmt.Errorf("can't get a list of NNS domains: %w", err) + } + if len(items) == nnsMaxTokens { + cmd.PrintErrln("Provided RPC endpoint doesn't support sessions, some hashes might be lost.") + } + for i := range items { + processItem(items[i]) + } + } else { + return err + } + } else { + defer func() { + _ = inv.TerminateSession(sessionID) + }() + + items, err := inv.TraverseIterator(sessionID, &iter, nnsMaxTokens) + for err == nil && len(items) != 0 { + for i := range items { + processItem(items[i]) + } + items, err = inv.TraverseIterator(sessionID, &iter, nnsMaxTokens) + } + if err != nil { + return fmt.Errorf("error during NNS domains iteration: %w", err) + } + } + fillContractVersion(cmd, c, infos) printContractInfo(cmd, infos)