github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/vm/vm_test.go (about)

     1  package vm
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"encoding/hex"
     7  	"errors"
     8  	"fmt"
     9  	"math"
    10  	"math/big"
    11  	"math/rand"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/nspcc-dev/neo-go/internal/random"
    16  	"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
    17  	"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
    18  	"github.com/nspcc-dev/neo-go/pkg/io"
    19  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
    20  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
    21  	"github.com/nspcc-dev/neo-go/pkg/vm/emit"
    22  	"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
    23  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    24  	"github.com/stretchr/testify/assert"
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  func fooInteropHandler(v *VM, id uint32) error {
    29  	if id == interopnames.ToID([]byte("foo")) {
    30  		if !v.AddGas(1) {
    31  			return errors.New("invalid gas amount")
    32  		}
    33  		v.Estack().PushVal(1)
    34  		return nil
    35  	}
    36  	return errors.New("syscall not found")
    37  }
    38  
    39  func TestInteropHook(t *testing.T) {
    40  	v := newTestVM()
    41  	v.SyscallHandler = fooInteropHandler
    42  
    43  	buf := io.NewBufBinWriter()
    44  	emit.Syscall(buf.BinWriter, "foo")
    45  	emit.Opcodes(buf.BinWriter, opcode.RET)
    46  	v.Load(buf.Bytes())
    47  	runVM(t, v)
    48  	assert.Equal(t, 1, v.estack.Len())
    49  	assert.Equal(t, big.NewInt(1), v.estack.Pop().value.Value())
    50  }
    51  
    52  func TestVM_SetPriceGetter(t *testing.T) {
    53  	v := newTestVM()
    54  	prog := []byte{
    55  		byte(opcode.PUSH4), byte(opcode.PUSH2),
    56  		byte(opcode.PUSHDATA1), 0x01, 0x01,
    57  		byte(opcode.PUSHDATA1), 0x02, 0xCA, 0xFE,
    58  		byte(opcode.PUSH4), byte(opcode.RET),
    59  	}
    60  
    61  	t.Run("no price getter", func(t *testing.T) {
    62  		v.Load(prog)
    63  		runVM(t, v)
    64  
    65  		require.EqualValues(t, 0, v.GasConsumed())
    66  	})
    67  
    68  	v.SetPriceGetter(func(op opcode.Opcode, p []byte) int64 {
    69  		if op == opcode.PUSH4 {
    70  			return 1
    71  		} else if op == opcode.PUSHDATA1 && bytes.Equal(p, []byte{0xCA, 0xFE}) {
    72  			return 7
    73  		}
    74  
    75  		return 0
    76  	})
    77  
    78  	t.Run("with price getter", func(t *testing.T) {
    79  		v.Load(prog)
    80  		runVM(t, v)
    81  
    82  		require.EqualValues(t, 9, v.GasConsumed())
    83  	})
    84  
    85  	t.Run("with sufficient gas limit", func(t *testing.T) {
    86  		v.Load(prog)
    87  		v.GasLimit = 9
    88  		runVM(t, v)
    89  
    90  		require.EqualValues(t, 9, v.GasConsumed())
    91  	})
    92  
    93  	t.Run("with small gas limit", func(t *testing.T) {
    94  		v.Load(prog)
    95  		v.GasLimit = 8
    96  		checkVMFailed(t, v)
    97  	})
    98  }
    99  
   100  func TestAddGas(t *testing.T) {
   101  	v := newTestVM()
   102  	v.GasLimit = 10
   103  	require.True(t, v.AddGas(5))
   104  	require.True(t, v.AddGas(5))
   105  	require.False(t, v.AddGas(5))
   106  }
   107  
   108  func TestPushBytes1to75(t *testing.T) {
   109  	buf := io.NewBufBinWriter()
   110  	for i := 1; i <= 75; i++ {
   111  		b := randomBytes(i)
   112  		emit.Bytes(buf.BinWriter, b)
   113  		vm := load(buf.Bytes())
   114  		err := vm.Step()
   115  		require.NoError(t, err)
   116  
   117  		assert.Equal(t, 1, vm.estack.Len())
   118  
   119  		elem := vm.estack.Pop()
   120  		assert.IsType(t, &stackitem.ByteArray{}, elem.value)
   121  		assert.IsType(t, elem.Bytes(), b)
   122  		assert.Equal(t, 0, vm.estack.Len())
   123  
   124  		errExec := vm.execute(nil, opcode.RET, nil)
   125  		require.NoError(t, errExec)
   126  
   127  		assert.Nil(t, vm.Context())
   128  		buf.Reset()
   129  	}
   130  }
   131  
   132  func runVM(t *testing.T, vm *VM) {
   133  	err := vm.Run()
   134  	require.NoError(t, err)
   135  	assert.Equal(t, false, vm.HasFailed())
   136  }
   137  
   138  func checkVMFailed(t *testing.T, vm *VM) {
   139  	err := vm.Run()
   140  	require.Error(t, err)
   141  	assert.Equal(t, true, vm.HasFailed())
   142  }
   143  
   144  func TestStackLimitPUSH1Good(t *testing.T) {
   145  	prog := make([]byte, MaxStackSize*2)
   146  	for i := 0; i < MaxStackSize; i++ {
   147  		prog[i] = byte(opcode.PUSH1)
   148  	}
   149  	for i := MaxStackSize; i < MaxStackSize*2; i++ {
   150  		prog[i] = byte(opcode.DROP)
   151  	}
   152  
   153  	v := load(prog)
   154  	runVM(t, v)
   155  }
   156  
   157  func TestStackLimitPUSH1Bad(t *testing.T) {
   158  	prog := make([]byte, MaxStackSize+1)
   159  	for i := range prog {
   160  		prog[i] = byte(opcode.PUSH1)
   161  	}
   162  	v := load(prog)
   163  	checkVMFailed(t, v)
   164  }
   165  
   166  func TestPUSHINT(t *testing.T) {
   167  	for i := byte(0); i < 5; i++ {
   168  		op := opcode.PUSHINT8 + opcode.Opcode(i)
   169  		t.Run(op.String(), func(t *testing.T) {
   170  			buf := random.Bytes((8 << i) / 8)
   171  			prog := append([]byte{byte(op)}, buf...)
   172  			runWithArgs(t, prog, bigint.FromBytes(buf))
   173  		})
   174  	}
   175  }
   176  
   177  func TestPUSHNULL(t *testing.T) {
   178  	prog := makeProgram(opcode.PUSHNULL, opcode.PUSHNULL, opcode.EQUAL)
   179  	v := load(prog)
   180  	require.NoError(t, v.Step())
   181  	require.Equal(t, 1, v.estack.Len())
   182  	runVM(t, v)
   183  	require.True(t, v.estack.Pop().Bool())
   184  }
   185  
   186  func TestISNULL(t *testing.T) {
   187  	prog := makeProgram(opcode.ISNULL)
   188  	t.Run("Integer", getTestFuncForVM(prog, false, 1))
   189  	t.Run("Null", getTestFuncForVM(prog, true, stackitem.Null{}))
   190  }
   191  
   192  func testISTYPE(t *testing.T, result bool, typ stackitem.Type, item stackitem.Item) {
   193  	prog := []byte{byte(opcode.ISTYPE), byte(typ)}
   194  	runWithArgs(t, prog, result, item)
   195  }
   196  
   197  func TestISTYPE(t *testing.T) {
   198  	t.Run("Integer", func(t *testing.T) {
   199  		testISTYPE(t, true, stackitem.IntegerT, stackitem.NewBigInteger(big.NewInt(42)))
   200  		testISTYPE(t, false, stackitem.IntegerT, stackitem.NewByteArray([]byte{}))
   201  	})
   202  	t.Run("Boolean", func(t *testing.T) {
   203  		testISTYPE(t, true, stackitem.BooleanT, stackitem.NewBool(true))
   204  		testISTYPE(t, false, stackitem.BooleanT, stackitem.NewByteArray([]byte{}))
   205  	})
   206  	t.Run("ByteArray", func(t *testing.T) {
   207  		testISTYPE(t, true, stackitem.ByteArrayT, stackitem.NewByteArray([]byte{}))
   208  		testISTYPE(t, false, stackitem.ByteArrayT, stackitem.NewBigInteger(big.NewInt(42)))
   209  	})
   210  	t.Run("Array", func(t *testing.T) {
   211  		testISTYPE(t, true, stackitem.ArrayT, stackitem.NewArray([]stackitem.Item{}))
   212  		testISTYPE(t, false, stackitem.ArrayT, stackitem.NewByteArray([]byte{}))
   213  	})
   214  	t.Run("Struct", func(t *testing.T) {
   215  		testISTYPE(t, true, stackitem.StructT, stackitem.NewStruct([]stackitem.Item{}))
   216  		testISTYPE(t, false, stackitem.StructT, stackitem.NewByteArray([]byte{}))
   217  	})
   218  	t.Run("Map", func(t *testing.T) {
   219  		testISTYPE(t, true, stackitem.MapT, stackitem.NewMap())
   220  		testISTYPE(t, false, stackitem.MapT, stackitem.NewByteArray([]byte{}))
   221  	})
   222  	t.Run("Interop", func(t *testing.T) {
   223  		testISTYPE(t, true, stackitem.InteropT, stackitem.NewInterop(42))
   224  		testISTYPE(t, false, stackitem.InteropT, stackitem.NewByteArray([]byte{}))
   225  	})
   226  }
   227  
   228  func testCONVERT(to stackitem.Type, item, res stackitem.Item) func(t *testing.T) {
   229  	return func(t *testing.T) {
   230  		prog := []byte{byte(opcode.CONVERT), byte(to)}
   231  		runWithArgs(t, prog, res, item)
   232  	}
   233  }
   234  
   235  func TestCONVERT(t *testing.T) {
   236  	type convertTC struct {
   237  		item, res stackitem.Item
   238  	}
   239  	arr := []stackitem.Item{
   240  		stackitem.NewBigInteger(big.NewInt(7)),
   241  		stackitem.NewByteArray([]byte{4, 8, 15}),
   242  	}
   243  	m := stackitem.NewMap()
   244  	m.Add(stackitem.NewByteArray([]byte{1}), stackitem.NewByteArray([]byte{2}))
   245  
   246  	getName := func(item stackitem.Item, typ stackitem.Type) string {
   247  		return fmt.Sprintf("%s->%s", item, typ)
   248  	}
   249  
   250  	t.Run("->Bool", func(t *testing.T) {
   251  		testBool := func(a, b stackitem.Item) func(t *testing.T) {
   252  			return testCONVERT(stackitem.BooleanT, a, b)
   253  		}
   254  
   255  		trueCases := []stackitem.Item{
   256  			stackitem.NewBool(true), stackitem.NewBigInteger(big.NewInt(11)), stackitem.NewByteArray([]byte{1, 2, 3}),
   257  			stackitem.NewArray(arr), stackitem.NewArray(nil),
   258  			stackitem.NewStruct(arr), stackitem.NewStruct(nil),
   259  			stackitem.NewMap(), m, stackitem.NewInterop(struct{}{}),
   260  			stackitem.NewPointer(0, []byte{}),
   261  		}
   262  		for i := range trueCases {
   263  			t.Run(getName(trueCases[i], stackitem.BooleanT), testBool(trueCases[i], stackitem.NewBool(true)))
   264  		}
   265  
   266  		falseCases := []stackitem.Item{
   267  			stackitem.NewBigInteger(big.NewInt(0)), stackitem.NewByteArray([]byte{0, 0}), stackitem.NewBool(false),
   268  		}
   269  		for i := range falseCases {
   270  			testBool(falseCases[i], stackitem.NewBool(false))
   271  		}
   272  	})
   273  
   274  	t.Run("compound/interop -> basic", func(t *testing.T) {
   275  		types := []stackitem.Type{stackitem.IntegerT, stackitem.ByteArrayT}
   276  		items := []stackitem.Item{stackitem.NewArray(nil), stackitem.NewStruct(nil), stackitem.NewMap(), stackitem.NewInterop(struct{}{})}
   277  		for _, typ := range types {
   278  			for j := range items {
   279  				t.Run(getName(items[j], typ), testCONVERT(typ, items[j], nil))
   280  			}
   281  		}
   282  	})
   283  
   284  	t.Run("primitive -> Integer/ByteArray", func(t *testing.T) {
   285  		n := big.NewInt(42)
   286  		b := bigint.ToBytes(n)
   287  
   288  		itemInt := stackitem.NewBigInteger(n)
   289  		itemBytes := stackitem.NewByteArray(b)
   290  
   291  		trueCases := map[stackitem.Type][]convertTC{
   292  			stackitem.IntegerT: {
   293  				{itemInt, itemInt},
   294  				{itemBytes, itemInt},
   295  				{stackitem.NewBool(true), stackitem.NewBigInteger(big.NewInt(1))},
   296  				{stackitem.NewBool(false), stackitem.NewBigInteger(big.NewInt(0))},
   297  			},
   298  			stackitem.ByteArrayT: {
   299  				{itemInt, itemBytes},
   300  				{itemBytes, itemBytes},
   301  				{stackitem.NewBool(true), stackitem.NewByteArray([]byte{1})},
   302  				{stackitem.NewBool(false), stackitem.NewByteArray([]byte{0})},
   303  			},
   304  		}
   305  
   306  		for typ := range trueCases {
   307  			for _, tc := range trueCases[typ] {
   308  				t.Run(getName(tc.item, typ), testCONVERT(typ, tc.item, tc.res))
   309  			}
   310  		}
   311  	})
   312  
   313  	t.Run("Struct<->Array", func(t *testing.T) {
   314  		arrayItem := stackitem.NewArray(arr)
   315  		structItem := stackitem.NewStruct(arr)
   316  		t.Run("Array->Array", testCONVERT(stackitem.ArrayT, arrayItem, arrayItem))
   317  		t.Run("Array->Struct", testCONVERT(stackitem.StructT, arrayItem, structItem))
   318  		t.Run("Struct->Array", testCONVERT(stackitem.ArrayT, structItem, arrayItem))
   319  		t.Run("Struct->Struct", testCONVERT(stackitem.StructT, structItem, structItem))
   320  	})
   321  
   322  	t.Run("Map->Map", testCONVERT(stackitem.MapT, m, m))
   323  
   324  	ptr := stackitem.NewPointer(1, []byte{1})
   325  	t.Run("Pointer->Pointer", testCONVERT(stackitem.PointerT, ptr, ptr))
   326  
   327  	t.Run("Null->", func(t *testing.T) {
   328  		types := []stackitem.Type{
   329  			stackitem.BooleanT, stackitem.ByteArrayT, stackitem.IntegerT, stackitem.ArrayT, stackitem.StructT, stackitem.MapT, stackitem.InteropT, stackitem.PointerT,
   330  		}
   331  		for i := range types {
   332  			t.Run(types[i].String(), testCONVERT(types[i], stackitem.Null{}, stackitem.Null{}))
   333  		}
   334  	})
   335  
   336  	t.Run("->Any", func(t *testing.T) {
   337  		items := []stackitem.Item{
   338  			stackitem.NewBigInteger(big.NewInt(1)), stackitem.NewByteArray([]byte{1}), stackitem.NewBool(true),
   339  			stackitem.NewArray(arr), stackitem.NewStruct(arr), m, stackitem.NewInterop(struct{}{}),
   340  		}
   341  
   342  		for i := range items {
   343  			t.Run(items[i].String(), testCONVERT(stackitem.AnyT, items[i], nil))
   344  		}
   345  	})
   346  }
   347  
   348  // appendBigStruct returns a program which:
   349  // 1. pushes size Structs on stack
   350  // 2. packs them into a new struct
   351  // 3. appends them to a zero-length array
   352  // Resulting stack size consists of:
   353  // - struct (size+1)
   354  // - array (1) of struct (size+1)
   355  // which equals to size*2+3 elements in total.
   356  func appendBigStruct(size uint16) []opcode.Opcode {
   357  	prog := make([]opcode.Opcode, size*2)
   358  	for i := uint16(0); i < size; i++ {
   359  		prog[i*2] = opcode.PUSH0
   360  		prog[i*2+1] = opcode.NEWSTRUCT
   361  	}
   362  
   363  	return append(prog,
   364  		opcode.INITSSLOT, 1,
   365  		opcode.PUSHINT16, opcode.Opcode(size), opcode.Opcode(size>>8), // LE
   366  		opcode.PACK, opcode.CONVERT, opcode.Opcode(stackitem.StructT),
   367  		opcode.STSFLD0, opcode.LDSFLD0,
   368  		opcode.DUP,
   369  		opcode.PUSH0, opcode.NEWARRAY,
   370  		opcode.SWAP,
   371  		opcode.APPEND, opcode.RET)
   372  }
   373  
   374  func TestStackLimitAPPENDStructGood(t *testing.T) {
   375  	prog := makeProgram(appendBigStruct(MaxStackSize/2 - 2)...)
   376  	v := load(prog)
   377  	runVM(t, v) // size = 2047 = (Max/2-2)*2+3 = Max-1
   378  }
   379  
   380  func TestStackLimitAPPENDStructBad(t *testing.T) {
   381  	prog := makeProgram(appendBigStruct(MaxStackSize/2 - 1)...)
   382  	v := load(prog)
   383  	checkVMFailed(t, v) // size = 2049 = (Max/2-1)*2+3 = Max+1
   384  }
   385  
   386  func TestStackLimit(t *testing.T) {
   387  	expected := []struct {
   388  		inst opcode.Opcode
   389  		size int
   390  	}{
   391  		{opcode.PUSH2, 2},    // 1 from INITSSLOT and 1 for integer 2
   392  		{opcode.NEWARRAY, 4}, // array + 2 items
   393  		{opcode.STSFLD0, 3},
   394  		{opcode.LDSFLD0, 4},
   395  		{opcode.NEWMAP, 5},
   396  		{opcode.DUP, 6},
   397  		{opcode.PUSH2, 7},
   398  		{opcode.LDSFLD0, 8},
   399  		{opcode.SETITEM, 7}, // -3 items and 1 new kv pair in map
   400  		{opcode.DUP, 8},
   401  		{opcode.PUSH2, 9},
   402  		{opcode.LDSFLD0, 10},
   403  		{opcode.SETITEM, 7}, // -3 items and no new elements in map
   404  		{opcode.DUP, 8},
   405  		{opcode.PUSH2, 9},
   406  		{opcode.REMOVE, 5}, // as we have right after NEWMAP
   407  		{opcode.DROP, 4},   // DROP map with no elements
   408  	}
   409  
   410  	prog := make([]opcode.Opcode, len(expected)+2)
   411  	prog[0] = opcode.INITSSLOT
   412  	prog[1] = 1
   413  	for i := range expected {
   414  		prog[i+2] = expected[i].inst
   415  	}
   416  
   417  	vm := load(makeProgram(prog...))
   418  	require.NoError(t, vm.Step(), "failed to initialize static slot")
   419  	for i := range expected {
   420  		require.NoError(t, vm.Step())
   421  		require.Equal(t, expected[i].size, int(vm.refs), "i: %d", i)
   422  	}
   423  }
   424  
   425  func TestPushm1to16(t *testing.T) {
   426  	var prog []byte
   427  	for i := int(opcode.PUSHM1); i <= int(opcode.PUSH16); i++ {
   428  		if i == 80 {
   429  			continue // opcode layout we got here.
   430  		}
   431  		prog = append(prog, byte(i))
   432  	}
   433  
   434  	vm := load(prog)
   435  	for i := int(opcode.PUSHM1); i <= int(opcode.PUSH16); i++ {
   436  		err := vm.Step()
   437  		require.NoError(t, err)
   438  
   439  		elem := vm.estack.Pop()
   440  		val := i - int(opcode.PUSH1) + 1
   441  		assert.Equal(t, elem.BigInt().Int64(), int64(val))
   442  	}
   443  }
   444  
   445  func TestPUSHDATA1(t *testing.T) {
   446  	t.Run("Good", getTestFuncForVM([]byte{byte(opcode.PUSHDATA1), 3, 1, 2, 3}, []byte{1, 2, 3}))
   447  	t.Run("NoN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA1)}, nil))
   448  	t.Run("BadN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA1), 1}, nil))
   449  }
   450  
   451  func TestPUSHDATA2(t *testing.T) {
   452  	t.Run("Good", getTestFuncForVM([]byte{byte(opcode.PUSHDATA2), 3, 0, 1, 2, 3}, []byte{1, 2, 3}))
   453  	t.Run("NoN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA2)}, nil))
   454  	t.Run("ShortN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA2), 0}, nil))
   455  	t.Run("BadN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA2), 1, 0}, nil))
   456  }
   457  
   458  func TestPUSHDATA4(t *testing.T) {
   459  	t.Run("Good", getTestFuncForVM([]byte{byte(opcode.PUSHDATA4), 3, 0, 0, 0, 1, 2, 3}, []byte{1, 2, 3}))
   460  	t.Run("NoN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA4)}, nil))
   461  	t.Run("BadN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA4), 1, 0, 0, 0}, nil))
   462  	t.Run("ShortN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA4), 0, 0, 0}, nil))
   463  }
   464  
   465  func TestPushData4BigN(t *testing.T) {
   466  	prog := make([]byte, 1+4+stackitem.MaxSize+1)
   467  	prog[0] = byte(opcode.PUSHDATA4)
   468  	binary.LittleEndian.PutUint32(prog[1:], stackitem.MaxSize+1)
   469  
   470  	vm := load(prog)
   471  	checkVMFailed(t, vm)
   472  }
   473  
   474  func getTestCallFlagsFunc(syscall []byte, flags callflag.CallFlag, result any) func(t *testing.T) {
   475  	return func(t *testing.T) {
   476  		script := append([]byte{byte(opcode.SYSCALL)}, syscall...)
   477  		v := newTestVM()
   478  		v.SyscallHandler = testSyscallHandler
   479  		v.LoadScriptWithFlags(script, flags)
   480  		if result == nil {
   481  			checkVMFailed(t, v)
   482  			return
   483  		}
   484  		runVM(t, v)
   485  		require.Equal(t, result, v.PopResult())
   486  	}
   487  }
   488  
   489  func TestCallFlags(t *testing.T) {
   490  	noFlags := []byte{0x77, 0x77, 0x77, 0x77}
   491  	readOnly := []byte{0x66, 0x66, 0x66, 0x66}
   492  	t.Run("NoFlagsNoRequired", getTestCallFlagsFunc(noFlags, callflag.NoneFlag, new(int)))
   493  	t.Run("ProvideFlagsNoRequired", getTestCallFlagsFunc(noFlags, callflag.AllowCall, new(int)))
   494  	t.Run("NoFlagsSomeRequired", getTestCallFlagsFunc(readOnly, callflag.NoneFlag, nil))
   495  	t.Run("OnlyOneProvided", getTestCallFlagsFunc(readOnly, callflag.AllowCall, nil))
   496  	t.Run("AllFlagsProvided", getTestCallFlagsFunc(readOnly, callflag.ReadOnly, new(int)))
   497  }
   498  
   499  func callNTimes(n uint16) []byte {
   500  	return makeProgram(
   501  		opcode.PUSHINT16, opcode.Opcode(n), opcode.Opcode(n>>8), // little-endian
   502  		opcode.INITSSLOT, 1,
   503  		opcode.STSFLD0, opcode.LDSFLD0,
   504  		opcode.JMPIF, 0x3, opcode.RET,
   505  		opcode.LDSFLD0, opcode.DEC,
   506  		opcode.CALL, 0xF9) // -7 -> JMP to TOALTSTACK)
   507  }
   508  
   509  func TestInvocationLimitGood(t *testing.T) {
   510  	prog := callNTimes(MaxInvocationStackSize - 1)
   511  	v := load(prog)
   512  	runVM(t, v)
   513  }
   514  
   515  func TestInvocationLimitBad(t *testing.T) {
   516  	prog := callNTimes(MaxInvocationStackSize)
   517  	v := load(prog)
   518  	checkVMFailed(t, v)
   519  }
   520  
   521  func isLongJMP(op opcode.Opcode) bool {
   522  	return op == opcode.JMPL || op == opcode.JMPIFL || op == opcode.JMPIFNOTL ||
   523  		op == opcode.JMPEQL || op == opcode.JMPNEL ||
   524  		op == opcode.JMPGEL || op == opcode.JMPGTL ||
   525  		op == opcode.JMPLEL || op == opcode.JMPLTL
   526  }
   527  
   528  func getJMPProgram(op opcode.Opcode) []byte {
   529  	prog := []byte{byte(op)}
   530  	if isLongJMP(op) {
   531  		prog = append(prog, 0x07, 0x00, 0x00, 0x00)
   532  	} else {
   533  		prog = append(prog, 0x04)
   534  	}
   535  	return append(prog, byte(opcode.PUSH1), byte(opcode.RET), byte(opcode.PUSH2), byte(opcode.RET))
   536  }
   537  
   538  func testJMP(t *testing.T, op opcode.Opcode, res any, items ...any) {
   539  	prog := getJMPProgram(op)
   540  	v := load(prog)
   541  	for i := range items {
   542  		v.estack.PushVal(items[i])
   543  	}
   544  	if res == nil {
   545  		checkVMFailed(t, v)
   546  		return
   547  	}
   548  	runVM(t, v)
   549  	require.EqualValues(t, res, v.estack.Pop().BigInt().Int64())
   550  }
   551  
   552  func TestJMPs(t *testing.T) {
   553  	testCases := []struct {
   554  		name  string
   555  		items []any
   556  	}{
   557  		{
   558  			name: "no condition",
   559  		},
   560  		{
   561  			name:  "single item (true)",
   562  			items: []any{true},
   563  		},
   564  		{
   565  			name:  "single item (false)",
   566  			items: []any{false},
   567  		},
   568  		{
   569  			name:  "24 and 42",
   570  			items: []any{24, 42},
   571  		},
   572  		{
   573  			name:  "42 and 24",
   574  			items: []any{42, 24},
   575  		},
   576  		{
   577  			name:  "42 and 42",
   578  			items: []any{42, 42},
   579  		},
   580  	}
   581  
   582  	// 2 is true, 1 is false
   583  	results := map[opcode.Opcode][]any{
   584  		opcode.JMP:      {2, 2, 2, 2, 2, 2},
   585  		opcode.JMPIF:    {nil, 2, 1, 2, 2, 2},
   586  		opcode.JMPIFNOT: {nil, 1, 2, 1, 1, 1},
   587  		opcode.JMPEQ:    {nil, nil, nil, 1, 1, 2},
   588  		opcode.JMPNE:    {nil, nil, nil, 2, 2, 1},
   589  		opcode.JMPGE:    {nil, nil, nil, 1, 2, 2},
   590  		opcode.JMPGT:    {nil, nil, nil, 1, 2, 1},
   591  		opcode.JMPLE:    {nil, nil, nil, 2, 1, 2},
   592  		opcode.JMPLT:    {nil, nil, nil, 2, 1, 1},
   593  	}
   594  
   595  	for i, tc := range testCases {
   596  		i := i
   597  		t.Run(tc.name, func(t *testing.T) {
   598  			for op := opcode.JMP; op < opcode.JMPLEL; op++ {
   599  				resOp := op
   600  				if isLongJMP(op) {
   601  					resOp--
   602  				}
   603  				t.Run(op.String(), func(t *testing.T) {
   604  					testJMP(t, op, results[resOp][i], tc.items...)
   605  				})
   606  			}
   607  		})
   608  	}
   609  }
   610  
   611  func TestPUSHA(t *testing.T) {
   612  	t.Run("Negative", getTestFuncForVM(makeProgram(opcode.PUSHA, 0xFF, 0xFF, 0xFF, 0xFF), nil))
   613  	t.Run("TooBig", getTestFuncForVM(makeProgram(opcode.PUSHA, 10, 0, 0, 0), nil))
   614  	t.Run("Good", func(t *testing.T) {
   615  		prog := makeProgram(opcode.NOP, opcode.PUSHA, 2, 0, 0, 0)
   616  		runWithArgs(t, prog, stackitem.NewPointer(3, prog))
   617  	})
   618  }
   619  
   620  func TestCALLA(t *testing.T) {
   621  	prog := makeProgram(opcode.CALLA, opcode.PUSH2, opcode.ADD, opcode.RET, opcode.PUSH3, opcode.RET)
   622  	t.Run("InvalidScript", getTestFuncForVM(prog, nil, stackitem.NewPointer(4, []byte{1})))
   623  	t.Run("Good", getTestFuncForVM(prog, 5, stackitem.NewPointer(4, prog)))
   624  }
   625  
   626  func TestCALL(t *testing.T) {
   627  	prog := makeProgram(
   628  		opcode.CALL, 4, opcode.ADD, opcode.RET,
   629  		opcode.CALL, 3, opcode.RET,
   630  		opcode.PUSH1, opcode.PUSH2, opcode.RET)
   631  	runWithArgs(t, prog, 3)
   632  }
   633  
   634  func TestNOT(t *testing.T) {
   635  	prog := makeProgram(opcode.NOT)
   636  	t.Run("Bool", getTestFuncForVM(prog, true, false))
   637  	t.Run("NonZeroInt", getTestFuncForVM(prog, false, 3))
   638  	t.Run("Array", getTestFuncForVM(prog, false, []stackitem.Item{}))
   639  	t.Run("Struct", getTestFuncForVM(prog, false, stackitem.NewStruct([]stackitem.Item{})))
   640  	t.Run("ByteArray0", getTestFuncForVM(prog, true, []byte{0, 0}))
   641  	t.Run("ByteArray1", getTestFuncForVM(prog, false, []byte{0, 1}))
   642  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
   643  	t.Run("Buffer0", getTestFuncForVM(prog, false, stackitem.NewBuffer([]byte{})))
   644  	t.Run("Buffer1", getTestFuncForVM(prog, false, stackitem.NewBuffer([]byte{1})))
   645  }
   646  
   647  // getBigInt returns 2^a+b.
   648  func getBigInt(a, b int64) *big.Int {
   649  	p := new(big.Int).Exp(big.NewInt(2), big.NewInt(a), nil)
   650  	p.Add(p, big.NewInt(b))
   651  	return p
   652  }
   653  
   654  func TestArith(t *testing.T) {
   655  	// results for 5 and 2
   656  	testCases := map[opcode.Opcode]int{
   657  		opcode.ADD: 7,
   658  		opcode.MUL: 10,
   659  		opcode.DIV: 2,
   660  		opcode.MOD: 1,
   661  		opcode.SUB: 3,
   662  	}
   663  
   664  	for op, res := range testCases {
   665  		t.Run(op.String(), getTestFuncForVM(makeProgram(op), res, 5, 2))
   666  	}
   667  }
   668  
   669  func TestADDBigResult(t *testing.T) {
   670  	prog := makeProgram(opcode.ADD)
   671  	runWithArgs(t, prog, nil, getBigInt(stackitem.MaxBigIntegerSizeBits-1, -1), 1) // 0x7FFF...
   672  }
   673  
   674  func TestMULBigResult(t *testing.T) {
   675  	prog := makeProgram(opcode.MUL)
   676  	bi := getBigInt(stackitem.MaxBigIntegerSizeBits/2+1, 0)
   677  	runWithArgs(t, prog, nil, bi, bi)
   678  }
   679  
   680  func TestArithNegativeArguments(t *testing.T) {
   681  	runCase := func(op opcode.Opcode, p, q, result int64) func(t *testing.T) {
   682  		return getTestFuncForVM(makeProgram(op), result, p, q)
   683  	}
   684  
   685  	t.Run("DIV", func(t *testing.T) {
   686  		t.Run("positive/positive", runCase(opcode.DIV, 5, 2, 2))
   687  		t.Run("positive/negative", runCase(opcode.DIV, 5, -2, -2))
   688  		t.Run("negative/positive", runCase(opcode.DIV, -5, 2, -2))
   689  		t.Run("negative/negative", runCase(opcode.DIV, -5, -2, 2))
   690  	})
   691  
   692  	t.Run("MOD", func(t *testing.T) {
   693  		t.Run("positive/positive", runCase(opcode.MOD, 5, 2, 1))
   694  		t.Run("positive/negative", runCase(opcode.MOD, 5, -2, 1))
   695  		t.Run("negative/positive", runCase(opcode.MOD, -5, 2, -1))
   696  		t.Run("negative/negative", runCase(opcode.MOD, -5, -2, -1))
   697  	})
   698  
   699  	t.Run("SHR", func(t *testing.T) {
   700  		t.Run("positive/positive", runCase(opcode.SHR, 5, 2, 1))
   701  		t.Run("negative/positive", runCase(opcode.SHR, -5, 2, -2))
   702  	})
   703  
   704  	t.Run("SHL", func(t *testing.T) {
   705  		t.Run("positive/positive", runCase(opcode.SHL, 5, 2, 20))
   706  		t.Run("negative/positive", runCase(opcode.SHL, -5, 2, -20))
   707  	})
   708  }
   709  
   710  func TestSUBBigResult(t *testing.T) {
   711  	prog := makeProgram(opcode.SUB)
   712  	bi := getBigInt(stackitem.MaxBigIntegerSizeBits-1, -1)
   713  	runWithArgs(t, prog, new(big.Int).Sub(big.NewInt(-1), bi), -1, bi)
   714  	runWithArgs(t, prog, nil, -2, bi)
   715  }
   716  
   717  func TestPOW(t *testing.T) {
   718  	prog := makeProgram(opcode.POW)
   719  	t.Run("good, positive", getTestFuncForVM(prog, 9, 3, 2))
   720  	t.Run("good, negative, even", getTestFuncForVM(prog, 4, -2, 2))
   721  	t.Run("good, negative, odd", getTestFuncForVM(prog, -8, -2, 3))
   722  	t.Run("zero", getTestFuncForVM(prog, 1, 3, 0))
   723  	t.Run("negative exponent", getTestFuncForVM(prog, nil, 3, -1))
   724  	t.Run("too big exponent", getTestFuncForVM(prog, nil, 1, maxSHLArg+1))
   725  }
   726  
   727  func TestSQRT(t *testing.T) {
   728  	prog := makeProgram(opcode.SQRT)
   729  	t.Run("good, positive", getTestFuncForVM(prog, 3, 9))
   730  	t.Run("good, round down", getTestFuncForVM(prog, 2, 8))
   731  	t.Run("one", getTestFuncForVM(prog, 1, 1))
   732  	t.Run("zero", getTestFuncForVM(prog, 0, 0))
   733  	t.Run("negative value", getTestFuncForVM(prog, nil, -1))
   734  }
   735  
   736  func TestMODMUL(t *testing.T) {
   737  	prog := makeProgram(opcode.MODMUL)
   738  	t.Run("bad, zero mod", getTestFuncForVM(prog, nil, 1, 2, 0))
   739  	t.Run("good, positive base", getTestFuncForVM(prog, 2, 3, 4, 5))
   740  	t.Run("good, zero base", getTestFuncForVM(prog, 0, 0, 4, 5))
   741  	t.Run("good, negative base", getTestFuncForVM(prog, 3, -3, 4, 5))
   742  	t.Run("good, positive base, negative mod", getTestFuncForVM(prog, 2, 3, 4, -5))
   743  	t.Run("good, negative base, negative mod", getTestFuncForVM(prog, 3, -3, 4, -5))
   744  }
   745  
   746  func TestMODPOW(t *testing.T) {
   747  	prog := makeProgram(opcode.MODPOW)
   748  	t.Run("good, positive base", getTestFuncForVM(prog, 1, 3, 4, 5))
   749  	t.Run("good, negative base", getTestFuncForVM(prog, 2, -3, 5, 5))
   750  	t.Run("good, positive base, negative mod", getTestFuncForVM(prog, 1, 3, 4, -5))
   751  	t.Run("good, negative base, negative mod", getTestFuncForVM(prog, 2, -3, 5, -5))
   752  	t.Run("bad, big negative exponent", getTestFuncForVM(prog, nil, 3, -2, 5))
   753  	t.Run("bad, zero modulus", getTestFuncForVM(prog, nil, 3, 4, 0))
   754  
   755  	t.Run("inverse compatibility", func(t *testing.T) { // Tests are taken from C# node.
   756  		t.Run("bad mod", getTestFuncForVM(prog, nil, 1, -1, 0))
   757  		t.Run("bad mod", getTestFuncForVM(prog, nil, 1, -1, 1))
   758  		t.Run("bad base", getTestFuncForVM(prog, nil, 0, -1, 0))
   759  		t.Run("bad base", getTestFuncForVM(prog, nil, 0, -1, 1))
   760  		t.Run("no inverse exists", getTestFuncForVM(prog, nil, math.MaxUint16, -1, math.MaxUint8))
   761  		t.Run("good", getTestFuncForVM(prog, 52, 19, -1, 141))
   762  	})
   763  }
   764  
   765  func TestSHR(t *testing.T) {
   766  	prog := makeProgram(opcode.SHR)
   767  	t.Run("Good", getTestFuncForVM(prog, 1, 4, 2))
   768  	t.Run("Zero", getTestFuncForVM(prog, []byte{0, 1}, []byte{0, 1}, 0))
   769  	t.Run("Negative", getTestFuncForVM(prog, nil, 5, -1))
   770  	t.Run("very big", getTestFuncForVM(prog, nil, 5, maxu64Plus(1)))
   771  }
   772  
   773  func TestSHL(t *testing.T) {
   774  	prog := makeProgram(opcode.SHL)
   775  	t.Run("Good", getTestFuncForVM(prog, 16, 4, 2))
   776  	t.Run("Zero", getTestFuncForVM(prog, []byte{0, 1}, []byte{0, 1}, 0))
   777  	t.Run("BigShift", getTestFuncForVM(prog, nil, 5, maxSHLArg+1))
   778  	t.Run("BigResult", getTestFuncForVM(prog, nil, getBigInt(stackitem.MaxBigIntegerSizeBits/2, 0), stackitem.MaxBigIntegerSizeBits/2))
   779  	t.Run("very big shift", getTestFuncForVM(prog, nil, 5, maxu64Plus(1)))
   780  }
   781  
   782  func TestArithNullArg(t *testing.T) {
   783  	for _, op := range []opcode.Opcode{opcode.LT, opcode.LE, opcode.GT, opcode.GE} {
   784  		prog := makeProgram(op)
   785  		t.Run(op.String(), func(t *testing.T) {
   786  			runWithArgs(t, prog, false, stackitem.Null{}, 0)
   787  			runWithArgs(t, prog, false, 0, stackitem.Null{})
   788  			runWithArgs(t, prog, nil, stackitem.NewInterop(nil), 1) // also has `.Value() == nil`
   789  		})
   790  	}
   791  }
   792  
   793  func TestLT(t *testing.T) {
   794  	prog := makeProgram(opcode.LT)
   795  	runWithArgs(t, prog, false, 4, 3)
   796  }
   797  
   798  func TestLE(t *testing.T) {
   799  	prog := makeProgram(opcode.LE)
   800  	runWithArgs(t, prog, true, 2, 3)
   801  }
   802  
   803  func TestGT(t *testing.T) {
   804  	prog := makeProgram(opcode.GT)
   805  	runWithArgs(t, prog, true, 9, 3)
   806  }
   807  
   808  func TestGE(t *testing.T) {
   809  	prog := makeProgram(opcode.GE)
   810  	runWithArgs(t, prog, true, 3, 3)
   811  }
   812  
   813  func TestDepth(t *testing.T) {
   814  	prog := makeProgram(opcode.DEPTH)
   815  	vm := load(prog)
   816  	vm.estack.PushVal(1)
   817  	vm.estack.PushVal(2)
   818  	vm.estack.PushVal(3)
   819  	runVM(t, vm)
   820  	assert.Equal(t, int64(3), vm.estack.Pop().BigInt().Int64())
   821  }
   822  
   823  type simpleEquatable struct {
   824  	ok bool
   825  }
   826  
   827  var _ = stackitem.Equatable(simpleEquatable{})
   828  
   829  func (e simpleEquatable) Equals(other stackitem.Equatable) bool {
   830  	_, ok := other.(simpleEquatable)
   831  	return ok && e.ok
   832  }
   833  
   834  func TestEQUALTrue(t *testing.T) {
   835  	prog := makeProgram(opcode.DUP, opcode.EQUAL)
   836  	t.Run("Array", getTestFuncForVM(prog, true, []stackitem.Item{}))
   837  	t.Run("Map", getTestFuncForVM(prog, true, stackitem.NewMap()))
   838  	t.Run("Buffer", getTestFuncForVM(prog, true, stackitem.NewBuffer([]byte{1, 2})))
   839  	t.Run("Equatable", getTestFuncForVM(prog, true, stackitem.NewInterop(simpleEquatable{ok: true})))
   840  }
   841  
   842  func TestEQUAL(t *testing.T) {
   843  	prog := makeProgram(opcode.EQUAL)
   844  	t.Run("NoArgs", getTestFuncForVM(prog, nil))
   845  	t.Run("OneArgument", getTestFuncForVM(prog, nil, 1))
   846  	t.Run("Integer", getTestFuncForVM(prog, true, 5, 5))
   847  	t.Run("IntegerByteArray", getTestFuncForVM(prog, false, []byte{16}, 16))
   848  	t.Run("BooleanInteger", getTestFuncForVM(prog, false, true, 1))
   849  	t.Run("Map", getTestFuncForVM(prog, false, stackitem.NewMap(), stackitem.NewMap()))
   850  	t.Run("Array", getTestFuncForVM(prog, false, []stackitem.Item{}, []stackitem.Item{}))
   851  	t.Run("Buffer", getTestFuncForVM(prog, false, stackitem.NewBuffer([]byte{42}), stackitem.NewBuffer([]byte{42})))
   852  	t.Run("EquatableFalse", getTestFuncForVM(prog, false, stackitem.NewInterop(simpleEquatable{false}), stackitem.NewInterop(simpleEquatable{})))
   853  	t.Run("EquatableTrue", getTestFuncForVM(prog, true, stackitem.NewInterop(simpleEquatable{true}), stackitem.NewInterop(simpleEquatable{})))
   854  }
   855  
   856  func TestEQUALByteArrayWithLimit(t *testing.T) {
   857  	prog := makeProgram(opcode.EQUAL)
   858  	t.Run("fits limit, equal", func(t *testing.T) {
   859  		args := make([]stackitem.Item, 2)
   860  		for i := range args {
   861  			args[i] = stackitem.NewStruct([]stackitem.Item{
   862  				stackitem.NewByteArray(make([]byte, stackitem.MaxByteArrayComparableSize/2)),
   863  				stackitem.NewByteArray(make([]byte, stackitem.MaxByteArrayComparableSize/2)),
   864  			})
   865  		}
   866  		getTestFuncForVM(prog, true, args[0], args[1])(t)
   867  	})
   868  	t.Run("exceeds limit", func(t *testing.T) {
   869  		args := make([]stackitem.Item, 2)
   870  		for i := range args {
   871  			args[i] = stackitem.NewStruct([]stackitem.Item{
   872  				stackitem.NewByteArray(make([]byte, stackitem.MaxByteArrayComparableSize/2+1)),
   873  				stackitem.NewByteArray(make([]byte, stackitem.MaxByteArrayComparableSize/2)),
   874  			})
   875  		}
   876  		getTestFuncForVM(prog, nil, args[0], args[1])(t) // should FAULT due to comparable limit exceeding
   877  	})
   878  	t.Run("fits limit, second elements are not equal", func(t *testing.T) {
   879  		args := make([]stackitem.Item, 2)
   880  		for i := range args {
   881  			args[i] = stackitem.NewStruct([]stackitem.Item{
   882  				stackitem.NewByteArray(make([]byte, stackitem.MaxByteArrayComparableSize-1)),
   883  				stackitem.NewBuffer(make([]byte, 1)),
   884  			})
   885  		}
   886  		getTestFuncForVM(prog, false, args[0], args[1])(t) // no limit is exceeded, but the second struct item is a Buffer.
   887  	})
   888  	t.Run("fits limit, equal", func(t *testing.T) {
   889  		args := make([]stackitem.Item, 2)
   890  		buf := stackitem.NewBuffer(make([]byte, 100500)) // takes only 1 comparable unit despite its length
   891  		for i := range args {
   892  			args[i] = stackitem.NewStruct([]stackitem.Item{
   893  				stackitem.NewByteArray(make([]byte, stackitem.MaxByteArrayComparableSize-1)),
   894  				buf,
   895  			})
   896  		}
   897  		getTestFuncForVM(prog, true, args[0], args[1])(t) // should HALT, because no limit exceeded
   898  	})
   899  	t.Run("exceeds limit, equal", func(t *testing.T) {
   900  		args := make([]stackitem.Item, 2)
   901  		buf := stackitem.NewBuffer(make([]byte, 100500)) // takes only 1 comparable unit despite its length
   902  		for i := range args {
   903  			args[i] = stackitem.NewStruct([]stackitem.Item{
   904  				stackitem.NewByteArray(make([]byte, stackitem.MaxByteArrayComparableSize-1)), // MaxByteArrayComparableSize-1 comparable  units
   905  				buf, // 1 comparable unit
   906  				buf, // 1 comparable unit
   907  			})
   908  		}
   909  		getTestFuncForVM(prog, nil, args[0], args[1])(t) // should FAULT, because limit is exceeded:
   910  	})
   911  }
   912  
   913  func runWithArgs(t *testing.T, prog []byte, result any, args ...any) {
   914  	getTestFuncForVM(prog, result, args...)(t)
   915  }
   916  
   917  func getCustomTestFuncForVM(prog []byte, check func(t *testing.T, v *VM), args ...any) func(t *testing.T) {
   918  	return func(t *testing.T) {
   919  		v := load(prog)
   920  		for i := range args {
   921  			v.estack.PushVal(args[i])
   922  		}
   923  		if check == nil {
   924  			checkVMFailed(t, v)
   925  			return
   926  		}
   927  		runVM(t, v)
   928  		check(t, v)
   929  	}
   930  }
   931  
   932  func getTestFuncForVM(prog []byte, result any, args ...any) func(t *testing.T) {
   933  	var f func(t *testing.T, v *VM)
   934  	if result != nil {
   935  		f = func(t *testing.T, v *VM) {
   936  			require.Equal(t, 1, v.estack.Len())
   937  			require.Equal(t, stackitem.Make(result).Value(), v.estack.Pop().Value())
   938  		}
   939  	}
   940  	return getCustomTestFuncForVM(prog, f, args...)
   941  }
   942  
   943  func makeRETProgram(t *testing.T, argCount, localCount int) []byte {
   944  	require.True(t, argCount+localCount <= 255)
   945  
   946  	fProg := []opcode.Opcode{opcode.INITSLOT, opcode.Opcode(localCount), opcode.Opcode(argCount)}
   947  	for i := 0; i < localCount; i++ {
   948  		fProg = append(fProg, opcode.PUSH8, opcode.STLOC, opcode.Opcode(i))
   949  	}
   950  	fProg = append(fProg, opcode.RET)
   951  
   952  	offset := uint32(len(fProg) + 5)
   953  	param := make([]byte, 4)
   954  	binary.LittleEndian.PutUint32(param, offset)
   955  
   956  	ops := []opcode.Opcode{
   957  		opcode.INITSSLOT, 0x01,
   958  		opcode.PUSHA, 11, 0, 0, 0,
   959  		opcode.STSFLD0,
   960  		opcode.JMPL, opcode.Opcode(param[0]), opcode.Opcode(param[1]), opcode.Opcode(param[2]), opcode.Opcode(param[3]),
   961  	}
   962  	ops = append(ops, fProg...)
   963  
   964  	// execute func multiple times to ensure total reference count is less than max
   965  	callCount := MaxStackSize/(argCount+localCount) + 1
   966  	args := make([]opcode.Opcode, argCount)
   967  	for i := range args {
   968  		args[i] = opcode.PUSH7
   969  	}
   970  	for i := 0; i < callCount; i++ {
   971  		ops = append(ops, args...)
   972  		ops = append(ops, opcode.LDSFLD0, opcode.CALLA)
   973  	}
   974  	return makeProgram(ops...)
   975  }
   976  
   977  func TestRETReferenceClear(t *testing.T) {
   978  	// 42 is a canary
   979  	t.Run("Argument", getTestFuncForVM(makeRETProgram(t, 100, 0), 42, 42))
   980  	t.Run("Local", getTestFuncForVM(makeRETProgram(t, 0, 100), 42, 42))
   981  }
   982  
   983  func TestNOTEQUALByteArray(t *testing.T) {
   984  	prog := makeProgram(opcode.NOTEQUAL)
   985  	t.Run("True", getTestFuncForVM(prog, true, []byte{1, 2}, []byte{0, 1, 2}))
   986  	t.Run("False", getTestFuncForVM(prog, false, []byte{1, 2}, []byte{1, 2}))
   987  }
   988  
   989  func TestNUMEQUAL(t *testing.T) {
   990  	prog := makeProgram(opcode.NUMEQUAL)
   991  	t.Run("True", getTestFuncForVM(prog, true, 2, 2))
   992  	t.Run("False", getTestFuncForVM(prog, false, 1, 2))
   993  }
   994  
   995  func TestNUMNOTEQUAL(t *testing.T) {
   996  	prog := makeProgram(opcode.NUMNOTEQUAL)
   997  	t.Run("True", getTestFuncForVM(prog, true, 1, 2))
   998  	t.Run("False", getTestFuncForVM(prog, false, 2, 2))
   999  }
  1000  
  1001  func TestINC(t *testing.T) {
  1002  	prog := makeProgram(opcode.INC)
  1003  	runWithArgs(t, prog, 2, 1)
  1004  }
  1005  
  1006  func TestINCBigResult(t *testing.T) {
  1007  	prog := makeProgram(opcode.INC, opcode.INC)
  1008  	vm := load(prog)
  1009  	x := getBigInt(stackitem.MaxBigIntegerSizeBits-1, -2)
  1010  	vm.estack.PushVal(x)
  1011  
  1012  	require.NoError(t, vm.Step())
  1013  	require.False(t, vm.HasFailed())
  1014  	require.Equal(t, 1, vm.estack.Len())
  1015  	require.Equal(t, new(big.Int).Add(x, big.NewInt(1)), vm.estack.Top().BigInt())
  1016  
  1017  	checkVMFailed(t, vm)
  1018  }
  1019  
  1020  func TestDECBigResult(t *testing.T) {
  1021  	prog := makeProgram(opcode.DEC, opcode.DEC)
  1022  	vm := load(prog)
  1023  	x := getBigInt(stackitem.MaxBigIntegerSizeBits-1, -1)
  1024  	x.Neg(x)
  1025  	vm.estack.PushVal(x)
  1026  
  1027  	require.NoError(t, vm.Step())
  1028  	require.False(t, vm.HasFailed())
  1029  	require.Equal(t, 1, vm.estack.Len())
  1030  	require.Equal(t, new(big.Int).Sub(x, big.NewInt(1)), vm.estack.Top().BigInt())
  1031  
  1032  	checkVMFailed(t, vm)
  1033  }
  1034  
  1035  func TestNEWBUFFER(t *testing.T) {
  1036  	prog := makeProgram(opcode.NEWBUFFER)
  1037  	t.Run("Good", getTestFuncForVM(prog, stackitem.NewBuffer([]byte{0, 0, 0}), 3))
  1038  	t.Run("Negative", getTestFuncForVM(prog, nil, -1))
  1039  	t.Run("TooBig", getTestFuncForVM(prog, nil, stackitem.MaxSize+1))
  1040  }
  1041  
  1042  func getTRYProgram(tryBlock, catchBlock, finallyBlock []byte) []byte {
  1043  	hasCatch := catchBlock != nil
  1044  	hasFinally := finallyBlock != nil
  1045  	tryOffset := len(tryBlock) + 3 + 2 // try args + endtry args
  1046  
  1047  	var (
  1048  		catchLen, finallyLen       int
  1049  		catchOffset, finallyOffset int
  1050  	)
  1051  	if hasCatch {
  1052  		catchLen = len(catchBlock) + 2 // endtry args
  1053  		catchOffset = tryOffset
  1054  	}
  1055  	if hasFinally {
  1056  		finallyLen = len(finallyBlock) + 1 // endfinally
  1057  		finallyOffset = tryOffset + catchLen
  1058  	}
  1059  	prog := []byte{byte(opcode.TRY), byte(catchOffset), byte(finallyOffset)}
  1060  	prog = append(prog, tryBlock...)
  1061  	prog = append(prog, byte(opcode.ENDTRY), byte(catchLen+finallyLen+2))
  1062  	if hasCatch {
  1063  		prog = append(prog, catchBlock...)
  1064  		prog = append(prog, byte(opcode.ENDTRY), byte(finallyLen+2))
  1065  	}
  1066  	if hasFinally {
  1067  		prog = append(prog, finallyBlock...)
  1068  		prog = append(prog, byte(opcode.ENDFINALLY))
  1069  	}
  1070  	prog = append(prog, byte(opcode.RET))
  1071  	return prog
  1072  }
  1073  
  1074  func getTRYTestFunc(result any, tryBlock, catchBlock, finallyBlock []byte) func(t *testing.T) {
  1075  	return func(t *testing.T) {
  1076  		prog := getTRYProgram(tryBlock, catchBlock, finallyBlock)
  1077  		runWithArgs(t, prog, result)
  1078  	}
  1079  }
  1080  
  1081  func TestTRY(t *testing.T) {
  1082  	throw := []byte{byte(opcode.PUSH13), byte(opcode.THROW)}
  1083  	push1 := []byte{byte(opcode.PUSH1)}
  1084  	add5 := []byte{byte(opcode.PUSH5), byte(opcode.ADD)}
  1085  	add9 := []byte{byte(opcode.PUSH9), byte(opcode.ADD)}
  1086  	t.Run("NoCatch", func(t *testing.T) {
  1087  		t.Run("NoFinally", func(t *testing.T) {
  1088  			prog := getTRYProgram(push1, nil, nil)
  1089  			vm := load(prog)
  1090  			checkVMFailed(t, vm)
  1091  		})
  1092  		t.Run("WithFinally", getTRYTestFunc(10, push1, nil, add9))
  1093  		t.Run("Throw", getTRYTestFunc(nil, throw, nil, add9))
  1094  	})
  1095  	t.Run("WithCatch", func(t *testing.T) {
  1096  		t.Run("NoFinally", func(t *testing.T) {
  1097  			t.Run("Simple", getTRYTestFunc(1, push1, add5, nil))
  1098  			t.Run("Throw", getTRYTestFunc(18, throw, add5, nil))
  1099  			t.Run("Abort", getTRYTestFunc(nil, []byte{byte(opcode.ABORT)}, push1, nil))
  1100  			t.Run("AbortMSG", getTRYTestFunc(nil, []byte{byte(opcode.PUSH1), byte(opcode.ABORTMSG)}, push1, nil))
  1101  			t.Run("ThrowInCatch", getTRYTestFunc(nil, throw, throw, nil))
  1102  		})
  1103  		t.Run("WithFinally", func(t *testing.T) {
  1104  			t.Run("Simple", getTRYTestFunc(10, push1, add5, add9))
  1105  			t.Run("Throw", getTRYTestFunc(27, throw, add5, add9))
  1106  		})
  1107  	})
  1108  	t.Run("Nested", func(t *testing.T) {
  1109  		t.Run("ReThrowInTry", func(t *testing.T) {
  1110  			inner := getTRYProgram(throw, []byte{byte(opcode.THROW)}, nil)
  1111  			getTRYTestFunc(27, inner, add5, add9)(t)
  1112  		})
  1113  		t.Run("ThrowInFinally", func(t *testing.T) {
  1114  			inner := getTRYProgram(throw, add5, []byte{byte(opcode.THROW)})
  1115  			getTRYTestFunc(32, inner, add5, add9)(t)
  1116  		})
  1117  		t.Run("TryMaxDepth", func(t *testing.T) {
  1118  			loopTries := []byte{byte(opcode.INITSLOT), 0x01, 0x00,
  1119  				byte(opcode.PUSH16), byte(opcode.INC), byte(opcode.STLOC0),
  1120  				byte(opcode.TRY), 1, 1, // jump target
  1121  				byte(opcode.LDLOC0), byte(opcode.DEC), byte(opcode.DUP),
  1122  				byte(opcode.STLOC0), byte(opcode.PUSH0),
  1123  				byte(opcode.JMPGT), 0xf8, byte(opcode.LDLOC0)}
  1124  			vm := load(loopTries)
  1125  			checkVMFailed(t, vm)
  1126  		})
  1127  	})
  1128  	t.Run("ThrowInCall", func(t *testing.T) {
  1129  		catchP := []byte{byte(opcode.CALL), 2, byte(opcode.PUSH1), byte(opcode.ADD), byte(opcode.THROW), byte(opcode.RET)}
  1130  		inner := getTRYProgram(throw, catchP, []byte{byte(opcode.PUSH2)})
  1131  		// add 5 to the exception, mul to the result of inner finally (2)
  1132  		getTRYTestFunc(47, inner, append(add5, byte(opcode.MUL)), add9)(t)
  1133  	})
  1134  	t.Run("nested, in throw and catch in call", func(t *testing.T) {
  1135  		catchP := []byte{byte(opcode.PUSH10), byte(opcode.ADD)}
  1136  		inner := getTRYProgram(throw, catchP, []byte{byte(opcode.PUSH2)})
  1137  		outer := getTRYProgram([]byte{byte(opcode.CALL), 0}, []byte{byte(opcode.PUSH3)}, []byte{byte(opcode.PUSH4)})
  1138  		outer = append(outer, byte(opcode.RET))
  1139  		outer[4] = byte(len(outer) - 3) // CALL argument at 3 (TRY) + 1 (CALL opcode)
  1140  		outer = append(outer, inner...)
  1141  		outer = append(outer, byte(opcode.RET))
  1142  
  1143  		v := load(outer)
  1144  		runVM(t, v)
  1145  		require.Equal(t, 3, v.Estack().Len())
  1146  		require.Equal(t, big.NewInt(4), v.Estack().Pop().Value())  // outer FINALLY
  1147  		require.Equal(t, big.NewInt(2), v.Estack().Pop().Value())  // inner FINALLY
  1148  		require.Equal(t, big.NewInt(23), v.Estack().Pop().Value()) // inner THROW + CATCH
  1149  	})
  1150  }
  1151  
  1152  func TestMEMCPY(t *testing.T) {
  1153  	prog := makeProgram(opcode.MEMCPY)
  1154  	t.Run("Good", func(t *testing.T) {
  1155  		buf := stackitem.NewBuffer([]byte{0, 1, 2, 3})
  1156  		runWithArgs(t, prog, stackitem.NewBuffer([]byte{0, 6, 7, 3}), buf, buf, 1, []byte{4, 5, 6, 7}, 2, 2)
  1157  	})
  1158  	t.Run("NonZeroDstIndex", func(t *testing.T) {
  1159  		buf := stackitem.NewBuffer([]byte{0, 1, 2})
  1160  		runWithArgs(t, prog, stackitem.NewBuffer([]byte{0, 6, 7}), buf, buf, 1, []byte{4, 5, 6, 7}, 2, 2)
  1161  	})
  1162  	t.Run("NegativeSize", getTestFuncForVM(prog, nil, stackitem.NewBuffer([]byte{0, 1}), 0, []byte{2}, 0, -1))
  1163  	t.Run("NegativeSrcIndex", getTestFuncForVM(prog, nil, stackitem.NewBuffer([]byte{0, 1}), 0, []byte{2}, -1, 1))
  1164  	t.Run("NegativeDstIndex", getTestFuncForVM(prog, nil, stackitem.NewBuffer([]byte{0, 1}), -1, []byte{2}, 0, 1))
  1165  	t.Run("BigSizeSrc", getTestFuncForVM(prog, nil, stackitem.NewBuffer([]byte{0, 1}), 0, []byte{2}, 0, 2))
  1166  	t.Run("BigSizeDst", getTestFuncForVM(prog, nil, stackitem.NewBuffer([]byte{0, 1}), 0, []byte{2, 3, 4}, 0, 3))
  1167  }
  1168  
  1169  func TestNEWARRAY0(t *testing.T) {
  1170  	prog := makeProgram(opcode.NEWARRAY0)
  1171  	runWithArgs(t, prog, []stackitem.Item{})
  1172  }
  1173  
  1174  func TestNEWSTRUCT0(t *testing.T) {
  1175  	prog := makeProgram(opcode.NEWSTRUCT0)
  1176  	runWithArgs(t, prog, stackitem.NewStruct([]stackitem.Item{}))
  1177  }
  1178  
  1179  func TestNEWARRAYArray(t *testing.T) {
  1180  	prog := makeProgram(opcode.NEWARRAY)
  1181  	t.Run("ByteArray", getTestFuncForVM(prog, stackitem.NewArray([]stackitem.Item{}), []byte{}))
  1182  	t.Run("BadSize", getTestFuncForVM(prog, nil, MaxStackSize+1))
  1183  	t.Run("Integer", getTestFuncForVM(prog, []stackitem.Item{stackitem.Null{}}, 1))
  1184  }
  1185  
  1186  func testNEWARRAYIssue437(t *testing.T, i1 opcode.Opcode, t2 stackitem.Type, appended bool) {
  1187  	prog := makeProgram(
  1188  		opcode.PUSH2, i1,
  1189  		opcode.DUP, opcode.PUSH3, opcode.APPEND,
  1190  		opcode.INITSSLOT, 1,
  1191  		opcode.STSFLD0, opcode.LDSFLD0, opcode.CONVERT, opcode.Opcode(t2),
  1192  		opcode.DUP, opcode.PUSH4, opcode.APPEND,
  1193  		opcode.LDSFLD0, opcode.PUSH5, opcode.APPEND)
  1194  
  1195  	arr := makeArrayOfType(4, stackitem.AnyT)
  1196  	arr[2] = stackitem.Make(3)
  1197  	arr[3] = stackitem.Make(4)
  1198  	if appended {
  1199  		arr = append(arr, stackitem.Make(5))
  1200  	}
  1201  
  1202  	if t2 == stackitem.ArrayT {
  1203  		runWithArgs(t, prog, stackitem.NewArray(arr))
  1204  	} else {
  1205  		runWithArgs(t, prog, stackitem.NewStruct(arr))
  1206  	}
  1207  }
  1208  
  1209  func TestNEWARRAYIssue437(t *testing.T) {
  1210  	t.Run("Array+Array", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWARRAY, stackitem.ArrayT, true) })
  1211  	t.Run("Struct+Struct", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWSTRUCT, stackitem.StructT, true) })
  1212  	t.Run("Array+Struct", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWARRAY, stackitem.StructT, false) })
  1213  	t.Run("Struct+Array", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWSTRUCT, stackitem.ArrayT, false) })
  1214  }
  1215  
  1216  func TestNEWARRAYT(t *testing.T) {
  1217  	testCases := map[stackitem.Type]stackitem.Item{
  1218  		stackitem.BooleanT:   stackitem.NewBool(false),
  1219  		stackitem.IntegerT:   stackitem.NewBigInteger(big.NewInt(0)),
  1220  		stackitem.ByteArrayT: stackitem.NewByteArray([]byte{}),
  1221  		stackitem.ArrayT:     stackitem.Null{},
  1222  		0xFF:                 nil,
  1223  	}
  1224  	for typ, item := range testCases {
  1225  		prog := makeProgram(opcode.NEWARRAYT, opcode.Opcode(typ), opcode.PUSH0, opcode.PICKITEM)
  1226  		t.Run(typ.String(), getTestFuncForVM(prog, item, 1))
  1227  	}
  1228  }
  1229  
  1230  func TestNEWSTRUCT(t *testing.T) {
  1231  	prog := makeProgram(opcode.NEWSTRUCT)
  1232  	t.Run("ByteArray", getTestFuncForVM(prog, stackitem.NewStruct([]stackitem.Item{}), []byte{}))
  1233  	t.Run("BadSize", getTestFuncForVM(prog, nil, MaxStackSize+1))
  1234  	t.Run("Integer", getTestFuncForVM(prog, stackitem.NewStruct([]stackitem.Item{stackitem.Null{}}), 1))
  1235  }
  1236  
  1237  func TestAPPEND(t *testing.T) {
  1238  	prog := makeProgram(opcode.DUP, opcode.PUSH5, opcode.APPEND)
  1239  	arr := []stackitem.Item{stackitem.Make(5)}
  1240  	t.Run("Array", getTestFuncForVM(prog, stackitem.NewArray(arr), stackitem.NewArray(nil)))
  1241  	t.Run("Struct", getTestFuncForVM(prog, stackitem.NewStruct(arr), stackitem.NewStruct(nil)))
  1242  }
  1243  
  1244  func TestAPPENDCloneStruct(t *testing.T) {
  1245  	prog := makeProgram(opcode.DUP, opcode.PUSH0, opcode.NEWSTRUCT, opcode.INITSSLOT, 1, opcode.STSFLD0,
  1246  		opcode.LDSFLD0, opcode.APPEND, opcode.LDSFLD0, opcode.PUSH1, opcode.APPEND)
  1247  	arr := []stackitem.Item{stackitem.NewStruct([]stackitem.Item{})}
  1248  	runWithArgs(t, prog, stackitem.NewArray(arr), stackitem.NewArray(nil))
  1249  }
  1250  
  1251  func TestAPPENDBad(t *testing.T) {
  1252  	prog := makeProgram(opcode.APPEND)
  1253  	t.Run("no arguments", getTestFuncForVM(prog, nil))
  1254  	t.Run("one argument", getTestFuncForVM(prog, nil, 1))
  1255  	t.Run("wrong type", getTestFuncForVM(prog, nil, []byte{}, 1))
  1256  }
  1257  
  1258  func TestAPPENDGoodSizeLimit(t *testing.T) {
  1259  	prog := makeProgram(opcode.NEWARRAY, opcode.DUP, opcode.PUSH0, opcode.APPEND)
  1260  	vm := load(prog)
  1261  	vm.estack.PushVal(MaxStackSize - 3) // 1 for array, 1 for copy, 1 for pushed 0.
  1262  	runVM(t, vm)
  1263  	assert.Equal(t, 1, vm.estack.Len())
  1264  	assert.Equal(t, MaxStackSize-2, len(vm.estack.Pop().Array()))
  1265  }
  1266  
  1267  func TestAPPENDBadSizeLimit(t *testing.T) {
  1268  	prog := makeProgram(opcode.NEWARRAY, opcode.DUP, opcode.PUSH0, opcode.APPEND)
  1269  	runWithArgs(t, prog, nil, MaxStackSize)
  1270  }
  1271  
  1272  func TestAPPENDRefSizeLimit(t *testing.T) {
  1273  	prog := makeProgram(opcode.NEWARRAY0, opcode.DUP, opcode.DUP, opcode.APPEND, opcode.JMP, 0xfd)
  1274  	runWithArgs(t, prog, nil)
  1275  }
  1276  
  1277  func TestPICKITEM(t *testing.T) {
  1278  	prog := makeProgram(opcode.PICKITEM)
  1279  	t.Run("bad index", getTestFuncForVM(prog, nil, []stackitem.Item{}, 0))
  1280  	t.Run("Array", getTestFuncForVM(prog, 2, []stackitem.Item{stackitem.Make(1), stackitem.Make(2)}, 1))
  1281  	t.Run("ByteArray", getTestFuncForVM(prog, 2, []byte{1, 2}, 1))
  1282  	t.Run("Buffer", getTestFuncForVM(prog, 2, stackitem.NewBuffer([]byte{1, 2}), 1))
  1283  	t.Run("Exceptions", func(t *testing.T) {
  1284  		tryProg := getTRYProgram(
  1285  			[]byte{byte(opcode.PICKITEM), byte(opcode.RET)},
  1286  			[]byte{byte(opcode.RET)}, nil)
  1287  		items := []stackitem.Item{
  1288  			stackitem.NewArray([]stackitem.Item{}),
  1289  			stackitem.NewBuffer([]byte{}),
  1290  			stackitem.NewByteArray([]byte{}),
  1291  		}
  1292  		for _, item := range items {
  1293  			t.Run(item.String()+", negative", getTestFuncForVM(tryProg,
  1294  				fmt.Sprintf("The value %d is out of range.", math.MinInt32),
  1295  				item, math.MinInt32))
  1296  			t.Run(item.String()+", very big index",
  1297  				getTestFuncForVM(tryProg, nil, item, int64(math.MaxInt32)+1))
  1298  		}
  1299  
  1300  		m := stackitem.NewMap()
  1301  		t.Run("Map, missing key", getTestFuncForVM(tryProg, "Key not found in Map", m, 1))
  1302  	})
  1303  }
  1304  
  1305  func TestVMPrintOps(t *testing.T) {
  1306  	w := io.NewBufBinWriter()
  1307  	emit.Bytes(w.BinWriter, make([]byte, 1000))
  1308  	emit.Opcodes(w.BinWriter, opcode.PUSH0)
  1309  	emit.Bytes(w.BinWriter, make([]byte, 8))
  1310  
  1311  	buf := bytes.NewBuffer(nil)
  1312  	v := New()
  1313  	v.Load(w.Bytes())
  1314  	v.PrintOps(buf)
  1315  
  1316  	ss := strings.Split(buf.String(), "\n")
  1317  	require.Equal(t, 5, len(ss)) // header + 3 opcodes + trailing newline
  1318  	require.True(t, len(ss[0]) < 1000)
  1319  	require.True(t, len(ss[1]) > 1000)
  1320  	require.True(t, len(ss[2]) < 1000)
  1321  	require.True(t, len(ss[3]) < 1000)
  1322  }
  1323  
  1324  func TestPICKITEMDupArray(t *testing.T) {
  1325  	prog := makeProgram(opcode.DUP, opcode.PUSH0, opcode.PICKITEM, opcode.ABS)
  1326  	vm := load(prog)
  1327  	vm.estack.PushVal([]stackitem.Item{stackitem.Make(-1)})
  1328  	runVM(t, vm)
  1329  	assert.Equal(t, 2, vm.estack.Len())
  1330  	assert.Equal(t, int64(1), vm.estack.Pop().BigInt().Int64())
  1331  	items := vm.estack.Pop().Value().([]stackitem.Item)
  1332  	assert.Equal(t, big.NewInt(-1), items[0].Value())
  1333  }
  1334  
  1335  func TestPICKITEMDupMap(t *testing.T) {
  1336  	prog := makeProgram(opcode.DUP, opcode.PUSHINT8, 42, opcode.PICKITEM, opcode.ABS)
  1337  	vm := load(prog)
  1338  	m := stackitem.NewMap()
  1339  	m.Add(stackitem.Make(42), stackitem.Make(-1))
  1340  	vm.estack.Push(Element{value: m})
  1341  	runVM(t, vm)
  1342  	assert.Equal(t, 2, vm.estack.Len())
  1343  	assert.Equal(t, int64(1), vm.estack.Pop().BigInt().Int64())
  1344  	items := vm.estack.Pop().Value().([]stackitem.MapElement)
  1345  	assert.Equal(t, 1, len(items))
  1346  	assert.Equal(t, big.NewInt(42), items[0].Key.Value())
  1347  	assert.Equal(t, big.NewInt(-1), items[0].Value.Value())
  1348  }
  1349  
  1350  func TestPICKITEMMap(t *testing.T) {
  1351  	prog := makeProgram(opcode.PICKITEM)
  1352  	m := stackitem.NewMap()
  1353  	m.Add(stackitem.Make(5), stackitem.Make(3))
  1354  	runWithArgs(t, prog, 3, m, 5)
  1355  }
  1356  
  1357  func TestSETITEMBuffer(t *testing.T) {
  1358  	prog := makeProgram(opcode.DUP, opcode.REVERSE4, opcode.SETITEM)
  1359  	t.Run("Good", getTestFuncForVM(prog, stackitem.NewBuffer([]byte{0, 42, 2}), 42, 1, stackitem.NewBuffer([]byte{0, 1, 2})))
  1360  	t.Run("BadValue", getTestFuncForVM(prog, nil, 256, 1, stackitem.NewBuffer([]byte{0, 1, 2})))
  1361  	t.Run("Exceptions", func(t *testing.T) {
  1362  		tryProg := getTRYProgram(
  1363  			[]byte{byte(opcode.SETITEM), byte(opcode.PUSH12), byte(opcode.RET)},
  1364  			[]byte{byte(opcode.RET)}, nil)
  1365  		t.Run("negative index", getTestFuncForVM(tryProg,
  1366  			fmt.Sprintf("The value %d is out of range.", math.MinInt32),
  1367  			stackitem.NewBuffer([]byte{0, 1, 2}), math.MinInt32, 0))
  1368  		t.Run("very big index", getTestFuncForVM(tryProg,
  1369  			nil, stackitem.NewBuffer([]byte{0, 1, 2}), int64(math.MaxInt32)+1, 0))
  1370  	})
  1371  }
  1372  
  1373  func TestSETITEMArray(t *testing.T) {
  1374  	tryProg := getTRYProgram(
  1375  		[]byte{byte(opcode.SETITEM), byte(opcode.RET)},
  1376  		[]byte{byte(opcode.RET)}, nil)
  1377  	t.Run("Good", func(t *testing.T) {
  1378  		arr := stackitem.NewArray([]stackitem.Item{stackitem.Make(12), stackitem.Make(2)})
  1379  		expected := stackitem.NewArray([]stackitem.Item{stackitem.Make(12), stackitem.Make(42)})
  1380  		runWithArgs(t, tryProg, expected, arr, arr, 1, 42)
  1381  	})
  1382  	t.Run("negative index", getTestFuncForVM(tryProg,
  1383  		fmt.Sprintf("The value %d is out of range.", math.MinInt32),
  1384  		[]stackitem.Item{}, math.MinInt32, 42))
  1385  	t.Run("very big index", getTestFuncForVM(tryProg,
  1386  		nil, []stackitem.Item{}, int64(math.MaxInt32)+1, 0))
  1387  }
  1388  
  1389  func TestSETITEMMap(t *testing.T) {
  1390  	prog := makeProgram(opcode.SETITEM, opcode.PICKITEM)
  1391  	m := stackitem.NewMap()
  1392  	m.Add(stackitem.Make(5), stackitem.Make(3))
  1393  	runWithArgs(t, prog, []byte{0, 1}, m, 5, m, 5, []byte{0, 1})
  1394  
  1395  	t.Run("big key", func(t *testing.T) {
  1396  		m := stackitem.NewMap()
  1397  		key := make([]byte, stackitem.MaxKeySize)
  1398  		for i := range key {
  1399  			key[i] = 0x0F
  1400  		}
  1401  		m.Add(stackitem.NewByteArray(key), stackitem.Make(3))
  1402  		runWithArgs(t, prog, "value", m, key, m, key, "value")
  1403  	})
  1404  }
  1405  
  1406  func TestSETITEMBigMapBad(t *testing.T) {
  1407  	prog := makeProgram(opcode.SETITEM)
  1408  	m := stackitem.NewMap()
  1409  	for i := 0; i < MaxStackSize; i++ {
  1410  		m.Add(stackitem.Make(i), stackitem.Make(i))
  1411  	}
  1412  
  1413  	runWithArgs(t, prog, nil, m, m, MaxStackSize, 0)
  1414  }
  1415  
  1416  // This test checks is SETITEM properly updates reference counter.
  1417  // 1. Create 2 arrays of size MaxStackSize/2 - 3.
  1418  // 2. SETITEM each of them to a map.
  1419  // 3. Replace each of them with a scalar value.
  1420  func TestSETITEMMapStackLimit(t *testing.T) {
  1421  	size := MaxStackSize/2 - 4
  1422  	m := stackitem.NewMap()
  1423  	m.Add(stackitem.NewBigInteger(big.NewInt(1)), stackitem.NewArray(makeArrayOfType(size, stackitem.BooleanT)))
  1424  	m.Add(stackitem.NewBigInteger(big.NewInt(2)), stackitem.NewArray(makeArrayOfType(size, stackitem.BooleanT)))
  1425  
  1426  	prog := makeProgram(
  1427  		opcode.DUP, opcode.PUSH1, opcode.PUSH1, opcode.SETITEM,
  1428  		opcode.DUP, opcode.PUSH2, opcode.PUSH2, opcode.SETITEM,
  1429  		opcode.DUP, opcode.PUSH3, opcode.PUSH3, opcode.SETITEM,
  1430  		opcode.DUP, opcode.PUSH4, opcode.PUSH4, opcode.SETITEM)
  1431  	v := load(prog)
  1432  	v.estack.PushVal(m)
  1433  	runVM(t, v)
  1434  }
  1435  
  1436  func TestSETITEMBigMapGood(t *testing.T) {
  1437  	prog := makeProgram(opcode.SETITEM)
  1438  	vm := load(prog)
  1439  
  1440  	m := stackitem.NewMap()
  1441  	for i := 0; i < MaxStackSize-3; i++ {
  1442  		m.Add(stackitem.Make(i), stackitem.Make(i))
  1443  	}
  1444  	vm.estack.Push(Element{value: m})
  1445  	vm.estack.PushVal(0)
  1446  	vm.estack.PushVal(0)
  1447  
  1448  	runVM(t, vm)
  1449  }
  1450  
  1451  func TestSIZE(t *testing.T) {
  1452  	prog := makeProgram(opcode.SIZE)
  1453  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  1454  	t.Run("ByteArray", getTestFuncForVM(prog, 2, []byte{0, 1}))
  1455  	t.Run("Buffer", getTestFuncForVM(prog, 2, stackitem.NewBuffer([]byte{0, 1})))
  1456  	t.Run("Bool", getTestFuncForVM(prog, 1, false))
  1457  	t.Run("Array", getTestFuncForVM(prog, 2, []stackitem.Item{stackitem.Make(1), stackitem.Make([]byte{})}))
  1458  	t.Run("Map", func(t *testing.T) {
  1459  		m := stackitem.NewMap()
  1460  		m.Add(stackitem.Make(5), stackitem.Make(6))
  1461  		m.Add(stackitem.Make([]byte{0, 1}), stackitem.Make(6))
  1462  		runWithArgs(t, prog, 2, m)
  1463  	})
  1464  }
  1465  
  1466  func TestKEYSMap(t *testing.T) {
  1467  	prog := makeProgram(opcode.KEYS)
  1468  	vm := load(prog)
  1469  
  1470  	m := stackitem.NewMap()
  1471  	m.Add(stackitem.Make(5), stackitem.Make(6))
  1472  	m.Add(stackitem.Make([]byte{0, 1}), stackitem.Make(6))
  1473  	vm.estack.Push(Element{value: m})
  1474  
  1475  	runVM(t, vm)
  1476  	assert.Equal(t, 1, vm.estack.Len())
  1477  
  1478  	top := vm.estack.Pop().value.(*stackitem.Array)
  1479  	assert.Equal(t, 2, len(top.Value().([]stackitem.Item)))
  1480  	assert.Contains(t, top.Value().([]stackitem.Item), stackitem.Make(5))
  1481  	assert.Contains(t, top.Value().([]stackitem.Item), stackitem.Make([]byte{0, 1}))
  1482  }
  1483  
  1484  func TestKEYS(t *testing.T) {
  1485  	prog := makeProgram(opcode.KEYS)
  1486  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  1487  	t.Run("WrongType", getTestFuncForVM(prog, nil, []stackitem.Item{}))
  1488  }
  1489  
  1490  func TestTry_ENDFINALLY_before_ENDTRY(t *testing.T) {
  1491  	prog := makeProgram(opcode.TRY, 0, 3, opcode.ENDFINALLY)
  1492  	require.NoError(t, IsScriptCorrect(prog, nil))
  1493  
  1494  	v := load(prog)
  1495  
  1496  	var err error
  1497  	require.NotPanics(t, func() { err = v.Run() })
  1498  	require.Error(t, err)
  1499  }
  1500  
  1501  func TestVALUESMap(t *testing.T) {
  1502  	prog := makeProgram(opcode.VALUES)
  1503  	vm := load(prog)
  1504  
  1505  	m := stackitem.NewMap()
  1506  	m.Add(stackitem.Make(5), stackitem.Make([]byte{2, 3}))
  1507  	m.Add(stackitem.Make([]byte{0, 1}), stackitem.Make([]stackitem.Item{}))
  1508  	vm.estack.Push(Element{value: m})
  1509  
  1510  	runVM(t, vm)
  1511  	assert.Equal(t, 1, vm.estack.Len())
  1512  
  1513  	top := vm.estack.Pop().value.(*stackitem.Array)
  1514  	assert.Equal(t, 2, len(top.Value().([]stackitem.Item)))
  1515  	assert.Contains(t, top.Value().([]stackitem.Item), stackitem.Make([]byte{2, 3}))
  1516  	assert.Contains(t, top.Value().([]stackitem.Item), stackitem.Make([]stackitem.Item{}))
  1517  }
  1518  
  1519  func TestVALUES(t *testing.T) {
  1520  	prog := makeProgram(opcode.VALUES)
  1521  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  1522  	t.Run("WrongType", getTestFuncForVM(prog, nil, 5))
  1523  	t.Run("Array", getTestFuncForVM(prog, []int{4}, []int{4}))
  1524  }
  1525  
  1526  func TestHASKEY(t *testing.T) {
  1527  	prog := makeProgram(opcode.HASKEY)
  1528  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  1529  	t.Run("OneArgument", getTestFuncForVM(prog, nil, 1))
  1530  	t.Run("WrongKeyType", getTestFuncForVM(prog, nil, []stackitem.Item{}, []stackitem.Item{}))
  1531  	t.Run("WrongCollectionType", getTestFuncForVM(prog, nil, 1, 2))
  1532  
  1533  	arr := makeArrayOfType(5, stackitem.BooleanT)
  1534  	t.Run("Array", func(t *testing.T) {
  1535  		t.Run("True", getTestFuncForVM(prog, true, stackitem.NewArray(arr), 4))
  1536  		t.Run("too big", getTestFuncForVM(prog, nil, stackitem.NewArray(arr), maxu64Plus(4)))
  1537  		t.Run("False", getTestFuncForVM(prog, false, stackitem.NewArray(arr), 5))
  1538  	})
  1539  	t.Run("Struct", func(t *testing.T) {
  1540  		t.Run("True", getTestFuncForVM(prog, true, stackitem.NewStruct(arr), 4))
  1541  		t.Run("too big", getTestFuncForVM(prog, nil, stackitem.NewStruct(arr), maxu64Plus(4)))
  1542  		t.Run("False", getTestFuncForVM(prog, false, stackitem.NewStruct(arr), 5))
  1543  	})
  1544  
  1545  	t.Run("Buffer", func(t *testing.T) {
  1546  		t.Run("True", getTestFuncForVM(prog, true, stackitem.NewBuffer([]byte{5, 5, 5}), 2))
  1547  		t.Run("too big", getTestFuncForVM(prog, nil, stackitem.NewBuffer([]byte{5, 5, 5}), maxu64Plus(2)))
  1548  		t.Run("False", getTestFuncForVM(prog, false, stackitem.NewBuffer([]byte{5, 5, 5}), 3))
  1549  		t.Run("Negative", getTestFuncForVM(prog, nil, stackitem.NewBuffer([]byte{5, 5, 5}), -1))
  1550  	})
  1551  
  1552  	t.Run("ByteArray", func(t *testing.T) {
  1553  		t.Run("True", getTestFuncForVM(prog, true, stackitem.NewByteArray([]byte{5, 5, 5}), 2))
  1554  		t.Run("too big", getTestFuncForVM(prog, nil, stackitem.NewByteArray([]byte{5, 5, 5}), maxu64Plus(2)))
  1555  		t.Run("False", getTestFuncForVM(prog, false, stackitem.NewByteArray([]byte{5, 5, 5}), 3))
  1556  		t.Run("Negative", getTestFuncForVM(prog, nil, stackitem.NewByteArray([]byte{5, 5, 5}), -1))
  1557  	})
  1558  }
  1559  
  1560  func TestHASKEYMap(t *testing.T) {
  1561  	prog := makeProgram(opcode.HASKEY)
  1562  	m := stackitem.NewMap()
  1563  	m.Add(stackitem.Make(5), stackitem.Make(6))
  1564  	t.Run("True", getTestFuncForVM(prog, true, m, 5))
  1565  	t.Run("False", getTestFuncForVM(prog, false, m, 6))
  1566  }
  1567  
  1568  func TestHASKEYBigKey(t *testing.T) {
  1569  	v := newTestVM()
  1570  
  1571  	buf := io.NewBufBinWriter()
  1572  	emit.Int(buf.BinWriter, 1024*1024)
  1573  	emit.Opcodes(buf.BinWriter, opcode.NEWBUFFER, opcode.NEWMAP)
  1574  	emit.Int(buf.BinWriter, 64)
  1575  	emit.Opcodes(buf.BinWriter, opcode.NEWBUFFER)
  1576  	emit.Opcodes(buf.BinWriter, opcode.INITSLOT, opcode.Opcode(0), opcode.Opcode(3))
  1577  
  1578  	emit.Opcodes(buf.BinWriter, opcode.LDARG1, opcode.LDARG0, opcode.CONVERT, opcode.Opcode(stackitem.ByteArrayT))
  1579  	emit.Opcodes(buf.BinWriter, opcode.LDARG0, opcode.SETITEM, opcode.LDARG1, opcode.LDARG2)
  1580  	emit.Opcodes(buf.BinWriter, opcode.CONVERT, opcode.Opcode(stackitem.ByteArrayT))
  1581  	emit.Opcodes(buf.BinWriter, opcode.HASKEY)
  1582  
  1583  	emit.Opcodes(buf.BinWriter, opcode.JMP, opcode.Opcode(0xFB)) // -5
  1584  	v.Load(buf.Bytes())
  1585  	checkVMFailed(t, v)
  1586  }
  1587  
  1588  func TestSIGN(t *testing.T) {
  1589  	prog := makeProgram(opcode.SIGN)
  1590  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  1591  	t.Run("WrongType", getTestFuncForVM(prog, nil, []stackitem.Item{}))
  1592  	t.Run("Bool", getTestFuncForVM(prog, 0, false))
  1593  	t.Run("PositiveInt", getTestFuncForVM(prog, 1, 2))
  1594  	t.Run("NegativeInt", getTestFuncForVM(prog, -1, -1))
  1595  	t.Run("Zero", getTestFuncForVM(prog, 0, 0))
  1596  	t.Run("ByteArray", getTestFuncForVM(prog, 1, []byte{0, 1}))
  1597  }
  1598  
  1599  func TestSimpleCall(t *testing.T) {
  1600  	buf := io.NewBufBinWriter()
  1601  	w := buf.BinWriter
  1602  	emit.Opcodes(w, opcode.PUSH2)
  1603  	emit.Instruction(w, opcode.CALL, []byte{03})
  1604  	emit.Opcodes(w, opcode.RET)
  1605  	emit.Opcodes(w, opcode.PUSH10)
  1606  	emit.Opcodes(w, opcode.ADD)
  1607  	emit.Opcodes(w, opcode.RET)
  1608  
  1609  	result := 12
  1610  	vm := load(buf.Bytes())
  1611  	runVM(t, vm)
  1612  	assert.Equal(t, result, int(vm.estack.Pop().BigInt().Int64()))
  1613  }
  1614  
  1615  func TestNZ(t *testing.T) {
  1616  	prog := makeProgram(opcode.NZ)
  1617  	t.Run("True", getTestFuncForVM(prog, true, 1))
  1618  	t.Run("False", getTestFuncForVM(prog, false, 0))
  1619  }
  1620  
  1621  func TestPICK(t *testing.T) {
  1622  	prog := makeProgram(opcode.PICK)
  1623  	t.Run("NoItem", getTestFuncForVM(prog, nil, 1))
  1624  	t.Run("Negative", getTestFuncForVM(prog, nil, -1))
  1625  	t.Run("very big", getTestFuncForVM(prog, nil, 1, 2, 3, maxu64Plus(1)))
  1626  }
  1627  
  1628  func TestPICKgood(t *testing.T) {
  1629  	prog := makeProgram(opcode.PICK)
  1630  	result := 2
  1631  	vm := load(prog)
  1632  	vm.estack.PushVal(0)
  1633  	vm.estack.PushVal(1)
  1634  	vm.estack.PushVal(result)
  1635  	vm.estack.PushVal(3)
  1636  	vm.estack.PushVal(4)
  1637  	vm.estack.PushVal(5)
  1638  	vm.estack.PushVal(3)
  1639  	runVM(t, vm)
  1640  	assert.Equal(t, int64(result), vm.estack.Pop().BigInt().Int64())
  1641  }
  1642  
  1643  func TestPICKDup(t *testing.T) {
  1644  	prog := makeProgram(opcode.PUSHM1, opcode.PUSH0,
  1645  		opcode.PUSH1,
  1646  		opcode.PUSH2,
  1647  		opcode.PICK,
  1648  		opcode.ABS)
  1649  	vm := load(prog)
  1650  	runVM(t, vm)
  1651  	assert.Equal(t, 4, vm.estack.Len())
  1652  	assert.Equal(t, int64(1), vm.estack.Pop().BigInt().Int64())
  1653  	assert.Equal(t, int64(1), vm.estack.Pop().BigInt().Int64())
  1654  	assert.Equal(t, int64(0), vm.estack.Pop().BigInt().Int64())
  1655  	assert.Equal(t, int64(-1), vm.estack.Pop().BigInt().Int64())
  1656  }
  1657  
  1658  func TestROTBad(t *testing.T) {
  1659  	prog := makeProgram(opcode.ROT)
  1660  	runWithArgs(t, prog, nil, 1, 2)
  1661  }
  1662  
  1663  func TestROTGood(t *testing.T) {
  1664  	prog := makeProgram(opcode.ROT)
  1665  	vm := load(prog)
  1666  	vm.estack.PushVal(1)
  1667  	vm.estack.PushVal(2)
  1668  	vm.estack.PushVal(3)
  1669  	runVM(t, vm)
  1670  	assert.Equal(t, 3, vm.estack.Len())
  1671  	assert.Equal(t, stackitem.Make(1), vm.estack.Pop().value)
  1672  	assert.Equal(t, stackitem.Make(3), vm.estack.Pop().value)
  1673  	assert.Equal(t, stackitem.Make(2), vm.estack.Pop().value)
  1674  }
  1675  
  1676  func TestROLLBad1(t *testing.T) {
  1677  	prog := makeProgram(opcode.ROLL)
  1678  	runWithArgs(t, prog, nil, 1, -1)
  1679  }
  1680  
  1681  func TestROLLBad2(t *testing.T) {
  1682  	prog := makeProgram(opcode.ROLL)
  1683  	runWithArgs(t, prog, nil, 1, 2, 3, 3)
  1684  }
  1685  
  1686  func maxu64Plus(x int64) *big.Int {
  1687  	bi := new(big.Int).SetUint64(math.MaxUint64)
  1688  	bi.Add(bi, big.NewInt(2))
  1689  	return bi
  1690  }
  1691  
  1692  func TestROLLBad3(t *testing.T) {
  1693  	prog := makeProgram(opcode.ROLL)
  1694  	runWithArgs(t, prog, nil, 1, 2, 3, maxu64Plus(2))
  1695  }
  1696  
  1697  func TestROLLGood(t *testing.T) {
  1698  	prog := makeProgram(opcode.ROLL)
  1699  	vm := load(prog)
  1700  	vm.estack.PushVal(1)
  1701  	vm.estack.PushVal(2)
  1702  	vm.estack.PushVal(3)
  1703  	vm.estack.PushVal(4)
  1704  	vm.estack.PushVal(1)
  1705  	runVM(t, vm)
  1706  	assert.Equal(t, 4, vm.estack.Len())
  1707  	assert.Equal(t, stackitem.Make(3), vm.estack.Pop().value)
  1708  	assert.Equal(t, stackitem.Make(4), vm.estack.Pop().value)
  1709  	assert.Equal(t, stackitem.Make(2), vm.estack.Pop().value)
  1710  	assert.Equal(t, stackitem.Make(1), vm.estack.Pop().value)
  1711  }
  1712  
  1713  func getCheckEStackFunc(items ...any) func(t *testing.T, v *VM) {
  1714  	return func(t *testing.T, v *VM) {
  1715  		require.Equal(t, len(items), v.estack.Len())
  1716  		for i := 0; i < len(items); i++ {
  1717  			assert.Equal(t, stackitem.Make(items[i]), v.estack.Peek(i).Item())
  1718  		}
  1719  	}
  1720  }
  1721  
  1722  func TestREVERSE3(t *testing.T) {
  1723  	prog := makeProgram(opcode.REVERSE3)
  1724  	t.Run("SmallStack", getTestFuncForVM(prog, nil, 1, 2))
  1725  	t.Run("Good", getCustomTestFuncForVM(prog, getCheckEStackFunc(1, 2, 3), 1, 2, 3))
  1726  }
  1727  
  1728  func TestREVERSE4(t *testing.T) {
  1729  	prog := makeProgram(opcode.REVERSE4)
  1730  	t.Run("SmallStack", getTestFuncForVM(prog, nil, 1, 2, 3))
  1731  	t.Run("Good", getCustomTestFuncForVM(prog, getCheckEStackFunc(1, 2, 3, 4), 1, 2, 3, 4))
  1732  }
  1733  
  1734  func TestREVERSEN(t *testing.T) {
  1735  	prog := makeProgram(opcode.REVERSEN)
  1736  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  1737  	t.Run("SmallStack", getTestFuncForVM(prog, nil, 1, 2, 3))
  1738  	t.Run("NegativeArgument", getTestFuncForVM(prog, nil, 1, 2, -1))
  1739  	t.Run("Zero", getCustomTestFuncForVM(prog, getCheckEStackFunc(3, 2, 1), 1, 2, 3, 0))
  1740  	t.Run("OneItem", getCustomTestFuncForVM(prog, getCheckEStackFunc(42), 42, 1))
  1741  	t.Run("Good", getCustomTestFuncForVM(prog, getCheckEStackFunc(1, 2, 3, 4, 5), 1, 2, 3, 4, 5, 5))
  1742  	t.Run("VeryBigNumber", getCustomTestFuncForVM(prog, nil, 1, 2, maxu64Plus(2)))
  1743  }
  1744  
  1745  func TestTUCKbadNoitems(t *testing.T) {
  1746  	prog := makeProgram(opcode.TUCK)
  1747  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  1748  	t.Run("NoItem", getTestFuncForVM(prog, nil, 1))
  1749  }
  1750  
  1751  func TestTUCKgood(t *testing.T) {
  1752  	prog := makeProgram(opcode.TUCK)
  1753  	vm := load(prog)
  1754  	vm.estack.PushVal(42)
  1755  	vm.estack.PushVal(34)
  1756  	runVM(t, vm)
  1757  	assert.Equal(t, int64(34), vm.estack.Peek(0).BigInt().Int64())
  1758  	assert.Equal(t, int64(42), vm.estack.Peek(1).BigInt().Int64())
  1759  	assert.Equal(t, int64(34), vm.estack.Peek(2).BigInt().Int64())
  1760  }
  1761  
  1762  func TestTUCKgood2(t *testing.T) {
  1763  	prog := makeProgram(opcode.TUCK)
  1764  	vm := load(prog)
  1765  	vm.estack.PushVal(11)
  1766  	vm.estack.PushVal(42)
  1767  	vm.estack.PushVal(34)
  1768  	runVM(t, vm)
  1769  	assert.Equal(t, int64(34), vm.estack.Peek(0).BigInt().Int64())
  1770  	assert.Equal(t, int64(42), vm.estack.Peek(1).BigInt().Int64())
  1771  	assert.Equal(t, int64(34), vm.estack.Peek(2).BigInt().Int64())
  1772  	assert.Equal(t, int64(11), vm.estack.Peek(3).BigInt().Int64())
  1773  }
  1774  
  1775  func TestOVER(t *testing.T) {
  1776  	prog := makeProgram(opcode.OVER)
  1777  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  1778  	t.Run("NoItem", getTestFuncForVM(prog, nil, 1))
  1779  }
  1780  
  1781  func TestOVERgood(t *testing.T) {
  1782  	prog := makeProgram(opcode.OVER)
  1783  	vm := load(prog)
  1784  	vm.estack.PushVal(42)
  1785  	vm.estack.PushVal(34)
  1786  	runVM(t, vm)
  1787  	assert.Equal(t, int64(42), vm.estack.Peek(0).BigInt().Int64())
  1788  	assert.Equal(t, int64(34), vm.estack.Peek(1).BigInt().Int64())
  1789  	assert.Equal(t, int64(42), vm.estack.Peek(2).BigInt().Int64())
  1790  	assert.Equal(t, 3, vm.estack.Len())
  1791  }
  1792  
  1793  func TestOVERDup(t *testing.T) {
  1794  	prog := makeProgram(opcode.PUSHDATA1, 2, 1, 0,
  1795  		opcode.PUSH1,
  1796  		opcode.OVER,
  1797  		opcode.PUSH1,
  1798  		opcode.LEFT,
  1799  		opcode.PUSHDATA1, 1, 2,
  1800  		opcode.CAT)
  1801  	vm := load(prog)
  1802  	runVM(t, vm)
  1803  	assert.Equal(t, 3, vm.estack.Len())
  1804  	assert.Equal(t, []byte{0x01, 0x02}, vm.estack.Pop().Bytes())
  1805  	assert.Equal(t, int64(1), vm.estack.Pop().BigInt().Int64())
  1806  	assert.Equal(t, []byte{0x01, 0x00}, vm.estack.Pop().Bytes())
  1807  }
  1808  
  1809  func TestNIPBadNoItem(t *testing.T) {
  1810  	prog := makeProgram(opcode.NIP)
  1811  	runWithArgs(t, prog, nil, 1)
  1812  }
  1813  
  1814  func TestNIPGood(t *testing.T) {
  1815  	prog := makeProgram(opcode.NIP)
  1816  	runWithArgs(t, prog, 2, 1, 2)
  1817  }
  1818  
  1819  func TestDROPBadNoItem(t *testing.T) {
  1820  	prog := makeProgram(opcode.DROP)
  1821  	runWithArgs(t, prog, nil)
  1822  }
  1823  
  1824  func TestDROPGood(t *testing.T) {
  1825  	prog := makeProgram(opcode.DROP)
  1826  	vm := load(prog)
  1827  	vm.estack.PushVal(1)
  1828  	runVM(t, vm)
  1829  	assert.Equal(t, 0, vm.estack.Len())
  1830  }
  1831  
  1832  func TestXDROP(t *testing.T) {
  1833  	prog := makeProgram(opcode.XDROP)
  1834  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  1835  	t.Run("NoN", getTestFuncForVM(prog, nil, 1, 2))
  1836  	t.Run("very big argument", getTestFuncForVM(prog, nil, 1, 2, maxu64Plus(1)))
  1837  	t.Run("Negative", getTestFuncForVM(prog, nil, 1, -1))
  1838  }
  1839  
  1840  func TestXDROPgood(t *testing.T) {
  1841  	prog := makeProgram(opcode.XDROP)
  1842  	vm := load(prog)
  1843  	vm.estack.PushVal(0)
  1844  	vm.estack.PushVal(1)
  1845  	vm.estack.PushVal(2)
  1846  	vm.estack.PushVal(2)
  1847  	runVM(t, vm)
  1848  	assert.Equal(t, 2, vm.estack.Len())
  1849  	assert.Equal(t, int64(2), vm.estack.Peek(0).BigInt().Int64())
  1850  	assert.Equal(t, int64(1), vm.estack.Peek(1).BigInt().Int64())
  1851  }
  1852  
  1853  func TestCLEAR(t *testing.T) {
  1854  	prog := makeProgram(opcode.CLEAR)
  1855  	v := load(prog)
  1856  	v.estack.PushVal(123)
  1857  	require.Equal(t, 1, v.estack.Len())
  1858  	require.NoError(t, v.Run())
  1859  	require.Equal(t, 0, v.estack.Len())
  1860  }
  1861  
  1862  func TestINVERTbadNoitem(t *testing.T) {
  1863  	prog := makeProgram(opcode.INVERT)
  1864  	runWithArgs(t, prog, nil)
  1865  }
  1866  
  1867  func TestINVERTgood1(t *testing.T) {
  1868  	prog := makeProgram(opcode.INVERT)
  1869  	runWithArgs(t, prog, -1, 0)
  1870  }
  1871  
  1872  func TestINVERTgood2(t *testing.T) {
  1873  	prog := makeProgram(opcode.INVERT)
  1874  	vm := load(prog)
  1875  	vm.estack.PushVal(-1)
  1876  	runVM(t, vm)
  1877  	assert.Equal(t, int64(0), vm.estack.Peek(0).BigInt().Int64())
  1878  }
  1879  
  1880  func TestINVERTgood3(t *testing.T) {
  1881  	prog := makeProgram(opcode.INVERT)
  1882  	vm := load(prog)
  1883  	vm.estack.PushVal(0x69)
  1884  	runVM(t, vm)
  1885  	assert.Equal(t, int64(-0x6A), vm.estack.Peek(0).BigInt().Int64())
  1886  }
  1887  
  1888  func TestINVERTWithConversion1(t *testing.T) {
  1889  	prog := makeProgram(opcode.PUSHDATA2, 0, 0, opcode.INVERT)
  1890  	vm := load(prog)
  1891  	runVM(t, vm)
  1892  	assert.Equal(t, int64(-1), vm.estack.Peek(0).BigInt().Int64())
  1893  }
  1894  
  1895  func TestINVERTWithConversion2(t *testing.T) {
  1896  	prog := makeProgram(opcode.PUSH0, opcode.PUSH1, opcode.NUMEQUAL, opcode.INVERT)
  1897  	vm := load(prog)
  1898  	runVM(t, vm)
  1899  	assert.Equal(t, int64(-1), vm.estack.Peek(0).BigInt().Int64())
  1900  }
  1901  
  1902  func TestCAT(t *testing.T) {
  1903  	prog := makeProgram(opcode.CAT)
  1904  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  1905  	t.Run("OneArgument", getTestFuncForVM(prog, nil, []byte("abc")))
  1906  	t.Run("BigItem", func(t *testing.T) {
  1907  		arg := make([]byte, stackitem.MaxSize/2+1)
  1908  		runWithArgs(t, prog, nil, arg, arg)
  1909  	})
  1910  	t.Run("Good", getTestFuncForVM(prog, stackitem.NewBuffer([]byte("abcdef")), []byte("abc"), []byte("def")))
  1911  	t.Run("Int0ByteArray", getTestFuncForVM(prog, stackitem.NewBuffer([]byte{}), 0, []byte{}))
  1912  	t.Run("ByteArrayInt1", getTestFuncForVM(prog, stackitem.NewBuffer([]byte{1}), []byte{}, 1))
  1913  }
  1914  
  1915  func TestSUBSTR(t *testing.T) {
  1916  	prog := makeProgram(opcode.SUBSTR)
  1917  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  1918  	t.Run("OneArgument", getTestFuncForVM(prog, nil, 1))
  1919  	t.Run("TwoArguments", getTestFuncForVM(prog, nil, 0, 2))
  1920  	t.Run("Good", getTestFuncForVM(prog, stackitem.NewBuffer([]byte("bc")), []byte("abcdef"), 1, 2))
  1921  	t.Run("BadOffset", getTestFuncForVM(prog, nil, []byte("abcdef"), 7, 1))
  1922  	t.Run("very big offset", getTestFuncForVM(prog, nil, []byte("abcdef"), maxu64Plus(1), 1))
  1923  	t.Run("BigLen", getTestFuncForVM(prog, nil, []byte("abcdef"), 1, 6))
  1924  	t.Run("very big len", getTestFuncForVM(prog, nil, []byte("abcdef"), 1, maxu64Plus(1)))
  1925  	t.Run("NegativeOffset", getTestFuncForVM(prog, nil, []byte("abcdef"), -1, 3))
  1926  	t.Run("NegativeLen", getTestFuncForVM(prog, nil, []byte("abcdef"), 3, -1))
  1927  }
  1928  
  1929  func TestSUBSTRBad387(t *testing.T) {
  1930  	prog := makeProgram(opcode.SUBSTR)
  1931  	vm := load(prog)
  1932  	b := make([]byte, 6, 20)
  1933  	copy(b, "abcdef")
  1934  	vm.estack.PushVal(b)
  1935  	vm.estack.PushVal(1)
  1936  	vm.estack.PushVal(6)
  1937  	checkVMFailed(t, vm)
  1938  }
  1939  
  1940  func TestLEFT(t *testing.T) {
  1941  	prog := makeProgram(opcode.LEFT)
  1942  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  1943  	t.Run("NoString", getTestFuncForVM(prog, nil, 2))
  1944  	t.Run("NegativeLen", getTestFuncForVM(prog, nil, "abcdef", -1))
  1945  	t.Run("Good", getTestFuncForVM(prog, stackitem.NewBuffer([]byte("ab")), "abcdef", 2))
  1946  	t.Run("BadBigLen", getTestFuncForVM(prog, nil, "abcdef", 8))
  1947  	t.Run("bad, very big len", getTestFuncForVM(prog, nil, "abcdef", maxu64Plus(2)))
  1948  }
  1949  
  1950  func TestRIGHT(t *testing.T) {
  1951  	prog := makeProgram(opcode.RIGHT)
  1952  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  1953  	t.Run("NoString", getTestFuncForVM(prog, nil, 2))
  1954  	t.Run("NegativeLen", getTestFuncForVM(prog, nil, "abcdef", -1))
  1955  	t.Run("Good", getTestFuncForVM(prog, stackitem.NewBuffer([]byte("ef")), "abcdef", 2))
  1956  	t.Run("BadLen", getTestFuncForVM(prog, nil, "abcdef", 8))
  1957  	t.Run("bad, very big len", getTestFuncForVM(prog, nil, "abcdef", maxu64Plus(2)))
  1958  }
  1959  
  1960  func TestPACK(t *testing.T) {
  1961  	for _, op := range []opcode.Opcode{opcode.PACK, opcode.PACKSTRUCT} {
  1962  		t.Run(op.String(), func(t *testing.T) {
  1963  			prog := makeProgram(op)
  1964  			t.Run("BadLen", getTestFuncForVM(prog, nil, 1))
  1965  			t.Run("BigLen", getTestFuncForVM(prog, nil, 100500))
  1966  			t.Run("Good0Len", getTestFuncForVM(prog, []stackitem.Item{}, 0))
  1967  		})
  1968  	}
  1969  }
  1970  
  1971  func TestPACKGood(t *testing.T) {
  1972  	for _, op := range []opcode.Opcode{opcode.PACK, opcode.PACKSTRUCT} {
  1973  		t.Run(op.String(), func(t *testing.T) {
  1974  			prog := makeProgram(op)
  1975  			elements := []int{55, 34, 42}
  1976  			vm := load(prog)
  1977  			// canary
  1978  			vm.estack.PushVal(1)
  1979  			for i := len(elements) - 1; i >= 0; i-- {
  1980  				vm.estack.PushVal(elements[i])
  1981  			}
  1982  			vm.estack.PushVal(len(elements))
  1983  			runVM(t, vm)
  1984  			assert.Equal(t, 2, vm.estack.Len())
  1985  			a := vm.estack.Peek(0).Array()
  1986  			assert.Equal(t, len(elements), len(a))
  1987  			for i := 0; i < len(elements); i++ {
  1988  				e := a[i].Value().(*big.Int)
  1989  				assert.Equal(t, int64(elements[i]), e.Int64())
  1990  			}
  1991  			assert.Equal(t, int64(1), vm.estack.Peek(1).BigInt().Int64())
  1992  		})
  1993  	}
  1994  }
  1995  
  1996  func TestPACK_UNPACK_MaxSize(t *testing.T) {
  1997  	prog := makeProgram(opcode.PACK, opcode.UNPACK)
  1998  	elements := make([]int, MaxStackSize-2)
  1999  	vm := load(prog)
  2000  	// canary
  2001  	vm.estack.PushVal(1)
  2002  	for i := len(elements) - 1; i >= 0; i-- {
  2003  		vm.estack.PushVal(elements[i])
  2004  	}
  2005  	vm.estack.PushVal(len(elements))
  2006  	runVM(t, vm)
  2007  	// check reference counter = 1+1+1024
  2008  	assert.Equal(t, 1+1+len(elements), int(vm.refs))
  2009  	assert.Equal(t, 1+1+len(elements), vm.estack.Len()) // canary + length + elements
  2010  	assert.Equal(t, int64(len(elements)), vm.estack.Peek(0).Value().(*big.Int).Int64())
  2011  	for i := 0; i < len(elements); i++ {
  2012  		e, ok := vm.estack.Peek(i + 1).Value().(*big.Int)
  2013  		assert.True(t, ok)
  2014  		assert.Equal(t, int64(elements[i]), e.Int64())
  2015  	}
  2016  	assert.Equal(t, int64(1), vm.estack.Peek(1+len(elements)).BigInt().Int64())
  2017  }
  2018  
  2019  func TestPACK_UNPACK_PACK_MaxSize(t *testing.T) {
  2020  	prog := makeProgram(opcode.PACK, opcode.UNPACK, opcode.PACK)
  2021  	elements := make([]int, MaxStackSize-2)
  2022  	vm := load(prog)
  2023  	// canary
  2024  	vm.estack.PushVal(1)
  2025  	for i := len(elements) - 1; i >= 0; i-- {
  2026  		vm.estack.PushVal(elements[i])
  2027  	}
  2028  	vm.estack.PushVal(len(elements))
  2029  	runVM(t, vm)
  2030  	// check reference counter = 1+1+1024
  2031  	assert.Equal(t, 1+1+len(elements), int(vm.refs))
  2032  	assert.Equal(t, 2, vm.estack.Len())
  2033  	a := vm.estack.Peek(0).Array()
  2034  	assert.Equal(t, len(elements), len(a))
  2035  	for i := 0; i < len(elements); i++ {
  2036  		e := a[i].Value().(*big.Int)
  2037  		assert.Equal(t, int64(elements[i]), e.Int64())
  2038  	}
  2039  	assert.Equal(t, int64(1), vm.estack.Peek(1).BigInt().Int64())
  2040  }
  2041  
  2042  func TestPACKMAP_UNPACK_PACKMAP_MaxSize(t *testing.T) {
  2043  	prog := makeProgram(opcode.PACKMAP, opcode.UNPACK, opcode.PACKMAP)
  2044  	elements := make([]int, (MaxStackSize-2)/2)
  2045  	vm := load(prog)
  2046  	// canary
  2047  	vm.estack.PushVal(-1)
  2048  	for i := len(elements) - 1; i >= 0; i-- {
  2049  		elements[i] = i
  2050  		vm.estack.PushVal(i * 2)
  2051  		vm.estack.PushVal(i)
  2052  	}
  2053  	vm.estack.PushVal(len(elements))
  2054  	runVM(t, vm)
  2055  	// check reference counter = 1+1+1024*2
  2056  	assert.Equal(t, 1+1+len(elements)*2, int(vm.refs))
  2057  	assert.Equal(t, 2, vm.estack.Len())
  2058  	m := vm.estack.Peek(0).value.(*stackitem.Map).Value().([]stackitem.MapElement)
  2059  	assert.Equal(t, len(elements), len(m))
  2060  	for i := 0; i < len(elements); i++ {
  2061  		k := m[i].Key.Value().(*big.Int)
  2062  		v := m[i].Value.Value().(*big.Int)
  2063  		assert.Equal(t, int64(elements[i]), k.Int64())
  2064  		assert.Equal(t, int64(elements[i])*2, v.Int64())
  2065  	}
  2066  	assert.Equal(t, int64(-1), vm.estack.Peek(1).BigInt().Int64())
  2067  }
  2068  
  2069  func TestPACKMAPBadKey(t *testing.T) {
  2070  	prog := makeProgram(opcode.PACKMAP)
  2071  	vm := load(prog)
  2072  	vm.estack.PushVal(1)
  2073  	vm.estack.PushItem(stackitem.NewBuffer([]byte{1}))
  2074  	vm.estack.PushVal(1)
  2075  	checkVMFailed(t, vm)
  2076  }
  2077  
  2078  func TestUNPACKBadNotArray(t *testing.T) {
  2079  	prog := makeProgram(opcode.UNPACK)
  2080  	runWithArgs(t, prog, nil, 1)
  2081  }
  2082  
  2083  func TestUNPACKGood(t *testing.T) {
  2084  	prog := makeProgram(opcode.UNPACK)
  2085  	elements := []int{55, 34, 42}
  2086  	vm := load(prog)
  2087  	// canary
  2088  	vm.estack.PushVal(1)
  2089  	vm.estack.PushVal(elements)
  2090  	runVM(t, vm)
  2091  	assert.Equal(t, 5, vm.estack.Len())
  2092  	assert.Equal(t, int64(len(elements)), vm.estack.Peek(0).BigInt().Int64())
  2093  	for k, v := range elements {
  2094  		assert.Equal(t, int64(v), vm.estack.Peek(k+1).BigInt().Int64())
  2095  	}
  2096  	assert.Equal(t, int64(1), vm.estack.Peek(len(elements)+1).BigInt().Int64())
  2097  }
  2098  
  2099  func TestREVERSEITEMS(t *testing.T) {
  2100  	prog := makeProgram(opcode.DUP, opcode.REVERSEITEMS)
  2101  	t.Run("InvalidItem", getTestFuncForVM(prog, nil, 1))
  2102  	t.Run("Buffer", getTestFuncForVM(prog, stackitem.NewBuffer([]byte{3, 2, 1}), stackitem.NewBuffer([]byte{1, 2, 3})))
  2103  }
  2104  
  2105  func testREVERSEITEMSIssue437(t *testing.T, i1 opcode.Opcode, t2 stackitem.Type, reversed bool) {
  2106  	prog := makeProgram(
  2107  		opcode.PUSH0, i1,
  2108  		opcode.DUP, opcode.PUSH1, opcode.APPEND,
  2109  		opcode.DUP, opcode.PUSH2, opcode.APPEND,
  2110  		opcode.DUP, opcode.CONVERT, opcode.Opcode(t2), opcode.REVERSEITEMS)
  2111  
  2112  	arr := make([]stackitem.Item, 2)
  2113  	if reversed {
  2114  		arr[0] = stackitem.Make(2)
  2115  		arr[1] = stackitem.Make(1)
  2116  	} else {
  2117  		arr[0] = stackitem.Make(1)
  2118  		arr[1] = stackitem.Make(2)
  2119  	}
  2120  
  2121  	if i1 == opcode.NEWARRAY {
  2122  		runWithArgs(t, prog, stackitem.NewArray(arr))
  2123  	} else {
  2124  		runWithArgs(t, prog, stackitem.NewStruct(arr))
  2125  	}
  2126  }
  2127  
  2128  func TestREVERSEITEMSIssue437(t *testing.T) {
  2129  	t.Run("Array+Array", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWARRAY, stackitem.ArrayT, true) })
  2130  	t.Run("Struct+Struct", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWSTRUCT, stackitem.StructT, true) })
  2131  	t.Run("Array+Struct", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWARRAY, stackitem.StructT, false) })
  2132  	t.Run("Struct+Array", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWSTRUCT, stackitem.ArrayT, false) })
  2133  }
  2134  
  2135  func TestREVERSEITEMSGoodOneElem(t *testing.T) {
  2136  	prog := makeProgram(opcode.DUP, opcode.REVERSEITEMS)
  2137  	elements := []int{22}
  2138  	vm := load(prog)
  2139  	vm.estack.PushVal(1)
  2140  	vm.estack.PushVal(elements)
  2141  	runVM(t, vm)
  2142  	assert.Equal(t, 2, vm.estack.Len())
  2143  	a := vm.estack.Peek(0).Array()
  2144  	assert.Equal(t, len(elements), len(a))
  2145  	e := a[0].Value().(*big.Int)
  2146  	assert.Equal(t, int64(elements[0]), e.Int64())
  2147  }
  2148  
  2149  func TestREVERSEITEMSGoodStruct(t *testing.T) {
  2150  	eodd := []int{22, 34, 42, 55, 81}
  2151  	even := []int{22, 34, 42, 55, 81, 99}
  2152  	eall := [][]int{eodd, even}
  2153  
  2154  	for _, elements := range eall {
  2155  		prog := makeProgram(opcode.DUP, opcode.REVERSEITEMS)
  2156  		vm := load(prog)
  2157  		vm.estack.PushVal(1)
  2158  
  2159  		arr := make([]stackitem.Item, len(elements))
  2160  		for i := range elements {
  2161  			arr[i] = stackitem.Make(elements[i])
  2162  		}
  2163  		vm.estack.Push(Element{value: stackitem.NewStruct(arr)})
  2164  
  2165  		runVM(t, vm)
  2166  		assert.Equal(t, 2, vm.estack.Len())
  2167  		a := vm.estack.Peek(0).Array()
  2168  		assert.Equal(t, len(elements), len(a))
  2169  		for k, v := range elements {
  2170  			e := a[len(a)-1-k].Value().(*big.Int)
  2171  			assert.Equal(t, int64(v), e.Int64())
  2172  		}
  2173  		assert.Equal(t, int64(1), vm.estack.Peek(1).BigInt().Int64())
  2174  	}
  2175  }
  2176  
  2177  func TestREVERSEITEMSGood(t *testing.T) {
  2178  	eodd := []int{22, 34, 42, 55, 81}
  2179  	even := []int{22, 34, 42, 55, 81, 99}
  2180  	eall := [][]int{eodd, even}
  2181  
  2182  	for _, elements := range eall {
  2183  		prog := makeProgram(opcode.DUP, opcode.REVERSEITEMS)
  2184  		vm := load(prog)
  2185  		vm.estack.PushVal(1)
  2186  		vm.estack.PushVal(elements)
  2187  		runVM(t, vm)
  2188  		assert.Equal(t, 2, vm.estack.Len())
  2189  		a := vm.estack.Peek(0).Array()
  2190  		assert.Equal(t, len(elements), len(a))
  2191  		for k, v := range elements {
  2192  			e := a[len(a)-1-k].Value().(*big.Int)
  2193  			assert.Equal(t, int64(v), e.Int64())
  2194  		}
  2195  		assert.Equal(t, int64(1), vm.estack.Peek(1).BigInt().Int64())
  2196  	}
  2197  }
  2198  
  2199  func TestREMOVE(t *testing.T) {
  2200  	prog := makeProgram(opcode.REMOVE)
  2201  	t.Run("NoArgument", getTestFuncForVM(prog, nil))
  2202  	t.Run("OneArgument", getTestFuncForVM(prog, nil, 1))
  2203  	t.Run("NotArray", getTestFuncForVM(prog, nil, 1, 1))
  2204  	t.Run("BadIndex", getTestFuncForVM(prog, nil, []int{22, 34, 42, 55, 81}, 10))
  2205  	t.Run("very big index", getTestFuncForVM(prog, nil, []int{22, 34, 42, 55, 81}, maxu64Plus(1)))
  2206  }
  2207  
  2208  func TestREMOVEGood(t *testing.T) {
  2209  	prog := makeProgram(opcode.DUP, opcode.PUSH2, opcode.REMOVE)
  2210  	elements := []int{22, 34, 42, 55, 81}
  2211  	reselements := []int{22, 34, 55, 81}
  2212  	vm := load(prog)
  2213  	vm.estack.PushVal(1)
  2214  	vm.estack.PushVal(elements)
  2215  	runVM(t, vm)
  2216  	assert.Equal(t, 2, vm.estack.Len())
  2217  	assert.Equal(t, stackitem.Make(reselements), vm.estack.Pop().value)
  2218  	assert.Equal(t, stackitem.Make(1), vm.estack.Pop().value)
  2219  }
  2220  
  2221  func TestREMOVEMap(t *testing.T) {
  2222  	prog := makeProgram(opcode.REMOVE, opcode.PUSH5, opcode.HASKEY)
  2223  	vm := load(prog)
  2224  
  2225  	m := stackitem.NewMap()
  2226  	m.Add(stackitem.Make(5), stackitem.Make(3))
  2227  	m.Add(stackitem.Make([]byte{0, 1}), stackitem.Make([]byte{2, 3}))
  2228  	vm.estack.Push(Element{value: m})
  2229  	vm.estack.Push(Element{value: m})
  2230  	vm.estack.PushVal(stackitem.Make(5))
  2231  
  2232  	runVM(t, vm)
  2233  	assert.Equal(t, 1, vm.estack.Len())
  2234  	assert.Equal(t, stackitem.Make(false), vm.estack.Pop().value)
  2235  }
  2236  
  2237  func testCLEARITEMS(t *testing.T, item stackitem.Item) {
  2238  	prog := makeProgram(opcode.DUP, opcode.DUP, opcode.CLEARITEMS, opcode.SIZE)
  2239  	v := load(prog)
  2240  	v.estack.PushVal(item)
  2241  	runVM(t, v)
  2242  	require.Equal(t, 2, v.estack.Len())
  2243  	require.EqualValues(t, 2, int(v.refs)) // empty collection + it's size
  2244  	require.EqualValues(t, 0, v.estack.Pop().BigInt().Int64())
  2245  }
  2246  
  2247  func TestCLEARITEMS(t *testing.T) {
  2248  	arr := []stackitem.Item{stackitem.NewBigInteger(big.NewInt(1)), stackitem.NewByteArray([]byte{1})}
  2249  	m := stackitem.NewMap()
  2250  	m.Add(stackitem.NewBigInteger(big.NewInt(1)), stackitem.NewByteArray([]byte{}))
  2251  	m.Add(stackitem.NewByteArray([]byte{42}), stackitem.NewBigInteger(big.NewInt(2)))
  2252  
  2253  	testCases := map[string]stackitem.Item{
  2254  		"empty Array":   stackitem.NewArray([]stackitem.Item{}),
  2255  		"filled Array":  stackitem.NewArray(arr),
  2256  		"empty Struct":  stackitem.NewStruct([]stackitem.Item{}),
  2257  		"filled Struct": stackitem.NewStruct(arr),
  2258  		"empty Map":     stackitem.NewMap(),
  2259  		"filled Map":    m,
  2260  	}
  2261  
  2262  	for name, item := range testCases {
  2263  		t.Run(name, func(t *testing.T) { testCLEARITEMS(t, item) })
  2264  	}
  2265  
  2266  	t.Run("Integer", func(t *testing.T) {
  2267  		prog := makeProgram(opcode.CLEARITEMS)
  2268  		runWithArgs(t, prog, nil, 1)
  2269  	})
  2270  }
  2271  
  2272  func TestPOPITEM(t *testing.T) {
  2273  	testPOPITEM := func(t *testing.T, item, elem, arr any) {
  2274  		prog := makeProgram(opcode.DUP, opcode.POPITEM)
  2275  		v := load(prog)
  2276  		v.estack.PushVal(item)
  2277  
  2278  		runVM(t, v)
  2279  		require.EqualValues(t, stackitem.Make(elem), v.estack.Pop().Item())
  2280  		require.EqualValues(t, stackitem.Make(arr), v.estack.Pop().Item())
  2281  	}
  2282  
  2283  	elems := []stackitem.Item{stackitem.Make(11), stackitem.Make(31)}
  2284  	t.Run("Array", func(t *testing.T) {
  2285  		testPOPITEM(t, stackitem.NewArray(elems), 31, elems[:1])
  2286  	})
  2287  	t.Run("Struct", func(t *testing.T) {
  2288  		testPOPITEM(t, stackitem.NewStruct(elems), 31, elems[:1])
  2289  	})
  2290  	t.Run("0-length array", func(t *testing.T) {
  2291  		prog := makeProgram(opcode.NEWARRAY0, opcode.POPITEM)
  2292  		v := load(prog)
  2293  		checkVMFailed(t, v)
  2294  	})
  2295  	t.Run("primitive type", func(t *testing.T) {
  2296  		prog := makeProgram(opcode.PUSH4, opcode.POPITEM)
  2297  		v := load(prog)
  2298  		checkVMFailed(t, v)
  2299  	})
  2300  }
  2301  
  2302  func TestSWAPGood(t *testing.T) {
  2303  	prog := makeProgram(opcode.SWAP)
  2304  	vm := load(prog)
  2305  	vm.estack.PushVal(2)
  2306  	vm.estack.PushVal(4)
  2307  	runVM(t, vm)
  2308  	assert.Equal(t, 2, vm.estack.Len())
  2309  	assert.Equal(t, int64(2), vm.estack.Pop().BigInt().Int64())
  2310  	assert.Equal(t, int64(4), vm.estack.Pop().BigInt().Int64())
  2311  }
  2312  
  2313  func TestSWAP(t *testing.T) {
  2314  	prog := makeProgram(opcode.SWAP)
  2315  	t.Run("EmptyStack", getTestFuncForVM(prog, nil))
  2316  	t.Run("SmallStack", getTestFuncForVM(prog, nil, 4))
  2317  }
  2318  
  2319  func TestDupInt(t *testing.T) {
  2320  	prog := makeProgram(opcode.DUP, opcode.ABS)
  2321  	vm := load(prog)
  2322  	vm.estack.PushVal(-1)
  2323  	runVM(t, vm)
  2324  	assert.Equal(t, 2, vm.estack.Len())
  2325  	assert.Equal(t, int64(1), vm.estack.Pop().BigInt().Int64())
  2326  	assert.Equal(t, int64(-1), vm.estack.Pop().BigInt().Int64())
  2327  }
  2328  
  2329  func TestNegateCopy(t *testing.T) {
  2330  	prog := makeProgram(opcode.NEGATE)
  2331  	v := load(prog)
  2332  	bi := stackitem.Make(-1)
  2333  	v.estack.PushVal(bi)
  2334  	v.estack.PushVal(bi)
  2335  	runVM(t, v)
  2336  	assert.Equal(t, 2, v.estack.Len())
  2337  	assert.Equal(t, int64(1), v.estack.Pop().BigInt().Int64())
  2338  	assert.Equal(t, int64(-1), v.estack.Pop().BigInt().Int64())
  2339  }
  2340  
  2341  func TestDupByteArray(t *testing.T) {
  2342  	prog := makeProgram(opcode.PUSHDATA1, 2, 1, 0,
  2343  		opcode.DUP,
  2344  		opcode.PUSH1,
  2345  		opcode.LEFT,
  2346  		opcode.PUSHDATA1, 1, 2,
  2347  		opcode.CAT)
  2348  	vm := load(prog)
  2349  	runVM(t, vm)
  2350  	assert.Equal(t, 2, vm.estack.Len())
  2351  	assert.Equal(t, []byte{0x01, 0x02}, vm.estack.Pop().Bytes())
  2352  	assert.Equal(t, []byte{0x01, 0x00}, vm.estack.Pop().Bytes())
  2353  }
  2354  
  2355  func TestDupBool(t *testing.T) {
  2356  	prog := makeProgram(opcode.PUSH0, opcode.NOT,
  2357  		opcode.DUP,
  2358  		opcode.PUSH1, opcode.NOT,
  2359  		opcode.BOOLAND)
  2360  	vm := load(prog)
  2361  	runVM(t, vm)
  2362  	assert.Equal(t, 2, vm.estack.Len())
  2363  	assert.Equal(t, false, vm.estack.Pop().Bool())
  2364  	assert.Equal(t, true, vm.estack.Pop().Bool())
  2365  }
  2366  
  2367  var opcodesTestCases = map[opcode.Opcode][]struct {
  2368  	name     string
  2369  	args     []any
  2370  	expected any
  2371  	actual   func(vm *VM) any
  2372  }{
  2373  	opcode.AND: {
  2374  		{
  2375  			name:     "1_1",
  2376  			args:     []any{1, 1},
  2377  			expected: int64(1),
  2378  			actual: func(vm *VM) any {
  2379  				return vm.estack.Pop().BigInt().Int64()
  2380  			},
  2381  		},
  2382  		{
  2383  			name:     "1_0",
  2384  			args:     []any{1, 0},
  2385  			expected: int64(0),
  2386  			actual: func(vm *VM) any {
  2387  				return vm.estack.Pop().BigInt().Int64()
  2388  			},
  2389  		},
  2390  		{
  2391  			name:     "0_1",
  2392  			args:     []any{0, 1},
  2393  			expected: int64(0),
  2394  			actual: func(vm *VM) any {
  2395  				return vm.estack.Pop().BigInt().Int64()
  2396  			},
  2397  		},
  2398  		{
  2399  			name:     "0_0",
  2400  			args:     []any{0, 0},
  2401  			expected: int64(0),
  2402  			actual: func(vm *VM) any {
  2403  				return vm.estack.Pop().BigInt().Int64()
  2404  			},
  2405  		},
  2406  		{
  2407  			name: "random_values",
  2408  			args: []any{
  2409  				[]byte{1, 0, 1, 0, 1, 0, 1, 1},
  2410  				[]byte{1, 1, 0, 0, 0, 0, 0, 1},
  2411  			},
  2412  			expected: []byte{1, 0, 0, 0, 0, 0, 0, 1},
  2413  			actual: func(vm *VM) any {
  2414  				return vm.estack.Pop().Bytes()
  2415  			},
  2416  		},
  2417  	},
  2418  	opcode.OR: {
  2419  		{
  2420  			name:     "1_1",
  2421  			args:     []any{1, 1},
  2422  			expected: int64(1),
  2423  			actual: func(vm *VM) any {
  2424  				return vm.estack.Pop().BigInt().Int64()
  2425  			},
  2426  		},
  2427  		{
  2428  			name:     "0_0",
  2429  			args:     []any{0, 0},
  2430  			expected: int64(0),
  2431  			actual: func(vm *VM) any {
  2432  				return vm.estack.Pop().BigInt().Int64()
  2433  			},
  2434  		},
  2435  		{
  2436  			name:     "0_1",
  2437  			args:     []any{0, 1},
  2438  			expected: int64(1),
  2439  			actual: func(vm *VM) any {
  2440  				return vm.estack.Pop().BigInt().Int64()
  2441  			},
  2442  		},
  2443  		{
  2444  			name:     "1_0",
  2445  			args:     []any{1, 0},
  2446  			expected: int64(1),
  2447  			actual: func(vm *VM) any {
  2448  				return vm.estack.Pop().BigInt().Int64()
  2449  			},
  2450  		},
  2451  		{
  2452  			name: "random_values",
  2453  			args: []any{
  2454  				[]byte{1, 0, 1, 0, 1, 0, 1, 1},
  2455  				[]byte{1, 1, 0, 0, 0, 0, 0, 1},
  2456  			},
  2457  			expected: []byte{1, 1, 1, 0, 1, 0, 1, 1},
  2458  			actual: func(vm *VM) any {
  2459  				return vm.estack.Pop().Bytes()
  2460  			},
  2461  		},
  2462  	},
  2463  	opcode.XOR: {
  2464  		{
  2465  			name:     "1_1",
  2466  			args:     []any{1, 1},
  2467  			expected: int64(0),
  2468  			actual: func(vm *VM) any {
  2469  				return vm.estack.Pop().BigInt().Int64()
  2470  			},
  2471  		},
  2472  		{
  2473  			name:     "0_0",
  2474  			args:     []any{0, 0},
  2475  			expected: int64(0),
  2476  			actual: func(vm *VM) any {
  2477  				return vm.estack.Pop().BigInt().Int64()
  2478  			},
  2479  		},
  2480  		{
  2481  			name:     "0_1",
  2482  			args:     []any{0, 1},
  2483  			expected: int64(1),
  2484  			actual: func(vm *VM) any {
  2485  				return vm.estack.Pop().BigInt().Int64()
  2486  			},
  2487  		},
  2488  		{
  2489  			name:     "1_0",
  2490  			args:     []any{1, 0},
  2491  			expected: int64(1),
  2492  			actual: func(vm *VM) any {
  2493  				return vm.estack.Pop().BigInt().Int64()
  2494  			},
  2495  		},
  2496  		{
  2497  			name: "random_values",
  2498  			args: []any{
  2499  				[]byte{1, 0, 1, 0, 1, 0, 1, 1},
  2500  				[]byte{1, 1, 0, 0, 0, 0, 0, 1},
  2501  			},
  2502  			expected: []byte{0, 1, 1, 0, 1, 0, 1},
  2503  			actual: func(vm *VM) any {
  2504  				return vm.estack.Pop().Bytes()
  2505  			},
  2506  		},
  2507  	},
  2508  	opcode.BOOLOR: {
  2509  		{
  2510  			name:     "1_1",
  2511  			args:     []any{true, true},
  2512  			expected: true,
  2513  			actual: func(vm *VM) any {
  2514  				return vm.estack.Pop().Bool()
  2515  			},
  2516  		},
  2517  		{
  2518  			name:     "0_0",
  2519  			args:     []any{false, false},
  2520  			expected: false,
  2521  			actual: func(vm *VM) any {
  2522  				return vm.estack.Pop().Bool()
  2523  			},
  2524  		},
  2525  		{
  2526  			name:     "0_1",
  2527  			args:     []any{false, true},
  2528  			expected: true,
  2529  			actual: func(vm *VM) any {
  2530  				return vm.estack.Pop().Bool()
  2531  			},
  2532  		},
  2533  		{
  2534  			name:     "1_0",
  2535  			args:     []any{true, false},
  2536  			expected: true,
  2537  			actual: func(vm *VM) any {
  2538  				return vm.estack.Pop().Bool()
  2539  			},
  2540  		},
  2541  	},
  2542  	opcode.MIN: {
  2543  		{
  2544  			name:     "3_5",
  2545  			args:     []any{3, 5},
  2546  			expected: int64(3),
  2547  			actual: func(vm *VM) any {
  2548  				return vm.estack.Pop().BigInt().Int64()
  2549  			},
  2550  		},
  2551  		{
  2552  			name:     "5_3",
  2553  			args:     []any{5, 3},
  2554  			expected: int64(3),
  2555  			actual: func(vm *VM) any {
  2556  				return vm.estack.Pop().BigInt().Int64()
  2557  			},
  2558  		},
  2559  		{
  2560  			name:     "3_3",
  2561  			args:     []any{3, 3},
  2562  			expected: int64(3),
  2563  			actual: func(vm *VM) any {
  2564  				return vm.estack.Pop().BigInt().Int64()
  2565  			},
  2566  		},
  2567  	},
  2568  	opcode.MAX: {
  2569  		{
  2570  			name:     "3_5",
  2571  			args:     []any{3, 5},
  2572  			expected: int64(5),
  2573  			actual: func(vm *VM) any {
  2574  				return vm.estack.Pop().BigInt().Int64()
  2575  			},
  2576  		},
  2577  		{
  2578  			name:     "5_3",
  2579  			args:     []any{5, 3},
  2580  			expected: int64(5),
  2581  			actual: func(vm *VM) any {
  2582  				return vm.estack.Pop().BigInt().Int64()
  2583  			},
  2584  		},
  2585  		{
  2586  			name:     "3_3",
  2587  			args:     []any{3, 3},
  2588  			expected: int64(3),
  2589  			actual: func(vm *VM) any {
  2590  				return vm.estack.Pop().BigInt().Int64()
  2591  			},
  2592  		},
  2593  	},
  2594  	opcode.WITHIN: {
  2595  		{
  2596  			name:     "within",
  2597  			args:     []any{4, 3, 5},
  2598  			expected: true,
  2599  			actual: func(vm *VM) any {
  2600  				return vm.estack.Pop().Bool()
  2601  			},
  2602  		},
  2603  		{
  2604  			name:     "less",
  2605  			args:     []any{2, 3, 5},
  2606  			expected: false,
  2607  			actual: func(vm *VM) any {
  2608  				return vm.estack.Pop().Bool()
  2609  			},
  2610  		},
  2611  		{
  2612  			name:     "more",
  2613  			args:     []any{6, 3, 5},
  2614  			expected: false,
  2615  			actual: func(vm *VM) any {
  2616  				return vm.estack.Pop().Bool()
  2617  			},
  2618  		},
  2619  	},
  2620  	opcode.NEGATE: {
  2621  		{
  2622  			name:     "3",
  2623  			args:     []any{3},
  2624  			expected: int64(-3),
  2625  			actual: func(vm *VM) any {
  2626  				return vm.estack.Pop().BigInt().Int64()
  2627  			},
  2628  		},
  2629  		{
  2630  			name:     "-3",
  2631  			args:     []any{-3},
  2632  			expected: int64(3),
  2633  			actual: func(vm *VM) any {
  2634  				return vm.estack.Pop().BigInt().Int64()
  2635  			},
  2636  		},
  2637  		{
  2638  			name:     "0",
  2639  			args:     []any{0},
  2640  			expected: int64(0),
  2641  			actual: func(vm *VM) any {
  2642  				return vm.estack.Pop().BigInt().Int64()
  2643  			},
  2644  		},
  2645  	},
  2646  }
  2647  
  2648  func TestBitAndNumericOpcodes(t *testing.T) {
  2649  	for code, opcodeTestCases := range opcodesTestCases {
  2650  		t.Run(code.String(), func(t *testing.T) {
  2651  			for _, testCase := range opcodeTestCases {
  2652  				prog := makeProgram(code)
  2653  				vm := load(prog)
  2654  				t.Run(testCase.name, func(t *testing.T) {
  2655  					for _, arg := range testCase.args {
  2656  						vm.estack.PushVal(arg)
  2657  					}
  2658  					runVM(t, vm)
  2659  					assert.Equal(t, testCase.expected, testCase.actual(vm))
  2660  				})
  2661  			}
  2662  		})
  2663  	}
  2664  }
  2665  
  2666  func TestSLOTOpcodes(t *testing.T) {
  2667  	t.Run("Fail", func(t *testing.T) {
  2668  		t.Run("EmptyStatic", getTestFuncForVM(makeProgram(opcode.INITSSLOT, 0), nil))
  2669  		t.Run("EmptyLocal", getTestFuncForVM(makeProgram(opcode.INITSLOT, 0, 0), nil))
  2670  		t.Run("NotEnoughArguments", getTestFuncForVM(makeProgram(opcode.INITSSLOT, 0, 2), nil, 1))
  2671  		t.Run("DoubleStatic", getTestFuncForVM(makeProgram(opcode.INITSSLOT, 1, opcode.INITSSLOT, 1), nil))
  2672  		t.Run("DoubleLocal", getTestFuncForVM(makeProgram(opcode.INITSLOT, 1, 0, opcode.INITSLOT, 1, 0), nil))
  2673  		t.Run("DoubleArgument", getTestFuncForVM(makeProgram(opcode.INITSLOT, 0, 1, opcode.INITSLOT, 0, 1), nil, 1, 2))
  2674  		t.Run("LoadBigStatic", getTestFuncForVM(makeProgram(opcode.INITSSLOT, 2, opcode.LDSFLD2), nil))
  2675  		t.Run("LoadBigLocal", getTestFuncForVM(makeProgram(opcode.INITSLOT, 2, 2, opcode.LDLOC2), nil, 1, 2))
  2676  		t.Run("LoadBigArgument", getTestFuncForVM(makeProgram(opcode.INITSLOT, 2, 2, opcode.LDARG2), nil, 1, 2))
  2677  		t.Run("StoreBigStatic", getTestFuncForVM(makeProgram(opcode.INITSSLOT, 2, opcode.STSFLD2), nil, 0))
  2678  		t.Run("StoreBigLocal", getTestFuncForVM(makeProgram(opcode.INITSLOT, 2, 2, opcode.STLOC2), nil, 0, 1, 2))
  2679  		t.Run("StoreBigArgument", getTestFuncForVM(makeProgram(opcode.INITSLOT, 2, 2, opcode.STARG2), nil, 0, 1, 2))
  2680  	})
  2681  
  2682  	t.Run("Default", func(t *testing.T) {
  2683  		t.Run("DefaultStatic", getTestFuncForVM(makeProgram(opcode.INITSSLOT, 2, opcode.LDSFLD1), stackitem.Null{}))
  2684  		t.Run("DefaultLocal", getTestFuncForVM(makeProgram(opcode.INITSLOT, 2, 0, opcode.LDLOC1), stackitem.Null{}))
  2685  		t.Run("DefaultArgument", getTestFuncForVM(makeProgram(opcode.INITSLOT, 0, 2, opcode.LDARG1), 2, 2, 1))
  2686  	})
  2687  
  2688  	t.Run("Set/Get", func(t *testing.T) {
  2689  		t.Run("FailCrossLoads", func(t *testing.T) {
  2690  			t.Run("Static/Local", getTestFuncForVM(makeProgram(opcode.INITSSLOT, 2, opcode.LDLOC1), nil))
  2691  			t.Run("Static/Argument", getTestFuncForVM(makeProgram(opcode.INITSSLOT, 2, opcode.LDARG1), nil))
  2692  			t.Run("Local/Argument", getTestFuncForVM(makeProgram(opcode.INITSLOT, 0, 2, opcode.LDLOC1), nil))
  2693  			t.Run("Argument/Local", getTestFuncForVM(makeProgram(opcode.INITSLOT, 2, 0, opcode.LDARG1), nil))
  2694  		})
  2695  
  2696  		t.Run("Static", getTestFuncForVM(makeProgram(opcode.INITSSLOT, 8, opcode.STSFLD, 7, opcode.LDSFLD, 7), 42, 42))
  2697  		t.Run("Local", getTestFuncForVM(makeProgram(opcode.INITSLOT, 8, 0, opcode.STLOC, 7, opcode.LDLOC, 7), 42, 42))
  2698  		t.Run("Argument", getTestFuncForVM(makeProgram(opcode.INITSLOT, 0, 2, opcode.STARG, 1, opcode.LDARG, 1), 42, 42, 1, 2))
  2699  	})
  2700  
  2701  	t.Run("InitStaticSlotInMethod", func(t *testing.T) {
  2702  		prog := makeProgram(
  2703  			opcode.CALL, 4, opcode.LDSFLD0, opcode.RET,
  2704  			opcode.INITSSLOT, 1, opcode.PUSH12, opcode.STSFLD0, opcode.RET,
  2705  		)
  2706  		runWithArgs(t, prog, 12)
  2707  	})
  2708  }
  2709  
  2710  func TestNestedStructClone(t *testing.T) {
  2711  	progs := []string{
  2712  		// VALUES for deeply nested structs, see neo-project/neo#2534.
  2713  		"5601c501fe0360589d604a12c0db415824f7cd45",
  2714  		// APPEND of deeply nested struct to empty array.
  2715  		"5601c2c501fe0360589d604a12c0db415824f7cf45",
  2716  		// VALUES for map with deeply nested struct.
  2717  		"5601c84a11c501fe0060589d604a12c0db415824f7d0cd45",
  2718  		// VALUES for a lot of not-so-deep nested structs.
  2719  		"5601c5000a60589d604a12c0db415824f701fe03504a519d4a102afa01ff03c0cd45",
  2720  	}
  2721  	for _, h := range progs {
  2722  		prog, err := hex.DecodeString(h)
  2723  		require.NoError(t, err)
  2724  		vm := load(prog)
  2725  		checkVMFailed(t, vm)
  2726  	}
  2727  }
  2728  
  2729  func TestNestedStructEquals(t *testing.T) {
  2730  	h := "560112c501fe0160589d604a12c0db415824f7509d4a102aec4597" // See neo-project/neo-vm#426.
  2731  	prog, err := hex.DecodeString(h)
  2732  	require.NoError(t, err)
  2733  	vm := load(prog)
  2734  	checkVMFailed(t, vm)
  2735  }
  2736  
  2737  func TestRemoveReferrer(t *testing.T) {
  2738  	h := "560110c34a10c36058cf4540" // #2501
  2739  	prog, err := hex.DecodeString(h)
  2740  	require.NoError(t, err)
  2741  	vm := load(prog)
  2742  	require.NoError(t, vm.StepInto()) // INITSSLOT
  2743  	assert.Equal(t, 1, int(vm.refs))
  2744  	require.NoError(t, vm.StepInto()) // PUSH0
  2745  	assert.Equal(t, 2, int(vm.refs))
  2746  	require.NoError(t, vm.StepInto()) // NEWARRAY
  2747  	assert.Equal(t, 2, int(vm.refs))
  2748  	require.NoError(t, vm.StepInto()) // DUP
  2749  	assert.Equal(t, 3, int(vm.refs))
  2750  	require.NoError(t, vm.StepInto()) // PUSH0
  2751  	assert.Equal(t, 4, int(vm.refs))
  2752  	require.NoError(t, vm.StepInto()) // NEWARRAY
  2753  	assert.Equal(t, 4, int(vm.refs))
  2754  	require.NoError(t, vm.StepInto()) // STSFLD0
  2755  	assert.Equal(t, 3, int(vm.refs))
  2756  	require.NoError(t, vm.StepInto()) // LDSFLD0
  2757  	assert.Equal(t, 4, int(vm.refs))
  2758  	require.NoError(t, vm.StepInto()) // APPEND
  2759  	assert.Equal(t, 3, int(vm.refs))
  2760  	require.NoError(t, vm.StepInto()) // DROP
  2761  	assert.Equal(t, 1, int(vm.refs))
  2762  	require.NoError(t, vm.StepInto()) // RET
  2763  	assert.Equal(t, 0, int(vm.refs))
  2764  }
  2765  
  2766  func TestUninitializedSyscallHandler(t *testing.T) {
  2767  	v := newTestVM()
  2768  	v.Reset(trigger.Application) // Reset SyscallHandler.
  2769  	id := make([]byte, 4)
  2770  	binary.LittleEndian.PutUint32(id, interopnames.ToID([]byte(interopnames.SystemRuntimeGasLeft)))
  2771  	script := append([]byte{byte(opcode.SYSCALL)}, id...)
  2772  	v.LoadScript(script)
  2773  	err := v.Run()
  2774  	require.Error(t, err)
  2775  	require.True(t, strings.Contains(err.Error(), "SyscallHandler is not initialized"), err.Error())
  2776  	assert.Equal(t, true, v.HasFailed())
  2777  }
  2778  
  2779  func makeProgram(opcodes ...opcode.Opcode) []byte {
  2780  	prog := make([]byte, len(opcodes)+1) // RET
  2781  	for i := 0; i < len(opcodes); i++ {
  2782  		prog[i] = byte(opcodes[i])
  2783  	}
  2784  	prog[len(prog)-1] = byte(opcode.RET)
  2785  	return prog
  2786  }
  2787  
  2788  func load(prog []byte) *VM {
  2789  	vm := newTestVM()
  2790  	if len(prog) != 0 {
  2791  		vm.LoadScript(prog)
  2792  	}
  2793  	return vm
  2794  }
  2795  
  2796  func randomBytes(n int) []byte {
  2797  	const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  2798  	b := make([]byte, n)
  2799  	for i := range b {
  2800  		b[i] = charset[rand.Intn(len(charset))]
  2801  	}
  2802  	return b
  2803  }
  2804  
  2805  func newTestVM() *VM {
  2806  	v := New()
  2807  	v.GasLimit = -1
  2808  	return v
  2809  }