vm: extend interops to contain price

The same way C# node does.
This commit is contained in:
Roman Khimov 2019-10-01 16:37:42 +03:00
parent ceca9cdb67
commit 26e3b6abbe
3 changed files with 18 additions and 12 deletions

View file

@ -45,9 +45,9 @@ func vmAndCompile(t *testing.T, src string) *vm.VM {
vm := vm.New(vm.ModeMute) vm := vm.New(vm.ModeMute)
storePlugin := newStoragePlugin() storePlugin := newStoragePlugin()
vm.RegisterInteropFunc("Neo.Storage.Get", storePlugin.Get) vm.RegisterInteropFunc("Neo.Storage.Get", storePlugin.Get, 1)
vm.RegisterInteropFunc("Neo.Storage.Put", storePlugin.Put) vm.RegisterInteropFunc("Neo.Storage.Put", storePlugin.Put, 1)
vm.RegisterInteropFunc("Neo.Storage.GetContext", storePlugin.GetContext) vm.RegisterInteropFunc("Neo.Storage.GetContext", storePlugin.GetContext, 1)
b, err := compiler.Compile(strings.NewReader(src), &compiler.Options{}) b, err := compiler.Compile(strings.NewReader(src), &compiler.Options{})
if err != nil { if err != nil {

View file

@ -33,7 +33,7 @@ type VM struct {
state State state State
// registered interop hooks. // registered interop hooks.
interop map[string]InteropFunc interop map[string]InteropFuncPrice
// callback to get scripts. // callback to get scripts.
getScript func(util.Uint160) []byte getScript func(util.Uint160) []byte
@ -48,10 +48,16 @@ type VM struct {
checkhash []byte checkhash []byte
} }
// InteropFuncPrice represents an interop function with a price.
type InteropFuncPrice struct {
Func InteropFunc
Price int
}
// New returns a new VM object ready to load .avm bytecode scripts. // New returns a new VM object ready to load .avm bytecode scripts.
func New(mode Mode) *VM { func New(mode Mode) *VM {
vm := &VM{ vm := &VM{
interop: make(map[string]InteropFunc), interop: make(map[string]InteropFuncPrice),
getScript: nil, getScript: nil,
state: haltState, state: haltState,
istack: NewStack("invocation"), istack: NewStack("invocation"),
@ -63,15 +69,15 @@ func New(mode Mode) *VM {
} }
// Register native interop hooks. // Register native interop hooks.
vm.RegisterInteropFunc("Neo.Runtime.Log", runtimeLog) vm.RegisterInteropFunc("Neo.Runtime.Log", runtimeLog, 1)
vm.RegisterInteropFunc("Neo.Runtime.Notify", runtimeNotify) vm.RegisterInteropFunc("Neo.Runtime.Notify", runtimeNotify, 1)
return vm return vm
} }
// RegisterInteropFunc will register the given InteropFunc to the VM. // RegisterInteropFunc will register the given InteropFunc to the VM.
func (v *VM) RegisterInteropFunc(name string, f InteropFunc) { func (v *VM) RegisterInteropFunc(name string, f InteropFunc, price int) {
v.interop[name] = f v.interop[name] = InteropFuncPrice{f, price}
} }
// Estack will return the evaluation stack so interop hooks can utilize this. // Estack will return the evaluation stack so interop hooks can utilize this.
@ -850,7 +856,7 @@ func (v *VM) execute(ctx *Context, op Instruction) {
if !ok { if !ok {
panic(fmt.Sprintf("interop hook (%s) not registered", api)) panic(fmt.Sprintf("interop hook (%s) not registered", api))
} }
if err := ifunc(v); err != nil { if err := ifunc.Func(v); err != nil {
panic(fmt.Sprintf("failed to invoke syscall: %s", err)) panic(fmt.Sprintf("failed to invoke syscall: %s", err))
} }

View file

@ -18,7 +18,7 @@ func TestInteropHook(t *testing.T) {
v.RegisterInteropFunc("foo", func(evm *VM) error { v.RegisterInteropFunc("foo", func(evm *VM) error {
evm.Estack().PushVal(1) evm.Estack().PushVal(1)
return nil return nil
}) }, 1)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
EmitSyscall(buf, "foo") EmitSyscall(buf, "foo")
@ -33,7 +33,7 @@ func TestInteropHook(t *testing.T) {
func TestRegisterInterop(t *testing.T) { func TestRegisterInterop(t *testing.T) {
v := New(ModeMute) v := New(ModeMute)
currRegistered := len(v.interop) currRegistered := len(v.interop)
v.RegisterInteropFunc("foo", func(evm *VM) error { return nil }) v.RegisterInteropFunc("foo", func(evm *VM) error { return nil }, 1)
assert.Equal(t, currRegistered+1, len(v.interop)) assert.Equal(t, currRegistered+1, len(v.interop))
_, ok := v.interop["foo"] _, ok := v.interop["foo"]
assert.Equal(t, true, ok) assert.Equal(t, true, ok)