[#932] adm: Move NNS methods to util package

Signed-off-by: Anton Nikiforov <an.nikiforov@yadro.com>
This commit is contained in:
Anton Nikiforov 2024-02-01 09:43:51 +03:00
parent cda3a3d834
commit 7954c7f8af
14 changed files with 78 additions and 68 deletions

View file

@ -97,7 +97,7 @@ func newPolicyContractInterface(cmd *cobra.Command) (*morph.ContractStorage, *ac
nnsCs, err := r.GetContractByID(1) nnsCs, err := r.GetContractByID(1)
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err) commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
ch, err = nnsResolveHash(inv, nnsCs.Hash, domainOf(policyContract)) ch, err = morphUtil.NNSResolveHash(inv, nnsCs.Hash, domainOf(policyContract))
commonCmd.ExitOnErr(cmd, "unable to resolve policy contract hash: %w", err) commonCmd.ExitOnErr(cmd, "unable to resolve policy contract hash: %w", err)
return morph.NewContractStorage(ac, ch), ac return morph.NewContractStorage(ac, ch), ac

View file

@ -64,7 +64,7 @@ func dumpBalances(cmd *cobra.Command, _ []string) error {
return fmt.Errorf("can't get NNS contract info: %w", err) return fmt.Errorf("can't get NNS contract info: %w", err)
} }
nmHash, err = nnsResolveHash(inv, nnsCs.Hash, domainOf(netmapContract)) nmHash, err = morphUtil.NNSResolveHash(inv, nnsCs.Hash, domainOf(netmapContract))
if err != nil { if err != nil {
return fmt.Errorf("can't get netmap contract hash: %w", err) return fmt.Errorf("can't get netmap contract hash: %w", err)
} }
@ -137,7 +137,7 @@ func printStorageNodeBalances(cmd *cobra.Command, inv *invoker.Invoker, nmHash u
} }
func printProxyContractBalance(cmd *cobra.Command, inv *invoker.Invoker, nnsHash util.Uint160) error { func printProxyContractBalance(cmd *cobra.Command, inv *invoker.Invoker, nnsHash util.Uint160) error {
h, err := nnsResolveHash(inv, nnsHash, domainOf(proxyContract)) h, err := morphUtil.NNSResolveHash(inv, nnsHash, domainOf(proxyContract))
if err != nil { if err != nil {
return fmt.Errorf("can't get hash of the proxy contract: %w", err) return fmt.Errorf("can't get hash of the proxy contract: %w", err)
} }
@ -170,7 +170,7 @@ func printAlphabetContractBalances(cmd *cobra.Command, c morphUtil.Client, inv *
} }
for i := range alphaList { for i := range alphaList {
h, err := parseNNSResolveResult(alphaRes.Stack[i]) h, err := morphUtil.ParseNNSResolveResult(alphaRes.Stack[i])
if err != nil { if err != nil {
return fmt.Errorf("can't fetch the alphabet contract #%d hash: %w", i, err) return fmt.Errorf("can't fetch the alphabet contract #%d hash: %w", i, err)
} }

View file

@ -38,7 +38,7 @@ func dumpNetworkConfig(cmd *cobra.Command, _ []string) error {
return fmt.Errorf("can't get NNS contract info: %w", err) return fmt.Errorf("can't get NNS contract info: %w", err)
} }
nmHash, err := nnsResolveHash(inv, cs.Hash, domainOf(netmapContract)) nmHash, err := util.NNSResolveHash(inv, cs.Hash, domainOf(netmapContract))
if err != nil { if err != nil {
return fmt.Errorf("can't get netmap contract hash: %w", err) return fmt.Errorf("can't get netmap contract hash: %w", err)
} }
@ -96,7 +96,7 @@ func setConfigCmd(cmd *cobra.Command, args []string) error {
return fmt.Errorf("can't get NNS contract info: %w", err) return fmt.Errorf("can't get NNS contract info: %w", err)
} }
nmHash, err := nnsResolveHash(wCtx.ReadOnlyInvoker, cs.Hash, domainOf(netmapContract)) nmHash, err := util.NNSResolveHash(wCtx.ReadOnlyInvoker, cs.Hash, domainOf(netmapContract))
if err != nil { if err != nil {
return fmt.Errorf("can't get netmap contract hash: %w", err) return fmt.Errorf("can't get netmap contract hash: %w", err)
} }

View file

@ -36,7 +36,7 @@ func getContainerContractHash(cmd *cobra.Command, inv *invoker.Invoker) (util.Ui
if err != nil { if err != nil {
return util.Uint160{}, fmt.Errorf("can't get NNS contract state: %w", err) return util.Uint160{}, fmt.Errorf("can't get NNS contract state: %w", err)
} }
ch, err = nnsResolveHash(inv, nnsCs.Hash, domainOf(containerContract)) ch, err = morphUtil.NNSResolveHash(inv, nnsCs.Hash, domainOf(containerContract))
if err != nil { if err != nil {
return util.Uint160{}, err return util.Uint160{}, err
} }
@ -307,7 +307,7 @@ func fetchContainerContractHash(wCtx *initializeContext) (util.Uint160, error) {
return util.Uint160{}, fmt.Errorf("can't get NNS contract state: %w", err) return util.Uint160{}, fmt.Errorf("can't get NNS contract state: %w", err)
} }
ch, err := nnsResolveHash(wCtx.ReadOnlyInvoker, nnsCs.Hash, domainOf(containerContract)) ch, err := morphUtil.NNSResolveHash(wCtx.ReadOnlyInvoker, nnsCs.Hash, domainOf(containerContract))
if err != nil { if err != nil {
return util.Uint160{}, fmt.Errorf("can't fetch container contract hash: %w", err) return util.Uint160{}, fmt.Errorf("can't fetch container contract hash: %w", err)
} }

View file

@ -89,7 +89,7 @@ func deployContractCmd(cmd *cobra.Command, args []string) error {
domain := ctrName + "." + zone domain := ctrName + "." + zone
isUpdate, _ := cmd.Flags().GetBool(updateFlag) isUpdate, _ := cmd.Flags().GetBool(updateFlag)
if isUpdate { if isUpdate {
cs.Hash, err = nnsResolveHash(c.ReadOnlyInvoker, nnsCs.Hash, domain) cs.Hash, err = util.NNSResolveHash(c.ReadOnlyInvoker, nnsCs.Hash, domain)
if err != nil { if err != nil {
return fmt.Errorf("can't fetch contract hash from NNS: %w", err) return fmt.Errorf("can't fetch contract hash from NNS: %w", err)
} }

View file

@ -79,7 +79,7 @@ func dumpContractHashes(cmd *cobra.Command, _ []string) error {
for i := 0; i < irSize; i++ { for i := 0; i < irSize; i++ {
info := contractDumpInfo{name: fmt.Sprintf("alphabet %d", i)} info := contractDumpInfo{name: fmt.Sprintf("alphabet %d", i)}
if h, err := parseNNSResolveResult(alphaRes.Stack[i]); err == nil { if h, err := morphUtil.ParseNNSResolveResult(alphaRes.Stack[i]); err == nil {
info.hash = h info.hash = h
} }
infos = append(infos, info) infos = append(infos, info)
@ -98,7 +98,7 @@ func dumpContractHashes(cmd *cobra.Command, _ []string) error {
info := contractDumpInfo{name: ctrName} info := contractDumpInfo{name: ctrName}
if len(res.Stack) != 0 { if len(res.Stack) != 0 {
if h, err := parseNNSResolveResult(res.Stack[0]); err == nil { if h, err := morphUtil.ParseNNSResolveResult(res.Stack[0]); err == nil {
info.hash = h info.hash = h
} }
} }
@ -133,7 +133,7 @@ func dumpCustomZoneHashes(cmd *cobra.Command, nnsHash util.Uint160, zone string,
return return
} }
h, err := nnsResolveHash(inv, nnsHash, string(bs)) h, err := morphUtil.NNSResolveHash(inv, nnsHash, string(bs))
if err != nil { if err != nil {
cmd.PrintErrf("Could not resolve name %s: %v\n", string(bs), err) cmd.PrintErrf("Could not resolve name %s: %v\n", string(bs), err)
return return

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"strings" "strings"
util2 "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/util"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/management" "github.com/nspcc-dev/neo-go/pkg/rpcclient/management"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap" "github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
@ -27,7 +28,7 @@ func forceNewEpochCmd(cmd *cobra.Command, _ []string) error {
return fmt.Errorf("can't get NNS contract info: %w", err) return fmt.Errorf("can't get NNS contract info: %w", err)
} }
nmHash, err := nnsResolveHash(wCtx.ReadOnlyInvoker, cs.Hash, domainOf(netmapContract)) nmHash, err := util2.NNSResolveHash(wCtx.ReadOnlyInvoker, cs.Hash, domainOf(netmapContract))
if err != nil { if err != nil {
return fmt.Errorf("can't get netmap contract hash: %w", err) return fmt.Errorf("can't get netmap contract hash: %w", err)
} }

View file

@ -431,7 +431,7 @@ func newFrostfsIDClient(cmd *cobra.Command) (*frostfsidClient, error) {
return nil, fmt.Errorf("can't get NNS contract info: %w", err) return nil, fmt.Errorf("can't get NNS contract info: %w", err)
} }
ffsidHash, err := nnsResolveHash(wCtx.ReadOnlyInvoker, cs.Hash, domainOf(frostfsIDContract)) ffsidHash, err := morphUtil.NNSResolveHash(wCtx.ReadOnlyInvoker, cs.Hash, domainOf(frostfsIDContract))
if err != nil { if err != nil {
return nil, fmt.Errorf("can't get proxy contract hash: %w", err) return nil, fmt.Errorf("can't get proxy contract hash: %w", err)
} }

View file

@ -203,7 +203,7 @@ func (c *initializeContext) deployOrUpdateContracts(w *io2.BufBinWriter, nnsHash
cs := c.getContract(ctrName) cs := c.getContract(ctrName)
method := updateMethodName method := updateMethodName
ctrHash, err := nnsResolveHash(c.ReadOnlyInvoker, nnsHash, domainOf(ctrName)) ctrHash, err := morphUtil.NNSResolveHash(c.ReadOnlyInvoker, nnsHash, domainOf(ctrName))
if err != nil { if err != nil {
if errors.Is(err, errMissingNNSRecord) { if errors.Is(err, errMissingNNSRecord) {
// if contract not found we deploy it instead of update // if contract not found we deploy it instead of update
@ -267,7 +267,7 @@ func (c *initializeContext) deployAlphabetAccounts(nnsHash util.Uint160, w *io2.
// alphabet contracts should be deployed by individual nodes to get different hashes. // alphabet contracts should be deployed by individual nodes to get different hashes.
for i, acc := range c.Accounts { for i, acc := range c.Accounts {
ctrHash, err := nnsResolveHash(c.ReadOnlyInvoker, nnsHash, getAlphabetNNSDomain(i)) ctrHash, err := morphUtil.NNSResolveHash(c.ReadOnlyInvoker, nnsHash, getAlphabetNNSDomain(i))
if err != nil { if err != nil {
return nil, fmt.Errorf("can't resolve hash for contract update: %w", err) return nil, fmt.Errorf("can't resolve hash for contract update: %w", err)
} }
@ -609,7 +609,7 @@ func (c *initializeContext) getFrostfsIDAdminFromContract() (util.Uint160, bool,
if err != nil { if err != nil {
return util.Uint160{}, false, fmt.Errorf("get nns contract: %w", err) return util.Uint160{}, false, fmt.Errorf("get nns contract: %w", err)
} }
fidHash, err := nnsResolveHash(c.ReadOnlyInvoker, cs.Hash, domainOf(frostfsIDContract)) fidHash, err := morphUtil.NNSResolveHash(c.ReadOnlyInvoker, cs.Hash, domainOf(frostfsIDContract))
if err != nil { if err != nil {
return util.Uint160{}, false, fmt.Errorf("resolve frostfsid contract hash: %w", err) return util.Uint160{}, false, fmt.Errorf("resolve frostfsid contract hash: %w", err)
} }
@ -638,7 +638,7 @@ func (c *initializeContext) getNetConfigFromNetmapContract() ([]stackitem.Item,
if err != nil { if err != nil {
return nil, fmt.Errorf("get nns contract: %w", err) return nil, fmt.Errorf("get nns contract: %w", err)
} }
nmHash, err := nnsResolveHash(c.ReadOnlyInvoker, cs.Hash, domainOf(netmapContract)) nmHash, err := morphUtil.NNSResolveHash(c.ReadOnlyInvoker, cs.Hash, domainOf(netmapContract))
if err != nil { if err != nil {
return nil, fmt.Errorf("can't get netmap contract hash: %w", err) return nil, fmt.Errorf("can't get netmap contract hash: %w", err)
} }

View file

@ -184,7 +184,7 @@ func (c *initializeContext) nnsRegisterDomainScript(nnsHash, expectedHash util.U
return bw.Bytes(), false, nil return bw.Bytes(), false, nil
} }
s, err := nnsResolveHash(c.ReadOnlyInvoker, nnsHash, domain) s, err := morphUtil.NNSResolveHash(c.ReadOnlyInvoker, nnsHash, domain)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
@ -220,21 +220,8 @@ func (c *initializeContext) nnsRootRegistered(nnsHash util.Uint160, zone string)
var errMissingNNSRecord = errors.New("missing NNS record") var errMissingNNSRecord = errors.New("missing NNS record")
// Returns errMissingNNSRecord if invocation fault exception contains "token not found".
func nnsResolveHash(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (util.Uint160, error) {
item, err := nnsResolve(inv, nnsHash, domain)
if err != nil {
return util.Uint160{}, err
}
return parseNNSResolveResult(item)
}
func nnsResolve(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (stackitem.Item, error) {
return unwrap.Item(inv.Call(nnsHash, "resolve", domain, int64(nns.TXT)))
}
func nnsResolveKey(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (*keys.PublicKey, error) { func nnsResolveKey(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (*keys.PublicKey, error) {
res, err := nnsResolve(inv, nnsHash, domain) res, err := morphUtil.NNSResolve(inv, nnsHash, domain)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -257,38 +244,6 @@ func nnsResolveKey(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (*
return nil, errors.New("no valid keys are found") return nil, errors.New("no valid keys are found")
} }
// parseNNSResolveResult parses the result of resolving NNS record.
// It works with multiple formats (corresponding to multiple NNS versions).
// If array of hashes is provided, it returns only the first one.
func parseNNSResolveResult(res stackitem.Item) (util.Uint160, error) {
arr, ok := res.Value().([]stackitem.Item)
if !ok {
arr = []stackitem.Item{res}
}
if _, ok := res.Value().(stackitem.Null); ok || len(arr) == 0 {
return util.Uint160{}, errors.New("NNS record is missing")
}
for i := range arr {
bs, err := arr[i].TryBytes()
if err != nil {
continue
}
// We support several formats for hash encoding, this logic should be maintained in sync
// with nnsResolve from pkg/morph/client/nns.go
h, err := util.Uint160DecodeStringLE(string(bs))
if err == nil {
return h, nil
}
h, err = address.StringToUint160(string(bs))
if err == nil {
return h, nil
}
}
return util.Uint160{}, errors.New("no valid hashes are found")
}
func nnsIsAvailable(c morphUtil.Client, nnsHash util.Uint160, name string) (bool, error) { func nnsIsAvailable(c morphUtil.Client, nnsHash util.Uint160, name string) (bool, error) {
switch c.(type) { switch c.(type) {
case *rpcclient.Client: case *rpcclient.Client:

View file

@ -21,7 +21,7 @@ func listNetmapCandidatesNodes(cmd *cobra.Command, _ []string) {
cs, err := r.GetContractByID(1) cs, err := r.GetContractByID(1)
commonCmd.ExitOnErr(cmd, "can't get NNS contract info: %w", err) commonCmd.ExitOnErr(cmd, "can't get NNS contract info: %w", err)
nmHash, err := nnsResolveHash(inv, cs.Hash, domainOf(netmapContract)) nmHash, err := util.NNSResolveHash(inv, cs.Hash, domainOf(netmapContract))
commonCmd.ExitOnErr(cmd, "can't get netmap contract hash: %w", err) commonCmd.ExitOnErr(cmd, "can't get netmap contract hash: %w", err)
res, err := inv.Call(nmHash, "netmapCandidates") res, err := inv.Call(nmHash, "netmapCandidates")

View file

@ -3,6 +3,7 @@ package morph
import ( import (
"fmt" "fmt"
util2 "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/util"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common" commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
@ -46,7 +47,7 @@ func processAccount(cmd *cobra.Command, addr util.Uint160, method string) error
return fmt.Errorf("can't get NNS contract info: %w", err) return fmt.Errorf("can't get NNS contract info: %w", err)
} }
proxyHash, err := nnsResolveHash(wCtx.ReadOnlyInvoker, cs.Hash, domainOf(proxyContract)) proxyHash, err := util2.NNSResolveHash(wCtx.ReadOnlyInvoker, cs.Hash, domainOf(proxyContract))
if err != nil { if err != nil {
return fmt.Errorf("can't get proxy contract hash: %w", err) return fmt.Errorf("can't get proxy contract hash: %w", err)
} }

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
netmapcontract "git.frostfs.info/TrueCloudLab/frostfs-contract/netmap" netmapcontract "git.frostfs.info/TrueCloudLab/frostfs-contract/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/util"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/management" "github.com/nspcc-dev/neo-go/pkg/rpcclient/management"
@ -40,7 +41,7 @@ func removeNodesCmd(cmd *cobra.Command, args []string) error {
return fmt.Errorf("can't get NNS contract info: %w", err) return fmt.Errorf("can't get NNS contract info: %w", err)
} }
nmHash, err := nnsResolveHash(wCtx.ReadOnlyInvoker, cs.Hash, domainOf(netmapContract)) nmHash, err := util.NNSResolveHash(wCtx.ReadOnlyInvoker, cs.Hash, domainOf(netmapContract))
if err != nil { if err != nil {
return fmt.Errorf("can't get netmap contract hash: %w", err) return fmt.Errorf("can't get netmap contract hash: %w", err)
} }

View file

@ -1,11 +1,18 @@
package util package util
import ( import (
"errors"
"fmt" "fmt"
"time" "time"
"git.frostfs.info/TrueCloudLab/frostfs-contract/nns"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate" "github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
"github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -88,3 +95,48 @@ func GetWalletAccount(w *wallet.Wallet, typ string) (*wallet.Account, error) {
} }
return nil, fmt.Errorf("account for '%s' not found", typ) return nil, fmt.Errorf("account for '%s' not found", typ)
} }
func NNSResolve(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (stackitem.Item, error) {
return unwrap.Item(inv.Call(nnsHash, "resolve", domain, int64(nns.TXT)))
}
// ParseNNSResolveResult parses the result of resolving NNS record.
// It works with multiple formats (corresponding to multiple NNS versions).
// If array of hashes is provided, it returns only the first one.
func ParseNNSResolveResult(res stackitem.Item) (util.Uint160, error) {
arr, ok := res.Value().([]stackitem.Item)
if !ok {
arr = []stackitem.Item{res}
}
if _, ok := res.Value().(stackitem.Null); ok || len(arr) == 0 {
return util.Uint160{}, errors.New("NNS record is missing")
}
for i := range arr {
bs, err := arr[i].TryBytes()
if err != nil {
continue
}
// We support several formats for hash encoding, this logic should be maintained in sync
// with NNSResolve from pkg/morph/client/nns.go
h, err := util.Uint160DecodeStringLE(string(bs))
if err == nil {
return h, nil
}
h, err = address.StringToUint160(string(bs))
if err == nil {
return h, nil
}
}
return util.Uint160{}, errors.New("no valid hashes are found")
}
// NNSResolveHash Returns errMissingNNSRecord if invocation fault exception contains "token not found".
func NNSResolveHash(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (util.Uint160, error) {
item, err := NNSResolve(inv, nnsHash, domain)
if err != nil {
return util.Uint160{}, err
}
return ParseNNSResolveResult(item)
}