forked from TrueCloudLab/neoneo-go
core: move System.Binary.*
interops to binary/
package
Also extend test suite.
This commit is contained in:
parent
2eb256014e
commit
d136569ac8
5 changed files with 155 additions and 100 deletions
57
pkg/core/interop/binary/encode.go
Normal file
57
pkg/core/interop/binary/encode.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
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
|
||||||
|
}
|
92
pkg/core/interop/binary/encode_test.go
Normal file
92
pkg/core/interop/binary/encode_test.go
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
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))
|
||||||
|
})
|
||||||
|
}
|
|
@ -2,14 +2,12 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"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/interop/contract"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
|
@ -193,51 +191,3 @@ func callDeploy(ic *interop.Context, cs *state.Contract, isUpdate bool) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// runtimeSerialize serializes top stack item into a ByteArray.
|
|
||||||
func runtimeSerialize(ic *interop.Context) error {
|
|
||||||
return vm.RuntimeSerialize(ic.VM)
|
|
||||||
}
|
|
||||||
|
|
||||||
// runtimeDeserialize deserializes ByteArray from a stack into an item.
|
|
||||||
func runtimeDeserialize(ic *interop.Context) error {
|
|
||||||
return vm.RuntimeDeserialize(ic.VM)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
|
||||||
"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"
|
||||||
|
@ -213,48 +211,6 @@ func TestECDSAVerify(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
t.Run("Encode64", func(t *testing.T) {
|
|
||||||
v.Estack().PushVal(original)
|
|
||||||
require.NoError(t, runtimeEncodeBase64(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, 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))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper functions to create VM, InteropContext, TX, Account, Contract.
|
// Helper functions to create VM, InteropContext, TX, Account, Contract.
|
||||||
|
|
||||||
func createVM(t *testing.T) (*vm.VM, *interop.Context, *Blockchain) {
|
func createVM(t *testing.T) (*vm.VM, *interop.Context, *Blockchain) {
|
||||||
|
|
|
@ -34,13 +34,13 @@ 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.SystemBinaryAtoi, Func: binary.Atoi, Price: 100000, ParamCount: 2},
|
{Name: interopnames.SystemBinaryAtoi, Func: binary.Atoi, Price: 100000, ParamCount: 2},
|
||||||
{Name: interopnames.SystemBinaryBase58Decode, Func: runtimeDecodeBase58, Price: 100000, ParamCount: 1},
|
{Name: interopnames.SystemBinaryBase58Decode, Func: binary.DecodeBase58, Price: 100000, ParamCount: 1},
|
||||||
{Name: interopnames.SystemBinaryBase58Encode, Func: runtimeEncodeBase58, Price: 100000, ParamCount: 1},
|
{Name: interopnames.SystemBinaryBase58Encode, Func: binary.EncodeBase58, Price: 100000, ParamCount: 1},
|
||||||
{Name: interopnames.SystemBinaryBase64Decode, Func: runtimeDecodeBase64, Price: 100000, ParamCount: 1},
|
{Name: interopnames.SystemBinaryBase64Decode, Func: binary.DecodeBase64, Price: 100000, ParamCount: 1},
|
||||||
{Name: interopnames.SystemBinaryBase64Encode, Func: runtimeEncodeBase64, Price: 100000, ParamCount: 1},
|
{Name: interopnames.SystemBinaryBase64Encode, Func: binary.EncodeBase64, Price: 100000, ParamCount: 1},
|
||||||
{Name: interopnames.SystemBinaryDeserialize, Func: runtimeDeserialize, Price: 500000, ParamCount: 1},
|
{Name: interopnames.SystemBinaryDeserialize, Func: binary.Deserialize, Price: 500000, ParamCount: 1},
|
||||||
{Name: interopnames.SystemBinaryItoa, Func: binary.Itoa, Price: 100000, ParamCount: 2},
|
{Name: interopnames.SystemBinaryItoa, Func: binary.Itoa, Price: 100000, ParamCount: 2},
|
||||||
{Name: interopnames.SystemBinarySerialize, Func: runtimeSerialize, Price: 100000, ParamCount: 1},
|
{Name: interopnames.SystemBinarySerialize, Func: binary.Serialize, Price: 100000, ParamCount: 1},
|
||||||
{Name: interopnames.SystemBlockchainGetBlock, Func: bcGetBlock, Price: 2500000,
|
{Name: interopnames.SystemBlockchainGetBlock, Func: bcGetBlock, Price: 2500000,
|
||||||
RequiredFlags: smartcontract.AllowStates, ParamCount: 1},
|
RequiredFlags: smartcontract.AllowStates, ParamCount: 1},
|
||||||
{Name: interopnames.SystemBlockchainGetContract, Func: bcGetContract, Price: 1000000,
|
{Name: interopnames.SystemBlockchainGetContract, Func: bcGetContract, Price: 1000000,
|
||||||
|
|
Loading…
Reference in a new issue