core/interop: add base58 encoding/decoding syscalls

Follow neo-project/neo#1833.
This commit is contained in:
Roman Khimov 2020-08-23 17:19:56 +03:00
parent 562e7e371f
commit 9c72ea1d64
6 changed files with 80 additions and 30 deletions

View file

@ -11,6 +11,8 @@ type Syscall struct {
// All lists are sorted, keep 'em this way, please. // All lists are sorted, keep 'em this way, please.
var syscalls = map[string]map[string]Syscall{ var syscalls = map[string]map[string]Syscall{
"binary": { "binary": {
"Base58Decode": {interopnames.SystemBinaryBase58Decode, false},
"Base58Encode": {interopnames.SystemBinaryBase58Encode, false},
"Base64Decode": {interopnames.SystemBinaryBase64Decode, false}, "Base64Decode": {interopnames.SystemBinaryBase64Decode, false},
"Base64Encode": {interopnames.SystemBinaryBase64Encode, false}, "Base64Encode": {interopnames.SystemBinaryBase64Encode, false},
"Deserialize": {interopnames.SystemBinaryDeserialize, false}, "Deserialize": {interopnames.SystemBinaryDeserialize, false},

View file

@ -2,6 +2,8 @@ package interopnames
// Names of all used interops. // Names of all used interops.
const ( const (
SystemBinaryBase58Decode = "System.Binary.Base58Decode"
SystemBinaryBase58Encode = "System.Binary.Base58Encode"
SystemBinaryBase64Decode = "System.Binary.Base64Decode" SystemBinaryBase64Decode = "System.Binary.Base64Decode"
SystemBinaryBase64Encode = "System.Binary.Base64Encode" SystemBinaryBase64Encode = "System.Binary.Base64Encode"
SystemBinaryDeserialize = "System.Binary.Deserialize" SystemBinaryDeserialize = "System.Binary.Deserialize"
@ -67,6 +69,8 @@ const (
) )
var names = []string{ var names = []string{
SystemBinaryBase58Decode,
SystemBinaryBase58Encode,
SystemBinaryBase64Decode, SystemBinaryBase64Decode,
SystemBinaryBase64Encode, SystemBinaryBase64Encode,
SystemBinaryDeserialize, SystemBinaryDeserialize,

View file

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/mr-tron/base58"
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/hash"
@ -195,16 +196,16 @@ func runtimeDeserialize(ic *interop.Context) error {
return vm.RuntimeDeserialize(ic.VM) return vm.RuntimeDeserialize(ic.VM)
} }
// runtimeEncode encodes top stack item into a base64 string. // runtimeEncodeBase64 encodes top stack item into a base64 string.
func runtimeEncode(ic *interop.Context) error { func runtimeEncodeBase64(ic *interop.Context) error {
src := ic.VM.Estack().Pop().Bytes() src := ic.VM.Estack().Pop().Bytes()
result := base64.StdEncoding.EncodeToString(src) result := base64.StdEncoding.EncodeToString(src)
ic.VM.Estack().PushVal([]byte(result)) ic.VM.Estack().PushVal([]byte(result))
return nil return nil
} }
// runtimeDecode decodes top stack item from base64 string to byte array. // runtimeDecodeBase64 decodes top stack item from base64 string to byte array.
func runtimeDecode(ic *interop.Context) error { func runtimeDecodeBase64(ic *interop.Context) error {
src := ic.VM.Estack().Pop().String() src := ic.VM.Estack().Pop().String()
result, err := base64.StdEncoding.DecodeString(src) result, err := base64.StdEncoding.DecodeString(src)
if err != nil { if err != nil {
@ -213,3 +214,22 @@ func runtimeDecode(ic *interop.Context) error {
ic.VM.Estack().PushVal(result) ic.VM.Estack().PushVal(result)
return nil return nil
} }
// runtimeEncodeBase58 encodes top stack item into a base58 string.
func runtimeEncodeBase58(ic *interop.Context) error {
src := ic.VM.Estack().Pop().Bytes()
result := base58.Encode(src)
ic.VM.Estack().PushVal([]byte(result))
return nil
}
// runtimeDecodeBase58 decodes top stack item from base58 string to byte array.
func runtimeDecodeBase58(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

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/mr-tron/base58"
"github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/dao"
@ -220,36 +221,45 @@ func TestECDSAVerify(t *testing.T) {
}) })
} }
func TestRuntimeEncode(t *testing.T) { func TestRuntimeEncodeDecode(t *testing.T) {
str := []byte("my pretty string") original := []byte("my pretty string")
encoded64 := base64.StdEncoding.EncodeToString(original)
encoded58 := base58.Encode(original)
v, ic, bc := createVM(t) v, ic, bc := createVM(t)
defer bc.Close() defer bc.Close()
v.Estack().PushVal(str) t.Run("Encode64", func(t *testing.T) {
require.NoError(t, runtimeEncode(ic)) v.Estack().PushVal(original)
require.NoError(t, runtimeEncodeBase64(ic))
expected := []byte(base64.StdEncoding.EncodeToString(str))
actual := v.Estack().Pop().Bytes()
require.Equal(t, expected, actual)
}
func TestRuntimeDecode(t *testing.T) {
expected := []byte("my pretty string")
str := base64.StdEncoding.EncodeToString(expected)
v, ic, bc := createVM(t)
defer bc.Close()
t.Run("positive", func(t *testing.T) {
v.Estack().PushVal(str)
require.NoError(t, runtimeDecode(ic))
actual := v.Estack().Pop().Bytes() actual := v.Estack().Pop().Bytes()
require.Equal(t, expected, actual) require.Equal(t, []byte(encoded64), actual)
}) })
t.Run("error", func(t *testing.T) { t.Run("Encode58", func(t *testing.T) {
v.Estack().PushVal(str + "%") v.Estack().PushVal(original)
require.Error(t, runtimeDecode(ic)) require.NoError(t, runtimeEncodeBase58(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, runtimeDecodeBase64(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, runtimeDecodeBase64(ic))
})
t.Run("Decode58/positive", func(t *testing.T) {
v.Estack().PushVal(encoded58)
require.NoError(t, runtimeDecodeBase58(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, runtimeDecodeBase58(ic))
}) })
} }

View file

@ -31,8 +31,10 @@ func SpawnVM(ic *interop.Context) *vm.VM {
// All lists are sorted, keep 'em this way, please. // All lists are sorted, keep 'em this way, please.
var systemInterops = []interop.Function{ var systemInterops = []interop.Function{
{Name: interopnames.SystemBinaryBase64Decode, Func: runtimeDecode, Price: 100000, ParamCount: 1}, {Name: interopnames.SystemBinaryBase58Decode, Func: runtimeDecodeBase58, Price: 100000, ParamCount: 1},
{Name: interopnames.SystemBinaryBase64Encode, Func: runtimeEncode, Price: 100000, ParamCount: 1}, {Name: interopnames.SystemBinaryBase58Encode, Func: runtimeEncodeBase58, Price: 100000, ParamCount: 1},
{Name: interopnames.SystemBinaryBase64Decode, Func: runtimeDecodeBase64, Price: 100000, ParamCount: 1},
{Name: interopnames.SystemBinaryBase64Encode, Func: runtimeEncodeBase64, Price: 100000, ParamCount: 1},
{Name: interopnames.SystemBinaryDeserialize, Func: runtimeDeserialize, Price: 500000, ParamCount: 1}, {Name: interopnames.SystemBinaryDeserialize, Func: runtimeDeserialize, Price: 500000, ParamCount: 1},
{Name: interopnames.SystemBinarySerialize, Func: runtimeSerialize, Price: 100000, ParamCount: 1}, {Name: interopnames.SystemBinarySerialize, Func: runtimeSerialize, Price: 100000, ParamCount: 1},
{Name: interopnames.SystemBlockchainGetBlock, Func: bcGetBlock, Price: 2500000, {Name: interopnames.SystemBlockchainGetBlock, Func: bcGetBlock, Price: 2500000,

View file

@ -28,3 +28,15 @@ func Base64Encode(b []byte) []byte {
func Base64Decode(b []byte) []byte { func Base64Decode(b []byte) []byte {
return nil return nil
} }
// 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) []byte {
return nil
}
// 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 nil
}