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 instantiate_wasm_invoke_start(filename): 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" return ret
def run_test_file(jsonfilename): d = None with open(jsonfilename) as f: d = json.load(f) if d == None: return -1 #print(d) #print(json.dumps(d,indent=2)) if "source_filename" not in d: print("this may not be a valid wabt test file") return -1 if verbose > -1: print("\nrunning tests in " + d["source_filename"]) tests = d["commands"] 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 = pywebassembly.init_store( ) #done once and lasts for lifetime of this abstract machine instantiate_spectest_module( store, modules, registered_modules) #module "spectest" is imported from by many tests registered_modules["spectest"] = modules[ "spectest"] #register module "spectest" to be import-able moduleinst = None num_tests_passed = 0 num_tests_tried = 0 for idx, test in enumerate(tests): #iterate over tests in this file if verbose > 1: print("\ntest #", idx, test["type"]) num_tests_tried += 1 if test["type"] == "module": #module store, moduleinst = test_opcode_module(test, store, modules, registered_modules) if moduleinst: num_tests_passed += 1 elif test["type"] == "register": #register test_opcode_register(test, store, modules, registered_modules, moduleinst) num_tests_passed += 1 elif test["type"] == "action": #action test_opcode_action(test, store, modules, registered_modules, moduleinst) num_tests_passed += 1 elif test["type"][:7] == "assert_": #assertion ret = test_opcode_assertion(test, store, modules, registered_modules, moduleinst) if test["type"] not in {"assert_return", "assert_trap"}: num_tests_tried -= 1 #hack to only count assert_... that are implemented if ret == "success": num_tests_passed += 1 if verbose > -1: print( "Passed", num_tests_passed, "out of", num_tests_tried, "tests" ) #"(actually, there are ",len(tests),"total tests, some test opcodes not implemented yet)")
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")
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. """ import sys sys.path.append('..') import pywebassembly as wasm #set up VM for multiple modules store = wasm.init_store() #do this once for each VM instance modules = { } #all moduleinst's indexed by their names, used to call funcs and resolve exports #instantiate first module file_ = open('mod1.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 store, moduleinst, ret = wasm.instantiate_module(store, module, externvalstar) #register this module instance so it can be imported from modules["mod1"] = moduleinst #instantiate second module
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