2022-07-07 14:41:01 +00:00
package params
2020-02-17 11:54:53 +00:00
import (
2022-06-22 10:03:53 +00:00
"encoding/base64"
2021-10-28 11:10:18 +00:00
"fmt"
2022-02-09 12:13:15 +00:00
"math/big"
2020-02-17 11:54:53 +00:00
"testing"
2020-08-27 08:44:40 +00:00
"github.com/nspcc-dev/neo-go/pkg/io"
2020-03-03 14:21:42 +00:00
"github.com/nspcc-dev/neo-go/pkg/util"
2020-08-27 08:44:40 +00:00
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
2020-02-17 11:54:53 +00:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestInvocationScriptCreationGood ( t * testing . T ) {
2021-10-28 11:10:18 +00:00
p := Param { RawMessage : [ ] byte ( ` "50befd26fdf6e4d957c11e078b24ebce6291456f" ` ) }
2020-02-17 11:54:53 +00:00
contract , err := p . GetUint160FromHex ( )
require . Nil ( t , err )
var paramScripts = [ ] struct {
ps Params
script string
} { {
2021-10-28 11:10:18 +00:00
ps : Params { { RawMessage : [ ] byte ( ` "transfer" ` ) } } ,
2022-06-22 10:03:53 +00:00
script : "wh8MCHRyYW5zZmVyDBRvRZFizuskiwcewVfZ5Pb9Jv2+UEFifVtS" ,
2020-02-17 11:54:53 +00:00
} , {
2021-10-28 11:10:18 +00:00
ps : Params { { RawMessage : [ ] byte ( ` 42 ` ) } } ,
2022-06-22 10:03:53 +00:00
script : "wh8MAjQyDBRvRZFizuskiwcewVfZ5Pb9Jv2+UEFifVtS" ,
2020-02-17 11:54:53 +00:00
} , {
2021-10-28 11:10:18 +00:00
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [] ` ) } } ,
rpc: adjust script creation with empty parameters list
Always use NEWARRAY0 where possible, see
https://github.com/neo-project/neo/blob/26d04a642ac5a1dd1827dabf5602767e0acba25c/src/neo/VM/Helper.cs#L41.
Compatibility is tested:
```
anna@kiwi:~/Documents/GitProjects/nspcc-dev/neo-go$ curl -d '{ "jsonrpc": "2.0", "id": 1, "method": "invokefunction", "params": ["50befd26fdf6e4d957c11e078b24ebce6291456f", "a", [] ]}' seed1.neo.org:10332 | json_pp
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 370 0 248 100 122 127 62 0:00:01 0:00:01 --:--:-- 190
{
"result" : {
"notifications" : [],
"stack" : [],
"script" : "wh8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=",
"gasconsumed" : "98403",
"state" : "FAULT",
"exception" : "Called Contract Does Not Exist: 0x50befd26fdf6e4d957c11e078b24ebce6291456f"
},
"jsonrpc" : "2.0",
"id" : 1
}
```
2022-06-22 10:23:55 +00:00
script : "wh8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=" ,
2020-02-17 11:54:53 +00:00
} , {
rpc: adjust TestInvocationScriptCreationGood testcase
Although neo-go can handle both ByteArray and ByteString parameter
types, C# node can't, so let's use the common one for tests. Compat
test:
```
anna@kiwi:~/Documents/GitProjects/nspcc-dev/neo-go$ curl -d '{ "jsonrpc": "2.0", "id": 1, "method": "invokefunction", "params": ["50befd26fdf6e4d957c11e078b24ebce6291456f", "a", [{"type": "ByteString", "value": "AwEtR+diEK7HO+Oas9GG4KQP6Nhr+j1Pq/2le6E7iPlq"}] ]}' seed1.neo.org:10332 | json_pp
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1271 0 1070 100 201 2860 537 --:--:-- --:--:-- --:--:-- 3398
{
"jsonrpc" : "2.0",
"id" : 1,
"error" : {
"message" : "Requested value 'ByteString' was not found.",
"data" : " at System.Enum.TryParseByName(RuntimeType enumType, ReadOnlySpan`1 value, Boolean ignoreCase, Boolean throwOnFailure, UInt64& result)\n at System.Enum.TryParseUInt32Enum(RuntimeType enumType, ReadOnlySpan`1 value, UInt32 maxInclusive, Boolean ignoreCase, Boolean throwOnFailure, TypeCode type, UInt32& result)\n at System.Enum.TryParse[TEnum](ReadOnlySpan`1 value, Boolean ignoreCase, Boolean throwOnFailure, TEnum& result)\n at System.Enum.TryParse[TEnum](String value, Boolean ignoreCase, Boolean throwOnFailure, TEnum& result)\n at Neo.SmartContract.ContractParameter.FromJson(JObject json)\n at Neo.Plugins.RpcServer.<>c.<InvokeFunction>b__43_0(JObject p)\n at System.Linq.Enumerable.SelectIListIterator`2.ToArray()\n at Neo.Plugins.RpcServer.InvokeFunction(JArray _params)\n at Neo.Plugins.RpcServer.ProcessRequestAsync(HttpContext context, JObject request)",
"code" : -2147024809
}
}
anna@kiwi:~/Documents/GitProjects/nspcc-dev/neo-go$ curl -d '{ "jsonrpc": "2.0", "id": 1, "method": "invokefunction", "params": ["50befd26fdf6e4d957c11e078b24ebce6291456f", "a", [{"type": "ByteArray", "value": "AwEtR+diEK7HO+Oas9GG4KQP6Nhr+j1Pq/2le6E7iPlq"}] ]}' seed1.neo.org:10332 | json_pp
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 507 0 307 100 200 161 105 0:00:01 0:00:01 --:--:-- 266
{
"result" : {
"gasconsumed" : "104526",
"notifications" : [],
"stack" : [],
"script" : "DCEDAS1H52IQrsc745qz0YbgpA/o2Gv6PU+r/aV7oTuI+WoRwB8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=",
"state" : "FAULT",
"exception" : "Called Contract Does Not Exist: 0x50befd26fdf6e4d957c11e078b24ebce6291456f"
},
"id" : 1,
"jsonrpc" : "2.0"
}
```
2022-06-22 12:33:56 +00:00
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [ { "type": "ByteArray", "value": "AwEtR+diEK7HO+Oas9GG4KQP6Nhr+j1Pq/2le6E7iPlq"}] ` ) } } ,
2022-06-22 10:03:53 +00:00
script : "DCEDAS1H52IQrsc745qz0YbgpA/o2Gv6PU+r/aV7oTuI+WoRwB8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=" ,
2020-02-17 11:54:53 +00:00
} , {
2021-10-28 11:10:18 +00:00
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [ { "type": "Signature", "value": "4edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f"}] ` ) } } ,
rpc: fix Signature parameter unmarshalling
It is based64 encoded and decoded, see
https://github.com/nspcc-dev/neo-go/blob/5108d1c2c748ad00de2c0b37c05f41e841d770c9/pkg/smartcontract/parameter.go#L78
and
https://github.com/neo-project/neo/blob/26d04a642ac5a1dd1827dabf5602767e0acba25c/src/neo/SmartContract/ContractParameter.cs#L150
and
https://github.com/neo-project/neo/blob/26d04a642ac5a1dd1827dabf5602767e0acba25c/src/neo/SmartContract/ContractParameter.cs#L79.
Also, TestInvocationScriptCreationGood is extended and compatibility
is tested with the following C# node requests:
```
anna@kiwi:~/Documents/GitProjects/nspcc-dev/neo-go$ curl -d '{ "jsonrpc": "2.0", "id": 1, "method": "invokefunction", "params": ["50befd26fdf6e4d957c11e078b24ebce6291456f", "a", [{"type": "Signature", "value": "4edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f"}]] }' seed1.neo.org:10332 | json_pp
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 665 0 381 100 284 197 147 0:00:01 0:00:01 --:--:-- 344
{
"jsonrpc" : "2.0",
"id" : 1,
"result" : {
"notifications" : [],
"stack" : [],
"script" : "DGDh51/nTTnvvV17TjrX3bfl3lrhztr1rXVtvvx7TTznjV/V1rvvbl/rnhzfffzRrdzzt7b3n1rTbl1rvTp3vbnlxvdrd9rTt5t71zrnn13R317rbXdzrzTj3Xrx5vXTnp8RwB8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=",
"exception" : "Called Contract Does Not Exist: 0x50befd26fdf6e4d957c11e078b24ebce6291456f",
"state" : "FAULT",
"gasconsumed" : "104526"
}
}
anna@kiwi:~/Documents/GitProjects/nspcc-dev/neo-go$ curl -d '{ "jsonrpc": "2.0", "id": 1, "method": "invokefunction", "params": ["50befd26fdf6e4d957c11e078b24ebce6291456f", "a", [{"type": "Signature", "value": "Tt9QBXcd4EYZI11aTHqaEbt44AhUHx2ncl9lTDM4CjyH4pWaAl2nBtclXLOj+gfr6cZVnQ2eYhPGgEkWjrEFbw=="}]] }' seed1.neo.org:10332 | json_pp
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 591 0 347 100 244 794 558 --:--:-- --:--:-- --:--:-- 1352
{
"jsonrpc" : "2.0",
"result" : {
"state" : "FAULT",
"exception" : "Called Contract Does Not Exist: 0x50befd26fdf6e4d957c11e078b24ebce6291456f",
"gasconsumed" : "104526",
"notifications" : [],
"stack" : [],
"script" : "DEBO31AFdx3gRhkjXVpMepoRu3jgCFQfHadyX2VMMzgKPIfilZoCXacG1yVcs6P6B+vpxlWdDZ5iE8aASRaOsQVvEcAfDAFhDBRvRZFizuskiwcewVfZ5Pb9Jv2+UEFifVtS"
},
"id" : 1
}
```
2022-06-22 09:57:19 +00:00
script : "DGDh51/nTTnvvV17TjrX3bfl3lrhztr1rXVtvvx7TTznjV/V1rvvbl/rnhzfffzRrdzzt7b3n1rTbl1rvTp3vbnlxvdrd9rTt5t71zrnn13R317rbXdzrzTj3Xrx5vXTnp8RwB8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=" ,
} , {
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [ { "type": "Signature", "value": "Tt9QBXcd4EYZI11aTHqaEbt44AhUHx2ncl9lTDM4CjyH4pWaAl2nBtclXLOj+gfr6cZVnQ2eYhPGgEkWjrEFbw=="}] ` ) } } ,
2022-06-22 10:03:53 +00:00
script : "DEBO31AFdx3gRhkjXVpMepoRu3jgCFQfHadyX2VMMzgKPIfilZoCXacG1yVcs6P6B+vpxlWdDZ5iE8aASRaOsQVvEcAfDAFhDBRvRZFizuskiwcewVfZ5Pb9Jv2+UEFifVtS" ,
2020-02-17 11:54:53 +00:00
} , {
2021-10-28 11:10:18 +00:00
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [ { "type": "String", "value": "50befd26fdf6e4d957c11e078b24ebce6291456f"}] ` ) } } ,
2022-06-22 10:03:53 +00:00
script : "DCg1MGJlZmQyNmZkZjZlNGQ5NTdjMTFlMDc4YjI0ZWJjZTYyOTE0NTZmEcAfDAFhDBRvRZFizuskiwcewVfZ5Pb9Jv2+UEFifVtS" ,
2020-02-17 11:54:53 +00:00
} , {
2021-10-28 11:10:18 +00:00
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [ { "type": "Hash160", "value": "50befd26fdf6e4d957c11e078b24ebce6291456f"}] ` ) } } ,
2022-06-22 10:03:53 +00:00
script : "DBRvRZFizuskiwcewVfZ5Pb9Jv2+UBHAHwwBYQwUb0WRYs7rJIsHHsFX2eT2/Sb9vlBBYn1bUg==" ,
2020-02-17 11:54:53 +00:00
} , {
2021-10-28 11:10:18 +00:00
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [ { "type": "Hash256", "value": "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"}] ` ) } } ,
2022-06-22 10:03:53 +00:00
script : "DCDnLShpee5ssbfmXf3fsuOEEAuNFI53WN5C5BaLcXksYBHAHwwBYQwUb0WRYs7rJIsHHsFX2eT2/Sb9vlBBYn1bUg==" ,
2020-02-17 11:54:53 +00:00
} , {
2021-10-28 11:10:18 +00:00
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [ { "type": "PublicKey", "value": "03c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c1"}] ` ) } } ,
2022-06-22 10:03:53 +00:00
script : "DCEDwInXEiuECkk1I06C4mrl79DCrLYnI53J8gcxEze28sERwB8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=" ,
2020-02-17 11:54:53 +00:00
} , {
2021-10-28 11:10:18 +00:00
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [ { "type": "Integer", "value": 42}] ` ) } } ,
2022-06-22 10:03:53 +00:00
script : "ACoRwB8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=" ,
2020-02-17 11:54:53 +00:00
} , {
2021-10-28 11:10:18 +00:00
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [ { "type": "Integer", "value": "42"}] ` ) } } , // C# code doesn't use strict type assertions for JSON-ised params
2022-06-22 10:03:53 +00:00
script : "ACoRwB8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=" ,
2021-10-28 11:10:18 +00:00
} , {
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [ { "type": "Integer", "value": true}] ` ) } } , // C# code doesn't use strict type assertions for JSON-ised params
2022-06-22 10:03:53 +00:00
script : "ERHAHwwBYQwUb0WRYs7rJIsHHsFX2eT2/Sb9vlBBYn1bUg==" ,
2021-10-28 11:10:18 +00:00
} , {
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [ { "type": "Boolean", "value": true}] ` ) } } ,
2022-10-28 09:23:27 +00:00
script : "CBHAHwwBYQwUb0WRYs7rJIsHHsFX2eT2/Sb9vlBBYn1bUg==" ,
2020-02-17 11:54:53 +00:00
} , {
2021-10-28 11:10:18 +00:00
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [ { "type": "Boolean", "value": false}] ` ) } } ,
2022-10-28 09:23:27 +00:00
script : "CRHAHwwBYQwUb0WRYs7rJIsHHsFX2eT2/Sb9vlBBYn1bUg==" ,
2021-10-28 11:10:18 +00:00
} , {
ps : Params { { RawMessage : [ ] byte ( ` "a" ` ) } , { RawMessage : [ ] byte ( ` [ { "type": "Boolean", "value": "blah"}] ` ) } } , // C# code doesn't use strict type assertions for JSON-ised params
2022-10-28 09:23:27 +00:00
script : "CBHAHwwBYQwUb0WRYs7rJIsHHsFX2eT2/Sb9vlBBYn1bUg==" ,
2020-02-17 11:54:53 +00:00
} }
2021-10-28 11:10:18 +00:00
for i , ps := range paramScripts {
method , err := ps . ps [ 0 ] . GetString ( )
require . NoError ( t , err , fmt . Sprintf ( "testcase #%d" , i ) )
2021-11-20 16:25:42 +00:00
var p * Param
if len ( ps . ps ) > 1 {
p = & ps . ps [ 1 ]
}
script , err := CreateFunctionInvocationScript ( contract , method , p )
2020-02-17 11:54:53 +00:00
assert . Nil ( t , err )
2022-06-22 10:03:53 +00:00
assert . Equal ( t , ps . script , base64 . StdEncoding . EncodeToString ( script ) , fmt . Sprintf ( "testcase #%d" , i ) )
2020-02-17 11:54:53 +00:00
}
}
func TestInvocationScriptCreationBad ( t * testing . T ) {
contract := util . Uint160 { }
2021-11-20 16:25:42 +00:00
var testParams = [ ] Param {
{ RawMessage : [ ] byte ( ` true ` ) } ,
{ RawMessage : [ ] byte ( ` [ { "type": "ByteArray", "value": "qwerty"}] ` ) } ,
{ RawMessage : [ ] byte ( ` [ { "type": "Signature", "value": "qwerty"}] ` ) } ,
{ RawMessage : [ ] byte ( ` [ { "type": "Hash160", "value": "qwerty"}] ` ) } ,
{ RawMessage : [ ] byte ( ` [ { "type": "Hash256", "value": "qwerty"}] ` ) } ,
{ RawMessage : [ ] byte ( ` [ { "type": "PublicKey", "value": 42}] ` ) } ,
{ RawMessage : [ ] byte ( ` [ { "type": "PublicKey", "value": "qwerty"}] ` ) } ,
{ RawMessage : [ ] byte ( ` [ { "type": "Integer", "value": "123q"}] ` ) } ,
{ RawMessage : [ ] byte ( ` [ { "type": "Unknown"}] ` ) } ,
2020-02-17 11:54:53 +00:00
}
2021-10-28 11:10:18 +00:00
for i , ps := range testParams {
2021-11-20 16:25:42 +00:00
_ , err := CreateFunctionInvocationScript ( contract , "" , & ps )
2021-10-28 11:10:18 +00:00
assert . NotNil ( t , err , fmt . Sprintf ( "testcase #%d" , i ) )
2020-02-17 11:54:53 +00:00
}
}
2020-08-27 08:44:40 +00:00
func TestExpandArrayIntoScript ( t * testing . T ) {
2022-02-09 12:13:15 +00:00
bi := new ( big . Int ) . Lsh ( big . NewInt ( 1 ) , 254 )
rawInt := make ( [ ] byte , 32 )
rawInt [ 31 ] = 0x40
2020-08-27 08:44:40 +00:00
testCases := [ ] struct {
Input [ ] Param
Expected [ ] byte
} {
{
2021-10-28 11:10:18 +00:00
Input : [ ] Param { { RawMessage : [ ] byte ( ` { "type": "String", "value": "a"} ` ) } } ,
2020-08-27 08:44:40 +00:00
Expected : [ ] byte { byte ( opcode . PUSHDATA1 ) , 1 , byte ( 'a' ) } ,
} ,
{
2021-10-28 11:10:18 +00:00
Input : [ ] Param { { RawMessage : [ ] byte ( ` { "type": "Array", "value": [ { "type": "String", "value": "a"}]} ` ) } } ,
2020-08-27 08:44:40 +00:00
Expected : [ ] byte { byte ( opcode . PUSHDATA1 ) , 1 , byte ( 'a' ) , byte ( opcode . PUSH1 ) , byte ( opcode . PACK ) } ,
} ,
2022-02-09 12:13:15 +00:00
{
Input : [ ] Param { { RawMessage : [ ] byte ( ` { "type": "Integer", "value": " ` + bi . String ( ) + ` "} ` ) } } ,
Expected : append ( [ ] byte { byte ( opcode . PUSHINT256 ) } , rawInt ... ) ,
} ,
2024-02-27 16:56:59 +00:00
{
Input : [ ] Param { { RawMessage : [ ] byte ( ` { "type": "Map", "value": [ { "key": { "type": "String", "value": "a" }, "value": { "type": "Integer", "value": 1}}, { "key": { "type": "String", "value": "b"}, "value": { "type": "Integer", "value": 2}}]} ` ) } } ,
Expected : [ ] byte {
byte ( opcode . PUSH2 ) , // value of element #2
byte ( opcode . PUSHDATA1 ) , 1 , byte ( 'b' ) , // key of element #2
byte ( opcode . PUSH1 ) , // value of element #1
byte ( opcode . PUSHDATA1 ) , 1 , byte ( 'a' ) , // key of element #1
byte ( opcode . PUSH2 ) , // map len
byte ( opcode . PACKMAP ) ,
} ,
} ,
2020-08-27 08:44:40 +00:00
}
for _ , c := range testCases {
script := io . NewBufBinWriter ( )
2021-03-10 14:43:52 +00:00
err := ExpandArrayIntoScript ( script . BinWriter , c . Input )
2020-08-27 08:44:40 +00:00
require . NoError ( t , err )
require . Equal ( t , c . Expected , script . Bytes ( ) )
}
errorCases := [ ] [ ] Param {
{
2021-10-28 11:10:18 +00:00
{ RawMessage : [ ] byte ( ` { "type": "Array", "value": "a"} ` ) } ,
2020-08-27 08:44:40 +00:00
} ,
{
2021-10-28 11:10:18 +00:00
{ RawMessage : [ ] byte ( ` { "type": "Array", "value": null} ` ) } ,
2020-08-27 08:44:40 +00:00
} ,
2022-02-09 12:38:22 +00:00
{
{ RawMessage : [ ] byte ( ` { "type": "Integer", "value": " ` +
new ( big . Int ) . Lsh ( big . NewInt ( 1 ) , 255 ) . String ( ) + ` "} ` ) } ,
} ,
2024-02-27 16:56:59 +00:00
{
{ RawMessage : [ ] byte ( ` { "type": "Map", "value": [ { "key": { "type": "InvalidT", "value": "a" }, "value": { "type": "Integer", "value": 1}}]} ` ) } ,
} ,
{
{ RawMessage : [ ] byte ( ` { "type": "Map", "value": [ { "key": { "type": "String", "value": "a" }, "value": { "type": "Integer", "value": "not-an-int"}}]} ` ) } ,
} ,
2020-08-27 08:44:40 +00:00
}
for _ , c := range errorCases {
script := io . NewBufBinWriter ( )
2021-03-10 14:43:52 +00:00
err := ExpandArrayIntoScript ( script . BinWriter , c )
2020-08-27 08:44:40 +00:00
require . Error ( t , err )
}
}