Browse Source

Catch wallet file related exceptions in Qt wizard.

3.2.x
SomberNight 7 years ago
parent
commit
61a45edee0
  1. 16
      gui/qt/__init__.py
  2. 13
      lib/bitcoin.py
  3. 20
      lib/keystore.py
  4. 26
      lib/storage.py
  5. 6
      lib/util.py
  6. 18
      lib/wallet.py
  7. 2
      plugins/trustedcoin/trustedcoin.py

16
gui/qt/__init__.py

@ -44,7 +44,8 @@ from electrum import WalletStorage
# from electrum.synchronizer import Synchronizer
# from electrum.verifier import SPV
# from electrum.util import DebugMem
from electrum.util import UserCancelled, print_error
from electrum.util import (UserCancelled, print_error,
WalletFileException, BitcoinException)
# from electrum.wallet import Abstract_Wallet
from .installwizard import InstallWizard, GoBack
@ -191,7 +192,7 @@ class ElectrumGui:
except BaseException as e:
traceback.print_exc(file=sys.stdout)
d = QMessageBox(QMessageBox.Warning, _('Error'),
_('Cannot load wallet:') + '\n' + str(e))
_('Cannot load wallet') + ' (1):\n' + str(e))
d.exec_()
return
if not wallet:
@ -203,7 +204,14 @@ class ElectrumGui:
pass
except GoBack as e:
print_error('[start_new_window] Exception caught (GoBack)', e)
wizard.terminate()
except (WalletFileException, BitcoinException) as e:
traceback.print_exc(file=sys.stderr)
d = QMessageBox(QMessageBox.Warning, _('Error'),
_('Cannot load wallet') + ' (2):\n' + str(e))
d.exec_()
return
finally:
wizard.terminate()
if not wallet:
return
@ -220,7 +228,7 @@ class ElectrumGui:
except BaseException as e:
traceback.print_exc(file=sys.stdout)
d = QMessageBox(QMessageBox.Warning, _('Error'),
_('Cannot create window for wallet:') + '\n' + str(e))
_('Cannot create window for wallet') + ':\n' + str(e))
d.exec_()
return
if uri:

13
lib/bitcoin.py

@ -32,7 +32,7 @@ import json
import ecdsa
import pyaes
from .util import bfh, bh2u, to_string
from .util import bfh, bh2u, to_string, BitcoinException
from . import version
from .util import print_error, InvalidPassword, assert_bytes, to_bytes, inv_dict
from . import segwit_addr
@ -349,7 +349,7 @@ def address_to_script(addr):
script += push_script(bh2u(hash_160))
script += '87' # op_equal
else:
raise BaseException('unknown address type')
raise BitcoinException('unknown address type: {}'.format(addrtype))
return script
def address_to_scripthash(addr):
@ -493,7 +493,8 @@ def deserialize_privkey(key):
vch = DecodeBase58Check(key)
except BaseException:
neutered_privkey = str(key)[:3] + '..' + str(key)[-2:]
raise BaseException("cannot deserialize", neutered_privkey)
raise BitcoinException("cannot deserialize privkey {}"
.format(neutered_privkey))
if txin_type is None:
# keys exported in version 3.0.x encoded script type in first byte
@ -888,7 +889,8 @@ def deserialize_xkey(xkey, prv, *, net=None):
net = constants.net
xkey = DecodeBase58Check(xkey)
if len(xkey) != 78:
raise BaseException('Invalid length')
raise BitcoinException('Invalid length for extended key: {}'
.format(len(xkey)))
depth = xkey[4]
fingerprint = xkey[5:9]
child_number = xkey[9:13]
@ -896,7 +898,8 @@ def deserialize_xkey(xkey, prv, *, net=None):
header = int('0x' + bh2u(xkey[0:4]), 16)
headers = net.XPRV_HEADERS if prv else net.XPUB_HEADERS
if header not in headers.values():
raise BaseException('Invalid xpub format', hex(header))
raise BitcoinException('Invalid extended key format: {}'
.format(hex(header)))
xtype = list(headers.keys())[list(headers.values()).index(header)]
n = 33 if prv else 32
K_or_k = xkey[13+n:]

20
lib/keystore.py

@ -29,7 +29,8 @@ from unicodedata import normalize
from . import bitcoin
from .bitcoin import *
from . import constants
from .util import PrintError, InvalidPassword, hfu
from .util import (PrintError, InvalidPassword, hfu, WalletFileException,
BitcoinException)
from .mnemonic import Mnemonic, load_wordlist
from .plugins import run_hook
@ -615,7 +616,8 @@ def xpubkey_to_address(x_pubkey):
mpk, s = Old_KeyStore.parse_xpubkey(x_pubkey)
pubkey = Old_KeyStore.get_pubkey_from_mpk(mpk, s[0], s[1])
else:
raise BaseException("Cannot parse pubkey")
raise BitcoinException("Cannot parse pubkey. prefix: {}"
.format(x_pubkey[0:2]))
if pubkey:
address = public_key_to_p2pkh(bfh(pubkey))
return pubkey, address
@ -634,14 +636,15 @@ def hardware_keystore(d):
if hw_type in hw_keystores:
constructor = hw_keystores[hw_type]
return constructor(d)
raise BaseException('unknown hardware type', hw_type)
raise WalletFileException('unknown hardware type: {}'.format(hw_type))
def load_keystore(storage, name):
w = storage.get('wallet_type', 'standard')
d = storage.get(name, {})
t = d.get('type')
if not t:
raise BaseException('wallet format requires update')
raise WalletFileException(
'Wallet format requires update.\n'
'Cannot find keystore for name {}'.format(name))
if t == 'old':
k = Old_KeyStore(d)
elif t == 'imported':
@ -651,7 +654,8 @@ def load_keystore(storage, name):
elif t == 'hardware':
k = hardware_keystore(d)
else:
raise BaseException('unknown wallet type', t)
raise WalletFileException(
'Unknown type {} for keystore named {}'.format(t, name))
return k
@ -709,7 +713,7 @@ def from_seed(seed, passphrase, is_p2sh):
xtype = 'p2wsh' if is_p2sh else 'p2wpkh'
keystore.add_xprv_from_seed(bip32_seed, xtype, der)
else:
raise BaseException(t)
raise BitcoinException('Unexpected seed type {}'.format(t))
return keystore
def from_private_key_list(text):
@ -743,5 +747,5 @@ def from_master_key(text):
elif is_xpub(text):
k = from_xpub(text)
else:
raise BaseException('Invalid key')
raise BitcoinException('Invalid master key')
return k

26
lib/storage.py

@ -33,7 +33,7 @@ import pbkdf2, hmac, hashlib
import base64
import zlib
from .util import PrintError, profiler, InvalidPassword
from .util import PrintError, profiler, InvalidPassword, WalletFileException
from .plugins import run_hook, plugin_loaders
from .keystore import bip44_derivation
from . import bitcoin
@ -113,7 +113,7 @@ class WalletStorage(PrintError):
if not self.manual_upgrades:
if self.requires_split():
raise BaseException("This wallet has multiple accounts and must be split")
raise WalletFileException("This wallet has multiple accounts and must be split")
if self.requires_upgrade():
self.upgrade()
@ -174,7 +174,7 @@ class WalletStorage(PrintError):
elif v == STO_EV_XPUB_PW:
return b'BIE2'
else:
raise Exception('no encryption magic for version: %s' % v)
raise WalletFileException('no encryption magic for version: %s' % v)
def decrypt(self, password):
ec_key = self.get_key(password)
@ -320,7 +320,7 @@ class WalletStorage(PrintError):
storage2.write()
result.append(new_path)
else:
raise BaseException("This wallet has multiple accounts and must be split")
raise WalletFileException("This wallet has multiple accounts and must be split")
return result
def requires_upgrade(self):
@ -419,7 +419,7 @@ class WalletStorage(PrintError):
d['seed'] = seed
self.put(key, d)
else:
raise Exception('Unable to tell wallet type. Is this even a wallet file?')
raise WalletFileException('Unable to tell wallet type. Is this even a wallet file?')
# remove junk
self.put('master_public_key', None)
self.put('master_public_keys', None)
@ -543,7 +543,7 @@ class WalletStorage(PrintError):
else:
addresses.append(addr)
if addresses and keypairs:
raise BaseException('mixed addresses and privkeys')
raise WalletFileException('mixed addresses and privkeys')
elif addresses:
self.put('addresses', addresses)
self.put('accounts', None)
@ -553,7 +553,7 @@ class WalletStorage(PrintError):
self.put('keypairs', keypairs)
self.put('accounts', None)
else:
raise BaseException('no addresses or privkeys')
raise WalletFileException('no addresses or privkeys')
def convert_account(self):
if not self._is_upgrade_method_needed(0, 13):
@ -566,9 +566,9 @@ class WalletStorage(PrintError):
if cur_version > max_version:
return False
elif cur_version < min_version:
raise BaseException(
('storage upgrade: unexpected version %d (should be %d-%d)'
% (cur_version, min_version, max_version)))
raise WalletFileException(
'storage upgrade: unexpected version {} (should be {}-{})'
.format(cur_version, min_version, max_version))
else:
return True
@ -584,7 +584,9 @@ class WalletStorage(PrintError):
if not seed_version:
seed_version = OLD_SEED_VERSION if len(self.get('master_public_key','')) == 128 else NEW_SEED_VERSION
if seed_version > FINAL_SEED_VERSION:
raise BaseException('This version of Electrum is too old to open this wallet')
raise WalletFileException('This version of Electrum is too old to open this wallet.\n'
'(highest supported storage version: {}, version of this file: {})'
.format(FINAL_SEED_VERSION, seed_version))
if seed_version==14 and self.get('seed_type') == 'segwit':
self.raise_unsupported_version(seed_version)
if seed_version >=12:
@ -607,4 +609,4 @@ class WalletStorage(PrintError):
else:
# creation was complete if electrum was run from source
msg += "\nPlease open this file with Electrum 1.9.8, and move your coins to a new wallet."
raise BaseException(msg)
raise WalletFileException(msg)

6
lib/util.py

@ -84,6 +84,12 @@ class TimeoutException(Exception):
return self.message
class WalletFileException(Exception): pass
class BitcoinException(Exception): pass
# Throw this exception to unwind the stack like when an error occurs.
# However unlike other exceptions the user won't be informed.
class UserCancelled(Exception):

18
lib/wallet.py

@ -44,7 +44,8 @@ import sys
from .i18n import _
from .util import (NotEnoughFunds, PrintError, UserCancelled, profiler,
format_satoshis, NoDynamicFeeEstimates, TimeoutException)
format_satoshis, NoDynamicFeeEstimates, TimeoutException,
WalletFileException, BitcoinException)
from .bitcoin import *
from .version import *
@ -131,6 +132,7 @@ def sweep_preparations(privkeys, network, imax=100):
find_utxos_for_privkey('p2pk', privkey, compressed)
if not inputs:
raise BaseException(_('No inputs found. (Note that inputs need to be confirmed)'))
# FIXME actually inputs need not be confirmed now, see https://github.com/kyuupichan/electrumx/issues/365
return inputs, keypairs
@ -335,7 +337,7 @@ class Abstract_Wallet(PrintError):
addrs = self.get_receiving_addresses()
if len(addrs) > 0:
if not bitcoin.is_address(addrs[0]):
raise Exception('The addresses in this wallet are not bitcoin addresses.')
raise WalletFileException('The addresses in this wallet are not bitcoin addresses.')
def synchronize(self):
pass
@ -1166,7 +1168,7 @@ class Abstract_Wallet(PrintError):
_type, data, value = o
if _type == TYPE_ADDRESS:
if not is_address(data):
raise BaseException("Invalid bitcoin address:" + data)
raise BaseException("Invalid bitcoin address: {}".format(data))
if value == '!':
if i_max is not None:
raise BaseException("More than one output set to spend max")
@ -1339,7 +1341,7 @@ class Abstract_Wallet(PrintError):
def bump_fee(self, tx, delta):
if tx.is_final():
raise BaseException(_("Cannot bump fee: transaction is final"))
raise BaseException(_('Cannot bump fee') + ': ' + _('transaction is final'))
inputs = copy.deepcopy(tx.inputs())
outputs = copy.deepcopy(tx.outputs())
for txin in inputs:
@ -1370,7 +1372,7 @@ class Abstract_Wallet(PrintError):
if delta > 0:
continue
if delta > 0:
raise BaseException(_('Cannot bump fee: could not find suitable outputs'))
raise BaseException(_('Cannot bump fee') + ': ' + _('could not find suitable outputs'))
locktime = self.get_local_height()
tx_new = Transaction.from_io(inputs, outputs, locktime=locktime)
tx_new.BIP_LI01_sort()
@ -1944,14 +1946,14 @@ class Imported_Wallet(Simple_Wallet):
txin_type, pubkey = self.keystore.import_privkey(sec, pw)
except Exception:
neutered_privkey = str(sec)[:3] + '..' + str(sec)[-2:]
raise BaseException('Invalid private key', neutered_privkey)
raise BitcoinException('Invalid private key: {}'.format(neutered_privkey))
if txin_type in ['p2pkh', 'p2wpkh', 'p2wpkh-p2sh']:
if redeem_script is not None:
raise BaseException('Cannot use redeem script with', txin_type)
raise BitcoinException('Cannot use redeem script with script type {}'.format(txin_type))
addr = bitcoin.pubkey_to_address(txin_type, pubkey)
elif txin_type in ['p2sh', 'p2wsh', 'p2wsh-p2sh']:
if redeem_script is None:
raise BaseException('Redeem script required for', txin_type)
raise BitcoinException('Redeem script required for script type {}'.format(txin_type))
addr = bitcoin.redeem_script_to_address(txin_type, redeem_script)
else:
raise NotImplementedError(txin_type)

2
plugins/trustedcoin/trustedcoin.py

@ -406,7 +406,7 @@ class TrustedCoinPlugin(BasePlugin):
xprv1, xpub1 = self.get_xkeys(seed, passphrase, "m/0'/")
xprv2, xpub2 = self.get_xkeys(seed, passphrase, "m/1'/")
else:
raise BaseException('unrecognized seed length')
raise BaseException('unrecognized seed length: {} words'.format(n))
return xprv1, xpub1, xprv2, xpub2
def create_keystore(self, wizard, seed, passphrase):

Loading…
Cancel
Save