github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/state/notification_event_test.go (about) 1 package state 2 3 import ( 4 "encoding/json" 5 "testing" 6 7 "github.com/nspcc-dev/neo-go/internal/random" 8 "github.com/nspcc-dev/neo-go/internal/testserdes" 9 "github.com/nspcc-dev/neo-go/pkg/io" 10 "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" 11 "github.com/nspcc-dev/neo-go/pkg/util" 12 "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" 13 "github.com/nspcc-dev/neo-go/pkg/vm/vmstate" 14 "github.com/stretchr/testify/require" 15 ) 16 17 func BenchmarkAppExecResult_EncodeBinary(b *testing.B) { 18 aer := &AppExecResult{ 19 Container: random.Uint256(), 20 Execution: Execution{ 21 Trigger: trigger.Application, 22 VMState: vmstate.Halt, 23 GasConsumed: 12345, 24 Stack: []stackitem.Item{}, 25 Events: []NotificationEvent{{ 26 ScriptHash: random.Uint160(), 27 Name: "Event", 28 Item: stackitem.NewArray([]stackitem.Item{stackitem.NewBool(true)}), 29 }}, 30 }, 31 } 32 33 w := io.NewBufBinWriter() 34 b.ReportAllocs() 35 b.ResetTimer() 36 for i := 0; i < b.N; i++ { 37 w.Reset() 38 aer.EncodeBinary(w.BinWriter) 39 } 40 } 41 42 func TestEncodeDecodeNotificationEvent(t *testing.T) { 43 event := &NotificationEvent{ 44 ScriptHash: random.Uint160(), 45 Name: "Event", 46 Item: stackitem.NewArray([]stackitem.Item{stackitem.NewBool(true)}), 47 } 48 49 testserdes.EncodeDecodeBinary(t, event, new(NotificationEvent)) 50 } 51 52 func TestEncodeDecodeAppExecResult(t *testing.T) { 53 newAer := func() *AppExecResult { 54 return &AppExecResult{ 55 Container: random.Uint256(), 56 Execution: Execution{ 57 Trigger: 1, 58 VMState: vmstate.Halt, 59 GasConsumed: 10, 60 Stack: []stackitem.Item{stackitem.NewBool(true)}, 61 Events: []NotificationEvent{}, 62 }, 63 } 64 } 65 t.Run("halt", func(t *testing.T) { 66 appExecResult := newAer() 67 appExecResult.VMState = vmstate.Halt 68 testserdes.EncodeDecodeBinary(t, appExecResult, new(AppExecResult)) 69 }) 70 t.Run("fault", func(t *testing.T) { 71 appExecResult := newAer() 72 appExecResult.VMState = vmstate.Fault 73 testserdes.EncodeDecodeBinary(t, appExecResult, new(AppExecResult)) 74 }) 75 t.Run("with interop", func(t *testing.T) { 76 appExecResult := newAer() 77 appExecResult.Stack = []stackitem.Item{stackitem.NewInterop(nil)} 78 testserdes.EncodeDecodeBinary(t, appExecResult, new(AppExecResult)) 79 }) 80 t.Run("recursive reference", func(t *testing.T) { 81 var arr = stackitem.NewArray(nil) 82 arr.Append(arr) 83 appExecResult := newAer() 84 appExecResult.Stack = []stackitem.Item{arr, stackitem.NewBool(true), stackitem.NewInterop(123)} 85 86 bs, err := testserdes.EncodeBinary(appExecResult) 87 require.NoError(t, err) 88 actual := new(AppExecResult) 89 require.NoError(t, testserdes.DecodeBinary(bs, actual)) 90 require.Equal(t, 3, len(actual.Stack)) 91 require.Nil(t, actual.Stack[0]) 92 require.Equal(t, true, actual.Stack[1].Value()) 93 require.Equal(t, stackitem.InteropT, actual.Stack[2].Type()) 94 95 bs1, err := testserdes.EncodeBinary(actual) 96 require.NoError(t, err) 97 require.Equal(t, bs, bs1) 98 }) 99 t.Run("invalid item type", func(t *testing.T) { 100 aer := newAer() 101 w := io.NewBufBinWriter() 102 w.WriteBytes(aer.Container[:]) 103 w.WriteB(byte(aer.Trigger)) 104 w.WriteB(byte(aer.VMState)) 105 w.WriteU64LE(uint64(aer.GasConsumed)) 106 stackitem.EncodeBinary(stackitem.NewBool(true), w.BinWriter) 107 require.NoError(t, w.Err) 108 require.Error(t, testserdes.DecodeBinary(w.Bytes(), new(AppExecResult))) 109 }) 110 } 111 112 func TestMarshalUnmarshalJSONNotificationEvent(t *testing.T) { 113 t.Run("positive", func(t *testing.T) { 114 ne := &NotificationEvent{ 115 ScriptHash: random.Uint160(), 116 Name: "my_ne", 117 Item: stackitem.NewArray([]stackitem.Item{ 118 stackitem.NewBool(true), 119 }), 120 } 121 testserdes.MarshalUnmarshalJSON(t, ne, new(NotificationEvent)) 122 }) 123 124 t.Run("MarshalJSON recursive reference", func(t *testing.T) { 125 i := make([]stackitem.Item, 1) 126 recursive := stackitem.NewArray(i) 127 i[0] = recursive 128 ne := &NotificationEvent{ 129 Item: recursive, 130 } 131 _, err := json.Marshal(ne) 132 require.NoError(t, err) 133 }) 134 135 t.Run("UnmarshalJSON error", func(t *testing.T) { 136 errorCases := []string{ 137 `{"contract":"0xBadHash","eventname":"my_ne","state":{"type":"Array","value":[{"type":"Boolean","value":true}]}}`, 138 `{"contract":"0xab2f820e2aa7cca1e081283c58a7d7943c33a2f1","eventname":"my_ne","state":{"type":"Array","value":[{"type":"BadType","value":true}]}}`, 139 `{"contract":"0xab2f820e2aa7cca1e081283c58a7d7943c33a2f1","eventname":"my_ne","state":{"type":"Boolean", "value":true}}`, 140 } 141 for _, errCase := range errorCases { 142 err := json.Unmarshal([]byte(errCase), new(NotificationEvent)) 143 require.Error(t, err) 144 } 145 }) 146 } 147 148 func TestMarshalUnmarshalJSONAppExecResult(t *testing.T) { 149 t.Run("positive, transaction", func(t *testing.T) { 150 appExecResult := &AppExecResult{ 151 Container: random.Uint256(), 152 Execution: Execution{ 153 Trigger: trigger.Application, 154 VMState: vmstate.Halt, 155 GasConsumed: 10, 156 Stack: []stackitem.Item{}, 157 Events: []NotificationEvent{}, 158 }, 159 } 160 testserdes.MarshalUnmarshalJSON(t, appExecResult, new(AppExecResult)) 161 }) 162 163 t.Run("positive, fault state", func(t *testing.T) { 164 appExecResult := &AppExecResult{ 165 Container: random.Uint256(), 166 Execution: Execution{ 167 Trigger: trigger.Application, 168 VMState: vmstate.Fault, 169 GasConsumed: 10, 170 Stack: []stackitem.Item{stackitem.NewBool(true)}, 171 Events: []NotificationEvent{}, 172 FaultException: "unhandled exception", 173 }, 174 } 175 testserdes.MarshalUnmarshalJSON(t, appExecResult, new(AppExecResult)) 176 }) 177 t.Run("positive, block", func(t *testing.T) { 178 appExecResult := &AppExecResult{ 179 Container: random.Uint256(), 180 Execution: Execution{ 181 Trigger: trigger.OnPersist, 182 VMState: vmstate.Halt, 183 GasConsumed: 10, 184 Stack: []stackitem.Item{}, 185 Events: []NotificationEvent{}, 186 }, 187 } 188 testserdes.MarshalUnmarshalJSON(t, appExecResult, new(AppExecResult)) 189 }) 190 191 t.Run("MarshalJSON recursive reference", func(t *testing.T) { 192 arr := stackitem.NewArray(nil) 193 arr.Append(arr) 194 errAer := &AppExecResult{ 195 Execution: Execution{ 196 Trigger: trigger.Application, 197 Stack: []stackitem.Item{arr, stackitem.NewBool(true), stackitem.NewInterop(123)}, 198 }, 199 } 200 201 bs, err := json.Marshal(errAer) 202 require.NoError(t, err) 203 204 actual := new(AppExecResult) 205 require.NoError(t, json.Unmarshal(bs, actual)) 206 require.Equal(t, 3, len(actual.Stack)) 207 require.Nil(t, actual.Stack[0]) 208 require.Equal(t, true, actual.Stack[1].Value()) 209 require.Equal(t, stackitem.InteropT, actual.Stack[2].Type()) 210 211 bs1, err := json.Marshal(actual) 212 require.NoError(t, err) 213 require.NotEqual(t, bs, bs1) // recursive ref error vs. unserializable nil 214 215 actual2 := new(AppExecResult) 216 require.NoError(t, json.Unmarshal(bs, actual2)) 217 bs2, err := json.Marshal(actual2) 218 require.NoError(t, err) 219 require.Equal(t, bs1, bs2) // unserializable nil in both cases 220 }) 221 222 t.Run("UnmarshalJSON error", func(t *testing.T) { 223 nilStackCases := []string{ 224 `{"container":"0x17145a039fca704fcdbeb46e6b210af98a1a9e5b9768e46ffc38f71c79ac2521","trigger":"Application","vmstate":"HALT","gasconsumed":"1","stack":[{"type":"WrongType","value":"1"}],"notifications":[]}`, 225 } 226 for _, str := range nilStackCases { 227 actual := new(AppExecResult) 228 err := json.Unmarshal([]byte(str), actual) 229 require.NoError(t, err) 230 require.Nil(t, actual.Stack) 231 } 232 233 errorCases := []string{ 234 `{"container":"0xBadHash","trigger":"Application","vmstate":"HALT","gasconsumed":"1","stack":[{"type":"Integer","value":"1"}],"notifications":[]}`, 235 `{"container":"0x17145a039fca704fcdbeb46e6b210af98a1a9e5b9768e46ffc38f71c79ac2521","trigger":"Application","vmstate":"BadState","gasconsumed":"1","stack":[{"type":"Integer","value":"1"}],"notifications":[]}`, 236 `{"container":"0x17145a039fca704fcdbeb46e6b210af98a1a9e5b9768e46ffc38f71c79ac2521","trigger":"BadTrigger","vmstate":"HALT","gasconsumed":"1","stack":[{"type":"Integer","value":"1"}],"notifications":[]}`, 237 } 238 for _, str := range errorCases { 239 actual := new(AppExecResult) 240 err := json.Unmarshal([]byte(str), actual) 241 require.Error(t, err) 242 } 243 }) 244 } 245 246 func TestContainedNotificationEvent_MarshalUnmarshalJSON(t *testing.T) { 247 testserdes.MarshalUnmarshalJSON(t, &ContainedNotificationEvent{ 248 Container: util.Uint256{1, 2, 3}, 249 NotificationEvent: NotificationEvent{ 250 ScriptHash: util.Uint160{4, 5, 6}, 251 Name: "alarm", 252 Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte("qwerty"))}), 253 }, 254 }, new(ContainedNotificationEvent)) 255 }