diff --git a/pkg/compiler/syscall.go b/pkg/compiler/syscall.go index 7f8a342754..f1c6ed792a 100644 --- a/pkg/compiler/syscall.go +++ b/pkg/compiler/syscall.go @@ -11,6 +11,8 @@ type Syscall struct { // All lists are sorted, keep 'em this way, please. var syscalls = map[string]map[string]Syscall{ "binary": { + "Base58Decode": {interopnames.SystemBinaryBase58Decode, false}, + "Base58Encode": {interopnames.SystemBinaryBase58Encode, false}, "Base64Decode": {interopnames.SystemBinaryBase64Decode, false}, "Base64Encode": {interopnames.SystemBinaryBase64Encode, false}, "Deserialize": {interopnames.SystemBinaryDeserialize, false}, diff --git a/pkg/core/interop/interopnames/names.go b/pkg/core/interop/interopnames/names.go index 01f36cdf16..93fc94366d 100644 --- a/pkg/core/interop/interopnames/names.go +++ b/pkg/core/interop/interopnames/names.go @@ -2,6 +2,8 @@ package interopnames // Names of all used interops. const ( + SystemBinaryBase58Decode = "System.Binary.Base58Decode" + SystemBinaryBase58Encode = "System.Binary.Base58Encode" SystemBinaryBase64Decode = "System.Binary.Base64Decode" SystemBinaryBase64Encode = "System.Binary.Base64Encode" SystemBinaryDeserialize = "System.Binary.Deserialize" @@ -67,6 +69,8 @@ const ( ) var names = []string{ + SystemBinaryBase58Decode, + SystemBinaryBase58Encode, SystemBinaryBase64Decode, SystemBinaryBase64Encode, SystemBinaryDeserialize, diff --git a/pkg/core/interop_neo.go b/pkg/core/interop_neo.go index 6fccc46380..244ccccf32 100644 --- a/pkg/core/interop_neo.go +++ b/pkg/core/interop_neo.go @@ -7,6 +7,7 @@ import ( "fmt" "sort" + "github.com/mr-tron/base58" "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/crypto/hash" @@ -195,16 +196,16 @@ func runtimeDeserialize(ic *interop.Context) error { return vm.RuntimeDeserialize(ic.VM) } -// runtimeEncode encodes top stack item into a base64 string. -func runtimeEncode(ic *interop.Context) error { +// runtimeEncodeBase64 encodes top stack item into a base64 string. +func runtimeEncodeBase64(ic *interop.Context) error { src := ic.VM.Estack().Pop().Bytes() result := base64.StdEncoding.EncodeToString(src) ic.VM.Estack().PushVal([]byte(result)) return nil } -// runtimeDecode decodes top stack item from base64 string to byte array. -func runtimeDecode(ic *interop.Context) error { +// runtimeDecodeBase64 decodes top stack item from base64 string to byte array. +func runtimeDecodeBase64(ic *interop.Context) error { src := ic.VM.Estack().Pop().String() result, err := base64.StdEncoding.DecodeString(src) if err != nil { @@ -213,3 +214,22 @@ func runtimeDecode(ic *interop.Context) error { ic.VM.Estack().PushVal(result) 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 +} diff --git a/pkg/core/interop_neo_test.go b/pkg/core/interop_neo_test.go index a36b89edc2..ef5bbfa286 100644 --- a/pkg/core/interop_neo_test.go +++ b/pkg/core/interop_neo_test.go @@ -5,6 +5,7 @@ import ( "fmt" "testing" + "github.com/mr-tron/base58" "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/dao" @@ -220,36 +221,45 @@ func TestECDSAVerify(t *testing.T) { }) } -func TestRuntimeEncode(t *testing.T) { - str := []byte("my pretty string") +func TestRuntimeEncodeDecode(t *testing.T) { + original := []byte("my pretty string") + encoded64 := base64.StdEncoding.EncodeToString(original) + encoded58 := base58.Encode(original) v, ic, bc := createVM(t) defer bc.Close() - v.Estack().PushVal(str) - require.NoError(t, runtimeEncode(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)) - + t.Run("Encode64", func(t *testing.T) { + v.Estack().PushVal(original) + require.NoError(t, runtimeEncodeBase64(ic)) actual := v.Estack().Pop().Bytes() - require.Equal(t, expected, actual) + require.Equal(t, []byte(encoded64), actual) }) - t.Run("error", func(t *testing.T) { - v.Estack().PushVal(str + "%") - require.Error(t, runtimeDecode(ic)) + t.Run("Encode58", func(t *testing.T) { + v.Estack().PushVal(original) + 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)) }) } diff --git a/pkg/core/interops.go b/pkg/core/interops.go index 8c3459ff98..7d2a00e1d1 100644 --- a/pkg/core/interops.go +++ b/pkg/core/interops.go @@ -31,8 +31,10 @@ func SpawnVM(ic *interop.Context) *vm.VM { // All lists are sorted, keep 'em this way, please. var systemInterops = []interop.Function{ - {Name: interopnames.SystemBinaryBase64Decode, Func: runtimeDecode, Price: 100000, ParamCount: 1}, - {Name: interopnames.SystemBinaryBase64Encode, Func: runtimeEncode, Price: 100000, ParamCount: 1}, + {Name: interopnames.SystemBinaryBase58Decode, Func: runtimeDecodeBase58, 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.SystemBinarySerialize, Func: runtimeSerialize, Price: 100000, ParamCount: 1}, {Name: interopnames.SystemBlockchainGetBlock, Func: bcGetBlock, Price: 2500000, diff --git a/pkg/interop/binary/binary.go b/pkg/interop/binary/binary.go index 647e4d19f3..e6c1a0392c 100644 --- a/pkg/interop/binary/binary.go +++ b/pkg/interop/binary/binary.go @@ -28,3 +28,15 @@ func Base64Encode(b []byte) []byte { func Base64Decode(b []byte) []byte { 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 +}