Merge pull request #2234 from nspcc-dev/rpc/params-parsing
rpc: method-specific parameters parsing optimisation
This commit is contained in:
commit
6b8e615094
15 changed files with 655 additions and 535 deletions
|
@ -95,10 +95,17 @@ it only works for native contracts.
|
||||||
VM state is included to verbose response along with other transaction fields if
|
VM state is included to verbose response along with other transaction fields if
|
||||||
the transaction is already on chain.
|
the transaction is already on chain.
|
||||||
|
|
||||||
|
##### `getstateroot`
|
||||||
|
|
||||||
|
This method is able to accept state root hash instead of index, unlike the C# node
|
||||||
|
where only index is accepted.
|
||||||
|
|
||||||
##### `getstorage`
|
##### `getstorage`
|
||||||
|
|
||||||
This method doesn't work for the Ledger contract, you can get data via regular
|
This method doesn't work for the Ledger contract, you can get data via regular
|
||||||
`getblock` and `getrawtransaction` calls.
|
`getblock` and `getrawtransaction` calls. This method is able to get storage of
|
||||||
|
the native contract by its name (case-insensitive), unlike the C# node where
|
||||||
|
it only possible for index or hash.
|
||||||
|
|
||||||
#### `getnep17balances`
|
#### `getnep17balances`
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ func Call(ic *interop.Context) error {
|
||||||
}
|
}
|
||||||
md := cs.Manifest.ABI.GetMethod(method, len(args))
|
md := cs.Manifest.ABI.GetMethod(method, len(args))
|
||||||
if md == nil {
|
if md == nil {
|
||||||
return errors.New("method not found")
|
return fmt.Errorf("method not found: %s/%d", method, len(args))
|
||||||
}
|
}
|
||||||
hasReturn := md.ReturnType != smartcontract.VoidType
|
hasReturn := md.ReturnType != smartcontract.VoidType
|
||||||
if !hasReturn {
|
if !hasReturn {
|
||||||
|
|
|
@ -1649,8 +1649,8 @@ func wrapInitResponse(r *request.In, resp string) string {
|
||||||
case "getversion":
|
case "getversion":
|
||||||
response = `{"id":1,"jsonrpc":"2.0","result":{"network":42,"tcpport":20332,"wsport":20342,"nonce":2153672787,"useragent":"/NEO-GO:0.73.1-pre-273-ge381358/"}}`
|
response = `{"id":1,"jsonrpc":"2.0","result":{"network":42,"tcpport":20332,"wsport":20342,"nonce":2153672787,"useragent":"/NEO-GO:0.73.1-pre-273-ge381358/"}}`
|
||||||
case "getcontractstate":
|
case "getcontractstate":
|
||||||
p, _ := r.Params()
|
p := request.Params(r.RawParams)
|
||||||
name, _ := p.ValueWithType(0, request.StringT).GetString()
|
name, _ := p.Value(0).GetString()
|
||||||
switch name {
|
switch name {
|
||||||
case "NeoToken":
|
case "NeoToken":
|
||||||
response = `{"id":1,"jsonrpc":"2.0","result":{"id":-1,"script":"DANORU9Ba2d4Cw==","manifest":{"name":"NEO","abi":{"hash":"0xde5f57d430d3dece511cf975a8d37848cb9e0525","methods":[{"name":"name","offset":0,"parameters":null,"returntype":"String"},{"name":"symbol","offset":0,"parameters":null,"returntype":"String"},{"name":"decimals","offset":0,"parameters":null,"returntype":"Integer"},{"name":"totalSupply","offset":0,"parameters":null,"returntype":"Integer"},{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer"},{"name":"transfer","offset":0,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Boolean"},{"name":"onPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"postPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"unclaimedGas","offset":0,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer"},{"name":"registerCandidate","offset":0,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"unregisterCandidate","offset":0,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"vote","offset":0,"parameters":[{"name":"account","type":"Hash160"},{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"getCandidates","offset":0,"parameters":null,"returntype":"Array"},{"name":"getСommittee","offset":0,"parameters":null,"returntype":"Array"},{"name":"getNextBlockValidators","offset":0,"parameters":null,"returntype":"Array"},{"name":"getGasPerBlock","offset":0,"parameters":null,"returntype":"Integer"},{"name":"setGasPerBlock","offset":0,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Boolean"}],"events":[{"name":"Transfer","parameters":null}]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-5"],"trusts":[],"safemethods":["name","symbol","decimals","totalSupply","balanceOf","unclaimedGas","getCandidates","getСommittee","getNextBlockValidators"],"extra":null},"hash":"0xde5f57d430d3dece511cf975a8d37848cb9e0525"}}`
|
response = `{"id":1,"jsonrpc":"2.0","result":{"id":-1,"script":"DANORU9Ba2d4Cw==","manifest":{"name":"NEO","abi":{"hash":"0xde5f57d430d3dece511cf975a8d37848cb9e0525","methods":[{"name":"name","offset":0,"parameters":null,"returntype":"String"},{"name":"symbol","offset":0,"parameters":null,"returntype":"String"},{"name":"decimals","offset":0,"parameters":null,"returntype":"Integer"},{"name":"totalSupply","offset":0,"parameters":null,"returntype":"Integer"},{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer"},{"name":"transfer","offset":0,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Boolean"},{"name":"onPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"postPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"unclaimedGas","offset":0,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer"},{"name":"registerCandidate","offset":0,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"unregisterCandidate","offset":0,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"vote","offset":0,"parameters":[{"name":"account","type":"Hash160"},{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"getCandidates","offset":0,"parameters":null,"returntype":"Array"},{"name":"getСommittee","offset":0,"parameters":null,"returntype":"Array"},{"name":"getNextBlockValidators","offset":0,"parameters":null,"returntype":"Array"},{"name":"getGasPerBlock","offset":0,"parameters":null,"returntype":"Integer"},{"name":"setGasPerBlock","offset":0,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Boolean"}],"events":[{"name":"Transfer","parameters":null}]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-5"],"trusts":[],"safemethods":["name","symbol","decimals","totalSupply","balanceOf","unclaimedGas","getCandidates","getСommittee","getNextBlockValidators"],"extra":null},"hash":"0xde5f57d430d3dece511cf975a8d37848cb9e0525"}}`
|
||||||
|
|
|
@ -134,9 +134,7 @@ readloop:
|
||||||
// Bad event received.
|
// Bad event received.
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
var slice []json.RawMessage
|
if event != response.MissedEventID && len(rr.RawParams) != 1 {
|
||||||
err = json.Unmarshal(rr.RawParams, &slice)
|
|
||||||
if err != nil || (event != response.MissedEventID && len(slice) != 1) {
|
|
||||||
// Bad event received.
|
// Bad event received.
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -159,7 +157,7 @@ readloop:
|
||||||
break readloop
|
break readloop
|
||||||
}
|
}
|
||||||
if event != response.MissedEventID {
|
if event != response.MissedEventID {
|
||||||
err = json.Unmarshal(slice[0], val)
|
err = json.Unmarshal(rr.RawParams[0].RawMessage, val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Bad event received.
|
// Bad event received.
|
||||||
break
|
break
|
||||||
|
|
|
@ -187,10 +187,8 @@ func TestWSFilteredSubscriptions(t *testing.T) {
|
||||||
},
|
},
|
||||||
func(t *testing.T, p *request.Params) {
|
func(t *testing.T, p *request.Params) {
|
||||||
param := p.Value(1)
|
param := p.Value(1)
|
||||||
raw, ok := param.Value.(json.RawMessage)
|
|
||||||
require.True(t, ok)
|
|
||||||
filt := new(request.BlockFilter)
|
filt := new(request.BlockFilter)
|
||||||
require.NoError(t, json.Unmarshal(raw, filt))
|
require.NoError(t, json.Unmarshal(param.RawMessage, filt))
|
||||||
require.Equal(t, 3, filt.Primary)
|
require.Equal(t, 3, filt.Primary)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -202,10 +200,8 @@ func TestWSFilteredSubscriptions(t *testing.T) {
|
||||||
},
|
},
|
||||||
func(t *testing.T, p *request.Params) {
|
func(t *testing.T, p *request.Params) {
|
||||||
param := p.Value(1)
|
param := p.Value(1)
|
||||||
raw, ok := param.Value.(json.RawMessage)
|
|
||||||
require.True(t, ok)
|
|
||||||
filt := new(request.TxFilter)
|
filt := new(request.TxFilter)
|
||||||
require.NoError(t, json.Unmarshal(raw, filt))
|
require.NoError(t, json.Unmarshal(param.RawMessage, filt))
|
||||||
require.Equal(t, util.Uint160{1, 2, 3, 4, 5}, *filt.Sender)
|
require.Equal(t, util.Uint160{1, 2, 3, 4, 5}, *filt.Sender)
|
||||||
require.Nil(t, filt.Signer)
|
require.Nil(t, filt.Signer)
|
||||||
},
|
},
|
||||||
|
@ -218,10 +214,8 @@ func TestWSFilteredSubscriptions(t *testing.T) {
|
||||||
},
|
},
|
||||||
func(t *testing.T, p *request.Params) {
|
func(t *testing.T, p *request.Params) {
|
||||||
param := p.Value(1)
|
param := p.Value(1)
|
||||||
raw, ok := param.Value.(json.RawMessage)
|
|
||||||
require.True(t, ok)
|
|
||||||
filt := new(request.TxFilter)
|
filt := new(request.TxFilter)
|
||||||
require.NoError(t, json.Unmarshal(raw, filt))
|
require.NoError(t, json.Unmarshal(param.RawMessage, filt))
|
||||||
require.Nil(t, filt.Sender)
|
require.Nil(t, filt.Sender)
|
||||||
require.Equal(t, util.Uint160{0, 42}, *filt.Signer)
|
require.Equal(t, util.Uint160{0, 42}, *filt.Signer)
|
||||||
},
|
},
|
||||||
|
@ -235,10 +229,8 @@ func TestWSFilteredSubscriptions(t *testing.T) {
|
||||||
},
|
},
|
||||||
func(t *testing.T, p *request.Params) {
|
func(t *testing.T, p *request.Params) {
|
||||||
param := p.Value(1)
|
param := p.Value(1)
|
||||||
raw, ok := param.Value.(json.RawMessage)
|
|
||||||
require.True(t, ok)
|
|
||||||
filt := new(request.TxFilter)
|
filt := new(request.TxFilter)
|
||||||
require.NoError(t, json.Unmarshal(raw, filt))
|
require.NoError(t, json.Unmarshal(param.RawMessage, filt))
|
||||||
require.Equal(t, util.Uint160{1, 2, 3, 4, 5}, *filt.Sender)
|
require.Equal(t, util.Uint160{1, 2, 3, 4, 5}, *filt.Sender)
|
||||||
require.Equal(t, util.Uint160{0, 42}, *filt.Signer)
|
require.Equal(t, util.Uint160{0, 42}, *filt.Signer)
|
||||||
},
|
},
|
||||||
|
@ -251,10 +243,8 @@ func TestWSFilteredSubscriptions(t *testing.T) {
|
||||||
},
|
},
|
||||||
func(t *testing.T, p *request.Params) {
|
func(t *testing.T, p *request.Params) {
|
||||||
param := p.Value(1)
|
param := p.Value(1)
|
||||||
raw, ok := param.Value.(json.RawMessage)
|
|
||||||
require.True(t, ok)
|
|
||||||
filt := new(request.NotificationFilter)
|
filt := new(request.NotificationFilter)
|
||||||
require.NoError(t, json.Unmarshal(raw, filt))
|
require.NoError(t, json.Unmarshal(param.RawMessage, filt))
|
||||||
require.Equal(t, util.Uint160{1, 2, 3, 4, 5}, *filt.Contract)
|
require.Equal(t, util.Uint160{1, 2, 3, 4, 5}, *filt.Contract)
|
||||||
require.Nil(t, filt.Name)
|
require.Nil(t, filt.Name)
|
||||||
},
|
},
|
||||||
|
@ -267,10 +257,8 @@ func TestWSFilteredSubscriptions(t *testing.T) {
|
||||||
},
|
},
|
||||||
func(t *testing.T, p *request.Params) {
|
func(t *testing.T, p *request.Params) {
|
||||||
param := p.Value(1)
|
param := p.Value(1)
|
||||||
raw, ok := param.Value.(json.RawMessage)
|
|
||||||
require.True(t, ok)
|
|
||||||
filt := new(request.NotificationFilter)
|
filt := new(request.NotificationFilter)
|
||||||
require.NoError(t, json.Unmarshal(raw, filt))
|
require.NoError(t, json.Unmarshal(param.RawMessage, filt))
|
||||||
require.Equal(t, "my_pretty_notification", *filt.Name)
|
require.Equal(t, "my_pretty_notification", *filt.Name)
|
||||||
require.Nil(t, filt.Contract)
|
require.Nil(t, filt.Contract)
|
||||||
},
|
},
|
||||||
|
@ -284,10 +272,8 @@ func TestWSFilteredSubscriptions(t *testing.T) {
|
||||||
},
|
},
|
||||||
func(t *testing.T, p *request.Params) {
|
func(t *testing.T, p *request.Params) {
|
||||||
param := p.Value(1)
|
param := p.Value(1)
|
||||||
raw, ok := param.Value.(json.RawMessage)
|
|
||||||
require.True(t, ok)
|
|
||||||
filt := new(request.NotificationFilter)
|
filt := new(request.NotificationFilter)
|
||||||
require.NoError(t, json.Unmarshal(raw, filt))
|
require.NoError(t, json.Unmarshal(param.RawMessage, filt))
|
||||||
require.Equal(t, util.Uint160{1, 2, 3, 4, 5}, *filt.Contract)
|
require.Equal(t, util.Uint160{1, 2, 3, 4, 5}, *filt.Contract)
|
||||||
require.Equal(t, "my_pretty_notification", *filt.Name)
|
require.Equal(t, "my_pretty_notification", *filt.Name)
|
||||||
},
|
},
|
||||||
|
@ -300,10 +286,8 @@ func TestWSFilteredSubscriptions(t *testing.T) {
|
||||||
},
|
},
|
||||||
func(t *testing.T, p *request.Params) {
|
func(t *testing.T, p *request.Params) {
|
||||||
param := p.Value(1)
|
param := p.Value(1)
|
||||||
raw, ok := param.Value.(json.RawMessage)
|
|
||||||
require.True(t, ok)
|
|
||||||
filt := new(request.ExecutionFilter)
|
filt := new(request.ExecutionFilter)
|
||||||
require.NoError(t, json.Unmarshal(raw, filt))
|
require.NoError(t, json.Unmarshal(param.RawMessage, filt))
|
||||||
require.Equal(t, "FAULT", filt.State)
|
require.Equal(t, "FAULT", filt.State)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -320,9 +304,8 @@ func TestWSFilteredSubscriptions(t *testing.T) {
|
||||||
req := request.In{}
|
req := request.In{}
|
||||||
err = ws.ReadJSON(&req)
|
err = ws.ReadJSON(&req)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
params, err := req.Params()
|
params := request.Params(req.RawParams)
|
||||||
require.NoError(t, err)
|
c.serverCode(t, ¶ms)
|
||||||
c.serverCode(t, params)
|
|
||||||
err = ws.SetWriteDeadline(time.Now().Add(2 * time.Second))
|
err = ws.SetWriteDeadline(time.Now().Add(2 * time.Second))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = ws.WriteMessage(1, []byte(`{"jsonrpc": "2.0", "id": 1, "result": "0"}`))
|
err = ws.WriteMessage(1, []byte(`{"jsonrpc": "2.0", "id": 1, "result": "0"}`))
|
||||||
|
|
|
@ -22,11 +22,10 @@ type (
|
||||||
// the server or to send to a server using
|
// the server or to send to a server using
|
||||||
// the client.
|
// the client.
|
||||||
Param struct {
|
Param struct {
|
||||||
Type paramType
|
json.RawMessage
|
||||||
Value interface{}
|
cache interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
paramType int
|
|
||||||
// FuncParam represents a function argument parameter used in the
|
// FuncParam represents a function argument parameter used in the
|
||||||
// invokefunction RPC method.
|
// invokefunction RPC method.
|
||||||
FuncParam struct {
|
FuncParam struct {
|
||||||
|
@ -64,68 +63,209 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// These are parameter types accepted by RPC server.
|
var (
|
||||||
const (
|
jsonNullBytes = []byte("null")
|
||||||
defaultT paramType = iota
|
jsonFalseBytes = []byte("false")
|
||||||
StringT
|
jsonTrueBytes = []byte("true")
|
||||||
NumberT
|
errMissingParameter = errors.New("parameter is missing")
|
||||||
BooleanT
|
errNotAString = errors.New("not a string")
|
||||||
ArrayT
|
errNotAnInt = errors.New("not an integer")
|
||||||
FuncParamT
|
errNotABool = errors.New("not a boolean")
|
||||||
BlockFilterT
|
errNotAnArray = errors.New("not an array")
|
||||||
TxFilterT
|
|
||||||
NotificationFilterT
|
|
||||||
ExecutionFilterT
|
|
||||||
SignerWithWitnessT
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var errMissingParameter = errors.New("parameter is missing")
|
|
||||||
|
|
||||||
func (p Param) String() string {
|
func (p Param) String() string {
|
||||||
return fmt.Sprintf("%v", p.Value)
|
str, _ := p.GetString()
|
||||||
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetString returns string value of the parameter.
|
// GetStringStrict returns string value of the parameter.
|
||||||
|
func (p *Param) GetStringStrict() (string, error) {
|
||||||
|
if p == nil {
|
||||||
|
return "", errMissingParameter
|
||||||
|
}
|
||||||
|
if p.IsNull() {
|
||||||
|
return "", errNotAString
|
||||||
|
}
|
||||||
|
if p.cache == nil {
|
||||||
|
var s string
|
||||||
|
err := json.Unmarshal(p.RawMessage, &s)
|
||||||
|
if err != nil {
|
||||||
|
return "", errNotAString
|
||||||
|
}
|
||||||
|
p.cache = s
|
||||||
|
}
|
||||||
|
if s, ok := p.cache.(string); ok {
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
return "", errNotAString
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetString returns string value of the parameter or tries to cast parameter to a string value.
|
||||||
func (p *Param) GetString() (string, error) {
|
func (p *Param) GetString() (string, error) {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return "", errMissingParameter
|
return "", errMissingParameter
|
||||||
}
|
}
|
||||||
str, ok := p.Value.(string)
|
if p.IsNull() {
|
||||||
if !ok {
|
return "", errNotAString
|
||||||
return "", errors.New("not a string")
|
|
||||||
}
|
}
|
||||||
return str, nil
|
if p.cache == nil {
|
||||||
}
|
var s string
|
||||||
|
err := json.Unmarshal(p.RawMessage, &s)
|
||||||
// GetBoolean returns boolean value of the parameter.
|
if err == nil {
|
||||||
func (p *Param) GetBoolean() bool {
|
p.cache = s
|
||||||
if p == nil {
|
} else {
|
||||||
return false
|
var i int
|
||||||
|
err = json.Unmarshal(p.RawMessage, &i)
|
||||||
|
if err == nil {
|
||||||
|
p.cache = i
|
||||||
|
} else {
|
||||||
|
var b bool
|
||||||
|
err = json.Unmarshal(p.RawMessage, &b)
|
||||||
|
if err == nil {
|
||||||
|
p.cache = b
|
||||||
|
} else {
|
||||||
|
return "", errNotAString
|
||||||
}
|
}
|
||||||
switch p.Type {
|
}
|
||||||
case NumberT:
|
}
|
||||||
return p.Value != 0
|
}
|
||||||
case StringT:
|
switch t := p.cache.(type) {
|
||||||
return p.Value != ""
|
case string:
|
||||||
case BooleanT:
|
return t, nil
|
||||||
return p.Value == true
|
case int:
|
||||||
|
return strconv.Itoa(t), nil
|
||||||
|
case bool:
|
||||||
|
if t {
|
||||||
|
return "true", nil
|
||||||
|
}
|
||||||
|
return "false", nil
|
||||||
default:
|
default:
|
||||||
return true
|
return "", errNotAString
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInt returns int value of te parameter.
|
// GetBooleanStrict returns boolean value of the parameter.
|
||||||
|
func (p *Param) GetBooleanStrict() (bool, error) {
|
||||||
|
if p == nil {
|
||||||
|
return false, errMissingParameter
|
||||||
|
}
|
||||||
|
if bytes.Equal(p.RawMessage, jsonTrueBytes) {
|
||||||
|
p.cache = true
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if bytes.Equal(p.RawMessage, jsonFalseBytes) {
|
||||||
|
p.cache = false
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, errNotABool
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBoolean returns boolean value of the parameter or tries to cast parameter to a bool value.
|
||||||
|
func (p *Param) GetBoolean() (bool, error) {
|
||||||
|
if p == nil {
|
||||||
|
return false, errMissingParameter
|
||||||
|
}
|
||||||
|
if p.IsNull() {
|
||||||
|
return false, errNotABool
|
||||||
|
}
|
||||||
|
var b bool
|
||||||
|
if p.cache == nil {
|
||||||
|
err := json.Unmarshal(p.RawMessage, &b)
|
||||||
|
if err == nil {
|
||||||
|
p.cache = b
|
||||||
|
} else {
|
||||||
|
var s string
|
||||||
|
err = json.Unmarshal(p.RawMessage, &s)
|
||||||
|
if err == nil {
|
||||||
|
p.cache = s
|
||||||
|
} else {
|
||||||
|
var i int
|
||||||
|
err = json.Unmarshal(p.RawMessage, &i)
|
||||||
|
if err == nil {
|
||||||
|
p.cache = i
|
||||||
|
} else {
|
||||||
|
return false, errNotABool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch t := p.cache.(type) {
|
||||||
|
case bool:
|
||||||
|
return t, nil
|
||||||
|
case string:
|
||||||
|
return t != "", nil
|
||||||
|
case int:
|
||||||
|
return t != 0, nil
|
||||||
|
default:
|
||||||
|
return false, errNotABool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIntStrict returns int value of the parameter if the parameter is integer.
|
||||||
|
func (p *Param) GetIntStrict() (int, error) {
|
||||||
|
if p == nil {
|
||||||
|
return 0, errMissingParameter
|
||||||
|
}
|
||||||
|
if p.IsNull() {
|
||||||
|
return 0, errNotAnInt
|
||||||
|
}
|
||||||
|
if p.cache == nil {
|
||||||
|
var i int
|
||||||
|
err := json.Unmarshal(p.RawMessage, &i)
|
||||||
|
if err != nil {
|
||||||
|
return i, errNotAnInt
|
||||||
|
}
|
||||||
|
p.cache = i
|
||||||
|
}
|
||||||
|
if i, ok := p.cache.(int); ok {
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
return 0, errNotAnInt
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInt returns int value of the parameter or tries to cast parameter to an int value.
|
||||||
func (p *Param) GetInt() (int, error) {
|
func (p *Param) GetInt() (int, error) {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return 0, errMissingParameter
|
return 0, errMissingParameter
|
||||||
}
|
}
|
||||||
i, ok := p.Value.(int)
|
if p.IsNull() {
|
||||||
if ok {
|
return 0, errNotAnInt
|
||||||
return i, nil
|
}
|
||||||
} else if s, ok := p.Value.(string); ok {
|
if p.cache == nil {
|
||||||
return strconv.Atoi(s)
|
var i int
|
||||||
|
err := json.Unmarshal(p.RawMessage, &i)
|
||||||
|
if err == nil {
|
||||||
|
p.cache = i
|
||||||
|
} else {
|
||||||
|
var s string
|
||||||
|
err = json.Unmarshal(p.RawMessage, &s)
|
||||||
|
if err == nil {
|
||||||
|
p.cache = s
|
||||||
|
} else {
|
||||||
|
var b bool
|
||||||
|
err = json.Unmarshal(p.RawMessage, &b)
|
||||||
|
if err == nil {
|
||||||
|
p.cache = b
|
||||||
|
} else {
|
||||||
|
return 0, errNotAnInt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch t := p.cache.(type) {
|
||||||
|
case int:
|
||||||
|
return t, nil
|
||||||
|
case string:
|
||||||
|
return strconv.Atoi(t)
|
||||||
|
case bool:
|
||||||
|
if t {
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
return 0, nil
|
||||||
|
default:
|
||||||
|
return 0, errNotAnInt
|
||||||
}
|
}
|
||||||
return 0, errors.New("not an integer")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetArray returns a slice of Params stored in the parameter.
|
// GetArray returns a slice of Params stored in the parameter.
|
||||||
|
@ -133,22 +273,21 @@ func (p *Param) GetArray() ([]Param, error) {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return nil, errMissingParameter
|
return nil, errMissingParameter
|
||||||
}
|
}
|
||||||
a, ok := p.Value.([]Param)
|
if p.IsNull() {
|
||||||
if ok {
|
return nil, errNotAnArray
|
||||||
return a, nil
|
|
||||||
}
|
}
|
||||||
raw, ok := p.Value.(json.RawMessage)
|
if p.cache == nil {
|
||||||
if !ok {
|
a := []Param{}
|
||||||
return nil, errors.New("not an array")
|
err := json.Unmarshal(p.RawMessage, &a)
|
||||||
}
|
|
||||||
|
|
||||||
a = []Param{}
|
|
||||||
err := json.Unmarshal(raw, &a)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("not an array")
|
return nil, errNotAnArray
|
||||||
}
|
}
|
||||||
p.Value = a
|
p.cache = a
|
||||||
|
}
|
||||||
|
if a, ok := p.cache.([]Param); ok {
|
||||||
return a, nil
|
return a, nil
|
||||||
|
}
|
||||||
|
return nil, errNotAnArray
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUint256 returns Uint256 value of the parameter.
|
// GetUint256 returns Uint256 value of the parameter.
|
||||||
|
@ -167,11 +306,8 @@ func (p *Param) GetUint160FromHex() (util.Uint160, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
}
|
}
|
||||||
if len(s) == 2*util.Uint160Size+2 && s[0] == '0' && s[1] == 'x' {
|
|
||||||
s = s[2:]
|
|
||||||
}
|
|
||||||
|
|
||||||
return util.Uint160DecodeStringLE(s)
|
return util.Uint160DecodeStringLE(strings.TrimPrefix(s, "0x"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUint160FromAddress returns Uint160 value of the parameter that was
|
// GetUint160FromAddress returns Uint160 value of the parameter that was
|
||||||
|
@ -200,20 +336,10 @@ func (p *Param) GetFuncParam() (FuncParam, error) {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return FuncParam{}, errMissingParameter
|
return FuncParam{}, errMissingParameter
|
||||||
}
|
}
|
||||||
fp, ok := p.Value.(FuncParam)
|
// This one doesn't need to be cached, it's used only once.
|
||||||
if ok {
|
fp := FuncParam{}
|
||||||
return fp, nil
|
err := json.Unmarshal(p.RawMessage, &fp)
|
||||||
}
|
|
||||||
raw, ok := p.Value.(json.RawMessage)
|
|
||||||
if !ok {
|
|
||||||
return FuncParam{}, errors.New("not a function parameter")
|
|
||||||
}
|
|
||||||
err := json.Unmarshal(raw, &fp)
|
|
||||||
if err != nil {
|
|
||||||
return fp, err
|
return fp, err
|
||||||
}
|
|
||||||
p.Value = fp
|
|
||||||
return fp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBytesHex returns []byte value of the parameter if
|
// GetBytesHex returns []byte value of the parameter if
|
||||||
|
@ -240,25 +366,20 @@ func (p *Param) GetBytesBase64() ([]byte, error) {
|
||||||
|
|
||||||
// GetSignerWithWitness returns SignerWithWitness value of the parameter.
|
// GetSignerWithWitness returns SignerWithWitness value of the parameter.
|
||||||
func (p *Param) GetSignerWithWitness() (SignerWithWitness, error) {
|
func (p *Param) GetSignerWithWitness() (SignerWithWitness, error) {
|
||||||
c, ok := p.Value.(SignerWithWitness)
|
// This one doesn't need to be cached, it's used only once.
|
||||||
if ok {
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
raw, ok := p.Value.(json.RawMessage)
|
|
||||||
if !ok {
|
|
||||||
return SignerWithWitness{}, errors.New("not a signer")
|
|
||||||
}
|
|
||||||
aux := new(signerWithWitnessAux)
|
aux := new(signerWithWitnessAux)
|
||||||
err := json.Unmarshal(raw, aux)
|
err := json.Unmarshal(p.RawMessage, aux)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return SignerWithWitness{}, errors.New("not a signer")
|
return SignerWithWitness{}, fmt.Errorf("not a signer: %w", err)
|
||||||
}
|
}
|
||||||
accParam := Param{StringT, aux.Account}
|
acc, err := util.Uint160DecodeStringLE(strings.TrimPrefix(aux.Account, "0x"))
|
||||||
acc, err := accParam.GetUint160FromAddressOrHex()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return SignerWithWitness{}, errors.New("not a signer")
|
acc, err = address.StringToUint160(aux.Account)
|
||||||
}
|
}
|
||||||
c = SignerWithWitness{
|
if err != nil {
|
||||||
|
return SignerWithWitness{}, fmt.Errorf("not a signer: %w", err)
|
||||||
|
}
|
||||||
|
c := SignerWithWitness{
|
||||||
Signer: transaction.Signer{
|
Signer: transaction.Signer{
|
||||||
Account: acc,
|
Account: acc,
|
||||||
Scopes: aux.Scopes,
|
Scopes: aux.Scopes,
|
||||||
|
@ -270,7 +391,6 @@ func (p *Param) GetSignerWithWitness() (SignerWithWitness, error) {
|
||||||
VerificationScript: aux.VerificationScript,
|
VerificationScript: aux.VerificationScript,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
p.Value = c
|
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,48 +429,9 @@ func (p Param) GetSignersWithWitnesses() ([]transaction.Signer, []transaction.Wi
|
||||||
return signers, witnesses, nil
|
return signers, witnesses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements json.Unmarshaler interface.
|
// IsNull returns whether parameter represents JSON nil value.
|
||||||
func (p *Param) UnmarshalJSON(data []byte) error {
|
func (p *Param) IsNull() bool {
|
||||||
r := bytes.NewReader(data)
|
return bytes.Equal(p.RawMessage, jsonNullBytes)
|
||||||
jd := json.NewDecoder(r)
|
|
||||||
jd.UseNumber()
|
|
||||||
tok, err := jd.Token()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
switch t := tok.(type) {
|
|
||||||
case json.Delim:
|
|
||||||
if t == json.Delim('[') {
|
|
||||||
var arr []Param
|
|
||||||
err := json.Unmarshal(data, &arr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
p.Type = ArrayT
|
|
||||||
p.Value = arr
|
|
||||||
} else {
|
|
||||||
p.Type = defaultT
|
|
||||||
p.Value = json.RawMessage(data)
|
|
||||||
}
|
|
||||||
case bool:
|
|
||||||
p.Type = BooleanT
|
|
||||||
p.Value = t
|
|
||||||
case float64: // unexpected because of `UseNumber`.
|
|
||||||
panic("unexpected")
|
|
||||||
case json.Number:
|
|
||||||
value, err := strconv.Atoi(string(t))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
p.Type = NumberT
|
|
||||||
p.Value = value
|
|
||||||
case string:
|
|
||||||
p.Type = StringT
|
|
||||||
p.Value = t
|
|
||||||
default: // null
|
|
||||||
p.Type = defaultT
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// signerWithWitnessAux is an auxiluary struct for JSON marshalling. We need it because of
|
// signerWithWitnessAux is an auxiluary struct for JSON marshalling. We need it because of
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
@ -15,66 +16,178 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParam_UnmarshalJSON(t *testing.T) {
|
func TestParam_UnmarshalJSON(t *testing.T) {
|
||||||
msg := `["str1", 123, null, ["str2", 3], [{"type": "String", "value": "jajaja"}],
|
type testCase struct {
|
||||||
|
check func(t *testing.T, p *Param)
|
||||||
|
expectedRawMessage []byte
|
||||||
|
}
|
||||||
|
msg := `["123", 123, null, ["str2", 3], [{"type": "String", "value": "jajaja"}],
|
||||||
{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569"},
|
{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569"},
|
||||||
{"account": "NYxb4fSZVKAz8YsgaPK2WkT3KcAE9b3Vag", "scopes": "Global"},
|
{"account": "NYxb4fSZVKAz8YsgaPK2WkT3KcAE9b3Vag", "scopes": "Global"},
|
||||||
[{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", "scopes": "Global"}]]`
|
[{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", "scopes": "Global"}]]`
|
||||||
expected := Params{
|
expected := []testCase{
|
||||||
{
|
{
|
||||||
Type: StringT,
|
check: func(t *testing.T, p *Param) {
|
||||||
Value: "str1",
|
expectedS := "123"
|
||||||
|
actualS, err := p.GetStringStrict()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expectedS, actualS)
|
||||||
|
actualS, err = p.GetString()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expectedS, actualS)
|
||||||
|
|
||||||
|
expectedI := 123
|
||||||
|
_, err = p.GetIntStrict()
|
||||||
|
require.Error(t, err)
|
||||||
|
actualI, err := p.GetInt()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expectedI, actualI)
|
||||||
|
|
||||||
|
expectedB := true
|
||||||
|
_, err = p.GetBooleanStrict()
|
||||||
|
require.Error(t, err)
|
||||||
|
actualB, err := p.GetBoolean()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expectedB, actualB)
|
||||||
|
|
||||||
|
_, err = p.GetArray()
|
||||||
|
require.Error(t, err)
|
||||||
|
},
|
||||||
|
expectedRawMessage: []byte(`"123"`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: NumberT,
|
check: func(t *testing.T, p *Param) {
|
||||||
Value: 123,
|
expectedS := "123"
|
||||||
|
_, err := p.GetStringStrict()
|
||||||
|
require.Error(t, err)
|
||||||
|
actualS, err := p.GetString()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expectedS, actualS)
|
||||||
|
|
||||||
|
expectedI := 123
|
||||||
|
actualI, err := p.GetIntStrict()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expectedI, actualI)
|
||||||
|
actualI, err = p.GetInt()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expectedI, actualI)
|
||||||
|
|
||||||
|
expectedB := true
|
||||||
|
_, err = p.GetBooleanStrict()
|
||||||
|
require.Error(t, err)
|
||||||
|
actualB, err := p.GetBoolean()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expectedB, actualB)
|
||||||
|
|
||||||
|
_, err = p.GetArray()
|
||||||
|
require.Error(t, err)
|
||||||
|
},
|
||||||
|
expectedRawMessage: []byte(`123`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: defaultT,
|
check: func(t *testing.T, p *Param) {
|
||||||
|
_, err := p.GetStringStrict()
|
||||||
|
require.Error(t, err)
|
||||||
|
_, err = p.GetString()
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
_, err = p.GetIntStrict()
|
||||||
|
require.Error(t, err)
|
||||||
|
_, err = p.GetInt()
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
_, err = p.GetBooleanStrict()
|
||||||
|
require.Error(t, err)
|
||||||
|
_, err = p.GetBoolean()
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
_, err = p.GetArray()
|
||||||
|
require.Error(t, err)
|
||||||
|
},
|
||||||
|
expectedRawMessage: []byte(`null`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: ArrayT,
|
check: func(t *testing.T, p *Param) {
|
||||||
Value: []Param{
|
_, err := p.GetStringStrict()
|
||||||
{
|
require.Error(t, err)
|
||||||
Type: StringT,
|
_, err = p.GetString()
|
||||||
Value: "str2",
|
require.Error(t, err)
|
||||||
|
|
||||||
|
_, err = p.GetIntStrict()
|
||||||
|
require.Error(t, err)
|
||||||
|
_, err = p.GetInt()
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
_, err = p.GetBooleanStrict()
|
||||||
|
require.Error(t, err)
|
||||||
|
_, err = p.GetBoolean()
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
a, err := p.GetArray()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, []Param{
|
||||||
|
{RawMessage: json.RawMessage(`"str2"`)},
|
||||||
|
{RawMessage: json.RawMessage(`3`)},
|
||||||
|
}, a)
|
||||||
|
},
|
||||||
|
expectedRawMessage: []byte(`["str2", 3]`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: NumberT,
|
check: func(t *testing.T, p *Param) {
|
||||||
Value: 3,
|
a, err := p.GetArray()
|
||||||
},
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(a))
|
||||||
|
fp, err := a[0].GetFuncParam()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, smartcontract.StringType, fp.Type)
|
||||||
|
strVal, err := fp.Value.GetStringStrict()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "jajaja", strVal)
|
||||||
},
|
},
|
||||||
|
expectedRawMessage: []byte(`[{"type": "String", "value": "jajaja"}]`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: ArrayT,
|
check: func(t *testing.T, p *Param) {
|
||||||
Value: []Param{
|
actual, err := p.GetSignerWithWitness()
|
||||||
{
|
require.NoError(t, err)
|
||||||
Type: defaultT,
|
expectedAcc, err := util.Uint160DecodeStringLE("cadb3dc2faa3ef14a13b619c9a43124755aa2569")
|
||||||
Value: json.RawMessage(`{"type": "String", "value": "jajaja"}`),
|
require.NoError(t, err)
|
||||||
},
|
require.Equal(t, SignerWithWitness{Signer: transaction.Signer{Account: expectedAcc}}, actual)
|
||||||
},
|
},
|
||||||
|
expectedRawMessage: []byte(`{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569"}`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: defaultT,
|
check: func(t *testing.T, p *Param) {
|
||||||
Value: json.RawMessage(`{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569"}`),
|
actual, err := p.GetSignerWithWitness()
|
||||||
|
require.NoError(t, err)
|
||||||
|
expectedAcc, err := address.StringToUint160("NYxb4fSZVKAz8YsgaPK2WkT3KcAE9b3Vag")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, SignerWithWitness{Signer: transaction.Signer{Account: expectedAcc, Scopes: transaction.Global}}, actual)
|
||||||
|
},
|
||||||
|
expectedRawMessage: []byte(`{"account": "NYxb4fSZVKAz8YsgaPK2WkT3KcAE9b3Vag", "scopes": "Global"}`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: defaultT,
|
check: func(t *testing.T, p *Param) {
|
||||||
Value: json.RawMessage(`{"account": "NYxb4fSZVKAz8YsgaPK2WkT3KcAE9b3Vag", "scopes": "Global"}`),
|
actualSigs, actualWtns, err := p.GetSignersWithWitnesses()
|
||||||
},
|
require.NoError(t, err)
|
||||||
{
|
require.Equal(t, 1, len(actualSigs))
|
||||||
Type: ArrayT,
|
require.Equal(t, 1, len(actualWtns))
|
||||||
Value: []Param{
|
expectedAcc, err := util.Uint160DecodeStringLE("cadb3dc2faa3ef14a13b619c9a43124755aa2569")
|
||||||
{
|
require.NoError(t, err)
|
||||||
Type: defaultT,
|
require.Equal(t, transaction.Signer{Account: expectedAcc, Scopes: transaction.Global}, actualSigs[0])
|
||||||
Value: json.RawMessage(`{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", "scopes": "Global"}`),
|
require.Equal(t, transaction.Witness{}, actualWtns[0])
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
expectedRawMessage: []byte(`[{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", "scopes": "Global"}]`),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var ps Params
|
var ps Params
|
||||||
require.NoError(t, json.Unmarshal([]byte(msg), &ps))
|
require.NoError(t, json.Unmarshal([]byte(msg), &ps))
|
||||||
require.Equal(t, expected, ps)
|
require.Equal(t, len(expected), len(ps))
|
||||||
|
for i, tc := range expected {
|
||||||
|
require.NotNil(t, ps[i])
|
||||||
|
require.Equal(t, json.RawMessage(tc.expectedRawMessage), ps[i].RawMessage, i)
|
||||||
|
tc.check(t, &ps[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetWitness(t *testing.T) {
|
func TestGetWitness(t *testing.T) {
|
||||||
|
@ -108,11 +221,10 @@ func TestGetWitness(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
p := Param{Value: json.RawMessage(tc.raw)}
|
p := Param{RawMessage: json.RawMessage(tc.raw)}
|
||||||
actual, err := p.GetSignerWithWitness()
|
actual, err := p.GetSignerWithWitness()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, tc.expected, actual)
|
require.Equal(t, tc.expected, actual)
|
||||||
require.Equal(t, tc.expected, p.Value)
|
|
||||||
|
|
||||||
actual, err = p.GetSignerWithWitness() // valid second invocation.
|
actual, err = p.GetSignerWithWitness() // valid second invocation.
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -120,57 +232,24 @@ func TestGetWitness(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParamGetString(t *testing.T) {
|
|
||||||
p := Param{StringT, "jajaja"}
|
|
||||||
str, err := p.GetString()
|
|
||||||
assert.Equal(t, "jajaja", str)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
p = Param{StringT, int(100500)}
|
|
||||||
_, err = p.GetString()
|
|
||||||
require.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParamGetInt(t *testing.T) {
|
|
||||||
p := Param{NumberT, int(100500)}
|
|
||||||
i, err := p.GetInt()
|
|
||||||
assert.Equal(t, 100500, i)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
p = Param{NumberT, "jajaja"}
|
|
||||||
_, err = p.GetInt()
|
|
||||||
require.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParamGetArray(t *testing.T) {
|
|
||||||
p := Param{ArrayT, []Param{{NumberT, 42}}}
|
|
||||||
a, err := p.GetArray()
|
|
||||||
assert.Equal(t, []Param{{NumberT, 42}}, a)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
p = Param{ArrayT, 42}
|
|
||||||
_, err = p.GetArray()
|
|
||||||
require.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParamGetUint256(t *testing.T) {
|
func TestParamGetUint256(t *testing.T) {
|
||||||
gas := "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"
|
gas := "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"
|
||||||
u256, _ := util.Uint256DecodeStringLE(gas)
|
u256, _ := util.Uint256DecodeStringLE(gas)
|
||||||
p := Param{StringT, gas}
|
p := Param{RawMessage: []byte(fmt.Sprintf(`"%s"`, gas))}
|
||||||
u, err := p.GetUint256()
|
u, err := p.GetUint256()
|
||||||
assert.Equal(t, u256, u)
|
assert.Equal(t, u256, u)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
p = Param{StringT, "0x" + gas}
|
p = Param{RawMessage: []byte(fmt.Sprintf(`"0x%s"`, gas))}
|
||||||
u, err = p.GetUint256()
|
u, err = p.GetUint256()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, u256, u)
|
assert.Equal(t, u256, u)
|
||||||
|
|
||||||
p = Param{StringT, 42}
|
p = Param{RawMessage: []byte(`42`)}
|
||||||
_, err = p.GetUint256()
|
_, err = p.GetUint256()
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
|
|
||||||
p = Param{StringT, "qq2c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"}
|
p = Param{RawMessage: []byte(`"qq2c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"`)}
|
||||||
_, err = p.GetUint256()
|
_, err = p.GetUint256()
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
@ -178,16 +257,16 @@ func TestParamGetUint256(t *testing.T) {
|
||||||
func TestParamGetUint160FromHex(t *testing.T) {
|
func TestParamGetUint160FromHex(t *testing.T) {
|
||||||
in := "50befd26fdf6e4d957c11e078b24ebce6291456f"
|
in := "50befd26fdf6e4d957c11e078b24ebce6291456f"
|
||||||
u160, _ := util.Uint160DecodeStringLE(in)
|
u160, _ := util.Uint160DecodeStringLE(in)
|
||||||
p := Param{StringT, in}
|
p := Param{RawMessage: []byte(fmt.Sprintf(`"%s"`, in))}
|
||||||
u, err := p.GetUint160FromHex()
|
u, err := p.GetUint160FromHex()
|
||||||
assert.Equal(t, u160, u)
|
assert.Equal(t, u160, u)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
p = Param{StringT, 42}
|
p = Param{RawMessage: []byte(`42`)}
|
||||||
_, err = p.GetUint160FromHex()
|
_, err = p.GetUint160FromHex()
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
|
|
||||||
p = Param{StringT, "wwbefd26fdf6e4d957c11e078b24ebce6291456f"}
|
p = Param{RawMessage: []byte(`"wwbefd26fdf6e4d957c11e078b24ebce6291456f"`)}
|
||||||
_, err = p.GetUint160FromHex()
|
_, err = p.GetUint160FromHex()
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
@ -195,16 +274,16 @@ func TestParamGetUint160FromHex(t *testing.T) {
|
||||||
func TestParamGetUint160FromAddress(t *testing.T) {
|
func TestParamGetUint160FromAddress(t *testing.T) {
|
||||||
in := "NPAsqZkx9WhNd4P72uhZxBhLinSuNkxfB8"
|
in := "NPAsqZkx9WhNd4P72uhZxBhLinSuNkxfB8"
|
||||||
u160, _ := address.StringToUint160(in)
|
u160, _ := address.StringToUint160(in)
|
||||||
p := Param{StringT, in}
|
p := Param{RawMessage: []byte(fmt.Sprintf(`"%s"`, in))}
|
||||||
u, err := p.GetUint160FromAddress()
|
u, err := p.GetUint160FromAddress()
|
||||||
assert.Equal(t, u160, u)
|
assert.Equal(t, u160, u)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
p = Param{StringT, 42}
|
p = Param{RawMessage: []byte(`42`)}
|
||||||
_, err = p.GetUint160FromAddress()
|
_, err = p.GetUint160FromAddress()
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
|
|
||||||
p = Param{StringT, "QK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y"}
|
p = Param{RawMessage: []byte(`"QK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y"`)}
|
||||||
_, err = p.GetUint160FromAddress()
|
_, err = p.GetUint160FromAddress()
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
@ -214,14 +293,14 @@ func TestParam_GetUint160FromAddressOrHex(t *testing.T) {
|
||||||
inHex, _ := address.StringToUint160(in)
|
inHex, _ := address.StringToUint160(in)
|
||||||
|
|
||||||
t.Run("Address", func(t *testing.T) {
|
t.Run("Address", func(t *testing.T) {
|
||||||
p := Param{StringT, in}
|
p := Param{RawMessage: []byte(fmt.Sprintf(`"%s"`, in))}
|
||||||
u, err := p.GetUint160FromAddressOrHex()
|
u, err := p.GetUint160FromAddressOrHex()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, inHex, u)
|
require.Equal(t, inHex, u)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Hex", func(t *testing.T) {
|
t.Run("Hex", func(t *testing.T) {
|
||||||
p := Param{StringT, inHex.StringLE()}
|
p := Param{RawMessage: []byte(fmt.Sprintf(`"%s"`, inHex.StringLE()))}
|
||||||
u, err := p.GetUint160FromAddressOrHex()
|
u, err := p.GetUint160FromAddressOrHex()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, inHex, u)
|
require.Equal(t, inHex, u)
|
||||||
|
@ -231,20 +310,14 @@ func TestParam_GetUint160FromAddressOrHex(t *testing.T) {
|
||||||
func TestParamGetFuncParam(t *testing.T) {
|
func TestParamGetFuncParam(t *testing.T) {
|
||||||
fp := FuncParam{
|
fp := FuncParam{
|
||||||
Type: smartcontract.StringType,
|
Type: smartcontract.StringType,
|
||||||
Value: Param{
|
Value: Param{RawMessage: []byte(`"jajaja"`)},
|
||||||
Type: StringT,
|
|
||||||
Value: "jajaja",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
p := Param{
|
|
||||||
Type: FuncParamT,
|
|
||||||
Value: fp,
|
|
||||||
}
|
}
|
||||||
|
p := Param{RawMessage: []byte(`{"type": "String", "value": "jajaja"}`)}
|
||||||
newfp, err := p.GetFuncParam()
|
newfp, err := p.GetFuncParam()
|
||||||
assert.Equal(t, fp, newfp)
|
assert.Equal(t, fp, newfp)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
p = Param{FuncParamT, 42}
|
p = Param{RawMessage: []byte(`42`)}
|
||||||
_, err = p.GetFuncParam()
|
_, err = p.GetFuncParam()
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
@ -252,16 +325,17 @@ func TestParamGetFuncParam(t *testing.T) {
|
||||||
func TestParamGetBytesHex(t *testing.T) {
|
func TestParamGetBytesHex(t *testing.T) {
|
||||||
in := "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"
|
in := "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"
|
||||||
inb, _ := hex.DecodeString(in)
|
inb, _ := hex.DecodeString(in)
|
||||||
p := Param{StringT, in}
|
p := Param{RawMessage: []byte(fmt.Sprintf(`"%s"`, in))}
|
||||||
bh, err := p.GetBytesHex()
|
bh, err := p.GetBytesHex()
|
||||||
assert.Equal(t, inb, bh)
|
assert.Equal(t, inb, bh)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
p = Param{StringT, 42}
|
p = Param{RawMessage: []byte(`42`)}
|
||||||
_, err = p.GetBytesHex()
|
h, err := p.GetBytesHex()
|
||||||
require.NotNil(t, err)
|
assert.Equal(t, []byte{0x42}, h) // that's the way how C# works: 42 -> "42" -> []byte{0x42}
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
p = Param{StringT, "qq2c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"}
|
p = Param{RawMessage: []byte(`"qq2c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"`)}
|
||||||
_, err = p.GetBytesHex()
|
_, err = p.GetBytesHex()
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
@ -270,16 +344,16 @@ func TestParamGetBytesBase64(t *testing.T) {
|
||||||
in := "Aj4A8DoW6HB84EXrQu6A05JFFUHuUQ3BjhyL77rFTXQm"
|
in := "Aj4A8DoW6HB84EXrQu6A05JFFUHuUQ3BjhyL77rFTXQm"
|
||||||
inb, err := base64.StdEncoding.DecodeString(in)
|
inb, err := base64.StdEncoding.DecodeString(in)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
p := Param{StringT, in}
|
p := Param{RawMessage: []byte(fmt.Sprintf(`"%s"`, in))}
|
||||||
bh, err := p.GetBytesBase64()
|
bh, err := p.GetBytesBase64()
|
||||||
assert.Equal(t, inb, bh)
|
assert.Equal(t, inb, bh)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
p = Param{StringT, 42}
|
p = Param{RawMessage: []byte(`42`)}
|
||||||
_, err = p.GetBytesBase64()
|
_, err = p.GetBytesBase64()
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
|
|
||||||
p = Param{StringT, "@j4A8DoW6HB84EXrQu6A05JFFUHuUQ3BjhyL77rFTXQm"}
|
p = Param{RawMessage: []byte("@j4A8DoW6HB84EXrQu6A05JFFUHuUQ3BjhyL77rFTXQm")}
|
||||||
_, err = p.GetBytesBase64()
|
_, err = p.GetBytesBase64()
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
@ -296,12 +370,12 @@ func TestParamGetSigner(t *testing.T) {
|
||||||
VerificationScript: []byte{1, 2, 3},
|
VerificationScript: []byte{1, 2, 3},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
p := Param{Type: SignerWithWitnessT, Value: c}
|
p := Param{RawMessage: []byte(`{"account": "0x0000000000000000000000000000000004030201", "scopes": "Global", "invocation": "AQID", "verification": "AQID"}`)}
|
||||||
actual, err := p.GetSignerWithWitness()
|
actual, err := p.GetSignerWithWitness()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, c, actual)
|
require.Equal(t, c, actual)
|
||||||
|
|
||||||
p = Param{Type: SignerWithWitnessT, Value: `{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", "scopes": 0}`}
|
p = Param{RawMessage: []byte(`"not a signer"`)}
|
||||||
_, err = p.GetSignerWithWitness()
|
_, err = p.GetSignerWithWitness()
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
@ -310,10 +384,7 @@ func TestParamGetSigners(t *testing.T) {
|
||||||
u1 := util.Uint160{1, 2, 3, 4}
|
u1 := util.Uint160{1, 2, 3, 4}
|
||||||
u2 := util.Uint160{5, 6, 7, 8}
|
u2 := util.Uint160{5, 6, 7, 8}
|
||||||
t.Run("from hashes", func(t *testing.T) {
|
t.Run("from hashes", func(t *testing.T) {
|
||||||
p := Param{ArrayT, []Param{
|
p := Param{RawMessage: []byte(fmt.Sprintf(`["%s", "%s"]`, u1.StringLE(), u2.StringLE()))}
|
||||||
{Type: StringT, Value: u1.StringLE()},
|
|
||||||
{Type: StringT, Value: u2.StringLE()},
|
|
||||||
}}
|
|
||||||
actual, _, err := p.GetSignersWithWitnesses()
|
actual, _, err := p.GetSignersWithWitnesses()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 2, len(actual))
|
require.Equal(t, 2, len(actual))
|
||||||
|
@ -321,56 +392,8 @@ func TestParamGetSigners(t *testing.T) {
|
||||||
require.True(t, u2.Equals(actual[1].Account))
|
require.True(t, u2.Equals(actual[1].Account))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("from signers", func(t *testing.T) {
|
|
||||||
c1 := SignerWithWitness{
|
|
||||||
Signer: transaction.Signer{
|
|
||||||
Account: u1,
|
|
||||||
Scopes: transaction.Global,
|
|
||||||
},
|
|
||||||
Witness: transaction.Witness{
|
|
||||||
InvocationScript: []byte{1, 2, 3},
|
|
||||||
VerificationScript: []byte{1, 2, 3},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
c2 := SignerWithWitness{
|
|
||||||
Signer: transaction.Signer{
|
|
||||||
Account: u2,
|
|
||||||
Scopes: transaction.CustomContracts,
|
|
||||||
AllowedContracts: []util.Uint160{
|
|
||||||
{1, 2, 3},
|
|
||||||
{4, 5, 6},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
p := Param{ArrayT, []Param{
|
|
||||||
{Type: SignerWithWitnessT, Value: c1},
|
|
||||||
{Type: SignerWithWitnessT, Value: c2},
|
|
||||||
}}
|
|
||||||
actualS, actualW, err := p.GetSignersWithWitnesses()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, 2, len(actualS))
|
|
||||||
require.Equal(t, transaction.Signer{
|
|
||||||
Account: c1.Account,
|
|
||||||
Scopes: c1.Scopes,
|
|
||||||
}, actualS[0])
|
|
||||||
require.Equal(t, transaction.Signer{
|
|
||||||
Account: c2.Account,
|
|
||||||
Scopes: c2.Scopes,
|
|
||||||
AllowedContracts: c2.AllowedContracts,
|
|
||||||
}, actualS[1])
|
|
||||||
require.EqualValues(t, 2, len(actualW))
|
|
||||||
require.EqualValues(t, transaction.Witness{
|
|
||||||
InvocationScript: c1.InvocationScript,
|
|
||||||
VerificationScript: c1.VerificationScript,
|
|
||||||
}, actualW[0])
|
|
||||||
require.Equal(t, transaction.Witness{}, actualW[1])
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("bad format", func(t *testing.T) {
|
t.Run("bad format", func(t *testing.T) {
|
||||||
p := Param{ArrayT, []Param{
|
p := Param{RawMessage: []byte(`"not a signer"`)}
|
||||||
{Type: StringT, Value: u1.StringLE()},
|
|
||||||
{Type: StringT, Value: "bla"},
|
|
||||||
}}
|
|
||||||
_, _, err := p.GetSignersWithWitnesses()
|
_, _, err := p.GetSignersWithWitnesses()
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
|
|
|
@ -17,15 +17,6 @@ func (p Params) Value(index int) *Param {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValueWithType returns the param struct at the given index if it
|
|
||||||
// exists and matches the given type.
|
|
||||||
func (p Params) ValueWithType(index int, valType paramType) *Param {
|
|
||||||
if val := p.Value(index); val != nil && val.Type == valType {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Params) String() string {
|
func (p Params) String() string {
|
||||||
return fmt.Sprintf("%v", []Param(p))
|
return fmt.Sprintf("%v", []Param(p))
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,8 +70,8 @@ func ExpandArrayIntoScript(script *io.BinWriter, slice []Param) error {
|
||||||
}
|
}
|
||||||
emit.Int(script, int64(val))
|
emit.Int(script, int64(val))
|
||||||
case smartcontract.BoolType:
|
case smartcontract.BoolType:
|
||||||
val, ok := fp.Value.Value.(bool)
|
val, err := fp.Value.GetBoolean() // not GetBooleanStrict(), because that's the way C# code works
|
||||||
if !ok {
|
if err != nil {
|
||||||
return errors.New("not a bool")
|
return errors.New("not a bool")
|
||||||
}
|
}
|
||||||
if val {
|
if val {
|
||||||
|
@ -90,6 +90,10 @@ func ExpandArrayIntoScript(script *io.BinWriter, slice []Param) error {
|
||||||
}
|
}
|
||||||
emit.Int(script, int64(len(val)))
|
emit.Int(script, int64(len(val)))
|
||||||
emit.Opcodes(script, opcode.PACK)
|
emit.Opcodes(script, opcode.PACK)
|
||||||
|
case smartcontract.AnyType:
|
||||||
|
if fp.Value.IsNull() {
|
||||||
|
emit.Opcodes(script, opcode.PUSHNULL)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("parameter type %v is not supported", fp.Type)
|
return fmt.Errorf("parameter type %v is not supported", fp.Type)
|
||||||
}
|
}
|
||||||
|
@ -102,29 +106,21 @@ func ExpandArrayIntoScript(script *io.BinWriter, slice []Param) error {
|
||||||
func CreateFunctionInvocationScript(contract util.Uint160, method string, params Params) ([]byte, error) {
|
func CreateFunctionInvocationScript(contract util.Uint160, method string, params Params) ([]byte, error) {
|
||||||
script := io.NewBufBinWriter()
|
script := io.NewBufBinWriter()
|
||||||
for i := len(params) - 1; i >= 0; i-- {
|
for i := len(params) - 1; i >= 0; i-- {
|
||||||
switch params[i].Type {
|
if slice, err := params[i].GetArray(); err == nil {
|
||||||
case StringT:
|
|
||||||
emit.String(script.BinWriter, params[i].String())
|
|
||||||
case NumberT:
|
|
||||||
num, err := params[i].GetInt()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
emit.String(script.BinWriter, strconv.Itoa(num))
|
|
||||||
case BooleanT:
|
|
||||||
val := params[i].GetBoolean()
|
|
||||||
emit.Bool(script.BinWriter, val)
|
|
||||||
case ArrayT:
|
|
||||||
slice, err := params[i].GetArray()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = ExpandArrayIntoScript(script.BinWriter, slice)
|
err = ExpandArrayIntoScript(script.BinWriter, slice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
emit.Int(script.BinWriter, int64(len(slice)))
|
emit.Int(script.BinWriter, int64(len(slice)))
|
||||||
emit.Opcodes(script.BinWriter, opcode.PACK)
|
emit.Opcodes(script.BinWriter, opcode.PACK)
|
||||||
|
} else if s, err := params[i].GetStringStrict(); err == nil {
|
||||||
|
emit.String(script.BinWriter, s)
|
||||||
|
} else if n, err := params[i].GetIntStrict(); err == nil {
|
||||||
|
emit.String(script.BinWriter, strconv.Itoa(n))
|
||||||
|
} else if b, err := params[i].GetBooleanStrict(); err == nil {
|
||||||
|
emit.Bool(script.BinWriter, b)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("failed to convert parmeter %s to script parameter", params[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(params) == 0 {
|
if len(params) == 0 {
|
||||||
|
|
|
@ -2,10 +2,10 @@ package request
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -13,7 +13,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInvocationScriptCreationGood(t *testing.T) {
|
func TestInvocationScriptCreationGood(t *testing.T) {
|
||||||
p := Param{Type: StringT, Value: "50befd26fdf6e4d957c11e078b24ebce6291456f"}
|
p := Param{RawMessage: []byte(`"50befd26fdf6e4d957c11e078b24ebce6291456f"`)}
|
||||||
contract, err := p.GetUint160FromHex()
|
contract, err := p.GetUint160FromHex()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
@ -21,49 +21,60 @@ func TestInvocationScriptCreationGood(t *testing.T) {
|
||||||
ps Params
|
ps Params
|
||||||
script string
|
script string
|
||||||
}{{
|
}{{
|
||||||
ps: Params{{Type: StringT, Value: "transfer"}},
|
ps: Params{{RawMessage: []byte(`"transfer"`)}},
|
||||||
script: "c21f0c087472616e736665720c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
script: "c21f0c087472616e736665720c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
}, {
|
}, {
|
||||||
ps: Params{{Type: NumberT, Value: 42}},
|
ps: Params{{RawMessage: []byte(`42`)}},
|
||||||
script: "c21f0c0234320c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
script: "c21f0c0234320c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
}, {
|
}, {
|
||||||
ps: Params{{Type: StringT, Value: "m"}, {Type: BooleanT, Value: true}},
|
ps: Params{{RawMessage: []byte(`"m"`)}, {RawMessage: []byte(`true`)}},
|
||||||
script: "11db201f0c016d0c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
script: "11db201f0c016d0c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
}, {
|
}, {
|
||||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{}}},
|
ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[]`)}},
|
||||||
script: "10c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
script: "10c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
}, {
|
}, {
|
||||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.ByteArrayType, Value: Param{Type: StringT, Value: "AwEtR+diEK7HO+Oas9GG4KQP6Nhr+j1Pq/2le6E7iPlq"}}}}}},
|
ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "ByteString", "value": "AwEtR+diEK7HO+Oas9GG4KQP6Nhr+j1Pq/2le6E7iPlq"}]`)}},
|
||||||
script: "0c2103012d47e76210aec73be39ab3d186e0a40fe8d86bfa3d4fabfda57ba13b88f96a11c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
script: "0c2103012d47e76210aec73be39ab3d186e0a40fe8d86bfa3d4fabfda57ba13b88f96a11c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
}, {
|
}, {
|
||||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.SignatureType, Value: Param{Type: StringT, Value: "4edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f"}}}}}},
|
ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Signature", "value": "4edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f"}]`)}},
|
||||||
script: "0c404edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f11c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
script: "0c404edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f11c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
}, {
|
}, {
|
||||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.StringType, Value: Param{Type: StringT, Value: "50befd26fdf6e4d957c11e078b24ebce6291456f"}}}}}},
|
ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "String", "value": "50befd26fdf6e4d957c11e078b24ebce6291456f"}]`)}},
|
||||||
script: "0c283530626566643236666466366534643935376331316530373862323465626365363239313435366611c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
script: "0c283530626566643236666466366534643935376331316530373862323465626365363239313435366611c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
}, {
|
}, {
|
||||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.Hash160Type, Value: Param{Type: StringT, Value: "50befd26fdf6e4d957c11e078b24ebce6291456f"}}}}}},
|
ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Hash160", "value": "50befd26fdf6e4d957c11e078b24ebce6291456f"}]`)}},
|
||||||
script: "0c146f459162ceeb248b071ec157d9e4f6fd26fdbe5011c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
script: "0c146f459162ceeb248b071ec157d9e4f6fd26fdbe5011c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
}, {
|
}, {
|
||||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.Hash256Type, Value: Param{Type: StringT, Value: "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"}}}}}},
|
ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Hash256", "value": "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"}]`)}},
|
||||||
script: "0c20e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6011c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
script: "0c20e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6011c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
}, {
|
}, {
|
||||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.PublicKeyType, Value: Param{Type: StringT, Value: "03c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c1"}}}}}},
|
ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "PublicKey", "value": "03c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c1"}]`)}},
|
||||||
script: "0c2103c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c111c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
script: "0c2103c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c111c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
}, {
|
}, {
|
||||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.IntegerType, Value: Param{Type: NumberT, Value: 42}}}}}},
|
ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Integer", "value": 42}]`)}},
|
||||||
script: "002a11c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
script: "002a11c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
}, {
|
}, {
|
||||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.BoolType, Value: Param{Type: BooleanT, Value: true}}}}}},
|
ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Integer", "value": "42"}]`)}}, // C# code doesn't use strict type assertions for JSON-ised params
|
||||||
|
script: "002a11c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
|
}, {
|
||||||
|
ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Integer", "value": true}]`)}}, // C# code doesn't use strict type assertions for JSON-ised params
|
||||||
script: "1111c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
script: "1111c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
}, {
|
}, {
|
||||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.BoolType, Value: Param{Type: BooleanT, Value: false}}}}}},
|
ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Boolean", "value": true}]`)}},
|
||||||
|
script: "1111c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
|
}, {
|
||||||
|
ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Boolean", "value": false}]`)}},
|
||||||
script: "1011c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
script: "1011c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
|
}, {
|
||||||
|
ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Boolean", "value": "blah"}]`)}}, // C# code doesn't use strict type assertions for JSON-ised params
|
||||||
|
script: "1111c01f0c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||||
}}
|
}}
|
||||||
for _, ps := range paramScripts {
|
for i, ps := range paramScripts {
|
||||||
script, err := CreateFunctionInvocationScript(contract, ps.ps[0].String(), ps.ps[1:])
|
method, err := ps.ps[0].GetString()
|
||||||
|
require.NoError(t, err, fmt.Sprintf("testcase #%d", i))
|
||||||
|
script, err := CreateFunctionInvocationScript(contract, method, ps.ps[1:])
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, ps.script, hex.EncodeToString(script))
|
assert.Equal(t, ps.script, hex.EncodeToString(script), fmt.Sprintf("testcase #%d", i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,25 +82,18 @@ func TestInvocationScriptCreationBad(t *testing.T) {
|
||||||
contract := util.Uint160{}
|
contract := util.Uint160{}
|
||||||
|
|
||||||
var testParams = []Params{
|
var testParams = []Params{
|
||||||
{{Type: NumberT, Value: "qwerty"}},
|
{{RawMessage: []byte(`[{"type": "ByteArray", "value": "qwerty"}]`)}},
|
||||||
{{Type: ArrayT, Value: 42}},
|
{{RawMessage: []byte(`[{"type": "Signature", "value": "qwerty"}]`)}},
|
||||||
{{Type: ArrayT, Value: []Param{{Type: NumberT, Value: 42}}}},
|
{{RawMessage: []byte(`[{"type": "Hash160", "value": "qwerty"}]`)}},
|
||||||
{{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.ByteArrayType, Value: Param{Type: StringT, Value: "qwerty"}}}}}},
|
{{RawMessage: []byte(`[{"type": "Hash256", "value": "qwerty"}]`)}},
|
||||||
{{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.SignatureType, Value: Param{Type: StringT, Value: "qwerty"}}}}}},
|
{{RawMessage: []byte(`[{"type": "PublicKey", "value": 42}]`)}},
|
||||||
{{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.StringType, Value: Param{Type: NumberT, Value: 42}}}}}},
|
{{RawMessage: []byte(`[{"type": "PublicKey", "value": "qwerty"}]`)}},
|
||||||
{{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.Hash160Type, Value: Param{Type: StringT, Value: "qwerty"}}}}}},
|
{{RawMessage: []byte(`[{"type": "Integer", "value": "123q"}]`)}},
|
||||||
{{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.Hash256Type, Value: Param{Type: StringT, Value: "qwerty"}}}}}},
|
{{RawMessage: []byte(`[{"type": "Unknown"}]`)}},
|
||||||
{{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.PublicKeyType, Value: Param{Type: NumberT, Value: 42}}}}}},
|
|
||||||
{{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.PublicKeyType, Value: Param{Type: StringT, Value: "qwerty"}}}}}},
|
|
||||||
{{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.IntegerType, Value: Param{Type: StringT, Value: "qwerty"}}}}}},
|
|
||||||
{{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.IntegerType, Value: Param{Type: BooleanT, Value: true}}}}}},
|
|
||||||
{{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.BoolType, Value: Param{Type: NumberT, Value: 42}}}}}},
|
|
||||||
{{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.BoolType, Value: Param{Type: StringT, Value: "qwerty"}}}}}},
|
|
||||||
{{Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.UnknownType, Value: Param{}}}}}},
|
|
||||||
}
|
}
|
||||||
for _, ps := range testParams {
|
for i, ps := range testParams {
|
||||||
_, err := CreateFunctionInvocationScript(contract, "", ps)
|
_, err := CreateFunctionInvocationScript(contract, "", ps)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err, fmt.Sprintf("testcase #%d", i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,11 +103,11 @@ func TestExpandArrayIntoScript(t *testing.T) {
|
||||||
Expected []byte
|
Expected []byte
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Input: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.StringType, Value: Param{Value: "a"}}}},
|
Input: []Param{{RawMessage: []byte(`{"type": "String", "value": "a"}`)}},
|
||||||
Expected: []byte{byte(opcode.PUSHDATA1), 1, byte('a')},
|
Expected: []byte{byte(opcode.PUSHDATA1), 1, byte('a')},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.ArrayType, Value: Param{Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.StringType, Value: Param{Value: "a"}}}}}}}},
|
Input: []Param{{RawMessage: []byte(`{"type": "Array", "value": [{"type": "String", "value": "a"}]}`)}},
|
||||||
Expected: []byte{byte(opcode.PUSHDATA1), 1, byte('a'), byte(opcode.PUSH1), byte(opcode.PACK)},
|
Expected: []byte{byte(opcode.PUSHDATA1), 1, byte('a'), byte(opcode.PUSH1), byte(opcode.PACK)},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -115,10 +119,10 @@ func TestExpandArrayIntoScript(t *testing.T) {
|
||||||
}
|
}
|
||||||
errorCases := [][]Param{
|
errorCases := [][]Param{
|
||||||
{
|
{
|
||||||
{Type: FuncParamT, Value: FuncParam{Type: smartcontract.ArrayType, Value: Param{Value: "a"}}},
|
{RawMessage: []byte(`{"type": "Array", "value": "a"}`)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{Type: FuncParamT, Value: FuncParam{Type: smartcontract.ArrayType, Value: Param{Value: []Param{{Type: FuncParamT, Value: nil}}}}},
|
{RawMessage: []byte(`{"type": "Array", "value": null}`)},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, c := range errorCases {
|
for _, c := range errorCases {
|
||||||
|
|
|
@ -53,7 +53,7 @@ type Request struct {
|
||||||
type In struct {
|
type In struct {
|
||||||
JSONRPC string `json:"jsonrpc"`
|
JSONRPC string `json:"jsonrpc"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
RawParams json.RawMessage `json:"params,omitempty"`
|
RawParams []Param `json:"params,omitempty"`
|
||||||
RawID json.RawMessage `json:"id,omitempty"`
|
RawID json.RawMessage `json:"id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,16 +134,3 @@ func NewIn() *In {
|
||||||
JSONRPC: JSONRPCVersion,
|
JSONRPC: JSONRPCVersion,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Params takes a slice of any type and attempts to bind
|
|
||||||
// the params to it.
|
|
||||||
func (r *In) Params() (*Params, error) {
|
|
||||||
params := Params{}
|
|
||||||
|
|
||||||
err := json.Unmarshal(r.RawParams, ¶ms)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error parsing params: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ¶ms, nil
|
|
||||||
}
|
|
||||||
|
|
49
pkg/rpc/request/types_test.go
Normal file
49
pkg/rpc/request/types_test.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type readCloser struct {
|
||||||
|
io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (readCloser) Close() error { return nil }
|
||||||
|
|
||||||
|
func BenchmarkUnmarshal(b *testing.B) {
|
||||||
|
req := []byte(`{"jsonrpc":"2.0", "method":"invokefunction","params":["0x50befd26fdf6e4d957c11e078b24ebce6291456f", "someMethod", [{"type": "String", "value": "50befd26fdf6e4d957c11e078b24ebce6291456f"}, {"type": "Integer", "value": "42"}, {"type": "Boolean", "value": false}]]}`)
|
||||||
|
b.Run("single", func(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.Run("unmarshal", func(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
b.StopTimer()
|
||||||
|
in := new(In)
|
||||||
|
b.StartTimer()
|
||||||
|
err := json.Unmarshal(req, in)
|
||||||
|
if err != nil {
|
||||||
|
b.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("decode data", func(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
b.StopTimer()
|
||||||
|
r := NewRequest()
|
||||||
|
r.In = new(In)
|
||||||
|
rd := bytes.NewReader(req)
|
||||||
|
b.StartTimer()
|
||||||
|
err := r.DecodeData(readCloser{rd})
|
||||||
|
if err != nil {
|
||||||
|
b.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
|
@ -335,10 +335,7 @@ func (s *Server) handleIn(req *request.In, sub *subscriber) response.Abstract {
|
||||||
return s.packResponse(req, nil, response.NewInvalidParamsError("Problem parsing JSON", fmt.Errorf("invalid version, expected 2.0 got: '%s'", req.JSONRPC)))
|
return s.packResponse(req, nil, response.NewInvalidParamsError("Problem parsing JSON", fmt.Errorf("invalid version, expected 2.0 got: '%s'", req.JSONRPC)))
|
||||||
}
|
}
|
||||||
|
|
||||||
reqParams, err := req.Params()
|
reqParams := request.Params(req.RawParams)
|
||||||
if err != nil {
|
|
||||||
return s.packResponse(req, nil, response.NewInvalidParamsError("Problem parsing request parameters", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
s.log.Debug("processing rpc request",
|
s.log.Debug("processing rpc request",
|
||||||
zap.String("method", req.Method),
|
zap.String("method", req.Method),
|
||||||
|
@ -349,11 +346,11 @@ func (s *Server) handleIn(req *request.In, sub *subscriber) response.Abstract {
|
||||||
resErr = response.NewMethodNotFoundError(fmt.Sprintf("Method '%s' not supported", req.Method), nil)
|
resErr = response.NewMethodNotFoundError(fmt.Sprintf("Method '%s' not supported", req.Method), nil)
|
||||||
handler, ok := rpcHandlers[req.Method]
|
handler, ok := rpcHandlers[req.Method]
|
||||||
if ok {
|
if ok {
|
||||||
res, resErr = handler(s, *reqParams)
|
res, resErr = handler(s, reqParams)
|
||||||
} else if sub != nil {
|
} else if sub != nil {
|
||||||
handler, ok := rpcWsHandlers[req.Method]
|
handler, ok := rpcWsHandlers[req.Method]
|
||||||
if ok {
|
if ok {
|
||||||
res, resErr = handler(s, *reqParams, sub)
|
res, resErr = handler(s, reqParams, sub)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s.packResponse(req, res, resErr)
|
return s.packResponse(req, res, resErr)
|
||||||
|
@ -462,27 +459,20 @@ func (s *Server) getConnectionCount(_ request.Params) (interface{}, *response.Er
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) blockHashFromParam(param *request.Param) (util.Uint256, *response.Error) {
|
func (s *Server) blockHashFromParam(param *request.Param) (util.Uint256, *response.Error) {
|
||||||
var hash util.Uint256
|
var (
|
||||||
|
hash util.Uint256
|
||||||
|
err error
|
||||||
|
)
|
||||||
if param == nil {
|
if param == nil {
|
||||||
return hash, response.ErrInvalidParams
|
return hash, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
|
|
||||||
switch param.Type {
|
if hash, err = param.GetUint256(); err != nil {
|
||||||
case request.StringT:
|
num, respErr := s.blockHeightFromParam(param)
|
||||||
var err error
|
if respErr != nil {
|
||||||
hash, err = param.GetUint256()
|
return hash, respErr
|
||||||
if err != nil {
|
|
||||||
return hash, response.ErrInvalidParams
|
|
||||||
}
|
|
||||||
case request.NumberT:
|
|
||||||
num, err := s.blockHeightFromParam(param)
|
|
||||||
if err != nil {
|
|
||||||
return hash, response.ErrInvalidParams
|
|
||||||
}
|
}
|
||||||
hash = s.chain.GetHeaderHash(num)
|
hash = s.chain.GetHeaderHash(num)
|
||||||
default:
|
|
||||||
return hash, response.ErrInvalidParams
|
|
||||||
}
|
}
|
||||||
return hash, nil
|
return hash, nil
|
||||||
}
|
}
|
||||||
|
@ -499,7 +489,7 @@ func (s *Server) getBlock(reqParams request.Params) (interface{}, *response.Erro
|
||||||
return nil, response.NewInternalServerError(fmt.Sprintf("Problem locating block with hash: %s", hash), err)
|
return nil, response.NewInternalServerError(fmt.Sprintf("Problem locating block with hash: %s", hash), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if reqParams.Value(1).GetBoolean() {
|
if v, _ := reqParams.Value(1).GetBoolean(); v {
|
||||||
return result.NewBlock(block, s.chain), nil
|
return result.NewBlock(block, s.chain), nil
|
||||||
}
|
}
|
||||||
writer := io.NewBufBinWriter()
|
writer := io.NewBufBinWriter()
|
||||||
|
@ -508,11 +498,7 @@ func (s *Server) getBlock(reqParams request.Params) (interface{}, *response.Erro
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getBlockHash(reqParams request.Params) (interface{}, *response.Error) {
|
func (s *Server) getBlockHash(reqParams request.Params) (interface{}, *response.Error) {
|
||||||
param := reqParams.ValueWithType(0, request.NumberT)
|
num, err := s.blockHeightFromParam(reqParams.Value(0))
|
||||||
if param == nil {
|
|
||||||
return nil, response.ErrInvalidParams
|
|
||||||
}
|
|
||||||
num, err := s.blockHeightFromParam(param)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
|
@ -557,7 +543,7 @@ func (s *Server) getPeers(_ request.Params) (interface{}, *response.Error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response.Error) {
|
func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response.Error) {
|
||||||
verbose := reqParams.Value(0).GetBoolean()
|
verbose, _ := reqParams.Value(0).GetBoolean()
|
||||||
mp := s.chain.GetMemPool()
|
mp := s.chain.GetMemPool()
|
||||||
hashList := make([]util.Uint256, 0)
|
hashList := make([]util.Uint256, 0)
|
||||||
for _, item := range mp.GetVerifiedTransactions() {
|
for _, item := range mp.GetVerifiedTransactions() {
|
||||||
|
@ -574,11 +560,15 @@ func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) validateAddress(reqParams request.Params) (interface{}, *response.Error) {
|
func (s *Server) validateAddress(reqParams request.Params) (interface{}, *response.Error) {
|
||||||
param := reqParams.Value(0)
|
param, err := reqParams.Value(0).GetString()
|
||||||
if param == nil {
|
if err != nil {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
return validateAddress(param.Value), nil
|
|
||||||
|
return result.ValidateAddress{
|
||||||
|
Address: reqParams.Value(0),
|
||||||
|
IsValid: validateAddress(param),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculateNetworkFee calculates network fee for the transaction.
|
// calculateNetworkFee calculates network fee for the transaction.
|
||||||
|
@ -644,11 +634,11 @@ func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, *resp
|
||||||
|
|
||||||
trig := trigger.All
|
trig := trigger.All
|
||||||
if len(reqParams) > 1 {
|
if len(reqParams) > 1 {
|
||||||
trigString := reqParams.ValueWithType(1, request.StringT)
|
trigString, err := reqParams.Value(1).GetString()
|
||||||
if trigString == nil {
|
if err != nil {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
trig, err = trigger.FromString(trigString.String())
|
trig, err = trigger.FromString(trigString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
|
@ -877,19 +867,13 @@ func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Err
|
||||||
if param == nil {
|
if param == nil {
|
||||||
return 0, response.ErrInvalidParams
|
return 0, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
switch param.Type {
|
if scriptHash, err := param.GetUint160FromHex(); err == nil {
|
||||||
case request.StringT:
|
|
||||||
var err error
|
|
||||||
scriptHash, err := param.GetUint160FromHex()
|
|
||||||
if err != nil {
|
|
||||||
return 0, response.ErrInvalidParams
|
|
||||||
}
|
|
||||||
cs := s.chain.GetContractState(scriptHash)
|
cs := s.chain.GetContractState(scriptHash)
|
||||||
if cs == nil {
|
if cs == nil {
|
||||||
return 0, response.ErrUnknown
|
return 0, response.ErrUnknown
|
||||||
}
|
}
|
||||||
result = cs.ID
|
result = cs.ID
|
||||||
case request.NumberT:
|
} else {
|
||||||
id, err := param.GetInt()
|
id, err := param.GetInt()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, response.ErrInvalidParams
|
return 0, response.ErrInvalidParams
|
||||||
|
@ -898,8 +882,6 @@ func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Err
|
||||||
return 0, response.WrapErrorWithData(response.ErrInvalidParams, err)
|
return 0, response.WrapErrorWithData(response.ErrInvalidParams, err)
|
||||||
}
|
}
|
||||||
result = int32(id)
|
result = int32(id)
|
||||||
default:
|
|
||||||
return 0, response.ErrInvalidParams
|
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
@ -910,25 +892,21 @@ func (s *Server) contractScriptHashFromParam(param *request.Param) (util.Uint160
|
||||||
if param == nil {
|
if param == nil {
|
||||||
return result, response.ErrInvalidParams
|
return result, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
switch param.Type {
|
nameOrHashOrIndex, err := param.GetString()
|
||||||
case request.StringT:
|
if err != nil {
|
||||||
var err error
|
return result, response.ErrInvalidParams
|
||||||
|
}
|
||||||
result, err = param.GetUint160FromAddressOrHex()
|
result, err = param.GetUint160FromAddressOrHex()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
name, err := param.GetString()
|
result, err = s.chain.GetNativeContractScriptHash(nameOrHashOrIndex)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return result, response.ErrInvalidParams
|
return result, nil
|
||||||
}
|
}
|
||||||
result, err = s.chain.GetNativeContractScriptHash(name)
|
id, err := strconv.Atoi(nameOrHashOrIndex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, response.NewRPCError("Unknown contract: querying by name is supported for native contracts only", "", nil)
|
return result, response.NewRPCError("Unknown contract", "", err)
|
||||||
}
|
|
||||||
case request.NumberT:
|
|
||||||
id, err := param.GetInt()
|
|
||||||
if err != nil {
|
|
||||||
return result, response.ErrInvalidParams
|
|
||||||
}
|
}
|
||||||
if err := checkInt32(id); err != nil {
|
if err := checkInt32(id); err != nil {
|
||||||
return result, response.WrapErrorWithData(response.ErrInvalidParams, err)
|
return result, response.WrapErrorWithData(response.ErrInvalidParams, err)
|
||||||
|
@ -937,9 +915,6 @@ func (s *Server) contractScriptHashFromParam(param *request.Param) (util.Uint160
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, response.NewRPCError("Unknown contract", "", err)
|
return result, response.NewRPCError("Unknown contract", "", err)
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
return result, response.ErrInvalidParams
|
|
||||||
}
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1168,7 +1143,7 @@ func (s *Server) getStateRoot(ps request.Params) (interface{}, *response.Error)
|
||||||
}
|
}
|
||||||
var rt *state.MPTRoot
|
var rt *state.MPTRoot
|
||||||
var h util.Uint256
|
var h util.Uint256
|
||||||
height, err := p.GetInt()
|
height, err := p.GetIntStrict()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if err := checkUint32(height); err != nil {
|
if err := checkUint32(height); err != nil {
|
||||||
return nil, response.WrapErrorWithData(response.ErrInvalidParams, err)
|
return nil, response.WrapErrorWithData(response.ErrInvalidParams, err)
|
||||||
|
@ -1219,7 +1194,7 @@ func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *resp
|
||||||
err = fmt.Errorf("invalid transaction %s: %w", txHash, err)
|
err = fmt.Errorf("invalid transaction %s: %w", txHash, err)
|
||||||
return nil, response.NewRPCError("Unknown transaction", err.Error(), err)
|
return nil, response.NewRPCError("Unknown transaction", err.Error(), err)
|
||||||
}
|
}
|
||||||
if reqParams.Value(1).GetBoolean() {
|
if v, _ := reqParams.Value(1).GetBoolean(); v {
|
||||||
if height == math.MaxUint32 {
|
if height == math.MaxUint32 {
|
||||||
return result.NewTransactionOutputRaw(tx, nil, nil, s.chain), nil
|
return result.NewTransactionOutputRaw(tx, nil, nil, s.chain), nil
|
||||||
}
|
}
|
||||||
|
@ -1274,12 +1249,7 @@ func (s *Server) getNativeContracts(_ request.Params) (interface{}, *response.Er
|
||||||
|
|
||||||
// getBlockSysFee returns the system fees of the block, based on the specified index.
|
// getBlockSysFee returns the system fees of the block, based on the specified index.
|
||||||
func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *response.Error) {
|
func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *response.Error) {
|
||||||
param := reqParams.ValueWithType(0, request.NumberT)
|
num, err := s.blockHeightFromParam(reqParams.Value(0))
|
||||||
if param == nil {
|
|
||||||
return 0, response.ErrInvalidParams
|
|
||||||
}
|
|
||||||
|
|
||||||
num, err := s.blockHeightFromParam(param)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, response.NewRPCError("Invalid height", "", nil)
|
return 0, response.NewRPCError("Invalid height", "", nil)
|
||||||
}
|
}
|
||||||
|
@ -1306,7 +1276,7 @@ func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *respons
|
||||||
return nil, respErr
|
return nil, respErr
|
||||||
}
|
}
|
||||||
|
|
||||||
verbose := reqParams.Value(1).GetBoolean()
|
verbose, _ := reqParams.Value(1).GetBoolean()
|
||||||
h, err := s.chain.GetHeader(hash)
|
h, err := s.chain.GetHeader(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.NewRPCError("unknown block", "", nil)
|
return nil, response.NewRPCError("unknown block", "", nil)
|
||||||
|
@ -1326,7 +1296,7 @@ func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *respons
|
||||||
|
|
||||||
// getUnclaimedGas returns unclaimed GAS amount of the specified address.
|
// getUnclaimedGas returns unclaimed GAS amount of the specified address.
|
||||||
func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Error) {
|
func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Error) {
|
||||||
u, err := ps.ValueWithType(0, request.StringT).GetUint160FromAddressOrHex()
|
u, err := ps.Value(0).GetUint160FromAddressOrHex()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
|
@ -1398,7 +1368,11 @@ func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *respons
|
||||||
if len(tx.Signers) == 0 {
|
if len(tx.Signers) == 0 {
|
||||||
tx.Signers = []transaction.Signer{{Account: util.Uint160{}, Scopes: transaction.None}}
|
tx.Signers = []transaction.Signer{{Account: util.Uint160{}, Scopes: transaction.None}}
|
||||||
}
|
}
|
||||||
script, err := request.CreateFunctionInvocationScript(scriptHash, reqParams[1].String(), reqParams[2:checkWitnessHashesIndex])
|
method, err := reqParams[1].GetString()
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.ErrInvalidParams
|
||||||
|
}
|
||||||
|
script, err := request.CreateFunctionInvocationScript(scriptHash, method, reqParams[2:checkWitnessHashesIndex])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.NewInternalServerError("can't create invocation script", err)
|
return nil, response.NewInternalServerError("can't create invocation script", err)
|
||||||
}
|
}
|
||||||
|
@ -1520,7 +1494,7 @@ func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash
|
||||||
|
|
||||||
// submitBlock broadcasts a raw block over the NEO network.
|
// submitBlock broadcasts a raw block over the NEO network.
|
||||||
func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.Error) {
|
func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.Error) {
|
||||||
blockBytes, err := reqParams.ValueWithType(0, request.StringT).GetBytesBase64()
|
blockBytes, err := reqParams.Value(0).GetBytesBase64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.NewInvalidParamsError("missing parameter or not base64", err)
|
return nil, response.NewInvalidParamsError("missing parameter or not base64", err)
|
||||||
}
|
}
|
||||||
|
@ -1550,10 +1524,7 @@ func (s *Server) submitNotaryRequest(ps request.Params) (interface{}, *response.
|
||||||
return nil, response.NewInternalServerError("P2PNotaryRequest was received, but P2PSignatureExtensions are disabled", nil)
|
return nil, response.NewInternalServerError("P2PNotaryRequest was received, but P2PSignatureExtensions are disabled", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ps) < 1 {
|
bytePayload, err := ps.Value(0).GetBytesBase64()
|
||||||
return nil, response.NewInvalidParamsError("not enough parameters", nil)
|
|
||||||
}
|
|
||||||
bytePayload, err := ps[0].GetBytesBase64()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.NewInvalidParamsError("not base64", err)
|
return nil, response.NewInvalidParamsError("not base64", err)
|
||||||
}
|
}
|
||||||
|
@ -1645,34 +1616,27 @@ func (s *Server) subscribe(reqParams request.Params, sub *subscriber) (interface
|
||||||
// Optional filter.
|
// Optional filter.
|
||||||
var filter interface{}
|
var filter interface{}
|
||||||
if p := reqParams.Value(1); p != nil {
|
if p := reqParams.Value(1); p != nil {
|
||||||
param, ok := p.Value.(json.RawMessage)
|
param := *p
|
||||||
if !ok {
|
jd := json.NewDecoder(bytes.NewReader(param.RawMessage))
|
||||||
return nil, response.ErrInvalidParams
|
|
||||||
}
|
|
||||||
jd := json.NewDecoder(bytes.NewReader(param))
|
|
||||||
jd.DisallowUnknownFields()
|
jd.DisallowUnknownFields()
|
||||||
switch event {
|
switch event {
|
||||||
case response.BlockEventID:
|
case response.BlockEventID:
|
||||||
flt := new(request.BlockFilter)
|
flt := new(request.BlockFilter)
|
||||||
err = jd.Decode(flt)
|
err = jd.Decode(flt)
|
||||||
p.Type = request.BlockFilterT
|
filter = *flt
|
||||||
p.Value = *flt
|
|
||||||
case response.TransactionEventID, response.NotaryRequestEventID:
|
case response.TransactionEventID, response.NotaryRequestEventID:
|
||||||
flt := new(request.TxFilter)
|
flt := new(request.TxFilter)
|
||||||
err = jd.Decode(flt)
|
err = jd.Decode(flt)
|
||||||
p.Type = request.TxFilterT
|
filter = *flt
|
||||||
p.Value = *flt
|
|
||||||
case response.NotificationEventID:
|
case response.NotificationEventID:
|
||||||
flt := new(request.NotificationFilter)
|
flt := new(request.NotificationFilter)
|
||||||
err = jd.Decode(flt)
|
err = jd.Decode(flt)
|
||||||
p.Type = request.NotificationFilterT
|
filter = *flt
|
||||||
p.Value = *flt
|
|
||||||
case response.ExecutionEventID:
|
case response.ExecutionEventID:
|
||||||
flt := new(request.ExecutionFilter)
|
flt := new(request.ExecutionFilter)
|
||||||
err = jd.Decode(flt)
|
err = jd.Decode(flt)
|
||||||
if err == nil && (flt.State == "HALT" || flt.State == "FAULT") {
|
if err == nil && (flt.State == "HALT" || flt.State == "FAULT") {
|
||||||
p.Type = request.ExecutionFilterT
|
filter = *flt
|
||||||
p.Value = *flt
|
|
||||||
} else if err == nil {
|
} else if err == nil {
|
||||||
err = errors.New("invalid state")
|
err = errors.New("invalid state")
|
||||||
}
|
}
|
||||||
|
@ -1680,7 +1644,6 @@ func (s *Server) subscribe(reqParams request.Params, sub *subscriber) (interface
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
filter = p.Value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.subsLock.Lock()
|
s.subsLock.Lock()
|
||||||
|
@ -1912,7 +1875,7 @@ drainloop:
|
||||||
func (s *Server) blockHeightFromParam(param *request.Param) (int, *response.Error) {
|
func (s *Server) blockHeightFromParam(param *request.Param) (int, *response.Error) {
|
||||||
num, err := param.GetInt()
|
num, err := param.GetInt()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil
|
return 0, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
|
|
||||||
if num < 0 || num > int(s.chain.BlockHeight()) {
|
if num < 0 || num > int(s.chain.BlockHeight()) {
|
||||||
|
@ -1946,11 +1909,9 @@ func (s *Server) logRequestError(r *request.Request, jsonErr *response.Error) {
|
||||||
|
|
||||||
if r.In != nil {
|
if r.In != nil {
|
||||||
logFields = append(logFields, zap.String("method", r.In.Method))
|
logFields = append(logFields, zap.String("method", r.In.Method))
|
||||||
params, err := r.In.Params()
|
params := request.Params(r.In.RawParams)
|
||||||
if err == nil {
|
|
||||||
logFields = append(logFields, zap.Any("params", params))
|
logFields = append(logFields, zap.Any("params", params))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
s.log.Error("Error encountered with rpc request", logFields...)
|
s.log.Error("Error encountered with rpc request", logFields...)
|
||||||
}
|
}
|
||||||
|
@ -1996,11 +1957,10 @@ func (s *Server) writeHTTPServerResponse(r *request.Request, w http.ResponseWrit
|
||||||
|
|
||||||
// validateAddress verifies that the address is a correct NEO address
|
// validateAddress verifies that the address is a correct NEO address
|
||||||
// see https://docs.neo.org/en-us/node/cli/2.9.4/api/validateaddress.html
|
// see https://docs.neo.org/en-us/node/cli/2.9.4/api/validateaddress.html
|
||||||
func validateAddress(addr interface{}) result.ValidateAddress {
|
func validateAddress(addr interface{}) bool {
|
||||||
resp := result.ValidateAddress{Address: addr}
|
|
||||||
if addr, ok := addr.(string); ok {
|
if addr, ok := addr.(string); ok {
|
||||||
_, err := address.StringToUint160(addr)
|
_, err := address.StringToUint160(addr)
|
||||||
resp.IsValid = (err == nil)
|
return err == nil
|
||||||
}
|
}
|
||||||
return resp
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ const (
|
||||||
notaryPass = "one"
|
notaryPass = "one"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getUnitTestChain(t *testing.T, enableOracle bool, enableNotary bool) (*core.Blockchain, *oracle.Oracle, config.Config, *zap.Logger) {
|
func getUnitTestChain(t testing.TB, enableOracle bool, enableNotary bool) (*core.Blockchain, *oracle.Oracle, config.Config, *zap.Logger) {
|
||||||
net := netmode.UnitTestNet
|
net := netmode.UnitTestNet
|
||||||
configPath := "../../../config"
|
configPath := "../../../config"
|
||||||
cfg, err := config.Load(configPath, net)
|
cfg, err := config.Load(configPath, net)
|
||||||
|
@ -97,7 +97,7 @@ func getTestBlocks(t *testing.T) []*block.Block {
|
||||||
return blocks
|
return blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
func initClearServerWithServices(t *testing.T, needOracle bool, needNotary bool) (*core.Blockchain, *Server, *httptest.Server) {
|
func initClearServerWithServices(t testing.TB, needOracle bool, needNotary bool) (*core.Blockchain, *Server, *httptest.Server) {
|
||||||
chain, orc, cfg, logger := getUnitTestChain(t, needOracle, needNotary)
|
chain, orc, cfg, logger := getUnitTestChain(t, needOracle, needNotary)
|
||||||
|
|
||||||
serverConfig := network.NewServerConfig(cfg)
|
serverConfig := network.NewServerConfig(cfg)
|
||||||
|
@ -113,7 +113,7 @@ func initClearServerWithServices(t *testing.T, needOracle bool, needNotary bool)
|
||||||
return chain, &rpcServer, srv
|
return chain, &rpcServer, srv
|
||||||
}
|
}
|
||||||
|
|
||||||
func initClearServerWithInMemoryChain(t *testing.T) (*core.Blockchain, *Server, *httptest.Server) {
|
func initClearServerWithInMemoryChain(t testing.TB) (*core.Blockchain, *Server, *httptest.Server) {
|
||||||
return initClearServerWithServices(t, false, false)
|
return initClearServerWithServices(t, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,9 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/network"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpc/request"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc/response"
|
"github.com/nspcc-dev/neo-go/pkg/rpc/response"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
|
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
|
||||||
rpc2 "github.com/nspcc-dev/neo-go/pkg/services/oracle/broadcaster"
|
rpc2 "github.com/nspcc-dev/neo-go/pkg/services/oracle/broadcaster"
|
||||||
|
@ -39,6 +41,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
)
|
)
|
||||||
|
|
||||||
type executor struct {
|
type executor struct {
|
||||||
|
@ -452,10 +455,6 @@ var rpcTestCases = map[string][]rpcTestCase{
|
||||||
return &v
|
return &v
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
params: "1",
|
|
||||||
fail: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"getblock": {
|
"getblock": {
|
||||||
{
|
{
|
||||||
|
@ -2160,3 +2159,45 @@ func checkNep17TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rc
|
||||||
}
|
}
|
||||||
require.Equal(t, arr, res.Received)
|
require.Equal(t, arr, res.Received)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkHandleIn(b *testing.B) {
|
||||||
|
chain, orc, cfg, logger := getUnitTestChain(b, false, false)
|
||||||
|
|
||||||
|
serverConfig := network.NewServerConfig(cfg)
|
||||||
|
serverConfig.LogLevel = zapcore.FatalLevel
|
||||||
|
server, err := network.NewServer(serverConfig, chain, logger)
|
||||||
|
require.NoError(b, err)
|
||||||
|
rpcServer := New(chain, cfg.ApplicationConfiguration.RPC, server, orc, logger)
|
||||||
|
defer chain.Close()
|
||||||
|
|
||||||
|
do := func(b *testing.B, req []byte) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
b.StopTimer()
|
||||||
|
in := new(request.In)
|
||||||
|
b.StartTimer()
|
||||||
|
err := json.Unmarshal(req, in)
|
||||||
|
if err != nil {
|
||||||
|
b.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
res := rpcServer.handleIn(in, nil)
|
||||||
|
if res.Error != nil {
|
||||||
|
b.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.StopTimer()
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Run("no extra params", func(b *testing.B) {
|
||||||
|
do(b, []byte(`{"jsonrpc":"2.0", "method":"validateaddress","params":["Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2"]}`))
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("with extra params", func(b *testing.B) {
|
||||||
|
do(b, []byte(`{"jsonrpc":"2.0", "method":"validateaddress","params":["Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2",
|
||||||
|
"set", "of", "different", "parameters", "to", "see", "the", "difference", "between", "unmarshalling", "algorithms", 1234, 5678, 1234567, 765432, true, false, null,
|
||||||
|
"0x50befd26fdf6e4d957c11e078b24ebce6291456f", "someMethod", [{"type": "String", "value": "50befd26fdf6e4d957c11e078b24ebce6291456f"},
|
||||||
|
{"type": "Integer", "value": "42"}, {"type": "Boolean", "value": false}]]}`))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue