def on_btnFindDMNTxHash_clicked(self, checked): if self.masternode and not self.updating_ui: found_protx = None if not ((self.masternode.ip and self.masternode.port) or (self.masternode.collateralTx and self.masternode.collateralTxIndex)): WndUtils.errorMsg('To be able to locate the deterministic masternode transaction you need to ' 'provide the masternode ip + port or collateral tx + tx index.') return try: txes = self.crownd_intf.protx('list', 'registered', True) for protx in txes: state = protx.get('state') if state: if (state.get('service') == self.masternode.ip + ':' + self.masternode.port) or \ (protx.get('collateralHash') == self.masternode.collateralTx and str(protx.get('collateralIndex', '')) == self.masternode.collateralTxIndex): found_protx = protx break except Exception as e: pass if found_protx: if self.masternode.dmn_tx_hash == protx.get('proTxHash'): WndUtils.infoMsg('You have te correct DMN TX hash in the masternode configuration.') else: self.edtDMNTxHash.setText(protx.get('proTxHash')) self.masternode.dmn_tx_hash = protx.get('proTxHash') self.set_modified() else: WndUtils.warnMsg('Couldn\'t find this masternode in the list of registered deterministic masternodes.') self.set_modified()
def my_excepthook(type, value, tback): print('=========================') traceback.print_tb(tback) traceback.print_stack() sys.__excepthook__(type, value, tback) logging.exception('Exception occurred') WndUtils.errorMsg(str(value))
def get_operator_key_to_display(self) -> str: ret = '' if self.masternode: if self.edit_mode: if self.masternode.dmn_operator_key_type == InputKeyType.PRIVATE: ret = self.masternode.dmn_operator_private_key else: ret = self.masternode.dmn_operator_public_key else: try: if self.masternode.dmn_operator_key_type == InputKeyType.PRIVATE: if self.act_view_as_operator_private_key.isChecked(): ret = self.masternode.dmn_operator_private_key elif self.act_view_as_operator_public_key.isChecked(): ret = self.masternode.get_dmn_operator_pubkey() else: ret = '???' else: if self.act_view_as_operator_public_key.isChecked(): ret = self.masternode.dmn_operator_public_key else: ret = '???' except Exception as e: msg = str(e) if not msg: msg = 'Key conversion error.' WndUtils.errorMsg(msg) return ret
def on_btnEnter_clicked(self): text = self.edtWord.text() if not text: WndUtils.errorMsg('Word cannot be empty.') elif text not in self.wordlist: WndUtils.errorMsg('Word is not in the allowed wordlist.') else: self.accept()
def my_excepthook(type, value, tback): print('=========================') traceback.print_tb(tback) for fh in logging.RootLogger.root.handlers: if isinstance(fh, logging.FileHandler): traceback.print_exception(type, value, tback, file=fh.stream) fh.flush() WndUtils.errorMsg(str(value))
def connect(self): import paramiko self.ssh = paramiko.SSHClient() self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) password = None pass_message = None while True: try: self.ssh.connect(self.host, port=int(self.port), username=self.username, password=password) self.connected = True if password: SshPassCache.save_password(self.username, self.host, password) break except PasswordRequiredException as e: # private key with password protection is used; ask user for password pass_message = "Enter passphrase for <b>private key</b> or password for %s" % \ (self.username + '@' + self.host) while True: password = SshPassCache.get_password(self.username, self.host, message=pass_message) if password: break except AuthenticationException as e: # This exception will be raised in the following cases: # 1. a private key with password protectection is used but the user enters incorrect password # 2. a private key exists but user's public key is not added to the server's allowed keys # 3. normal login to server is performed but the user enters bad password # So, in the first case, the second query for password will ask for normal password to server, not # for a private key. WndUtils.errorMsg(message='Incorrect password, try again...') while True: password = SshPassCache.get_password(self.username, self.host, message=pass_message) if password: break except SSHException as e: if e.args and e.args[ 0] == 'No authentication methods available': while True: password = SshPassCache.get_password( self.username, self.host) if password: break else: raise except Exception as e: raise
def rpc_command(self, command: str, *args): if self.main_dlg.dashd_intf: ret = self.main_dlg.dashd_intf.rpc_call(command, *args) try: if isinstance(ret, str): ret = json.loads(ret) ret = json.dumps(ret, default=EncodeDecimal, indent = 4, separators = (',', ': ')) except Exception: pass self.message(ret, style="white-space: pre-wrap;") return True else: WndUtils.errorMsg('Not connected to a GINcoin node') return False
def my_excepthook(type, value, tback): print('=========================') traceback.print_tb(tback) for fh in logging.RootLogger.root.handlers: if isinstance(fh, logging.FileHandler): traceback.print_exception(type, value, tback, file=fh.stream) fh.flush() msg = str(value) if not msg: try: msg = 'An unhandled exception accurred: ' + value.__class__.__name__ + '.' except: msg = 'An unhandled exception accurred.' WndUtils.errorMsg(msg)
def exec_columns_dialog(self, parent_window: QWidget): try: cols = [] for col in sorted(self._columns, key=lambda x: x.visual_index): cols.append([col.caption, col.visible, col]) ui = ColumnsConfigDlg(parent_window, columns=cols) ret = ui.exec_() if ret > 0: for visual_idx, (_, visible, col) in enumerate(cols): col.visual_index = visual_idx col.visible = visible self._apply_columns_to_ui() except Exception as e: logging.exception('Exception while configuring table view columns') WndUtils.errorMsg(str(e))
def get_owner_key_to_display(self) -> str: ret = '' if self.masternode: if self.edit_mode: if self.masternode.dmn_owner_key_type == InputKeyType.PRIVATE: ret = self.masternode.dmn_owner_private_key else: ret = self.masternode.dmn_owner_address else: try: if self.masternode.dmn_owner_key_type == InputKeyType.PRIVATE: if self.act_view_as_owner_private_key.isChecked(): ret = self.masternode.dmn_owner_private_key elif self.act_view_as_owner_public_address.isChecked(): if self.masternode.dmn_owner_private_key: ret = crown_utils.wif_privkey_to_address(self.masternode.dmn_owner_private_key, self.app_config.crown_network) elif self.act_view_as_owner_public_key.isChecked(): if self.masternode.dmn_owner_private_key: ret = crown_utils.wif_privkey_to_pubkey(self.masternode.dmn_owner_private_key) elif self.act_view_as_owner_public_key_hash.isChecked(): if self.masternode.dmn_owner_private_key: pubkey = crown_utils.wif_privkey_to_pubkey(self.masternode.dmn_owner_private_key) pubkey_bin = bytes.fromhex(pubkey) pub_hash = bitcoin.bin_hash160(pubkey_bin) ret = pub_hash.hex() else: ret = '???' else: if self.act_view_as_owner_public_address.isChecked(): ret = self.masternode.dmn_owner_address elif self.act_view_as_owner_public_key_hash.isChecked(): ret = self.masternode.get_dmn_owner_pubkey_hash() else: ret = '???' except Exception as e: msg = str(e) if not msg: msg = 'Key conversion error.' WndUtils.errorMsg(msg) return ret
def init(self, app_path): """ Initialize configuration after openning the application. """ self.app_path = app_path try: with open(os.path.join(app_path, 'version.txt')) as fptr: lines = fptr.read().splitlines() self.app_version = app_utils.extract_app_version(lines) except: pass parser = argparse.ArgumentParser() parser.add_argument('--config', help="Path to a configuration file", dest='config') parser.add_argument('--data-dir', help="Root directory for configuration file, cache and log dubdirs", dest='data_dir') args = parser.parse_args() app_user_dir = '' if args.data_dir: if os.path.exists(args.data_dir): if os.path.isdir(args.data_dir): app_user_dir = args.data_dir else: WndUtils.errorMsg('--data-dir parameter doesn\'t point to a directory. Using the default ' 'data directory.') else: WndUtils.errorMsg('--data-dir parameter doesn\'t point to an existing directory. Using the default ' 'data directory.') if not app_user_dir: home_dir = expanduser('~') app_user_dir = os.path.join(home_dir, APP_NAME_SHORT) if not os.path.exists(app_user_dir): os.makedirs(app_user_dir) self.cache_dir = os.path.join(app_user_dir, 'cache') if not os.path.exists(self.cache_dir): os.makedirs(self.cache_dir) cache.init(self.cache_dir, self.app_version) self.app_last_version = cache.get_value('app_version', '', str) self.app_config_file_name = '' if args.config is not None: self.app_config_file_name = args.config if not os.path.exists(self.app_config_file_name): msg = 'Config file "%s" does not exist.' % self.app_config_file_name print(msg) raise Exception(msg) if not self.app_config_file_name: self.app_config_file_name = os.path.join(app_user_dir, 'config.ini') # setup logging self.log_dir = os.path.join(app_user_dir, 'logs') self.log_file = os.path.join(self.log_dir, 'dmt.log') if not os.path.exists(self.log_dir): os.makedirs(self.log_dir) self.log_level_str = 'INFO' log_exists = os.path.exists(self.log_file) handler = RotatingFileHandler(filename=self.log_file, mode='a', backupCount=30) logger = logging.getLogger() formatter = logging.Formatter(fmt='%(asctime)s %(levelname)s |%(threadName)s |%(filename)s |%(funcName)s ' '|%(message)s', datefmt='%Y-%m-%d %H:%M:%S') handler.setFormatter(formatter) logger.addHandler(handler) logger.setLevel(self.log_level_str) if log_exists: handler.doRollover() logging.info('App started') # database (SQLITE) cache for caching bigger datasets: self.db_cache_file_name = os.path.join(self.cache_dir, 'dmt_cache.db') try: self.db_intf = DBCache(self.db_cache_file_name) except Exception as e: logging.exception('SQLite initialization error') # directory for configuration backups: self.cfg_backup_dir = os.path.join(app_user_dir, 'backup') if not os.path.exists(self.cfg_backup_dir): os.makedirs(self.cfg_backup_dir) try: # read configuration from a file self.read_from_file() except: pass if not self.app_last_version or \ app_utils.version_str_to_number(self.app_last_version) < app_utils.version_str_to_number(self.app_version): cache.save_data() self.initialized = True
def send_upd_tx(self): # verify the owner key used in the configuration if self.masternode.dmn_owner_key_type == InputKeyType.PRIVATE and self.masternode.dmn_owner_private_key: owner_address = wif_privkey_to_address( self.masternode.dmn_owner_private_key, self.app_config.crown_network) if owner_address != self.dmn_owner_address: raise Exception( 'Inconsistency of the owner key between the app configuration and the data ' 'on the Crown network.') else: raise Exception( 'To use this feature, you need to have the owner private key in your masternode ' 'configuration.') try: funding_address = '' params = [ 'update_registrar', self.dmn_protx_hash, self.dmn_new_operator_pubkey, self.dmn_new_voting_address, self.dmn_new_payout_address, funding_address ] try: upd_reg_support = self.crownd_intf.checkfeaturesupport( 'protx_update_registrar', self.app_config.app_version) if not upd_reg_support.get('enabled'): if upd_reg_support.get('message'): raise Exception(upd_reg_support.get('message')) else: raise Exception( 'The \'protx_update_registrar\' function is not supported by the RPC node ' 'you are connected to.') public_proxy_node = True active = self.app_config.feature_update_registrar_automatic.get_value( ) if not active: msg = self.app_config.feature_update_registrar_automatic.get_message( ) if not msg: msg = 'The functionality of the automatic execution of the update_registrar command on the ' \ '"public" RPC nodes is inactive. Use the manual method or contact the program author ' \ 'for details.' raise Exception(msg) except JSONRPCException as e: public_proxy_node = False if not public_proxy_node: try: # find an address to be used as the source of the transaction fees min_fee = round(1024 * FEE_DUFF_PER_BYTE / 1e8, 8) balances = self.crownd_intf.listaddressbalances(min_fee) bal_list = [] for addr in balances: bal_list.append({ 'address': addr, 'amount': balances[addr] }) bal_list.sort(key=lambda x: x['amount']) if not bal_list: raise Exception( "No address can be found in the node's wallet with sufficient funds to " "cover the transaction fees.") params[5] = bal_list[0]['address'] except JSONRPCException as e: logging.warning( "Couldn't list the node address balances. We assume you are using a " "public RPC node and the funding address for the transaction fee will " "be estimated during the `update_registrar` call") else: params.append(self.masternode.dmn_owner_private_key) upd_tx_hash = self.crownd_intf.rpc_call(True, False, 'protx', *params) if upd_tx_hash: logging.info( 'update_registrar successfully executed, tx hash: ' + upd_tx_hash) changed = False if self.dmn_new_voting_address != self.dmn_prev_voting_address: changed = self.masternode.dmn_voting_key_type != self.dmn_voting_key_type self.masternode.dmn_voting_key_type = self.dmn_voting_key_type if self.dmn_voting_key_type == InputKeyType.PRIVATE: changed = changed or self.masternode.dmn_voting_private_key != self.dmn_new_voting_privkey self.masternode.dmn_voting_private_key = self.dmn_new_voting_privkey else: changed = changed or self.masternode.dmn_voting_address != self.dmn_new_voting_address self.masternode.dmn_voting_address = self.dmn_new_voting_address if self.dmn_new_operator_pubkey != self.dmn_prev_operator_pubkey: changed = changed or self.masternode.dmn_operator_key_type != self.dmn_operator_key_type self.masternode.dmn_operator_key_type = self.dmn_operator_key_type if self.dmn_operator_key_type == InputKeyType.PRIVATE: changed = changed or self.masternode.dmn_operator_private_key != self.dmn_new_operator_privkey self.masternode.dmn_operator_private_key = self.dmn_new_operator_privkey else: changed = changed or self.masternode.dmn_operator_public_key != self.dmn_new_operator_pubkey self.masternode.dmn_operator_public_key = self.dmn_new_operator_pubkey if self.on_upd_success_callback: self.on_upd_success_callback(self.masternode) self.btnSendUpdateTx.setDisabled(True) self.edtPayoutAddress.setReadOnly(True) self.edtOperatorKey.setReadOnly(True) self.edtVotingKey.setReadOnly(True) self.btnGenerateOperatorKey.setDisabled(True) self.btnGenerateVotingKey.setDisabled(True) self.btnClose.show() url = self.app_config.get_block_explorer_tx() if url: url = url.replace('%TXID%', upd_tx_hash) upd_tx_hash = f'<a href="{url}">{upd_tx_hash}</a>' msg = 'The update_registrar transaction has been successfully sent. ' \ f'Tx hash: {upd_tx_hash}. <br><br>' \ f'The new values will be visible on the network after the transaction is confirmed, i.e. in ' \ f'about 2.5 minutes.' if changed: msg += '<br><br>The app configuration has been updated accordingly.' WndUtils.infoMsg(msg) except Exception as e: if str(e).find('protx-dup') >= 0: WndUtils.errorMsg( 'The previous protx transaction has not been confirmed yet. Wait until it is ' 'confirmed before sending a new transaction.') else: logging.error( 'Exception occurred while sending protx update_registrar.') WndUtils.errorMsg(str(e))
def send_revoke_tx(self): try: funding_address = '' params = [ 'revoke', self.dmn_protx_hash, self.masternode.dmn_operator_private_key, self.revocation_reason, funding_address ] try: revoke_support = self.polisd_intf.checkfeaturesupport( 'protx_revoke', self.app_config.app_version) if not revoke_support.get('enabled'): if revoke_support.get('message'): raise Exception(revoke_support.get('message')) else: raise Exception( 'The \'protx_revoke\' function is not supported by the RPC node ' 'you are connected to.') public_proxy_node = True active = self.app_config.feature_revoke_operator_automatic.get_value( ) if not active: msg = self.app_config.feature_revoke_operator_automatic.get_message( ) if not msg: msg = 'The functionality of the automatic execution of the revoke command on the ' \ '"public" RPC nodes is inactive. Use the manual method or contact the program author ' \ 'for details.' raise Exception(msg) except JSONRPCException as e: public_proxy_node = False if not public_proxy_node: try: # find an address to be used as the source of the transaction fees min_fee = round(1024 * FEE_DUFF_PER_BYTE / 1e8, 8) balances = self.polisd_intf.listaddressbalances(min_fee) bal_list = [] for addr in balances: bal_list.append({ 'address': addr, 'amount': balances[addr] }) bal_list.sort(key=lambda x: x['amount']) if not bal_list: raise Exception( "No address can be found in the node's wallet with sufficient funds to " "cover the transaction fees.") params[5] = bal_list[0]['address'] except JSONRPCException as e: logging.warning( "Couldn't list the node address balances. We assume you are using a " "public RPC node and the funding address for the transaction fee will " "be estimated during the `update_registrar` call") upd_tx_hash = self.polisd_intf.rpc_call(True, False, 'protx', *params) if upd_tx_hash: logging.info('revoke successfully executed, tx hash: ' + upd_tx_hash) self.btnSendRevokeTx.setDisabled(True) self.cboReason.setDisabled(True) self.btnClose.show() url = self.app_config.get_block_explorer_tx() if url: url = url.replace('%TXID%', upd_tx_hash) upd_tx_hash = f'<a href="{url}">{upd_tx_hash}</a>' msg = 'The revoke transaction has been successfully sent. ' \ f'Tx hash: {upd_tx_hash}. <br><br>' \ f'The new values will be visible on the network after the transaction is confirmed, i.e. in ' \ f'about 2 minutes.' WndUtils.infoMsg(msg) except Exception as e: if str(e).find('protx-dup') >= 0: WndUtils.errorMsg( 'The previous protx transaction has not been confirmed yet. Wait until it is ' 'confirmed before sending a new transaction.') else: logging.error( 'Exception occurred while sending protx revoke: ' + str(e)) WndUtils.errorMsg(str(e))
def on_btn_main_accepted(self): if self.device_selected_index is None: WndUtils.errorMsg('No item selected.') else: self.accept()
def send_upd_tx(self): try: funding_address = '' if self.dmn_new_ip: dmn_new_ip_port = self.dmn_new_ip + ':' + str( self.dmn_new_port) else: dmn_new_ip_port = '"0"' params = [ 'update_service', self.dmn_protx_hash, dmn_new_ip_port, self.masternode.dmn_operator_private_key, self.dmn_new_operator_payout_address, funding_address ] try: upd_service_support = self.fixd_intf.checkfeaturesupport( 'protx_update_service', self.app_config.app_version) if not upd_service_support.get('enabled'): if upd_service_support.get('message'): raise Exception(upd_service_support.get('message')) else: raise Exception( 'The \'protx_update_service\' function is not supported by the RPC node ' 'you are connected to.') public_proxy_node = True active = self.app_config.feature_update_service_automatic.get_value( ) if not active: msg = self.app_config.feature_update_service_automatic.get_message( ) if not msg: msg = 'The functionality of the automatic execution of the update_service command on the ' \ '"public" RPC nodes is inactive. Use the manual method or contact the program author ' \ 'for details.' raise Exception(msg) except JSONRPCException as e: public_proxy_node = False if not public_proxy_node: try: # find an address to be used as the source of the transaction fees min_fee = round(1024 * FEE_DUFF_PER_BYTE / 1e8, 8) balances = self.fixd_intf.listaddressbalances(min_fee) bal_list = [] for addr in balances: bal_list.append({ 'address': addr, 'amount': balances[addr] }) bal_list.sort(key=lambda x: x['amount']) if not bal_list: raise Exception( "No address can be found in the node's wallet with sufficient funds to " "cover the transaction fees.") params[5] = bal_list[0]['address'] except JSONRPCException as e: logging.warning( "Couldn't list the node address balances. We assume you are using a " "public RPC node and the funding address for the transaction fee will " "be estimated during the `update_registrar` call") upd_tx_hash = self.fixd_intf.rpc_call(True, False, 'protx', *params) if upd_tx_hash: logging.info( 'update_service successfully executed, tx hash: ' + upd_tx_hash) self.btnSendUpdateTx.setDisabled(True) self.edtOperatorPayoutAddress.setReadOnly(True) self.edtIP.setReadOnly(True) self.edtPort.setReadOnly(True) self.btnClose.show() url = self.app_config.get_block_explorer_tx() if url: url = url.replace('%TXID%', upd_tx_hash) upd_tx_hash = f'<a href="{url}">{upd_tx_hash}</a>' msg = 'The update_service transaction has been successfully sent. ' \ f'Tx hash: {upd_tx_hash}. <br><br>' \ f'The new values will be visible on the network after the transaction is confirmed, i.e. in ' \ f'about 2.5 minutes.' if bool(dmn_new_ip_port ) and self.dmn_prev_ip_port != dmn_new_ip_port: msg += '\n\nYou have changed the masternode IP/port. Do you want to automatically update ' \ 'this in the app configuration?' if self.queryDlg( msg, buttons=QMessageBox.Yes | QMessageBox.No, default_button=QMessageBox.Yes, icon=QMessageBox.Information) == QMessageBox.Yes: self.masternode.ip = self.dmn_new_ip self.masternode.port = str(self.dmn_new_port) if self.on_mn_config_updated_callback: self.on_mn_config_updated_callback(self.masternode) else: WndUtils.infoMsg(msg) except Exception as e: if str(e).find('protx-dup') >= 0: WndUtils.errorMsg( 'The previous protx transaction has not been confirmed yet. Wait until it is ' 'confirmed before sending a new transaction.') else: logging.error( 'Exception occurred while sending protx update_service: ' + str(e)) WndUtils.errorMsg(str(e))
def get_collateral_tx_address_thread(self, ctrl: CtrlObject): txes_cnt = 0 msg = '' break_scanning = False ctrl.dlg_config_fun(dlg_title="Validating collateral transaction.", show_progress_bar=False) ctrl.display_msg_fun('Verifying collateral transaction...') def check_break_scanning(): nonlocal break_scanning if self.finishing or break_scanning: # stop the scanning process if the dialog finishes or the address/bip32path has been found raise BreakFetchTransactionsException() def fetch_txes_feeback(tx_cnt: int): nonlocal msg, txes_cnt txes_cnt += tx_cnt ctrl.display_msg_fun(msg + '<br><br>' + 'Number of transactions fetched so far: ' + str(txes_cnt)) def on_msg_link_activated(link: str): nonlocal break_scanning if link == 'break': break_scanning = True try: tx = self.dashd_intf.getrawtransaction(self.dmn_collateral_tx, 1, skip_cache=True) except Exception as e: raise Exception( 'Cannot get the collateral transaction due to the following errror: ' + str(e)) vouts = tx.get('vout') if vouts: if self.dmn_collateral_tx_index < len(vouts): vout = vouts[self.dmn_collateral_tx_index] spk = vout.get('scriptPubKey') if not spk: raise Exception( f'The collateral transaction ({self.dmn_collateral_tx}) output ' f'({self.dmn_collateral_tx_index}) doesn\'t have value in the scriptPubKey ' f'field.') ads = spk.get('addresses') if not ads or len(ads) < 0: raise Exception( 'The collateral transaction output doesn\'t have the Dash address assigned.' ) self.dmn_collateral_tx_address = ads[0] else: raise Exception( f'Transaction {self.dmn_collateral_tx} doesn\'t have output with index: ' f'{self.dmn_collateral_tx_index}') else: raise Exception('Invalid collateral transaction') ctrl.display_msg_fun( 'Verifying the collateral transaction address on your hardware wallet.' ) if not self.main_dlg.connect_hardware_wallet(): return False if self.dmn_collateral_tx_address_path: addr = hw_intf.get_address(self.main_dlg.hw_session, self.dmn_collateral_tx_address_path) msg = '' if addr != self.dmn_collateral_tx_address: log.warning( f'The address returned by the hardware wallet ({addr}) for the BIP32 path ' f'{self.dmn_collateral_tx_address_path} differs from the address stored the mn configuration ' f'(self.dmn_collateral_tx_address). Need to scan wallet for a correct BIP32 path.' ) msg = '<span style="color:red">The BIP32 path of the collateral address from your mn config is incorret.<br></span>' \ f'Trying to find the BIP32 path of the address {self.dmn_collateral_tx_address} in your wallet.' \ f'<br>This may take a while (<a href="break">break</a>)...' self.dmn_collateral_tx_address_path = '' else: msg = 'Looking for a BIP32 path of the Dash address related to the masternode collateral.<br>' \ 'This may take a while (<a href="break">break</a>)....' if not self.dmn_collateral_tx_address_path and not self.finishing: lbl = ctrl.get_msg_label_control() if lbl: def set(): lbl.setOpenExternalLinks(False) lbl.setTextInteractionFlags(lbl.textInteractionFlags() & ~Qt.TextSelectableByMouse) lbl.linkActivated.connect(on_msg_link_activated) lbl.repaint() WndUtils.call_in_main_thread(set) ctrl.display_msg_fun(msg) # fetch the transactions that involved the addresses stored in the wallet - during this # all the used addresses are revealed addr = self.bip44_wallet.scan_wallet_for_address( self.dmn_collateral_tx_address, check_break_scanning, fetch_txes_feeback) if not addr: if not break_scanning: WndUtils.errorMsg( f'Couldn\'t find a BIP32 path of the collateral address ({self.dmn_collateral_tx_address}).' ) return False else: self.dmn_collateral_tx_address_path = addr.bip32_path return True
def proregtx_automatic_thread(self, ctrl): log.debug('Starting proregtx_prepare_thread') def set_text(widget, text: str): def call(widget, text): widget.setText(text) widget.repaint() widget.setVisible(True) WndUtils.call_in_main_thread(call, widget, text) def finished_with_success(): def call(): self.next_step() WndUtils.call_in_main_thread(call) try: # preparing protx message try: funding_address = '' if not self.dashd_intf.is_current_connection_public(): try: # find an address to be used as the source of the transaction fees min_fee = round(1024 * FEE_DUFF_PER_BYTE / 1e8, 8) balances = self.dashd_intf.listaddressbalances(min_fee) bal_list = [] for addr in balances: bal_list.append({ 'address': addr, 'amount': balances[addr] }) bal_list.sort(key=lambda x: x['amount']) if not bal_list: raise Exception( "No address can be found in the node's wallet with sufficient funds to " "cover the transaction fees.") funding_address = bal_list[0]['address'] self.dashd_intf.disable_conf_switching() except JSONRPCException as e: log.info( "Couldn't list the node address balances. We assume you are using a public RPC node and " "the funding address for the transaction fees will be estimated during the " "`register_prepare` call") set_text( self.lblProtxTransaction1, '<b>1. Preparing a ProRegTx transaction on a remote node...</b>' ) params = [ 'register_prepare', self.dmn_collateral_tx, self.dmn_collateral_tx_index, self.dmn_ip + ':' + str(self.dmn_tcp_port) if self.dmn_ip else '0', self.dmn_owner_privkey, self.dmn_operator_pubkey, self.dmn_voting_address, str(round(self.dmn_operator_reward, 2)), self.dmn_owner_payout_addr ] if funding_address: params.append(funding_address) call_ret = self.dashd_intf.protx(*params) call_ret_str = json.dumps(call_ret, default=EncodeDecimal) msg_to_sign = call_ret.get('signMessage', '') protx_tx = call_ret.get('tx') log.debug('register_prepare returned: ' + call_ret_str) set_text( self.lblProtxTransaction1, '<b>1. Preparing a ProRegTx transaction on a remote node.</b> <span style="color:green">' 'Success.</span>') except Exception as e: set_text( self.lblProtxTransaction1, '<b>1. Preparing a ProRegTx transaction on a remote node.</b> <span style="color:red">Failed ' f'with the following error: {str(e)}</span>') return # diable config switching since the protx transaction has input associated with the specific node/wallet self.dashd_intf.disable_conf_switching() set_text( self.lblProtxTransaction2, '<b>Message to be signed:</b><br><code>' + msg_to_sign + '</code>') # signing message: set_text(self.lblProtxTransaction3, '<b>2. Signing message with hardware wallet...</b>') try: payload_sig_str = self.sign_protx_message_with_hw(msg_to_sign) set_text( self.lblProtxTransaction3, '<b>2. Signing message with hardware wallet.</b> ' '<span style="color:green">Success.</span>') except HardwareWalletCancelException: set_text( self.lblProtxTransaction3, '<b>2. Signing message with hardware wallet.</b> <span style="color:red">Cancelled.</span>' ) return except Exception as e: log.exception('Signature failed.') set_text( self.lblProtxTransaction3, '<b>2. Signing message with hardware wallet.</b> <span style="color:red">Failed with the ' f'following error: {str(e)}.</span>') return # submitting signed transaction set_text( self.lblProtxTransaction4, '<b>3. Submitting the signed protx transaction to the remote node...</b>' ) try: self.dmn_reg_tx_hash = self.dashd_intf.protx( 'register_submit', protx_tx, payload_sig_str) # self.dmn_reg_tx_hash = 'dfb396d84373b305f7186984a969f92469d66c58b02fb3269a2ac8b67247dfe3' log.debug('protx register_submit returned: ' + str(self.dmn_reg_tx_hash)) set_text( self.lblProtxTransaction4, '<b>3. Submitting the signed protx transaction to the remote node.</b> <span style="' 'color:green">Success.</span>') finished_with_success() except Exception as e: log.exception('protx register_submit failed') set_text( self.lblProtxTransaction4, '<b>3. Submitting the signed protx transaction to the remote node.</b> ' f'<span style="color:red">Failed with the following error: {str(e)}</span>' ) except Exception as e: log.exception('Exception occurred') WndUtils.errorMsg(str(e)) finally: self.dashd_intf.enable_conf_switching()