def invoke(firstarg='0.0.0.0', sport='8787', upnp_str=None, addr_str=None): bindhost, *extrahosts = firstarg.split(',') if len(extrahosts) > 1: raise Exception("too many hosts") elif len(extrahosts) == 1: [ announcehost, ] = extrahosts else: announcehost = None port = int(sport) pnp = get_upnp() if upnp_str == 'upnp' else None if not pnp and not addr_str: # third arg may be addr_str, so swap the args addr_str = upnp_str upnp_str = None addr = None if addr_str: assert Address.is_valid( addr_str), "Invalid donation address specified" addr = Address.from_string(addr_str) return self.start_fusion_server(network, bindhost, port, upnp=pnp, announcehost=announcehost, donation_address=addr)
def donation_address(self, window) -> Optional[Tuple[str, Address]]: ''' Plugin API: Returns a tuple of (description, Address) or None. This is the donation address that we as a client got from the remote server (as opposed to the donation address we announce if we are a server). ''' if self.remote_donation_address and Address.is_valid( self.remote_donation_address): return (self.fullname() + " " + _("Server") + ": " + self.get_server()[0], Address.from_string(self.remote_donation_address))
def delete_history(self, address: Address) -> None: if isinstance(address, str) and Address.is_valid(address): address = Address.from_string(address) storage = self.parent.wallet.storage if self.parent.wallet else None if storage: if True: #with self.lock: addrstr = address.to_storage_string() k = 'contact_history_%s' % (addrstr) storage.put(k, None) self.print_error("Deleted %s" % addrstr)
def get_history(self, address: Address) -> list: ret = list() if isinstance(address, str) and Address.is_valid(address): address = Address.from_string(address) storage = self.parent.wallet.storage if self.parent.wallet else None if storage: addrstr = address.to_storage_string() k = 'contact_history_%s' % (addrstr) hdict = storage.get(k) if hdict: ret = list(hdict.values()) ret.sort(key=lambda x: x[1], reverse=True) return ret
def _open_internal_link(self, target): ''' accepts either a str txid, str address, or a QUrl which should be of the bare form "txid" and/or "address" -- used by the clickable links in the inputs/outputs QTextBrowsers''' if isinstance(target, QUrl): target = target.toString(QUrl.None_) assert target if Address.is_valid(target): # target was an address, open address dialog self.main_window.show_address(Address.from_string(target), parent=self) else: # target was a txid, open new tx dialog self.main_window.do_process_from_txid(txid=target, parent=self)
def doReloadForKey(self, key: Any) -> Any: t0 = time.time() hist = list() unk = False duped = '' if isinstance(key, (type(None), list)): # the common case, 'None' or [Address] hist = get_history(domain=key) # contacts entires elif isinstance(key, contacts.ContactsEntry): hist = get_contact_history(key.address) elif isinstance(key, Address): # support for list-less single Address.. call self again with the proper format hist = self.get([key]) duped = ' (duped) ' elif isinstance(key, str): # support for string addresses or tx_hashes.. detect which and act accordingly if Address.is_valid(key): hist = self.get( [Address.from_string(key)] ) # recursively call self with propery list data type, which will end up calling get_history (it's ok -- this is to cache results uniformly!) duped = ' (duped) ' elif gui.ElectrumGui.gui.wallet and gui.ElectrumGui.gui.wallet.transactions.get( key, None): fullHist = self.get( None ) # recursively call self to get a full history (will be cached so it's ok!) try: hentry = fullHist.get_by_txid(key) hist.append(hentry) except KeyError: pass else: unk = True else: unk = True dstr = str(key) if not isinstance( key, contacts.ContactsEntry ) else '[ContactsEntry: ' + key.address_str + ']' if unk: utils.NSLog( "HistoryMgr: failed to retrieve any data for unknown domain=%s, returning empty list", dstr[:80]) else: time_taken = time.time() - t0 utils.NSLog( "HistoryMgr: refresh %d entries for domain=%s in %f ms%s (hist result type=%s)", len(hist), dstr[:80], time_taken * 1e3, duped, ''.join(list(str(type(hist)))[-19:-2])) gui.ElectrumGui.gui.refresh_cost('history', time_taken) return hist
def doConversion_(self, text) -> bool: self.cash.text = "" self.legacy.text = "" self.cpyCashBut.enabled = False self.cpyLegBut.enabled = False self.qrButShowCash.enabled = False self.qrButShowLegacy.enabled = False text = text.strip() addy = None try: addy = Address.from_string(text) except: pass if addy: self.cash.text = addy.to_full_string(Address.FMT_CASHADDR) self.legacy.text = addy.to_full_string(Address.FMT_LEGACY) self.cpyCashBut.enabled = True self.cpyLegBut.enabled = True self.qrButShowCash.enabled = True self.qrButShowLegacy.enabled = True return True return False
def doVerify(self) -> None: addrtf = self.tf address_str = str(addrtf.text).strip() message = str(self.topTvDel.text) signature = str(self.botTvDel.text).strip() if not signature: parent().show_message( _("Please provide both a signature and a message to verify")) return try: address = Address.from_string(address_str) except: parent().show_error(_('Invalid Ergon address.')) return message = message.encode('utf-8') try: # This can raise on invalid base64 sig = base64.b64decode(signature) verified = bitcoin.verify_message( address, sig, message) # this raises too on failure except: verified = False if verified: parent().show_message(_("Signature verified"), title=_("Success")) else: parent().show_error(_("Wrong signature"))
def on_edited(self, item, column, prior_value): contact = item.data(0, self.DataRoles.Contact) if column == 2: # Label label_key = contact.address try: label_key = Address.from_string(label_key).to_storage_string() except: pass self.wallet.set_label(label_key, item.text(2)) self.update( ) # force refresh in case 2 contacts use the same address return # else.. Name typ = contact.type was_cur, was_sel = bool(self.currentItem()), item.isSelected() name, value = item.text(1), item.text(3) del item # paranoia # On success, parent.set_contact returns the new key (address text) # if 'cashacct'.. or always the same key for all other types. key = self.parent.set_contact(name, value, typ=typ, replace=contact) if key: # Due to deferred updates, on_update will actually be called later. # So, we have to save the edited item's "current" and "selected" # status here. 'on_update' will look at this tuple and clear it # after updating. self._edited_item_cur_sel = (key, was_cur, was_sel)
def make_unsigned_transaction(self, amount, fee, all_inputs, outputs, changes): ''' make unsigned transaction ''' dust = self.dust_threshold( ) # always 546 for now, but this call is here in case something more sophisticated happens in the future coins = {} tx_inputs = [] amounts = {} try: for player in all_inputs: inputs_coins = self.get_coins(all_inputs[player]) # if there are no coins on input it terminates the process if inputs_coins: coins[player] = inputs_coins else: return None except BaseException as e: self.print_error('make_unsigned_transaction:', repr(e)) return None for player, pubkey_utxos in coins.items(): amounts[player] = 0 for pubkey, utxos in pubkey_utxos.items(): for utxo in utxos: utxo['type'] = 'p2pkh' utxo['address'] = Address.from_pubkey(pubkey) utxo['pubkeys'] = [pubkey] utxo['x_pubkeys'] = [pubkey] utxo['prevout_hash'] = utxo['tx_hash'] utxo['prevout_n'] = utxo['tx_pos'] utxo['signatures'] = [None] utxo['num_sig'] = 1 tx_inputs.append(utxo) amounts[player] += utxo['value'] tx_inputs.sort(key=lambda x: x['prevout_hash'] + str(x["tx_pos"])) tx_outputs = [(TYPE_ADDRESS, Address.from_string(output), int(amount)) for output in outputs] transaction = Transaction.from_io(tx_inputs, tx_outputs, sign_schnorr=False) tx_changes = [ (TYPE_ADDRESS, Address.from_string(changes[player]), int(amounts[player] - amount - fee)) for player in sorted(changes) if Address.is_valid(changes[player]) and int(amounts[player] - amount - fee) >= dust ] transaction.add_outputs(tx_changes) return transaction
def view_addr_link_activated(addr): if isinstance(parent, ElectrumWindow): try: address = Address.from_string(addr) parent.show_address(address, parent=parent.top_level_window()) except Exception as e: parent.print_error(repr(e))
def decodeAddress(addr: str) -> Address: ret = None if addr: try: # re-encode addr in case they went to/from cashaddr ret = Address.from_string(addr) except BaseException as e: utils.NSLog("Caught exception decoding address %s: %s", addr, str(e)) return ret
def open_link(link): if Address.is_valid(link): addr = Address.from_string(link) if wallet.is_mine(addr): parent.show_address(addr) else: addr_URL = web.BE_URL(parent.config, 'addr', addr) if addr_URL: webopen(addr_URL) return if link.startswith('http'): webopen(link) elif len(link) == 64: # 64 character txid tx = wallet.transactions.get(link) if tx: parent.show_transaction(tx, tx_desc=wallet.get_label(link)) else: parent.do_process_from_txid(txid=link, tx_desc=wallet.get_label(link)) return
def getaddressunspent(self, address): """Returns the UTXO list of any address. Note: This is a walletless server query, results are not checked by SPV. """ if not isinstance(address, Address): try: address = Address.from_string(address) except AddressError: return None sh = address.to_scripthash_hex() return self.network.synchronous_get( ('blockchain.scripthash.listunspent', [sh]))
def get_full_contacts(self, include_pseudo: bool = True) -> List[Contact]: ''' Returns all the contacts, with the "My CashAcct" pseudo-contacts clobbering dupes of the same type that were manually added. Client code should scan for type == 'cashacct' and type == 'cashacct_W' ''' if include_pseudo: # filter out cachaccts that are "Wallet", as they will be added # at the end as pseudo contacts if they also appear in real contacts real_contacts = [ contact for contact in self.parent.contacts.get_all(nocopy=True) if contact.type != 'cashacct' # accept anything that's not cashacct or not Address.is_valid( contact.address ) # or if it is, it can have invalid address as it's clearly 'not mine" or not self.wallet.is_mine( # or if it's not mine Address.from_string(contact.address)) ] return real_contacts + self._make_wallet_cashacct_pseudo_contacts() else: return self.parent.contacts.get_all(nocopy=True)
def check_inputs_for_sufficient_funds_and_return_total( self, inputs, amount): """ This function check on blockchain for sufficient funds. inputs is a dict with bitcoin pubkeys as a keys and list of utxo hashes as values. the sum of all utxo values should be greater then amount it does as follows: 1. check utxo list for every pubkey in the dict 2. check if utxo from inputs are in the utxo list on blockchain for these pubkeys 2.a return None if there is a utxo from list not in utxo set from blockchain 2.b return None if utxo in list is not confirmed 3. return True, total_amt if summary values of utxos are greater then amount and False, None otherwise returns None,None on blockchain communication error """ assert amount > 0, "Amount must be > 0!" def _utxo_name(x): return x['tx_hash'] + ":" + str(x['tx_pos']) total = 0 try: for public_key, pk_inputs in inputs.items(): try: address = Address.from_pubkey(public_key) except AddressError: # refuse to accept something that doesn't parse as a pubkey return False, None unspent_list = self.getaddressunspent(address) utxos = { _utxo_name(utxo): utxo['value'] for utxo in unspent_list if utxo.get('height', -1) > 0 # all inputs must have at least 1 confirmation } for utxo in pk_inputs: val = utxos.get(utxo) if val is None: return False, None # utxo does not exist or was spent total += val answer = total >= amount if answer: return True, total return False, total except BaseException as e: #import traceback #traceback.print_exc() self.print_error("check_inputs_for_sufficient_funds: ", repr(e)) return None, None
def load_shuffle_change_shared_with_others(wallet): ''' Modifies wallet instance and adds _shuffle_change_shared_with_others retrieving it from storage. _shuffle_patched_ need not be set. ''' wallet._shuffle_change_shared_with_others = set() tmpadrs = wallet.storage.get( ConfKeys.PerWallet.CHANGE_SHARED_WITH_OTHERS, []) if isinstance(tmpadrs, (list, tuple, set)): for a in tmpadrs: try: a = Address.from_string(a) if not wallet.get_address_history( a ): # no need to re-add to set if it has a history since it won't be shared anyway with the network if it's been used. This set is used only to not cross over shuffled out addresses with change addresses for unused addrs when shuffling wallet._shuffle_change_shared_with_others.add(a) except (AddressError, TypeError): pass
def tx_from_components(all_components, session_hash): """ Returns the tx and a list of indices matching inputs with components""" input_indices = [] assert len(session_hash) == 32 if Protocol.FUSE_ID is None: prefix = [] else: assert len(Protocol.FUSE_ID) == 4 prefix = [4, *Protocol.FUSE_ID] inputs = [] outputs = [ (TYPE_SCRIPT, ScriptOutput(bytes([OpCodes.OP_RETURN, *prefix, 32]) + session_hash), 0) ] for i, compser in enumerate(all_components): comp = pb.Component() comp.ParseFromString(compser) ctype = comp.WhichOneof('component') if ctype == 'input': inp = comp.input if len(inp.prev_txid) != 32: raise FusionError("bad component prevout") inputs.append( dict(address=Address.from_P2PKH_hash(hash160(inp.pubkey)), prevout_hash=inp.prev_txid[::-1].hex(), prevout_n=inp.prev_index, num_sig=1, signatures=[None], type='p2pkh', x_pubkeys=[inp.pubkey.hex()], pubkeys=[inp.pubkey.hex()], sequence=0xffffffff, value=inp.amount)) input_indices.append(i) elif ctype == 'output': out = comp.output atype, addr = get_address_from_output_script(out.scriptpubkey) if atype != TYPE_ADDRESS: raise FusionError("bad component address") outputs.append((TYPE_ADDRESS, addr, out.amount)) elif ctype != 'blank': raise FusionError("bad component") tx = Transaction.from_io(inputs, outputs, locktime=0, sign_schnorr=True) tx.version = 1 return tx, input_indices
def _make_wallet_cashacct_pseudo_contacts(self, exclude_contacts=[] ) -> List[Contact]: ''' Returns a list of 'fake' contacts that come from the wallet's own registered Cash Accounts. These contacts do not exist in the wallet.contacts object but are created on-the-fly from the wallet.cashacct list of registered & verified Cash Accounts. The creation of this list is relatively cheap and scales as the lookups are O(logN) in the cashaccts caches. This is a convenience so that the Contacts tab shows "my" cash accounts after registration as well as external Cash Accounts. Note that the "mine" entries won't be shown if the user explicitly added his own as "external"... ''' try: excl_chk = set((c.name, Address.from_string(c.address)) for c in exclude_contacts if c.type == 'cashacct') except: # Hmm.. invalid address? excl_chk = set() wallet_cashaccts = [] v_txids = set() # Add the [Mine] pseudo-contacts for ca_info in self.wallet.cashacct.get_wallet_cashaccounts(): v_txids.add(ca_info.txid) name = self.wallet.cashacct.fmt_info(ca_info, emoji=False) if (name, ca_info.address) in excl_chk: continue wallet_cashaccts.append( Contact(name=name, address=ca_info.address.to_ui_string(), type='cashacct_W')) # Add the [Pend] pseudo-contacts for txid, tup in self._ca_pending_conf.copy().items(): if txid in v_txids or self.wallet.cashacct.is_verified(txid): self._ca_pending_conf.pop(txid, None) continue if tup in excl_chk: continue name, address = tup wallet_cashaccts.append( Contact(name=name, address=address.to_ui_string(), type='cashacct_T')) return wallet_cashaccts
def doReloadForKey(self, key: Any) -> Any: if key is None: a = AddressData(gui.ElectrumGui.gui) a.refresh() utils.NSLog("AddressMgr refresh (full)") return a elif key and isinstance(key, (str, Address)): if isinstance(key, str): key = Address.from_string(key) a = self.get( None ) # recursive call to self to get cached 'all' or rebuild 'all' if not cached if a: entries = a.master[0][0] for entry in entries: if entry.address == key: return entry return None
def do_send(self): if not Address.is_valid(self.str_recipient): print(_('Invalid Bitcoin address')) return try: amount = int(PyDecimal(self.str_amount) * COIN) except Exception: print(_('Invalid Amount')) return try: fee = int(PyDecimal(self.str_fee) * COIN) except Exception: print(_('Invalid Fee')) return if self.wallet.has_password(): password = self.password_dialog() if not password: return else: password = None c = "" while c != "y": c = input("ok to send (y/n)?") if c == "n": return try: tx = self.wallet.mktx([(TYPE_ADDRESS, self.str_recipient, amount)], password, self.config, fee) except Exception as e: print(str(e)) return if self.str_description: self.wallet.labels[tx.txid()] = self.str_description print(_("Please wait...")) status, msg = self.network.broadcast_transaction(tx) if status: print(_('Payment sent.')) else: print(_('Error'))
def get_coins(self, inputs): coins = {} for public_key, utxos in inputs.items(): address = Address.from_pubkey(public_key) coins[public_key] = [ ] # FIXME: Should probably use a defaultdict here but maybe we want calling code to fail on KeyError ? unspent_list = self.getaddressunspent(address) utxo_dicts = { "{}:{}".format(utxo["tx_hash"], utxo["tx_pos"]): utxo for utxo in unspent_list } for utxo in utxos: utxo_dict = utxo_dicts.get(utxo) if utxo_dict: coins[public_key].append(utxo_dict) else: # uh-oh.. not found. may have been double-spent in the meantimg or buggy Player peer. return None return coins
def getUnusedAddress(self) -> None: wallet = parent().wallet if not wallet: return # hide receive tab if no receive requests available b = len(wallet.receive_requests) > 0 #self.setVisible(b) #self.parent.receive_requests_label.setVisible(b) #if not b: # self.parent.expires_label.hide() # self.parent.expires_combo.show() domain = wallet.get_addresses() if self.addrStr: # update the receive address if necessary current_address = Address.from_string(self.addrStr) addr = wallet.get_unused_address() if not current_address in domain and addr: self.setReceiveAddress_(addr.to_ui_string()) current_address = addr.to_ui_string()
def on_update(self): self.chkVisible() # update the receive address if necessary current_address_string = self.parent.receive_address_e.text().strip() current_address = Address.from_string(current_address_string) if len( current_address_string) else None domain = self.wallet.get_receiving_addresses() addr = self.wallet.get_unused_address() if current_address not in domain and addr: self.parent.set_receive_address(addr) # clear the list and fill it again item = self.currentItem() prev_sel = item.data(0, Qt.UserRole) if item else None self.clear() for req in self.wallet.get_sorted_requests(self.config): address = req['address'] if address not in domain: continue timestamp = req.get('time', 0) amount = req.get('amount') expiration = req.get('exp', None) message = req.get('memo', '') date = format_time(timestamp) status = req.get('status') signature = req.get('sig') requestor = req.get('name', '') amount_str = self.parent.format_amount(amount) if amount else "" item = QTreeWidgetItem([ date, address.to_ui_string(), '', message, amount_str, _(pr_tooltips.get(status, '')) ]) item.setData(0, Qt.UserRole, address) if signature is not None: item.setIcon(2, QIcon(":icons/seal.svg")) item.setToolTip(2, 'signed by ' + requestor) if status is not PR_UNKNOWN: item.setIcon(6, QIcon(pr_icons.get(status))) self.addTopLevelItem(item) if prev_sel == address: self.setCurrentItem(item)
def doSign(self) -> None: addrtf = self.tf address = str(addrtf.text).strip() message = str(self.topTvDel.text) signatureTvDel = self.botTvDel try: print("address = ", address) addr = Address.from_string(address) except: parent().show_error(_('Invalid Ergon address.')) return if addr.kind != addr.ADDR_P2PKH: msg_sign = _("Signing with an address actually means signing with the corresponding " "private key, and verifying with the corresponding public key. The " "address you have entered does not have a unique public key, so these " "operations cannot be performed.") + '\n\n' + \ _('The operation is undefined. Not just in Oregano, but in general.') parent().show_message( _('Cannot sign messages with this type of address.') + '\n\n' + msg_sign) return if not parent().wallet: return if parent().wallet.is_watching_only(): parent().show_message(_('This is a watching-only wallet.')) return if not parent().wallet.is_mine(addr): parent().show_message(_('Address not in wallet.')) return def onPw(password: str) -> None: try: signed = parent().wallet.sign_message(addr, message, password) except: parent().show_error(str(sys.exc_info()[1])) return signatureTvDel.text = base64.b64encode(signed).decode('ascii') parent().show_message(_( "The signature for the provided message has been pasted into the signature text box." ), title=_("Success")) parent().prompt_password_if_needed_asynch(onPw, vc=self)
def __init__(self, window, wallet, network_settings, period = 10.0, logger = None, password=None, timeout=60.0, typ=Messages.DEFAULT # NB: Only DEFAULT is currently supported ): super().__init__() cls = type(self) self.daemon = True self.timeout = timeout self.version = cls.PROTOCOL_VERSION + (1 if networks.net.TESTNET else 0) self.type = typ assert self.type == Messages.DEFAULT, "BackgroundShufflingThread currently only supports DEFAULT shuffles" cls.latest_shuffle_settings = cls.ShuffleSettings(self.type, Messages.TYPE_NAME_DICT[self.type], self.version, 0, 0, self.FEE) # set UPPER_BOUND and LOWER_BOUND from config keys here. Note all instances will see these changes immediately. cls.update_lower_and_upper_bound_from_config() self.period = period self.logger = logger self.wallet = wallet self.window = window self.host = network_settings.get("host", None) self.info_port = network_settings.get("info", None) self.port = 1337 # default value -- will get set to real value from server's stat port in run() method self.poolSize = 3 # default value -- will get set to real value from server's stat port in run() method self.banScore = 0 # comes from stats port -- our own personal ban score self.banned = False # comes from stats port. True if our IP is banned (default ban duration: 30 mins) self.ssl = network_settings.get("ssl", None) self.lock = threading.RLock() self.password = password self.threads = {scale:None for scale in self.scales} self.shared_chan = Channel(switch_timeout=None) # threads write a 3-tuple here: (killme_flg, thr, msg) self.stop_flg = threading.Event() self.last_idle_check = 0.0 # timestamp in seconds unix time self.done_utxos = dict() self._paused = False self._coins_busy_shuffling = set() # 'prevout_hash:n' (name) set of all coins that are currently being shuffled by a ProtocolThread. Both wallet locks should be held to read/write this. self._last_server_check = 0.0 # timestamp in seconds unix time self._dummy_address = Address.from_pubkey(EC_KEY(number_to_string(1337, generator_secp256k1.order())).get_public_key()) # dummy address # below 4 vars are related to the "delayed unreserve address" mechanism as part of the bug #70 & #97 workaround and the complexity created by it.. self._delayed_unreserve_addresses = dict() # dict of Address -> time.time() timestamp when its shuffle ended self._last_delayed_unreserve_check = 0.0 # timestamp in seconds unix time self._delayed_unreserve_check_interval = 60.0 # check these addresses every 60 seconds. self._delayed_unreserve_timeout = 600.0 # how long before the delayed-unreserve addresses expire; 10 minutes
def check_input_electrumx(network, inpcomp): """ Check an InputComponent against electrumx service. This can be a bit slow since it gets all utxos on that address. Returns normally if the check passed. Raises ValidationError if the input is not consistent with blockchain (according to server), and raises other exceptions if the server times out or gives an unexpected kind of response. """ address = Address.from_pubkey(inpcomp.pubkey) prevhash = inpcomp.prev_txid[::-1].hex() prevn = inpcomp.prev_index sh = address.to_scripthash_hex() u = network.synchronous_get(('blockchain.scripthash.listunspent', [sh]), timeout=5) for item in u: if prevhash == item['tx_hash'] and prevn == item['tx_pos']: break else: raise ValidationError('missing or spent or scriptpubkey mismatch') check(item['height'] > 0, 'not confirmed') check(item['value'] == inpcomp.amount, 'amount mismatch')
def do_send(self): if not Address.is_valid(self.str_recipient): self.show_message(_('Invalid Bitcoin address')) return try: amount = int(PyDecimal(self.str_amount) * COIN) except Exception: self.show_message(_('Invalid Amount')) return try: fee = int(PyDecimal(self.str_fee) * COIN) except Exception: self.show_message(_('Invalid Fee')) return if self.wallet.has_password(): password = self.password_dialog() if not password: return else: password = None try: tx = self.wallet.mktx([(TYPE_ADDRESS, self.str_recipient, amount)], password, self.config, fee) except Exception as e: self.show_message(str(e)) return if self.str_description: self.wallet.labels[tx.txid()] = self.str_description self.show_message(_("Please wait..."), getchar=False) status, msg = self.network.broadcast_transaction(tx) if status: self.show_message(_('Payment sent.')) self.do_clear() #self.update_contacts_tab() else: self.show_message(_('Error'))
def viewWillDisappear_(self, animated: bool) -> None: send_super(__class__, self, 'viewWillDisappear:', animated, argtypes=[c_bool]) parent().cash_addr_sig.disconnect(self) data = utils.nspy_get_byname(self, 'data') if not data: data = DialogData(None, None) text = self.tf.text.strip() if self.mode == SignVerify: try: address = Address.from_string(text) data = utils.set_namedtuple_field(data, 'address', address) except: pass elif self.mode == EncryptDecrypt: data = utils.set_namedtuple_field(data, 'pubkey', text) utils.nspy_put_byname(self, data, 'data') if self.kbas: utils.unregister_keyboard_autoscroll(self.kbas) self.kbas = None
def parse_address(self, line): r = line.strip() m = re.match(RE_ALIAS, r) address = m.group(2) if m else r return Address.from_string(address)