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)
storePlugin := newStoragePlugin()
vm.RegisterInteropFunc("Neo.Storage.Get", storePlugin.Get)
vm.RegisterInteropFunc("Neo.Storage.Put", storePlugin.Put)
vm.RegisterInteropFunc("Neo.Storage.GetContext", storePlugin.GetContext)
vm.RegisterInteropFunc("Neo.Storage.Get", storePlugin.Get, 1)
vm.RegisterInteropFunc("Neo.Storage.Put", storePlugin.Put, 1)
vm.RegisterInteropFunc("Neo.Storage.GetContext", storePlugin.GetContext, 1)
b, err := compiler.Compile(strings.NewReader(src), &compiler.Options{})
if err != nil {

View file

@ -33,7 +33,7 @@ type VM struct {
state State
// registered interop hooks.
interop map[string]InteropFunc
interop map[string]InteropFuncPrice
// callback to get scripts.
getScript func(util.Uint160) []byte
@ -48,10 +48,16 @@ type VM struct {
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.
func New(mode Mode) *VM {
vm := &VM{
interop: make(map[string]InteropFunc),
interop: make(map[string]InteropFuncPrice),
getScript: nil,
state: haltState,
istack: NewStack("invocation"),
@ -63,15 +69,15 @@ func New(mode Mode) *VM {
}
// Register native interop hooks.
vm.RegisterInteropFunc("Neo.Runtime.Log", runtimeLog)
vm.RegisterInteropFunc("Neo.Runtime.Notify", runtimeNotify)
vm.RegisterInteropFunc("Neo.Runtime.Log", runtimeLog, 1)
vm.RegisterInteropFunc("Neo.Runtime.Notify", runtimeNotify, 1)
return vm
}
// RegisterInteropFunc will register the given InteropFunc to the VM.
func (v *VM) RegisterInteropFunc(name string, f InteropFunc) {
v.interop[name] = f
func (v *VM) RegisterInteropFunc(name string, f InteropFunc, price int) {
v.interop[name] = InteropFuncPrice{f, price}
}
// 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 {
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))
}

View file

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