forked from TrueCloudLab/neoneo-go
core: implement System.Runtime.GetNotifications syscall
This commit is contained in:
parent
afd8f3b87a
commit
75e597f880
4 changed files with 84 additions and 0 deletions
|
@ -28,6 +28,7 @@ var syscalls = map[string]map[string]string{
|
||||||
"GetCallingScriptHash": "System.Runtime.GetCallingScriptHash",
|
"GetCallingScriptHash": "System.Runtime.GetCallingScriptHash",
|
||||||
"GetEntryScriptHash": "System.Runtime.GetEntryScriptHash",
|
"GetEntryScriptHash": "System.Runtime.GetEntryScriptHash",
|
||||||
"GetExecutingScriptHash": "System.Runtime.GetExecutingScriptHash",
|
"GetExecutingScriptHash": "System.Runtime.GetExecutingScriptHash",
|
||||||
|
"GetNotifications": "System.Runtime.GetNotifications",
|
||||||
|
|
||||||
"GasLeft": "System.Runtime.GasLeft",
|
"GasLeft": "System.Runtime.GasLeft",
|
||||||
"GetTrigger": "System.Runtime.GetTrigger",
|
"GetTrigger": "System.Runtime.GetTrigger",
|
||||||
|
|
|
@ -2,7 +2,11 @@ package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GasLeft returns remaining amount of GAS.
|
// GasLeft returns remaining amount of GAS.
|
||||||
|
@ -10,3 +14,38 @@ func GasLeft(_ *interop.Context, v *vm.VM) error {
|
||||||
v.Estack().PushVal(int64(v.GasLimit - v.GasConsumed()))
|
v.Estack().PushVal(int64(v.GasLimit - v.GasConsumed()))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNotifications returns notifications emitted by current contract execution.
|
||||||
|
func GetNotifications(ic *interop.Context, v *vm.VM) error {
|
||||||
|
item := v.Estack().Pop().Item()
|
||||||
|
notifications := ic.Notifications
|
||||||
|
if _, ok := item.(stackitem.Null); !ok {
|
||||||
|
b, err := item.TryBytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
u, err := util.Uint160DecodeBytesBE(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
notifications = []state.NotificationEvent{}
|
||||||
|
for i := range ic.Notifications {
|
||||||
|
if ic.Notifications[i].ScriptHash.Equals(u) {
|
||||||
|
notifications = append(notifications, ic.Notifications[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(notifications) > vm.MaxStackSize {
|
||||||
|
return errors.New("too many notifications")
|
||||||
|
}
|
||||||
|
arr := stackitem.NewArray(make([]stackitem.Item, 0, len(notifications)))
|
||||||
|
for i := range notifications {
|
||||||
|
ev := stackitem.NewArray([]stackitem.Item{
|
||||||
|
stackitem.NewByteArray(notifications[i].ScriptHash.BytesBE()),
|
||||||
|
notifications[i].Item,
|
||||||
|
})
|
||||||
|
arr.Append(ev)
|
||||||
|
}
|
||||||
|
v.Estack().PushVal(arr)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -208,3 +208,39 @@ func TestRuntimeGasLeft(t *testing.T) {
|
||||||
require.NoError(t, runtime.GasLeft(ic, v))
|
require.NoError(t, runtime.GasLeft(ic, v))
|
||||||
require.EqualValues(t, 42, v.Estack().Pop().BigInt().Int64())
|
require.EqualValues(t, 42, v.Estack().Pop().BigInt().Int64())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRuntimeGetNotifications(t *testing.T) {
|
||||||
|
v, ic, chain := createVM(t)
|
||||||
|
defer chain.Close()
|
||||||
|
|
||||||
|
ic.Notifications = []state.NotificationEvent{
|
||||||
|
{ScriptHash: util.Uint160{1}, Item: stackitem.NewByteArray([]byte{11})},
|
||||||
|
{ScriptHash: util.Uint160{2}, Item: stackitem.NewByteArray([]byte{22})},
|
||||||
|
{ScriptHash: util.Uint160{1}, Item: stackitem.NewByteArray([]byte{33})},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("NoFilter", func(t *testing.T) {
|
||||||
|
v.Estack().PushVal(stackitem.Null{})
|
||||||
|
require.NoError(t, runtime.GetNotifications(ic, v))
|
||||||
|
|
||||||
|
arr := v.Estack().Pop().Array()
|
||||||
|
require.Equal(t, len(ic.Notifications), len(arr))
|
||||||
|
for i := range arr {
|
||||||
|
elem := arr[i].Value().([]stackitem.Item)
|
||||||
|
require.Equal(t, ic.Notifications[i].ScriptHash.BytesBE(), elem[0].Value())
|
||||||
|
require.Equal(t, ic.Notifications[i].Item, elem[1])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("WithFilter", func(t *testing.T) {
|
||||||
|
h := util.Uint160{2}.BytesBE()
|
||||||
|
v.Estack().PushVal(h)
|
||||||
|
require.NoError(t, runtime.GetNotifications(ic, v))
|
||||||
|
|
||||||
|
arr := v.Estack().Pop().Array()
|
||||||
|
require.Equal(t, 1, len(arr))
|
||||||
|
elem := arr[0].Value().([]stackitem.Item)
|
||||||
|
require.Equal(t, h, elem[0].Value())
|
||||||
|
require.Equal(t, ic.Notifications[1].Item, elem[1])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -60,3 +60,11 @@ func Verification() byte {
|
||||||
func GasLeft() int64 {
|
func GasLeft() int64 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNotifications returns notifications emitted by contract h.
|
||||||
|
// 'nil' literal means no filtering. It returns slice consisting of following elements:
|
||||||
|
// [ scripthash of notification's contract , emitted item ].
|
||||||
|
// This function uses `System.Runtime.GetNotifications` syscall.
|
||||||
|
func GetNotifications(h []byte) [][]interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue