Merge pull request #1824 from nspcc-dev/native/libs
native: implement StdLib and CryptoLib contracts
This commit is contained in:
commit
5dff7afd5a
88 changed files with 1674 additions and 1550 deletions
|
@ -2,11 +2,11 @@
|
|||
"version": "3.0",
|
||||
"accounts": [
|
||||
{
|
||||
"address": "NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcILQZVEDXg=",
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcJBdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw==",
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
"version": "3.0",
|
||||
"accounts": [
|
||||
{
|
||||
"address": "NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcILQZVEDXg=",
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcJBdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw==",
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -44,11 +44,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NVNvVRW5Q5naSx2k2iZm7xRgtRNGuZppAK",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NNudMSGzEoktFzdYGYoNb3bzHzbmM1genF",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EQwhArNiK/QBe9/jF8WK7V9MdT8ga324lgRvp9d0u8S/f43CEQtBE43vrw==",
|
||||
"script": "EQwhArNiK/QBe9/jF8WK7V9MdT8ga324lgRvp9d0u8S/f43CEUF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
"version": "3.0",
|
||||
"accounts": [
|
||||
{
|
||||
"address": "NWvKSwutC8D6VKmmPxAEgFKx2NLvFhn8q5",
|
||||
"key": "6PYKEHagXJ3mDLdga1FoyTGRtPdJgPz6Gb8sjEFwZvRu7ncD9PVZfHtMzL",
|
||||
"address": "NUREbqw2kfbPgDeEz8Dac2QxntGGqqFMm7",
|
||||
"key": "6PYXADog3RQCwKRhqQsobwZEFopdcCJuMfPosM9pXPaDWSguKvznLdpADk",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCECEDp/fdAWVYWX95YNJ8UWpDlP2Wi55lFV60sBPkBAQG4LQZVEDXg=",
|
||||
"script": "DCECEDp/fdAWVYWX95YNJ8UWpDlP2Wi55lFV60sBPkBAQG5BdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
|
||||
"key": "6PYKEHagXJ3mDLdga1FoyTGRtPdJgPz6Gb8sjEFwZvRu7ncD9PVZfHtMzL",
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYXADog3RQCwKRhqQsobwZEFopdcCJuMfPosM9pXPaDWSguKvznLdpADk",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw==",
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
"version": "3.0",
|
||||
"accounts": [
|
||||
{
|
||||
"address": "NNB3RsnTABEwoKEudNG92njds91WtiCuxd",
|
||||
"key": "6PYLjn1Zw3RQmP3CkDxoZvYtMpu7ZUdjHnvu7wPuohUcXWCMh9vY661R8A",
|
||||
"address": "NQP81vKVRmwZHveX8C9Rbf2qejSpT1W1Eu",
|
||||
"key": "6PYScv3Vgvdi9EkhDNvHXdvQeuaXK9gRwXDmytCswZMNpTzMLvfgR3U5dK",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCED2QwH32PmkM53kS4Qq1GsyUS2aGAje2CMT4+DCece5pkLQZVEDXg=",
|
||||
"script": "DCED2QwH32PmkM53kS4Qq1GsyUS2aGAje2CMT4+DCece5plBdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
|
||||
"key": "6PYLjn1Zw3RQmP3CkDxoZvYtMpu7ZUdjHnvu7wPuohUcXWCMh9vY661R8A",
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYScv3Vgvdi9EkhDNvHXdvQeuaXK9gRwXDmytCswZMNpTzMLvfgR3U5dK",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw==",
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
"version": "3.0",
|
||||
"accounts": [
|
||||
{
|
||||
"address": "Nfzo95iBXfeAGx5rdjPedZRAqHKh9hwMdR",
|
||||
"key": "6PYLbYYg9jUgzJQpKhpvNExa2UEgtp4356XPg56pHuCpE7gQmj84ESNjYW",
|
||||
"address": "NLA34vf8eXGGUhRjVaYe5f8YsyYHTehbDZ",
|
||||
"key": "6PYVwp1Sdg9DfTzvg42PZxgzMDf5a5FYBgT6ynKKzwmSHuhGkipoNjyW3a",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWILQZVEDXg=",
|
||||
"script": "DCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWJBdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
|
||||
"key": "6PYLbYYg9jUgzJQpKhpvNExa2UEgtp4356XPg56pHuCpE7gQmj84ESNjYW",
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYVwp1Sdg9DfTzvg42PZxgzMDf5a5FYBgT6ynKKzwmSHuhGkipoNjyW3a",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw==",
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
|
|
@ -31,8 +31,8 @@ import (
|
|||
|
||||
const (
|
||||
validatorWIF = "KxyjQ8eUa4FHt3Gvioyt1Wz29cTUrE4eTqX3yFSk1YFCsPL8uNsY"
|
||||
validatorAddr = "NVNvVRW5Q5naSx2k2iZm7xRgtRNGuZppAK"
|
||||
multisigAddr = "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY"
|
||||
validatorAddr = "NNudMSGzEoktFzdYGYoNb3bzHzbmM1genF"
|
||||
multisigAddr = "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6"
|
||||
|
||||
validatorWallet = "testdata/wallet1_solo.json"
|
||||
)
|
||||
|
|
|
@ -51,7 +51,7 @@ func TestNEP17Balance(t *testing.T) {
|
|||
})
|
||||
t.Run("all accounts", func(t *testing.T) {
|
||||
e.Run(t, cmdbase...)
|
||||
addr1, err := address.StringToUint160("NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc")
|
||||
addr1, err := address.StringToUint160("NTh9TnZTstvAePEYWDGLLxidBikJE24uTo")
|
||||
require.NoError(t, err)
|
||||
e.checkNextLine(t, "^Account "+address.Uint160ToString(addr1))
|
||||
e.checkNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
|
||||
|
@ -60,12 +60,12 @@ func TestNEP17Balance(t *testing.T) {
|
|||
e.checkNextLine(t, "^\\s*Updated:")
|
||||
e.checkNextLine(t, "^\\s*$")
|
||||
|
||||
addr2, err := address.StringToUint160("NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY")
|
||||
addr2, err := address.StringToUint160("NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6")
|
||||
require.NoError(t, err)
|
||||
e.checkNextLine(t, "^Account "+address.Uint160ToString(addr2))
|
||||
e.checkNextLine(t, "^\\s*$")
|
||||
|
||||
addr3, err := address.StringToUint160("NVNvVRW5Q5naSx2k2iZm7xRgtRNGuZppAK")
|
||||
addr3, err := address.StringToUint160("NNudMSGzEoktFzdYGYoNb3bzHzbmM1genF")
|
||||
require.NoError(t, err)
|
||||
e.checkNextLine(t, "^Account "+address.Uint160ToString(addr3))
|
||||
// The order of assets is undefined.
|
||||
|
@ -85,7 +85,7 @@ func TestNEP17Balance(t *testing.T) {
|
|||
}
|
||||
|
||||
e.checkNextLine(t, "^\\s*$")
|
||||
addr4, err := address.StringToUint160("NWTDxsHVde5qSjRkTRUAg6i8xC3JSWEC9k") // deployed verify.go contract
|
||||
addr4, err := address.StringToUint160("NTe3yHH5zsaEGvEHTsFRpCjTef6Aod4yb6") // deployed verify.go contract
|
||||
require.NoError(t, err)
|
||||
e.checkNextLine(t, "^Account "+address.Uint160ToString(addr4))
|
||||
e.checkEOF(t)
|
||||
|
@ -136,7 +136,7 @@ func TestNEP17Transfer(t *testing.T) {
|
|||
require.Equal(t, big.NewInt(1), b)
|
||||
|
||||
t.Run("default address", func(t *testing.T) {
|
||||
const validatorDefault = "NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc"
|
||||
const validatorDefault = "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo"
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
|
|
BIN
cli/testdata/chain50x2.acc
vendored
BIN
cli/testdata/chain50x2.acc
vendored
Binary file not shown.
32
cli/testdata/testwallet.json
vendored
32
cli/testdata/testwallet.json
vendored
|
@ -1 +1,31 @@
|
|||
{"version":"3.0","accounts":[{"address":"NNuJqXDnRqvwgzhSzhH4jnVFWB1DyZ34EM","key":"6PYT6enT6eh4gu4ew3Mx58pFFDQNhuR1qQPuU594Eo5u4sA2ZvE4MqJV12","label":"kek","contract":{"script":"DCECl3UyEIq6T5RRIXS6z4tNdZPTzQ7NvXyx7FwK05d9UyYLQZVEDXg=","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"lock":false,"isdefault":false}],"scrypt":{"n":16384,"r":8,"p":8},"extra":{"Tokens":null}}
|
||||
{
|
||||
"version" : "3.0",
|
||||
"extra" : {
|
||||
"Tokens" : null
|
||||
},
|
||||
"accounts" : [
|
||||
{
|
||||
"lock" : false,
|
||||
"isdefault" : false,
|
||||
"key" : "6PYRjaxsdSrW8zBzPynkC9uJRHpkhFHiQTuYY33gNL1wTimTbpN8S8eCNc",
|
||||
"address" : "NUSEsqon6PikQA5mDFaV4njemF9Su8JEmf",
|
||||
"contract" : {
|
||||
"parameters" : [
|
||||
{
|
||||
"type" : "Signature",
|
||||
"name" : "parameter0"
|
||||
}
|
||||
],
|
||||
"script" : "DCECl3UyEIq6T5RRIXS6z4tNdZPTzQ7NvXyx7FwK05d9UyZBdHR2qg==",
|
||||
"deployed" : false
|
||||
},
|
||||
"label" : "kek"
|
||||
}
|
||||
],
|
||||
"scrypt" : {
|
||||
"r" : 8,
|
||||
"p" : 8,
|
||||
"n" : 16384
|
||||
}
|
||||
}
|
||||
|
||||
|
|
24
cli/testdata/wallet1_solo.json
vendored
24
cli/testdata/wallet1_solo.json
vendored
|
@ -2,11 +2,11 @@
|
|||
"version": "3.0",
|
||||
"accounts": [
|
||||
{
|
||||
"address": "NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcILQZVEDXg=",
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcJBdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"isdefault": true
|
||||
},
|
||||
{
|
||||
"address": "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw==",
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -44,11 +44,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NVNvVRW5Q5naSx2k2iZm7xRgtRNGuZppAK",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NNudMSGzEoktFzdYGYoNb3bzHzbmM1genF",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EQwhArNiK/QBe9/jF8WK7V9MdT8ga324lgRvp9d0u8S/f43CEQtBE43vrw==",
|
||||
"script": "EQwhArNiK/QBe9/jF8WK7V9MdT8ga324lgRvp9d0u8S/f43CEUF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -61,11 +61,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address" : "NWTDxsHVde5qSjRkTRUAg6i8xC3JSWEC9k",
|
||||
"key" : "6PYXDze5Ak4HahYKygcNzk6n65ACjWdDCYLSuKgA5KG8vyMJSFboUNSiPD",
|
||||
"address" : "NTe3yHH5zsaEGvEHTsFRpCjTef6Aod4yb6",
|
||||
"key" : "6PYSgdjUPVjo3ZJLg2CsheXnEZzyvUuSm4jCtXP6X7FT82sAQHWt2wpu5A",
|
||||
"label" : "",
|
||||
"contract" : {
|
||||
"script" : "VwEAEUBXAANA",
|
||||
"script" : "VwEAEdsgQFcAA0A=",
|
||||
"deployed" : true,
|
||||
"parameters" : []
|
||||
},
|
||||
|
|
12
cli/testdata/wallets/testwallet_NEO3.json
vendored
12
cli/testdata/wallets/testwallet_NEO3.json
vendored
|
@ -2,11 +2,11 @@
|
|||
"version": "3.0",
|
||||
"accounts": [
|
||||
{
|
||||
"address": "NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcILQZVEDXg=",
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcJBdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw==",
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
|
|
@ -318,7 +318,7 @@ func TestWalletDump(t *testing.T) {
|
|||
w := new(wallet.Wallet)
|
||||
require.NoError(t, json.Unmarshal([]byte(rawStr), w))
|
||||
require.Equal(t, 1, len(w.Accounts))
|
||||
require.Equal(t, "NNuJqXDnRqvwgzhSzhH4jnVFWB1DyZ34EM", w.Accounts[0].Address)
|
||||
require.Equal(t, "NUSEsqon6PikQA5mDFaV4njemF9Su8JEmf", w.Accounts[0].Address)
|
||||
|
||||
t.Run("with decrypt", func(t *testing.T) {
|
||||
cmd = append(cmd, "--decrypt")
|
||||
|
@ -333,7 +333,7 @@ func TestWalletDump(t *testing.T) {
|
|||
w := new(wallet.Wallet)
|
||||
require.NoError(t, json.Unmarshal([]byte(rawStr), w))
|
||||
require.Equal(t, 1, len(w.Accounts))
|
||||
require.Equal(t, "NNuJqXDnRqvwgzhSzhH4jnVFWB1DyZ34EM", w.Accounts[0].Address)
|
||||
require.Equal(t, "NUSEsqon6PikQA5mDFaV4njemF9Su8JEmf", w.Accounts[0].Address)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -343,27 +343,27 @@ func TestDumpKeys(t *testing.T) {
|
|||
pubRegex := "^0[23][a-hA-H0-9]{64}$"
|
||||
t.Run("all", func(t *testing.T) {
|
||||
e.Run(t, cmd...)
|
||||
e.checkNextLine(t, "NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc")
|
||||
e.checkNextLine(t, "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo")
|
||||
e.checkNextLine(t, pubRegex)
|
||||
e.checkNextLine(t, "^\\s*$")
|
||||
e.checkNextLine(t, "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY")
|
||||
e.checkNextLine(t, "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6")
|
||||
for i := 0; i < 4; i++ {
|
||||
e.checkNextLine(t, pubRegex)
|
||||
}
|
||||
e.checkNextLine(t, "^\\s*$")
|
||||
e.checkNextLine(t, "NVNvVRW5Q5naSx2k2iZm7xRgtRNGuZppAK")
|
||||
e.checkNextLine(t, "NNudMSGzEoktFzdYGYoNb3bzHzbmM1genF")
|
||||
e.checkNextLine(t, pubRegex)
|
||||
e.checkEOF(t)
|
||||
})
|
||||
t.Run("simple signature", func(t *testing.T) {
|
||||
cmd := append(cmd, "--address", "NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc")
|
||||
cmd := append(cmd, "--address", "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo")
|
||||
e.Run(t, cmd...)
|
||||
e.checkNextLine(t, "simple signature contract")
|
||||
e.checkNextLine(t, pubRegex)
|
||||
e.checkEOF(t)
|
||||
})
|
||||
t.Run("3/4 multisig", func(t *testing.T) {
|
||||
cmd := append(cmd, "-a", "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY")
|
||||
cmd := append(cmd, "-a", "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6")
|
||||
e.Run(t, cmd...)
|
||||
e.checkNextLine(t, "3 out of 4 multisig contract")
|
||||
for i := 0; i < 4; i++ {
|
||||
|
@ -372,7 +372,7 @@ func TestDumpKeys(t *testing.T) {
|
|||
e.checkEOF(t)
|
||||
})
|
||||
t.Run("1/1 multisig", func(t *testing.T) {
|
||||
cmd := append(cmd, "--address", "NVNvVRW5Q5naSx2k2iZm7xRgtRNGuZppAK")
|
||||
cmd := append(cmd, "--address", "NNudMSGzEoktFzdYGYoNb3bzHzbmM1genF")
|
||||
e.Run(t, cmd...)
|
||||
e.checkNextLine(t, "1 out of 1 multisig contract")
|
||||
e.checkNextLine(t, pubRegex)
|
||||
|
|
|
@ -2,8 +2,8 @@ package timer
|
|||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/binary"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/util"
|
||||
|
@ -35,7 +35,7 @@ func _deploy(_ interface{}, isUpdate bool) {
|
|||
sh := runtime.GetCallingScriptHash()
|
||||
storage.Put(ctx, mgmtKey, sh)
|
||||
storage.Put(ctx, ticksKey, defaultTicks)
|
||||
i := binary.Itoa(defaultTicks, 10)
|
||||
i := std.Itoa(defaultTicks, 10)
|
||||
runtime.Log("Timer set to " + i + " ticks.")
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ func Tick() bool {
|
|||
return contract.Call(runtime.GetExecutingScriptHash(), "selfDestroy", contract.All).(bool)
|
||||
}
|
||||
storage.Put(ctx, ticksKey, ticksLeft)
|
||||
i := binary.Itoa(ticksLeft.(int), 10)
|
||||
i := std.Itoa(ticksLeft.(int), 10)
|
||||
runtime.Log(i + " ticks left.")
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -14,36 +14,36 @@ type Ktype struct {
|
|||
// Arr contains a set of known keys in Ktype format.
|
||||
var Arr = []Ktype{
|
||||
{
|
||||
Address: "NNWAo5vdVJz1oyCuNiaTBA3amBHnWCF4Yk",
|
||||
Address: "NQrEVKgpx2qEg6DpVMT5H8kFa7kc2DFgqS",
|
||||
PrivateKey: "7d128a6d096f0c14c3a25a2b0c41cf79661bfcb4a8cc95aaaea28bde4d732344",
|
||||
PublicKey: "02028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef",
|
||||
Wif: "L1QqQJnpBwbsPGAuutuzPTac8piqvbR1HRjrY5qHup48TBCBFe4g",
|
||||
Passphrase: "city of zion",
|
||||
EncryptedWif: "6PYSeMMbJtfMRD81eHzriwrRKquu2dgLNurYcAbmJa7YqAiThgA2vGQu5o",
|
||||
EncryptedWif: "6PYWaEBMd9UTVFKi1YahYXY5NMLDg9U6w2gpQYUnx8wvaFgdo8EeVPaD7o",
|
||||
},
|
||||
{
|
||||
Address: "NiwvMyWYeNghLG8tDyKkWwuZV3wS8CPrrV",
|
||||
Address: "NYaVsrMV9GS8aaspRS4odXf1WHZdMmJiPC",
|
||||
PrivateKey: "9ab7e154840daca3a2efadaf0df93cd3a5b51768c632f5433f86909d9b994a69",
|
||||
PublicKey: "031d8e1630ce640966967bc6d95223d21f44304133003140c3b52004dc981349c9",
|
||||
Wif: "L2QTooFoDFyRFTxmtiVHt5CfsXfVnexdbENGDkkrrgTTryiLsPMG",
|
||||
Passphrase: "我的密码",
|
||||
EncryptedWif: "6PYKWKaq5NMyjt8cjvnJnvmV13inhFuePpWZMkddFAMCgjC3ETt7kX16V9",
|
||||
EncryptedWif: "6PYUpn5uxTpsoawM3YKEWamk2oiKeafQBBK3Vutsowogy8a86jPu71xhE9",
|
||||
},
|
||||
{
|
||||
Address: "NTWHAzB82LRGWNuuqjVyyzpGvF3WxbbPoG",
|
||||
Address: "NWcpK2143ZjgzDYyQJhoKrodJUymHTxPzR",
|
||||
PrivateKey: "3edee7036b8fd9cef91de47386b191dd76db2888a553e7736bb02808932a915b",
|
||||
PublicKey: "02232ce8d2e2063dce0451131851d47421bfc4fc1da4db116fca5302c0756462fa",
|
||||
Wif: "KyKvWLZsNwBJx5j9nurHYRwhYfdQUu9tTEDsLCUHDbYBL8cHxMiG",
|
||||
Passphrase: "MyL33tP@33w0rd",
|
||||
EncryptedWif: "6PYSzKoJBQMj9uHUv1Sc2ZhMrydqDF8ZCTeE9FuPiNdEx7Lo9NoEuaXeyk",
|
||||
EncryptedWif: "6PYRbKt55d4NXxCESqk8n9kURqopvixEY5nhAYe2ZJ4c1oDWAjtFX8hd1M",
|
||||
},
|
||||
{
|
||||
Address: "xdf4UGKevVrMR1j3UkPsuoYKSC4ocoAkKx",
|
||||
PrivateKey: "zzdee7036b8fd9cef91de47386b191dd76db2888a553e7736bb02808932a915b",
|
||||
PublicKey: "zz232ce8d2e2063dce0451131851d47421bfc4fc1da4db116fca5302c0756462fa",
|
||||
Wif: "zzKvWLZsNwBJx5j9nurHYRwhYfdQUu9tTEDsLCUHDbYBL8cHxMiG",
|
||||
Passphrase: "zzL33tP@33w0rd",
|
||||
EncryptedWif: "6PYSzKoJBQMj9uHUv1Sc2ZhMrydqDF8ZCTeE9FuPiNdEx7Lo9NoEuaXeyk",
|
||||
Address: "NWcpK2143ZjgzDYyQJhoKrodJUymHTxPzR",
|
||||
PrivateKey: "3edee7036b8fd9cef91de47386b191dd76db2888a553e7736bb02808932a915",
|
||||
PublicKey: "02232ce8d2e2063dce0451131851d47421bfc4fc1da4db116fca5302c0756462fa",
|
||||
Wif: "KyKvWLZsNwBJx5j9nurHYRwhYfdQUu9tTEDsLCUHDbYBL8cHxMiS",
|
||||
Passphrase: "invalid_pass_but_valid_wif",
|
||||
EncryptedWif: "6PYRbKt55d4NXxCESqk8n9kURqopvixEY5nhAYe2ZJ4c1oDWAjtFX8hd1M",
|
||||
Invalid: true,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -49,44 +49,44 @@ func NewTransferFromOwner(bc blockchainer.Blockchainer, contractHash, to util.Ui
|
|||
}
|
||||
|
||||
// NewDeployTx returns new deployment tx for contract with name with Go code read from r.
|
||||
func NewDeployTx(bc blockchainer.Blockchainer, name string, sender util.Uint160, r gio.Reader) (*transaction.Transaction, util.Uint160, error) {
|
||||
func NewDeployTx(bc blockchainer.Blockchainer, name string, sender util.Uint160, r gio.Reader) (*transaction.Transaction, util.Uint160, []byte, error) {
|
||||
// nef.NewFile() cares about version a lot.
|
||||
config.Version = "0.90.0-test"
|
||||
|
||||
avm, di, err := compiler.CompileWithDebugInfo(name, r)
|
||||
if err != nil {
|
||||
return nil, util.Uint160{}, err
|
||||
return nil, util.Uint160{}, nil, err
|
||||
}
|
||||
|
||||
ne, err := nef.NewFile(avm)
|
||||
if err != nil {
|
||||
return nil, util.Uint160{}, err
|
||||
return nil, util.Uint160{}, nil, err
|
||||
}
|
||||
|
||||
m, err := di.ConvertToManifest(&compiler.Options{Name: name})
|
||||
if err != nil {
|
||||
return nil, util.Uint160{}, err
|
||||
return nil, util.Uint160{}, nil, err
|
||||
}
|
||||
|
||||
rawManifest, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return nil, util.Uint160{}, err
|
||||
return nil, util.Uint160{}, nil, err
|
||||
}
|
||||
neb, err := ne.Bytes()
|
||||
if err != nil {
|
||||
return nil, util.Uint160{}, err
|
||||
return nil, util.Uint160{}, nil, err
|
||||
}
|
||||
buf := io.NewBufBinWriter()
|
||||
emit.AppCall(buf.BinWriter, bc.ManagementContractHash(), "deploy", callflag.All, neb, rawManifest)
|
||||
if buf.Err != nil {
|
||||
return nil, util.Uint160{}, buf.Err
|
||||
return nil, util.Uint160{}, nil, buf.Err
|
||||
}
|
||||
|
||||
tx := transaction.New(Network(), buf.Bytes(), 100*native.GASFactor)
|
||||
tx.Signers = []transaction.Signer{{Account: sender}}
|
||||
h := state.CreateContractHash(tx.Sender(), ne.Checksum, name)
|
||||
|
||||
return tx, h, nil
|
||||
return tx, h, avm, nil
|
||||
}
|
||||
|
||||
// SignTx signs provided transactions with validator keys.
|
||||
|
|
|
@ -118,13 +118,14 @@ func TestInline(t *testing.T) {
|
|||
func TestInlineInLoop(t *testing.T) {
|
||||
t.Run("simple", func(t *testing.T) {
|
||||
src := `package foo
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/binary"
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
||||
import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/inline"
|
||||
func Main() int {
|
||||
sum := 0
|
||||
values := []int{10, 11}
|
||||
for _, v := range values {
|
||||
binary.Itoa(v, 10)
|
||||
_ = v // use 'v'
|
||||
storage.GetContext() // push something on stack to check it's dropped
|
||||
sum += inline.VarSum(1, 2, 3, 4)
|
||||
}
|
||||
return sum
|
||||
|
@ -133,14 +134,16 @@ func TestInlineInLoop(t *testing.T) {
|
|||
})
|
||||
t.Run("inlined argument", func(t *testing.T) {
|
||||
src := `package foo
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/binary"
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
||||
import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/inline"
|
||||
func Main() int {
|
||||
sum := 0
|
||||
values := []int{10, 11}
|
||||
for _, v := range values {
|
||||
binary.Itoa(v, 10)
|
||||
sum += inline.VarSum(1, 2, 3, binary.Atoi("4", 10))
|
||||
_ = v // use 'v'
|
||||
storage.GetContext() // push something on stack to check it's dropped
|
||||
sum += inline.VarSum(1, 2, 3, runtime.GetTime()) // runtime.GetTime always returns 4 in these tests
|
||||
}
|
||||
return sum
|
||||
}`
|
||||
|
@ -148,12 +151,12 @@ func TestInlineInLoop(t *testing.T) {
|
|||
})
|
||||
t.Run("check clean stack on return", func(t *testing.T) {
|
||||
src := `package foo
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/binary"
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
||||
import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/inline"
|
||||
func Main() int {
|
||||
values := []int{10, 11, 12}
|
||||
for _, v := range values {
|
||||
binary.Itoa(v, 10)
|
||||
storage.GetContext() // push something on stack to check it's dropped
|
||||
if v == 11 {
|
||||
return inline.VarSum(2, 20, 200)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/crypto"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/gas"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
|
||||
|
@ -18,6 +19,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/interop/native/oracle"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/policy"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/roles"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
@ -37,6 +39,8 @@ func TestContractHashes(t *testing.T) {
|
|||
require.Equal(t, []byte(ledger.Hash), cs.Ledger.Hash.BytesBE())
|
||||
require.Equal(t, []byte(management.Hash), cs.Management.Hash.BytesBE())
|
||||
require.Equal(t, []byte(notary.Hash), cs.Notary.Hash.BytesBE())
|
||||
require.Equal(t, []byte(crypto.Hash), cs.Crypto.Hash.BytesBE())
|
||||
require.Equal(t, []byte(std.Hash), cs.Std.Hash.BytesBE())
|
||||
}
|
||||
|
||||
// testPrintHash is a helper for updating contract hashes.
|
||||
|
@ -77,6 +81,11 @@ func TestNameServiceRecordType(t *testing.T) {
|
|||
require.EqualValues(t, native.RecordTypeAAAA, nameservice.TypeAAAA)
|
||||
}
|
||||
|
||||
func TestCryptoLibNamedCurve(t *testing.T) {
|
||||
require.EqualValues(t, native.Secp256k1, crypto.Secp256k1)
|
||||
require.EqualValues(t, native.Secp256r1, crypto.Secp256r1)
|
||||
}
|
||||
|
||||
type nativeTestCase struct {
|
||||
method string
|
||||
params []string
|
||||
|
@ -88,6 +97,7 @@ func TestNativeHelpersCompile(t *testing.T) {
|
|||
u160 := `interop.Hash160("aaaaaaaaaaaaaaaaaaaa")`
|
||||
u256 := `interop.Hash256("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")`
|
||||
pub := `interop.PublicKey("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")`
|
||||
sig := `interop.Signature("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")`
|
||||
nep17TestCases := []nativeTestCase{
|
||||
{"balanceOf", []string{u160}},
|
||||
{"decimals", nil},
|
||||
|
@ -176,6 +186,23 @@ func TestNativeHelpersCompile(t *testing.T) {
|
|||
{"update", []string{"nil", "nil"}},
|
||||
{"updateWithData", []string{"nil", "nil", "123"}},
|
||||
})
|
||||
runNativeTestCases(t, cs.Crypto.ContractMD, "crypto", []nativeTestCase{
|
||||
{"sha256", []string{"[]byte{1, 2, 3}"}},
|
||||
{"ripemd160", []string{"[]byte{1, 2, 3}"}},
|
||||
{"verifyWithECDsa", []string{"[]byte{1, 2, 3}", pub, sig, "crypto.Secp256k1"}},
|
||||
})
|
||||
runNativeTestCases(t, cs.Std.ContractMD, "std", []nativeTestCase{
|
||||
{"serialize", []string{"[]byte{1, 2, 3}"}},
|
||||
{"deserialize", []string{"[]byte{1, 2, 3}"}},
|
||||
{"jsonSerialize", []string{"[]byte{1, 2, 3}"}},
|
||||
{"jsonDeserialize", []string{"[]byte{1, 2, 3}"}},
|
||||
{"base64Encode", []string{"[]byte{1, 2, 3}"}},
|
||||
{"base64Decode", []string{"[]byte{1, 2, 3}"}},
|
||||
{"base58Encode", []string{"[]byte{1, 2, 3}"}},
|
||||
{"base58Decode", []string{"[]byte{1, 2, 3}"}},
|
||||
{"itoa", []string{"4", "10"}},
|
||||
{"atoi", []string{`"4"`, "10"}},
|
||||
})
|
||||
}
|
||||
|
||||
func runNativeTestCases(t *testing.T, ctr interop.ContractMD, name string, testCases []nativeTestCase) {
|
||||
|
@ -205,6 +232,7 @@ func runNativeTestCase(t *testing.T, ctr interop.ContractMD, name, method string
|
|||
}
|
||||
methodUpper := strings.ToUpper(method[:1]) + method[1:] // ASCII only
|
||||
methodUpper = strings.ReplaceAll(methodUpper, "Gas", "GAS")
|
||||
methodUpper = strings.ReplaceAll(methodUpper, "Json", "JSON")
|
||||
src := fmt.Sprintf(srcTmpl, name, name, methodUpper, strings.Join(params, ","))
|
||||
|
||||
v, s := vmAndCompileInterop(t, src)
|
||||
|
|
|
@ -61,24 +61,14 @@ func TestSyscallExecution(t *testing.T) {
|
|||
sigs := "[]interop.Signature{" + sig + "}"
|
||||
sctx := "storage.Context{}"
|
||||
interops := map[string]syscallTestCase{
|
||||
"binary.Atoi": {interopnames.SystemBinaryAtoi, []string{`"123"`, "10"}, false},
|
||||
"binary.Base58Decode": {interopnames.SystemBinaryBase58Decode, []string{b}, false},
|
||||
"binary.Base58Encode": {interopnames.SystemBinaryBase58Encode, []string{b}, false},
|
||||
"binary.Base64Decode": {interopnames.SystemBinaryBase64Decode, []string{b}, false},
|
||||
"binary.Base64Encode": {interopnames.SystemBinaryBase64Encode, []string{b}, false},
|
||||
"binary.Deserialize": {interopnames.SystemBinaryDeserialize, []string{b}, false},
|
||||
"binary.Itoa": {interopnames.SystemBinaryItoa, []string{"123", "10"}, false},
|
||||
"binary.Serialize": {interopnames.SystemBinarySerialize, []string{"10"}, false},
|
||||
"contract.Call": {interopnames.SystemContractCall, []string{u160, `"m"`, "1", "3"}, false},
|
||||
"contract.CreateMultisigAccount": {interopnames.SystemContractCreateMultisigAccount, []string{"1", pubs}, false},
|
||||
"contract.CreateStandardAccount": {interopnames.SystemContractCreateStandardAccount, []string{pub}, false},
|
||||
"contract.IsStandard": {interopnames.SystemContractIsStandard, []string{b}, false},
|
||||
"contract.IsStandard": {interopnames.SystemContractIsStandard, []string{u160}, false},
|
||||
"contract.GetCallFlags": {interopnames.SystemContractGetCallFlags, nil, false},
|
||||
"iterator.Create": {interopnames.SystemIteratorCreate, []string{pubs}, false},
|
||||
"iterator.Next": {interopnames.SystemIteratorNext, []string{"iterator.Iterator{}"}, false},
|
||||
"iterator.Value": {interopnames.SystemIteratorValue, []string{"iterator.Iterator{}"}, false},
|
||||
"json.FromJSON": {interopnames.SystemJSONDeserialize, []string{b}, false},
|
||||
"json.ToJSON": {interopnames.SystemJSONSerialize, []string{b}, false},
|
||||
"runtime.CheckWitness": {interopnames.SystemRuntimeCheckWitness, []string{b}, false},
|
||||
"runtime.GasLeft": {interopnames.SystemRuntimeGasLeft, nil, false},
|
||||
"runtime.GetCallingScriptHash": {interopnames.SystemRuntimeGetCallingScriptHash, nil, false},
|
||||
|
@ -99,12 +89,8 @@ func TestSyscallExecution(t *testing.T) {
|
|||
"storage.GetReadOnlyContext": {interopnames.SystemStorageGetReadOnlyContext, nil, false},
|
||||
"storage.Put": {interopnames.SystemStoragePut, []string{sctx, b, b}, true},
|
||||
"storage.ConvertContextToReadOnly": {interopnames.SystemStorageAsReadOnly, []string{sctx}, false},
|
||||
"crypto.ECDsaSecp256r1Verify": {interopnames.NeoCryptoVerifyWithECDsaSecp256r1, []string{b, pub, sig}, false},
|
||||
"crypto.ECDsaSecp256k1Verify": {interopnames.NeoCryptoVerifyWithECDsaSecp256k1, []string{b, pub, sig}, false},
|
||||
"crypto.ECDSASecp256r1CheckMultisig": {interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1, []string{b, pubs, sigs}, false},
|
||||
"crypto.ECDSASecp256k1CheckMultisig": {interopnames.NeoCryptoCheckMultisigWithECDsaSecp256k1, []string{b, pubs, sigs}, false},
|
||||
"crypto.SHA256": {interopnames.NeoCryptoSHA256, []string{b}, false},
|
||||
"crypto.RIPEMD160": {interopnames.NeoCryptoRIPEMD160, []string{b}, false},
|
||||
"crypto.CheckMultisig": {interopnames.NeoCryptoCheckMultisig, []string{pubs, sigs}, false},
|
||||
"crypto.CheckSig": {interopnames.NeoCryptoCheckSig, []string{pub, sig}, false},
|
||||
}
|
||||
ic := &interop.Context{}
|
||||
core.SpawnVM(ic) // set Functions field
|
||||
|
@ -209,20 +195,20 @@ func TestNotify(t *testing.T) {
|
|||
|
||||
func TestSyscallInGlobalInit(t *testing.T) {
|
||||
src := `package foo
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/binary"
|
||||
var a = binary.Base58Decode([]byte("5T"))
|
||||
func Main() []byte {
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||
var a = runtime.CheckWitness([]byte("5T"))
|
||||
func Main() bool {
|
||||
return a
|
||||
}`
|
||||
v, s := vmAndCompileInterop(t, src)
|
||||
s.interops[interopnames.ToID([]byte(interopnames.SystemBinaryBase58Decode))] = func(v *vm.VM) error {
|
||||
s.interops[interopnames.ToID([]byte(interopnames.SystemRuntimeCheckWitness))] = func(v *vm.VM) error {
|
||||
s := v.Estack().Pop().Value().([]byte)
|
||||
require.Equal(t, "5T", string(s))
|
||||
v.Estack().PushVal([]byte{1, 2})
|
||||
v.Estack().PushVal(true)
|
||||
return nil
|
||||
}
|
||||
require.NoError(t, v.Run())
|
||||
require.Equal(t, []byte{1, 2}, v.Estack().Pop().Value())
|
||||
require.Equal(t, true, v.Estack().Pop().Value())
|
||||
}
|
||||
|
||||
func TestOpcode(t *testing.T) {
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
package compiler_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/crypto"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSHA256(t *testing.T) {
|
||||
src := `
|
||||
package foo
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/crypto"
|
||||
)
|
||||
func Main() []byte {
|
||||
src := []byte{0x97}
|
||||
hash := crypto.SHA256(src)
|
||||
return hash
|
||||
}
|
||||
`
|
||||
v := vmAndCompile(t, src)
|
||||
ic := &interop.Context{Trigger: trigger.Verification}
|
||||
ic.VM = v
|
||||
crypto.Register(ic)
|
||||
v.SyscallHandler = ic.SyscallHandler
|
||||
require.NoError(t, v.Run())
|
||||
require.True(t, v.Estack().Len() >= 1)
|
||||
|
||||
h := []byte{0x2a, 0xa, 0xb7, 0x32, 0xb4, 0xe9, 0xd8, 0x5e, 0xf7, 0xdc, 0x25, 0x30, 0x3b, 0x64, 0xab, 0x52, 0x7c, 0x25, 0xa4, 0xd7, 0x78, 0x15, 0xeb, 0xb5, 0x79, 0xf3, 0x96, 0xec, 0x6c, 0xac, 0xca, 0xd3}
|
||||
require.Equal(t, h, v.PopResult())
|
||||
}
|
|
@ -16,11 +16,10 @@ import (
|
|||
func TestVerifyGood(t *testing.T) {
|
||||
msg := []byte("test message")
|
||||
pub, sig := signMessage(t, msg)
|
||||
src := getVerifyProg(pub, sig, msg)
|
||||
src := getVerifyProg(pub, sig)
|
||||
|
||||
v, p := vmAndCompileInterop(t, src)
|
||||
p.interops[interopnames.ToID([]byte(interopnames.NeoCryptoVerifyWithECDsaSecp256r1))] = func(v *vm.VM) error {
|
||||
assert.Equal(t, msg, v.Estack().Pop().Bytes())
|
||||
p.interops[interopnames.ToID([]byte(interopnames.NeoCryptoCheckSig))] = func(v *vm.VM) error {
|
||||
assert.Equal(t, pub, v.Estack().Pop().Bytes())
|
||||
assert.Equal(t, sig, v.Estack().Pop().Bytes())
|
||||
v.Estack().PushVal(true)
|
||||
|
@ -40,10 +39,9 @@ func signMessage(t *testing.T, msg []byte) ([]byte, []byte) {
|
|||
return pub, sig
|
||||
}
|
||||
|
||||
func getVerifyProg(pub, sig, msg []byte) string {
|
||||
func getVerifyProg(pub, sig []byte) string {
|
||||
pubS := fmt.Sprintf("%#v", pub)
|
||||
sigS := fmt.Sprintf("%#v", sig)
|
||||
msgS := fmt.Sprintf("%#v", msg)
|
||||
|
||||
return `
|
||||
package hello
|
||||
|
@ -53,8 +51,7 @@ func getVerifyProg(pub, sig, msg []byte) string {
|
|||
func Main() bool {
|
||||
pub := ` + pubS + `
|
||||
sig := ` + sigS + `
|
||||
msg := ` + msgS + `
|
||||
return crypto.ECDsaSecp256r1Verify(msg, pub, sig)
|
||||
return crypto.CheckSig(pub, sig)
|
||||
}
|
||||
`
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ package compiler_test
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -109,8 +107,7 @@ func newStoragePlugin() *storagePlugin {
|
|||
s.interops[interopnames.ToID([]byte(interopnames.SystemStoragePut))] = s.Put
|
||||
s.interops[interopnames.ToID([]byte(interopnames.SystemStorageGetContext))] = s.GetContext
|
||||
s.interops[interopnames.ToID([]byte(interopnames.SystemRuntimeNotify))] = s.Notify
|
||||
s.interops[interopnames.ToID([]byte(interopnames.SystemBinaryAtoi))] = s.Atoi
|
||||
s.interops[interopnames.ToID([]byte(interopnames.SystemBinaryItoa))] = s.Itoa
|
||||
s.interops[interopnames.ToID([]byte(interopnames.SystemRuntimeGetTime))] = s.GetTime
|
||||
return s
|
||||
|
||||
}
|
||||
|
@ -126,24 +123,6 @@ func (s *storagePlugin) syscallHandler(v *vm.VM, id uint32) error {
|
|||
return errors.New("syscall not found")
|
||||
}
|
||||
|
||||
func (s *storagePlugin) Atoi(v *vm.VM) error {
|
||||
str := v.Estack().Pop().String()
|
||||
base := v.Estack().Pop().BigInt().Int64()
|
||||
n, err := strconv.ParseInt(str, int(base), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Estack().PushVal(big.NewInt(n))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *storagePlugin) Itoa(v *vm.VM) error {
|
||||
n := v.Estack().Pop().BigInt()
|
||||
base := v.Estack().Pop().BigInt()
|
||||
v.Estack().PushVal(n.Text(int(base.Int64())))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *storagePlugin) Notify(v *vm.VM) error {
|
||||
name := v.Estack().Pop().String()
|
||||
item := stackitem.NewArray(v.Estack().Pop().Array())
|
||||
|
@ -185,3 +164,10 @@ func (s *storagePlugin) GetContext(vm *vm.VM) error {
|
|||
vm.Estack().PushVal(10)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *storagePlugin) GetTime(vm *vm.VM) error {
|
||||
// Pushing anything on the stack here will work. This is just to satisfy
|
||||
// the compiler, thinking it has pushed the context ^^.
|
||||
vm.Estack().PushVal(4)
|
||||
return nil
|
||||
}
|
||||
|
|
29
pkg/consensus/testdata/wallet1.json
vendored
29
pkg/consensus/testdata/wallet1.json
vendored
|
@ -2,11 +2,11 @@
|
|||
"version": "3.0",
|
||||
"accounts": [
|
||||
{
|
||||
"address": "NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcILQZVEDXg=",
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcJBdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw==",
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -42,23 +42,6 @@
|
|||
},
|
||||
"lock": false,
|
||||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NVNvVRW5Q5naSx2k2iZm7xRgtRNGuZppAK",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EQwhArNiK/QBe9/jF8WK7V9MdT8ga324lgRvp9d0u8S/f43CEQtBE43vrw==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
"type": "Signature"
|
||||
}
|
||||
],
|
||||
"deployed": false
|
||||
},
|
||||
"lock": false,
|
||||
"isdefault": false
|
||||
}
|
||||
],
|
||||
"scrypt": {
|
||||
|
|
12
pkg/consensus/testdata/wallet2.json
vendored
12
pkg/consensus/testdata/wallet2.json
vendored
|
@ -2,11 +2,11 @@
|
|||
"version": "3.0",
|
||||
"accounts": [
|
||||
{
|
||||
"address": "NWvKSwutC8D6VKmmPxAEgFKx2NLvFhn8q5",
|
||||
"key": "6PYKEHagXJ3mDLdga1FoyTGRtPdJgPz6Gb8sjEFwZvRu7ncD9PVZfHtMzL",
|
||||
"address": "NUREbqw2kfbPgDeEz8Dac2QxntGGqqFMm7",
|
||||
"key": "6PYXADog3RQCwKRhqQsobwZEFopdcCJuMfPosM9pXPaDWSguKvznLdpADk",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCECEDp/fdAWVYWX95YNJ8UWpDlP2Wi55lFV60sBPkBAQG4LQZVEDXg=",
|
||||
"script": "DCECEDp/fdAWVYWX95YNJ8UWpDlP2Wi55lFV60sBPkBAQG5BdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
|
||||
"key": "6PYKEHagXJ3mDLdga1FoyTGRtPdJgPz6Gb8sjEFwZvRu7ncD9PVZfHtMzL",
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYXADog3RQCwKRhqQsobwZEFopdcCJuMfPosM9pXPaDWSguKvznLdpADk",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw==",
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
|
12
pkg/consensus/testdata/wallet3.json
vendored
12
pkg/consensus/testdata/wallet3.json
vendored
|
@ -2,11 +2,11 @@
|
|||
"version": "3.0",
|
||||
"accounts": [
|
||||
{
|
||||
"address": "NNB3RsnTABEwoKEudNG92njds91WtiCuxd",
|
||||
"key": "6PYLjn1Zw3RQmP3CkDxoZvYtMpu7ZUdjHnvu7wPuohUcXWCMh9vY661R8A",
|
||||
"address": "NQP81vKVRmwZHveX8C9Rbf2qejSpT1W1Eu",
|
||||
"key": "6PYScv3Vgvdi9EkhDNvHXdvQeuaXK9gRwXDmytCswZMNpTzMLvfgR3U5dK",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCED2QwH32PmkM53kS4Qq1GsyUS2aGAje2CMT4+DCece5pkLQZVEDXg=",
|
||||
"script": "DCED2QwH32PmkM53kS4Qq1GsyUS2aGAje2CMT4+DCece5plBdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
|
||||
"key": "6PYLjn1Zw3RQmP3CkDxoZvYtMpu7ZUdjHnvu7wPuohUcXWCMh9vY661R8A",
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYScv3Vgvdi9EkhDNvHXdvQeuaXK9gRwXDmytCswZMNpTzMLvfgR3U5dK",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw==",
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
|
12
pkg/consensus/testdata/wallet4.json
vendored
12
pkg/consensus/testdata/wallet4.json
vendored
|
@ -2,11 +2,11 @@
|
|||
"version": "3.0",
|
||||
"accounts": [
|
||||
{
|
||||
"address": "Nfzo95iBXfeAGx5rdjPedZRAqHKh9hwMdR",
|
||||
"key": "6PYLbYYg9jUgzJQpKhpvNExa2UEgtp4356XPg56pHuCpE7gQmj84ESNjYW",
|
||||
"address": "NLA34vf8eXGGUhRjVaYe5f8YsyYHTehbDZ",
|
||||
"key": "6PYVwp1Sdg9DfTzvg42PZxgzMDf5a5FYBgT6ynKKzwmSHuhGkipoNjyW3a",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWILQZVEDXg=",
|
||||
"script": "DCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWJBdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
|
||||
"key": "6PYLbYYg9jUgzJQpKhpvNExa2UEgtp4356XPg56pHuCpE7gQmj84ESNjYW",
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYVwp1Sdg9DfTzvg42PZxgzMDf5a5FYBgT6ynKKzwmSHuhGkipoNjyW3a",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw==",
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
|
|
@ -1229,7 +1229,7 @@ func TestIsTxStillRelevant(t *testing.T) {
|
|||
currentHeight := contract.Call(addr, "currentIndex", contract.ReadStates)
|
||||
return currentHeight.(int) < %d
|
||||
}`, bc.BlockHeight()+2) // deploy + next block
|
||||
txDeploy, h, err := testchain.NewDeployTx(bc, "TestVerify", neoOwner, strings.NewReader(src))
|
||||
txDeploy, h, _, err := testchain.NewDeployTx(bc, "TestVerify", neoOwner, strings.NewReader(src))
|
||||
require.NoError(t, err)
|
||||
txDeploy.ValidUntilBlock = bc.BlockHeight() + 1
|
||||
addSigners(neoOwner, txDeploy)
|
||||
|
|
|
@ -18,13 +18,13 @@ func Calculate(base int64, script []byte) (int64, int) {
|
|||
)
|
||||
if vm.IsSignatureContract(script) {
|
||||
size += 67 + io.GetVarSize(script)
|
||||
netFee += Opcode(base, opcode.PUSHDATA1, opcode.PUSHNULL, opcode.PUSHDATA1) + base*ECDSAVerifyPrice
|
||||
netFee += Opcode(base, opcode.PUSHDATA1, opcode.PUSHDATA1) + base*ECDSAVerifyPrice
|
||||
} else if m, pubs, ok := vm.ParseMultiSigContract(script); ok {
|
||||
n := len(pubs)
|
||||
sizeInv := 66 * m
|
||||
size += io.GetVarSize(sizeInv) + sizeInv + io.GetVarSize(script)
|
||||
netFee += calculateMultisig(base, m) + calculateMultisig(base, n)
|
||||
netFee += Opcode(base, opcode.PUSHNULL) + base*ECDSAVerifyPrice*int64(n)
|
||||
netFee += base * ECDSAVerifyPrice * int64(n)
|
||||
} else {
|
||||
// We can support more contract types in the future.
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package core
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
@ -268,7 +269,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
require.NoError(t, acc0.SignTx(txSendRaw))
|
||||
bw := io.NewBufBinWriter()
|
||||
txSendRaw.EncodeBinary(bw.BinWriter)
|
||||
t.Logf("sendrawtransaction: %s", hex.EncodeToString(bw.Bytes()))
|
||||
t.Logf("sendrawtransaction: %s", base64.StdEncoding.EncodeToString(bw.Bytes()))
|
||||
require.False(t, saveChain)
|
||||
}
|
||||
|
||||
|
@ -449,6 +450,9 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
|
|||
require.NoError(t, ntr.Accounts[0].Decrypt("one"))
|
||||
bc.setNodesByRole(t, true, native.RoleP2PNotary, keys.PublicKeys{ntr.Accounts[0].PrivateKey().PublicKey()})
|
||||
t.Logf("Designated Notary node: %s", hex.EncodeToString(ntr.Accounts[0].PrivateKey().PublicKey().Bytes()))
|
||||
|
||||
// Compile contract to test `invokescript` RPC call
|
||||
_, _ = newDeployTx(t, bc, priv0ScriptHash, prefix+"invokescript_contract.go", "ContractForInvokescriptTest")
|
||||
}
|
||||
|
||||
func newNEP17Transfer(sc, from, to util.Uint160, amount int64, additionalArgs ...interface{}) *transaction.Transaction {
|
||||
|
@ -466,9 +470,9 @@ func newNEP17Transfer(sc, from, to util.Uint160, amount int64, additionalArgs ..
|
|||
func newDeployTx(t *testing.T, bc *Blockchain, sender util.Uint160, name, ctrName string) (*transaction.Transaction, util.Uint160) {
|
||||
c, err := ioutil.ReadFile(name)
|
||||
require.NoError(t, err)
|
||||
tx, h, err := testchain.NewDeployTx(bc, ctrName, sender, bytes.NewReader(c))
|
||||
tx, h, avm, err := testchain.NewDeployTx(bc, ctrName, sender, bytes.NewReader(c))
|
||||
require.NoError(t, err)
|
||||
t.Logf("contractHash (%s): %s", name, h.StringLE())
|
||||
t.Logf("contract (%s): \n\tHash: %s\n\tAVM: %s", name, h.StringLE(), base64.StdEncoding.EncodeToString(avm))
|
||||
return tx, h
|
||||
}
|
||||
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
package binary
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/mr-tron/base58"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
)
|
||||
|
||||
// Serialize serializes top stack item into a ByteArray.
|
||||
func Serialize(ic *interop.Context) error {
|
||||
return vm.RuntimeSerialize(ic.VM)
|
||||
}
|
||||
|
||||
// Deserialize deserializes ByteArray from a stack into an item.
|
||||
func Deserialize(ic *interop.Context) error {
|
||||
return vm.RuntimeDeserialize(ic.VM)
|
||||
}
|
||||
|
||||
// EncodeBase64 encodes top stack item into a base64 string.
|
||||
func EncodeBase64(ic *interop.Context) error {
|
||||
src := ic.VM.Estack().Pop().Bytes()
|
||||
result := base64.StdEncoding.EncodeToString(src)
|
||||
ic.VM.Estack().PushVal([]byte(result))
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeBase64 decodes top stack item from base64 string to byte array.
|
||||
func DecodeBase64(ic *interop.Context) error {
|
||||
src := ic.VM.Estack().Pop().String()
|
||||
result, err := base64.StdEncoding.DecodeString(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ic.VM.Estack().PushVal(result)
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeBase58 encodes top stack item into a base58 string.
|
||||
func EncodeBase58(ic *interop.Context) error {
|
||||
src := ic.VM.Estack().Pop().Bytes()
|
||||
result := base58.Encode(src)
|
||||
ic.VM.Estack().PushVal([]byte(result))
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeBase58 decodes top stack item from base58 string to byte array.
|
||||
func DecodeBase58(ic *interop.Context) error {
|
||||
src := ic.VM.Estack().Pop().String()
|
||||
result, err := base58.Decode(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ic.VM.Estack().PushVal(result)
|
||||
return nil
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
package binary
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/mr-tron/base58"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRuntimeSerialize(t *testing.T) {
|
||||
t.Run("recursive", func(t *testing.T) {
|
||||
arr := stackitem.NewArray(nil)
|
||||
arr.Append(arr)
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
ic.VM.Estack().PushVal(arr)
|
||||
require.Error(t, Serialize(ic))
|
||||
})
|
||||
t.Run("big item", func(t *testing.T) {
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
ic.VM.Estack().PushVal(make([]byte, stackitem.MaxSize))
|
||||
require.Error(t, Serialize(ic))
|
||||
})
|
||||
t.Run("good", func(t *testing.T) {
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
ic.VM.Estack().PushVal(42)
|
||||
require.NoError(t, Serialize(ic))
|
||||
|
||||
w := io.NewBufBinWriter()
|
||||
stackitem.EncodeBinaryStackItem(stackitem.Make(42), w.BinWriter)
|
||||
require.NoError(t, w.Err)
|
||||
|
||||
encoded := w.Bytes()
|
||||
require.Equal(t, encoded, ic.VM.Estack().Pop().Bytes())
|
||||
|
||||
ic.VM.Estack().PushVal(encoded)
|
||||
require.NoError(t, Deserialize(ic))
|
||||
require.Equal(t, big.NewInt(42), ic.VM.Estack().Pop().BigInt())
|
||||
|
||||
t.Run("bad", func(t *testing.T) {
|
||||
encoded[0] ^= 0xFF
|
||||
ic.VM.Estack().PushVal(encoded)
|
||||
require.Error(t, Deserialize(ic))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestRuntimeEncodeDecode(t *testing.T) {
|
||||
original := []byte("my pretty string")
|
||||
encoded64 := base64.StdEncoding.EncodeToString(original)
|
||||
encoded58 := base58.Encode(original)
|
||||
v := vm.New()
|
||||
ic := &interop.Context{VM: v}
|
||||
|
||||
t.Run("Encode64", func(t *testing.T) {
|
||||
v.Estack().PushVal(original)
|
||||
require.NoError(t, EncodeBase64(ic))
|
||||
actual := v.Estack().Pop().Bytes()
|
||||
require.Equal(t, []byte(encoded64), actual)
|
||||
})
|
||||
t.Run("Encode58", func(t *testing.T) {
|
||||
v.Estack().PushVal(original)
|
||||
require.NoError(t, EncodeBase58(ic))
|
||||
actual := v.Estack().Pop().Bytes()
|
||||
require.Equal(t, []byte(encoded58), actual)
|
||||
})
|
||||
t.Run("Decode64/positive", func(t *testing.T) {
|
||||
v.Estack().PushVal(encoded64)
|
||||
require.NoError(t, DecodeBase64(ic))
|
||||
actual := v.Estack().Pop().Bytes()
|
||||
require.Equal(t, original, actual)
|
||||
})
|
||||
t.Run("Decode64/error", func(t *testing.T) {
|
||||
v.Estack().PushVal(encoded64 + "%")
|
||||
require.Error(t, DecodeBase64(ic))
|
||||
})
|
||||
t.Run("Decode58/positive", func(t *testing.T) {
|
||||
v.Estack().PushVal(encoded58)
|
||||
require.NoError(t, DecodeBase58(ic))
|
||||
actual := v.Estack().Pop().Bytes()
|
||||
require.Equal(t, original, actual)
|
||||
})
|
||||
t.Run("Decode58/error", func(t *testing.T) {
|
||||
v.Estack().PushVal(encoded58 + "%")
|
||||
require.Error(t, DecodeBase58(ic))
|
||||
})
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package binary
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidBase is returned when base is invalid.
|
||||
ErrInvalidBase = errors.New("invalid base")
|
||||
// ErrInvalidFormat is returned when string is not a number.
|
||||
ErrInvalidFormat = errors.New("invalid format")
|
||||
)
|
||||
|
||||
// Itoa converts number to string.
|
||||
func Itoa(ic *interop.Context) error {
|
||||
num := ic.VM.Estack().Pop().BigInt()
|
||||
base := ic.VM.Estack().Pop().BigInt()
|
||||
if !base.IsInt64() {
|
||||
return ErrInvalidBase
|
||||
}
|
||||
var s string
|
||||
switch b := base.Int64(); b {
|
||||
case 10:
|
||||
s = num.Text(10)
|
||||
case 16:
|
||||
if num.Sign() == 0 {
|
||||
s = "0"
|
||||
break
|
||||
}
|
||||
bs := bigint.ToBytes(num)
|
||||
reverse(bs)
|
||||
s = hex.EncodeToString(bs)
|
||||
if pad := bs[0] & 0xF8; pad == 0 || pad == 0xF8 {
|
||||
s = s[1:]
|
||||
}
|
||||
s = strings.ToUpper(s)
|
||||
default:
|
||||
return ErrInvalidBase
|
||||
}
|
||||
ic.VM.Estack().PushVal(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Atoi converts string to number.
|
||||
func Atoi(ic *interop.Context) error {
|
||||
num := ic.VM.Estack().Pop().String()
|
||||
base := ic.VM.Estack().Pop().BigInt()
|
||||
if !base.IsInt64() {
|
||||
return ErrInvalidBase
|
||||
}
|
||||
var bi *big.Int
|
||||
switch b := base.Int64(); b {
|
||||
case 10:
|
||||
var ok bool
|
||||
bi, ok = new(big.Int).SetString(num, int(b))
|
||||
if !ok {
|
||||
return ErrInvalidFormat
|
||||
}
|
||||
case 16:
|
||||
changed := len(num)%2 != 0
|
||||
if changed {
|
||||
num = "0" + num
|
||||
}
|
||||
bs, err := hex.DecodeString(num)
|
||||
if err != nil {
|
||||
return ErrInvalidFormat
|
||||
}
|
||||
if changed && bs[0]&0x8 != 0 {
|
||||
bs[0] |= 0xF0
|
||||
}
|
||||
reverse(bs)
|
||||
bi = bigint.FromBytes(bs)
|
||||
default:
|
||||
return ErrInvalidBase
|
||||
}
|
||||
ic.VM.Estack().PushVal(bi)
|
||||
return nil
|
||||
}
|
||||
|
||||
func reverse(b []byte) {
|
||||
l := len(b)
|
||||
for i := 0; i < l/2; i++ {
|
||||
b[i], b[l-i-1] = b[l-i-1], b[i]
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
package binary
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestItoa(t *testing.T) {
|
||||
var testCases = []struct {
|
||||
num *big.Int
|
||||
base *big.Int
|
||||
result string
|
||||
}{
|
||||
{big.NewInt(0), big.NewInt(10), "0"},
|
||||
{big.NewInt(0), big.NewInt(16), "0"},
|
||||
{big.NewInt(1), big.NewInt(10), "1"},
|
||||
{big.NewInt(-1), big.NewInt(10), "-1"},
|
||||
{big.NewInt(1), big.NewInt(16), "1"},
|
||||
{big.NewInt(7), big.NewInt(16), "7"},
|
||||
{big.NewInt(8), big.NewInt(16), "08"},
|
||||
{big.NewInt(65535), big.NewInt(16), "0FFFF"},
|
||||
{big.NewInt(15), big.NewInt(16), "0F"},
|
||||
{big.NewInt(-1), big.NewInt(16), "F"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
ic.VM.Estack().PushVal(tc.base)
|
||||
ic.VM.Estack().PushVal(tc.num)
|
||||
require.NoError(t, Itoa(ic))
|
||||
require.Equal(t, tc.result, ic.VM.Estack().Pop().String())
|
||||
|
||||
ic = &interop.Context{VM: vm.New()}
|
||||
ic.VM.Estack().PushVal(tc.base)
|
||||
ic.VM.Estack().PushVal(tc.result)
|
||||
|
||||
require.NoError(t, Atoi(ic))
|
||||
require.Equal(t, tc.num, ic.VM.Estack().Pop().BigInt())
|
||||
}
|
||||
|
||||
t.Run("-1", func(t *testing.T) {
|
||||
for _, s := range []string{"FF", "FFF", "FFFF"} {
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
ic.VM.Estack().PushVal(16)
|
||||
ic.VM.Estack().PushVal(s)
|
||||
|
||||
require.NoError(t, Atoi(ic))
|
||||
require.Equal(t, big.NewInt(-1), ic.VM.Estack().Pop().BigInt())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestItoaError(t *testing.T) {
|
||||
var testCases = []struct {
|
||||
num *big.Int
|
||||
base *big.Int
|
||||
err error
|
||||
}{
|
||||
{big.NewInt(1), big.NewInt(13), ErrInvalidBase},
|
||||
{big.NewInt(-1), new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(10)), ErrInvalidBase},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
ic.VM.Estack().PushVal(tc.base)
|
||||
ic.VM.Estack().PushVal(tc.num)
|
||||
err := Itoa(ic)
|
||||
require.True(t, errors.Is(err, tc.err), "got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAtoiError(t *testing.T) {
|
||||
var testCases = []struct {
|
||||
num string
|
||||
base *big.Int
|
||||
err error
|
||||
}{
|
||||
{"1", big.NewInt(13), ErrInvalidBase},
|
||||
{"1", new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(16)), ErrInvalidBase},
|
||||
{"1_000", big.NewInt(10), ErrInvalidFormat},
|
||||
{"FE", big.NewInt(10), ErrInvalidFormat},
|
||||
{"XD", big.NewInt(16), ErrInvalidFormat},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
ic.VM.Estack().PushVal(tc.base)
|
||||
ic.VM.Estack().PushVal(tc.num)
|
||||
err := Atoi(ic)
|
||||
require.True(t, errors.Is(err, tc.err), "got: %v", err)
|
||||
}
|
||||
}
|
|
@ -5,64 +5,16 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// ECDSASecp256r1Verify checks ECDSA signature using Secp256r1 elliptic curve.
|
||||
func ECDSASecp256r1Verify(ic *interop.Context) error {
|
||||
return ecdsaVerify(ic, elliptic.P256())
|
||||
}
|
||||
|
||||
// ECDSASecp256k1Verify checks ECDSA signature using Secp256k1 elliptic curve
|
||||
func ECDSASecp256k1Verify(ic *interop.Context) error {
|
||||
return ecdsaVerify(ic, btcec.S256())
|
||||
}
|
||||
|
||||
// ecdsaVerify is internal representation of ECDSASecp256k1Verify and
|
||||
// ECDSASecp256r1Verify.
|
||||
func ecdsaVerify(ic *interop.Context, curve elliptic.Curve) error {
|
||||
hashToCheck, err := getMessageHash(ic, ic.VM.Estack().Pop().Item())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keyb := ic.VM.Estack().Pop().Bytes()
|
||||
signature := ic.VM.Estack().Pop().Bytes()
|
||||
pkey, err := keys.NewPublicKeyFromBytes(keyb, curve)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res := pkey.Verify(signature, hashToCheck.BytesBE())
|
||||
ic.VM.Estack().PushVal(res)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ECDSASecp256r1CheckMultisig checks multiple ECDSA signatures at once using
|
||||
// Secp256r1 elliptic curve.
|
||||
func ECDSASecp256r1CheckMultisig(ic *interop.Context) error {
|
||||
return ecdsaCheckMultisig(ic, elliptic.P256())
|
||||
}
|
||||
|
||||
// ECDSASecp256k1CheckMultisig checks multiple ECDSA signatures at once using
|
||||
// Secp256k1 elliptic curve.
|
||||
func ECDSASecp256k1CheckMultisig(ic *interop.Context) error {
|
||||
return ecdsaCheckMultisig(ic, btcec.S256())
|
||||
}
|
||||
|
||||
// ecdsaCheckMultisig is internal representation of ECDSASecp256r1CheckMultisig and
|
||||
// ECDSASecp256k1CheckMultisig
|
||||
func ecdsaCheckMultisig(ic *interop.Context, curve elliptic.Curve) error {
|
||||
hashToCheck, err := getMessageHash(ic, ic.VM.Estack().Pop().Item())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hashToCheck := ic.Container.GetSignedHash()
|
||||
pkeys, err := ic.VM.Estack().PopSigElements()
|
||||
if err != nil {
|
||||
return fmt.Errorf("wrong parameters: %w", err)
|
||||
|
@ -79,23 +31,21 @@ func ecdsaCheckMultisig(ic *interop.Context, curve elliptic.Curve) error {
|
|||
if len(pkeys) < len(sigs) {
|
||||
return errors.New("more signatures than there are keys")
|
||||
}
|
||||
sigok := vm.CheckMultisigPar(ic.VM, curve, hashToCheck.BytesBE(), pkeys, sigs)
|
||||
sigok := vm.CheckMultisigPar(ic.VM, elliptic.P256(), hashToCheck.BytesBE(), pkeys, sigs)
|
||||
ic.VM.Estack().PushVal(sigok)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getMessageHash(ic *interop.Context, item stackitem.Item) (util.Uint256, error) {
|
||||
var msg []byte
|
||||
switch val := item.(type) {
|
||||
case *stackitem.Interop:
|
||||
return val.Value().(crypto.Verifiable).GetSignedHash(), nil
|
||||
case stackitem.Null:
|
||||
return ic.Container.GetSignedHash(), nil
|
||||
default:
|
||||
var err error
|
||||
if msg, err = val.TryBytes(); err != nil {
|
||||
return util.Uint256{}, err
|
||||
// ECDSASecp256r1CheckSig checks ECDSA signature using Secp256r1 elliptic curve.
|
||||
func ECDSASecp256r1CheckSig(ic *interop.Context) error {
|
||||
hashToCheck := ic.Container.GetSignedHash()
|
||||
keyb := ic.VM.Estack().Pop().Bytes()
|
||||
signature := ic.VM.Estack().Pop().Bytes()
|
||||
pkey, err := keys.NewPublicKeyFromBytes(keyb, elliptic.P256())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return hash.Sha256(msg), nil
|
||||
res := pkey.Verify(signature, hashToCheck.BytesBE())
|
||||
ic.VM.Estack().PushVal(res)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
|
@ -20,116 +21,14 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestECDSASecp256r1Verify(t *testing.T) {
|
||||
testECDSAVerify(t, true)
|
||||
}
|
||||
|
||||
func TestECDSASecp256k1Verify(t *testing.T) {
|
||||
testECDSAVerify(t, false)
|
||||
}
|
||||
|
||||
func testECDSAVerify(t *testing.T, isR1 bool) {
|
||||
var priv *keys.PrivateKey
|
||||
var err error
|
||||
if isR1 {
|
||||
priv, err = keys.NewPrivateKey()
|
||||
} else {
|
||||
priv, err = keys.NewSecp256k1PrivateKey()
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
verifyFunc := ECDSASecp256r1Verify
|
||||
if !isR1 {
|
||||
verifyFunc = ECDSASecp256k1Verify
|
||||
}
|
||||
d := dao.NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet, false)
|
||||
ic := &interop.Context{DAO: dao.NewCached(d)}
|
||||
runCase := func(t *testing.T, isErr bool, result interface{}, args ...interface{}) {
|
||||
ic.SpawnVM()
|
||||
for i := range args {
|
||||
ic.VM.Estack().PushVal(args[i])
|
||||
}
|
||||
|
||||
var err error
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("panic: %v", r)
|
||||
}
|
||||
}()
|
||||
err = verifyFunc(ic)
|
||||
}()
|
||||
|
||||
if isErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, ic.VM.Estack().Len())
|
||||
require.Equal(t, result, ic.VM.Estack().Pop().Value().(bool))
|
||||
}
|
||||
|
||||
msg := []byte("test message")
|
||||
|
||||
t.Run("success", func(t *testing.T) {
|
||||
sign := priv.Sign(msg)
|
||||
runCase(t, false, true, sign, priv.PublicKey().Bytes(), msg)
|
||||
})
|
||||
|
||||
t.Run("signed interop item", func(t *testing.T) {
|
||||
tx := transaction.New(netmode.UnitTestNet, []byte{0, 1, 2}, 1)
|
||||
msg := tx.GetSignedPart()
|
||||
sign := priv.Sign(msg)
|
||||
runCase(t, false, true, sign, priv.PublicKey().Bytes(), stackitem.NewInterop(tx))
|
||||
})
|
||||
|
||||
t.Run("signed script container", func(t *testing.T) {
|
||||
tx := transaction.New(netmode.UnitTestNet, []byte{0, 1, 2}, 1)
|
||||
msg := tx.GetSignedPart()
|
||||
sign := priv.Sign(msg)
|
||||
ic.Container = tx
|
||||
runCase(t, false, true, sign, priv.PublicKey().Bytes(), stackitem.Null{})
|
||||
})
|
||||
|
||||
t.Run("missing arguments", func(t *testing.T) {
|
||||
runCase(t, true, false)
|
||||
sign := priv.Sign(msg)
|
||||
runCase(t, true, false, sign)
|
||||
runCase(t, true, false, sign, priv.PublicKey().Bytes())
|
||||
})
|
||||
|
||||
t.Run("invalid signature", func(t *testing.T) {
|
||||
sign := priv.Sign(msg)
|
||||
sign[0] = ^sign[0]
|
||||
runCase(t, false, false, sign, priv.PublicKey().Bytes(), msg)
|
||||
})
|
||||
|
||||
t.Run("invalid public key", func(t *testing.T) {
|
||||
sign := priv.Sign(msg)
|
||||
pub := priv.PublicKey().Bytes()
|
||||
pub[0] = 0xFF // invalid prefix
|
||||
runCase(t, true, false, sign, pub, msg)
|
||||
})
|
||||
|
||||
t.Run("invalid message", func(t *testing.T) {
|
||||
sign := priv.Sign(msg)
|
||||
runCase(t, true, false, sign, priv.PublicKey().Bytes(),
|
||||
stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(msg)}))
|
||||
})
|
||||
}
|
||||
|
||||
func initCHECKMULTISIG(isR1 bool, msg []byte, n int) ([]stackitem.Item, []stackitem.Item, map[string]*keys.PublicKey, error) {
|
||||
func initCHECKMULTISIG(msg []byte, n int) ([]stackitem.Item, []stackitem.Item, map[string]*keys.PublicKey, error) {
|
||||
var err error
|
||||
|
||||
keyMap := make(map[string]*keys.PublicKey)
|
||||
pkeys := make([]*keys.PrivateKey, n)
|
||||
pubs := make([]stackitem.Item, n)
|
||||
for i := range pubs {
|
||||
if isR1 {
|
||||
pkeys[i], err = keys.NewPrivateKey()
|
||||
} else {
|
||||
pkeys[i], err = keys.NewSecp256k1PrivateKey()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
@ -162,27 +61,29 @@ func subSlice(arr []stackitem.Item, indices []int) []stackitem.Item {
|
|||
return result
|
||||
}
|
||||
|
||||
func initCheckMultisigVMNoArgs(isR1 bool) *vm.VM {
|
||||
func initCheckMultisigVMNoArgs(container *transaction.Transaction) *vm.VM {
|
||||
buf := make([]byte, 5)
|
||||
buf[0] = byte(opcode.SYSCALL)
|
||||
if isR1 {
|
||||
binary.LittleEndian.PutUint32(buf[1:], ecdsaSecp256r1CheckMultisigID)
|
||||
} else {
|
||||
binary.LittleEndian.PutUint32(buf[1:], ecdsaSecp256k1CheckMultisigID)
|
||||
}
|
||||
binary.LittleEndian.PutUint32(buf[1:], neoCryptoCheckMultisigID)
|
||||
|
||||
ic := &interop.Context{Trigger: trigger.Verification}
|
||||
ic := &interop.Context{
|
||||
Trigger: trigger.Verification,
|
||||
Container: container,
|
||||
}
|
||||
Register(ic)
|
||||
v := ic.SpawnVM()
|
||||
v.LoadScript(buf)
|
||||
return v
|
||||
}
|
||||
|
||||
func initCHECKMULTISIGVM(t *testing.T, isR1 bool, n int, ik, is []int) *vm.VM {
|
||||
v := initCheckMultisigVMNoArgs(isR1)
|
||||
msg := []byte("NEO - An Open Network For Smart Economy")
|
||||
func initCHECKMULTISIGVM(t *testing.T, n int, ik, is []int) *vm.VM {
|
||||
tx := transaction.New(netmode.UnitTestNet, []byte("NEO - An Open Network For Smart Economy"), 10)
|
||||
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
|
||||
tx.Scripts = []transaction.Witness{{}}
|
||||
|
||||
pubs, sigs, _, err := initCHECKMULTISIG(isR1, msg, n)
|
||||
v := initCheckMultisigVMNoArgs(tx)
|
||||
|
||||
pubs, sigs, _, err := initCHECKMULTISIG(tx.GetSignedPart(), n)
|
||||
require.NoError(t, err)
|
||||
|
||||
pubs = subSlice(pubs, ik)
|
||||
|
@ -190,13 +91,12 @@ func initCHECKMULTISIGVM(t *testing.T, isR1 bool, n int, ik, is []int) *vm.VM {
|
|||
|
||||
v.Estack().PushVal(sigs)
|
||||
v.Estack().PushVal(pubs)
|
||||
v.Estack().PushVal(msg)
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func testCHECKMULTISIGGood(t *testing.T, isR1 bool, n int, is []int) {
|
||||
v := initCHECKMULTISIGVM(t, isR1, n, nil, is)
|
||||
func testCHECKMULTISIGGood(t *testing.T, n int, is []int) {
|
||||
v := initCHECKMULTISIGVM(t, n, nil, is)
|
||||
|
||||
require.NoError(t, v.Run())
|
||||
assert.Equal(t, 1, v.Estack().Len())
|
||||
|
@ -204,25 +104,21 @@ func testCHECKMULTISIGGood(t *testing.T, isR1 bool, n int, is []int) {
|
|||
}
|
||||
|
||||
func TestECDSASecp256r1CheckMultisigGood(t *testing.T) {
|
||||
testCurveCHECKMULTISIGGood(t, true)
|
||||
testCurveCHECKMULTISIGGood(t)
|
||||
}
|
||||
|
||||
func TestECDSASecp256k1CheckMultisigGood(t *testing.T) {
|
||||
testCurveCHECKMULTISIGGood(t, false)
|
||||
func testCurveCHECKMULTISIGGood(t *testing.T) {
|
||||
t.Run("3_1", func(t *testing.T) { testCHECKMULTISIGGood(t, 3, []int{1}) })
|
||||
t.Run("2_2", func(t *testing.T) { testCHECKMULTISIGGood(t, 2, []int{0, 1}) })
|
||||
t.Run("3_3", func(t *testing.T) { testCHECKMULTISIGGood(t, 3, []int{0, 1, 2}) })
|
||||
t.Run("3_2", func(t *testing.T) { testCHECKMULTISIGGood(t, 3, []int{0, 2}) })
|
||||
t.Run("4_2", func(t *testing.T) { testCHECKMULTISIGGood(t, 4, []int{0, 2}) })
|
||||
t.Run("10_7", func(t *testing.T) { testCHECKMULTISIGGood(t, 10, []int{2, 3, 4, 5, 6, 8, 9}) })
|
||||
t.Run("12_9", func(t *testing.T) { testCHECKMULTISIGGood(t, 12, []int{0, 1, 4, 5, 6, 7, 8, 9}) })
|
||||
}
|
||||
|
||||
func testCurveCHECKMULTISIGGood(t *testing.T, isR1 bool) {
|
||||
t.Run("3_1", func(t *testing.T) { testCHECKMULTISIGGood(t, isR1, 3, []int{1}) })
|
||||
t.Run("2_2", func(t *testing.T) { testCHECKMULTISIGGood(t, isR1, 2, []int{0, 1}) })
|
||||
t.Run("3_3", func(t *testing.T) { testCHECKMULTISIGGood(t, isR1, 3, []int{0, 1, 2}) })
|
||||
t.Run("3_2", func(t *testing.T) { testCHECKMULTISIGGood(t, isR1, 3, []int{0, 2}) })
|
||||
t.Run("4_2", func(t *testing.T) { testCHECKMULTISIGGood(t, isR1, 4, []int{0, 2}) })
|
||||
t.Run("10_7", func(t *testing.T) { testCHECKMULTISIGGood(t, isR1, 10, []int{2, 3, 4, 5, 6, 8, 9}) })
|
||||
t.Run("12_9", func(t *testing.T) { testCHECKMULTISIGGood(t, isR1, 12, []int{0, 1, 4, 5, 6, 7, 8, 9}) })
|
||||
}
|
||||
|
||||
func testCHECKMULTISIGBad(t *testing.T, isR1 bool, isErr bool, n int, ik, is []int) {
|
||||
v := initCHECKMULTISIGVM(t, isR1, n, ik, is)
|
||||
func testCHECKMULTISIGBad(t *testing.T, isErr bool, n int, ik, is []int) {
|
||||
v := initCHECKMULTISIGVM(t, n, ik, is)
|
||||
|
||||
if isErr {
|
||||
require.Error(t, v.Run())
|
||||
|
@ -234,48 +130,99 @@ func testCHECKMULTISIGBad(t *testing.T, isR1 bool, isErr bool, n int, ik, is []i
|
|||
}
|
||||
|
||||
func TestECDSASecp256r1CheckMultisigBad(t *testing.T) {
|
||||
testCurveCHECKMULTISIGBad(t, true)
|
||||
testCurveCHECKMULTISIGBad(t)
|
||||
}
|
||||
|
||||
func TestECDSASecp256k1CheckMultisigBad(t *testing.T) {
|
||||
testCurveCHECKMULTISIGBad(t, false)
|
||||
}
|
||||
|
||||
func testCurveCHECKMULTISIGBad(t *testing.T, isR1 bool) {
|
||||
t.Run("1_1 wrong signature", func(t *testing.T) { testCHECKMULTISIGBad(t, isR1, false, 2, []int{0}, []int{1}) })
|
||||
t.Run("3_2 wrong order", func(t *testing.T) { testCHECKMULTISIGBad(t, isR1, false, 3, []int{0, 2}, []int{2, 0}) })
|
||||
t.Run("3_2 duplicate sig", func(t *testing.T) { testCHECKMULTISIGBad(t, isR1, false, 3, nil, []int{0, 0}) })
|
||||
t.Run("1_2 too many signatures", func(t *testing.T) { testCHECKMULTISIGBad(t, isR1, true, 2, []int{0}, []int{0, 1}) })
|
||||
func testCurveCHECKMULTISIGBad(t *testing.T) {
|
||||
t.Run("1_1 wrong signature", func(t *testing.T) { testCHECKMULTISIGBad(t, false, 2, []int{0}, []int{1}) })
|
||||
t.Run("3_2 wrong order", func(t *testing.T) { testCHECKMULTISIGBad(t, false, 3, []int{0, 2}, []int{2, 0}) })
|
||||
t.Run("3_2 duplicate sig", func(t *testing.T) { testCHECKMULTISIGBad(t, false, 3, nil, []int{0, 0}) })
|
||||
t.Run("1_2 too many signatures", func(t *testing.T) { testCHECKMULTISIGBad(t, true, 2, []int{0}, []int{0, 1}) })
|
||||
t.Run("gas limit exceeded", func(t *testing.T) {
|
||||
v := initCHECKMULTISIGVM(t, isR1, 1, []int{0}, []int{0})
|
||||
v := initCHECKMULTISIGVM(t, 1, []int{0}, []int{0})
|
||||
v.GasLimit = fee.ECDSAVerifyPrice - 1
|
||||
require.Error(t, v.Run())
|
||||
})
|
||||
|
||||
msg := []byte("NEO - An Open Network For Smart Economy")
|
||||
pubs, sigs, _, err := initCHECKMULTISIG(isR1, msg, 1)
|
||||
pubs, sigs, _, err := initCHECKMULTISIG(msg, 1)
|
||||
require.NoError(t, err)
|
||||
arr := stackitem.NewArray([]stackitem.Item{stackitem.NewArray(nil)})
|
||||
tx := transaction.New(netmode.UnitTestNet, []byte("NEO - An Open Network For Smart Economy"), 10)
|
||||
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
|
||||
tx.Scripts = []transaction.Witness{{}}
|
||||
|
||||
t.Run("invalid message type", func(t *testing.T) {
|
||||
v := initCheckMultisigVMNoArgs(isR1)
|
||||
v.Estack().PushVal(sigs)
|
||||
v.Estack().PushVal(pubs)
|
||||
v.Estack().PushVal(stackitem.NewArray(nil))
|
||||
require.Error(t, v.Run())
|
||||
})
|
||||
t.Run("invalid public keys", func(t *testing.T) {
|
||||
v := initCheckMultisigVMNoArgs(isR1)
|
||||
v := initCheckMultisigVMNoArgs(tx)
|
||||
v.Estack().PushVal(sigs)
|
||||
v.Estack().PushVal(arr)
|
||||
v.Estack().PushVal(msg)
|
||||
require.Error(t, v.Run())
|
||||
})
|
||||
t.Run("invalid signatures", func(t *testing.T) {
|
||||
v := initCheckMultisigVMNoArgs(isR1)
|
||||
v := initCheckMultisigVMNoArgs(tx)
|
||||
v.Estack().PushVal(arr)
|
||||
v.Estack().PushVal(pubs)
|
||||
v.Estack().PushVal(msg)
|
||||
require.Error(t, v.Run())
|
||||
})
|
||||
}
|
||||
|
||||
func TestCheckSig(t *testing.T) {
|
||||
priv, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
verifyFunc := ECDSASecp256r1CheckSig
|
||||
d := dao.NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet, false)
|
||||
ic := &interop.Context{DAO: dao.NewCached(d)}
|
||||
runCase := func(t *testing.T, isErr bool, result interface{}, args ...interface{}) {
|
||||
ic.SpawnVM()
|
||||
for i := range args {
|
||||
ic.VM.Estack().PushVal(args[i])
|
||||
}
|
||||
|
||||
var err error
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("panic: %v", r)
|
||||
}
|
||||
}()
|
||||
err = verifyFunc(ic)
|
||||
}()
|
||||
|
||||
if isErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, ic.VM.Estack().Len())
|
||||
require.Equal(t, result, ic.VM.Estack().Pop().Value().(bool))
|
||||
}
|
||||
|
||||
tx := transaction.New(netmode.UnitTestNet, []byte{0, 1, 2}, 1)
|
||||
msg := tx.GetSignedPart()
|
||||
ic.Container = tx
|
||||
|
||||
t.Run("success", func(t *testing.T) {
|
||||
sign := priv.Sign(msg)
|
||||
runCase(t, false, true, sign, priv.PublicKey().Bytes())
|
||||
})
|
||||
|
||||
t.Run("missing argument", func(t *testing.T) {
|
||||
runCase(t, true, false)
|
||||
sign := priv.Sign(msg)
|
||||
runCase(t, true, false, sign)
|
||||
})
|
||||
|
||||
t.Run("invalid signature", func(t *testing.T) {
|
||||
sign := priv.Sign(msg)
|
||||
sign[0] = ^sign[0]
|
||||
runCase(t, false, false, sign, priv.PublicKey().Bytes())
|
||||
})
|
||||
|
||||
t.Run("invalid public key", func(t *testing.T) {
|
||||
sign := priv.Sign(msg)
|
||||
pub := priv.PublicKey().Bytes()
|
||||
pub[0] = 0xFF // invalid prefix
|
||||
runCase(t, true, false, sign, pub)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// Sha256 returns sha256 hash of the data.
|
||||
func Sha256(ic *interop.Context) error {
|
||||
h, err := getMessageHash(ic, ic.VM.Estack().Pop().Item())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ic.VM.Estack().PushVal(h.BytesBE())
|
||||
return nil
|
||||
}
|
||||
|
||||
// RipeMD160 returns RipeMD160 hash of the data.
|
||||
func RipeMD160(ic *interop.Context) error {
|
||||
var msg []byte
|
||||
|
||||
item := ic.VM.Estack().Pop().Item()
|
||||
switch val := item.(type) {
|
||||
case *stackitem.Interop:
|
||||
msg = val.Value().(crypto.Verifiable).GetSignedPart()
|
||||
case stackitem.Null:
|
||||
msg = ic.Container.GetSignedPart()
|
||||
default:
|
||||
var err error
|
||||
if msg, err = val.TryBytes(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
h := hash.RipeMD160(msg).BytesBE()
|
||||
ic.VM.Estack().PushVal(h)
|
||||
return nil
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type testVerifiable []byte
|
||||
|
||||
var _ crypto.Verifiable = testVerifiable{}
|
||||
|
||||
func (v testVerifiable) GetSignedPart() []byte {
|
||||
return v
|
||||
}
|
||||
func (v testVerifiable) GetSignedHash() util.Uint256 {
|
||||
return hash.Sha256(v)
|
||||
}
|
||||
|
||||
func testHash0100(t *testing.T, result string, interopFunc func(*interop.Context) error) {
|
||||
t.Run("good", func(t *testing.T) {
|
||||
bs := []byte{1, 0}
|
||||
|
||||
checkGood := func(t *testing.T, ic *interop.Context) {
|
||||
require.NoError(t, interopFunc(ic))
|
||||
require.Equal(t, 1, ic.VM.Estack().Len())
|
||||
require.Equal(t, result, hex.EncodeToString(ic.VM.Estack().Pop().Bytes()))
|
||||
}
|
||||
t.Run("raw bytes", func(t *testing.T) {
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
ic.VM.Estack().PushVal(bs)
|
||||
checkGood(t, ic)
|
||||
})
|
||||
t.Run("interop", func(t *testing.T) {
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
ic.VM.Estack().PushVal(stackitem.NewInterop(testVerifiable(bs)))
|
||||
checkGood(t, ic)
|
||||
})
|
||||
t.Run("container", func(t *testing.T) {
|
||||
ic := &interop.Context{VM: vm.New(), Container: testVerifiable(bs)}
|
||||
ic.VM.Estack().PushVal(stackitem.Null{})
|
||||
checkGood(t, ic)
|
||||
})
|
||||
})
|
||||
t.Run("bad message", func(t *testing.T) {
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
ic.VM.Estack().PushVal(stackitem.NewArray(nil))
|
||||
require.Error(t, interopFunc(ic))
|
||||
})
|
||||
}
|
||||
|
||||
func TestSHA256(t *testing.T) {
|
||||
// 0x0100 hashes to 47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254
|
||||
res := "47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254"
|
||||
testHash0100(t, res, Sha256)
|
||||
}
|
||||
|
||||
func TestRIPEMD160(t *testing.T) {
|
||||
// 0x0100 hashes to 213492c0c6fc5d61497cf17249dd31cd9964b8a3
|
||||
res := "213492c0c6fc5d61497cf17249dd31cd9964b8a3"
|
||||
testHash0100(t, res, RipeMD160)
|
||||
}
|
|
@ -6,21 +6,13 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
ecdsaSecp256r1VerifyID = interopnames.ToID([]byte(interopnames.NeoCryptoVerifyWithECDsaSecp256r1))
|
||||
ecdsaSecp256k1VerifyID = interopnames.ToID([]byte(interopnames.NeoCryptoVerifyWithECDsaSecp256k1))
|
||||
ecdsaSecp256r1CheckMultisigID = interopnames.ToID([]byte(interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1))
|
||||
ecdsaSecp256k1CheckMultisigID = interopnames.ToID([]byte(interopnames.NeoCryptoCheckMultisigWithECDsaSecp256k1))
|
||||
sha256ID = interopnames.ToID([]byte(interopnames.NeoCryptoSHA256))
|
||||
ripemd160ID = interopnames.ToID([]byte(interopnames.NeoCryptoRIPEMD160))
|
||||
neoCryptoCheckMultisigID = interopnames.ToID([]byte(interopnames.NeoCryptoCheckMultisig))
|
||||
neoCryptoCheckSigID = interopnames.ToID([]byte(interopnames.NeoCryptoCheckSig))
|
||||
)
|
||||
|
||||
var cryptoInterops = []interop.Function{
|
||||
{ID: ecdsaSecp256r1VerifyID, Func: ECDSASecp256r1Verify},
|
||||
{ID: ecdsaSecp256k1VerifyID, Func: ECDSASecp256k1Verify},
|
||||
{ID: ecdsaSecp256r1CheckMultisigID, Func: ECDSASecp256r1CheckMultisig},
|
||||
{ID: ecdsaSecp256k1CheckMultisigID, Func: ECDSASecp256k1CheckMultisig},
|
||||
{ID: sha256ID, Func: Sha256},
|
||||
{ID: ripemd160ID, Func: RipeMD160},
|
||||
{ID: neoCryptoCheckMultisigID, Func: ECDSASecp256r1CheckMultisig},
|
||||
{ID: neoCryptoCheckSigID, Func: ECDSASecp256r1CheckSig},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -2,14 +2,6 @@ package interopnames
|
|||
|
||||
// Names of all used interops.
|
||||
const (
|
||||
SystemBinaryAtoi = "System.Binary.Atoi"
|
||||
SystemBinaryBase58Decode = "System.Binary.Base58Decode"
|
||||
SystemBinaryBase58Encode = "System.Binary.Base58Encode"
|
||||
SystemBinaryBase64Decode = "System.Binary.Base64Decode"
|
||||
SystemBinaryBase64Encode = "System.Binary.Base64Encode"
|
||||
SystemBinaryDeserialize = "System.Binary.Deserialize"
|
||||
SystemBinaryItoa = "System.Binary.Itoa"
|
||||
SystemBinarySerialize = "System.Binary.Serialize"
|
||||
SystemCallbackCreate = "System.Callback.Create"
|
||||
SystemCallbackCreateFromMethod = "System.Callback.CreateFromMethod"
|
||||
SystemCallbackCreateFromSyscall = "System.Callback.CreateFromSyscall"
|
||||
|
@ -25,8 +17,6 @@ const (
|
|||
SystemIteratorCreate = "System.Iterator.Create"
|
||||
SystemIteratorNext = "System.Iterator.Next"
|
||||
SystemIteratorValue = "System.Iterator.Value"
|
||||
SystemJSONDeserialize = "System.Json.Deserialize"
|
||||
SystemJSONSerialize = "System.Json.Serialize"
|
||||
SystemRuntimeCheckWitness = "System.Runtime.CheckWitness"
|
||||
SystemRuntimeGasLeft = "System.Runtime.GasLeft"
|
||||
SystemRuntimeGetCallingScriptHash = "System.Runtime.GetCallingScriptHash"
|
||||
|
@ -47,23 +37,11 @@ const (
|
|||
SystemStorageGetReadOnlyContext = "System.Storage.GetReadOnlyContext"
|
||||
SystemStoragePut = "System.Storage.Put"
|
||||
SystemStorageAsReadOnly = "System.Storage.AsReadOnly"
|
||||
NeoCryptoVerifyWithECDsaSecp256r1 = "Neo.Crypto.VerifyWithECDsaSecp256r1"
|
||||
NeoCryptoVerifyWithECDsaSecp256k1 = "Neo.Crypto.VerifyWithECDsaSecp256k1"
|
||||
NeoCryptoCheckMultisigWithECDsaSecp256r1 = "Neo.Crypto.CheckMultisigWithECDsaSecp256r1"
|
||||
NeoCryptoCheckMultisigWithECDsaSecp256k1 = "Neo.Crypto.CheckMultisigWithECDsaSecp256k1"
|
||||
NeoCryptoSHA256 = "Neo.Crypto.SHA256"
|
||||
NeoCryptoRIPEMD160 = "Neo.Crypto.RIPEMD160"
|
||||
NeoCryptoCheckMultisig = "Neo.Crypto.CheckMultisig"
|
||||
NeoCryptoCheckSig = "Neo.Crypto.CheckSig"
|
||||
)
|
||||
|
||||
var names = []string{
|
||||
SystemBinaryAtoi,
|
||||
SystemBinaryBase58Decode,
|
||||
SystemBinaryBase58Encode,
|
||||
SystemBinaryBase64Decode,
|
||||
SystemBinaryBase64Encode,
|
||||
SystemBinaryDeserialize,
|
||||
SystemBinaryItoa,
|
||||
SystemBinarySerialize,
|
||||
SystemCallbackCreate,
|
||||
SystemCallbackCreateFromMethod,
|
||||
SystemCallbackCreateFromSyscall,
|
||||
|
@ -79,8 +57,6 @@ var names = []string{
|
|||
SystemIteratorCreate,
|
||||
SystemIteratorNext,
|
||||
SystemIteratorValue,
|
||||
SystemJSONDeserialize,
|
||||
SystemJSONSerialize,
|
||||
SystemRuntimeCheckWitness,
|
||||
SystemRuntimeGasLeft,
|
||||
SystemRuntimeGetCallingScriptHash,
|
||||
|
@ -101,10 +77,6 @@ var names = []string{
|
|||
SystemStorageGetReadOnlyContext,
|
||||
SystemStoragePut,
|
||||
SystemStorageAsReadOnly,
|
||||
NeoCryptoVerifyWithECDsaSecp256r1,
|
||||
NeoCryptoVerifyWithECDsaSecp256k1,
|
||||
NeoCryptoCheckMultisigWithECDsaSecp256r1,
|
||||
NeoCryptoCheckMultisigWithECDsaSecp256k1,
|
||||
NeoCryptoSHA256,
|
||||
NeoCryptoRIPEMD160,
|
||||
NeoCryptoCheckMultisig,
|
||||
NeoCryptoCheckSig,
|
||||
}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
package json
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// Serialize handles System.JSON.Serialize syscall.
|
||||
func Serialize(ic *interop.Context) error {
|
||||
item := ic.VM.Estack().Pop().Item()
|
||||
data, err := stackitem.ToJSON(item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ic.VM.Estack().PushVal(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deserialize handles System.JSON.Deserialize syscall.
|
||||
func Deserialize(ic *interop.Context) error {
|
||||
data := ic.VM.Estack().Pop().Bytes()
|
||||
item, err := stackitem.FromJSON(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ic.VM.Estack().PushVal(item)
|
||||
return nil
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package json
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
serializeID = interopnames.ToID([]byte(interopnames.SystemJSONSerialize))
|
||||
deserializeID = interopnames.ToID([]byte(interopnames.SystemJSONDeserialize))
|
||||
)
|
||||
|
||||
var jsonInterops = []interop.Function{
|
||||
{ID: serializeID, Func: Serialize},
|
||||
{ID: deserializeID, Func: Deserialize},
|
||||
}
|
||||
|
||||
func init() {
|
||||
interop.Sort(jsonInterops)
|
||||
}
|
||||
|
||||
func getTestFunc(id uint32, arg interface{}, result interface{}) func(t *testing.T) {
|
||||
prog := make([]byte, 5)
|
||||
prog[0] = byte(opcode.SYSCALL)
|
||||
binary.LittleEndian.PutUint32(prog[1:], id)
|
||||
|
||||
return func(t *testing.T) {
|
||||
ic := &interop.Context{}
|
||||
ic.Functions = append(ic.Functions, jsonInterops)
|
||||
v := ic.SpawnVM()
|
||||
v.LoadScript(prog)
|
||||
v.Estack().PushVal(arg)
|
||||
if result == nil {
|
||||
require.Error(t, v.Run())
|
||||
return
|
||||
}
|
||||
require.NoError(t, v.Run())
|
||||
require.Equal(t, stackitem.Make(result), v.Estack().Pop().Item())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSerialize(t *testing.T) {
|
||||
t.Run("Serialize", func(t *testing.T) {
|
||||
t.Run("Good", getTestFunc(serializeID, 42, []byte("42")))
|
||||
t.Run("Bad", func(t *testing.T) {
|
||||
arr := stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(make([]byte, stackitem.MaxSize/2)),
|
||||
stackitem.NewByteArray(make([]byte, stackitem.MaxSize/2)),
|
||||
})
|
||||
getTestFunc(serializeID, arr, nil)(t)
|
||||
})
|
||||
})
|
||||
t.Run("Deserialize", func(t *testing.T) {
|
||||
t.Run("Good", getTestFunc(deserializeID, []byte("42"), 42))
|
||||
t.Run("Bad", getTestFunc(deserializeID, []byte("{]"), nil))
|
||||
})
|
||||
}
|
|
@ -316,6 +316,7 @@ func TestStorageDelete(t *testing.T) {
|
|||
// getTestContractState returns 2 contracts second of which is allowed to call the first.
|
||||
func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
|
||||
mgmtHash := bc.ManagementContractHash()
|
||||
stdHash := bc.contracts.Std.Hash
|
||||
|
||||
w := io.NewBufBinWriter()
|
||||
emit.Opcodes(w.BinWriter, opcode.ABORT)
|
||||
|
@ -339,16 +340,20 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
|
|||
emit.Opcodes(w.BinWriter, opcode.LDSFLD0, opcode.SUB,
|
||||
opcode.CONVERT, opcode.Opcode(stackitem.BooleanT), opcode.RET)
|
||||
deployOff := w.Len()
|
||||
emit.Opcodes(w.BinWriter, opcode.SWAP, opcode.JMPIF, 2+8+1+1+5+3)
|
||||
emit.Opcodes(w.BinWriter, opcode.SWAP, opcode.JMPIF, 2+8+1+1+1+1+39+3)
|
||||
emit.String(w.BinWriter, "create") // 8 bytes
|
||||
emit.Int(w.BinWriter, 2) // 1 byte
|
||||
emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemBinarySerialize) // 5 bytes
|
||||
emit.Opcodes(w.BinWriter, opcode.CALL, 3+8+1+1+5+3, opcode.RET)
|
||||
emit.Int(w.BinWriter, 1) // 1 byte (args count for `serialize`)
|
||||
emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte (pack args into array for `serialize`)
|
||||
emit.AppCallNoArgs(w.BinWriter, stdHash, "serialize", callflag.All) // 39 bytes
|
||||
emit.Opcodes(w.BinWriter, opcode.CALL, 3+8+1+1+1+1+39+3, opcode.RET)
|
||||
emit.String(w.BinWriter, "update") // 8 bytes
|
||||
emit.Int(w.BinWriter, 2) // 1 byte
|
||||
emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemBinarySerialize) // 5 bytes
|
||||
emit.Int(w.BinWriter, 1) // 1 byte (args count for `serialize`)
|
||||
emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte (pack args into array for `serialize`)
|
||||
emit.AppCallNoArgs(w.BinWriter, stdHash, "serialize", callflag.All) // 39 bytes
|
||||
emit.Opcodes(w.BinWriter, opcode.CALL, 3, opcode.RET)
|
||||
putValOff := w.Len()
|
||||
emit.String(w.BinWriter, "initial")
|
||||
|
|
|
@ -10,12 +10,10 @@ package core
|
|||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/binary"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/crypto"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/iterator"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/json"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||
|
@ -32,14 +30,6 @@ func SpawnVM(ic *interop.Context) *vm.VM {
|
|||
|
||||
// All lists are sorted, keep 'em this way, please.
|
||||
var systemInterops = []interop.Function{
|
||||
{Name: interopnames.SystemBinaryAtoi, Func: binary.Atoi, Price: 1 << 12, ParamCount: 2},
|
||||
{Name: interopnames.SystemBinaryBase58Decode, Func: binary.DecodeBase58, Price: 1 << 12, ParamCount: 1},
|
||||
{Name: interopnames.SystemBinaryBase58Encode, Func: binary.EncodeBase58, Price: 1 << 12, ParamCount: 1},
|
||||
{Name: interopnames.SystemBinaryBase64Decode, Func: binary.DecodeBase64, Price: 1 << 12, ParamCount: 1},
|
||||
{Name: interopnames.SystemBinaryBase64Encode, Func: binary.EncodeBase64, Price: 1 << 12, ParamCount: 1},
|
||||
{Name: interopnames.SystemBinaryDeserialize, Func: binary.Deserialize, Price: 1 << 14, ParamCount: 1},
|
||||
{Name: interopnames.SystemBinaryItoa, Func: binary.Itoa, Price: 1 << 12, ParamCount: 2},
|
||||
{Name: interopnames.SystemBinarySerialize, Func: binary.Serialize, Price: 1 << 12, ParamCount: 1},
|
||||
{Name: interopnames.SystemContractCall, Func: contract.Call, Price: 1 << 15,
|
||||
RequiredFlags: callflag.ReadStates | callflag.AllowCall, ParamCount: 4},
|
||||
{Name: interopnames.SystemContractCallNative, Func: native.Call, Price: 0, ParamCount: 1},
|
||||
|
@ -52,8 +42,6 @@ var systemInterops = []interop.Function{
|
|||
{Name: interopnames.SystemIteratorCreate, Func: iterator.Create, Price: 1 << 4, ParamCount: 1},
|
||||
{Name: interopnames.SystemIteratorNext, Func: iterator.Next, Price: 1 << 15, ParamCount: 1},
|
||||
{Name: interopnames.SystemIteratorValue, Func: iterator.Value, Price: 1 << 4, ParamCount: 1},
|
||||
{Name: interopnames.SystemJSONDeserialize, Func: json.Deserialize, Price: 1 << 14, ParamCount: 1},
|
||||
{Name: interopnames.SystemJSONSerialize, Func: json.Serialize, Price: 1 << 12, ParamCount: 1},
|
||||
{Name: interopnames.SystemRuntimeCheckWitness, Func: runtime.CheckWitness, Price: 1 << 10,
|
||||
RequiredFlags: callflag.NoneFlag, ParamCount: 1},
|
||||
{Name: interopnames.SystemRuntimeGasLeft, Func: runtime.GasLeft, Price: 1 << 4},
|
||||
|
@ -87,14 +75,8 @@ var systemInterops = []interop.Function{
|
|||
}
|
||||
|
||||
var neoInterops = []interop.Function{
|
||||
{Name: interopnames.NeoCryptoVerifyWithECDsaSecp256r1, Func: crypto.ECDSASecp256r1Verify,
|
||||
Price: fee.ECDSAVerifyPrice, ParamCount: 3},
|
||||
{Name: interopnames.NeoCryptoVerifyWithECDsaSecp256k1, Func: crypto.ECDSASecp256k1Verify,
|
||||
Price: fee.ECDSAVerifyPrice, ParamCount: 3},
|
||||
{Name: interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1, Func: crypto.ECDSASecp256r1CheckMultisig, Price: 0, ParamCount: 3},
|
||||
{Name: interopnames.NeoCryptoCheckMultisigWithECDsaSecp256k1, Func: crypto.ECDSASecp256k1CheckMultisig, Price: 0, ParamCount: 3},
|
||||
{Name: interopnames.NeoCryptoSHA256, Func: crypto.Sha256, Price: 1 << 15, ParamCount: 1},
|
||||
{Name: interopnames.NeoCryptoRIPEMD160, Func: crypto.RipeMD160, Price: 1 << 15, ParamCount: 1},
|
||||
{Name: interopnames.NeoCryptoCheckMultisig, Func: crypto.ECDSASecp256r1CheckMultisig, Price: 0, ParamCount: 2},
|
||||
{Name: interopnames.NeoCryptoCheckSig, Func: crypto.ECDSASecp256r1CheckSig, Price: fee.ECDSAVerifyPrice, ParamCount: 2},
|
||||
}
|
||||
|
||||
// initIDinInteropsSlice initializes IDs from names in one given
|
||||
|
|
|
@ -24,6 +24,8 @@ type Contracts struct {
|
|||
Designate *Designate
|
||||
NameService *NameService
|
||||
Notary *Notary
|
||||
Crypto *Crypto
|
||||
Std *Std
|
||||
Contracts []interop.Contract
|
||||
// persistScript is vm script which executes "onPersist" method of every native contract.
|
||||
persistScript []byte
|
||||
|
@ -61,6 +63,14 @@ func NewContracts(p2pSigExtensionsEnabled bool) *Contracts {
|
|||
cs.Management = mgmt
|
||||
cs.Contracts = append(cs.Contracts, mgmt)
|
||||
|
||||
s := newStd()
|
||||
cs.Std = s
|
||||
cs.Contracts = append(cs.Contracts, s)
|
||||
|
||||
c := newCrypto()
|
||||
cs.Crypto = c
|
||||
cs.Contracts = append(cs.Contracts, c)
|
||||
|
||||
ledger := newLedger()
|
||||
cs.Ledger = ledger
|
||||
cs.Contracts = append(cs.Contracts, ledger)
|
||||
|
|
138
pkg/core/native/crypto.go
Normal file
138
pkg/core/native/crypto.go
Normal file
|
@ -0,0 +1,138 @@
|
|||
package native
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// Crypto represents CryptoLib contract.
|
||||
type Crypto struct {
|
||||
interop.ContractMD
|
||||
}
|
||||
|
||||
// NamedCurve identifies named elliptic curves.
|
||||
type NamedCurve byte
|
||||
|
||||
// Various named elliptic curves.
|
||||
const (
|
||||
Secp256k1 NamedCurve = 22
|
||||
Secp256r1 NamedCurve = 23
|
||||
)
|
||||
|
||||
const cryptoContractID = -3
|
||||
|
||||
func newCrypto() *Crypto {
|
||||
c := &Crypto{ContractMD: *interop.NewContractMD(nativenames.CryptoLib, cryptoContractID)}
|
||||
defer c.UpdateHash()
|
||||
|
||||
desc := newDescriptor("sha256", smartcontract.ByteArrayType,
|
||||
manifest.NewParameter("data", smartcontract.ByteArrayType))
|
||||
md := newMethodAndPrice(c.sha256, 1<<15, callflag.NoneFlag)
|
||||
c.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("ripemd160", smartcontract.ByteArrayType,
|
||||
manifest.NewParameter("data", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(c.ripemd160, 1<<15, callflag.NoneFlag)
|
||||
c.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("verifyWithECDsa", smartcontract.BoolType,
|
||||
manifest.NewParameter("message", smartcontract.ByteArrayType),
|
||||
manifest.NewParameter("pubkey", smartcontract.ByteArrayType),
|
||||
manifest.NewParameter("signature", smartcontract.ByteArrayType),
|
||||
manifest.NewParameter("curve", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(c.verifyWithECDsa, 1<<15, callflag.NoneFlag)
|
||||
c.AddMethod(md, desc)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Crypto) sha256(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
bs, err := args[0].TryBytes()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return stackitem.NewByteArray(hash.Sha256(bs).BytesBE())
|
||||
}
|
||||
|
||||
func (c *Crypto) ripemd160(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
bs, err := args[0].TryBytes()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return stackitem.NewByteArray(hash.RipeMD160(bs).BytesBE())
|
||||
}
|
||||
|
||||
func (c *Crypto) verifyWithECDsa(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
msg, err := args[0].TryBytes()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("invalid message stackitem: %w", err))
|
||||
}
|
||||
hashToCheck := hash.Sha256(msg)
|
||||
pubkey, err := args[1].TryBytes()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("invalid pubkey stackitem: %w", err))
|
||||
}
|
||||
signature, err := args[2].TryBytes()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("invalid signature stackitem: %w", err))
|
||||
}
|
||||
curve, err := curveFromStackitem(args[3])
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("invalid curve stackitem: %w", err))
|
||||
}
|
||||
pkey, err := keys.NewPublicKeyFromBytes(pubkey, curve)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to decode pubkey: %w", err))
|
||||
}
|
||||
res := pkey.Verify(signature, hashToCheck.BytesBE())
|
||||
return stackitem.NewBool(res)
|
||||
}
|
||||
|
||||
func curveFromStackitem(si stackitem.Item) (elliptic.Curve, error) {
|
||||
curve, err := si.TryInteger()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !curve.IsInt64() {
|
||||
return nil, errors.New("not an int64")
|
||||
}
|
||||
c := curve.Int64()
|
||||
switch c {
|
||||
case int64(Secp256k1):
|
||||
return btcec.S256(), nil
|
||||
case int64(Secp256r1):
|
||||
return elliptic.P256(), nil
|
||||
default:
|
||||
return nil, errors.New("unsupported curve type")
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata implements Contract interface.
|
||||
func (c *Crypto) Metadata() *interop.ContractMD {
|
||||
return &c.ContractMD
|
||||
}
|
||||
|
||||
// Initialize implements Contract interface.
|
||||
func (c *Crypto) Initialize(ic *interop.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnPersist implements Contract interface.
|
||||
func (c *Crypto) OnPersist(ic *interop.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostPersist implements Contract interface.
|
||||
func (c *Crypto) PostPersist(ic *interop.Context) error {
|
||||
return nil
|
||||
}
|
122
pkg/core/native/crypto_test.go
Normal file
122
pkg/core/native/crypto_test.go
Normal file
|
@ -0,0 +1,122 @@
|
|||
package native
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSha256(t *testing.T) {
|
||||
c := newCrypto()
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
|
||||
t.Run("bad arg type", func(t *testing.T) {
|
||||
require.Panics(t, func() {
|
||||
c.sha256(ic, []stackitem.Item{stackitem.NewInterop(nil)})
|
||||
})
|
||||
})
|
||||
t.Run("good", func(t *testing.T) {
|
||||
// 0x0100 hashes to 47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254
|
||||
require.Equal(t, "47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254", hex.EncodeToString(c.sha256(ic, []stackitem.Item{stackitem.NewByteArray([]byte{1, 0})}).Value().([]byte)))
|
||||
})
|
||||
}
|
||||
|
||||
func TestRIPEMD160(t *testing.T) {
|
||||
c := newCrypto()
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
|
||||
t.Run("bad arg type", func(t *testing.T) {
|
||||
require.Panics(t, func() {
|
||||
c.ripemd160(ic, []stackitem.Item{stackitem.NewInterop(nil)})
|
||||
})
|
||||
})
|
||||
t.Run("good", func(t *testing.T) {
|
||||
// 0x0100 hashes to 213492c0c6fc5d61497cf17249dd31cd9964b8a3
|
||||
require.Equal(t, "213492c0c6fc5d61497cf17249dd31cd9964b8a3", hex.EncodeToString(c.ripemd160(ic, []stackitem.Item{stackitem.NewByteArray([]byte{1, 0})}).Value().([]byte)))
|
||||
})
|
||||
}
|
||||
|
||||
func TestCryptoLibVerifyWithECDsa(t *testing.T) {
|
||||
t.Run("R1", func(t *testing.T) {
|
||||
testECDSAVerify(t, Secp256r1)
|
||||
})
|
||||
t.Run("K1", func(t *testing.T) {
|
||||
testECDSAVerify(t, Secp256k1)
|
||||
})
|
||||
}
|
||||
|
||||
func testECDSAVerify(t *testing.T, curve NamedCurve) {
|
||||
var (
|
||||
priv *keys.PrivateKey
|
||||
err error
|
||||
c = newCrypto()
|
||||
ic = &interop.Context{VM: vm.New()}
|
||||
actual stackitem.Item
|
||||
)
|
||||
switch curve {
|
||||
case Secp256k1:
|
||||
priv, err = keys.NewSecp256k1PrivateKey()
|
||||
case Secp256r1:
|
||||
priv, err = keys.NewPrivateKey()
|
||||
default:
|
||||
t.Fatal("unknown curve")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
runCase := func(t *testing.T, isErr bool, result interface{}, args ...interface{}) {
|
||||
argsArr := make([]stackitem.Item, len(args))
|
||||
for i := range args {
|
||||
argsArr[i] = stackitem.Make(args[i])
|
||||
}
|
||||
if isErr {
|
||||
require.Panics(t, func() {
|
||||
_ = c.verifyWithECDsa(ic, argsArr)
|
||||
})
|
||||
} else {
|
||||
require.NotPanics(t, func() {
|
||||
actual = c.verifyWithECDsa(ic, argsArr)
|
||||
})
|
||||
require.Equal(t, stackitem.Make(result), actual)
|
||||
}
|
||||
}
|
||||
|
||||
msg := []byte("test message")
|
||||
sign := priv.Sign(msg)
|
||||
|
||||
t.Run("bad message item", func(t *testing.T) {
|
||||
runCase(t, true, false, stackitem.NewInterop("cheburek"), priv.PublicKey().Bytes(), sign, int64(curve))
|
||||
})
|
||||
t.Run("bad pubkey item", func(t *testing.T) {
|
||||
runCase(t, true, false, msg, stackitem.NewInterop("cheburek"), sign, int64(curve))
|
||||
})
|
||||
t.Run("bad pubkey bytes", func(t *testing.T) {
|
||||
runCase(t, true, false, msg, []byte{1, 2, 3}, sign, int64(curve))
|
||||
})
|
||||
t.Run("bad signature item", func(t *testing.T) {
|
||||
runCase(t, true, false, msg, priv.PublicKey().Bytes(), stackitem.NewInterop("cheburek"), int64(curve))
|
||||
})
|
||||
t.Run("bad curve item", func(t *testing.T) {
|
||||
runCase(t, true, false, msg, priv.PublicKey().Bytes(), sign, stackitem.NewInterop("cheburek"))
|
||||
})
|
||||
t.Run("bad curve value", func(t *testing.T) {
|
||||
runCase(t, true, false, msg, priv.PublicKey().Bytes(), sign, new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(1)))
|
||||
})
|
||||
t.Run("unknown curve", func(t *testing.T) {
|
||||
runCase(t, true, false, msg, priv.PublicKey().Bytes(), sign, int64(123))
|
||||
})
|
||||
t.Run("invalid signature", func(t *testing.T) {
|
||||
s := priv.Sign(msg)
|
||||
s[0] = ^s[0]
|
||||
runCase(t, false, false, s, priv.PublicKey().Bytes(), msg, int64(curve))
|
||||
})
|
||||
t.Run("success", func(t *testing.T) {
|
||||
runCase(t, false, true, msg, priv.PublicKey().Bytes(), sign, int64(curve))
|
||||
})
|
||||
}
|
|
@ -52,7 +52,7 @@ type roleData struct {
|
|||
}
|
||||
|
||||
const (
|
||||
designateContractID = -6
|
||||
designateContractID = -8
|
||||
|
||||
// maxNodeCount is the maximum number of nodes to set the role for.
|
||||
maxNodeCount = 32
|
||||
|
|
|
@ -26,7 +26,7 @@ type Ledger struct {
|
|||
}
|
||||
|
||||
const (
|
||||
ledgerContractID = -2
|
||||
ledgerContractID = -4
|
||||
|
||||
prefixBlockHash = 9
|
||||
prefixCurrentBlock = 12
|
||||
|
|
|
@ -54,7 +54,7 @@ const (
|
|||
)
|
||||
|
||||
const (
|
||||
nameServiceID = -8
|
||||
nameServiceID = -10
|
||||
|
||||
prefixRoots = 10
|
||||
prefixDomainPrice = 22
|
||||
|
|
|
@ -18,7 +18,7 @@ type GAS struct {
|
|||
NEO *NEO
|
||||
}
|
||||
|
||||
const gasContractID = -4
|
||||
const gasContractID = -6
|
||||
|
||||
// GASFactor is a divisor for finding GAS integral value.
|
||||
const GASFactor = NEOTotalSupply
|
||||
|
|
|
@ -50,7 +50,7 @@ type NEO struct {
|
|||
}
|
||||
|
||||
const (
|
||||
neoContractID = -3
|
||||
neoContractID = -5
|
||||
// NEOTotalSupply is the total amount of NEO in the system.
|
||||
NEOTotalSupply = 100000000
|
||||
// prefixCandidate is a prefix used to store validator's data.
|
||||
|
|
|
@ -11,4 +11,6 @@ const (
|
|||
Designation = "RoleManagement"
|
||||
Notary = "Notary"
|
||||
NameService = "NameService"
|
||||
CryptoLib = "CryptoLib"
|
||||
StdLib = "StdLib"
|
||||
)
|
||||
|
|
|
@ -47,7 +47,7 @@ type Oracle struct {
|
|||
}
|
||||
|
||||
const (
|
||||
oracleContractID = -7
|
||||
oracleContractID = -9
|
||||
maxURLLength = 256
|
||||
maxFilterLength = 128
|
||||
maxCallbackLength = 32
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
policyContractID = -5
|
||||
policyContractID = -7
|
||||
|
||||
defaultExecFeeFactor = interop.DefaultBaseExecFee
|
||||
defaultFeePerByte = 1000
|
||||
|
|
273
pkg/core/native/std.go
Normal file
273
pkg/core/native/std.go
Normal file
|
@ -0,0 +1,273 @@
|
|||
package native
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/mr-tron/base58"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// Std represents StdLib contract.
|
||||
type Std struct {
|
||||
interop.ContractMD
|
||||
}
|
||||
|
||||
const stdContractID = -2
|
||||
|
||||
var (
|
||||
// ErrInvalidBase is returned when base is invalid.
|
||||
ErrInvalidBase = errors.New("invalid base")
|
||||
// ErrInvalidFormat is returned when string is not a number.
|
||||
ErrInvalidFormat = errors.New("invalid format")
|
||||
)
|
||||
|
||||
func newStd() *Std {
|
||||
s := &Std{ContractMD: *interop.NewContractMD(nativenames.StdLib, stdContractID)}
|
||||
defer s.UpdateHash()
|
||||
|
||||
desc := newDescriptor("serialize", smartcontract.ByteArrayType,
|
||||
manifest.NewParameter("item", smartcontract.AnyType))
|
||||
md := newMethodAndPrice(s.serialize, 1<<12, callflag.NoneFlag)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("deserialize", smartcontract.AnyType,
|
||||
manifest.NewParameter("data", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(s.deserialize, 1<<14, callflag.NoneFlag)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("jsonSerialize", smartcontract.ByteArrayType,
|
||||
manifest.NewParameter("item", smartcontract.AnyType))
|
||||
md = newMethodAndPrice(s.jsonSerialize, 1<<12, callflag.NoneFlag)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("jsonDeserialize", smartcontract.AnyType,
|
||||
manifest.NewParameter("json", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(s.jsonDeserialize, 1<<14, callflag.NoneFlag)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("itoa", smartcontract.StringType,
|
||||
manifest.NewParameter("value", smartcontract.IntegerType),
|
||||
manifest.NewParameter("base", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(s.itoa, 1<<12, callflag.NoneFlag)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("atoi", smartcontract.IntegerType,
|
||||
manifest.NewParameter("value", smartcontract.StringType),
|
||||
manifest.NewParameter("base", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(s.atoi, 1<<12, callflag.NoneFlag)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("base64Encode", smartcontract.StringType,
|
||||
manifest.NewParameter("data", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(s.base64Encode, 1<<12, callflag.NoneFlag)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("base64Decode", smartcontract.ByteArrayType,
|
||||
manifest.NewParameter("s", smartcontract.StringType))
|
||||
md = newMethodAndPrice(s.base64Decode, 1<<12, callflag.NoneFlag)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("base58Encode", smartcontract.StringType,
|
||||
manifest.NewParameter("data", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(s.base58Encode, 1<<12, callflag.NoneFlag)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("base58Decode", smartcontract.ByteArrayType,
|
||||
manifest.NewParameter("s", smartcontract.StringType))
|
||||
md = newMethodAndPrice(s.base58Decode, 1<<12, callflag.NoneFlag)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Std) serialize(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
data, err := stackitem.SerializeItem(args[0])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if len(data) > stackitem.MaxSize {
|
||||
panic(errors.New("too big item"))
|
||||
}
|
||||
|
||||
return stackitem.NewByteArray(data)
|
||||
}
|
||||
|
||||
func (s *Std) deserialize(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
data, err := args[0].TryBytes()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
item, err := stackitem.DeserializeItem(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
func (s *Std) jsonSerialize(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
data, err := stackitem.ToJSON(args[0])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if len(data) > stackitem.MaxSize {
|
||||
panic(errors.New("too big item"))
|
||||
}
|
||||
|
||||
return stackitem.NewByteArray(data)
|
||||
}
|
||||
|
||||
func (s *Std) jsonDeserialize(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
data, err := args[0].TryBytes()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
item, err := stackitem.FromJSON(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
func (s *Std) itoa(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
num := toBigInt(args[0])
|
||||
base := toBigInt(args[1])
|
||||
if !base.IsInt64() {
|
||||
panic(ErrInvalidBase)
|
||||
}
|
||||
var str string
|
||||
switch b := base.Int64(); b {
|
||||
case 10:
|
||||
str = num.Text(10)
|
||||
case 16:
|
||||
if num.Sign() == 0 {
|
||||
str = "0"
|
||||
break
|
||||
}
|
||||
bs := bigint.ToBytes(num)
|
||||
reverse(bs)
|
||||
str = hex.EncodeToString(bs)
|
||||
if pad := bs[0] & 0xF8; pad == 0 || pad == 0xF8 {
|
||||
str = str[1:]
|
||||
}
|
||||
str = strings.ToUpper(str)
|
||||
default:
|
||||
panic(ErrInvalidBase)
|
||||
}
|
||||
return stackitem.NewByteArray([]byte(str))
|
||||
}
|
||||
|
||||
func (s *Std) atoi(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
num := toString(args[0])
|
||||
base := toBigInt(args[1])
|
||||
if !base.IsInt64() {
|
||||
panic(ErrInvalidBase)
|
||||
}
|
||||
var bi *big.Int
|
||||
switch b := base.Int64(); b {
|
||||
case 10:
|
||||
var ok bool
|
||||
bi, ok = new(big.Int).SetString(num, int(b))
|
||||
if !ok {
|
||||
panic(ErrInvalidFormat)
|
||||
}
|
||||
case 16:
|
||||
changed := len(num)%2 != 0
|
||||
if changed {
|
||||
num = "0" + num
|
||||
}
|
||||
bs, err := hex.DecodeString(num)
|
||||
if err != nil {
|
||||
panic(ErrInvalidFormat)
|
||||
}
|
||||
if changed && bs[0]&0x8 != 0 {
|
||||
bs[0] |= 0xF0
|
||||
}
|
||||
reverse(bs)
|
||||
bi = bigint.FromBytes(bs)
|
||||
default:
|
||||
panic(ErrInvalidBase)
|
||||
}
|
||||
|
||||
return stackitem.NewBigInteger(bi)
|
||||
}
|
||||
|
||||
func reverse(b []byte) {
|
||||
l := len(b)
|
||||
for i := 0; i < l/2; i++ {
|
||||
b[i], b[l-i-1] = b[l-i-1], b[i]
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Std) base64Encode(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
src, err := args[0].TryBytes()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
result := base64.StdEncoding.EncodeToString(src)
|
||||
|
||||
return stackitem.NewByteArray([]byte(result))
|
||||
}
|
||||
|
||||
func (s *Std) base64Decode(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
src := toString(args[0])
|
||||
result, err := base64.StdEncoding.DecodeString(src)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return stackitem.NewByteArray(result)
|
||||
}
|
||||
|
||||
func (s *Std) base58Encode(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
src, err := args[0].TryBytes()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
result := base58.Encode(src)
|
||||
|
||||
return stackitem.NewByteArray([]byte(result))
|
||||
}
|
||||
|
||||
func (s *Std) base58Decode(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
src := toString(args[0])
|
||||
result, err := base58.Decode(src)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return stackitem.NewByteArray(result)
|
||||
}
|
||||
|
||||
// Metadata implements Contract interface.
|
||||
func (s *Std) Metadata() *interop.ContractMD {
|
||||
return &s.ContractMD
|
||||
}
|
||||
|
||||
// Initialize implements Contract interface.
|
||||
func (s *Std) Initialize(ic *interop.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnPersist implements Contract interface.
|
||||
func (s *Std) OnPersist(ic *interop.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostPersist implements Contract interface.
|
||||
func (s *Std) PostPersist(ic *interop.Context) error {
|
||||
return nil
|
||||
}
|
328
pkg/core/native/std_test.go
Normal file
328
pkg/core/native/std_test.go
Normal file
|
@ -0,0 +1,328 @@
|
|||
package native
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/mr-tron/base58"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestStdLibItoaAtoi(t *testing.T) {
|
||||
s := newStd()
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
var actual stackitem.Item
|
||||
|
||||
t.Run("itoa-atoi", func(t *testing.T) {
|
||||
var testCases = []struct {
|
||||
num *big.Int
|
||||
base *big.Int
|
||||
result string
|
||||
}{
|
||||
{big.NewInt(0), big.NewInt(10), "0"},
|
||||
{big.NewInt(0), big.NewInt(16), "0"},
|
||||
{big.NewInt(1), big.NewInt(10), "1"},
|
||||
{big.NewInt(-1), big.NewInt(10), "-1"},
|
||||
{big.NewInt(1), big.NewInt(16), "1"},
|
||||
{big.NewInt(7), big.NewInt(16), "7"},
|
||||
{big.NewInt(8), big.NewInt(16), "08"},
|
||||
{big.NewInt(65535), big.NewInt(16), "0FFFF"},
|
||||
{big.NewInt(15), big.NewInt(16), "0F"},
|
||||
{big.NewInt(-1), big.NewInt(16), "F"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.itoa(ic, []stackitem.Item{stackitem.Make(tc.num), stackitem.Make(tc.base)})
|
||||
})
|
||||
require.Equal(t, stackitem.Make(tc.result), actual)
|
||||
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.atoi(ic, []stackitem.Item{stackitem.Make(tc.result), stackitem.Make(tc.base)})
|
||||
})
|
||||
require.Equal(t, stackitem.Make(tc.num), actual)
|
||||
}
|
||||
|
||||
t.Run("-1", func(t *testing.T) {
|
||||
for _, str := range []string{"FF", "FFF", "FFFF"} {
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.atoi(ic, []stackitem.Item{stackitem.Make(str), stackitem.Make(16)})
|
||||
})
|
||||
|
||||
require.Equal(t, stackitem.Make(-1), actual)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("itoa error", func(t *testing.T) {
|
||||
var testCases = []struct {
|
||||
num *big.Int
|
||||
base *big.Int
|
||||
err error
|
||||
}{
|
||||
{big.NewInt(1), big.NewInt(13), ErrInvalidBase},
|
||||
{big.NewInt(-1), new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(10)), ErrInvalidBase},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
require.PanicsWithError(t, tc.err.Error(), func() {
|
||||
_ = s.itoa(ic, []stackitem.Item{stackitem.Make(tc.num), stackitem.Make(tc.base)})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("atoi error", func(t *testing.T) {
|
||||
var testCases = []struct {
|
||||
num string
|
||||
base *big.Int
|
||||
err error
|
||||
}{
|
||||
{"1", big.NewInt(13), ErrInvalidBase},
|
||||
{"1", new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(16)), ErrInvalidBase},
|
||||
{"1_000", big.NewInt(10), ErrInvalidFormat},
|
||||
{"FE", big.NewInt(10), ErrInvalidFormat},
|
||||
{"XD", big.NewInt(16), ErrInvalidFormat},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
require.PanicsWithError(t, tc.err.Error(), func() {
|
||||
_ = s.atoi(ic, []stackitem.Item{stackitem.Make(tc.num), stackitem.Make(tc.base)})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestStdLibJSON(t *testing.T) {
|
||||
s := newStd()
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
var actual stackitem.Item
|
||||
|
||||
t.Run("JSONSerialize", func(t *testing.T) {
|
||||
t.Run("Good", func(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.jsonSerialize(ic, []stackitem.Item{stackitem.Make(42)})
|
||||
})
|
||||
|
||||
require.Equal(t, stackitem.Make([]byte("42")), actual)
|
||||
})
|
||||
|
||||
t.Run("Bad", func(t *testing.T) {
|
||||
arr := stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(make([]byte, stackitem.MaxSize/2)),
|
||||
stackitem.NewByteArray(make([]byte, stackitem.MaxSize/2)),
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
_ = s.jsonSerialize(ic, []stackitem.Item{arr})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("JSONDeserialize", func(t *testing.T) {
|
||||
t.Run("Good", func(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.jsonDeserialize(ic, []stackitem.Item{stackitem.Make("42")})
|
||||
})
|
||||
|
||||
require.Equal(t, stackitem.Make(42), actual)
|
||||
})
|
||||
t.Run("Bad", func(t *testing.T) {
|
||||
require.Panics(t, func() {
|
||||
_ = s.jsonDeserialize(ic, []stackitem.Item{stackitem.Make("{]")})
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
_ = s.jsonDeserialize(ic, []stackitem.Item{stackitem.NewInterop(nil)})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStdLibEncodeDecode(t *testing.T) {
|
||||
s := newStd()
|
||||
original := []byte("my pretty string")
|
||||
encoded64 := base64.StdEncoding.EncodeToString(original)
|
||||
encoded58 := base58.Encode(original)
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
var actual stackitem.Item
|
||||
|
||||
t.Run("Encode64", func(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.base64Encode(ic, []stackitem.Item{stackitem.Make(original)})
|
||||
})
|
||||
require.Equal(t, stackitem.Make(encoded64), actual)
|
||||
})
|
||||
t.Run("Encode58", func(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.base58Encode(ic, []stackitem.Item{stackitem.Make(original)})
|
||||
})
|
||||
require.Equal(t, stackitem.Make(encoded58), actual)
|
||||
})
|
||||
t.Run("Decode64/positive", func(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.base64Decode(ic, []stackitem.Item{stackitem.Make(encoded64)})
|
||||
})
|
||||
require.Equal(t, stackitem.Make(original), actual)
|
||||
})
|
||||
t.Run("Decode64/error", func(t *testing.T) {
|
||||
require.Panics(t, func() {
|
||||
_ = s.base64Decode(ic, []stackitem.Item{stackitem.Make(encoded64 + "%")})
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
_ = s.base64Decode(ic, []stackitem.Item{stackitem.NewInterop(nil)})
|
||||
})
|
||||
})
|
||||
t.Run("Decode58/positive", func(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.base58Decode(ic, []stackitem.Item{stackitem.Make(encoded58)})
|
||||
})
|
||||
require.Equal(t, stackitem.Make(original), actual)
|
||||
})
|
||||
t.Run("Decode58/error", func(t *testing.T) {
|
||||
require.Panics(t, func() {
|
||||
_ = s.base58Decode(ic, []stackitem.Item{stackitem.Make(encoded58 + "%")})
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
_ = s.base58Decode(ic, []stackitem.Item{stackitem.NewInterop(nil)})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStdLibSerialize(t *testing.T) {
|
||||
s := newStd()
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
|
||||
t.Run("recursive", func(t *testing.T) {
|
||||
arr := stackitem.NewArray(nil)
|
||||
arr.Append(arr)
|
||||
require.Panics(t, func() {
|
||||
_ = s.serialize(ic, []stackitem.Item{arr})
|
||||
})
|
||||
})
|
||||
t.Run("big item", func(t *testing.T) {
|
||||
require.Panics(t, func() {
|
||||
_ = s.serialize(ic, []stackitem.Item{stackitem.NewByteArray(make([]byte, stackitem.MaxSize))})
|
||||
})
|
||||
})
|
||||
t.Run("good", func(t *testing.T) {
|
||||
var (
|
||||
actualSerialized stackitem.Item
|
||||
actualDeserialized stackitem.Item
|
||||
)
|
||||
require.NotPanics(t, func() {
|
||||
actualSerialized = s.serialize(ic, []stackitem.Item{stackitem.Make(42)})
|
||||
})
|
||||
|
||||
w := io.NewBufBinWriter()
|
||||
stackitem.EncodeBinaryStackItem(stackitem.Make(42), w.BinWriter)
|
||||
require.NoError(t, w.Err)
|
||||
|
||||
encoded := w.Bytes()
|
||||
require.Equal(t, stackitem.Make(encoded), actualSerialized)
|
||||
|
||||
require.NotPanics(t, func() {
|
||||
actualDeserialized = s.deserialize(ic, []stackitem.Item{actualSerialized})
|
||||
})
|
||||
require.Equal(t, stackitem.Make(42), actualDeserialized)
|
||||
|
||||
t.Run("bad", func(t *testing.T) {
|
||||
encoded[0] ^= 0xFF
|
||||
require.Panics(t, func() {
|
||||
_ = s.deserialize(ic, []stackitem.Item{stackitem.Make(encoded)})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStdLibSerializeDeserialize(t *testing.T) {
|
||||
s := newStd()
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
var actual stackitem.Item
|
||||
|
||||
checkSerializeDeserialize := func(t *testing.T, value interface{}, expected stackitem.Item) {
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.serialize(ic, []stackitem.Item{stackitem.Make(value)})
|
||||
})
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.deserialize(ic, []stackitem.Item{actual})
|
||||
})
|
||||
require.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
t.Run("Bool", func(t *testing.T) {
|
||||
checkSerializeDeserialize(t, true, stackitem.NewBool(true))
|
||||
})
|
||||
t.Run("ByteArray", func(t *testing.T) {
|
||||
checkSerializeDeserialize(t, []byte{1, 2, 3}, stackitem.NewByteArray([]byte{1, 2, 3}))
|
||||
})
|
||||
t.Run("Integer", func(t *testing.T) {
|
||||
checkSerializeDeserialize(t, 48, stackitem.NewBigInteger(big.NewInt(48)))
|
||||
})
|
||||
t.Run("Array", func(t *testing.T) {
|
||||
arr := stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make(true),
|
||||
stackitem.Make(123),
|
||||
stackitem.NewMap()})
|
||||
checkSerializeDeserialize(t, arr, arr)
|
||||
})
|
||||
t.Run("Struct", func(t *testing.T) {
|
||||
st := stackitem.NewStruct([]stackitem.Item{
|
||||
stackitem.Make(true),
|
||||
stackitem.Make(123),
|
||||
stackitem.NewMap(),
|
||||
})
|
||||
checkSerializeDeserialize(t, st, st)
|
||||
})
|
||||
t.Run("Map", func(t *testing.T) {
|
||||
item := stackitem.NewMap()
|
||||
item.Add(stackitem.Make(true), stackitem.Make([]byte{1, 2, 3}))
|
||||
item.Add(stackitem.Make([]byte{0}), stackitem.Make(false))
|
||||
checkSerializeDeserialize(t, item, item)
|
||||
})
|
||||
t.Run("Serialize MapCompat", func(t *testing.T) {
|
||||
resHex := "480128036b6579280576616c7565"
|
||||
res, err := hex.DecodeString(resHex)
|
||||
require.NoError(t, err)
|
||||
|
||||
item := stackitem.NewMap()
|
||||
item.Add(stackitem.Make([]byte("key")), stackitem.Make([]byte("value")))
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.serialize(ic, []stackitem.Item{stackitem.Make(item)})
|
||||
})
|
||||
bytes, err := actual.TryBytes()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, res, bytes)
|
||||
})
|
||||
t.Run("Serialize Interop", func(t *testing.T) {
|
||||
require.Panics(t, func() {
|
||||
actual = s.serialize(ic, []stackitem.Item{stackitem.NewInterop("kek")})
|
||||
})
|
||||
})
|
||||
t.Run("Serialize Array bad", func(t *testing.T) {
|
||||
item := stackitem.NewArray([]stackitem.Item{stackitem.NewBool(true), stackitem.NewBool(true)})
|
||||
item.Value().([]stackitem.Item)[1] = item
|
||||
require.Panics(t, func() {
|
||||
actual = s.serialize(ic, []stackitem.Item{item})
|
||||
})
|
||||
})
|
||||
t.Run("Deserialize unknown", func(t *testing.T) {
|
||||
data, err := stackitem.SerializeItem(stackitem.NewBigInteger(big.NewInt(123)))
|
||||
require.NoError(t, err)
|
||||
|
||||
data[0] = 0xFF
|
||||
require.Panics(t, func() {
|
||||
actual = s.deserialize(ic, []stackitem.Item{stackitem.Make(data)})
|
||||
})
|
||||
})
|
||||
t.Run("Deserialize not a byte array", func(t *testing.T) {
|
||||
require.Panics(t, func() {
|
||||
actual = s.deserialize(ic, []stackitem.Item{stackitem.NewInterop(nil)})
|
||||
})
|
||||
})
|
||||
}
|
|
@ -29,7 +29,7 @@ import (
|
|||
)
|
||||
|
||||
// getTestContractState returns test contract which uses oracles.
|
||||
func getOracleContractState(h util.Uint160) *state.Contract {
|
||||
func getOracleContractState(h util.Uint160, stdHash util.Uint160) *state.Contract {
|
||||
w := io.NewBufBinWriter()
|
||||
emit.Int(w.BinWriter, 5)
|
||||
emit.Opcodes(w.BinWriter, opcode.PACK)
|
||||
|
@ -49,7 +49,9 @@ func getOracleContractState(h util.Uint160) *state.Contract {
|
|||
emit.Opcodes(w.BinWriter, opcode.ABORT)
|
||||
emit.Int(w.BinWriter, 4) // url, userData, code, result
|
||||
emit.Opcodes(w.BinWriter, opcode.PACK)
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemBinarySerialize)
|
||||
emit.Int(w.BinWriter, 1) // 1 byte (args count for `serialize`)
|
||||
emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte (pack args into array for `serialize`)
|
||||
emit.AppCallNoArgs(w.BinWriter, stdHash, "serialize", callflag.All) // 39 bytes
|
||||
emit.String(w.BinWriter, "lastOracleResponse")
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext)
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemStoragePut)
|
||||
|
@ -117,7 +119,7 @@ func TestOracle_Request(t *testing.T) {
|
|||
bc := newTestChain(t)
|
||||
|
||||
orc := bc.contracts.Oracle
|
||||
cs := getOracleContractState(orc.Hash)
|
||||
cs := getOracleContractState(orc.Hash, bc.contracts.Std.Hash)
|
||||
require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs))
|
||||
|
||||
gasForResponse := int64(2000_1234)
|
||||
|
|
|
@ -97,9 +97,9 @@ func TestCreateResponseTx(t *testing.T) {
|
|||
bc.SetOracle(orc)
|
||||
tx, err := orc.CreateResponseTx(int64(req.GasForResponse), 1, resp)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 167, tx.Size())
|
||||
assert.Equal(t, int64(2216640), tx.NetworkFee)
|
||||
assert.Equal(t, int64(97783360), tx.SystemFee)
|
||||
assert.Equal(t, 166, tx.Size())
|
||||
assert.Equal(t, int64(2215610), tx.NetworkFee)
|
||||
assert.Equal(t, int64(97784390), tx.SystemFee)
|
||||
}
|
||||
|
||||
func TestOracle_InvalidWallet(t *testing.T) {
|
||||
|
@ -130,7 +130,7 @@ func TestOracle(t *testing.T) {
|
|||
orc1.UpdateNativeContract(orcNative.NEF.Script, orcNative.GetOracleResponseScript(), orcNative.Hash, md.MD.Offset)
|
||||
orc2.UpdateNativeContract(orcNative.NEF.Script, orcNative.GetOracleResponseScript(), orcNative.Hash, md.MD.Offset)
|
||||
|
||||
cs := getOracleContractState(bc.contracts.Oracle.Hash)
|
||||
cs := getOracleContractState(bc.contracts.Oracle.Hash, bc.contracts.Std.Hash)
|
||||
require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs))
|
||||
|
||||
putOracleRequest(t, cs.Hash, bc, "http://get.1234", nil, "handle", []byte{}, 10_000_000)
|
||||
|
@ -271,7 +271,7 @@ func TestOracleFull(t *testing.T) {
|
|||
orc.OnTransaction = func(tx *transaction.Transaction) { _ = mp.Add(tx, bc) }
|
||||
bc.SetOracle(orc)
|
||||
|
||||
cs := getOracleContractState(bc.contracts.Oracle.Hash)
|
||||
cs := getOracleContractState(bc.contracts.Oracle.Hash, bc.contracts.Std.Hash)
|
||||
require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs))
|
||||
|
||||
go bc.Run()
|
||||
|
|
|
@ -17,14 +17,14 @@ func TestGenesisBlockMainNet(t *testing.T) {
|
|||
block, err := createGenesisBlock(cfg.ProtocolConfiguration)
|
||||
require.NoError(t, err)
|
||||
|
||||
expect := "d71dfebcc59d42b2f3b3f0e0d6b3b77a4880276db1df92c08c7c1bac94bece35"
|
||||
expect := "de3bfe3e328af04d48f62bd7a9c533641cc0e1fb6a7741c5119d6a6eaedc5269"
|
||||
assert.Equal(t, expect, block.Hash().StringLE())
|
||||
}
|
||||
|
||||
func TestGetConsensusAddressMainNet(t *testing.T) {
|
||||
var (
|
||||
consensusAddr = "NiVihDFvZacZhujTWkBhRz32UDuNRp416f"
|
||||
consensusScript = "f7b4d00143932f3b6243cfc06cb4a68f22c739e2"
|
||||
consensusAddr = "NSX179gdoQmF8nu34rQdL4dYAfdCQhHtQS"
|
||||
consensusScript = "4870eaa62eee7c76b76d2ae933d4c027f5f5c77d"
|
||||
)
|
||||
|
||||
cfg, err := config.Load("../../config", netmode.MainNet)
|
||||
|
|
|
@ -18,7 +18,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
)
|
||||
|
||||
// coordLen is the number of bytes in serialized X or Y coordinate.
|
||||
|
@ -317,8 +316,7 @@ func (p *PublicKey) GetVerificationScript() []byte {
|
|||
return buf.Bytes()
|
||||
}
|
||||
emit.Bytes(buf.BinWriter, b)
|
||||
emit.Opcodes(buf.BinWriter, opcode.PUSHNULL)
|
||||
emit.Syscall(buf.BinWriter, interopnames.NeoCryptoVerifyWithECDsaSecp256r1)
|
||||
emit.Syscall(buf.BinWriter, interopnames.NeoCryptoCheckSig)
|
||||
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ func TestPubkeyToAddress(t *testing.T) {
|
|||
pubKey, err := NewPublicKeyFromString("031ee4e73a17d8f76dc02532e2620bcb12425b33c0c9f9694cc2caa8226b68cad4")
|
||||
require.NoError(t, err)
|
||||
actual := pubKey.Address()
|
||||
expected := "NcKJdJTEDeCSV9BJAKWWxkBMcHTeVnSzJo"
|
||||
expected := "NWmVWWvFA6RxvTs4kgY1NnwTXeLYwWxPb1"
|
||||
require.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
Package binary provides binary serialization routines.
|
||||
*/
|
||||
package binary
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/neogointernal"
|
||||
)
|
||||
|
||||
// Serialize serializes any given item into a byte slice. It works for all
|
||||
// regular VM types (not ones from interop package) and allows to save them in
|
||||
// storage or pass into Notify and then Deserialize them on the next run or in
|
||||
// the external event receiver. It uses `System.Binary.Serialize` syscall.
|
||||
func Serialize(item interface{}) []byte {
|
||||
return neogointernal.Syscall1("System.Binary.Serialize", item).([]byte)
|
||||
}
|
||||
|
||||
// Deserialize unpacks previously serialized value from a byte slice, it's the
|
||||
// opposite of Serialize. It uses `System.Binary.Deserialize` syscall.
|
||||
func Deserialize(b []byte) interface{} {
|
||||
return neogointernal.Syscall1("System.Binary.Deserialize", b)
|
||||
}
|
||||
|
||||
// Base64Encode encodes given byte slice into a base64 string and returns byte
|
||||
// representation of this string. It uses `System.Binary.Base64Encode` interop.
|
||||
func Base64Encode(b []byte) string {
|
||||
return neogointernal.Syscall1("System.Binary.Base64Encode", b).(string)
|
||||
}
|
||||
|
||||
// Base64Decode decodes given base64 string represented as a byte slice into
|
||||
// byte slice. It uses `System.Binary.Base64Decode` interop.
|
||||
func Base64Decode(b []byte) []byte {
|
||||
return neogointernal.Syscall1("System.Binary.Base64Decode", b).([]byte)
|
||||
}
|
||||
|
||||
// Base58Encode encodes given byte slice into a base58 string and returns byte
|
||||
// representation of this string. It uses `System.Binary.Base58Encode` syscall.
|
||||
func Base58Encode(b []byte) string {
|
||||
return neogointernal.Syscall1("System.Binary.Base58Encode", b).(string)
|
||||
}
|
||||
|
||||
// Base58Decode decodes given base58 string represented as a byte slice into
|
||||
// a new byte slice. It uses `System.Binary.Base58Decode` syscall.
|
||||
func Base58Decode(b []byte) []byte {
|
||||
return neogointernal.Syscall1("System.Binary.Base58Decode", b).([]byte)
|
||||
}
|
||||
|
||||
// Itoa converts num in a given base to string. Base should be either 10 or 16.
|
||||
// It uses `System.Binary.Itoa` syscall.
|
||||
func Itoa(num int, base int) string {
|
||||
return neogointernal.Syscall2("System.Binary.Itoa", num, base).(string)
|
||||
}
|
||||
|
||||
// Atoi converts string to a number in a given base. Base should be either 10 or 16.
|
||||
// It uses `System.Binary.Atoi` syscall.
|
||||
func Atoi(s string, base int) int {
|
||||
return neogointernal.Syscall2("System.Binary.Atoi", s, base).(int)
|
||||
}
|
|
@ -8,36 +8,15 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/interop/neogointernal"
|
||||
)
|
||||
|
||||
// SHA256 computes SHA256 hash of b. It uses `Neo.Crypto.SHA256` syscall.
|
||||
func SHA256(b []byte) interop.Hash256 {
|
||||
return neogointernal.Syscall1("Neo.Crypto.SHA256", b).(interop.Hash256)
|
||||
// CheckMultisig checks that script container (transaction) is signed by multiple
|
||||
// ECDSA keys at once. It uses `Neo.Crypto.CheckMultisig` syscall.
|
||||
func CheckMultisig(pubs []interop.PublicKey, sigs []interop.Signature) bool {
|
||||
return neogointernal.Syscall2("Neo.Crypto.CheckMultisig", pubs, sigs).(bool)
|
||||
}
|
||||
|
||||
// RIPEMD160 computes RIPEMD160 hash of b. It uses `Neo.Crypto.RIPEMD160` syscall.
|
||||
func RIPEMD160(b []byte) interop.Hash160 {
|
||||
return neogointernal.Syscall1("Neo.Crypto.RIPEMD160", b).(interop.Hash160)
|
||||
}
|
||||
|
||||
// ECDsaSecp256r1Verify checks that sig is correct msg's signature for a given pub
|
||||
// (serialized public key). It uses `Neo.Crypto.VerifyWithECDsaSecp256r1` syscall.
|
||||
func ECDsaSecp256r1Verify(msg []byte, pub interop.PublicKey, sig interop.Signature) bool {
|
||||
return neogointernal.Syscall3("Neo.Crypto.VerifyWithECDsaSecp256r1", msg, pub, sig).(bool)
|
||||
}
|
||||
|
||||
// ECDsaSecp256k1Verify checks that sig is correct msg's signature for a given pub
|
||||
// (serialized public key). It uses `Neo.Crypto.VerifyWithECDsaSecp256k1` syscall.
|
||||
func ECDsaSecp256k1Verify(msg []byte, pub interop.PublicKey, sig interop.Signature) bool {
|
||||
return neogointernal.Syscall3("Neo.Crypto.VerifyWithECDsaSecp256k1", msg, pub, sig).(bool)
|
||||
}
|
||||
|
||||
// ECDSASecp256r1CheckMultisig checks multiple ECDSA signatures at once. It uses
|
||||
// `Neo.Crypto.CheckMultisigWithECDsaSecp256r1` syscall.
|
||||
func ECDSASecp256r1CheckMultisig(msg []byte, pubs []interop.PublicKey, sigs []interop.Signature) bool {
|
||||
return neogointernal.Syscall3("Neo.Crypto.CheckMultisigWithECDsaSecp256r1", msg, pubs, sigs).(bool)
|
||||
}
|
||||
|
||||
// ECDSASecp256k1CheckMultisig checks multiple ECDSA signatures at once. It uses
|
||||
// `Neo.Crypto.CheckMultisigWithECDsaSecp256k1` syscall.
|
||||
func ECDSASecp256k1CheckMultisig(msg []byte, pubs []interop.PublicKey, sigs []interop.Signature) bool {
|
||||
return neogointernal.Syscall3("Neo.Crypto.CheckMultisigWithECDsaSecp256k1", msg, pubs, sigs).(bool)
|
||||
// CheckSig checks that sig is correct signature of the script container
|
||||
// (transaction) for a given pub (serialized public key). It uses
|
||||
// `Neo.Crypto.CheckSig` syscall.
|
||||
func CheckSig(pub interop.PublicKey, sig interop.Signature) bool {
|
||||
return neogointernal.Syscall2("Neo.Crypto.CheckSig", pub, sig).(bool)
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
Package json provides various JSON serialization/deserialization routines.
|
||||
*/
|
||||
package json
|
||||
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop/neogointernal"
|
||||
|
||||
// ToJSON serializes value to json. It uses `System.Json.Serialize` syscall.
|
||||
// Serialization format is the following:
|
||||
// []byte -> base64 string
|
||||
// bool -> json boolean
|
||||
// nil -> Null
|
||||
// string -> base64 encoded sequence of underlying bytes
|
||||
// (u)int* -> integer, only value in -2^53..2^53 are allowed
|
||||
// []interface{} -> json array
|
||||
// map[type1]type2 -> json object with string keys marshaled as strings (not base64).
|
||||
func ToJSON(item interface{}) []byte {
|
||||
return neogointernal.Syscall1("System.Json.Serialize", item).([]byte)
|
||||
}
|
||||
|
||||
// FromJSON deserializes value from json. It uses `System.Json.Deserialize` syscall.
|
||||
// It performs deserialization as follows:
|
||||
// strings -> []byte (string) from base64
|
||||
// integers -> (u)int* types
|
||||
// null -> interface{}(nil)
|
||||
// arrays -> []interface{}
|
||||
// maps -> map[string]interface{}
|
||||
func FromJSON(data []byte) interface{} {
|
||||
return neogointernal.Syscall1("System.Json.Deserialize", data).(interface{})
|
||||
}
|
34
pkg/interop/native/crypto/crypto.go
Normal file
34
pkg/interop/native/crypto/crypto.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||
)
|
||||
|
||||
// Hash represents CryptoLib contract hash.
|
||||
const Hash = "\x1b\xf5\x75\xab\x11\x89\x68\x84\x13\x61\x0a\x35\xa1\x28\x86\xcd\xe0\xb6\x6c\x72"
|
||||
|
||||
// NamedCurve represents named elliptic curve.
|
||||
type NamedCurve byte
|
||||
|
||||
// Various named elliptic curves.
|
||||
const (
|
||||
Secp256k1 NamedCurve = 22
|
||||
Secp256r1 NamedCurve = 23
|
||||
)
|
||||
|
||||
// Sha256 calls `sha256` method of native CryptoLib contract and computes SHA256 hash of b.
|
||||
func Sha256(b []byte) interop.Hash256 {
|
||||
return contract.Call(interop.Hash160(Hash), "sha256", contract.NoneFlag, b).(interop.Hash256)
|
||||
}
|
||||
|
||||
// Ripemd160 calls `ripemd160` method of native CryptoLib contract and computes RIPEMD160 hash of b.
|
||||
func Ripemd160(b []byte) interop.Hash160 {
|
||||
return contract.Call(interop.Hash160(Hash), "ripemd160", contract.NoneFlag, b).(interop.Hash160)
|
||||
}
|
||||
|
||||
// VerifyWithECDsa calls `verifyWithECDsa` method of native CryptoLib contract and checks that sig is
|
||||
// correct msg's signature for a given pub (serialized public key on a given curve).
|
||||
func VerifyWithECDsa(msg []byte, pub interop.PublicKey, sig interop.Signature, curve NamedCurve) bool {
|
||||
return contract.Call(interop.Hash160(Hash), "verifyWithECDsa", contract.NoneFlag, msg, pub, sig, curve).(bool)
|
||||
}
|
97
pkg/interop/native/std/std.go
Normal file
97
pkg/interop/native/std/std.go
Normal file
|
@ -0,0 +1,97 @@
|
|||
package std
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||
)
|
||||
|
||||
// Hash represents StdLib contract hash.
|
||||
const Hash = "\xc0\xef\x39\xce\xe0\xe4\xe9\x25\xc6\xc2\xa0\x6a\x79\xe1\x44\x0d\xd8\x6f\xce\xac"
|
||||
|
||||
// Serialize calls `serialize` method of StdLib native contract and serializes
|
||||
// any given item into a byte slice. It works for all regular VM types (not ones
|
||||
// from interop package) and allows to save them in storage or pass into Notify
|
||||
// and then Deserialize them on the next run or in the external event receiver.
|
||||
func Serialize(item interface{}) []byte {
|
||||
return contract.Call(interop.Hash160(Hash), "serialize", contract.NoneFlag,
|
||||
item).([]byte)
|
||||
}
|
||||
|
||||
// Deserialize calls `deserialize` method of StdLib native contract and unpacks
|
||||
// previously serialized value from a byte slice, it's the opposite of Serialize.
|
||||
func Deserialize(b []byte) interface{} {
|
||||
return contract.Call(interop.Hash160(Hash), "deserialize", contract.NoneFlag,
|
||||
b)
|
||||
}
|
||||
|
||||
// JSONSerialize serializes value to json. It uses `jsonSerialize` method of StdLib native
|
||||
// contract.
|
||||
// Serialization format is the following:
|
||||
// []byte -> base64 string
|
||||
// bool -> json boolean
|
||||
// nil -> Null
|
||||
// string -> base64 encoded sequence of underlying bytes
|
||||
// (u)int* -> integer, only value in -2^53..2^53 are allowed
|
||||
// []interface{} -> json array
|
||||
// map[type1]type2 -> json object with string keys marshaled as strings (not base64).
|
||||
func JSONSerialize(item interface{}) []byte {
|
||||
return contract.Call(interop.Hash160(Hash), "jsonSerialize", contract.NoneFlag,
|
||||
item).([]byte)
|
||||
}
|
||||
|
||||
// JSONDeserialize deserializes value from json. It uses `jsonDeserialize` method of StdLib
|
||||
// native contract.
|
||||
// It performs deserialization as follows:
|
||||
// strings -> []byte (string) from base64
|
||||
// integers -> (u)int* types
|
||||
// null -> interface{}(nil)
|
||||
// arrays -> []interface{}
|
||||
// maps -> map[string]interface{}
|
||||
func JSONDeserialize(data []byte) interface{} {
|
||||
return contract.Call(interop.Hash160(Hash), "jsonDeserialize", contract.NoneFlag,
|
||||
data)
|
||||
}
|
||||
|
||||
// Base64Encode calls `base64Encode` method of StdLib native contract and encodes
|
||||
// given byte slice into a base64 string and returns byte representation of this
|
||||
// string.
|
||||
func Base64Encode(b []byte) string {
|
||||
return contract.Call(interop.Hash160(Hash), "base64Encode", contract.NoneFlag,
|
||||
b).(string)
|
||||
}
|
||||
|
||||
// Base64Decode calls `base64Decode` method of StdLib native contract and decodes
|
||||
// given base64 string represented as a byte slice into byte slice.
|
||||
func Base64Decode(b []byte) []byte {
|
||||
return contract.Call(interop.Hash160(Hash), "base64Decode", contract.NoneFlag,
|
||||
b).([]byte)
|
||||
}
|
||||
|
||||
// Base58Encode calls `base58Encode` method of StdLib native contract and encodes
|
||||
// given byte slice into a base58 string and returns byte representation of this
|
||||
// string.
|
||||
func Base58Encode(b []byte) string {
|
||||
return contract.Call(interop.Hash160(Hash), "base58Encode", contract.NoneFlag,
|
||||
b).(string)
|
||||
}
|
||||
|
||||
// Base58Decode calls `base58Decode` method of StdLib native contract and decodes
|
||||
// given base58 string represented as a byte slice into a new byte slice.
|
||||
func Base58Decode(b []byte) []byte {
|
||||
return contract.Call(interop.Hash160(Hash), "base58Decode", contract.NoneFlag,
|
||||
b).([]byte)
|
||||
}
|
||||
|
||||
// Itoa converts num in a given base to string. Base should be either 10 or 16.
|
||||
// It uses `itoa` method of StdLib native contract.
|
||||
func Itoa(num int, base int) string {
|
||||
return contract.Call(interop.Hash160(Hash), "itoa", contract.NoneFlag,
|
||||
num, base).(string)
|
||||
}
|
||||
|
||||
// Atoi converts string to a number in a given base. Base should be either 10 or 16.
|
||||
// It uses `atoi` method of StdLib native contract.
|
||||
func Atoi(s string, base int) int {
|
||||
return contract.Call(interop.Hash160(Hash), "atoi", contract.NoneFlag,
|
||||
s, base).(int)
|
||||
}
|
|
@ -1113,7 +1113,7 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
|
|||
name: "getnep17transfers_invalid_params_error 2",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
var stop uint32
|
||||
return c.GetNEP17Transfers("NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", nil, &stop, nil, nil)
|
||||
return c.GetNEP17Transfers("NTh9TnZTstvAePEYWDGLLxidBikJE24uTo", nil, &stop, nil, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1121,7 +1121,7 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
|
|||
invoke: func(c *Client) (interface{}, error) {
|
||||
var start uint32
|
||||
var limit int
|
||||
return c.GetNEP17Transfers("NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", &start, nil, &limit, nil)
|
||||
return c.GetNEP17Transfers("NTh9TnZTstvAePEYWDGLLxidBikJE24uTo", &start, nil, &limit, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1129,7 +1129,7 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
|
|||
invoke: func(c *Client) (interface{}, error) {
|
||||
var start, stop uint32
|
||||
var page int
|
||||
return c.GetNEP17Transfers("NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", &start, &stop, nil, &page)
|
||||
return c.GetNEP17Transfers("NTh9TnZTstvAePEYWDGLLxidBikJE24uTo", &start, &stop, nil, &page)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@ package server
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/internal/testchain"
|
||||
|
@ -139,8 +139,10 @@ func TestAddNetworkFee(t *testing.T) {
|
|||
priv := testchain.PrivateKeyByID(0)
|
||||
acc1 := wallet.NewAccountFromPrivateKey(priv)
|
||||
acc1.Contract.Deployed = true
|
||||
acc1.Contract.Script, _ = hex.DecodeString(verifyContractAVM)
|
||||
h, _ := util.Uint160DecodeStringLE(verifyContractHash)
|
||||
acc1.Contract.Script, err = base64.StdEncoding.DecodeString(verifyContractAVM)
|
||||
require.NoError(t, err)
|
||||
h, err := util.Uint160DecodeStringLE(verifyContractHash)
|
||||
require.NoError(t, err)
|
||||
tx.ValidUntilBlock = chain.BlockHeight() + 10
|
||||
|
||||
t.Run("Valid", func(t *testing.T) {
|
||||
|
|
|
@ -59,13 +59,13 @@ type rpcTestCase struct {
|
|||
check func(t *testing.T, e *executor, result interface{})
|
||||
}
|
||||
|
||||
const testContractHash = "500858b96054d3c302078882c30e76915aac1c83"
|
||||
const deploymentTxHash = "e5503038c2cd602c100690e266b75e2a9d3dda90a63791fd5ab3008ff053eaae"
|
||||
const genesisBlockHash = "9e7cf6fcfc8d0d6831fac75fa895535a5f1960f45a34754b57bff4d4929635c5"
|
||||
const testContractHash = "1e1c3024bd955ff3baf7cb92e3b7608c7bb3712b"
|
||||
const deploymentTxHash = "7cf43b182dee2e8bd2c5209cd230799aeba1b5b13000db682d917c89eacd1eae"
|
||||
const genesisBlockHash = "d237e3500d8b4cf0df3fd9c4c053016afae141207a6c732303bdd91aff444ecc"
|
||||
|
||||
const verifyContractHash = "03ffc0897543b9b709e0f8cab4a7682dae0ba943"
|
||||
const verifyContractAVM = "570300412d51083021700c14aa8acf859d4fe402b34e673f2156821796a488ebdb30716813cedb2869db289740"
|
||||
const testVerifyContractAVM = "VwcADBQBDAMOBQYMDQIODw0DDgcJAAAAANswcGgRVUH4J+yMIaonBwAAABFADBQNDwMCCQACAQMHAwQFAgEADgYMCdswcWkRVUH4J+yMIaonBwAAABJAE0A="
|
||||
const verifyContractHash = "5bb4bac40e961e334ba7bd36d2496010f67e246e"
|
||||
const verifyContractAVM = "VwMAQS1RCDAhcAwUVVQtU+0PVUb61E1umZEoZwIvzl7bMHFoE87bKGnbKJdA"
|
||||
const invokescriptContractAVM = "VwcADBQBDAMOBQYMDQIODw0DDgcJAAAAANswcGhB+CfsjCGqJgQRQAwUDQ8DAgkAAgEDBwMEBQIBAA4GDAnbMHFpQfgn7IwhqiYEEkATQA=="
|
||||
|
||||
var rpcTestCases = map[string][]rpcTestCase{
|
||||
"getapplicationlog": {
|
||||
|
@ -183,7 +183,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
check: func(t *testing.T, e *executor, cs interface{}) {
|
||||
res, ok := cs.(*state.Contract)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, int32(-5), res.ID)
|
||||
assert.Equal(t, int32(-7), res.ID)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -743,8 +743,8 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
},
|
||||
{
|
||||
name: "positive, good witness",
|
||||
// script is base64-encoded `test_verify.avm` representation, hashes are hex-encoded LE bytes of hashes used in the contract with `0x` prefix
|
||||
params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c01","0x090c060e00010205040307030102000902030f0d"]]`, testVerifyContractAVM),
|
||||
// script is base64-encoded `invokescript_contract.avm` representation, hashes are hex-encoded LE bytes of hashes used in the contract with `0x` prefix
|
||||
params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c01","0x090c060e00010205040307030102000902030f0d"]]`, invokescriptContractAVM),
|
||||
result: func(e *executor) interface{} { return &result.Invoke{} },
|
||||
check: func(t *testing.T, e *executor, inv interface{}) {
|
||||
res, ok := inv.(*result.Invoke)
|
||||
|
@ -756,7 +756,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
},
|
||||
{
|
||||
name: "positive, bad witness of second hash",
|
||||
params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c01"]]`, testVerifyContractAVM),
|
||||
params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c01"]]`, invokescriptContractAVM),
|
||||
result: func(e *executor) interface{} { return &result.Invoke{} },
|
||||
check: func(t *testing.T, e *executor, inv interface{}) {
|
||||
res, ok := inv.(*result.Invoke)
|
||||
|
@ -768,7 +768,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
},
|
||||
{
|
||||
name: "positive, no good hashes",
|
||||
params: fmt.Sprintf(`["%s"]`, testVerifyContractAVM),
|
||||
params: fmt.Sprintf(`["%s"]`, invokescriptContractAVM),
|
||||
result: func(e *executor) interface{} { return &result.Invoke{} },
|
||||
check: func(t *testing.T, e *executor, inv interface{}) {
|
||||
res, ok := inv.(*result.Invoke)
|
||||
|
@ -780,7 +780,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
},
|
||||
{
|
||||
name: "positive, bad hashes witness",
|
||||
params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c02"]]`, testVerifyContractAVM),
|
||||
params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c02"]]`, invokescriptContractAVM),
|
||||
result: func(e *executor) interface{} { return &result.Invoke{} },
|
||||
check: func(t *testing.T, e *executor, inv interface{}) {
|
||||
res, ok := inv.(*result.Invoke)
|
||||
|
@ -817,7 +817,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
assert.NotNil(t, res.Script)
|
||||
assert.Equal(t, "HALT", res.State)
|
||||
assert.NotEqual(t, 0, res.GasConsumed)
|
||||
assert.Equal(t, true, res.Stack[0].Value().(bool))
|
||||
assert.Equal(t, true, res.Stack[0].Value().(bool), fmt.Sprintf("check address in verification_contract.go: expected %s", testchain.PrivateKeyByID(0).Address()))
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -865,12 +865,12 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
"sendrawtransaction": {
|
||||
{
|
||||
name: "positive",
|
||||
params: `["AAsAAACAlpgAAAAAACYcEwAAAAAAsAQAAAGqis+FnU/kArNOZz8hVoIXlqSI6wEAXQMA6HZIFwAAAAwUeLpMJACf5RDhNsmZWi4FIV4b5NwMFKqKz4WdT+QCs05nPyFWgheWpIjrE8AMCHRyYW5zZmVyDBQlBZ7LSHjTqHX5HFHO3tMw1Fdf3kFifVtSOAFCDEDqL1as9/ZGKdySLWWmAXbzljr9S3wlnyAXo6UTk0b46lRwRiRZCDKst3lAaaspg93IYrA7ajPUQozUxFy8CUHCKQwhArNiK/QBe9/jF8WK7V9MdT8ga324lgRvp9d0u8S/f43CC0GVRA14"]`,
|
||||
params: `["ADQSAADA2KcAAAAAABDiEgAAAAAAgBYAAAFVVC1T7Q9VRvrUTW6ZkShnAi/OXgEAYBDAAwDodkgXAAAADBRdSe/t0S4+BgGLRljbEKiXX8gLTgwUVVQtU+0PVUb61E1umZEoZwIvzl4UwB8MCHRyYW5zZmVyDBT1Y+pAvCg9TQ4FxI6jBbPyoHNA70FifVtSOQFCDEAppqgOf7RZvrS+uOVzVNlcQAQnyujtzHzv9/Za+FFkxWFd8mZ6AvWnFXAL0W5NafW4xyP7Kp/qgWCmZrHINaLkKAwhArNiK/QBe9/jF8WK7V9MdT8ga324lgRvp9d0u8S/f43CQXR0dqo="]`,
|
||||
result: func(e *executor) interface{} { return &result.RelayResult{} },
|
||||
check: func(t *testing.T, e *executor, inv interface{}) {
|
||||
res, ok := inv.(*result.RelayResult)
|
||||
require.True(t, ok)
|
||||
expectedHash, err := util.Uint256DecodeStringLE("ab5573cfc8d70774f04aa7d5521350cfc1aa1239c44c24e490e139408cd46a57")
|
||||
expectedHash, err := util.Uint256DecodeStringLE("3b133d0c2912da4f99680ae3a5f0e178bc761f2c360662a1fabbe1a8dbe309ea")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expectedHash, res.Hash)
|
||||
},
|
||||
|
@ -1598,7 +1598,7 @@ func checkNep17Balances(t *testing.T, e *executor, acc interface{}) {
|
|||
},
|
||||
{
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
Amount: "78994294100",
|
||||
Amount: "78994302340",
|
||||
LastUpdated: 8,
|
||||
}},
|
||||
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
|
||||
|
|
BIN
pkg/rpc/server/testdata/test_verify.avm
vendored
BIN
pkg/rpc/server/testdata/test_verify.avm
vendored
Binary file not shown.
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
|
@ -6,9 +6,9 @@ import (
|
|||
)
|
||||
|
||||
// Verify is a verification contract method.
|
||||
// It returns true iff it is signed by NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc (id-0 private key from testchain).
|
||||
// It returns true iff it is signed by NTh9TnZTstvAePEYWDGLLxidBikJE24uTo (id-0 private key from testchain).
|
||||
func Verify() bool {
|
||||
tx := runtime.GetScriptContainer()
|
||||
addr := util.FromAddress("NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc")
|
||||
addr := util.FromAddress("NTh9TnZTstvAePEYWDGLLxidBikJE24uTo")
|
||||
return util.Equals(string(tx.Sender), string(addr))
|
||||
}
|
||||
|
|
66
pkg/services/notary/testdata/notary1.json
vendored
66
pkg/services/notary/testdata/notary1.json
vendored
|
@ -1 +1,65 @@
|
|||
{"version":"3.0","accounts":[{"address":"NSbjd7dSePTZ6QpADAuM5722QpBmL5124W","key":"6PYVWTfkNCYvyQhyFLHH5dyRyT6jSi8u8Z8kn122PACfsDWi4QgkGm8FyW","label":"NotaryNode1","contract":{"script":"DCEDm5PmbOfVPmYXTSVW903XnOhhNBTsF9oDlVYusIH/ui0LQZVEDXg=","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"lock":false,"isdefault":false},{"address":"NisSvmSd2Lp28tjr8EqCZB5ahHDvBExo2j","key":"6PYLvgnZNwhiiZPiSCw3B3bHSFwbSXgh3MkGt4gL69MD8Sw7LMnuUgM9KQ","label":"three","contract":{"script":"DCEDHRWEIGXHCwUU2Fc7B0qrYPezXR0sfdEduRExyzIKVC8LQZVEDXg=","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"lock":false,"isdefault":false},{"address":"NRCCdGifyUWKnFotZhcgKpmxhhVJSJb94r","key":"6PYKXkuJ7G6bTj62bjy8fsBLF5okYNdAEBhKPCv8nmcALCtk2yPtBo835p","label":"four","contract":{"script":"DCECmUfs/gqKHd3AdJm5+Ev6zkubV8pP8DZzgu8+t5WdphILQZVEDXg=","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"lock":false,"isdefault":false}],"scrypt":{"n":16384,"r":8,"p":8},"extra":{"Tokens":null}}
|
||||
{
|
||||
"scrypt" : {
|
||||
"n" : 16384,
|
||||
"r" : 8,
|
||||
"p" : 8
|
||||
},
|
||||
"accounts" : [
|
||||
{
|
||||
"contract" : {
|
||||
"parameters" : [
|
||||
{
|
||||
"type" : "Signature",
|
||||
"name" : "parameter0"
|
||||
}
|
||||
],
|
||||
"deployed" : false,
|
||||
"script" : "DCEDm5PmbOfVPmYXTSVW903XnOhhNBTsF9oDlVYusIH/ui1BdHR2qg=="
|
||||
},
|
||||
"label" : "NotaryNode1",
|
||||
"address" : "NS6vb4uE8wdQfcQbFcRY7yquSbwbVcMSV3",
|
||||
"isdefault" : false,
|
||||
"lock" : false,
|
||||
"key" : "6PYMGBef95jMZJTQcH9ZP5PuecWa2H86HFbdnfe7VQs8uPZ3S6pu4D5NpP"
|
||||
},
|
||||
{
|
||||
"contract" : {
|
||||
"script" : "DCEDHRWEIGXHCwUU2Fc7B0qrYPezXR0sfdEduRExyzIKVC9BdHR2qg==",
|
||||
"deployed" : false,
|
||||
"parameters" : [
|
||||
{
|
||||
"name" : "parameter0",
|
||||
"type" : "Signature"
|
||||
}
|
||||
]
|
||||
},
|
||||
"label" : "three",
|
||||
"address" : "NakELwR1i6brB7EmYLc6yPbvk78Qi5Qbpi",
|
||||
"isdefault" : false,
|
||||
"lock" : false,
|
||||
"key" : "6PYLm6kse9FVpKoBbhYYSFHhFUUL2bZYePU95x7Ncknu798WEHYmTuUijR"
|
||||
},
|
||||
{
|
||||
"contract" : {
|
||||
"parameters" : [
|
||||
{
|
||||
"name" : "parameter0",
|
||||
"type" : "Signature"
|
||||
}
|
||||
],
|
||||
"deployed" : false,
|
||||
"script" : "DCECmUfs/gqKHd3AdJm5+Ev6zkubV8pP8DZzgu8+t5WdphJBdHR2qg=="
|
||||
},
|
||||
"key" : "6PYWBWehojbBn8U2XWcXxuWqPrnp9qwQ5rD3RKQza1iR5ZBCPHXxCQonYm",
|
||||
"isdefault" : false,
|
||||
"lock" : false,
|
||||
"address" : "NLWXE5CMEqJzEVtscF4BoTvSbiBr1FwtBb",
|
||||
"label" : "four"
|
||||
}
|
||||
],
|
||||
"extra" : {
|
||||
"Tokens" : null
|
||||
},
|
||||
"version" : "3.0"
|
||||
}
|
||||
|
||||
|
|
31
pkg/services/notary/testdata/notary2.json
vendored
31
pkg/services/notary/testdata/notary2.json
vendored
|
@ -1 +1,30 @@
|
|||
{"version":"3.0","accounts":[{"address":"NfFcJvWcHe8SSS92hNZhyQUJ6cg3pb36Tf","key":"6PYU2QoD52Xt9Z6QmNGUJWn89qUD1W6QqAL4Y8nfTWtTKvmVpQh8wsH6qY","label":"NotaryNode2","contract":{"script":"DCECIcKj0GFdv4b1NZrw9X6zLNLWzmNKAxtw6olIMZxpPRQLQZVEDXg=","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"lock":false,"isdefault":false}],"scrypt":{"n":16384,"r":8,"p":8},"extra":{"Tokens":null}}
|
||||
{
|
||||
"scrypt" : {
|
||||
"r" : 8,
|
||||
"p" : 8,
|
||||
"n" : 16384
|
||||
},
|
||||
"version" : "3.0",
|
||||
"extra" : {
|
||||
"Tokens" : null
|
||||
},
|
||||
"accounts" : [
|
||||
{
|
||||
"address" : "NYt1oLCMMvqxnAVMJCSk87kZTP693GxK11",
|
||||
"key" : "6PYWejAoqoF4JT5P9N3EcqC5tRC1MXx2gZ1R2WWryjDUH1bMAo3Bd68nCo",
|
||||
"lock" : false,
|
||||
"isdefault" : false,
|
||||
"contract" : {
|
||||
"parameters" : [
|
||||
{
|
||||
"name" : "parameter0",
|
||||
"type" : "Signature"
|
||||
}
|
||||
],
|
||||
"deployed" : false,
|
||||
"script" : "DCECIcKj0GFdv4b1NZrw9X6zLNLWzmNKAxtw6olIMZxpPRRBdHR2qg=="
|
||||
},
|
||||
"label" : "NotaryNode2"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
31
pkg/services/oracle/testdata/oracle1.json
vendored
31
pkg/services/oracle/testdata/oracle1.json
vendored
|
@ -1 +1,30 @@
|
|||
{"version":"3.0","accounts":[{"address":"NMy1PN9GCdGc26YFG7JruYg7UBStw2pPKN","key":"6PYML6dDTMXJBD7ywRwiCAhseCPToWkMfvPUViuxiXM6s5oi7ggf4ho3AK","label":"","contract":{"script":"DCEDNxK01e1DnGA+TiGU3H4DKUuGliSz89/NuZCbVvA2u0wLQZVEDXg=","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"lock":false,"isdefault":false}],"scrypt":{"n":16384,"r":8,"p":8},"extra":{"Tokens":null}}
|
||||
{
|
||||
"accounts" : [
|
||||
{
|
||||
"address" : "NPcxgUcZorwb1njfRGL7JEyc6SsTku42ek",
|
||||
"key" : "6PYPy72Gnoif27u9Uy5r2sqMwTTYMLRBGwPcJmB1GP1FTPp4U3M9fZVdtg",
|
||||
"lock" : false,
|
||||
"isdefault" : false,
|
||||
"contract" : {
|
||||
"parameters" : [
|
||||
{
|
||||
"type" : "Signature",
|
||||
"name" : "parameter0"
|
||||
}
|
||||
],
|
||||
"script" : "DCEDNxK01e1DnGA+TiGU3H4DKUuGliSz89/NuZCbVvA2u0xBdHR2qg==",
|
||||
"deployed" : false
|
||||
},
|
||||
"label" : ""
|
||||
}
|
||||
],
|
||||
"extra" : {
|
||||
"Tokens" : null
|
||||
},
|
||||
"version" : "3.0",
|
||||
"scrypt" : {
|
||||
"n" : 16384,
|
||||
"p" : 8,
|
||||
"r" : 8
|
||||
}
|
||||
}
|
||||
|
|
31
pkg/services/oracle/testdata/oracle2.json
vendored
31
pkg/services/oracle/testdata/oracle2.json
vendored
|
@ -1 +1,30 @@
|
|||
{"version":"3.0","accounts":[{"address":"NU7QxQXULbmZU7kaWUaeF3r9v3zimU42bV","key":"6PYKv77p5wihN64XaPB5Nbci1sCLV5CrzSu8GKv7UHXHRtytfLt8zfrMgT","label":"","contract":{"script":"DCEDEXzwIl4Jhvsj98GYIPFFiedeb1QdP8T79uSBSDNsiswLQZVEDXg=","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"lock":false,"isdefault":false}],"scrypt":{"n":16384,"r":8,"p":8},"extra":{"Tokens":null}}
|
||||
{
|
||||
"version" : "3.0",
|
||||
"extra" : {
|
||||
"Tokens" : null
|
||||
},
|
||||
"accounts" : [
|
||||
{
|
||||
"isdefault" : false,
|
||||
"label" : "",
|
||||
"key" : "6PYTgfwm5kuahFNN391D6p21ivKrHpvr8Wnn1mBpMnavn6PxkK2prSsxye",
|
||||
"address" : "NhSCnPJdgLdxnQaYHmW9A3WFLT9DiicBfK",
|
||||
"lock" : false,
|
||||
"contract" : {
|
||||
"script" : "DCEDEXzwIl4Jhvsj98GYIPFFiedeb1QdP8T79uSBSDNsisxBdHR2qg==",
|
||||
"deployed" : false,
|
||||
"parameters" : [
|
||||
{
|
||||
"type" : "Signature",
|
||||
"name" : "parameter0"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"scrypt" : {
|
||||
"p" : 8,
|
||||
"n" : 16384,
|
||||
"r" : 8
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
)
|
||||
|
||||
// CreateMultiSigRedeemScript creates an "m out of n" type verification script
|
||||
|
@ -31,8 +30,7 @@ func CreateMultiSigRedeemScript(m int, publicKeys keys.PublicKeys) ([]byte, erro
|
|||
emit.Bytes(buf.BinWriter, pubKey.Bytes())
|
||||
}
|
||||
emit.Int(buf.BinWriter, int64(len(publicKeys)))
|
||||
emit.Opcodes(buf.BinWriter, opcode.PUSHNULL)
|
||||
emit.Syscall(buf.BinWriter, interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1)
|
||||
emit.Syscall(buf.BinWriter, interopnames.NeoCryptoCheckMultisig)
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
|
|
@ -32,9 +32,8 @@ func TestCreateMultiSigRedeemScript(t *testing.T) {
|
|||
}
|
||||
|
||||
assert.Equal(t, opcode.PUSH3, opcode.Opcode(br.ReadB()))
|
||||
assert.Equal(t, opcode.PUSHNULL, opcode.Opcode(br.ReadB()))
|
||||
assert.Equal(t, opcode.SYSCALL, opcode.Opcode(br.ReadB()))
|
||||
assert.Equal(t, interopnames.ToID([]byte(interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1)), br.ReadU32LE())
|
||||
assert.Equal(t, interopnames.ToID([]byte(interopnames.NeoCryptoCheckMultisig)), br.ReadU32LE())
|
||||
}
|
||||
|
||||
func TestCreateDefaultMultiSigRedeemScript(t *testing.T) {
|
||||
|
|
|
@ -299,8 +299,8 @@ func TestRunWithDifferentArguments(t *testing.T) {
|
|||
|
||||
func TestPrintOps(t *testing.T) {
|
||||
w := io.NewBufBinWriter()
|
||||
emit.Opcodes(w.BinWriter, opcode.PUSH1)
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemBinarySerialize)
|
||||
emit.String(w.BinWriter, "log")
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemRuntimeLog)
|
||||
emit.Instruction(w.BinWriter, opcode.PUSHDATA1, []byte{3, 1, 2, 3})
|
||||
script := w.Bytes()
|
||||
e := newTestVMCLI(t)
|
||||
|
@ -312,9 +312,9 @@ func TestPrintOps(t *testing.T) {
|
|||
e.checkNextLine(t, ".*no program loaded")
|
||||
e.checkNextLine(t, fmt.Sprintf("READY: loaded %d instructions", len(script)))
|
||||
e.checkNextLine(t, "INDEX.*OPCODE.*PARAMETER")
|
||||
e.checkNextLine(t, "0.*PUSH1")
|
||||
e.checkNextLine(t, "1.*SYSCALL.*System\\.Binary\\.Serialize")
|
||||
e.checkNextLine(t, "6.*PUSHDATA1.*010203")
|
||||
e.checkNextLine(t, "0.*PUSHDATA1.*6c6f67")
|
||||
e.checkNextLine(t, "5.*SYSCALL.*System\\.Runtime\\.Log")
|
||||
e.checkNextLine(t, "10.*PUSHDATA1.*010203")
|
||||
}
|
||||
|
||||
func TestLoadAbort(t *testing.T) {
|
||||
|
|
|
@ -13,8 +13,8 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
verifyInteropID = interopnames.ToID([]byte(interopnames.NeoCryptoVerifyWithECDsaSecp256r1))
|
||||
multisigInteropID = interopnames.ToID([]byte(interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1))
|
||||
verifyInteropID = interopnames.ToID([]byte(interopnames.NeoCryptoCheckSig))
|
||||
multisigInteropID = interopnames.ToID([]byte(interopnames.NeoCryptoCheckMultisig))
|
||||
)
|
||||
|
||||
func getNumOfThingsFromInstr(instr opcode.Opcode, param []byte) (int, bool) {
|
||||
|
@ -49,6 +49,9 @@ func IsMultiSigContract(script []byte) bool {
|
|||
// from the verification script of the contract.
|
||||
func ParseMultiSigContract(script []byte) (int, [][]byte, bool) {
|
||||
var nsigs, nkeys int
|
||||
if len(script) < 42 {
|
||||
return nsigs, nil, false
|
||||
}
|
||||
|
||||
ctx := NewContext(script)
|
||||
instr, param, err := ctx.Next()
|
||||
|
@ -87,10 +90,6 @@ func ParseMultiSigContract(script []byte) (int, [][]byte, bool) {
|
|||
if nkeys2 != nkeys {
|
||||
return nsigs, nil, false
|
||||
}
|
||||
instr, _, err = ctx.Next()
|
||||
if err != nil || instr != opcode.PUSHNULL {
|
||||
return nsigs, nil, false
|
||||
}
|
||||
instr, param, err = ctx.Next()
|
||||
if err != nil || instr != opcode.SYSCALL || binary.LittleEndian.Uint32(param) != multisigInteropID {
|
||||
return nsigs, nil, false
|
||||
|
@ -112,7 +111,7 @@ func IsSignatureContract(script []byte) bool {
|
|||
// ParseSignatureContract parses simple signature contract and returns
|
||||
// public key.
|
||||
func ParseSignatureContract(script []byte) ([]byte, bool) {
|
||||
if len(script) != 41 {
|
||||
if len(script) != 40 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
|
@ -122,10 +121,6 @@ func ParseSignatureContract(script []byte) ([]byte, bool) {
|
|||
return nil, false
|
||||
}
|
||||
pub := param
|
||||
instr, _, err = ctx.Next()
|
||||
if err != nil || instr != opcode.PUSHNULL {
|
||||
return nil, false
|
||||
}
|
||||
instr, param, err = ctx.Next()
|
||||
if err != nil || instr != opcode.SYSCALL || binary.LittleEndian.Uint32(param) != verifyInteropID {
|
||||
return nil, false
|
||||
|
|
|
@ -16,12 +16,11 @@ import (
|
|||
)
|
||||
|
||||
func testSignatureContract() []byte {
|
||||
prog := make([]byte, 41)
|
||||
prog := make([]byte, 40)
|
||||
prog[0] = byte(opcode.PUSHDATA1)
|
||||
prog[1] = 33
|
||||
prog[35] = byte(opcode.PUSHNULL)
|
||||
prog[36] = byte(opcode.SYSCALL)
|
||||
binary.LittleEndian.PutUint32(prog[37:], verifyInteropID)
|
||||
prog[35] = byte(opcode.SYSCALL)
|
||||
binary.LittleEndian.PutUint32(prog[36:], verifyInteropID)
|
||||
return prog
|
||||
}
|
||||
|
||||
|
@ -43,7 +42,7 @@ func TestIsSignatureContract(t *testing.T) {
|
|||
|
||||
t.Run("invalid interop ID", func(t *testing.T) {
|
||||
prog := testSignatureContract()
|
||||
binary.LittleEndian.PutUint32(prog[37:], ^verifyInteropID)
|
||||
binary.LittleEndian.PutUint32(prog[36:], ^verifyInteropID)
|
||||
assert.False(t, IsSignatureContract(prog))
|
||||
assert.False(t, IsStandardContract(prog))
|
||||
})
|
||||
|
@ -55,13 +54,6 @@ func TestIsSignatureContract(t *testing.T) {
|
|||
assert.False(t, IsStandardContract(prog))
|
||||
})
|
||||
|
||||
t.Run("no PUSHNULL", func(t *testing.T) {
|
||||
prog := testSignatureContract()
|
||||
prog[35] = byte(opcode.PUSH1)
|
||||
assert.False(t, IsSignatureContract(prog))
|
||||
assert.False(t, IsStandardContract(prog))
|
||||
})
|
||||
|
||||
t.Run("invalid length", func(t *testing.T) {
|
||||
prog := testSignatureContract()
|
||||
prog = append(prog, 0)
|
||||
|
@ -110,15 +102,9 @@ func TestIsMultiSigContract(t *testing.T) {
|
|||
assert.False(t, IsMultiSigContract(prog))
|
||||
})
|
||||
|
||||
t.Run("no PUSHNULL", func(t *testing.T) {
|
||||
prog := testMultisigContract(t, 2, 2)
|
||||
prog[len(prog)-6] ^= 0xFF
|
||||
assert.False(t, IsMultiSigContract(prog))
|
||||
})
|
||||
|
||||
t.Run("invalid keys number", func(t *testing.T) {
|
||||
prog := testMultisigContract(t, 2, 2)
|
||||
prog[len(prog)-7] = byte(opcode.PUSH3)
|
||||
prog[len(prog)-6] = byte(opcode.PUSH3)
|
||||
assert.False(t, IsMultiSigContract(prog))
|
||||
})
|
||||
|
||||
|
|
|
@ -19,10 +19,6 @@ type interopIDFuncPrice struct {
|
|||
}
|
||||
|
||||
var defaultVMInterops = []interopIDFuncPrice{
|
||||
{ID: interopnames.ToID([]byte(interopnames.SystemBinaryDeserialize)),
|
||||
Func: RuntimeDeserialize, Price: 1 << 14},
|
||||
{ID: interopnames.ToID([]byte(interopnames.SystemBinarySerialize)),
|
||||
Func: RuntimeSerialize, Price: 1 << 12},
|
||||
{ID: interopnames.ToID([]byte(interopnames.SystemRuntimeLog)),
|
||||
Func: runtimeLog, Price: 1 << 15, RequiredFlags: callflag.AllowNotify},
|
||||
{ID: interopnames.ToID([]byte(interopnames.SystemRuntimeNotify)),
|
||||
|
@ -68,35 +64,6 @@ func runtimeNotify(vm *VM) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// RuntimeSerialize handles System.Binary.Serialize syscall.
|
||||
func RuntimeSerialize(vm *VM) error {
|
||||
item := vm.Estack().Pop()
|
||||
data, err := stackitem.SerializeItem(item.value)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if len(data) > stackitem.MaxSize {
|
||||
return errors.New("too big item")
|
||||
}
|
||||
|
||||
vm.Estack().PushVal(data)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RuntimeDeserialize handles System.Binary.Deserialize syscall.
|
||||
func RuntimeDeserialize(vm *VM) error {
|
||||
data := vm.Estack().Pop().Bytes()
|
||||
|
||||
item, err := stackitem.DeserializeItem(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vm.Estack().Push(&Element{value: item})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// init sorts the global defaultVMInterops value.
|
||||
func init() {
|
||||
sort.Slice(defaultVMInterops, func(i, j int) bool {
|
||||
|
|
|
@ -3,7 +3,6 @@ package vm
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
|
@ -531,168 +530,6 @@ func getSyscallProg(name string) (prog []byte) {
|
|||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func getSerializeProg() (prog []byte) {
|
||||
prog = append(prog, getSyscallProg(interopnames.SystemBinarySerialize)...)
|
||||
prog = append(prog, getSyscallProg(interopnames.SystemBinaryDeserialize)...)
|
||||
prog = append(prog, byte(opcode.RET))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func testSerialize(t *testing.T, vm *VM) {
|
||||
err := vm.Step()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, vm.estack.Len())
|
||||
require.IsType(t, (*stackitem.ByteArray)(nil), vm.estack.Top().value)
|
||||
|
||||
err = vm.Step()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, vm.estack.Len())
|
||||
}
|
||||
|
||||
func TestSerializeBool(t *testing.T) {
|
||||
vm := load(getSerializeProg())
|
||||
vm.estack.PushVal(true)
|
||||
|
||||
testSerialize(t, vm)
|
||||
|
||||
require.IsType(t, (*stackitem.Bool)(nil), vm.estack.Top().value)
|
||||
require.Equal(t, true, vm.estack.Top().Bool())
|
||||
}
|
||||
|
||||
func TestSerializeByteArray(t *testing.T) {
|
||||
vm := load(getSerializeProg())
|
||||
value := []byte{1, 2, 3}
|
||||
vm.estack.PushVal(value)
|
||||
|
||||
testSerialize(t, vm)
|
||||
|
||||
require.IsType(t, (*stackitem.ByteArray)(nil), vm.estack.Top().value)
|
||||
require.Equal(t, value, vm.estack.Top().Bytes())
|
||||
}
|
||||
|
||||
func TestSerializeInteger(t *testing.T) {
|
||||
vm := load(getSerializeProg())
|
||||
value := int64(123)
|
||||
vm.estack.PushVal(value)
|
||||
|
||||
testSerialize(t, vm)
|
||||
|
||||
require.IsType(t, (*stackitem.BigInteger)(nil), vm.estack.Top().value)
|
||||
require.Equal(t, value, vm.estack.Top().BigInt().Int64())
|
||||
}
|
||||
|
||||
func TestSerializeArray(t *testing.T) {
|
||||
vm := load(getSerializeProg())
|
||||
item := stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make(true),
|
||||
stackitem.Make(123),
|
||||
stackitem.NewMap(),
|
||||
})
|
||||
|
||||
vm.estack.Push(&Element{value: item})
|
||||
|
||||
testSerialize(t, vm)
|
||||
|
||||
require.IsType(t, (*stackitem.Array)(nil), vm.estack.Top().value)
|
||||
require.Equal(t, item.Value().([]stackitem.Item), vm.estack.Top().Array())
|
||||
}
|
||||
|
||||
func TestSerializeArrayBad(t *testing.T) {
|
||||
vm := load(getSerializeProg())
|
||||
item := stackitem.NewArray(makeArrayOfType(2, stackitem.BooleanT))
|
||||
item.Value().([]stackitem.Item)[1] = item
|
||||
|
||||
vm.estack.Push(&Element{value: item})
|
||||
|
||||
err := vm.Step()
|
||||
require.Error(t, err)
|
||||
require.True(t, vm.HasFailed())
|
||||
}
|
||||
|
||||
func TestSerializeDupInteger(t *testing.T) {
|
||||
prog := makeProgram(
|
||||
opcode.PUSH0, opcode.NEWARRAY, opcode.INITSSLOT, 1,
|
||||
opcode.DUP, opcode.PUSH2, opcode.DUP, opcode.STSFLD0, opcode.APPEND,
|
||||
opcode.DUP, opcode.LDSFLD0, opcode.APPEND,
|
||||
)
|
||||
vm := load(append(prog, getSerializeProg()...))
|
||||
|
||||
runVM(t, vm)
|
||||
}
|
||||
|
||||
func TestSerializeStruct(t *testing.T) {
|
||||
vm := load(getSerializeProg())
|
||||
item := stackitem.NewStruct([]stackitem.Item{
|
||||
stackitem.Make(true),
|
||||
stackitem.Make(123),
|
||||
stackitem.NewMap(),
|
||||
})
|
||||
|
||||
vm.estack.Push(&Element{value: item})
|
||||
|
||||
testSerialize(t, vm)
|
||||
|
||||
require.IsType(t, (*stackitem.Struct)(nil), vm.estack.Top().value)
|
||||
require.Equal(t, item.Value().([]stackitem.Item), vm.estack.Top().Array())
|
||||
}
|
||||
|
||||
func TestDeserializeUnknown(t *testing.T) {
|
||||
prog := append(getSyscallProg(interopnames.SystemBinaryDeserialize), byte(opcode.RET))
|
||||
|
||||
data, err := stackitem.SerializeItem(stackitem.NewBigInteger(big.NewInt(123)))
|
||||
require.NoError(t, err)
|
||||
|
||||
data[0] = 0xFF
|
||||
|
||||
runWithArgs(t, prog, nil, data)
|
||||
}
|
||||
|
||||
func TestSerializeMap(t *testing.T) {
|
||||
vm := load(getSerializeProg())
|
||||
item := stackitem.NewMap()
|
||||
item.Add(stackitem.Make(true), stackitem.Make([]byte{1, 2, 3}))
|
||||
item.Add(stackitem.Make([]byte{0}), stackitem.Make(false))
|
||||
|
||||
vm.estack.Push(&Element{value: item})
|
||||
|
||||
testSerialize(t, vm)
|
||||
|
||||
require.IsType(t, (*stackitem.Map)(nil), vm.estack.Top().value)
|
||||
require.Equal(t, item.Value(), vm.estack.Top().value.(*stackitem.Map).Value())
|
||||
}
|
||||
|
||||
func TestSerializeMapCompat(t *testing.T) {
|
||||
resHex := "480128036b6579280576616c7565"
|
||||
res, err := hex.DecodeString(resHex)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a map, push key and value, add KV to map, serialize.
|
||||
buf := io.NewBufBinWriter()
|
||||
emit.Opcodes(buf.BinWriter, opcode.NEWMAP)
|
||||
emit.Opcodes(buf.BinWriter, opcode.DUP)
|
||||
emit.Bytes(buf.BinWriter, []byte("key"))
|
||||
emit.Bytes(buf.BinWriter, []byte("value"))
|
||||
emit.Opcodes(buf.BinWriter, opcode.SETITEM)
|
||||
emit.Syscall(buf.BinWriter, interopnames.SystemBinarySerialize)
|
||||
require.NoError(t, buf.Err)
|
||||
|
||||
vm := load(buf.Bytes())
|
||||
runVM(t, vm)
|
||||
assert.Equal(t, res, vm.estack.Pop().Bytes())
|
||||
}
|
||||
|
||||
func TestSerializeInterop(t *testing.T) {
|
||||
vm := load(getSerializeProg())
|
||||
item := stackitem.NewInterop("kek")
|
||||
|
||||
vm.estack.Push(&Element{value: item})
|
||||
|
||||
err := vm.Step()
|
||||
require.Error(t, err)
|
||||
require.True(t, vm.HasFailed())
|
||||
}
|
||||
|
||||
func getTestCallFlagsFunc(syscall []byte, flags callflag.CallFlag, result interface{}) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
script := append([]byte{byte(opcode.SYSCALL)}, syscall...)
|
||||
|
|
|
@ -113,13 +113,13 @@ func TestAccount_ConvertMultisig(t *testing.T) {
|
|||
t.Run("1/1 multisig", func(t *testing.T) {
|
||||
pubs := convertPubs(t, hexs[:1])
|
||||
require.NoError(t, a.ConvertMultisig(1, pubs))
|
||||
require.Equal(t, "NVNvVRW5Q5naSx2k2iZm7xRgtRNGuZppAK", a.Address)
|
||||
require.Equal(t, "NNudMSGzEoktFzdYGYoNb3bzHzbmM1genF", a.Address)
|
||||
})
|
||||
|
||||
t.Run("3/4 multisig", func(t *testing.T) {
|
||||
pubs := convertPubs(t, hexs)
|
||||
require.NoError(t, a.ConvertMultisig(3, pubs))
|
||||
require.Equal(t, "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY", a.Address)
|
||||
require.Equal(t, "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6", a.Address)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -135,11 +135,11 @@ func convertPubs(t *testing.T, hexKeys []string) []*keys.PublicKey {
|
|||
|
||||
func compareFields(t *testing.T, tk keytestcases.Ktype, acc *Account) {
|
||||
want, have := tk.Address, acc.Address
|
||||
require.Equalf(t, want, have, "expected %s got %s", want, have)
|
||||
require.Equalf(t, want, have, "expected address %s got %s", want, have)
|
||||
want, have = tk.Wif, acc.wif
|
||||
require.Equalf(t, want, have, "expected %s got %s", want, have)
|
||||
require.Equalf(t, want, have, "expected wif %s got %s", want, have)
|
||||
want, have = tk.PublicKey, hex.EncodeToString(acc.publicKey)
|
||||
require.Equalf(t, want, have, "expected %s got %s", want, have)
|
||||
require.Equalf(t, want, have, "expected pub key %s got %s", want, have)
|
||||
want, have = tk.PrivateKey, acc.privateKey.String()
|
||||
require.Equalf(t, want, have, "expected %s got %s", want, have)
|
||||
require.Equalf(t, want, have, "expected priv key %s got %s", want, have)
|
||||
}
|
||||
|
|
12
pkg/wallet/testdata/wallet1.json
vendored
12
pkg/wallet/testdata/wallet1.json
vendored
|
@ -2,11 +2,11 @@
|
|||
"version": "3.0",
|
||||
"accounts": [
|
||||
{
|
||||
"address": "NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcILQZVEDXg=",
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcJBdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw==",
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
|
18
pkg/wallet/testdata/wallet2.json
vendored
18
pkg/wallet/testdata/wallet2.json
vendored
|
@ -2,11 +2,11 @@
|
|||
"version": "3.0",
|
||||
"accounts": [
|
||||
{
|
||||
"address": "NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcILQZVEDXg=",
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcJBdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
|
||||
"key": "6PYN7LvaWqBNw7Xb7a52LSbPnP91kyuzYi3HncGvQwQoYAY2W8DncTgpux",
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw==",
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
@ -44,11 +44,11 @@
|
|||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address": "NWvKSwutC8D6VKmmPxAEgFKx2NLvFhn8q5",
|
||||
"key": "6PYKEHagXJ3mDLdga1FoyTGRtPdJgPz6Gb8sjEFwZvRu7ncD9PVZfHtMzL",
|
||||
"address": "NUREbqw2kfbPgDeEz8Dac2QxntGGqqFMm7",
|
||||
"key": "6PYXADog3RQCwKRhqQsobwZEFopdcCJuMfPosM9pXPaDWSguKvznLdpADk",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCECEDp/fdAWVYWX95YNJ8UWpDlP2Wi55lFV60sBPkBAQG4LQZVEDXg=",
|
||||
"script": "DCECEDp/fdAWVYWX95YNJ8UWpDlP2Wi55lFV60sBPkBAQG5BdHR2qg==",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
|
|
|
@ -186,14 +186,14 @@ func TestWalletGetChangeAddress(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
sh := w1.GetChangeAddress()
|
||||
// No default address, the first one is used.
|
||||
expected, err := address.StringToUint160("NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc")
|
||||
expected, err := address.StringToUint160("NTh9TnZTstvAePEYWDGLLxidBikJE24uTo")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expected, sh)
|
||||
w2, err := NewWalletFromFile("testdata/wallet2.json")
|
||||
require.NoError(t, err)
|
||||
sh = w2.GetChangeAddress()
|
||||
// Default address.
|
||||
expected, err = address.StringToUint160("NWvKSwutC8D6VKmmPxAEgFKx2NLvFhn8q5")
|
||||
expected, err = address.StringToUint160("NUREbqw2kfbPgDeEz8Dac2QxntGGqqFMm7")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expected, sh)
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ func main() {
|
|||
handleError("can't tranfser GAS", err)
|
||||
lastBlock = addBlock(bc, lastBlock, valScript, txMoveNeo, txMoveGas)
|
||||
|
||||
tx, contractHash, err := testchain.NewDeployTx(bc, "DumpContract", h, strings.NewReader(contract))
|
||||
tx, contractHash, _, err := testchain.NewDeployTx(bc, "DumpContract", h, strings.NewReader(contract))
|
||||
handleError("can't create deploy tx", err)
|
||||
tx.NetworkFee = 10_000_000
|
||||
tx.ValidUntilBlock = bc.BlockHeight() + 1
|
||||
|
|
Loading…
Reference in a new issue