def clear_testnet_cache(verbosity=None): ''' Remove wallet files associated with the current testnet. ''' if not setup.file_prefix(): return logger.TRACE(''' Removing testnet cache for prefix `{}` '''.format(setup.file_prefix())) kill_keosd() # otherwise the manager may protects the wallet files dir = wallet_dir() files = os.listdir(dir) try: for file in files: if file.startswith(setup.file_prefix()): os.remove(os.path.join(dir, file)) except Exception as e: raise errors.Error(''' Cannot remove testnet cache. The error message is: {} '''.format(str(e))) logger.TRACE(''' Testnet cache successfully removed. ''')
def remove_key(self, account_or_key): ''' ''' self.open_unlock() removed_keys = [] account_name = None if isinstance(account_or_key, interface.Account): cleos.WalletRemove_key(interface.key_arg(account_or_key, is_owner_key=True, is_private_key=True), self.name, is_verbose=False) removed_keys.append( interface.key_arg(account_or_key, is_owner_key=True, is_private_key=False)) cleos.WalletRemove_key(interface.key_arg(account_or_key, is_owner_key=False, is_private_key=True), self.name, is_verbose=False) removed_keys.append( interface.key_arg(account_or_key, is_owner_key=False, is_private_key=False)) else: cleos.WalletRemove_key(interface.key_arg(account_or_key, is_private_key=True), self.name, is_verbose=False) removed_keys.append( interface.key_arg(account_or_key, is_private_key=False)) if account_name is None: if len(removed_keys) > 0: logger.TRACE( ''' Removing key '{}' from the wallet '{}' '''.format(removed_keys[0], self.name), verbosity) else: logger.TRACE(''' Removing keys of the account '{}' from the wallet '{}' '''.format(account_name, self.name)) wallet_keys = cleos.WalletKeys(is_verbose=False) for key in removed_keys: if key in wallet_keys.json: raise errors.Error(''' Failed to remove key '{}' from the wallet '{}' '''.format(key, self.name)) logger.TRACE(''' * Cross-checked: all listed keys removed from the wallet. ''') return True
def put_account_to_wallet_and_on_stack( account_object_name, account_object, logger=None): if logger is None: logger = account_object global wallet_singleton global wallet_globals if account_object.owner_key: if wallet_singleton.keys_in_wallets([account_object.owner_key.key_private, \ account_object.active_key.key_private]): wallet_singleton.map_account(account_object_name, account_object) else: if wallet_singleton.import_key(account_object): wallet_singleton.map_account(account_object_name, account_object) else: logger.TRACE(''' Wrong or missing keys for the account ``{}`` in the wallets. '''.format(account_object.name)) return False # export the account object to the globals in the wallet module: global wallet_globals wallet_globals[account_object_name] = account_object account_object.in_wallet_on_stack = True return True
def unlock(self): ''' Unlock the wallet. Returns `WalletUnlock` object. ''' result = cleos.WalletUnlock(self.name, self.password, is_verbose=False) logger.TRACE(''' * Wallet ``{}`` unlocked. '''.format(self.name))
def open(self): ''' Opens the wallet. Returns `WalletOpen` object ''' result = cleos.WalletOpen(self.name, is_verbose=False) logger.TRACE(''' * Wallet ``{}`` opened. '''.format(self.name))
def __init__( self, account_object_name, name=None, owner_key=None, active_key=None, verbosity=None): self.account_object_name = account_object_name if name is None: self.name = cleos.account_name() else: self.name = name if active_key is None: active_key = owner_key self.exists = False self.in_wallet_on_stack = False #self.has_keys = owner_key and not owner_key.key_private is None self.has_keys = not owner_key is None try: cleos.GetAccount.__init__( self, self.name, is_info=False, is_verbose=False) except errors.AccountDoesNotExistError: return self.exists = True if owner_key is None: self.owner_key = cleos.CreateKey( "owner", self.json["permissions"][1]["required_auth"]["keys"] \ [0]["key"], is_verbose=0) else: # an orphan account, private key is restored from cache self.owner_key = cleos.CreateKey( "owner", self.json["permissions"][1]["required_auth"]["keys"] \ [0]["key"], interface.key_arg( owner_key, is_owner_key=True, is_private_key=True), is_verbose=0) if active_key is None: self.owner_key = cleos.CreateKey( "owner", self.json["permissions"][0]["required_auth"]["keys"] \ [0]["key"], is_verbose=0) else: # an orphan account, private key is restored from cache self.active_key = cleos.CreateKey( "active", self.json["permissions"][0]["required_auth"]["keys"] \ [0]["key"], interface.key_arg( active_key, is_owner_key=False, is_private_key=True), is_verbose=0) logger.TRACE(''' * Account ``{}`` exists in the blockchain. '''.format(self.name))
def __init__(self, name=None, password="", verbosity=None, file=False): cleos.set_local_nodeos_address_if_none() if name is None: name = setup.wallet_default_name else: name = setup.file_prefix() + name if not self.wallet is None: raise errors.Error(''' It can be only one ``Wallet`` object in the script; there is one named ``{}``. '''.format(wallet.name)) return self.wallet_dir = manager.wallet_dir() logger.INFO(''' * Wallet name is ``{}``, wallet directory is {}. '''.format(name, self.wallet_dir)) if not password: # look for password: passwords = wallet_json_read() if name in passwords: password = passwords[name] logger.INFO( ''' The password is restored from the file: {} '''.format( os.path.join(self.wallet_dir, setup.password_map)), verbosity) cleos.WalletCreate.__init__(self, name, password, is_verbose=False) if self.is_created: # new password logger.INFO( ''' * Created wallet ``{}``. '''.format(self.name), verbosity) if manager.is_local_testnet() or file: password_map = wallet_json_read() password_map[name] = self.password wallet_json_write(password_map) logger.INFO( ''' * Password is saved to the file ``{}`` in the wallet directory. '''.format(setup.password_map), verbosity) else: logger.OUT(self.out_msg) else: logger.TRACE(''' Opened wallet ``{}`` '''.format(self.name))
def deploy(self, permission=None, dont_broadcast=None, payer=None): if not self.is_built(): raise errors.Error(''' Contract needs to be built before deployment. ''') return if dont_broadcast is None: dont_broadcast = self.dont_broadcast try: result = cleos.SetContract(self.account, self.contract_dir, self.wasm_file, self.abi_file, permission, self.expiration_sec, self.skip_signature, dont_broadcast, self.forceUnique, self.max_cpu_usage, self.max_net_usage, self.ref_block, is_verbose=False, json=True) except errors.LowRamError as e: logger.TRACE(''' * RAM needed is {}.kByte, buying RAM {}.kByte. '''.format(e.needs_kbyte, e.deficiency_kbyte)) buy_ram_kbytes = str(e.deficiency_kbyte + 1) if not payer: payer = self.account payer.buy_ram(buy_ram_kbytes, self.account) result = cleos.SetContract(self.account, self.contract_dir, self.wasm_file, self.abi_file, permission, self.expiration_sec, self.skip_signature, dont_broadcast, self.forceUnique, self.max_cpu_usage, self.max_net_usage, self.ref_block, is_verbose=False, json=True) logger.INFO(''' * Contract {} is deployed. '''.format(self.contract_dir)) self.contract = result
def keys(self): ''' Lists public keys from all unlocked wallets. Returns `cleos.WalletKeys` object. ''' self.open_unlock() self.wallet_keys = cleos.WalletKeys(is_verbose=False) logger.TRACE(''' Keys in all open walets: {} '''.format(self.wallet_keys.out_msg))
def is_local_testnet_running(): account_ = cleos.GetAccount(self.name, is_info=False, is_verbose=False) if not account_.error and \ self.key_public == \ account_.json["permissions"][0]["required_auth"]["keys"] \ [0]["key"]: self.account_info = str(account_) logger.TRACE(''' Local testnet is ON: the `eosio` account is master. ''') return True else: return False
def map_account(self, account_object_name, account_object): ''' ''' if not self.is_name_taken(account_object_name, account_object.name): account_map_json = manager.account_map(self) if account_map_json is None: return account_map_json[account_object.name] = account_object_name with open(self.wallet_dir + setup.account_map, "w") as out: out.write( json.dumps(account_map_json, indent=3, sort_keys=True)) logger.TRACE(''' * Account object ``{}`` stored in the file ``{}`` in the wallet directory: {} '''.format(account_object_name, setup.account_map, self.wallet_dir + setup.account_map))
def import_key(self, account_or_key): ''' Imports private keys of an account into wallet. Returns list of `cleos.WalletImport` objects ''' self.open_unlock() imported_keys = [] account_name = None if isinstance(account_or_key, interface.Account): account_name = account_or_key.name wallet_import = cleos.WalletImport(interface.key_arg( account_or_key, is_owner_key=True, is_private_key=True), self.name, is_verbose=False) imported_keys.append( interface.key_arg(account_or_key, is_owner_key=True, is_private_key=False)) wallet_import = cleos.WalletImport(interface.key_arg( account_or_key, is_owner_key=False, is_private_key=True), self.name, is_verbose=False) imported_keys.append( interface.key_arg(account_or_key, is_owner_key=False, is_private_key=False)) logger.TRACE(''' * Importing keys of the account ``{}`` into the wallet ``{}`` '''.format(account_name, self.name)) else: wallet_import = cleos.WalletImport(interface.key_arg( account_or_key, is_private_key=True), self.name, is_verbose=False) logger.TRACE(''' * Importing keys into the wallet ``{}`` '''.format(self.name)) return True wallet_keys = cleos.WalletKeys(is_verbose=False) if len(imported_keys) == 0: raise errors.Error(''' The list of imported keys is empty. ''') ok = True for key in imported_keys: if not key in wallet_keys.json: ok = False raise errors.Error(''' Failed to import keys of the account '{}' into the wallet '{}' '''.format(account_name if account_name else "n/a", self.name)) if ok: logger.TRACE(''' * Cross-checked: all account keys are in the wallet. ''') return True
def create_master_account( account_object_name, account_name=None, owner_key=None, active_key=None, verbosity=None): '''Create account object in caller's global namespace. - **parameters**:: account_object_name:: the name of the account object account_name: the name of the account; random, if not set verbosity: argument to the internal logger ### Preconditions Check the following conditions: * precisely one ``Wallet`` object is defined; ### Local testnet If the local testnet is running, create an account object representing the ``eosio`` account. Put the account into the wallet. Put the account object into the global namespace of the caller, and **return**. ### Remote testnet Otherwise, an outer testnet has to be defined with ``setup.set_nodeos_address(<url>)``. ### Existing account If the ``account_name`` argument is set, check the testnet for presence of the account. If present, create the corresponding object and put the account into the wallet, and put the account object into the global namespace of the caller. and **return**. Otherwise start a registration procedure, described in the next paragraph. ### Registration to a remote testnet If the ``account_name`` argument is not set or it does not address any existing account, see the previous paragraph, start a registration procedure. * if the ``account_name`` argument is not set, make it random * print registration data, namely: * account name * owner public key * active public key * owner private key * active private key * wait for the user to register the master account * . . . . * detect the named account on the remote testnet * put the account into the wallet * put the account object into the global namespace of the caller ### Name conflict between account objects If the new account object is going to be added to the wallet, an error is reported. Then an offer is given to edith the mapping file in order to resolve the conflict. When the conflict is resolved, the procedure finishes successfully. ''' globals = inspect.stack()[1][0].f_globals if account_object_name: # account_object_name==None in register_testnet ''' Check the conditions: * a ``Wallet`` object is defined. * the account object name is not in use, already. ''' is_wallet_defined(logger, globals) global wallet_singleton if wallet_singleton is None: return if account_object_name in globals: if not isinstance(globals[account_object_name], interface.Account): raise errors.Error(''' The global variable {} type is not ``Account``. '''.format(account_object_name)) return logger.INFO(''' ######## Account object ``{}`` restored from the blockchain. '''.format(account_object_name)) return #wallet_singleton.is_name_taken(account_object_name, account_name) if isinstance(account_name, testnet.Testnet): owner_key = account_name.owner_key active_key = account_name.active_key account_name = account_name.account_name logger.INFO(''' ######### Create a master account object ``{}``. '''.format(account_object_name)) ''' If the local testnet is running, create an account object representing the ``eosio`` account. Put the account into the wallet. Put the account object into the global namespace of the caller, and **return**. ''' account_object = Eosio(account_object_name) if is_local_testnet_running(account_object): put_account_to_wallet_and_on_stack( account_object_name, account_object, logger) return ''' Otherwise, an outer testnet has to be defined with ``setup.set_nodeos_address(<url>)``. ''' if manager.is_local_testnet(): raise errors.Error(''' If the local testnet is not running, an outer testnet has to be defined with `setup.set_nodeos_address(<url>)`. Use 'setup.set_nodeos_address(<URL>)' ''') return ''' If the ``account_name`` argument is not set, it is randomized. Check the testnet for presence of the account. If present, create the corresponding object and see whether it is in the wallets. If so, put the account object into the global namespace of the caller. and **return**. ''' first_while = True while True: account_object = GetAccount( account_object_name, account_name, owner_key, active_key, verbosity) if first_while and account_name and owner_key and active_key \ and not account_object.exists: raise errors.Error(''' There is no account named ``{}`` in the blockchain. '''.format(account_name)) return first_while = False if account_object.exists: if account_object.has_keys: # it is your account logger.TRACE(''' * Checking whether the wallet has keys to the account ``{}`` '''.format(account_object.name)) logger.TRACE(''' * The account object is created. ''') if account_object_name: if append_account_methods_and_finish( account_object_name, account_object): logger.TRACE(''' * The account ``{}`` is in the wallet. '''.format(account_object.name)) return else: return account_object else: # the name is taken by somebody else logger.TRACE(''' ### You can try another name. Do you wish to do this? ''') decision = input("y/n <<< ") if decision == "y": account_name = input( "enter the account name or nothing to make the name random <<< ") else: return else: owner_key_new = cleos.CreateKey("owner", is_verbose=False) active_key_new = cleos.CreateKey("active", is_verbose=False) logger.OUT(''' Use the following data to register a new account on a public testnet: Account Name: {} Owner Public Key: {} Active Public Key: {} Owner Private Key: {} Active Private Key: {} '''.format( account_object.name, owner_key_new.key_public, active_key_new.key_public, owner_key_new.key_private, active_key_new.key_private )) while True: is_ready = input("enter 'go' when ready or 'q' to quit <<< ") if is_ready == "q": return else: if is_ready == "go": break account_name = account_object.name owner_key = owner_key_new active_key = active_key_new
def create_account( account_object_name, creator, account_name="", owner_key="", active_key="", stake_net=3, stake_cpu=3, permission=None, buy_ram_kbytes=8, buy_ram="", transfer=False, expiration_sec=30, skip_signature=0, dont_broadcast=0, forceUnique=0, max_cpu_usage=0, max_net_usage=0, ref_block=None, restore=False, verbosity=None): global wallet_singleton globals = inspect.stack()[1][0].f_globals ''' Check the conditions: * a ``Wallet`` object is defined; * the account object name is not in use, already. ''' is_wallet_defined(logger) if wallet_singleton is None: return #wallet_singleton.is_name_taken(account_object_name, account_name) if account_object_name in globals: if not isinstance(globals[account_object_name], interface.Account): raise errors.Error(''' The global variable ``{}`` type is not ``Account``. '''.format(account_object_name)) return logger.INFO(''' ######## Account object ``{}`` restored from the blockchain. '''.format(account_object_name)) return logger.INFO(''' ######### Create an account object ``{}``. '''.format(account_object_name)) ''' Create an account object. ''' account_object = None if restore: if creator: account_name = creator logger.INFO(''' ... for an existing blockchain account ``{}`` mapped as ``{}``. '''.format(account_name, account_object_name), translate=False) account_object = RestoreAccount(account_name, verbosity) account_object.account_object_name = account_object_name else: if not account_name: account_name = cleos.account_name() if owner_key: if not active_key: active_key = owner_key else: owner_key = cleos.CreateKey("owner", is_verbose=False) active_key = cleos.CreateKey("active", is_verbose=False) if stake_net and not manager.is_local_testnet(): logger.INFO(''' ... delegating stake to a new blockchain account ``{}`` mapped as ``{}``. '''.format(account_name, account_object_name)) try: account_object = SystemNewaccount( creator, account_name, owner_key, active_key, stake_net, stake_cpu, permission, buy_ram_kbytes, buy_ram, transfer, expiration_sec, skip_signature, dont_broadcast, forceUnique, max_cpu_usage, max_net_usage, ref_block, verbosity ) except errors.LowRamError as e: logger.TRACE(''' * RAM needed is {}.kByte, buying RAM {}.kByte. '''.format( e.needs_kbyte, e.deficiency_kbyte)) buy_ram_kbytes = str( e.deficiency_kbyte + 1) account_object = SystemNewaccount( creator, account_name, owner_key, active_key, stake_net, stake_cpu, permission, buy_ram_kbytes, buy_ram, transfer, expiration_sec, skip_signature, dont_broadcast, forceUnique, max_cpu_usage, max_net_usage, ref_block, verbosity ) else: logger.INFO(''' ... for a new blockchain account ``{}``. '''.format(account_name)) account_object = CreateAccount( creator, account_name, owner_key, active_key, permission, expiration_sec, skip_signature, dont_broadcast, forceUnique, max_cpu_usage, max_net_usage, ref_block, verbosity ) account_object.account_object_name = account_object_name account_object.owner_key = owner_key account_object.active_key = active_key logger.TRACE(''' * The account object is created. ''') append_account_methods_and_finish(account_object_name, account_object)
def lock_all(self): ''' Lock the wallet. Returns `cleos.WalletLock` object. ''' result = cleos.WalletLockAll(is_verbose=False) logger.TRACE("All wallets locked.")
def lock(self): ''' Lock the wallet. Returns `cleos.WalletLock` object. ''' result = cleos.WalletLock(self.name, is_verbose=False) logger.TRACE("Wallet `{}` locked.".format(self.name))
def append_account_methods_and_finish(account_object_name, account_object): def code(account_object, code="", abi="", wasm=False): result = cleos.GetCode(account_object, code, abi, is_verbose=False) logger.INFO(''' * code() ''') logger.OUT(result.out_msg) account_object.code = types.MethodType(code, account_object) def is_code(account_object): get_code = cleos.GetCode(account_object.name, is_verbose=False) if get_code.code_hash == \ "0000000000000000000000000000000000000000000000000000000000000000": return "" else: return get_code.code_hash account_object.is_code = types.MethodType(is_code, account_object) def set_contract( account_object, contract_dir, wast_file="", abi_file="", permission=None, expiration_sec=30, skip_signature=0, dont_broadcast=0, forceUnique=0, max_cpu_usage=0, max_net_usage=0, ref_block=None): result = cleos.SetContract( account_object, contract_dir, wast_file, abi_file, permission, expiration_sec, skip_signature, dont_broadcast, forceUnique, max_cpu_usage, max_net_usage, ref_block, is_verbose=False ) logger.OUT(result) account_object.set_contract = result account_object.set_contract = types.MethodType( set_contract , account_object) def push_action( account_object, action, data, permission=None, expiration_sec=30, skip_signature=0, dont_broadcast=0, forceUnique=0, max_cpu_usage=0, max_net_usage=0, ref_block=None, json=False): data = _data_json(data) result = cleos.PushAction( account_object, action, data, permission, expiration_sec, skip_signature, dont_broadcast, forceUnique, max_cpu_usage, max_net_usage, ref_block, is_verbose=False, json=True) logger.INFO(''' * Push action ``{}``: '''.format(action)) logger.INFO(''' {} '''.format(re.sub(' +',' ', data))) account_object.action = result try: account_object._console = result.console logger.DEBUG(account_object._console) except: pass if json: logger.OUT(result.out_msg) account_object.action = result account_object.push_action = types.MethodType( push_action, account_object) def show_action(account_object, action, data, permission=None): ''' Implements the `push action` command without broadcasting. ''' account_object.push_action( action, data, permission, dont_broadcast=1, json=True) account_object.show_action = types.MethodType( show_action, account_object) def table( account_object, table_name, scope="", binary=False, limit=10, key="", lower="", upper=""): logger.INFO(''' * Table ``{}`` for ``{}`` '''.format(table_name, scope)) result = cleos.GetTable( account_object, table_name, scope, binary, limit, key, lower, upper, is_verbose=False) try: account_map = manager.account_map() scope = account_map[str(scope)] except: pass logger.OUT(result.out_msg) return result account_object.table = types.MethodType(table, account_object) def __str__(account_object): return account_object.name account_object.__str__ = types.MethodType(__str__, account_object) def buy_ram( account_object, amount_kbytes, receiver=None, expiration_sec=30, skip_signature=0, dont_broadcast=0, forceUnique=0, max_cpu_usage=0, max_net_usage=0, ref_block=None): if manager.is_local_testnet(): return if receiver is None: receiver = account_object buy_ram_kbytes = 1 result = cleosys.BuyRam( account_object, receiver, amount_kbytes, buy_ram_kbytes, expiration_sec, skip_signature, dont_broadcast, forceUnique, max_cpu_usage, max_net_usage, ref_block, is_verbose=0 ) logger.INFO(''' * Transfered RAM from {} to {} kbytes: {} '''.format(result.payer, result.receiver, result.amount)) account_object.buy_ram = types.MethodType(buy_ram, account_object) def delegate_bw( account_object, stake_net_quantity, stake_cpu_quantity, receiver=None, permission=None, transfer=False, expiration_sec=30, skip_signature=0, dont_broadcast=0, forceUnique=0, max_cpu_usage=0, max_net_usage=0, ref_block=None, is_verbose=1): if manager.is_local_testnet(): return if receiver is None: receiver = account_object result = cleosys.DelegateBw( account_object, receiver, stake_net_quantity, stake_cpu_quantity, permission, transfer, expiration_sec, skip_signature, dont_broadcast, forceUnique, max_cpu_usage, max_net_usage, ref_block, is_verbose=0 ) logger.INFO(''' * Delegated stake from {} to {} NET: {} CPU: {} '''.format( result.payer, result.receiver, result.stake_net_quantity, result.stake_cpu_quantity)) account_object.delegate_bw = types.MethodType(delegate_bw, account_object) def info(account_object): print("Account object name: {}\n{}".format( account_object_name, str(cleos.GetAccount(account_object.name, is_verbose=0)))) account_object.info = types.MethodType(info, account_object) get_account = cleos.GetAccount(account_object, is_info=False, is_verbose=0) logger.TRACE(''' * Cross-checked: account object ``{}`` mapped to an existing account ``{}``. '''.format(account_object_name, account_object.name), translate=False) return put_account_to_wallet_and_on_stack( account_object_name, account_object)
def ABI(contract_dir_hint=None, code_name=None, include_dir=None): '''Given a hint to a contract directory, produce ABI file. ''' contract_dir = config.getContractDir(contract_dir_hint) srcs = config.getContractSourceFiles(contract_dir) if not srcs: raise errors.Error(''' "The source is empty. The assumed contract dir is {} '''.format(contract_dir)) return targetDirPath = getTargetDirPath(contract_dir) for src in srcs: srcPath = src if os.path.splitext(src)[1].lower() == ".abi": logger.INFO(''' NOTE: An ABI exists in the source directory. Cannot overwrite it: {} Just copying it to the target directory. '''.format(src)) shutil.move(srcPath, os.path.join(targetDirPath, os.path.basename(srcPath))) return sourcePath = srcs[0] source_dir = os.path.dirname(srcs[0]) if not code_name: code_name = os.path.splitext(os.path.basename(srcs[0]))[0] command_line = [ config.get_eosio_abigen(), "-extra-arg=-c", "-extra-arg=--std=c++14", "-extra-arg=--target=wasm32", "-extra-arg=-nostdinc", "-extra-arg=-nostdinc++", "-extra-arg=-DABIGEN", "-extra-arg=-I" + config.getSourceDir() + "/contracts/libc++/upstream/include", "-extra-arg=-I" + config.getSourceDir() + "/contracts/musl/upstream/include", "-extra-arg=-I" + config.getSourceDir() + "/externals/magic_get/include", "-extra-arg=-I" + config.getEOSIO_BOOST_INCLUDE_DIR(), "-extra-arg=-I" + config.getSourceDir() + "/contracts", "-extra-arg=-I" + config.getSourceDir() + "/build/contracts", "-extra-arg=-I" + source_dir ] if include_dir: include_dirs = include_dir.split(",") for dir in include_dirs: command_line.append("-extra-arg=-I " + dir) command_line.extend([ "-extra-arg=-fparse-all-comments", "-destination-file=" + os.path.join(targetDirPath, code_name + ".abi"), # "-verbose=" + to_string(verbose), "-context=" + source_dir, sourcePath, "--" ]) if setup.is_print_command_line: print("######## {}:".format(config.get_eosio_abigen())) print(" ".join(command_line)) process(command_line) logger.TRACE(''' ABI file writen to file: {} '''.format(targetDirPath))
def WAST(contract_dir_hint, code_name=None, include_dir=None, compile_only=False): '''Given a hint to a contract directory, produce WAST and WASM code. ''' contract_dir = config.getContractDir(contract_dir_hint) srcs = config.getContractSourceFiles(contract_dir) if not srcs: raise errors.Error(''' "The source is empty. The assumed contract dir is {} '''.format(contract_dir)) return targetPathWast = None target_dir_path = getTargetDirPath(contract_dir) workdir = os.path.join(target_dir_path, "working_dir") if not os.path.exists(workdir): os.makedirs(workdir) workdir_build = os.path.join(workdir, "build") if not os.path.exists(workdir_build): os.mkdir(workdir_build) objectFileList = [] extensions = [".h", ".hpp", ".hxx", ".c", ".cpp", ".cxx", ".c++"] if not code_name: code_name = os.path.splitext(os.path.basename(srcs[0]))[0] targetPathWast = os.path.join(target_dir_path, code_name + ".wast") targetPathWasm = os.path.join(target_dir_path, code_name + ".wasm") for file in srcs: if not os.path.splitext(file)[1].lower() in extensions: continue command_line = [ config.getEOSIO_WASM_CLANG(), "-emit-llvm", "-O3", "--std=c++14", "--target=wasm32", "-nostdinc", #"-DBOOST_DISABLE_ASSERTS -DBOOST_EXCEPTION_DISABLE", "-nostdlib", "-nostdlibinc", "-ffreestanding", "-nostdlib", "-fno-threadsafe-statics", "-fno-rtti", "-fno-exceptions", "-I", config.getSourceDir() + "/contracts/libc++/upstream/include", "-I", config.getSourceDir() + "/contracts/musl/upstream/include", "-I", config.getSourceDir() + "/externals/magic_get/include", "-I", config.getEOSIO_BOOST_INCLUDE_DIR(), "-I", config.getSourceDir() + "/contracts", "-I", config.getSourceDir() + "/build/contracts", "-I", contract_dir ] if include_dir: include_dirs = include_dir.split(",") for dir in include_dirs: command_line.extend(["-I", dir]) output = os.path.join(workdir_build, code_name + ".o") objectFileList.append(output) command_line.extend(["-c", file, "-o", output]) if setup.is_print_command_line: print("######## {}:".format(config.getEOSIO_WASM_CLANG())) print(" ".join(command_line)) try: process(command_line) except Exception as e: try: shutil.rmtree(workdir) except: pass raise errors.Error(str(e)) if not compile_only: command_line = [ config.getEOSIO_WASM_LLVM_LINK(), "-only-needed", "-o", workdir + "/linked.bc", " ".join(objectFileList), config.getSourceDir() + "/build/contracts/musl/libc.bc", config.getSourceDir() + "/build/contracts/libc++/libc++.bc", config.getSourceDir() + "/build/contracts/eosiolib/eosiolib.bc" ] if setup.is_print_command_line: print("######## {}:".format(config.getEOSIO_WASM_LLVM_LINK())) print(" ".join(command_line)) try: process(command_line) except Exception as e: try: shutil.rmtree(workdir) except: pass raise errors.Error(str(e)) command_line = [ config.getEOSIO_WASM_LLC(), "-thread-model=single", "--asm-verbose=false", "-o", workdir + "/assembly.s", workdir + "/linked.bc" ] if setup.is_print_command_line: print("######## {}:".format(config.getEOSIO_WASM_LLC())) print(" ".join(command_line)) try: process(command_line) except Exception as e: raise errors.Error(str(e)) try: shutil.rmtree(workdir) except: pass raise errors.Error(str(e)) command_line = [ config.getEOSIO_S2WASM(), "-o", targetPathWast, "-s", "16384", workdir + "/assembly.s" ] if setup.is_print_command_line: print("######## {}:".format(config.getEOSIO_S2WASM())) print(" ".join(command_line)) try: process(command_line) except Exception as e: try: shutil.rmtree(workdir) except: pass raise errors.Error(str(e)) logger.TRACE(''' WAST file writen to file: {} '''.format(targetPathWast)) command_line = [ config.getEOSIO_WAST2WASM(), targetPathWast, targetPathWasm, "-n" ] if setup.is_print_command_line: print("######## {}:".format(config.getEOSIO_WAST2WASM())) print(" ".join(command_line)) try: process(command_line) except Exception as e: try: shutil.rmtree(workdir) except: pass raise errors.Error(str(e)) logger.TRACE(''' WASM file writen to file: {} '''.format(targetPathWasm)) try: shutil.rmtree(workdir) except: pass
def template_create(project_name, template_name=None, workspace_dir=None, remove_existing=False, open_vscode=False): '''Given the project name and template name, create a smart contract project. ''' project_name = project_name.strip() if not template_name: template_name = config.DEFAULT_TEMPLATE template_name = template_name.strip() if not workspace_dir \ or not os.path.isabs(workspace_dir) \ or not os.path.exists(workspace_dir): workspace_dir = config.getContractWorkspace() workspace_dir = workspace_dir.strip() template_dir = os.path.join(config.getEosFactoryDir(), config.templContractsDir, template_name) if not os.path.exists(template_dir): raise errors.Error(''' TemplateCreate '{}' does not exist. '''.format(template_dir)) project_dir = os.path.join(workspace_dir, project_name) if os.path.exists(project_dir): if remove_existing: try: shutil.rmtree(project_dir) except Exception as e: raise errors.Error(str(e)) else: logger.INFO(''' NOTE: Contract workspace '{}' already exists. Cannot owerwrite it. '''.format(project_dir)) return try: # make contract directory and its build directory: os.makedirs(os.path.join(project_dir, "build")) except Exception as e: raise errors.Error(str(e)) def copy_dir_contents(project_dir, template_dir, directory, project_name): contents = os.listdir(os.path.join(template_dir, directory)) for item in contents: path = os.path.join(directory, item) template_path = os.path.join(template_dir, path) contract_path = os.path.join( project_dir, path.replace(config.TEMPLATE_TOKEN, project_name)) if os.path.isdir(template_path): os.mkdir(contract_path) copy_dir_contents(project_dir, template_dir, path, project_name) elif os.path.isfile(template_path): copy(template_path, contract_path, project_name) def copy(template_path, contract_path, project_name): with open(template_path, "r") as input: template = input.read() template = template.replace("@" + config.TEMPLATE_TOKEN + "@", project_name) with open(contract_path, "w") as output: output.write(template) copy_dir_contents(project_dir, template_dir, "", project_name) logger.TRACE(''' * Contract project '{}' created from template '{}' in directory {} '''.format(project_name, template_name, project_dir)) if open_vscode: if is_windows_ubuntu(): commandLine = "cmd.exe /C code {}".format( utils.wslMapLinuxWindows(project_dir)) elif uname() == "Darwin": commandLine = "open -n -b com.microsoft.VSCode --args {}".format( project_dir) else: commandLine = "code {}".format(project_dir) os.system(commandLine) return project_dir