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)
Пример #3
0
    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
Пример #4
0
 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))
Пример #6
0
    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)
Пример #7
0
 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()
Пример #8
0
 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)
Пример #9
0
 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)
Пример #10
0
    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))
Пример #11
0
    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
Пример #15
0
    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
Пример #16
0
 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)
Пример #24
0
    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)