2019-11-28 16:06:09 +00:00
|
|
|
package state
|
2019-11-26 15:47:07 +00:00
|
|
|
|
|
|
|
import (
|
2020-09-03 16:58:50 +00:00
|
|
|
"encoding/json"
|
2019-11-26 15:47:07 +00:00
|
|
|
"testing"
|
|
|
|
|
2020-11-23 11:09:00 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/internal/random"
|
|
|
|
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
2020-12-18 09:28:01 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
2020-09-21 11:08:15 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
2020-06-03 12:55:06 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
2022-07-08 14:28:29 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
2020-09-03 16:58:50 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2019-11-26 15:47:07 +00:00
|
|
|
)
|
|
|
|
|
2021-08-06 08:55:43 +00:00
|
|
|
func BenchmarkAppExecResult_EncodeBinary(b *testing.B) {
|
|
|
|
aer := &AppExecResult{
|
|
|
|
Container: random.Uint256(),
|
|
|
|
Execution: Execution{
|
|
|
|
Trigger: trigger.Application,
|
2022-07-08 14:28:29 +00:00
|
|
|
VMState: vmstate.Halt,
|
2021-08-06 08:55:43 +00:00
|
|
|
GasConsumed: 12345,
|
|
|
|
Stack: []stackitem.Item{},
|
|
|
|
Events: []NotificationEvent{{
|
|
|
|
ScriptHash: random.Uint160(),
|
|
|
|
Name: "Event",
|
|
|
|
Item: stackitem.NewArray([]stackitem.Item{stackitem.NewBool(true)}),
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
w := io.NewBufBinWriter()
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
w.Reset()
|
|
|
|
aer.EncodeBinary(w.BinWriter)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-26 15:47:07 +00:00
|
|
|
func TestEncodeDecodeNotificationEvent(t *testing.T) {
|
|
|
|
event := &NotificationEvent{
|
2019-12-04 12:24:49 +00:00
|
|
|
ScriptHash: random.Uint160(),
|
2020-06-29 08:25:32 +00:00
|
|
|
Name: "Event",
|
|
|
|
Item: stackitem.NewArray([]stackitem.Item{stackitem.NewBool(true)}),
|
2019-11-26 15:47:07 +00:00
|
|
|
}
|
|
|
|
|
2020-03-26 14:43:24 +00:00
|
|
|
testserdes.EncodeDecodeBinary(t, event, new(NotificationEvent))
|
2019-11-26 15:47:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestEncodeDecodeAppExecResult(t *testing.T) {
|
2020-12-18 09:28:01 +00:00
|
|
|
newAer := func() *AppExecResult {
|
|
|
|
return &AppExecResult{
|
2020-11-11 15:43:28 +00:00
|
|
|
Container: random.Uint256(),
|
|
|
|
Execution: Execution{
|
|
|
|
Trigger: 1,
|
2022-07-08 14:28:29 +00:00
|
|
|
VMState: vmstate.Halt,
|
2020-11-11 15:43:28 +00:00
|
|
|
GasConsumed: 10,
|
2020-12-18 09:28:01 +00:00
|
|
|
Stack: []stackitem.Item{stackitem.NewBool(true)},
|
2020-11-11 15:43:28 +00:00
|
|
|
Events: []NotificationEvent{},
|
|
|
|
},
|
2020-10-05 14:04:17 +00:00
|
|
|
}
|
2020-12-18 09:28:01 +00:00
|
|
|
}
|
|
|
|
t.Run("halt", func(t *testing.T) {
|
|
|
|
appExecResult := newAer()
|
2022-07-08 14:28:29 +00:00
|
|
|
appExecResult.VMState = vmstate.Halt
|
2020-10-05 14:04:17 +00:00
|
|
|
testserdes.EncodeDecodeBinary(t, appExecResult, new(AppExecResult))
|
|
|
|
})
|
|
|
|
t.Run("fault", func(t *testing.T) {
|
2020-12-18 09:28:01 +00:00
|
|
|
appExecResult := newAer()
|
2022-07-08 14:28:29 +00:00
|
|
|
appExecResult.VMState = vmstate.Fault
|
2020-12-18 09:28:01 +00:00
|
|
|
testserdes.EncodeDecodeBinary(t, appExecResult, new(AppExecResult))
|
|
|
|
})
|
|
|
|
t.Run("with interop", func(t *testing.T) {
|
|
|
|
appExecResult := newAer()
|
|
|
|
appExecResult.Stack = []stackitem.Item{stackitem.NewInterop(nil)}
|
2020-10-05 14:04:17 +00:00
|
|
|
testserdes.EncodeDecodeBinary(t, appExecResult, new(AppExecResult))
|
|
|
|
})
|
2020-12-18 09:28:01 +00:00
|
|
|
t.Run("recursive reference", func(t *testing.T) {
|
|
|
|
var arr = stackitem.NewArray(nil)
|
|
|
|
arr.Append(arr)
|
|
|
|
appExecResult := newAer()
|
|
|
|
appExecResult.Stack = []stackitem.Item{arr, stackitem.NewBool(true), stackitem.NewInterop(123)}
|
|
|
|
|
|
|
|
bs, err := testserdes.EncodeBinary(appExecResult)
|
|
|
|
require.NoError(t, err)
|
|
|
|
actual := new(AppExecResult)
|
|
|
|
require.NoError(t, testserdes.DecodeBinary(bs, actual))
|
|
|
|
require.Equal(t, 3, len(actual.Stack))
|
|
|
|
require.Nil(t, actual.Stack[0])
|
|
|
|
require.Equal(t, true, actual.Stack[1].Value())
|
|
|
|
require.Equal(t, stackitem.InteropT, actual.Stack[2].Type())
|
|
|
|
|
|
|
|
bs1, err := testserdes.EncodeBinary(actual)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, bs, bs1)
|
|
|
|
})
|
|
|
|
t.Run("invalid item type", func(t *testing.T) {
|
|
|
|
aer := newAer()
|
|
|
|
w := io.NewBufBinWriter()
|
|
|
|
w.WriteBytes(aer.Container[:])
|
|
|
|
w.WriteB(byte(aer.Trigger))
|
|
|
|
w.WriteB(byte(aer.VMState))
|
|
|
|
w.WriteU64LE(uint64(aer.GasConsumed))
|
2021-07-06 16:56:23 +00:00
|
|
|
stackitem.EncodeBinary(stackitem.NewBool(true), w.BinWriter)
|
2020-12-18 09:28:01 +00:00
|
|
|
require.NoError(t, w.Err)
|
|
|
|
require.Error(t, testserdes.DecodeBinary(w.Bytes(), new(AppExecResult)))
|
|
|
|
})
|
2019-11-26 15:47:07 +00:00
|
|
|
}
|
2020-09-03 16:58:50 +00:00
|
|
|
|
|
|
|
func TestMarshalUnmarshalJSONNotificationEvent(t *testing.T) {
|
|
|
|
t.Run("positive", func(t *testing.T) {
|
|
|
|
ne := &NotificationEvent{
|
|
|
|
ScriptHash: random.Uint160(),
|
|
|
|
Name: "my_ne",
|
|
|
|
Item: stackitem.NewArray([]stackitem.Item{
|
|
|
|
stackitem.NewBool(true),
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
testserdes.MarshalUnmarshalJSON(t, ne, new(NotificationEvent))
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("MarshalJSON recursive reference", func(t *testing.T) {
|
|
|
|
i := make([]stackitem.Item, 1)
|
|
|
|
recursive := stackitem.NewArray(i)
|
|
|
|
i[0] = recursive
|
|
|
|
ne := &NotificationEvent{
|
|
|
|
Item: recursive,
|
|
|
|
}
|
|
|
|
_, err := json.Marshal(ne)
|
|
|
|
require.NoError(t, err)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("UnmarshalJSON error", func(t *testing.T) {
|
|
|
|
errorCases := []string{
|
|
|
|
`{"contract":"0xBadHash","eventname":"my_ne","state":{"type":"Array","value":[{"type":"Boolean","value":true}]}}`,
|
|
|
|
`{"contract":"0xab2f820e2aa7cca1e081283c58a7d7943c33a2f1","eventname":"my_ne","state":{"type":"Array","value":[{"type":"BadType","value":true}]}}`,
|
|
|
|
`{"contract":"0xab2f820e2aa7cca1e081283c58a7d7943c33a2f1","eventname":"my_ne","state":{"type":"Boolean", "value":true}}`,
|
|
|
|
}
|
|
|
|
for _, errCase := range errorCases {
|
|
|
|
err := json.Unmarshal([]byte(errCase), new(NotificationEvent))
|
|
|
|
require.Error(t, err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMarshalUnmarshalJSONAppExecResult(t *testing.T) {
|
2020-09-21 11:08:15 +00:00
|
|
|
t.Run("positive, transaction", func(t *testing.T) {
|
2020-09-03 16:58:50 +00:00
|
|
|
appExecResult := &AppExecResult{
|
2020-11-11 15:43:28 +00:00
|
|
|
Container: random.Uint256(),
|
|
|
|
Execution: Execution{
|
|
|
|
Trigger: trigger.Application,
|
2022-07-08 14:28:29 +00:00
|
|
|
VMState: vmstate.Halt,
|
2020-11-11 15:43:28 +00:00
|
|
|
GasConsumed: 10,
|
|
|
|
Stack: []stackitem.Item{},
|
|
|
|
Events: []NotificationEvent{},
|
|
|
|
},
|
2020-09-03 16:58:50 +00:00
|
|
|
}
|
2021-02-09 08:16:18 +00:00
|
|
|
testserdes.MarshalUnmarshalJSON(t, appExecResult, new(AppExecResult))
|
2020-09-03 16:58:50 +00:00
|
|
|
})
|
|
|
|
|
2020-10-05 14:04:17 +00:00
|
|
|
t.Run("positive, fault state", func(t *testing.T) {
|
|
|
|
appExecResult := &AppExecResult{
|
2020-11-11 15:43:28 +00:00
|
|
|
Container: random.Uint256(),
|
|
|
|
Execution: Execution{
|
|
|
|
Trigger: trigger.Application,
|
2022-07-08 14:28:29 +00:00
|
|
|
VMState: vmstate.Fault,
|
2020-11-11 15:43:28 +00:00
|
|
|
GasConsumed: 10,
|
2020-12-18 09:28:01 +00:00
|
|
|
Stack: []stackitem.Item{stackitem.NewBool(true)},
|
2020-11-11 15:43:28 +00:00
|
|
|
Events: []NotificationEvent{},
|
|
|
|
FaultException: "unhandled exception",
|
|
|
|
},
|
2020-10-05 14:04:17 +00:00
|
|
|
}
|
|
|
|
testserdes.MarshalUnmarshalJSON(t, appExecResult, new(AppExecResult))
|
|
|
|
})
|
2020-09-21 11:08:15 +00:00
|
|
|
t.Run("positive, block", func(t *testing.T) {
|
|
|
|
appExecResult := &AppExecResult{
|
2020-11-11 15:43:28 +00:00
|
|
|
Container: random.Uint256(),
|
|
|
|
Execution: Execution{
|
|
|
|
Trigger: trigger.OnPersist,
|
2022-07-08 14:28:29 +00:00
|
|
|
VMState: vmstate.Halt,
|
2020-11-11 15:43:28 +00:00
|
|
|
GasConsumed: 10,
|
|
|
|
Stack: []stackitem.Item{},
|
|
|
|
Events: []NotificationEvent{},
|
|
|
|
},
|
2020-09-21 11:08:15 +00:00
|
|
|
}
|
2020-11-12 10:06:11 +00:00
|
|
|
testserdes.MarshalUnmarshalJSON(t, appExecResult, new(AppExecResult))
|
2020-09-21 11:08:15 +00:00
|
|
|
})
|
|
|
|
|
2020-09-03 16:58:50 +00:00
|
|
|
t.Run("MarshalJSON recursive reference", func(t *testing.T) {
|
2020-12-18 09:28:01 +00:00
|
|
|
arr := stackitem.NewArray(nil)
|
|
|
|
arr.Append(arr)
|
|
|
|
errAer := &AppExecResult{
|
|
|
|
Execution: Execution{
|
|
|
|
Trigger: trigger.Application,
|
|
|
|
Stack: []stackitem.Item{arr, stackitem.NewBool(true), stackitem.NewInterop(123)},
|
2020-09-03 16:58:50 +00:00
|
|
|
},
|
|
|
|
}
|
2020-12-18 09:28:01 +00:00
|
|
|
|
|
|
|
bs, err := json.Marshal(errAer)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
actual := new(AppExecResult)
|
|
|
|
require.NoError(t, json.Unmarshal(bs, actual))
|
|
|
|
require.Equal(t, 3, len(actual.Stack))
|
|
|
|
require.Nil(t, actual.Stack[0])
|
|
|
|
require.Equal(t, true, actual.Stack[1].Value())
|
|
|
|
require.Equal(t, stackitem.InteropT, actual.Stack[2].Type())
|
|
|
|
|
|
|
|
bs1, err := json.Marshal(actual)
|
|
|
|
require.NoError(t, err)
|
2021-07-06 21:38:19 +00:00
|
|
|
require.NotEqual(t, bs, bs1) // recursive ref error vs. unserializable nil
|
|
|
|
|
|
|
|
actual2 := new(AppExecResult)
|
|
|
|
require.NoError(t, json.Unmarshal(bs, actual2))
|
|
|
|
bs2, err := json.Marshal(actual2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, bs1, bs2) // unserializable nil in both cases
|
2020-09-03 16:58:50 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("UnmarshalJSON error", func(t *testing.T) {
|
|
|
|
nilStackCases := []string{
|
2020-11-12 10:06:11 +00:00
|
|
|
`{"container":"0x17145a039fca704fcdbeb46e6b210af98a1a9e5b9768e46ffc38f71c79ac2521","trigger":"Application","vmstate":"HALT","gasconsumed":"1","stack":[{"type":"WrongType","value":"1"}],"notifications":[]}`,
|
2020-09-03 16:58:50 +00:00
|
|
|
}
|
|
|
|
for _, str := range nilStackCases {
|
|
|
|
actual := new(AppExecResult)
|
|
|
|
err := json.Unmarshal([]byte(str), actual)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Nil(t, actual.Stack)
|
|
|
|
}
|
|
|
|
|
|
|
|
errorCases := []string{
|
2020-11-12 10:06:11 +00:00
|
|
|
`{"container":"0xBadHash","trigger":"Application","vmstate":"HALT","gasconsumed":"1","stack":[{"type":"Integer","value":"1"}],"notifications":[]}`,
|
|
|
|
`{"container":"0x17145a039fca704fcdbeb46e6b210af98a1a9e5b9768e46ffc38f71c79ac2521","trigger":"Application","vmstate":"BadState","gasconsumed":"1","stack":[{"type":"Integer","value":"1"}],"notifications":[]}`,
|
|
|
|
`{"container":"0x17145a039fca704fcdbeb46e6b210af98a1a9e5b9768e46ffc38f71c79ac2521","trigger":"BadTrigger","vmstate":"HALT","gasconsumed":"1","stack":[{"type":"Integer","value":"1"}],"notifications":[]}`,
|
2020-09-03 16:58:50 +00:00
|
|
|
}
|
|
|
|
for _, str := range errorCases {
|
|
|
|
actual := new(AppExecResult)
|
|
|
|
err := json.Unmarshal([]byte(str), actual)
|
|
|
|
require.Error(t, err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|