From 8cd95f1f7f1de783e55d2ddeae6d8d91033be52b Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Mon, 15 May 2023 16:19:48 +0200 Subject: [PATCH] qml: limit BIP39 cosigners script type to initial choice (bip39) or initial seed (electrum) --- .../qml/components/wizard/WCBIP39Refine.qml | 7 ++++++- .../gui/qml/components/wizard/WCHaveSeed.qml | 9 +++++++++ electrum/gui/qml/qebitcoin.py | 6 +++--- electrum/wizard.py | 20 +++++++++++-------- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/electrum/gui/qml/components/wizard/WCBIP39Refine.qml b/electrum/gui/qml/components/wizard/WCBIP39Refine.qml index 647c23c33..7f2599c9c 100644 --- a/electrum/gui/qml/components/wizard/WCBIP39Refine.qml +++ b/electrum/gui/qml/components/wizard/WCBIP39Refine.qml @@ -129,19 +129,24 @@ WizardComponent { property string scripttype: 'p2sh' text: qsTr('legacy multisig (p2sh)') visible: isMultisig + enabled: !cosigner || wizard_data['script_type'] == 'p2sh' + checked: cosigner ? wizard_data['script_type'] == 'p2sh' : false } RadioButton { ButtonGroup.group: scripttypegroup property string scripttype: 'p2wsh-p2sh' text: qsTr('p2sh-segwit multisig (p2wsh-p2sh)') visible: isMultisig + enabled: !cosigner || wizard_data['script_type'] == 'p2wsh-p2sh' + checked: cosigner ? wizard_data['script_type'] == 'p2wsh-p2sh' : false } RadioButton { ButtonGroup.group: scripttypegroup property string scripttype: 'p2wsh' - checked: isMultisig text: qsTr('native segwit multisig (p2wsh)') visible: isMultisig + enabled: !cosigner || wizard_data['script_type'] == 'p2wsh' + checked: cosigner ? wizard_data['script_type'] == 'p2wsh' : isMultisig } InfoTextArea { diff --git a/electrum/gui/qml/components/wizard/WCHaveSeed.qml b/electrum/gui/qml/components/wizard/WCHaveSeed.qml index c8fa5c797..eb1998da0 100644 --- a/electrum/gui/qml/components/wizard/WCHaveSeed.qml +++ b/electrum/gui/qml/components/wizard/WCHaveSeed.qml @@ -31,6 +31,15 @@ WizardComponent { wizard_data['seed_type'] = bitcoin.seedType wizard_data['seed_extend'] = extendcb.checked wizard_data['seed_extra_words'] = extendcb.checked ? customwordstext.text : '' + + // determine script type from electrum seed type + // (used to limit script type options for bip39 cosigners) + if (wizard_data['wallet_type'] == 'multisig' && seed_variant_cb.currentValue == 'electrum') { + wizard_data['script_type'] = { + 'standard': 'p2sh', + 'segwit': 'p2wsh' + }[bitcoin.seedType] + } } } diff --git a/electrum/gui/qml/qebitcoin.py b/electrum/gui/qml/qebitcoin.py index 95897d39f..e3a7304da 100644 --- a/electrum/gui/qml/qebitcoin.py +++ b/electrum/gui/qml/qebitcoin.py @@ -30,15 +30,15 @@ class QEBitcoin(QObject): self._validationMessage = '' self._words = None - @pyqtProperty('QString', notify=generatedSeedChanged) + @pyqtProperty(str, notify=generatedSeedChanged) def generatedSeed(self): return self._generated_seed - @pyqtProperty('QString', notify=seedTypeChanged) + @pyqtProperty(str, notify=seedTypeChanged) def seedType(self): return self._seed_type - @pyqtProperty('QString', notify=validationMessageChanged) + @pyqtProperty(str, notify=validationMessageChanged) def validationMessage(self): return self._validationMessage diff --git a/electrum/wizard.py b/electrum/wizard.py index 65ac64244..91a5801fe 100644 --- a/electrum/wizard.py +++ b/electrum/wizard.py @@ -275,7 +275,7 @@ class NewWalletWizard(AbstractWizard): self._logger.info('maybe_master_pubkey2') return - wizard_data['multisig_master_pubkey'] = self.keystore_from_data(wizard_data).get_master_public_key() + wizard_data['multisig_master_pubkey'] = self.keystore_from_data(wizard_data['wallet_type'], wizard_data).get_master_public_key() def on_cosigner_keystore_type(self, wizard_data): t = wizard_data['cosigner_keystore_type'] @@ -308,10 +308,10 @@ class NewWalletWizard(AbstractWizard): def has_duplicate_masterkeys(self, wizard_data) -> bool: """Multisig wallets need distinct master keys. If True, need to prevent wallet-creation.""" xpubs = [] - xpubs.append(self.keystore_from_data(wizard_data).get_master_public_key()) + xpubs.append(self.keystore_from_data(wizard_data['wallet_type'], wizard_data).get_master_public_key()) for cosigner in wizard_data['multisig_cosigner_data']: data = wizard_data['multisig_cosigner_data'][cosigner] - xpubs.append(self.keystore_from_data(data).get_master_public_key()) + xpubs.append(self.keystore_from_data(wizard_data['wallet_type'], data).get_master_public_key()) assert xpubs return len(xpubs) != len(set(xpubs)) @@ -321,10 +321,10 @@ class NewWalletWizard(AbstractWizard): If True, need to prevent wallet-creation. """ xpubs = [] - xpubs.append(self.keystore_from_data(wizard_data).get_master_public_key()) + xpubs.append(self.keystore_from_data(wizard_data['wallet_type'], wizard_data).get_master_public_key()) for cosigner in wizard_data['multisig_cosigner_data']: data = wizard_data['multisig_cosigner_data'][cosigner] - xpubs.append(self.keystore_from_data(data).get_master_public_key()) + xpubs.append(self.keystore_from_data(wizard_data['wallet_type'], data).get_master_public_key()) assert xpubs try: k_xpub_type = xpub_type(xpubs[0]) @@ -339,14 +339,18 @@ class NewWalletWizard(AbstractWizard): return True return False - def keystore_from_data(self, data): + def keystore_from_data(self, wallet_type, data): if 'seed' in data: if data['seed_variant'] == 'electrum': return keystore.from_seed(data['seed'], data['seed_extra_words'], True) elif data['seed_variant'] == 'bip39': root_seed = keystore.bip39_to_seed(data['seed'], data['seed_extra_words']) derivation = normalize_bip32_derivation(data['derivation_path']) - return keystore.from_bip43_rootseed(root_seed, derivation, xtype='p2wsh') + if wallet_type == 'multisig': + script = data['script_type'] if data['script_type'] != 'p2sh' else 'standard' + else: + script = data['script_type'] if data['script_type'] != 'p2pkh' else 'standard' + 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: @@ -448,7 +452,7 @@ class NewWalletWizard(AbstractWizard): db.put('wallet_type', '%dof%d' % (data['multisig_signatures'],data['multisig_participants'])) db.put('x1/', k.dump()) for cosigner in data['multisig_cosigner_data']: - cosigner_keystore = self.keystore_from_data(data['multisig_cosigner_data'][cosigner]) + cosigner_keystore = self.keystore_from_data('multisig', data['multisig_cosigner_data'][cosigner]) if not isinstance(cosigner_keystore, keystore.Xpub): raise Exception(f"unexpected keystore(cosigner) type={type(cosigner_keystore)} in multisig. not bip32.") if k_xpub_type != xpub_type(cosigner_keystore.xpub):