[#936] morph/nns: Add record existence check

Also, add ErrNNSRecordNotFound error that
indicates that required hash is not presented
in `NNS` contract.

Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
Pavel Karpy 2021-10-20 16:17:01 +03:00 committed by Alex Vanin
parent e500efb9b3
commit b492201a84

View file

@ -32,6 +32,13 @@ const (
NNSReputationContractName = "reputation.neofs" NNSReputationContractName = "reputation.neofs"
) )
var (
// ErrNNSRecordNotFound means that there is no such record in NNS contract.
ErrNNSRecordNotFound = errors.New("record has not been found in NNS contract")
errEmptyResultStack = errors.New("returned result stack is empty")
)
// NNSAlphabetContractName returns contract name of the alphabet contract in NNS // NNSAlphabetContractName returns contract name of the alphabet contract in NNS
// based on alphabet index. // based on alphabet index.
func NNSAlphabetContractName(index int) string { func NNSAlphabetContractName(index int) string {
@ -40,6 +47,7 @@ func NNSAlphabetContractName(index int) string {
// NNSContractAddress returns contract address script hash based on its name // NNSContractAddress returns contract address script hash based on its name
// in NNS contract. // in NNS contract.
// If script hash has not been found, returns ErrNNSRecordNotFound.
func (c *Client) NNSContractAddress(name string) (sh util.Uint160, err error) { func (c *Client) NNSContractAddress(name string) (sh util.Uint160, err error) {
if c.multiClient != nil { if c.multiClient != nil {
return sh, c.multiClient.iterateClients(func(c *Client) error { return sh, c.multiClient.iterateClients(func(c *Client) error {
@ -61,6 +69,15 @@ func (c *Client) NNSContractAddress(name string) (sh util.Uint160, err error) {
} }
func nnsResolve(c *client.Client, nnsHash util.Uint160, domain string) (util.Uint160, error) { func nnsResolve(c *client.Client, nnsHash util.Uint160, domain string) (util.Uint160, error) {
found, err := exists(c, nnsHash, domain)
if err != nil {
return util.Uint160{}, fmt.Errorf("could not check presence in NNS contract for %s: %w", domain, err)
}
if !found {
return util.Uint160{}, ErrNNSRecordNotFound
}
result, err := c.InvokeFunction(nnsHash, "resolve", []smartcontract.Parameter{ result, err := c.InvokeFunction(nnsHash, "resolve", []smartcontract.Parameter{
{ {
Type: smartcontract.StringType, Type: smartcontract.StringType,
@ -78,7 +95,7 @@ func nnsResolve(c *client.Client, nnsHash util.Uint160, domain string) (util.Uin
return util.Uint160{}, fmt.Errorf("invocation failed: %s", result.FaultException) return util.Uint160{}, fmt.Errorf("invocation failed: %s", result.FaultException)
} }
if len(result.Stack) == 0 { if len(result.Stack) == 0 {
return util.Uint160{}, errors.New("result stack is empty") return util.Uint160{}, errEmptyResultStack
} }
// Parse the result of resolving NNS record. // Parse the result of resolving NNS record.
@ -97,3 +114,30 @@ func nnsResolve(c *client.Client, nnsHash util.Uint160, domain string) (util.Uin
} }
return util.Uint160DecodeStringLE(string(bs)) return util.Uint160DecodeStringLE(string(bs))
} }
func exists(c *client.Client, nnsHash util.Uint160, domain string) (bool, error) {
result, err := c.InvokeFunction(nnsHash, "isAvailable", []smartcontract.Parameter{
{
Type: smartcontract.StringType,
Value: domain,
},
}, nil)
if err != nil {
return false, err
}
if len(result.Stack) == 0 {
return false, errEmptyResultStack
}
res := result.Stack[0]
available, err := res.TryBool()
if err != nil {
return false, fmt.Errorf("malformed response: %w", err)
}
// not available means that it is taken
// and, therefore, exists
return !available, nil
}