def instantiate_wasm_invoke_func(filename,funcname,args):
  file_ = open(filename, 'rb')
  if not file_: return "error, could not open "+filename
  bytestar = memoryview(file_.read())
  if not bytestar: return "error, could not read "+filename
  module = wasm.decode_module(bytestar)	#get module as abstract syntax
  #print("module",module)
  if not module: return "error, could not decode "+filename
  store = wasm.init_store()		#do this once for each VM instance
  externvalstar = []			#imports, hopefully none
  store,moduleinst,ret = wasm.instantiate_module(store,module,externvalstar)
  if moduleinst == "error": return "error, module could not be instantiated"
  #print("moduleinst",moduleinst)
  externval = wasm.get_export(moduleinst, funcname)
  if not externval or externval[0]!="func": return "error, "+funcname+" is not a function export of the module"
  #print("externval",externval)
  funcaddr = externval[1]
  valstar = [["i32.const",int(arg)] for arg in args]
  #print("valstar",valstar)
  store,ret = wasm.invoke_func(store,funcaddr,valstar)
  if ret=="trap": return "error, invokation resulted in a trap"
  #print("ret",ret)
  if type(ret)==list and len(ret)>0:
    ret = ret[0]
  return ret
def test_opcode_action_invoke(test, store, modules, registered_modules,
                              moduleinst):
    if verbose > 1: print(test["action"]["field"])
    #print(test["action"])
    if "module" in test["action"]:
        moduleinst = modules[test["action"]["module"]]
    #print("moduleinst",moduleinst)
    #get function name, which could include unicode bytes like \u001b which must be converted to unicode string
    funcname = test["action"]["field"]
    #print("funcname",funcname)
    funcname_with_codepoints_translated = ""
    idx = 0
    utf8_bytes = bytearray()
    for c in funcname:
        utf8_bytes += bytearray([ord(c)])
    utf8_bytes = pywebassembly.spec_binary_uN_inv(len(funcname),
                                                  32) + utf8_bytes
    _, funcname = pywebassembly.spec_binary_name(utf8_bytes, 0)
    #print("funcname",funcname)
    #get function address
    funcaddr = None
    #print(moduleinst["exports"])
    #print("moduleinst",moduleinst)
    #print("ok moduleinst",moduleinst)
    #print("test ok",test)
    for export in moduleinst["exports"]:
        #print("export[\"name\"]",export["name"])
        if export["name"] == funcname:
            funcaddr = export["value"][1]
    if verbose > 2: print("funcaddr", funcaddr)
    #print("funcaddr",funcaddr)
    #funcbody = store["funcs"][funcaddr]["code"]["body"]
    #print(pywebassembly.print_tree_expr(funcbody))
    #get args
    args = []
    float_flag = 0
    #print(test["action"]["args"])
    for idx in range(len(test["action"]["args"])):
        type_ = test["action"]["args"][idx]["type"]
        value = test["action"]["args"][idx]["value"]
        value = int(
            value)  #wabt outputs integers (even floats are encoded as ints)
        if type_ in {"f32", "f64"}:
            if verbose > 1: print("found float arg so skipping")
            float_flag = 1  #this is a hack to avoid floating point until implemented
            value = int2float(int(type_[1:]), value)
        args += [[type_ + ".const", value]]
    #print("args: ",args)
    #invoke func
    ret = []
    #if not float_flag:
    _, ret = pywebassembly.invoke_func(store, funcaddr, args)
    #else:
    #  num_tests_tried-=1
    return ret
Example #3
0
File: juno.py Project: lrettig/juno
def juno_execute(state, msg, tx_context, computation):
    logger = logging.getLogger('juno')

    code = computation.code
    gas = msg.gas
    args = msg.data

    if not has_wasm_preamble(code):
        raise Exception("Invalid code")

    logger.debug('juno_execute')
    # if VERBOSE>1: print("call_contract(",moduleid,funcname,arg,gas,")")
    # spin-up a VM instance with eei module
    modules = {}			#all moduleinst's indexed by their names, used to call funcs and resolve exports
    registered_modules = {}	#all moduleinst's which can be imported from, indexed by their registered name
    store = wasm.init_store()	#done once and lasts for lifetime of this abstract machine
    instantiate_eei_module(store,modules,gas)	#instantiate the EEI module "ethereum"
    registered_modules["ethereum"] = modules["ethereum"] 		#register module "ethereum" to be import-able
    # instantiate module which contains the func to-be-called
    # module_as_bytes = trinity.get_module_as_bytes(moduleid)	#TODO: need API to get module bytes
    module = wasm.decode_module(code)		#get module as abstract syntax
    externvalstar = []					#populate imports
    for import_ in module["imports"]:
        if import_["module"] not in registered_modules:
            logger.error('module not in registered_modules')
            return -1, -1
        importmoduleinst = registered_modules[import_["module"]]
        externval = None
        for export in importmoduleinst["exports"]:
            if export["name"] == import_["name"]:
                externval = export["value"]
        if externval == None:
            logger.error('Missing import')
            return None #error
        if externval[0] != import_["desc"][0]:
            logger.error('Bad imported function signature')
            return None #error
        externvalstar += [externval]
    store,moduleinst,ret = wasm.instantiate_module(store,module,externvalstar)
    # finally, call the function
    externval = wasm.get_export(moduleinst, "main")	#we want to call function "main"
    funcaddr = externval[1]				#the address of the funcname
    store,ret = wasm.invoke_func(store,funcaddr,args)	#finally, invoke the function
    print("Initial gas was ", gas, ", gas left is ", store["gasLeft"])
    computation.consume_gas(gas - store["gasLeft"], "juno")
Example #4
0
def test_opcode_action_invoke(test, store, modules, registered_modules,
                              moduleinst):
    if verbose > 1: print(test["action"]["field"])
    if "module" in test["action"]:
        moduleinst = modules[test["action"]["module"]]
    #get function name, which could include unicode bytes like \u001b which must be converted to unicode string
    funcname = test["action"]["field"]
    funcname_with_codepoints_translated = ""
    idx = 0
    utf8_bytes = binary_format.spec_binary_name_inv(funcname)
    _, funcname = binary_format.spec_binary_name(utf8_bytes, 0)
    #get function address
    funcaddr = None
    for export in moduleinst["exports"]:
        if export["name"] == funcname:
            funcaddr = export["value"][1]
    if verbose > 2: print("funcaddr", funcaddr)
    #get args
    args = []
    float_flag = 0
    for idx in range(len(test["action"]["args"])):
        type_ = test["action"]["args"][idx]["type"]
        value = test["action"]["args"][idx]["value"]
        value = int(
            value)  #wabt outputs integers (even floats are encoded as ints)
        if type_ in {"f32", "f64"}:
            if verbose > 1: print("found float arg so skipping")
            float_flag = 1  #this is a hack to avoid floating point until implemented
            value = int2float(int(type_[1:]), value)
        args += [[type_ + ".const", value]]
    #invoke func
    ret = []
    #if not float_flag:
    _, ret = wasm.invoke_func(store, funcaddr, args)
    #else:
    #  num_tests_tried-=1
    return ret
modules["mod1"] = moduleinst

#instantiate second module
file_ = open('mod2.wasm', 'rb')
bytecode = memoryview(
    file_.read())  #can also use bytearray or bytes instead of memoryview
module = wasm.decode_module(bytecode)  #get module as abstract syntax
externvalstar = []  #imports, none for fibonacci.wasm
for import_ in module[
        "imports"]:  #for each import, look for it's matching export
    importmoduleinst = modules[import_["module"]]
    externval = None
    for export in importmoduleinst["exports"]:
        if export["name"] == import_["name"]:
            externval = export["value"]
    if externval[0] != import_["desc"][0]:
        print("unlinkable"
              )  #error: import type (func, table, mem, globa) doesn't match
    externvalstar += [externval]
store, moduleinst, ret = wasm.instantiate_module(store, module, externvalstar)
modules["mod2"] = moduleinst

#call function
externval = wasm.get_export(modules["mod2"],
                            "f1")  #we want to call the function "fib"
funcaddr = externval[1]  #the address of the funcinst for "fib"
store, ret = wasm.invoke_func(store, funcaddr,
                              [])  #finally, invoke the function

print(ret)  #list of return values, limitted to one value in Wasm 1.0
Example #6
0
  def exec_(self, calldata):
    """
      The following function is used to call a given contract.
      This will "spin-up" a new VM, execute the contract, and output the contract's return values and gas used.
    """
    self.calldata = calldata[:]

    # spin-up a VM
    modules = {}		# all moduleinst's indexed by their names, used to call funcs and resolve exports
    registered_modules = {}	# all moduleinst's which can be imported from, indexed by their registered name
    store = wasm.init_store()	# done once and lasts for lifetime of this abstract machine

    # create host module
    def eth2_loadPreStateRoot(store,arg):
      if verbose: print("eth2_loadPreStateRoot")
      offset = arg[0]
      self.module_memory[offset:offset+32] = self.state_root[:]
      return store,[]

    def eth2_blockDataSize(store,arg):
      if verbose: print("eth2_blockDataSize", len(self.calldata))
      return store,[len(self.calldata)]

    def eth2_blockDataCopy(store,arg):
      if verbose: print("eth2_blockDataCopy")
      memory_offset = arg[0]
      calldata_offset = arg[1]
      length = arg[2]
      self.module_memory[memory_offset:memory_offset+length] = self.calldata[calldata_offset:calldata_offset+length]
      return store,[]

    def eth2_savePostStateRoot(store,arg):
      if verbose: print("eth2_savePostStateRoot", arg[0])
      offset = arg[0]
      self.state_root[:] = self.module_memory[offset:offset+32]
      return store,[]

    def eth2_pushNewDeposit(store,arg):
      if verbose: print("eth2_pushNewDeposit")
      offset = arg[0]
      length = arg[1]
      return store,[]

    def eth2_debugPrintMem(store,arg):
      if verbose: print("eth2_debugPrintMem")
      offset = arg[0]
      length = arg[1]
      print(self.module_memory[offset:offset+length])
      return store,[]

    wasm.alloc_func(store, [["i32"],[]], eth2_loadPreStateRoot)
    wasm.alloc_func(store, [[],["i32"]], eth2_blockDataSize)
    wasm.alloc_func(store, [["i32","i32","i32"],[]], eth2_blockDataCopy)
    wasm.alloc_func(store, [["i32"],[]], eth2_savePostStateRoot)
    wasm.alloc_func(store, [["i32","i32"],[]], eth2_pushNewDeposit)
    wasm.alloc_func(store, [["i32","i32"],[]], eth2_debugPrintMem)
    modules["env"] =      {"types":[[["i32"],[]],
                                    [[],["i32"]],
                                    [["i32","i32","i32"],[]],
                                    [["i32","i32"],[]],
                                   ],
                           "funcaddrs":[0,1,2,3,4,5],
                           "tableaddrs":[],
                           "memaddrs":[],
                           "globaladdrs":[],
                           "exports":[{"name":"eth2_loadPreStateRoot","value":["func",0]},
                                      {"name":"eth2_blockDataSize","value":["func",1]},
                                      {"name":"eth2_blockDataCopy","value":["func",2]},
                                      {"name":"eth2_savePostStateRoot","value":["func",3]},
                                      {"name":"eth2_pushNewDeposit","value":["func",4]},
                                      {"name":"eth2_debugPrintMem","value":["func",5]},
                                     ]
                          }

    # register the host module
    registered_modules["env"] = modules["env"]           		#register module "ethereum" to be import-able

    # instantiate module which contains the func to-be-called
    module = wasm.decode_module(self.bytecode)                          #get module as abstract syntax
    externvalstar = []			           	                #populate imports
    for import_ in module["imports"]:
      if import_["module"] not in registered_modules: return None #error
      importmoduleinst = registered_modules[import_["module"]]
      externval = None
      for export in importmoduleinst["exports"]:
        if export["name"] == import_["name"]:
          externval = export["value"]
      if externval == None: return None #error
      if externval[0] != import_["desc"][0]: return None #error
      externvalstar += [externval]
    store,moduleinst,ret = wasm.instantiate_module(store,module,externvalstar)

    # get its memory
    self.module_memory = store["mems"][0]["data"]

    # finally, call the function
    externval = wasm.get_export(moduleinst, "main")	#we want to call function "main"
    funcaddr = externval[1]				#the address of the funcname
    args = []
    store,ret = wasm.invoke_func(store,funcaddr,args)	#finally, invoke the function
    return ret