68 lines
2 KiB
Go
68 lines
2 KiB
Go
package resolver
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/nns"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-lifecycler/internal/morph"
|
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
)
|
|
|
|
// ResolveContractHash determine contract hash by resolving NNS name.
|
|
func ResolveContractHash(cli *morph.Client, contractHash string) (util.Uint160, error) {
|
|
if hash, err := util.Uint160DecodeStringLE(contractHash); err == nil {
|
|
return hash, nil
|
|
}
|
|
|
|
if strings.Count(contractHash, ".") != 1 {
|
|
return util.Uint160{}, fmt.Errorf("invalid contract name: '%s'", contractHash)
|
|
}
|
|
|
|
nnsContract, err := cli.Client().NNSHash()
|
|
if err != nil {
|
|
return util.Uint160{}, fmt.Errorf("get NNS contract hash: %w", err)
|
|
}
|
|
|
|
return invokeResolve(cli, nnsContract, contractHash)
|
|
}
|
|
|
|
func invokeResolve(cli *morph.Client, nnsContract util.Uint160, contractHash string) (util.Uint160, error) {
|
|
items, err := cli.Client().TestInvoke(nnsContract, "resolve", contractHash, int64(nns.TXT))
|
|
if err != nil {
|
|
return util.Uint160{}, fmt.Errorf("contract invocation: %w", err)
|
|
}
|
|
if len(items) != 1 {
|
|
return util.Uint160{}, fmt.Errorf("stack has %d items", len(items))
|
|
}
|
|
|
|
if _, ok := items[0].(stackitem.Null); !ok {
|
|
arr, ok := items[0].Value().([]stackitem.Item)
|
|
if !ok {
|
|
// unexpected for types from stackitem package
|
|
return util.Uint160{}, errors.New("invalid cast to stack item slice")
|
|
}
|
|
|
|
for i := range arr {
|
|
recordValue, err := arr[i].TryBytes()
|
|
if err != nil {
|
|
return util.Uint160{}, fmt.Errorf("convert array item to byte slice: %w", err)
|
|
}
|
|
|
|
strRecordValue := string(recordValue)
|
|
scriptHash, err := address.StringToUint160(strRecordValue)
|
|
if err == nil {
|
|
return scriptHash, nil
|
|
}
|
|
scriptHash, err = util.Uint160DecodeStringLE(strRecordValue)
|
|
if err == nil {
|
|
return scriptHash, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
return util.Uint160{}, errors.New("record not found")
|
|
}
|