core: remove System.Binary.[Serialize, Deserialize] syscalls

And move their tests to native StdLib.
This commit is contained in:
Anna Shaleva 2021-03-04 15:46:56 +03:00
parent 5c9c168ee5
commit 14ade42101
13 changed files with 163 additions and 312 deletions

View file

@ -61,8 +61,6 @@ func TestSyscallExecution(t *testing.T) {
sigs := "[]interop.Signature{" + sig + "}"
sctx := "storage.Context{}"
interops := map[string]syscallTestCase{
"binary.Deserialize": {interopnames.SystemBinaryDeserialize, []string{b}, 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},

View file

@ -1,16 +0,0 @@
package binary
import (
"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)
}

View file

@ -1,49 +0,0 @@
package binary
import (
"math/big"
"testing"
"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))
})
})
}

View file

@ -2,8 +2,6 @@ package interopnames
// Names of all used interops.
const (
SystemBinaryDeserialize = "System.Binary.Deserialize"
SystemBinarySerialize = "System.Binary.Serialize"
SystemCallbackCreate = "System.Callback.Create"
SystemCallbackCreateFromMethod = "System.Callback.CreateFromMethod"
SystemCallbackCreateFromSyscall = "System.Callback.CreateFromSyscall"
@ -46,8 +44,6 @@ const (
)
var names = []string{
SystemBinaryDeserialize,
SystemBinarySerialize,
SystemCallbackCreate,
SystemCallbackCreateFromMethod,
SystemCallbackCreateFromSyscall,

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,7 +10,6 @@ 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"
@ -31,8 +30,6 @@ func SpawnVM(ic *interop.Context) *vm.VM {
// All lists are sorted, keep 'em this way, please.
var systemInterops = []interop.Function{
{Name: interopnames.SystemBinaryDeserialize, Func: binary.Deserialize, Price: 1 << 14, ParamCount: 1},
{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},

View file

@ -2,14 +2,17 @@ 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"
)
@ -190,3 +193,136 @@ func TestStdLibEncodeDecode(t *testing.T) {
})
})
}
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

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

@ -1,22 +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)
}

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

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