Browse Source

implement bip39 seed to wallet

fix auto-upgrade wallet
patch-4
Sander van Grieken 3 years ago
parent
commit
e329c54162
  1. 4
      electrum/gui/qml/components/OpenWallet.qml
  2. 30
      electrum/gui/qml/components/Wallets.qml
  3. 44
      electrum/gui/qml/components/wizard/WCBIP39Refine.qml
  4. 4
      electrum/gui/qml/qebitcoin.py
  5. 5
      electrum/gui/qml/qewallet.py
  6. 50
      electrum/gui/qml/qewalletdb.py

4
electrum/gui/qml/components/OpenWallet.qml

@ -95,10 +95,6 @@ Pane {
Daemon.availableWallets.reload() Daemon.availableWallets.reload()
app.stack.pop() app.stack.pop()
} }
onRequiresUpgradeChanged: {
if (requiresUpgrade)
wallet_db.doUpgrade()
}
onReadyChanged: { onReadyChanged: {
if (ready) { if (ready) {
Daemon.load_wallet(Daemon.path, password.text) Daemon.load_wallet(Daemon.path, password.text)

30
electrum/gui/qml/components/Wallets.qml

@ -1,6 +1,7 @@
import QtQuick 2.6 import QtQuick 2.6
import QtQuick.Layouts 1.0 import QtQuick.Layouts 1.0
import QtQuick.Controls 2.0 import QtQuick.Controls 2.0
import QtQuick.Controls.Material 2.0
import org.electrum 1.0 import org.electrum 1.0
@ -25,25 +26,25 @@ Pane {
columns: 4 columns: 4
Label { text: 'Wallet'; Layout.columnSpan: 2 } Label { text: 'Wallet'; Layout.columnSpan: 2 }
Label { text: Daemon.walletName; Layout.columnSpan: 2 } Label { text: Daemon.walletName; Layout.columnSpan: 2; color: Material.accentColor }
Label { text: 'derivation path (BIP32)'; visible: Daemon.currentWallet.isDeterministic; Layout.columnSpan: 2 }
Label { text: Daemon.currentWallet.derivationPath; visible: Daemon.currentWallet.isDeterministic; color: Material.accentColor; Layout.columnSpan: 2 }
Label { text: 'txinType' } Label { text: 'txinType' }
Label { text: Daemon.currentWallet.txinType } Label { text: Daemon.currentWallet.txinType; color: Material.accentColor }
Label { text: 'is deterministic' } Label { text: 'is deterministic' }
Label { text: Daemon.currentWallet.isDeterministic } Label { text: Daemon.currentWallet.isDeterministic; color: Material.accentColor }
Label { text: 'is watch only' } Label { text: 'is watch only' }
Label { text: Daemon.currentWallet.isWatchOnly } Label { text: Daemon.currentWallet.isWatchOnly; color: Material.accentColor }
Label { text: 'is Encrypted' } Label { text: 'is Encrypted' }
Label { text: Daemon.currentWallet.isEncrypted } Label { text: Daemon.currentWallet.isEncrypted; color: Material.accentColor }
Label { text: 'is Hardware' } Label { text: 'is Hardware' }
Label { text: Daemon.currentWallet.isHardware } Label { text: Daemon.currentWallet.isHardware; color: Material.accentColor }
Label { text: 'derivation path (BIP32)'; visible: Daemon.currentWallet.isDeterministic }
Label { text: Daemon.currentWallet.derivationPath; visible: Daemon.currentWallet.isDeterministic }
} }
} }
// } // }
@ -75,16 +76,19 @@ Pane {
} }
RowLayout { RowLayout {
x: 10
spacing: 10 spacing: 10
width: parent.width - 20 width: parent.width
Image { Image {
source: "../../kivy/theming/light/wallet.png" id: walleticon
source: "../../icons/wallet.png"
fillMode: Image.PreserveAspectFit
Layout.preferredWidth: 32
Layout.preferredHeight: 32
} }
Label { Label {
font.pointSize: 11 font.pixelSize: 18
text: model.name text: model.name
Layout.fillWidth: true Layout.fillWidth: true
} }

44
electrum/gui/qml/components/wizard/WCBIP39Refine.qml

@ -10,24 +10,36 @@ WizardComponent {
valid: false valid: false
onAccept: { onAccept: {
wizard_data['script_type'] = scripttypegroup.checkedButton.scripttype
wizard_data['derivation_path'] = derivationpathtext.text
} }
function getScriptTypePurposeDict() {
function setDerivationPath() { return {
var addrtype = {
'p2pkh': 44, 'p2pkh': 44,
'p2wpkh-p2sh': 49, 'p2wpkh-p2sh': 49,
'p2wpkh': 84 'p2wpkh': 84
} }
var nChain = Network.isTestNet ? 1 : 0 }
function validate() {
valid = false
if (!scripttypegroup.checkedButton.scripttype in getScriptTypePurposeDict())
return
if (!bitcoin.verify_derivation_path(derivationpathtext.text))
return
valid = true
}
function setDerivationPath() {
var p = getScriptTypePurposeDict()
derivationpathtext.text = derivationpathtext.text =
"m/" + addrtype[addresstypegroup.checkedButton.addresstype] + "'/" "m/" + p[scripttypegroup.checkedButton.scripttype] + "'/"
+ (Network.isTestNet ? 1 : 0) + "'/0'" + (Network.isTestNet ? 1 : 0) + "'/0'"
} }
ButtonGroup { ButtonGroup {
id: addresstypegroup id: scripttypegroup
onCheckedButtonChanged: { onCheckedButtonChanged: {
console.log('button changed: ' + checkedButton.addresstype)
setDerivationPath() setDerivationPath()
} }
} }
@ -50,18 +62,18 @@ WizardComponent {
} }
Label { text: qsTr('Choose the type of addresses in your wallet.') } Label { text: qsTr('Choose the type of addresses in your wallet.') }
RadioButton { RadioButton {
ButtonGroup.group: addresstypegroup ButtonGroup.group: scripttypegroup
property string addresstype: 'p2pkh' property string scripttype: 'p2pkh'
text: qsTr('legacy (p2pkh)') text: qsTr('legacy (p2pkh)')
} }
RadioButton { RadioButton {
ButtonGroup.group: addresstypegroup ButtonGroup.group: scripttypegroup
property string addresstype: 'p2wpkh-p2sh' property string scripttype: 'p2wpkh-p2sh'
text: qsTr('wrapped segwit (p2wpkh-p2sh)') text: qsTr('wrapped segwit (p2wpkh-p2sh)')
} }
RadioButton { RadioButton {
ButtonGroup.group: addresstypegroup ButtonGroup.group: scripttypegroup
property string addresstype: 'p2wpkh' property string scripttype: 'p2wpkh'
checked: true checked: true
text: qsTr('native segwit (p2wpkh)') text: qsTr('native segwit (p2wpkh)')
} }
@ -73,8 +85,14 @@ WizardComponent {
id: derivationpathtext id: derivationpathtext
Layout.fillWidth: true Layout.fillWidth: true
placeholderText: qsTr('Derivation path') placeholderText: qsTr('Derivation path')
onTextChanged: validate()
} }
} }
} }
Bitcoin {
id: bitcoin
}
} }

4
electrum/gui/qml/qebitcoin.py

@ -4,6 +4,7 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from electrum.logging import get_logger from electrum.logging import get_logger
from electrum.keystore import bip39_is_checksum_valid from electrum.keystore import bip39_is_checksum_valid
from electrum.bip32 import is_bip32_derivation
from electrum.slip39 import decode_mnemonic, Slip39Error from electrum.slip39 import decode_mnemonic, Slip39Error
from electrum import mnemonic from electrum import mnemonic
@ -107,3 +108,6 @@ class QEBitcoin(QObject):
self._logger.debug('seed verified: ' + str(seed_valid)) self._logger.debug('seed verified: ' + str(seed_valid))
@pyqtSlot(str, result=bool)
def verify_derivation_path(self, path):
return is_bip32_derivation(path)

5
electrum/gui/qml/qewallet.py

@ -175,7 +175,10 @@ class QEWallet(QObject):
@pyqtProperty('QString', notify=dataChanged) @pyqtProperty('QString', notify=dataChanged)
def derivationPath(self): def derivationPath(self):
return self.wallet.get_address_path_str(self.wallet.dummy_address()) keystores = self.wallet.get_keystores()
if len(keystores) > 1:
self._logger.debug('multiple keystores not supported yet')
return keystores[0].get_derivation_prefix()
balanceChanged = pyqtSignal() balanceChanged = pyqtSignal()

50
electrum/gui/qml/qewalletdb.py

@ -5,6 +5,7 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from electrum.logging import Logger, get_logger from electrum.logging import Logger, get_logger
from electrum.storage import WalletStorage, StorageEncryptionVersion from electrum.storage import WalletStorage, StorageEncryptionVersion
from electrum.wallet_db import WalletDB from electrum.wallet_db import WalletDB
from electrum.bip32 import normalize_bip32_derivation
from electrum.util import InvalidPassword from electrum.util import InvalidPassword
from electrum import keystore from electrum import keystore
@ -28,8 +29,6 @@ class QEWalletDB(QObject):
passwordChanged = pyqtSignal() passwordChanged = pyqtSignal()
invalidPasswordChanged = pyqtSignal() invalidPasswordChanged = pyqtSignal()
requiresSplitChanged = pyqtSignal() requiresSplitChanged = pyqtSignal()
requiresUpgradeChanged = pyqtSignal()
upgradingChanged = pyqtSignal()
splitFinished = pyqtSignal() splitFinished = pyqtSignal()
readyChanged = pyqtSignal() readyChanged = pyqtSignal()
createError = pyqtSignal([str], arguments=["error"]) createError = pyqtSignal([str], arguments=["error"])
@ -41,8 +40,6 @@ class QEWalletDB(QObject):
self._needsHWDevice = False self._needsHWDevice = False
self._password = '' self._password = ''
self._requiresSplit = False self._requiresSplit = False
self._requiresUpgrade = False
self._upgrading = False
self._invalidPassword = False self._invalidPassword = False
self._storage = None self._storage = None
@ -115,14 +112,6 @@ class QEWalletDB(QObject):
def requiresSplit(self): def requiresSplit(self):
return self._requiresSplit return self._requiresSplit
@pyqtProperty(bool, notify=requiresUpgradeChanged)
def requiresUpgrade(self):
return self._requiresUpgrade
@pyqtProperty(bool, notify=upgradingChanged)
def upgrading(self):
return self._upgrading
@pyqtProperty(bool, notify=invalidPasswordChanged) @pyqtProperty(bool, notify=invalidPasswordChanged)
def invalidPassword(self): def invalidPassword(self):
return self._invalidPassword return self._invalidPassword
@ -142,23 +131,6 @@ class QEWalletDB(QObject):
self.splitFinished.emit() self.splitFinished.emit()
@pyqtSlot()
def doUpgrade(self):
self._logger.warning('doUpgrade')
if not self._requiresUpgrade:
return
self._logger.warning('upgrading')
self._upgrading = True
self.upgradingChanged.emit()
self._db.upgrade()
self._db.write(self._storage)
self._upgrading = False
self.upgradingChanged.emit()
def load_storage(self): def load_storage(self):
self._storage = WalletStorage(self._path) self._storage = WalletStorage(self._path)
if not self._storage.file_exists(): if not self._storage.file_exists():
@ -188,15 +160,15 @@ class QEWalletDB(QObject):
self._requiresSplit = True self._requiresSplit = True
self.requiresSplitChanged.emit() self.requiresSplitChanged.emit()
return return
if self._db.requires_upgrade():
self._logger.warning('requires upgrade')
self._requiresUpgrade = True
self.requiresUpgradeChanged.emit()
return
if self._db.get_action(): if self._db.get_action():
self._logger.warning('action pending. QML version doesn\'t support continuation of wizard') self._logger.warning('action pending. QML version doesn\'t support continuation of wizard')
return return
if self._db.requires_upgrade():
self._logger.warning('wallet requires upgrade, upgrading')
self._db.upgrade()
self._db.write(self._storage)
self._ready = True self._ready = True
self.readyChanged.emit() self.readyChanged.emit()
@ -212,7 +184,15 @@ class QEWalletDB(QObject):
raise Exception('file already exists at path') raise Exception('file already exists at path')
storage = WalletStorage(path) storage = WalletStorage(path)
k = keystore.from_seed(data['seed'], data['seed_extra_words'], data['wallet_type'] == 'multisig') if data['seed_type'] in ['old', 'standard', 'segwit']: #2fa, 2fa-segwit
self._logger.debug('creating keystore from electrum seed')
k = keystore.from_seed(data['seed'], data['seed_extra_words'], data['wallet_type'] == 'multisig')
elif data['seed_type'] == 'bip39':
self._logger.debug('creating keystore from bip39 seed')
root_seed = keystore.bip39_to_seed(data['seed'], data['seed_extra_words'])
derivation = normalize_bip32_derivation(data['derivation_path'])
script = data['script_type'] if data['script_type'] != 'p2pkh' else 'standard'
k = keystore.from_bip43_rootseed(root_seed, derivation, xtype=script)
if data['encrypt']: if data['encrypt']:
storage.set_password(data['password'], enc_version=StorageEncryptionVersion.USER_PASSWORD) storage.set_password(data['password'], enc_version=StorageEncryptionVersion.USER_PASSWORD)

Loading…
Cancel
Save