*: make Notify interop accept event name
This commit is contained in:
parent
1154e180fa
commit
3d7fa9de93
17 changed files with 84 additions and 43 deletions
|
@ -7,16 +7,16 @@ import (
|
||||||
// Main is that famous Main() function, you know.
|
// Main is that famous Main() function, you know.
|
||||||
func Main() bool {
|
func Main() bool {
|
||||||
tx := runtime.GetScriptContainer()
|
tx := runtime.GetScriptContainer()
|
||||||
runtime.Notify(tx.Hash)
|
runtime.Notify("Tx", tx.Hash)
|
||||||
|
|
||||||
callingScriptHash := runtime.GetCallingScriptHash()
|
callingScriptHash := runtime.GetCallingScriptHash()
|
||||||
runtime.Notify(callingScriptHash)
|
runtime.Notify("Calling", callingScriptHash)
|
||||||
|
|
||||||
execScriptHash := runtime.GetExecutingScriptHash()
|
execScriptHash := runtime.GetExecutingScriptHash()
|
||||||
runtime.Notify(execScriptHash)
|
runtime.Notify("Executing", execScriptHash)
|
||||||
|
|
||||||
entryScriptHash := runtime.GetEntryScriptHash()
|
entryScriptHash := runtime.GetEntryScriptHash()
|
||||||
runtime.Notify(entryScriptHash)
|
runtime.Notify("Entry", entryScriptHash)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,6 @@ func Log(args []interface{}) bool {
|
||||||
|
|
||||||
// Notify notifies about given message
|
// Notify notifies about given message
|
||||||
func Notify(args []interface{}) bool {
|
func Notify(args []interface{}) bool {
|
||||||
runtime.Notify(args[0])
|
runtime.Notify("Event", args[0])
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,7 @@ func TestNotify(t *testing.T) {
|
||||||
src := `package foo
|
src := `package foo
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||||
func Main(arg int) {
|
func Main(arg int) {
|
||||||
runtime.Notify(arg, "sum", arg+1)
|
runtime.Notify("Event1", arg, "sum", arg+1)
|
||||||
runtime.Notify()
|
|
||||||
runtime.Notify("single")
|
runtime.Notify("single")
|
||||||
}`
|
}`
|
||||||
|
|
||||||
|
@ -39,10 +38,11 @@ func TestNotify(t *testing.T) {
|
||||||
v.Estack().PushVal(11)
|
v.Estack().PushVal(11)
|
||||||
|
|
||||||
require.NoError(t, v.Run())
|
require.NoError(t, v.Run())
|
||||||
require.Equal(t, 3, len(s.events))
|
require.Equal(t, 2, len(s.events))
|
||||||
|
|
||||||
exp0 := []stackitem.Item{stackitem.NewBigInteger(big.NewInt(11)), stackitem.NewByteArray([]byte("sum")), stackitem.NewBigInteger(big.NewInt(12))}
|
exp0 := []stackitem.Item{stackitem.NewBigInteger(big.NewInt(11)), stackitem.NewByteArray([]byte("sum")), stackitem.NewBigInteger(big.NewInt(12))}
|
||||||
assert.Equal(t, exp0, s.events[0].Value())
|
assert.Equal(t, "Event1", s.events[0].Name)
|
||||||
assert.Equal(t, []stackitem.Item{}, s.events[1].Value())
|
assert.Equal(t, exp0, s.events[0].Item.Value())
|
||||||
assert.Equal(t, []stackitem.Item{stackitem.NewByteArray([]byte("single"))}, s.events[2].Value())
|
assert.Equal(t, "single", s.events[1].Name)
|
||||||
|
assert.Equal(t, []stackitem.Item{}, s.events[1].Item.Value())
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
@ -74,7 +75,7 @@ func vmAndCompileInterop(t *testing.T, src string) (*vm.VM, *storagePlugin) {
|
||||||
type storagePlugin struct {
|
type storagePlugin struct {
|
||||||
mem map[string][]byte
|
mem map[string][]byte
|
||||||
interops map[uint32]vm.InteropFunc
|
interops map[uint32]vm.InteropFunc
|
||||||
events []stackitem.Item
|
events []state.NotificationEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStoragePlugin() *storagePlugin {
|
func newStoragePlugin() *storagePlugin {
|
||||||
|
@ -99,7 +100,12 @@ func (s *storagePlugin) getInterop(id uint32) *vm.InteropFuncPrice {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storagePlugin) Notify(v *vm.VM) error {
|
func (s *storagePlugin) Notify(v *vm.VM) error {
|
||||||
s.events = append(s.events, v.Estack().Pop().Item())
|
name := string(v.Estack().Pop().Bytes())
|
||||||
|
item := stackitem.NewArray(v.Estack().Pop().Array())
|
||||||
|
s.events = append(s.events, state.NotificationEvent{
|
||||||
|
Name: name,
|
||||||
|
Item: item,
|
||||||
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -661,16 +661,15 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc *Blockchain) handleNotification(note *state.NotificationEvent, d *dao.Cached, b *block.Block, h util.Uint256) {
|
func (bc *Blockchain) handleNotification(note *state.NotificationEvent, d *dao.Cached, b *block.Block, h util.Uint256) {
|
||||||
arr, ok := note.Item.Value().([]stackitem.Item)
|
if note.Name != "transfer" && note.Name != "Transfer" {
|
||||||
if !ok || len(arr) != 4 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
op, ok := arr[0].Value().([]byte)
|
arr, ok := note.Item.Value().([]stackitem.Item)
|
||||||
if !ok || (string(op) != "transfer" && string(op) != "Transfer") {
|
if !ok || len(arr) != 3 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var from []byte
|
var from []byte
|
||||||
fromValue := arr[1].Value()
|
fromValue := arr[0].Value()
|
||||||
// we don't have `from` set when we are minting tokens
|
// we don't have `from` set when we are minting tokens
|
||||||
if fromValue != nil {
|
if fromValue != nil {
|
||||||
from, ok = fromValue.([]byte)
|
from, ok = fromValue.([]byte)
|
||||||
|
@ -679,7 +678,7 @@ func (bc *Blockchain) handleNotification(note *state.NotificationEvent, d *dao.C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var to []byte
|
var to []byte
|
||||||
toValue := arr[2].Value()
|
toValue := arr[1].Value()
|
||||||
// we don't have `to` set when we are burning tokens
|
// we don't have `to` set when we are burning tokens
|
||||||
if toValue != nil {
|
if toValue != nil {
|
||||||
to, ok = toValue.([]byte)
|
to, ok = toValue.([]byte)
|
||||||
|
@ -687,9 +686,9 @@ func (bc *Blockchain) handleNotification(note *state.NotificationEvent, d *dao.C
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
amount, ok := arr[3].Value().(*big.Int)
|
amount, ok := arr[2].Value().(*big.Int)
|
||||||
if !ok {
|
if !ok {
|
||||||
bs, ok := arr[3].Value().([]byte)
|
bs, ok := arr[2].Value().([]byte)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ func GetNotifications(ic *interop.Context, v *vm.VM) error {
|
||||||
for i := range notifications {
|
for i := range notifications {
|
||||||
ev := stackitem.NewArray([]stackitem.Item{
|
ev := stackitem.NewArray([]stackitem.Item{
|
||||||
stackitem.NewByteArray(notifications[i].ScriptHash.BytesBE()),
|
stackitem.NewByteArray(notifications[i].ScriptHash.BytesBE()),
|
||||||
|
stackitem.Make(notifications[i].Name),
|
||||||
notifications[i].Item,
|
notifications[i].Item,
|
||||||
})
|
})
|
||||||
arr.Append(ev)
|
arr.Append(ev)
|
||||||
|
|
|
@ -27,6 +27,8 @@ const (
|
||||||
// MaxTraceableBlocks is the maximum number of blocks before current chain
|
// MaxTraceableBlocks is the maximum number of blocks before current chain
|
||||||
// height we're able to give information about.
|
// height we're able to give information about.
|
||||||
MaxTraceableBlocks = transaction.MaxValidUntilBlockIncrement
|
MaxTraceableBlocks = transaction.MaxValidUntilBlockIncrement
|
||||||
|
// MaxEventNameLen is the maximum length of a name for event.
|
||||||
|
MaxEventNameLen = 32
|
||||||
)
|
)
|
||||||
|
|
||||||
// StorageContext contains storing id and read/write flag, it's used as
|
// StorageContext contains storing id and read/write flag, it's used as
|
||||||
|
@ -244,19 +246,26 @@ func runtimeGetTrigger(ic *interop.Context, v *vm.VM) error {
|
||||||
// runtimeNotify should pass stack item to the notify plugin to handle it, but
|
// runtimeNotify should pass stack item to the notify plugin to handle it, but
|
||||||
// in neo-go the only meaningful thing to do here is to log.
|
// in neo-go the only meaningful thing to do here is to log.
|
||||||
func runtimeNotify(ic *interop.Context, v *vm.VM) error {
|
func runtimeNotify(ic *interop.Context, v *vm.VM) error {
|
||||||
// It can be just about anything.
|
name := v.Estack().Pop().Bytes()
|
||||||
e := v.Estack().Pop()
|
if len(name) > MaxEventNameLen {
|
||||||
item := e.Item()
|
return fmt.Errorf("event name must be less than %d", MaxEventNameLen)
|
||||||
|
}
|
||||||
|
elem := v.Estack().Pop()
|
||||||
|
args := elem.Array()
|
||||||
// But it has to be serializable, otherwise we either have some broken
|
// But it has to be serializable, otherwise we either have some broken
|
||||||
// (recursive) structure inside or an interop item that can't be used
|
// (recursive) structure inside or an interop item that can't be used
|
||||||
// outside of the interop subsystem anyway. I'd probably fail transactions
|
// outside of the interop subsystem anyway. I'd probably fail transactions
|
||||||
// that emit such broken notifications, but that might break compatibility
|
// that emit such broken notifications, but that might break compatibility
|
||||||
// with testnet/mainnet, so we're replacing these with error messages.
|
// with testnet/mainnet, so we're replacing these with error messages.
|
||||||
_, err := stackitem.SerializeItem(item)
|
_, err := stackitem.SerializeItem(elem.Item())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
item = stackitem.NewByteArray([]byte(fmt.Sprintf("bad notification: %v", err)))
|
args = []stackitem.Item{stackitem.NewByteArray([]byte(fmt.Sprintf("bad notification: %v", err)))}
|
||||||
|
}
|
||||||
|
ne := state.NotificationEvent{
|
||||||
|
ScriptHash: v.GetCurrentScriptHash(),
|
||||||
|
Name: string(name),
|
||||||
|
Item: stackitem.NewArray(args),
|
||||||
}
|
}
|
||||||
ne := state.NotificationEvent{ScriptHash: v.GetCurrentScriptHash(), Item: item}
|
|
||||||
ic.Notifications = append(ic.Notifications, ne)
|
ic.Notifications = append(ic.Notifications, ne)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,9 +247,9 @@ func TestRuntimeGetNotifications(t *testing.T) {
|
||||||
defer chain.Close()
|
defer chain.Close()
|
||||||
|
|
||||||
ic.Notifications = []state.NotificationEvent{
|
ic.Notifications = []state.NotificationEvent{
|
||||||
{ScriptHash: util.Uint160{1}, Item: stackitem.NewByteArray([]byte{11})},
|
{ScriptHash: util.Uint160{1}, Name: "Event1", Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte{11})})},
|
||||||
{ScriptHash: util.Uint160{2}, Item: stackitem.NewByteArray([]byte{22})},
|
{ScriptHash: util.Uint160{2}, Name: "Event2", Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte{22})})},
|
||||||
{ScriptHash: util.Uint160{1}, Item: stackitem.NewByteArray([]byte{33})},
|
{ScriptHash: util.Uint160{1}, Name: "Event1", Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte{33})})},
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("NoFilter", func(t *testing.T) {
|
t.Run("NoFilter", func(t *testing.T) {
|
||||||
|
@ -261,7 +261,10 @@ func TestRuntimeGetNotifications(t *testing.T) {
|
||||||
for i := range arr {
|
for i := range arr {
|
||||||
elem := arr[i].Value().([]stackitem.Item)
|
elem := arr[i].Value().([]stackitem.Item)
|
||||||
require.Equal(t, ic.Notifications[i].ScriptHash.BytesBE(), elem[0].Value())
|
require.Equal(t, ic.Notifications[i].ScriptHash.BytesBE(), elem[0].Value())
|
||||||
require.Equal(t, ic.Notifications[i].Item, elem[1])
|
name, err := elem[1].TryBytes()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, ic.Notifications[i].Name, string(name))
|
||||||
|
require.Equal(t, ic.Notifications[i].Item, elem[2])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -274,7 +277,10 @@ func TestRuntimeGetNotifications(t *testing.T) {
|
||||||
require.Equal(t, 1, len(arr))
|
require.Equal(t, 1, len(arr))
|
||||||
elem := arr[0].Value().([]stackitem.Item)
|
elem := arr[0].Value().([]stackitem.Item)
|
||||||
require.Equal(t, h, elem[0].Value())
|
require.Equal(t, h, elem[0].Value())
|
||||||
require.Equal(t, ic.Notifications[1].Item, elem[1])
|
name, err := elem[1].TryBytes()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, ic.Notifications[1].Name, string(name))
|
||||||
|
require.Equal(t, ic.Notifications[1].Item, elem[2])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,8 +138,8 @@ func addrToStackItem(u *util.Uint160) stackitem.Item {
|
||||||
func (c *nep5TokenNative) emitTransfer(ic *interop.Context, from, to *util.Uint160, amount *big.Int) {
|
func (c *nep5TokenNative) emitTransfer(ic *interop.Context, from, to *util.Uint160, amount *big.Int) {
|
||||||
ne := state.NotificationEvent{
|
ne := state.NotificationEvent{
|
||||||
ScriptHash: c.Hash,
|
ScriptHash: c.Hash,
|
||||||
|
Name: "Transfer",
|
||||||
Item: stackitem.NewArray([]stackitem.Item{
|
Item: stackitem.NewArray([]stackitem.Item{
|
||||||
stackitem.NewByteArray([]byte("Transfer")),
|
|
||||||
addrToStackItem(from),
|
addrToStackItem(from),
|
||||||
addrToStackItem(to),
|
addrToStackItem(to),
|
||||||
stackitem.NewBigInteger(amount),
|
stackitem.NewBigInteger(amount),
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
|
@ -12,7 +14,8 @@ import (
|
||||||
// notification and that item itself.
|
// notification and that item itself.
|
||||||
type NotificationEvent struct {
|
type NotificationEvent struct {
|
||||||
ScriptHash util.Uint160
|
ScriptHash util.Uint160
|
||||||
Item stackitem.Item
|
Name string
|
||||||
|
Item *stackitem.Array
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppExecResult represent the result of the script execution, gathering together
|
// AppExecResult represent the result of the script execution, gathering together
|
||||||
|
@ -29,13 +32,24 @@ type AppExecResult struct {
|
||||||
// EncodeBinary implements the Serializable interface.
|
// EncodeBinary implements the Serializable interface.
|
||||||
func (ne *NotificationEvent) EncodeBinary(w *io.BinWriter) {
|
func (ne *NotificationEvent) EncodeBinary(w *io.BinWriter) {
|
||||||
ne.ScriptHash.EncodeBinary(w)
|
ne.ScriptHash.EncodeBinary(w)
|
||||||
|
w.WriteString(ne.Name)
|
||||||
stackitem.EncodeBinaryStackItem(ne.Item, w)
|
stackitem.EncodeBinaryStackItem(ne.Item, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBinary implements the Serializable interface.
|
// DecodeBinary implements the Serializable interface.
|
||||||
func (ne *NotificationEvent) DecodeBinary(r *io.BinReader) {
|
func (ne *NotificationEvent) DecodeBinary(r *io.BinReader) {
|
||||||
ne.ScriptHash.DecodeBinary(r)
|
ne.ScriptHash.DecodeBinary(r)
|
||||||
ne.Item = stackitem.DecodeBinaryStackItem(r)
|
ne.Name = r.ReadString()
|
||||||
|
item := stackitem.DecodeBinaryStackItem(r)
|
||||||
|
if r.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
r.Err = errors.New("Array or Struct expected")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ne.Item = stackitem.NewArray(arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeBinary implements the Serializable interface.
|
// EncodeBinary implements the Serializable interface.
|
||||||
|
|
|
@ -12,7 +12,8 @@ import (
|
||||||
func TestEncodeDecodeNotificationEvent(t *testing.T) {
|
func TestEncodeDecodeNotificationEvent(t *testing.T) {
|
||||||
event := &NotificationEvent{
|
event := &NotificationEvent{
|
||||||
ScriptHash: random.Uint160(),
|
ScriptHash: random.Uint160(),
|
||||||
Item: stackitem.NewBool(true),
|
Name: "Event",
|
||||||
|
Item: stackitem.NewArray([]stackitem.Item{stackitem.NewBool(true)}),
|
||||||
}
|
}
|
||||||
|
|
||||||
testserdes.EncodeDecodeBinary(t, event, new(NotificationEvent))
|
testserdes.EncodeDecodeBinary(t, event, new(NotificationEvent))
|
||||||
|
|
|
@ -17,12 +17,12 @@ func CheckWitness(hashOrKey []byte) bool {
|
||||||
func Log(message string) {}
|
func Log(message string) {}
|
||||||
|
|
||||||
// Notify sends a notification (collecting all arguments in an array) to the
|
// Notify sends a notification (collecting all arguments in an array) to the
|
||||||
// executing environment. Unlike Log it can accept any data and resulting
|
// executing environment. Unlike Log it can accept any data along with the event name
|
||||||
// notification is saved in application log. It's intended to be used as a
|
// and resulting notification is saved in application log. It's intended to be used as a
|
||||||
// part of contract's API to external systems, these events can be monitored
|
// part of contract's API to external systems, these events can be monitored
|
||||||
// from outside and act upon accordingly. This function uses
|
// from outside and act upon accordingly. This function uses
|
||||||
// `System.Runtime.Notify` syscall.
|
// `System.Runtime.Notify` syscall.
|
||||||
func Notify(arg ...interface{}) {}
|
func Notify(name string, arg ...interface{}) {}
|
||||||
|
|
||||||
// GetTime returns the timestamp of the most recent block. Note that when running
|
// GetTime returns the timestamp of the most recent block. Note that when running
|
||||||
// script in test mode this would be the last accepted (persisted) block in the
|
// script in test mode this would be the last accepted (persisted) block in the
|
||||||
|
|
|
@ -28,7 +28,11 @@ type NotificationEvent struct {
|
||||||
// result.NotificationEvent.
|
// result.NotificationEvent.
|
||||||
func StateEventToResultNotification(event state.NotificationEvent) NotificationEvent {
|
func StateEventToResultNotification(event state.NotificationEvent) NotificationEvent {
|
||||||
seen := make(map[stackitem.Item]bool)
|
seen := make(map[stackitem.Item]bool)
|
||||||
item := smartcontract.ParameterFromStackItem(event.Item, seen)
|
args := stackitem.NewArray([]stackitem.Item{
|
||||||
|
stackitem.Make(event.Name),
|
||||||
|
event.Item,
|
||||||
|
})
|
||||||
|
item := smartcontract.ParameterFromStackItem(args, seen)
|
||||||
return NotificationEvent{
|
return NotificationEvent{
|
||||||
Contract: event.ScriptHash,
|
Contract: event.ScriptHash,
|
||||||
Item: item,
|
Item: item,
|
||||||
|
|
|
@ -51,8 +51,8 @@ type rpcTestCase struct {
|
||||||
check func(t *testing.T, e *executor, result interface{})
|
check func(t *testing.T, e *executor, result interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
const testContractHash = "10e262ef80c76bdecca287a2c047841fc02c3129"
|
const testContractHash = "402da558b87b5e54b59dc242c788bb4dd4cd906c"
|
||||||
const deploymentTxHash = "49f555734b90eb7d4f87041b5146a9b6bc7cf70060bb665212773719091b3a81"
|
const deploymentTxHash = "2afd69cc80ebe900a060450e8628b57063f3ec93ca5fc7f94582be4a4f3a041f"
|
||||||
|
|
||||||
var rpcTestCases = map[string][]rpcTestCase{
|
var rpcTestCases = map[string][]rpcTestCase{
|
||||||
"getapplicationlog": {
|
"getapplicationlog": {
|
||||||
|
|
BIN
pkg/rpc/server/testdata/test_contract.avm
vendored
BIN
pkg/rpc/server/testdata/test_contract.avm
vendored
Binary file not shown.
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
|
@ -82,8 +82,9 @@ func runtimeLog(vm *VM) error {
|
||||||
|
|
||||||
// runtimeNotify handles the syscall "System.Runtime.Notify" for printing and logging stuff.
|
// runtimeNotify handles the syscall "System.Runtime.Notify" for printing and logging stuff.
|
||||||
func runtimeNotify(vm *VM) error {
|
func runtimeNotify(vm *VM) error {
|
||||||
|
name := vm.Estack().Pop().Bytes()
|
||||||
item := vm.Estack().Pop()
|
item := vm.Estack().Pop()
|
||||||
fmt.Printf("NEO-GO-VM (notify) > %s\n", item.Value())
|
fmt.Printf("NEO-GO-VM (notify) > [%s] %s\n", string(name), item.Value())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue