implement bip39 seed to wallet
fix auto-upgrade wallet
This commit is contained in:
@@ -95,10 +95,6 @@ Pane {
|
||||
Daemon.availableWallets.reload()
|
||||
app.stack.pop()
|
||||
}
|
||||
onRequiresUpgradeChanged: {
|
||||
if (requiresUpgrade)
|
||||
wallet_db.doUpgrade()
|
||||
}
|
||||
onReadyChanged: {
|
||||
if (ready) {
|
||||
Daemon.load_wallet(Daemon.path, password.text)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import QtQuick 2.6
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Controls.Material 2.0
|
||||
|
||||
import org.electrum 1.0
|
||||
|
||||
@@ -25,25 +26,25 @@ Pane {
|
||||
columns: 4
|
||||
|
||||
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: Daemon.currentWallet.txinType }
|
||||
Label { text: Daemon.currentWallet.txinType; color: Material.accentColor }
|
||||
|
||||
Label { text: 'is deterministic' }
|
||||
Label { text: Daemon.currentWallet.isDeterministic }
|
||||
Label { text: Daemon.currentWallet.isDeterministic; color: Material.accentColor }
|
||||
|
||||
Label { text: 'is watch only' }
|
||||
Label { text: Daemon.currentWallet.isWatchOnly }
|
||||
Label { text: Daemon.currentWallet.isWatchOnly; color: Material.accentColor }
|
||||
|
||||
Label { text: 'is Encrypted' }
|
||||
Label { text: Daemon.currentWallet.isEncrypted }
|
||||
Label { text: Daemon.currentWallet.isEncrypted; color: Material.accentColor }
|
||||
|
||||
Label { text: 'is Hardware' }
|
||||
Label { text: Daemon.currentWallet.isHardware }
|
||||
|
||||
Label { text: 'derivation path (BIP32)'; visible: Daemon.currentWallet.isDeterministic }
|
||||
Label { text: Daemon.currentWallet.derivationPath; visible: Daemon.currentWallet.isDeterministic }
|
||||
Label { text: Daemon.currentWallet.isHardware; color: Material.accentColor }
|
||||
}
|
||||
}
|
||||
// }
|
||||
@@ -75,16 +76,19 @@ Pane {
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
x: 10
|
||||
spacing: 10
|
||||
width: parent.width - 20
|
||||
width: parent.width
|
||||
|
||||
Image {
|
||||
source: "../../kivy/theming/light/wallet.png"
|
||||
id: walleticon
|
||||
source: "../../icons/wallet.png"
|
||||
fillMode: Image.PreserveAspectFit
|
||||
Layout.preferredWidth: 32
|
||||
Layout.preferredHeight: 32
|
||||
}
|
||||
|
||||
Label {
|
||||
font.pointSize: 11
|
||||
font.pixelSize: 18
|
||||
text: model.name
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
@@ -10,24 +10,36 @@ WizardComponent {
|
||||
valid: false
|
||||
|
||||
onAccept: {
|
||||
wizard_data['script_type'] = scripttypegroup.checkedButton.scripttype
|
||||
wizard_data['derivation_path'] = derivationpathtext.text
|
||||
}
|
||||
|
||||
function setDerivationPath() {
|
||||
var addrtype = {
|
||||
function getScriptTypePurposeDict() {
|
||||
return {
|
||||
'p2pkh': 44,
|
||||
'p2wpkh-p2sh': 49,
|
||||
'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 =
|
||||
"m/" + addrtype[addresstypegroup.checkedButton.addresstype] + "'/"
|
||||
"m/" + p[scripttypegroup.checkedButton.scripttype] + "'/"
|
||||
+ (Network.isTestNet ? 1 : 0) + "'/0'"
|
||||
}
|
||||
|
||||
ButtonGroup {
|
||||
id: addresstypegroup
|
||||
id: scripttypegroup
|
||||
onCheckedButtonChanged: {
|
||||
console.log('button changed: ' + checkedButton.addresstype)
|
||||
setDerivationPath()
|
||||
}
|
||||
}
|
||||
@@ -50,18 +62,18 @@ WizardComponent {
|
||||
}
|
||||
Label { text: qsTr('Choose the type of addresses in your wallet.') }
|
||||
RadioButton {
|
||||
ButtonGroup.group: addresstypegroup
|
||||
property string addresstype: 'p2pkh'
|
||||
ButtonGroup.group: scripttypegroup
|
||||
property string scripttype: 'p2pkh'
|
||||
text: qsTr('legacy (p2pkh)')
|
||||
}
|
||||
RadioButton {
|
||||
ButtonGroup.group: addresstypegroup
|
||||
property string addresstype: 'p2wpkh-p2sh'
|
||||
ButtonGroup.group: scripttypegroup
|
||||
property string scripttype: 'p2wpkh-p2sh'
|
||||
text: qsTr('wrapped segwit (p2wpkh-p2sh)')
|
||||
}
|
||||
RadioButton {
|
||||
ButtonGroup.group: addresstypegroup
|
||||
property string addresstype: 'p2wpkh'
|
||||
ButtonGroup.group: scripttypegroup
|
||||
property string scripttype: 'p2wpkh'
|
||||
checked: true
|
||||
text: qsTr('native segwit (p2wpkh)')
|
||||
}
|
||||
@@ -73,8 +85,14 @@ WizardComponent {
|
||||
id: derivationpathtext
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr('Derivation path')
|
||||
onTextChanged: validate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bitcoin {
|
||||
id: bitcoin
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
|
||||
|
||||
from electrum.logging import get_logger
|
||||
from electrum.keystore import bip39_is_checksum_valid
|
||||
from electrum.bip32 import is_bip32_derivation
|
||||
from electrum.slip39 import decode_mnemonic, Slip39Error
|
||||
from electrum import mnemonic
|
||||
|
||||
@@ -107,3 +108,6 @@ class QEBitcoin(QObject):
|
||||
|
||||
self._logger.debug('seed verified: ' + str(seed_valid))
|
||||
|
||||
@pyqtSlot(str, result=bool)
|
||||
def verify_derivation_path(self, path):
|
||||
return is_bip32_derivation(path)
|
||||
|
||||
@@ -175,7 +175,10 @@ class QEWallet(QObject):
|
||||
|
||||
@pyqtProperty('QString', notify=dataChanged)
|
||||
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()
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
|
||||
from electrum.logging import Logger, get_logger
|
||||
from electrum.storage import WalletStorage, StorageEncryptionVersion
|
||||
from electrum.wallet_db import WalletDB
|
||||
from electrum.bip32 import normalize_bip32_derivation
|
||||
from electrum.util import InvalidPassword
|
||||
from electrum import keystore
|
||||
|
||||
@@ -28,8 +29,6 @@ class QEWalletDB(QObject):
|
||||
passwordChanged = pyqtSignal()
|
||||
invalidPasswordChanged = pyqtSignal()
|
||||
requiresSplitChanged = pyqtSignal()
|
||||
requiresUpgradeChanged = pyqtSignal()
|
||||
upgradingChanged = pyqtSignal()
|
||||
splitFinished = pyqtSignal()
|
||||
readyChanged = pyqtSignal()
|
||||
createError = pyqtSignal([str], arguments=["error"])
|
||||
@@ -41,8 +40,6 @@ class QEWalletDB(QObject):
|
||||
self._needsHWDevice = False
|
||||
self._password = ''
|
||||
self._requiresSplit = False
|
||||
self._requiresUpgrade = False
|
||||
self._upgrading = False
|
||||
self._invalidPassword = False
|
||||
|
||||
self._storage = None
|
||||
@@ -115,14 +112,6 @@ class QEWalletDB(QObject):
|
||||
def requiresSplit(self):
|
||||
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)
|
||||
def invalidPassword(self):
|
||||
return self._invalidPassword
|
||||
@@ -142,23 +131,6 @@ class QEWalletDB(QObject):
|
||||
|
||||
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):
|
||||
self._storage = WalletStorage(self._path)
|
||||
if not self._storage.file_exists():
|
||||
@@ -188,15 +160,15 @@ class QEWalletDB(QObject):
|
||||
self._requiresSplit = True
|
||||
self.requiresSplitChanged.emit()
|
||||
return
|
||||
if self._db.requires_upgrade():
|
||||
self._logger.warning('requires upgrade')
|
||||
self._requiresUpgrade = True
|
||||
self.requiresUpgradeChanged.emit()
|
||||
return
|
||||
if self._db.get_action():
|
||||
self._logger.warning('action pending. QML version doesn\'t support continuation of wizard')
|
||||
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.readyChanged.emit()
|
||||
|
||||
@@ -212,7 +184,15 @@ class QEWalletDB(QObject):
|
||||
raise Exception('file already exists at 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']:
|
||||
storage.set_password(data['password'], enc_version=StorageEncryptionVersion.USER_PASSWORD)
|
||||
|
||||
Reference in New Issue
Block a user