From 2caa8f13cf63680e2fade196f6129a05e654c4ac Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Mon, 18 Sep 2023 23:56:17 +0200 Subject: [PATCH] wizard: make wizard.keystore_from_data more robust; - always store 'keystore_type' in cosigner data and use same types as main - dont share 'hardware_device' in root of dict, but store for each cosigner - properly return hardware keystore for hardware cosigners --- .../components/wizard/WCCosignerKeystore.qml | 8 ++++-- electrum/gui/qt/wizard/wallet.py | 28 +++++++++++-------- electrum/wizard.py | 10 ++++--- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/electrum/gui/qml/components/wizard/WCCosignerKeystore.qml b/electrum/gui/qml/components/wizard/WCCosignerKeystore.qml index c6d971c5a..46801a9b5 100644 --- a/electrum/gui/qml/components/wizard/WCCosignerKeystore.qml +++ b/electrum/gui/qml/components/wizard/WCCosignerKeystore.qml @@ -19,7 +19,9 @@ WizardComponent { function apply() { wizard_data['cosigner_keystore_type'] = keystoregroup.checkedButton.keystoretype wizard_data['multisig_current_cosigner'] = cosigner - wizard_data['multisig_cosigner_data'][cosigner.toString()] = {} + wizard_data['multisig_cosigner_data'][cosigner.toString()] = { + 'keystore_type': keystoregroup.checkedButton.keystoretype + } } ButtonGroup { @@ -80,13 +82,13 @@ WizardComponent { } ElRadioButton { ButtonGroup.group: keystoregroup - property string keystoretype: 'key' + property string keystoretype: 'masterkey' checked: true text: qsTr('Cosigner key') } ElRadioButton { ButtonGroup.group: keystoregroup - property string keystoretype: 'seed' + property string keystoretype: 'haveseed' text: qsTr('Cosigner seed') } } diff --git a/electrum/gui/qt/wizard/wallet.py b/electrum/gui/qt/wizard/wallet.py index 94d6ccad9..b644ed5ba 100644 --- a/electrum/gui/qt/wizard/wallet.py +++ b/electrum/gui/qt/wizard/wallet.py @@ -769,8 +769,8 @@ class WCCosignerKeystore(WizardComponent): message = _('Add a cosigner to your multi-sig wallet') choices = [ - ('key', _('Enter cosigner key')), - ('seed', _('Enter cosigner seed')), + ('masterkey', _('Enter cosigner key')), + ('haveseed', _('Enter cosigner seed')), ('hardware', _('Cosign with hardware device')) ] @@ -806,7 +806,9 @@ class WCCosignerKeystore(WizardComponent): def apply(self): self.wizard_data['cosigner_keystore_type'] = self.choice_w.selected_item[0] self.wizard_data['multisig_current_cosigner'] = self.cosigner - self.wizard_data['multisig_cosigner_data'][str(self.cosigner)] = {} + self.wizard_data['multisig_cosigner_data'][str(self.cosigner)] = { + 'keystore_type': self.choice_w.selected_item[0] + } class WCHaveMasterKey(WizardComponent): @@ -1214,8 +1216,8 @@ class WCChooseHWDevice(WizardComponent, Logger): def apply(self): if self.choice_w: - # TODO: data is not (de)serializable yet, wizard_data cannot be persisted - self.wizard_data['hardware_device'] = self.choice_w.selected_item[0] + cosigner_data = self.wizard.current_cosigner(self.wizard_data) + cosigner_data['hardware_device'] = self.choice_w.selected_item[0] class WCWalletPasswordHardware(WizardComponent): @@ -1307,7 +1309,8 @@ class WCHWXPub(WizardComponent, Logger): self.layout().addWidget(self.ok_l) def on_ready(self): - _name, _info = self.wizard_data['hardware_device'] + cosigner_data = self.wizard.current_cosigner(self.wizard_data) + _name, _info = cosigner_data['hardware_device'] self.plugin = self.plugins.get_plugin(_info.plugin_name) self.title = _('Retrieving extended public key from {} ({})').format(_info.model_name, _info.label) @@ -1316,9 +1319,8 @@ class WCHWXPub(WizardComponent, Logger): if not client.handler: client.handler = self.plugin.create_handler(self.wizard) - cosigner = self.wizard.current_cosigner(self.wizard_data) - xtype = cosigner['script_type'] - derivation = cosigner['derivation_path'] + xtype = cosigner_data['script_type'] + derivation = cosigner_data['derivation_path'] def get_xpub_task(client, derivation, xtype): try: @@ -1340,7 +1342,8 @@ class WCHWXPub(WizardComponent, Logger): t.start() def get_xpub_from_client(self, client, derivation, xtype): # override for HWW specific client if needed - _name, _info = self.wizard_data['hardware_device'] + cosigner_data = self.wizard.current_cosigner(self.wizard_data) + _name, _info = cosigner_data['hardware_device'] if xtype not in self.plugin.SUPPORTED_XTYPES: raise ScriptTypeNotSupported(_('This type of script is not supported with {}').format(_info.model_name)) return client.get_xpub(derivation, xtype) @@ -1362,8 +1365,8 @@ class WCHWXPub(WizardComponent, Logger): self.wizard.requestNext.emit() # via signal, so it triggers Next/Finish on GUI thread after on_updated() def apply(self): - _name, _info = self.wizard_data['hardware_device'] cosigner_data = self.wizard.current_cosigner(self.wizard_data) + _name, _info = cosigner_data['hardware_device'] cosigner_data['hw_type'] = _info.plugin_name cosigner_data['master_key'] = self.xpub cosigner_data['root_fingerprint'] = self.root_fingerprint @@ -1376,7 +1379,8 @@ class WCHWUninitialized(WizardComponent): WizardComponent.__init__(self, parent, wizard, title=_('Hardware not initialized')) def on_ready(self): - _name, _info = self.wizard_data['hardware_device'] + cosigner_data = self.wizard.current_cosigner(self.wizard_data) + _name, _info = cosigner_data['hardware_device'] label = WWLabel(_('This {} is not initialized. Use manufacturer tooling to initialize the device.').format(_info.model_name)) label.setAlignment(Qt.AlignCenter) self.layout().addWidget(label) diff --git a/electrum/wizard.py b/electrum/wizard.py index dc09e65ce..0ea5282eb 100644 --- a/electrum/wizard.py +++ b/electrum/wizard.py @@ -338,8 +338,8 @@ class NewWalletWizard(AbstractWizard): def on_cosigner_keystore_type(self, wizard_data: dict) -> str: t = wizard_data['cosigner_keystore_type'] return { - 'key': 'multisig_cosigner_key', - 'seed': 'multisig_cosigner_seed', + 'masterkey': 'multisig_cosigner_key', + 'haveseed': 'multisig_cosigner_seed', 'hardware': 'multisig_cosigner_hardware' }.get(t) @@ -396,7 +396,7 @@ class NewWalletWizard(AbstractWizard): return False def keystore_from_data(self, wallet_type: str, data: dict): - if 'seed' in data: + if data['keystore_type'] in ['createseed', 'haveseed'] and 'seed' in data: if data['seed_variant'] == 'electrum': return keystore.from_seed(data['seed'], data['seed_extra_words'], True) elif data['seed_variant'] == 'bip39': @@ -417,8 +417,10 @@ class NewWalletWizard(AbstractWizard): return keystore.from_bip43_rootseed(root_seed, derivation, xtype=script) else: raise Exception('Unsupported seed variant %s' % data['seed_variant']) - elif 'master_key' in data: + elif data['keystore_type'] == 'masterkey' and 'master_key' in data: return keystore.from_master_key(data['master_key']) + elif data['keystore_type'] == 'hardware': + return self.hw_keystore(data) else: raise Exception('no seed or master_key in data')