ONT实现API的流程

[TOC]

实现方式

本体是在原有VM的基础上添加了memory部分,实现wasm虚拟机的堆栈处理部分。 在调用合约时会执行下面函数:

func (this *WasmVmService) Invoke() (interface{}, error) {


    stateMachine := NewWasmStateMachine()



    //register the "CallContract" function



    stateMachine.Register("ONT_CallContract", this.callContract)



    stateMachine.Register("ONT_MarshalNativeParams", this.marshalNativeParams)



    stateMachine.Register("ONT_MarshalNeoParams", this.marshalNeoParams)

这里注册了ONT的API,注册函数将函数执行和名称存在一个map里:

func (i *WasmStateReader) Register(name string, handler func(*exec.ExecutionEngine) (bool, error)) bool {


    if _, ok := i.serviceMap[name]; ok {



        return false



    }



    i.serviceMap[name] = handler



    return true



}

等待执行时取出,实现体内部则是调用自己实现的memory:

func (this *WasmVmService) runtimeLog(engine *exec.ExecutionEngine) (bool, error) {


    vm := engine.GetVM()



    envCall := vm.GetEnvCall()



    params := envCall.GetParams()



    if len(params) != 1 {



        return false, errors.NewErr("[RuntimeLog]parameter count error ")



    }



    item, err := vm.GetPointerMemory(params[0])



    if err != nil {



        return false, err



    }



    context := this.ContextRef.CurrentContext()



    txHash := this.Tx.Hash()



    event.PushSmartCodeEvent(txHash, 0, event.EVENT_LOG, &event.LogEventArgs{TxHash: txHash, ContractAddress: context.ContractAddress, Message: string(item)})



    vm.RestoreCtx()



    return true, nil



}

将获取的结果存入堆栈中,并返回指针。 在执行代码时,首先解析module部分,然后创建新的VM:

func (e *ExecutionEngine) call(caller common.Address,


    code []byte,



    input []byte,



    actionName string,



    ver byte) (returnbytes []byte, er error) {



    if ver > 0 { //production contract version



        methodName := CONTRACT_METHOD_NAME //fix to "invoke"



        //1. read code



        bf := bytes.NewBuffer(code)



        //2. read module



        m, err := wasm.ReadModule(bf, importer)



        if err != nil {



            return nil, errors.NewErr("[Call]Verify wasm failed!" + err.Error())



        }



        //3. verify the module



        //already verified in step 2



        //4. check the export



        //every wasm should have at least 1 export



        if m.Export == nil {



            return nil, errors.NewErr("[Call]No export in wasm!")



        }



        vm, err := NewVM(m)

load部分就是将解析出的module加载到虚拟机,这个过程会调用vm.newFuncTable()来生成函数列表:

func (vm *VM) newFuncTable() {


    vm.funcTable[ops.I32Clz] = vm.i32Clz



    vm.funcTable[ops.I32Ctz] = vm.i32Ctz



    vm.funcTable[ops.I32Popcnt] = vm.i32Popcnt



    vm.funcTable[ops.I32Add] = vm.i32Add



    vm.funcTable[ops.I32Sub] = vm.i32Sub


    vm.funcTable[ops.Call] = vm.call


    vm.funcTable[ops.CallIndirect] = vm.callIndirect

vm.call里面就实现了我们上面定义的API:

func (vm *VM) call() {


    index := vm.fetchUint32()



    vm.doCall(vm.compiledFuncs[index], int64(index))



}
func (vm *VM) doCall(compiled compiledFunction, index int64) {


        vm.envCall.envPreCtx = prevCtxt



        v, ok := vm.Services[compiled.name]



        if ok {



            rtn, err := v(vm.Engine)

这里还有一个问题存疑,就是在解析wasm文件时,调用的ONT API是作为外部函数的,解析时会找不到,这个是通过编译器解决的还是其他方式还未看懂。

最后更新于