neoneo-go/pkg/rpc/param.go
Roman Khimov cf39171485 rpc: implement invokefunction, fix #347
Param getters were redone to return errors because otherwise bad FuncParam
values could lead to panic. FuncParam itself might be not the most elegant
solution, but it works good enough for now.
2019-11-27 13:00:11 +03:00

164 lines
3.3 KiB
Go

package rpc
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/CityOfZion/neo-go/pkg/crypto"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/pkg/errors"
)
type (
// Param represents a param either passed to
// the server or to send to a server using
// the client.
Param struct {
Type paramType
Value interface{}
}
paramType int
// FuncParam represents a function argument parameter used in the
// invokefunction RPC method.
FuncParam struct {
Type StackParamType `json:"type"`
Value Param `json:"value"`
}
)
const (
defaultT paramType = iota
stringT
numberT
arrayT
funcParamT
)
func (p Param) String() string {
return fmt.Sprintf("%v", p.Value)
}
// GetString returns string value of the parameter.
func (p Param) GetString() (string, error) {
str, ok := p.Value.(string)
if !ok {
return "", errors.New("not a string")
}
return str, nil
}
// GetInt returns int value of te parameter.
func (p Param) GetInt() (int, error) {
i, ok := p.Value.(int)
if !ok {
return 0, errors.New("not an integer")
}
return i, nil
}
// GetArray returns a slice of Params stored in the parameter.
func (p Param) GetArray() ([]Param, error) {
a, ok := p.Value.([]Param)
if !ok {
return nil, errors.New("not an array")
}
return a, nil
}
// GetUint256 returns Uint256 value of the parameter.
func (p Param) GetUint256() (util.Uint256, error) {
s, err := p.GetString()
if err != nil {
return util.Uint256{}, err
}
return util.Uint256DecodeReverseString(s)
}
// GetUint160FromHex returns Uint160 value of the parameter encoded in hex.
func (p Param) GetUint160FromHex() (util.Uint160, error) {
s, err := p.GetString()
if err != nil {
return util.Uint160{}, err
}
scriptHashLE, err := util.Uint160DecodeString(s)
if err != nil {
return util.Uint160{}, err
}
return util.Uint160DecodeBytes(scriptHashLE.BytesReverse())
}
// GetUint160FromAddress returns Uint160 value of the parameter that was
// supplied as an address.
func (p Param) GetUint160FromAddress() (util.Uint160, error) {
s, err := p.GetString()
if err != nil {
return util.Uint160{}, err
}
return crypto.Uint160DecodeAddress(s)
}
// GetFuncParam returns current parameter as a function call parameter.
func (p Param) GetFuncParam() (FuncParam, error) {
fp, ok := p.Value.(FuncParam)
if !ok {
return FuncParam{}, errors.New("not a function parameter")
}
return fp, nil
}
// GetBytesHex returns []byte value of the parameter if
// it is a hex-encoded string.
func (p Param) GetBytesHex() ([]byte, error) {
s, err := p.GetString()
if err != nil {
return nil, err
}
return hex.DecodeString(s)
}
// UnmarshalJSON implements json.Unmarshaler interface.
func (p *Param) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err == nil {
p.Type = stringT
p.Value = s
return nil
}
var num float64
if err := json.Unmarshal(data, &num); err == nil {
p.Type = numberT
p.Value = int(num)
return nil
}
r := bytes.NewReader(data)
jd := json.NewDecoder(r)
jd.DisallowUnknownFields()
var fp FuncParam
if err := jd.Decode(&fp); err == nil {
p.Type = funcParamT
p.Value = fp
return nil
}
var ps []Param
if err := json.Unmarshal(data, &ps); err == nil {
p.Type = arrayT
p.Value = ps
return nil
}
return errors.New("unknown type")
}