[#93] Return NNS resolver
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
a5b61c4f64
commit
a2572a23a3
3 changed files with 123 additions and 1 deletions
3
go.mod
3
go.mod
|
@ -9,11 +9,12 @@ require (
|
||||||
github.com/hashicorp/golang-lru v0.5.4
|
github.com/hashicorp/golang-lru v0.5.4
|
||||||
github.com/mr-tron/base58 v1.2.0
|
github.com/mr-tron/base58 v1.2.0
|
||||||
github.com/nspcc-dev/hrw v1.0.9
|
github.com/nspcc-dev/hrw v1.0.9
|
||||||
|
github.com/nspcc-dev/neo-go v0.98.0
|
||||||
github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1
|
github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1
|
||||||
github.com/nspcc-dev/neofs-crypto v0.3.0
|
github.com/nspcc-dev/neofs-crypto v0.3.0
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.0
|
github.com/nspcc-dev/rfc6979 v0.2.0
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
go.uber.org/zap v1.18.1
|
go.uber.org/zap v1.18.1
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
|
||||||
google.golang.org/grpc v1.41.0
|
google.golang.org/grpc v1.41.0
|
||||||
)
|
)
|
||||||
|
|
BIN
go.sum
BIN
go.sum
Binary file not shown.
121
resolver/nns.go
Normal file
121
resolver/nns.go
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
package resolver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
nns "github.com/nspcc-dev/neo-go/examples/nft-nd-nns"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpc/client"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NNSResolver interface {
|
||||||
|
// ResolveContainerName get record for domain name+'.container' from NNS contract.
|
||||||
|
ResolveContainerName(name string) (*cid.ID, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type nnsResolver struct {
|
||||||
|
rpc *client.Client
|
||||||
|
nnsHash util.Uint160
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
resolve = "resolve"
|
||||||
|
containerDomain = ".container"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewNNSResolver creates resolver that can get records from NNS contract.
|
||||||
|
func NewNNSResolver(rpc *client.Client) (NNSResolver, error) {
|
||||||
|
nnsContract, err := rpc.GetContractStateByID(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &nnsResolver{
|
||||||
|
rpc: rpc,
|
||||||
|
nnsHash: nnsContract.Hash,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *nnsResolver) ResolveContainerName(name string) (*cid.ID, error) {
|
||||||
|
res, err := n.rpc.InvokeFunction(n.nnsHash, resolve, []smartcontract.Parameter{
|
||||||
|
{
|
||||||
|
Type: smartcontract.StringType,
|
||||||
|
Value: name + containerDomain,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: smartcontract.IntegerType,
|
||||||
|
Value: int64(nns.TXT),
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = getInvocationError(res); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
arr, err := getArrString(res.Stack)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cnrID := cid.New()
|
||||||
|
for _, rec := range arr {
|
||||||
|
if err = cnrID.Parse(rec); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return cnrID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getArrString(st []stackitem.Item) ([]string, error) {
|
||||||
|
array, err := getArray(st)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make([]string, len(array))
|
||||||
|
for i, item := range array {
|
||||||
|
bs, err := item.TryBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res[i] = string(bs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getArray(st []stackitem.Item) ([]stackitem.Item, error) {
|
||||||
|
index := len(st) - 1 // top stack element is last in the array
|
||||||
|
arr, err := st[index].Convert(stackitem.ArrayT)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, ok := arr.(stackitem.Null); ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator, ok := arr.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("bad conversion")
|
||||||
|
}
|
||||||
|
return iterator, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInvocationError(result *result.Invoke) error {
|
||||||
|
if result.State != vm.HaltState.String() {
|
||||||
|
return fmt.Errorf("invocation failed: %s", result.FaultException)
|
||||||
|
}
|
||||||
|
if len(result.Stack) == 0 {
|
||||||
|
return fmt.Errorf("result stack is empty")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in a new issue