def on_hw_device_selected(self, anchor: str): try: if self.hw_change_enabled: self.hw_devices.select_device(self.parent(), open_client_session=True) except Exception as e: WndUtils.error_msg(str(e))
def go_to_next_step(self): if self.current_step == Step.STEP_SEED_SOURCE: if self.scenario in (Scenario.ON_DEVICE, Scenario.IN_APP_WORDS): self.set_current_step(Step.STEP_NUMBER_OF_WORDS) elif self.scenario == Scenario.IN_APP_ENTROPY: self.set_current_step(Step.STEP_HEX_ENTROPY) elif self.current_step == Step.STEP_NUMBER_OF_WORDS: if self.word_count in (12, 18, 24): if self.scenario == Scenario.ON_DEVICE: self.set_current_step(Step.STEP_OPTIONS) elif self.scenario == Scenario.IN_APP_WORDS: self.set_current_step(Step.STEP_SEED_WORDS) self.set_word_count(self.word_count) else: WndUtils.error_msg('Choose the number of the seed words.') elif self.current_step == Step.STEP_HEX_ENTROPY: if self.apply_entropy_input(): self.set_current_step(Step.STEP_OPTIONS) elif self.current_step == Step.STEP_SEED_WORDS: if self.apply_words_input(): self.set_current_step(Step.STEP_OPTIONS) elif self.current_step == Step.STEP_OPTIONS: self.set_current_step(Step.STEP_RECOVERING) self.recover_hw() elif self.current_step == Step.STEP_RECOVERING: self.set_current_step(Step.STEP_FINISHED)
def init_hw(self): try: self.hw_conn_change_allowed = False if self.rbWordsCount12.isChecked(): word_count = 12 elif self.rbWordsCount18.isChecked(): word_count = 18 elif self.rbWordsCount24.isChecked(): word_count = 24 else: WndUtils.error_msg( 'Enter the valid number of seed words count.') return use_pin = True if self.chbUsePIN.isChecked() else False use_passphrase = True if self.chbUsePassphrase.isChecked( ) else False label = self.edtDeviceLabel.text() self.hw_devices.initialize_device(self.cur_hw_device, word_count, use_passphrase, use_pin, label, parent_window=self.parent_dialog) self.set_current_step(Step.STEP_FINISHED) except CancelException: self.go_to_prev_step() self.hw_devices.open_hw_session(self.cur_hw_device, force_reconnect=True) except Exception as e: WndUtils.error_msg(str(e), True) self.go_to_prev_step() finally: self.hw_conn_change_allowed = True
def on_btnEnter_clicked(self): text = self.edtWord.text() if not text: WndUtils.error_msg('Word cannot be empty.') elif text not in self.wordlist: WndUtils.error_msg('Word is not in the allowed wordlist.') else: self.accept()
def on_tabFirmwareWebSources_itemSelectionChanged(self): try: idx = self.tabFirmwareWebSources.currentIndex() row_index = -1 if idx: row_index = idx.row() self.select_firmware(row_index) except Exception as e: WndUtils.error_msg(str(e))
def go_to_next_step(self): try: if self.current_step == Step.STEP_DESCRIPTION: self.set_current_step(Step.STEP_ENTER_USER_PASS) elif self.current_step == Step.STEP_ENTER_USER_PASS: if self.generate_rpcauth(): self.set_current_step(Step.STEP_FINISHED) except Exception as e: WndUtils.error_msg(str(e), True)
def wipe_hw(self): try: self.hw_devices.wipe_device(self.cur_hw_device, parent_window=self.parent_dialog) self.go_to_next_step() except CancelException: self.go_to_prev_step() self.hw_devices.open_hw_session(self.cur_hw_device, force_reconnect=True) except Exception as e: WndUtils.error_msg(str(e), True) self.go_to_prev_step()
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 occurred: ' + value.__class__.__name__ + '.' except: msg = 'An unhandled exception occurred.' WndUtils.error_msg(msg)
def update_ui(self): try: if self.cur_hw_device and self.cur_hw_device.hw_client and self.cur_hw_device.hw_type != HWType.ledger_nano: if self.current_step == Step.STEP_FINISHED: self.update_action_subtitle('finished') self.show_message_page('Operation completed.') elif self.current_step == Step.STEP_NO_HW_ERROR: self.show_message_page() else: self.show_action_page() else: self.show_message_page( 'Connect Trezor/Keepkey hardware wallet') except Exception as e: WndUtils.error_msg(str(e), True)
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.error_msg(str(e))
def update_ui(self): try: self.show_action_page() if self.current_step == Step.STEP_DESCRIPTION: self.update_action_subtitle('') self.pages.setCurrentIndex(Pages.PAGE_DESCRIPTION.value) elif self.current_step == Step.STEP_ENTER_USER_PASS: self.update_action_subtitle('enter username and password') self.pages.setCurrentIndex(Pages.PAGE_ENTER_USER_PASS.value) elif self.current_step == Step.STEP_FINISHED: self.update_action_subtitle('summary') self.display_summary() self.pages.setCurrentIndex(Pages.PAGE_SUMMARY.value) except Exception as e: WndUtils.error_msg(str(e), True)
def update_ui(self): try: if self.cur_hw_device and self.cur_hw_device.hw_client and self.cur_hw_device.hw_type != HWType.ledger_nano: self.show_action_page() if self.current_step == Step.STEP_SELECT_FIRMWARE_SOURCE: self.update_action_subtitle('select the firmware source') if not self.cur_hw_device.bootloader_mode: self.lblCurrentFirmwareVersion.setText('Your current firmware version: ' + self.cur_hw_device.firmware_version) else: self.lblCurrentFirmwareVersion.setText('Your current bootloader version: ' + self.cur_hw_device.firmware_version) self.pages.setCurrentIndex(Pages.PAGE_FIRMWARE_SOURCE.value) if self.hw_firmware_source_type == FirmwareSource.INTERNET: self.lblFileLabel.setVisible(False) self.edtFirmwareFilePath.setVisible(False) self.btnChooseFirmwareFile.setVisible(False) self.tabFirmwareWebSources.setVisible(True) self.edtFirmwareNotes.setVisible(True) elif self.hw_firmware_source_type == FirmwareSource.LOCAL_FILE: self.lblFileLabel.setVisible(True) self.edtFirmwareFilePath.setVisible(True) self.btnChooseFirmwareFile.setVisible(True) self.tabFirmwareWebSources.setVisible(False) self.edtFirmwareNotes.setVisible(False) elif self.current_step == Step.STEP_PREPARE_FIRMWARE_DATA: self.update_action_subtitle('preparing firmware data') self.pages.setCurrentIndex(Pages.PAGE_PREPARE_FIRMWARE.value) elif self.current_step == Step.STEP_UPLOADING_FIRMWARE: self.update_action_subtitle('uploading firmware') self.pages.setCurrentIndex(Pages.PAGE_UPLOAD_FIRMWARE.value) elif self.current_step == Step.STEP_FINISHED_UPDATE: self.update_action_subtitle('update finished') self.pages.setCurrentIndex(Pages.PAGE_MESSAGE.value) self.lblMessage.setText('<b>Firmware update has been completed successfully.<br>Now you can ' 'restart your hardware wallet in normal mode.</b>') else: self.show_message_page('Connect Trezor/Keepkey hardware wallet') except Exception as e: WndUtils.error_msg(str(e), True)
def recover_hw(self): try: self.hw_conn_change_allowed = False use_pin = True if self.chbUsePIN.isChecked() else False use_passphrase = True if self.chbUsePassphrase.isChecked( ) else False label = self.edtDeviceLabel.text() if self.scenario == Scenario.ON_DEVICE: input_type: Literal["scrambled_words", "matrix"] = "scrambled_words" if self.cur_hw_device.hw_type == HWType.trezor: if self.rbWordsMatrix.isChecked(): input_type = "matrix" self.hw_devices.recover_device( self.cur_hw_device, word_count=self.word_count, passphrase_enabled=use_passphrase, pin_enabled=use_pin, hw_label=label, input_type=input_type, parent_window=self.parent_dialog) elif self.scenario in (Scenario.IN_APP_WORDS, Scenario.IN_APP_ENTROPY): words = ' '.join(self.entropy_to_mnemonic(self.entropy)) pin = self.edtPrimaryPIN.text() if use_pin else '' secondary_pin = self.edtSecondaryPIN.text() passphrase = self.edtPassphrase.text( ) if use_passphrase else '' self.hw_devices.recover_device_with_seed_input( self.cur_hw_device, words, pin, passphrase, secondary_pin) else: raise Exception('Not implemented') self.set_current_step(Step.STEP_FINISHED) except CancelException: self.go_to_prev_step() self.hw_devices.open_hw_session(self.cur_hw_device, force_reconnect=True) except Exception as e: self.go_to_prev_step() WndUtils.error_msg(str(e), True) finally: self.hw_conn_change_allowed = True
def rpc_command(self, command: str, *args): if self.main_dlg.dashd_intf: ret = self.main_dlg.dashd_intf.rpc_call(False, True, 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.error_msg('Not connected to a Dash node') return False
def generate_rpcauth(self) -> bool: user = self.edtUser.text() password = self.edtPassword.text() ret = True if not user: WndUtils.error_msg('Enter username') ret = False if not password: WndUtils.error_msg('Enter password') ret = False salt = hexlify(urandom(16)).decode() m = hmac.new(bytearray(salt, 'utf-8'), bytearray(password, 'utf-8'), 'SHA256') password_hmac = m.hexdigest() self.rpcauth = f'rpcauth={user}:{salt}${password_hmac}' return ret
def update_ui(self): try: if self.cur_hw_device and self.cur_hw_device.hw_client and self.cur_hw_device.hw_type != HWType.ledger_nano: if self.current_step == Step.STEP_INPUT_OPTIONS: self.pages.setCurrentIndex(Pages.PAGE_OPTIONS.value) self.update_action_subtitle( 'enter hardware wallet options') elif self.current_step == Step.STEP_INITIALIZING_HW: self.update_action_subtitle('initializing device') self.pages.setCurrentIndex(Pages.PAGE_OPTIONS.value) elif self.current_step == Step.STEP_FINISHED: self.update_action_subtitle('finished') self.show_message_page( '<b>Hardware wallet successfully initialized.</b>') return self.show_action_page() else: self.show_message_page( 'Connect Trezor/Keepkey hardware wallet') except Exception as e: WndUtils.error_msg(str(e), True)
def upload_firmware_thread(self, ctrl: CtrlObject): """ Thread that performs upload of the selected firmware to the hardware wallet device. The device has to be in bootloader mode. """ def add_info(msg: str): def append_message_mainth(msg_: str): t = self.lblUploadFirmwareMessage.text() t += f'<div>{msg}</div>' self.lblUploadFirmwareMessage.setText(t) WndUtils.call_in_main_thread(append_message_mainth, msg) update_ok = False try: self.hw_conn_change_allowed = False add_info('Uploading new firmware.<br><br><b>Click the confirmation button on your hardware wallet device ' 'if necessary.</b>') if self.cur_hw_device.hw_type == HWType.trezor: update_ok = self.cur_hw_device.hw_client.firmware_update(self.selected_firmware_source_web.fingerprint, self.firmware_data) elif self.cur_hw_device.hw_type == HWType.keepkey: update_ok = self.cur_hw_device.hw_client.firmware_update(BytesIO(self.firmware_data)) else: WndUtils.call_in_main_thread(self.go_to_prev_step) raise Exception('Invalid hardware wallet type') if not update_ok: WndUtils.error_msg('Operation failed. Look into the log file for details.') except CancelException: pass except Exception as e: WndUtils.error_msg('Operation failed with the following error: ' + str(e)) finally: self.hw_conn_change_allowed = True self.upload_firmware_thread_obj = None if update_ok: WndUtils.call_in_main_thread(self.go_to_next_step) else: WndUtils.call_in_main_thread(self.go_to_prev_step)
def apply_words_input(self) -> bool: """ Read all the seed words from the editor and convert them to entropy (self.entropy) :return: True if successful, False otherwise """ success = True if self.scenario == Scenario.IN_APP_WORDS: wl = self.mnemonic.wordlist invalid_indexes = [] suppress_error_message = False for idx, word in enumerate( self.words_wdg.get_cur_mnemonic_words()): if not word: WndUtils.error_msg( 'Cannot continue - not all words are entered.') success = False suppress_error_message = True break if word not in wl: success = False invalid_indexes.append(idx) if not success: # verify the whole word-set entered by the user (checksum) if not suppress_error_message: WndUtils.error_msg( 'Cannot continue - invalid word(s): %s.' % ','.join(['#' + str(x + 1) for x in invalid_indexes])) else: try: ws = self.words_wdg.get_cur_mnemonic_words() self.entropy = self.mnemonic.to_entropy(ws) except Exception as e: success = False if str(e) == 'Failed checksum.': WndUtils.error_msg( 'Invalid checksum of the provided words. You\'ve probably mistyped some' ' words or changed their order.') else: WndUtils.error_msg( 'There was an error in the provided word-list. Error details: ' + str(e)) return success
def go_to_next_step(self): if self.current_step == Step.STEP_SELECT_FIRMWARE_SOURCE: if self.hw_firmware_source_type == FirmwareSource.INTERNET: if not self.selected_firmware_source_web: WndUtils.error_msg('No firmware selected.') return elif self.hw_firmware_source_type == FirmwareSource.LOCAL_FILE: if not os.path.isfile(self.selected_firmware_source_file): WndUtils.error_msg('You must enter the name and path to the firmware file to be uploaded to the ' 'device.') return self.current_step = Step.STEP_PREPARE_FIRMWARE_DATA self.set_controls_initial_state_for_step(False) self.update_ui() WndUtils.run_thread(self, self.prepare_firmware_upload_thread, ()) elif self.current_step == Step.STEP_PREPARE_FIRMWARE_DATA: # reconnect hardware wallet device to check if it in bootloader mode self.hw_devices.open_hw_session(self.cur_hw_device, force_reconnect=True) if self.cur_hw_device and self.cur_hw_device.hw_client: if self.cur_hw_device.bootloader_mode: if self.upload_firmware_thread_obj is None: self.current_step = Step.STEP_UPLOADING_FIRMWARE self.set_controls_initial_state_for_step(False) self.update_ui() self.upload_firmware_thread_obj = WndUtils.run_thread(self, self.upload_firmware_thread, ()) else: logging.error('Thread upload_firmware_thread is already running') else: WndUtils.error_msg("Enter your hardware wallet into bootloader mode.") else: WndUtils.error_msg("Your hardware wallet doesn't seem to be connected.") elif self.current_step == Step.STEP_UPLOADING_FIRMWARE: self.current_step = Step.STEP_FINISHED_UPDATE self.set_controls_initial_state_for_step(False) self.update_ui()
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.dashd_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.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.") 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.dashd_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.5 minutes.' WndUtils.info_msg(msg) except Exception as e: if str(e).find('protx-dup') >= 0: WndUtils.error_msg( '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.error_msg(str(e))
def operation_failed(message: str): WndUtils.error_msg(message) self.set_btn_continue_enabled(False) self.set_btn_back_enabled(True) self.set_btn_cancel_enabled(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.dash_network) if owner_address != self.dmn_owner_address: raise Exception( 'Inconsistency of the owner key between the app configuration and the data ' 'on the Dash 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.dashd_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.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.") 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.dashd_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.info_msg(msg) except Exception as e: if str(e).find('protx-dup') >= 0: WndUtils.error_msg( '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.error_msg(str(e))
def update_ui(self): try: green_color = get_widget_font_color_green(self) if self.cur_hw_device and self.cur_hw_device.hw_client and self.cur_hw_device.hw_type != HWType.ledger_nano: if self.current_step == Step.STEP_SETTINGS: self.show_action_page() self.wdgHwSettings.setVisible(True) self.lblMessage.setVisible(False) self.read_hw_features() version_info_msg = self.hw_opt_firmware_version if self.cur_hw_device.bootloader_mode: self.lblFirmwareVersionLabel.setText( 'Bootloader version:') else: self.lblFirmwareVersionLabel.setText( 'Firmware version:') cur_fw_version = self.cur_hw_device.firmware_version latest_fw_version_src = self.latest_firmwares.get( self.cur_hw_device.get_hw_model()) latest_fw_version = latest_fw_version_src.version if latest_fw_version_src else None if cur_fw_version and latest_fw_version and \ app_utils.is_version_greater(latest_fw_version, cur_fw_version): if re.match('\s*http(s)?://', latest_fw_version_src.notes, re.IGNORECASE): ver_str = f'<a href={latest_fw_version_src.notes}>{latest_fw_version}</a>' else: ver_str = latest_fw_version version_info_msg += f' <span style="color:{green_color}">(new version available: ' + ver_str + ')</span>' self.lblFirmwareVersion.setText(version_info_msg) if self.hw_opt_pin_protection is True: self.lblPinStatus.setText('enabled') self.btnEnDisPin.setText('Disable') self.btnEnDisPin.setEnabled(True) self.btnChangePin.setEnabled(True) self.lblPinStatus.setStyleSheet( f'QLabel{{color: {green_color}}}') elif self.hw_opt_pin_protection is False: self.lblPinStatus.setText('disabled') self.btnEnDisPin.setText('Enable') self.btnEnDisPin.setEnabled(True) self.btnChangePin.setEnabled(True) self.lblPinStatus.setStyleSheet('QLabel{color: red}') else: self.lblPinStatus.setText('not available') self.lblPinStatus.setStyleSheet( 'QLabel{color: orange}') self.btnEnDisPin.setText('Enable') self.btnEnDisPin.setDisabled(True) self.btnChangePin.setDisabled(True) if self.hw_opt_passphrase_protection is True: self.lblPassStatus.setText('enabled') self.lblPassStatus.setStyleSheet( f'QLabel{{color: {green_color}}}') self.btnEnDisPass.setText('Disable') self.btnEnDisPass.setEnabled(True) elif self.hw_opt_passphrase_protection is False: self.lblPassStatus.setText('disabled') self.lblPassStatus.setStyleSheet('QLabel{color: red}') self.btnEnDisPass.setText('Enable') self.btnEnDisPass.setEnabled(True) else: self.lblPassStatus.setText('not available') self.lblPassStatus.setStyleSheet( 'QLabel{color: orange}') self.btnEnDisPass.setText('Enable') self.btnEnDisPass.setDisabled(True) if self.hw_opt_passphrase_always_on_device is True: self.lblPassAlwaysOnDeviceStatus.setText('enabled') self.lblPassAlwaysOnDeviceStatus.setStyleSheet( f'QLabel{{color: {green_color}}}') self.btnEnDisPassAlwaysOnDevice.setText('Disable') self.btnEnDisPassAlwaysOnDevice.setEnabled(True) elif self.hw_opt_passphrase_always_on_device is False: self.lblPassAlwaysOnDeviceStatus.setText('disabled') self.lblPassAlwaysOnDeviceStatus.setStyleSheet( 'QLabel{color: red}') self.btnEnDisPassAlwaysOnDevice.setText('Enable') self.btnEnDisPassAlwaysOnDevice.setEnabled(True) else: self.lblPassAlwaysOnDeviceStatus.setText( 'not available') self.lblPassAlwaysOnDeviceStatus.setStyleSheet( 'QLabel{color: orange}') self.btnEnDisPassAlwaysOnDevice.setText('Enable') self.btnEnDisPassAlwaysOnDevice.setDisabled(True) if self.hw_opt_wipe_code_protection is True: self.lblWipeCodeStatus.setText('enabled') self.lblWipeCodeStatus.setStyleSheet( f'QLabel{{color: {green_color}}}') self.btnEnDisWipeCode.setText('Disable') self.btnEnDisWipeCode.setEnabled(True) elif self.hw_opt_wipe_code_protection is False: self.lblWipeCodeStatus.setText('disabled') self.lblWipeCodeStatus.setStyleSheet( 'QLabel{color: red}') self.btnEnDisWipeCode.setText('Enable') self.btnEnDisWipeCode.setEnabled(True) else: self.lblWipeCodeStatus.setText('not available') self.lblWipeCodeStatus.setStyleSheet( 'QLabel{color: orange}') self.btnEnDisWipeCode.setText('Enable') self.btnEnDisWipeCode.setDisabled(True) if self.hw_opt_sd_protection is True: self.lblSDCardProtectionStatus.setText('enabled') self.lblSDCardProtectionStatus.setStyleSheet( f'QLabel{{color: {green_color}}}') self.btnEnDisSDCardProtection.setText('Disable') self.btnEnDisSDCardProtection.setEnabled(True) self.btnRefreshSDCardProtection.setEnabled(True) elif self.hw_opt_sd_protection is False: self.lblSDCardProtectionStatus.setText('disabled') self.lblSDCardProtectionStatus.setStyleSheet( 'QLabel{color: red}') self.btnEnDisSDCardProtection.setText('Enable') self.btnEnDisSDCardProtection.setEnabled(True) self.btnRefreshSDCardProtection.setEnabled(True) else: self.lblSDCardProtectionStatus.setText('not available') self.lblSDCardProtectionStatus.setStyleSheet( 'QLabel{color: orange}') self.btnEnDisSDCardProtection.setText('Enable') self.btnEnDisSDCardProtection.setDisabled(True) self.btnRefreshSDCardProtection.setDisabled(True) if self.cur_hw_device.device_label: self.lblLabelValue.setText( self.cur_hw_device.device_label) else: self.lblLabelValue.setText('not set') else: self.show_message_page( 'Connect Trezor/Keepkey hardware wallet') except Exception as e: WndUtils.error_msg(str(e), True)
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.dashd_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.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.") 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.dashd_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.query_dlg( 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.info_msg(msg) except Exception as e: if str(e).find('protx-dup') >= 0: WndUtils.error_msg( '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.error_msg(str(e))
def update_ui(self): try: # if self.cur_hw_device and self.cur_hw_device.hw_client: if self.cur_hw_device: if self.current_step == Step.STEP_SEED_SOURCE: self.pages.setCurrentIndex(Pages.PAGE_SEED_SOURCE.value) self.update_action_subtitle('choose scenario') if self.cur_hw_device.hw_type in (HWType.trezor, HWType.keepkey): self.rbSeedSourceHwScreen.setEnabled(True) self.rbSeedSourceAppWords.setEnabled(False) self.rbSeedSourceAppEntropy.setEnabled(False) self.rbSeedSourceHwScreen.setChecked(True) elif self.cur_hw_device.hw_type == HWType.ledger_nano: self.rbSeedSourceHwScreen.setEnabled(False) self.rbSeedSourceAppWords.setEnabled(True) self.rbSeedSourceAppEntropy.setEnabled(True) if not self.rbSeedSourceAppWords.isChecked( ) and not self.rbSeedSourceAppEntropy.isChecked(): self.rbSeedSourceAppWords.setChecked(True) if self.scenario in (Scenario.IN_APP_WORDS, Scenario.IN_APP_ENTROPY): self.lblActionTypeMessage.setVisible(True) self.lblActionTypeMessage.setText( '<b style="color:red">Use this method only for test seeds and for real seeds only on an ' 'offline computer that will never be connected to the network.</b>' ) else: self.lblActionTypeMessage.setVisible(False) elif self.current_step == Step.STEP_NUMBER_OF_WORDS: self.update_action_subtitle('number of seed words') self.pages.setCurrentIndex( Pages.PAGE_NUMBER_OF_WORDS.value) if self.cur_hw_device.get_hw_model() == HWModel.trezor_t: self.lblPage1Message.show() self.lblPage1Message.setText( 'Note: Trezor T may ask you for the number words of your recovery ' 'seed regardless of this setting.') else: self.lblPage1Message.hide() elif self.current_step == Step.STEP_HEX_ENTROPY: self.update_action_subtitle('hexadecimal entropy') self.pages.setCurrentIndex(Pages.PAGE_HEX_ENTROPY.value) elif self.current_step == Step.STEP_SEED_WORDS: self.update_action_subtitle('seed words') self.pages.setCurrentIndex(Pages.PAGE_SEED_WORDS.value) elif self.current_step == Step.STEP_OPTIONS: self.update_action_subtitle('hardware wallet options') self.pages.setCurrentIndex(Pages.PAGE_OPTIONS.value) if self.cur_hw_device.hw_type in (HWType.trezor, HWType.keepkey): self.btnShowPIN.hide() self.edtPrimaryPIN.hide() self.edtPassphrase.hide() self.btnShowPassphrase.hide() self.edtSecondaryPIN.hide() self.btnShowSecondaryPIN.hide() self.edtDeviceLabel.show() self.lblDeviceLabel.show() self.lblPinMessage.show() self.lblPinMessage.setText( 'Note: if set, the device will ask you for a new PIN ' 'during the recovery.') self.lblPassphraseMessage.show() self.lblPassphraseMessage.setText( '<span style="color:gray">Note: passphrase is not stored on the device - if this setting ' 'is on, you will<br>be asked for it every time you open the wallet.</span>' ) elif self.cur_hw_device.hw_type == HWType.ledger_nano: self.btnShowPIN.show() self.edtPrimaryPIN.show() self.edtPassphrase.show() self.btnShowPassphrase.show() self.edtSecondaryPIN.show() self.btnShowSecondaryPIN.show() self.edtDeviceLabel.hide() self.lblDeviceLabel.hide() self.lblPinMessage.hide() self.lblPassphraseMessage.hide() if self.chbUsePIN.isChecked(): self.edtPrimaryPIN.setReadOnly(False) self.btnShowPIN.setEnabled(True) self.edtSecondaryPIN.setReadOnly(False) self.btnShowSecondaryPIN.setEnabled(True) else: self.edtPrimaryPIN.setReadOnly(True) self.btnShowPIN.setDisabled(True) self.edtSecondaryPIN.setReadOnly(True) self.btnShowSecondaryPIN.setDisabled(True) if self.chbUsePassphrase.isChecked(): self.edtPassphrase.setReadOnly(False) self.btnShowPassphrase.setEnabled(True) else: self.edtPassphrase.setReadOnly(True) self.btnShowPassphrase.setDisabled(True) if self.scenario == Scenario.IN_APP_WORDS and self.entropy: self.lblOptionsEntropy.setText( 'Your recovery seed hexadecimal entropy: ' + self.entropy.hex()) self.lblOptionsEntropy.setVisible(True) else: self.lblOptionsEntropy.setVisible(False) # if self.scenario in (Scenario.IN_APP_WORDS, Scenario.IN_APP_ENTROPY): # self.btnPreviewAddresses.show() # else: # self.btnPreviewAddresses.hide() if self.scenario == Scenario.ON_DEVICE and self.cur_hw_device.get_hw_model( ) == HWModel.trezor_one: self.lblDeviceWordsInputType.show() self.gbDeviceWordsInputType.show() else: self.lblDeviceWordsInputType.hide() self.gbDeviceWordsInputType.hide() if self.cur_hw_device.hw_type in (HWType.trezor, HWType.keepkey): if self.cur_hw_device.initialized: self.lblOptionsPageMessage.show() self.lblOptionsPageMessage.setText( 'Note: The currently selected device is initialized. If you ' 'continue, the device will be wiped before starting recovery.' ) self.lblOptionsPageMessage.setWordWrap(True) self.lblOptionsPageMessage.setStyleSheet( 'QLabel{color:red}') else: self.lblOptionsPageMessage.hide() elif self.cur_hw_device.hw_type == HWType.ledger_nano: msg_text = '<span><b>Important! Start your Ledger Nano S wallet in recovery mode:</b></span>' \ '<ol><li>Clear the device by selecting the \'Settings->Device->Reset all\' (Nano ' \ 'S) or \'Security->Reset device\' (Nano X) menu ' \ 'item.</li>' \ '<li>Power the device off.</li>' \ '<li>Power the device on while holding down the right-hand (Nano S) or left-hand ' \ '(Nano X) physical button.</li>' \ '</ol>' self.lblOptionsPageMessage.show() self.lblOptionsPageMessage.setText(msg_text) self.lblOptionsPageMessage.setStyleSheet('') elif self.current_step == Step.STEP_FINISHED: self.update_action_subtitle('finished') self.show_message_page( '<b>Hardware wallet successfully recovered.</b>') return elif self.current_step == Step.STEP_NO_HW_ERROR: return self.show_action_page() else: self.show_message_page( 'Connect Trezor/Keepkey hardware wallet') except Exception as e: WndUtils.error_msg(str(e), True)