github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/interop/runtime/util_test.go (about)

     1  package runtime
     2  
     3  import (
     4  	"encoding/hex"
     5  	"testing"
     6  
     7  	"github.com/nspcc-dev/neo-go/internal/random"
     8  	"github.com/nspcc-dev/neo-go/pkg/core/interop"
     9  	"github.com/nspcc-dev/neo-go/pkg/core/state"
    10  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
    11  	"github.com/nspcc-dev/neo-go/pkg/util"
    12  	"github.com/nspcc-dev/neo-go/pkg/vm"
    13  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func TestGasLeft(t *testing.T) {
    18  	t.Run("no limit", func(t *testing.T) {
    19  		ic := &interop.Context{VM: vm.New()}
    20  		ic.VM.GasLimit = -1
    21  		ic.VM.AddGas(58)
    22  		require.NoError(t, GasLeft(ic))
    23  		checkStack(t, ic.VM, -1)
    24  	})
    25  	t.Run("with limit", func(t *testing.T) {
    26  		ic := &interop.Context{VM: vm.New()}
    27  		ic.VM.GasLimit = 100
    28  		ic.VM.AddGas(58)
    29  		require.NoError(t, GasLeft(ic))
    30  		checkStack(t, ic.VM, 42)
    31  	})
    32  }
    33  
    34  func TestRuntimeGetNotifications(t *testing.T) {
    35  	v := vm.New()
    36  	ic := &interop.Context{
    37  		VM: v,
    38  		Notifications: []state.NotificationEvent{
    39  			{ScriptHash: util.Uint160{1}, Name: "Event1", Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte{11})})},
    40  			{ScriptHash: util.Uint160{2}, Name: "Event2", Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte{22})})},
    41  			{ScriptHash: util.Uint160{1}, Name: "Event1", Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte{33})})},
    42  		},
    43  	}
    44  
    45  	t.Run("NoFilter", func(t *testing.T) {
    46  		v.Estack().PushVal(stackitem.Null{})
    47  		require.NoError(t, GetNotifications(ic))
    48  
    49  		arr := v.Estack().Pop().Array()
    50  		require.Equal(t, len(ic.Notifications), len(arr))
    51  		for i := range arr {
    52  			elem := arr[i].Value().([]stackitem.Item)
    53  			require.Equal(t, ic.Notifications[i].ScriptHash.BytesBE(), elem[0].Value())
    54  			name, err := stackitem.ToString(elem[1])
    55  			require.NoError(t, err)
    56  			require.Equal(t, ic.Notifications[i].Name, name)
    57  			ic.Notifications[i].Item.MarkAsReadOnly() // tiny hack for test to be able to compare object references.
    58  			require.Equal(t, ic.Notifications[i].Item, elem[2])
    59  		}
    60  	})
    61  
    62  	t.Run("WithFilter", func(t *testing.T) {
    63  		h := util.Uint160{2}.BytesBE()
    64  		v.Estack().PushVal(h)
    65  		require.NoError(t, GetNotifications(ic))
    66  
    67  		arr := v.Estack().Pop().Array()
    68  		require.Equal(t, 1, len(arr))
    69  		elem := arr[0].Value().([]stackitem.Item)
    70  		require.Equal(t, h, elem[0].Value())
    71  		name, err := stackitem.ToString(elem[1])
    72  		require.NoError(t, err)
    73  		require.Equal(t, ic.Notifications[1].Name, name)
    74  		require.Equal(t, ic.Notifications[1].Item, elem[2])
    75  	})
    76  
    77  	t.Run("Bad", func(t *testing.T) {
    78  		t.Run("not bytes", func(t *testing.T) {
    79  			v.Estack().PushVal(stackitem.NewInterop(util.Uint160{1}))
    80  			require.Error(t, GetNotifications(ic))
    81  		})
    82  		t.Run("not uint160", func(t *testing.T) {
    83  			v.Estack().PushVal([]byte{1, 2, 3})
    84  			require.Error(t, GetNotifications(ic))
    85  		})
    86  		t.Run("too many notifications", func(t *testing.T) {
    87  			for i := 0; i <= vm.MaxStackSize; i++ {
    88  				ic.Notifications = append(ic.Notifications, state.NotificationEvent{
    89  					ScriptHash: util.Uint160{3},
    90  					Name:       "Event3",
    91  					Item:       stackitem.NewArray(nil),
    92  				})
    93  			}
    94  			v.Estack().PushVal(stackitem.Null{})
    95  			require.Error(t, GetNotifications(ic))
    96  		})
    97  	})
    98  }
    99  
   100  func TestRuntimeGetInvocationCounter(t *testing.T) {
   101  	ic := &interop.Context{VM: vm.New(), Invocations: make(map[util.Uint160]int)}
   102  	h := random.Uint160()
   103  	ic.Invocations[h] = 42
   104  
   105  	t.Run("No invocations", func(t *testing.T) {
   106  		h1 := h
   107  		h1[0] ^= 0xFF
   108  		ic.VM.LoadScriptWithHash([]byte{1}, h1, callflag.NoneFlag)
   109  		// do not return an error in this case.
   110  		require.NoError(t, GetInvocationCounter(ic))
   111  		checkStack(t, ic.VM, 1)
   112  	})
   113  	t.Run("NonZero", func(t *testing.T) {
   114  		ic.VM.LoadScriptWithHash([]byte{1}, h, callflag.NoneFlag)
   115  		require.NoError(t, GetInvocationCounter(ic))
   116  		checkStack(t, ic.VM, 42)
   117  	})
   118  }
   119  
   120  // Test compatibility with C# implementation.
   121  // https://github.com/neo-project/neo/blob/master/tests/neo.UnitTests/Cryptography/UT_Murmur128.cs
   122  func TestMurmurCompat(t *testing.T) {
   123  	res := murmur128([]byte("hello"), 123)
   124  	require.Equal(t, "0bc59d0ad25fde2982ed65af61227a0e", hex.EncodeToString(res))
   125  
   126  	res = murmur128([]byte("world"), 123)
   127  	require.Equal(t, "3d3810fed480472bd214a14023bb407f", hex.EncodeToString(res))
   128  
   129  	res = murmur128([]byte("hello world"), 123)
   130  	require.Equal(t, "e0a0632d4f51302c55e3b3e48d28795d", hex.EncodeToString(res))
   131  
   132  	bs, _ := hex.DecodeString("718f952132679baa9c5c2aa0d329fd2a")
   133  	res = murmur128(bs, 123)
   134  	require.Equal(t, "9b4aa747ff0cf4e41b3d96251551c8ae", hex.EncodeToString(res))
   135  }