vm: extend interops to contain price
The same way C# node does.
This commit is contained in:
parent
ceca9cdb67
commit
26e3b6abbe
3 changed files with 18 additions and 12 deletions
|
@ -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 {
|
||||||
|
|
20
pkg/vm/vm.go
20
pkg/vm/vm.go
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue