Merge pull request #1824 from nspcc-dev/native/libs

native: implement StdLib and CryptoLib contracts
This commit is contained in:
Roman Khimov 2021-03-10 22:07:14 +03:00 committed by GitHub
commit 5dff7afd5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
88 changed files with 1674 additions and 1550 deletions

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -31,8 +31,8 @@ import (
const (
validatorWIF = "KxyjQ8eUa4FHt3Gvioyt1Wz29cTUrE4eTqX3yFSk1YFCsPL8uNsY"
validatorAddr = "NVNvVRW5Q5naSx2k2iZm7xRgtRNGuZppAK"
multisigAddr = "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY"
validatorAddr = "NNudMSGzEoktFzdYGYoNb3bzHzbmM1genF"
multisigAddr = "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6"
validatorWallet = "testdata/wallet1_solo.json"
)

View file

@ -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,

Binary file not shown.

View file

@ -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
}
}

View file

@ -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" : []
},

View file

@ -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",

View file

@ -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)

View file

@ -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
}

View file

@ -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,
},
}

View file

@ -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.

View file

@ -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)
}

View file

@ -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)

View file

@ -61,50 +61,36 @@ 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.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},
"runtime.GetEntryScriptHash": {interopnames.SystemRuntimeGetEntryScriptHash, nil, false},
"runtime.GetExecutingScriptHash": {interopnames.SystemRuntimeGetExecutingScriptHash, nil, false},
"runtime.GetInvocationCounter": {interopnames.SystemRuntimeGetInvocationCounter, nil, false},
"runtime.GetNotifications": {interopnames.SystemRuntimeGetNotifications, []string{u160}, false},
"runtime.GetScriptContainer": {interopnames.SystemRuntimeGetScriptContainer, nil, false},
"runtime.GetTime": {interopnames.SystemRuntimeGetTime, nil, false},
"runtime.GetTrigger": {interopnames.SystemRuntimeGetTrigger, nil, false},
"runtime.Log": {interopnames.SystemRuntimeLog, []string{`"msg"`}, true},
"runtime.Notify": {interopnames.SystemRuntimeNotify, []string{`"ev"`, "1"}, true},
"runtime.Platform": {interopnames.SystemRuntimePlatform, nil, false},
"storage.Delete": {interopnames.SystemStorageDelete, []string{sctx, b}, true},
"storage.Find": {interopnames.SystemStorageFind, []string{sctx, b, "storage.None"}, false},
"storage.Get": {interopnames.SystemStorageGet, []string{sctx, b}, false},
"storage.GetContext": {interopnames.SystemStorageGetContext, nil, false},
"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},
"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{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},
"runtime.CheckWitness": {interopnames.SystemRuntimeCheckWitness, []string{b}, false},
"runtime.GasLeft": {interopnames.SystemRuntimeGasLeft, nil, false},
"runtime.GetCallingScriptHash": {interopnames.SystemRuntimeGetCallingScriptHash, nil, false},
"runtime.GetEntryScriptHash": {interopnames.SystemRuntimeGetEntryScriptHash, nil, false},
"runtime.GetExecutingScriptHash": {interopnames.SystemRuntimeGetExecutingScriptHash, nil, false},
"runtime.GetInvocationCounter": {interopnames.SystemRuntimeGetInvocationCounter, nil, false},
"runtime.GetNotifications": {interopnames.SystemRuntimeGetNotifications, []string{u160}, false},
"runtime.GetScriptContainer": {interopnames.SystemRuntimeGetScriptContainer, nil, false},
"runtime.GetTime": {interopnames.SystemRuntimeGetTime, nil, false},
"runtime.GetTrigger": {interopnames.SystemRuntimeGetTrigger, nil, false},
"runtime.Log": {interopnames.SystemRuntimeLog, []string{`"msg"`}, true},
"runtime.Notify": {interopnames.SystemRuntimeNotify, []string{`"ev"`, "1"}, true},
"runtime.Platform": {interopnames.SystemRuntimePlatform, nil, false},
"storage.Delete": {interopnames.SystemStorageDelete, []string{sctx, b}, true},
"storage.Find": {interopnames.SystemStorageFind, []string{sctx, b, "storage.None"}, false},
"storage.Get": {interopnames.SystemStorageGet, []string{sctx, b}, false},
"storage.GetContext": {interopnames.SystemStorageGetContext, nil, false},
"storage.GetReadOnlyContext": {interopnames.SystemStorageGetReadOnlyContext, nil, false},
"storage.Put": {interopnames.SystemStoragePut, []string{sctx, b, b}, true},
"storage.ConvertContextToReadOnly": {interopnames.SystemStorageAsReadOnly, []string{sctx}, 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) {

View file

@ -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())
}

View file

@ -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)
}
`
}

View file

@ -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
}

View file

@ -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": {

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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)

View file

@ -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.
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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))
})
}

View file

@ -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]
}
}

View file

@ -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)
}
}

View file

@ -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
}

View file

@ -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()
}
pkeys[i], err = keys.NewPrivateKey()
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)
})
}

View file

@ -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
}

View file

@ -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)
}

View file

@ -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() {

View file

@ -2,68 +2,46 @@ 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"
SystemCallbackInvoke = "System.Callback.Invoke"
SystemContractCall = "System.Contract.Call"
SystemContractCallNative = "System.Contract.CallNative"
SystemContractCreateMultisigAccount = "System.Contract.CreateMultisigAccount"
SystemContractCreateStandardAccount = "System.Contract.CreateStandardAccount"
SystemContractIsStandard = "System.Contract.IsStandard"
SystemContractGetCallFlags = "System.Contract.GetCallFlags"
SystemContractNativeOnPersist = "System.Contract.NativeOnPersist"
SystemContractNativePostPersist = "System.Contract.NativePostPersist"
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"
SystemRuntimeGetEntryScriptHash = "System.Runtime.GetEntryScriptHash"
SystemRuntimeGetExecutingScriptHash = "System.Runtime.GetExecutingScriptHash"
SystemRuntimeGetInvocationCounter = "System.Runtime.GetInvocationCounter"
SystemRuntimeGetNotifications = "System.Runtime.GetNotifications"
SystemRuntimeGetScriptContainer = "System.Runtime.GetScriptContainer"
SystemRuntimeGetTime = "System.Runtime.GetTime"
SystemRuntimeGetTrigger = "System.Runtime.GetTrigger"
SystemRuntimeLog = "System.Runtime.Log"
SystemRuntimeNotify = "System.Runtime.Notify"
SystemRuntimePlatform = "System.Runtime.Platform"
SystemStorageDelete = "System.Storage.Delete"
SystemStorageFind = "System.Storage.Find"
SystemStorageGet = "System.Storage.Get"
SystemStorageGetContext = "System.Storage.GetContext"
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"
SystemCallbackCreate = "System.Callback.Create"
SystemCallbackCreateFromMethod = "System.Callback.CreateFromMethod"
SystemCallbackCreateFromSyscall = "System.Callback.CreateFromSyscall"
SystemCallbackInvoke = "System.Callback.Invoke"
SystemContractCall = "System.Contract.Call"
SystemContractCallNative = "System.Contract.CallNative"
SystemContractCreateMultisigAccount = "System.Contract.CreateMultisigAccount"
SystemContractCreateStandardAccount = "System.Contract.CreateStandardAccount"
SystemContractIsStandard = "System.Contract.IsStandard"
SystemContractGetCallFlags = "System.Contract.GetCallFlags"
SystemContractNativeOnPersist = "System.Contract.NativeOnPersist"
SystemContractNativePostPersist = "System.Contract.NativePostPersist"
SystemIteratorCreate = "System.Iterator.Create"
SystemIteratorNext = "System.Iterator.Next"
SystemIteratorValue = "System.Iterator.Value"
SystemRuntimeCheckWitness = "System.Runtime.CheckWitness"
SystemRuntimeGasLeft = "System.Runtime.GasLeft"
SystemRuntimeGetCallingScriptHash = "System.Runtime.GetCallingScriptHash"
SystemRuntimeGetEntryScriptHash = "System.Runtime.GetEntryScriptHash"
SystemRuntimeGetExecutingScriptHash = "System.Runtime.GetExecutingScriptHash"
SystemRuntimeGetInvocationCounter = "System.Runtime.GetInvocationCounter"
SystemRuntimeGetNotifications = "System.Runtime.GetNotifications"
SystemRuntimeGetScriptContainer = "System.Runtime.GetScriptContainer"
SystemRuntimeGetTime = "System.Runtime.GetTime"
SystemRuntimeGetTrigger = "System.Runtime.GetTrigger"
SystemRuntimeLog = "System.Runtime.Log"
SystemRuntimeNotify = "System.Runtime.Notify"
SystemRuntimePlatform = "System.Runtime.Platform"
SystemStorageDelete = "System.Storage.Delete"
SystemStorageFind = "System.Storage.Find"
SystemStorageGet = "System.Storage.Get"
SystemStorageGetContext = "System.Storage.GetContext"
SystemStorageGetReadOnlyContext = "System.Storage.GetReadOnlyContext"
SystemStoragePut = "System.Storage.Put"
SystemStorageAsReadOnly = "System.Storage.AsReadOnly"
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,
}

View file

@ -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
}

View file

@ -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))
})
}

View file

@ -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.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.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.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.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.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")

View file

@ -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

View file

@ -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
View 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
}

View 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))
})
}

View file

@ -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

View file

@ -26,7 +26,7 @@ type Ledger struct {
}
const (
ledgerContractID = -2
ledgerContractID = -4
prefixBlockHash = 9
prefixCurrentBlock = 12

View file

@ -54,7 +54,7 @@ const (
)
const (
nameServiceID = -8
nameServiceID = -10
prefixRoots = 10
prefixDomainPrice = 22

View file

@ -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

View file

@ -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.

View file

@ -11,4 +11,6 @@ const (
Designation = "RoleManagement"
Notary = "Notary"
NameService = "NameService"
CryptoLib = "CryptoLib"
StdLib = "StdLib"
)

View file

@ -47,7 +47,7 @@ type Oracle struct {
}
const (
oracleContractID = -7
oracleContractID = -9
maxURLLength = 256
maxFilterLength = 128
maxCallbackLength = 32

View file

@ -19,7 +19,7 @@ import (
)
const (
policyContractID = -5
policyContractID = -7
defaultExecFeeFactor = interop.DefaultBaseExecFee
defaultFeePerByte = 1000

273
pkg/core/native/std.go Normal file
View 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
View 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)})
})
})
}

View file

@ -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)

View file

@ -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()

View file

@ -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)

View file

@ -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()
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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{})
}

View 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)
}

View 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)
}

View file

@ -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)
},
},
{

View file

@ -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) {

View file

@ -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(),

Binary file not shown.

Binary file not shown.

View file

@ -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))
}

View file

@ -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"
}

View file

@ -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"
}
]
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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
}

View file

@ -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) {

View file

@ -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) {

View file

@ -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

View file

@ -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))
})

View file

@ -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 {

View file

@ -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...)

View file

@ -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)
}

View file

@ -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",

View file

@ -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",

View file

@ -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)
}

View file

@ -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