neo-go/pkg/rpcclient/native.go
Roman Khimov f011b3c3dd rpcclient: introduce NEO wrapper
Notice that int64 types are used for gas per block or registration price
because the price has to fit into the system fee limitation and gas per block
value can't be more than 10 GAS. We use int64 for votes as well in other types
since NEO is limited to 100M.
2022-08-17 22:03:09 +03:00

159 lines
6 KiB
Go

package rpcclient
// Various non-policy things from native contracts.
import (
"crypto/elliptic"
"errors"
"fmt"
"github.com/google/uuid"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nns"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
// GetOraclePrice invokes `getPrice` method on a native Oracle contract.
//
// Deprecated: please use oracle subpackage.
func (c *Client) GetOraclePrice() (int64, error) {
oracleHash, err := c.GetNativeContractHash(nativenames.Oracle)
if err != nil {
return 0, fmt.Errorf("failed to get native Oracle hash: %w", err)
}
return c.invokeNativeGetMethod(oracleHash, "getPrice")
}
// GetNNSPrice invokes `getPrice` method on a NeoNameService contract with the specified hash.
func (c *Client) GetNNSPrice(nnsHash util.Uint160) (int64, error) {
return c.invokeNativeGetMethod(nnsHash, "getPrice")
}
// GetGasPerBlock invokes `getGasPerBlock` method on a native NEO contract.
//
// Deprecated: please use neo subpackage. This method will be removed in future releases.
func (c *Client) GetGasPerBlock() (int64, error) {
return c.getFromNEO("getGasPerBlock")
}
// GetCandidateRegisterPrice invokes `getRegisterPrice` method on native NEO contract.
//
// Deprecated: please use neo subpackage. This method will be removed in future releases.
func (c *Client) GetCandidateRegisterPrice() (int64, error) {
return c.getFromNEO("getRegisterPrice")
}
func (c *Client) getFromNEO(meth string) (int64, error) {
neoHash, err := c.GetNativeContractHash(nativenames.Neo)
if err != nil {
return 0, fmt.Errorf("failed to get native NEO hash: %w", err)
}
return c.invokeNativeGetMethod(neoHash, meth)
}
// GetDesignatedByRole invokes `getDesignatedByRole` method on a native RoleManagement contract.
//
// Deprecated: please use rolemgmt package.
func (c *Client) GetDesignatedByRole(role noderoles.Role, index uint32) (keys.PublicKeys, error) {
rmHash, err := c.GetNativeContractHash(nativenames.Designation)
if err != nil {
return nil, fmt.Errorf("failed to get native RoleManagement hash: %w", err)
}
arr, err := unwrap.Array(c.reader.Call(rmHash, "getDesignatedByRole", int64(role), index))
if err != nil {
return nil, err
}
pks := make(keys.PublicKeys, len(arr))
for i, item := range arr {
val, err := item.TryBytes()
if err != nil {
return nil, fmt.Errorf("invalid array element #%d: %s", i, item.Type())
}
pks[i], err = keys.NewPublicKeyFromBytes(val, elliptic.P256())
if err != nil {
return nil, err
}
}
return pks, nil
}
// NNSResolve invokes `resolve` method on a NameService contract with the specified hash.
func (c *Client) NNSResolve(nnsHash util.Uint160, name string, typ nns.RecordType) (string, error) {
if typ == nns.CNAME {
return "", errors.New("can't resolve CNAME record type")
}
return unwrap.UTF8String(c.reader.Call(nnsHash, "resolve", name, int64(typ)))
}
// NNSIsAvailable invokes `isAvailable` method on a NeoNameService contract with the specified hash.
func (c *Client) NNSIsAvailable(nnsHash util.Uint160, name string) (bool, error) {
return unwrap.Bool(c.reader.Call(nnsHash, "isAvailable", name))
}
// NNSGetAllRecords returns iterator over records for a given name from NNS service.
// First return value is the session ID, the second one is Iterator itself, the
// third one is an error. Use TraverseIterator method to traverse iterator values or
// TerminateSession to terminate opened iterator session. See TraverseIterator and
// TerminateSession documentation for more details.
func (c *Client) NNSGetAllRecords(nnsHash util.Uint160, name string) (uuid.UUID, result.Iterator, error) {
return unwrap.SessionIterator(c.reader.Call(nnsHash, "getAllRecords", name))
}
// NNSUnpackedGetAllRecords returns a set of records for a given name from NNS service
// (config.DefaultMaxIteratorResultItems at max). It differs from NNSGetAllRecords in
// that no iterator session is used to retrieve values from iterator. Instead, unpacking
// VM script is created and invoked via `invokescript` JSON-RPC call.
func (c *Client) NNSUnpackedGetAllRecords(nnsHash util.Uint160, name string) ([]nns.RecordState, error) {
arr, err := unwrap.Array(c.reader.CallAndExpandIterator(nnsHash, "getAllRecords", config.DefaultMaxIteratorResultItems, name))
if err != nil {
return nil, err
}
res := make([]nns.RecordState, len(arr))
for i := range arr {
rs, ok := arr[i].Value().([]stackitem.Item)
if !ok {
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: not a struct", i)
}
if len(rs) != 3 {
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: wrong number of elements", i)
}
name, err := rs[0].TryBytes()
if err != nil {
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: %w", i, err)
}
typ, err := rs[1].TryInteger()
if err != nil {
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: %w", i, err)
}
data, err := rs[2].TryBytes()
if err != nil {
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: %w", i, err)
}
u64Typ := typ.Uint64()
if !typ.IsUint64() || u64Typ > 255 {
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: bad type", i)
}
res[i] = nns.RecordState{
Name: string(name),
Type: nns.RecordType(u64Typ),
Data: string(data),
}
}
return res, nil
}
// GetNotaryServiceFeePerKey returns a reward per notary request key for the designated
// notary nodes. It doesn't cache the result.
func (c *Client) GetNotaryServiceFeePerKey() (int64, error) {
notaryHash, err := c.GetNativeContractHash(nativenames.Notary)
if err != nil {
return 0, fmt.Errorf("failed to get native Notary hash: %w", err)
}
return c.invokeNativeGetMethod(notaryHash, "getNotaryServiceFeePerKey")
}