Browse Source

separation between wallet storage and config

283
ThomasV 11 years ago
parent
commit
d99a381d83
  1. 15
      electrum
  2. 74
      gui/gui_classic.py
  3. 10
      gui/gui_text.py
  4. 9
      gui/installwizard.py
  5. 2
      lib/__init__.py
  6. 2
      lib/interface.py
  7. 135
      lib/simple_config.py
  8. 202
      lib/wallet.py

15
electrum

@ -107,7 +107,7 @@ if __name__ == '__main__':
util.check_windows_wallet_migration() util.check_windows_wallet_migration()
config = SimpleConfig(config_options) config = SimpleConfig(config_options)
storage = WalletStorage(config)
if len(args)==0: if len(args)==0:
url = None url = None
@ -145,12 +145,12 @@ if __name__ == '__main__':
# instanciate wallet for command-line # instanciate wallet for command-line
wallet = Wallet(config) wallet = Wallet(storage)
if cmd not in known_commands: if cmd not in known_commands:
cmd = 'help' cmd = 'help'
if not config.wallet_file_exists and cmd not in ['help','create','restore']: if not storage.file_exists and cmd not in ['help','create','restore']:
print_msg("Error: Wallet file not found.") print_msg("Error: Wallet file not found.")
print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option") print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option")
sys.exit(0) sys.exit(0)
@ -203,7 +203,7 @@ if __name__ == '__main__':
wallet.set_verifier(verifier) wallet.set_verifier(verifier)
print_msg("Recovering wallet...") print_msg("Recovering wallet...")
WalletSynchronizer(wallet, config).start() WalletSynchronizer(wallet).start()
wallet.update() wallet.update()
if wallet.is_found(): if wallet.is_found():
print_msg("Recovery successful") print_msg("Recovery successful")
@ -317,9 +317,6 @@ if __name__ == '__main__':
message = ' '.join(args[min_args:]) message = ' '.join(args[min_args:])
print_msg("Warning: Final argument was reconstructed from several arguments:", repr(message)) print_msg("Warning: Final argument was reconstructed from several arguments:", repr(message))
args = args[0:min_args] + [ message ] args = args[0:min_args] + [ message ]
# open session # open session
@ -333,10 +330,10 @@ if __name__ == '__main__':
verifier = WalletVerifier(interface, config) verifier = WalletVerifier(interface, config)
verifier.start() verifier.start()
wallet.set_verifier(verifier) wallet.set_verifier(verifier)
synchronizer = WalletSynchronizer(wallet, config) synchronizer = WalletSynchronizer(wallet)
synchronizer.start() synchronizer.start()
wallet.update() wallet.update()
#wallet.save()
# run the command # run the command

74
gui/gui_classic.py

@ -43,6 +43,8 @@ from electrum.wallet import format_satoshis
from electrum.bitcoin import Transaction, is_valid from electrum.bitcoin import Transaction, is_valid
from electrum import mnemonic from electrum import mnemonic
from electrum import util, bitcoin, commands, Interface, Wallet, WalletVerifier, WalletSynchronizer from electrum import util, bitcoin, commands, Interface, Wallet, WalletVerifier, WalletSynchronizer
from electrum import SimpleConfig, Wallet, WalletSynchronizer, WalletStorage
import bmp, pyqrnative import bmp, pyqrnative
import exchange_rate import exchange_rate
@ -225,9 +227,12 @@ class ElectrumWindow(QMainWindow):
def __init__(self, config): def __init__(self, config):
QMainWindow.__init__(self) QMainWindow.__init__(self)
self.config = config
self.init_plugins()
self._close_electrum = False self._close_electrum = False
self.lite = None self.lite = None
self.config = config
self.current_account = self.config.get("current_account", None) self.current_account = self.config.get("current_account", None)
self.icon = QIcon(os.getcwd() + '/icons/electrum.png') self.icon = QIcon(os.getcwd() + '/icons/electrum.png')
@ -237,14 +242,14 @@ class ElectrumWindow(QMainWindow):
self.build_menu() self.build_menu()
self.tray.show() self.tray.show()
self.init_plugins()
self.create_status_bar() self.create_status_bar()
self.need_update = threading.Event() self.need_update = threading.Event()
self.expert_mode = config.get('classic_expert_mode', False) self.expert_mode = config.get('classic_expert_mode', False)
self.decimal_point = config.get('decimal_point', 8) self.decimal_point = config.get('decimal_point', 8)
self.num_zeros = int(config.get('num_zeros',0))
self.fee = int(config.get('fee_per_kb',20000))
set_language(config.get('language')) set_language(config.get('language'))
@ -287,11 +292,12 @@ class ElectrumWindow(QMainWindow):
tabs.setCurrentIndex (n) tabs.setCurrentIndex (n)
tabs.setCurrentIndex (0) tabs.setCurrentIndex (0)
# plugins that need to change the GUI do it here # plugins that need to change the GUI do it here
self.run_hook('init') self.run_hook('init')
def load_wallet(self, wallet): def load_wallet(self, wallet):
import electrum import electrum
self.wallet = wallet self.wallet = wallet
@ -301,7 +307,7 @@ class ElectrumWindow(QMainWindow):
self.wallet.interface.register_callback('disconnected', lambda: self.emit(QtCore.SIGNAL('update_status'))) self.wallet.interface.register_callback('disconnected', lambda: self.emit(QtCore.SIGNAL('update_status')))
self.wallet.interface.register_callback('disconnecting', lambda: self.emit(QtCore.SIGNAL('update_status'))) self.wallet.interface.register_callback('disconnecting', lambda: self.emit(QtCore.SIGNAL('update_status')))
self.wallet.interface.register_callback('new_transaction', lambda: self.emit(QtCore.SIGNAL('transaction_signal'))) self.wallet.interface.register_callback('new_transaction', lambda: self.emit(QtCore.SIGNAL('transaction_signal')))
title = 'Electrum ' + self.wallet.electrum_version + ' - ' + self.config.path title = 'Electrum ' + self.wallet.electrum_version + ' - ' #+ self.config.path
if not self.wallet.seed: title += ' [%s]' % (_('seedless')) if not self.wallet.seed: title += ' [%s]' % (_('seedless'))
self.setWindowTitle( title ) self.setWindowTitle( title )
self.update_wallet() self.update_wallet()
@ -326,21 +332,20 @@ class ElectrumWindow(QMainWindow):
def select_wallet_file(self): def select_wallet_file(self):
wallet_folder = self.wallet.config.path wallet_folder = self.wallet.storage.path
re.sub("(\/\w*.dat)$", "", wallet_folder) re.sub("(\/\w*.dat)$", "", wallet_folder)
file_name = unicode( QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder, "*.dat") ) file_name = unicode( QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder, "*.dat") )
return file_name return file_name
def open_wallet(self): def open_wallet(self):
from electrum import SimpleConfig, Wallet, WalletSynchronizer
filename = self.select_wallet_file() filename = self.select_wallet_file()
if not filename: if not filename:
return return
config = SimpleConfig({'wallet_path': filename}) storage = WalletStorage({'wallet_path': filename})
if not config.wallet_file_exists: if not storage.file_exists:
self.show_message("file not found "+ filename) self.show_message("file not found "+ filename)
return return
@ -348,30 +353,27 @@ class ElectrumWindow(QMainWindow):
verifier = self.wallet.verifier verifier = self.wallet.verifier
self.wallet.synchronizer.stop() self.wallet.synchronizer.stop()
self.config = config
# create wallet # create wallet
wallet = Wallet(config) wallet = Wallet(storage)
wallet.interface = interface wallet.interface = interface
wallet.verifier = verifier wallet.verifier = verifier
synchronizer = WalletSynchronizer(wallet, config) synchronizer = WalletSynchronizer(wallet)
synchronizer.start() synchronizer.start()
self.load_wallet(wallet) self.load_wallet(wallet)
def new_wallet(self): def new_wallet(self):
from electrum import SimpleConfig, Wallet, WalletSynchronizer
import installwizard import installwizard
wallet_folder = self.wallet.config.path wallet_folder = self.wallet.storage.path
re.sub("(\/\w*.dat)$", "", wallet_folder) re.sub("(\/\w*.dat)$", "", wallet_folder)
filename = self.getSaveFileName("Select your wallet file", wallet_folder, "*.dat") filename = self.getSaveFileName("Select your wallet file", wallet_folder, "*.dat")
config = SimpleConfig({'wallet_path': filename}) storage = WalletStorage({'wallet_path': filename})
assert not config.wallet_file_exists assert not storage.file_exists
wizard = installwizard.InstallWizard(config, self.wallet.interface) wizard = installwizard.InstallWizard(self.config, self.wallet.interface, storage)
wallet = wizard.run() wallet = wizard.run()
if wallet: if wallet:
self.load_wallet(wallet) self.load_wallet(wallet)
@ -522,14 +524,20 @@ class ElectrumWindow(QMainWindow):
return return
def set_fee(self, fee):
if self.fee != fee:
self.fee = fee
self.config.set_key('fee_per_kb', self.fee, True)
def set_label(self, name, text = None): def set_label(self, name, text = None):
changed = False changed = False
old_text = self.wallet.labels.get(name) old_text = self.wallet.labels.get(name)
if text: if text:
if old_text != text: if old_text != text:
self.wallet.labels[name] = text self.wallet.labels[name] = text
self.wallet.config.set_key('labels', self.wallet.labels) self.wallet.storage.set_key('labels', self.wallet.labels)
changed = True changed = True
else: else:
if old_text: if old_text:
@ -572,7 +580,7 @@ class ElectrumWindow(QMainWindow):
self.run_hook('timer_actions') self.run_hook('timer_actions')
def format_amount(self, x, is_diff=False, whitespaces=False): def format_amount(self, x, is_diff=False, whitespaces=False):
return format_satoshis(x, is_diff, self.wallet.num_zeros, self.decimal_point, whitespaces) return format_satoshis(x, is_diff, self.num_zeros, self.decimal_point, whitespaces)
def read_amount(self, x): def read_amount(self, x):
if x in['.', '']: return None if x in['.', '']: return None
@ -1966,7 +1974,7 @@ class ElectrumWindow(QMainWindow):
nz_label = QLabel(_('Display zeros')) nz_label = QLabel(_('Display zeros'))
grid_ui.addWidget(nz_label, 0, 0) grid_ui.addWidget(nz_label, 0, 0)
nz_e = AmountEdit(None,True) nz_e = AmountEdit(None,True)
nz_e.setText("%d"% self.wallet.num_zeros) nz_e.setText("%d"% self.num_zeros)
grid_ui.addWidget(nz_e, 0, 1) grid_ui.addWidget(nz_e, 0, 1)
msg = _('Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"') msg = _('Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"')
grid_ui.addWidget(HelpButton(msg), 0, 2) grid_ui.addWidget(HelpButton(msg), 0, 2)
@ -2022,7 +2030,7 @@ class ElectrumWindow(QMainWindow):
fee_label = QLabel(_('Transaction fee')) fee_label = QLabel(_('Transaction fee'))
grid_wallet.addWidget(fee_label, 0, 0) grid_wallet.addWidget(fee_label, 0, 0)
fee_e = AmountEdit(self.base_unit) fee_e = AmountEdit(self.base_unit)
fee_e.setText(self.format_amount(self.wallet.fee).strip()) fee_e.setText(self.format_amount(self.fee).strip())
grid_wallet.addWidget(fee_e, 0, 2) grid_wallet.addWidget(fee_e, 0, 2)
msg = _('Fee per kilobyte of transaction.') + ' ' \ msg = _('Fee per kilobyte of transaction.') + ' ' \
+ _('Recommended value') + ': ' + self.format_amount(50000) + _('Recommended value') + ': ' + self.format_amount(50000)
@ -2112,7 +2120,7 @@ class ElectrumWindow(QMainWindow):
QMessageBox.warning(self, _('Error'), _('Invalid value') +': %s'%fee, _('OK')) QMessageBox.warning(self, _('Error'), _('Invalid value') +': %s'%fee, _('OK'))
return return
self.wallet.set_fee(fee) self.set_fee(fee)
nz = unicode(nz_e.text()) nz = unicode(nz_e.text())
try: try:
@ -2122,8 +2130,8 @@ class ElectrumWindow(QMainWindow):
QMessageBox.warning(self, _('Error'), _('Invalid value')+':%s'%nz, _('OK')) QMessageBox.warning(self, _('Error'), _('Invalid value')+':%s'%nz, _('OK'))
return return
if self.wallet.num_zeros != nz: if self.num_zeros != nz:
self.wallet.num_zeros = nz self.num_zeros = nz
self.config.set_key('num_zeros', nz, True) self.config.set_key('num_zeros', nz, True)
self.update_history_tab() self.update_history_tab()
self.update_receive_tab() self.update_receive_tab()
@ -2211,23 +2219,23 @@ class ElectrumGui:
def main(self, url): def main(self, url):
found = self.config.wallet_file_exists storage = WalletStorage(self.config)
if not found: if not storage.file_exists:
import installwizard import installwizard
wizard = installwizard.InstallWizard(self.config, self.interface) wizard = installwizard.InstallWizard(self.config, self.interface, storage)
wallet = wizard.run() wallet = wizard.run()
if not wallet: if not wallet:
exit() exit()
else: else:
wallet = Wallet(self.config) wallet = Wallet(storage)
wallet.interface = self.interface wallet.interface = self.interface
verifier = WalletVerifier(self.interface, self.config) verifier = WalletVerifier(self.interface, storage)
verifier.start() verifier.start()
wallet.set_verifier(verifier) wallet.set_verifier(verifier)
synchronizer = WalletSynchronizer(wallet, self.config) synchronizer = WalletSynchronizer(wallet)
synchronizer.start() synchronizer.start()
s = Timer() s = Timer()

10
gui/gui_text.py

@ -5,7 +5,7 @@ _ = lambda x:x
from electrum.util import format_satoshis, set_verbosity from electrum.util import format_satoshis, set_verbosity
from electrum.bitcoin import is_valid from electrum.bitcoin import is_valid
from electrum import Wallet, WalletVerifier, WalletSynchronizer from electrum import Wallet, WalletVerifier, WalletSynchronizer, WalletStorage
import tty, sys import tty, sys
@ -15,19 +15,19 @@ class ElectrumGui:
def __init__(self, config, interface): def __init__(self, config, interface):
self.config = config self.config = config
found = self.config.wallet_file_exists storage = WalletStorage(config)
if not found: if not storage.file_exists:
print "Wallet not found. try 'electrum create'" print "Wallet not found. try 'electrum create'"
exit() exit()
wallet = Wallet(self.config) wallet = Wallet(storage)
wallet.interface = interface wallet.interface = interface
self.wallet = wallet self.wallet = wallet
verifier = WalletVerifier(interface, config) verifier = WalletVerifier(interface, config)
verifier.start() verifier.start()
wallet.set_verifier(verifier) wallet.set_verifier(verifier)
synchronizer = WalletSynchronizer(wallet, config) synchronizer = WalletSynchronizer(wallet)
synchronizer.start() synchronizer.start()
self.stdscr = curses.initscr() self.stdscr = curses.initscr()

9
gui/installwizard.py

@ -14,10 +14,11 @@ import sys
class InstallWizard(QDialog): class InstallWizard(QDialog):
def __init__(self, config, interface): def __init__(self, config, interface, storage):
QDialog.__init__(self) QDialog.__init__(self)
self.config = config self.config = config
self.interface = interface self.interface = interface
self.storage = storage
def restore_or_create(self): def restore_or_create(self):
@ -146,7 +147,7 @@ class InstallWizard(QDialog):
a = self.restore_or_create() a = self.restore_or_create()
if not a: exit() if not a: exit()
wallet = Wallet(self.config) wallet = Wallet(self.storage)
wallet.interface = self.interface wallet.interface = self.interface
if a =='create': if a =='create':
@ -179,10 +180,10 @@ class InstallWizard(QDialog):
#self.interface.start(wait = False) #self.interface.start(wait = False)
# start wallet threads # start wallet threads
verifier = WalletVerifier(self.interface, self.config) verifier = WalletVerifier(self.interface, self.storage)
verifier.start() verifier.start()
wallet.set_verifier(verifier) wallet.set_verifier(verifier)
synchronizer = WalletSynchronizer(wallet, self.config) synchronizer = WalletSynchronizer(wallet)
synchronizer.start() synchronizer.start()

2
lib/__init__.py

@ -1,6 +1,6 @@
from version import ELECTRUM_VERSION from version import ELECTRUM_VERSION
from util import format_satoshis, print_msg, print_json, print_error, set_verbosity from util import format_satoshis, print_msg, print_json, print_error, set_verbosity
from wallet import WalletSynchronizer from wallet import WalletSynchronizer, WalletStorage
from wallet_factory import WalletFactory as Wallet from wallet_factory import WalletFactory as Wallet
from verifier import WalletVerifier from verifier import WalletVerifier
from interface import Interface, pick_random_server, DEFAULT_SERVERS from interface import Interface, pick_random_server, DEFAULT_SERVERS

2
lib/interface.py

@ -392,7 +392,7 @@ class Interface(threading.Thread):
self.unanswered_requests[self.message_id] = method, params, channel self.unanswered_requests[self.message_id] = method, params, channel
ids.append(self.message_id) ids.append(self.message_id)
# uncomment to debug # uncomment to debug
# print "-->",request # print "-->", request
self.message_id += 1 self.message_id += 1
out += request + '\n' out += request + '\n'
while out: while out:

135
lib/simple_config.py

@ -6,6 +6,9 @@ from version import ELECTRUM_VERSION, SEED_VERSION
class SimpleConfig: class SimpleConfig:
""" """
The SimpleConfig class is responsible for handling operations involving The SimpleConfig class is responsible for handling operations involving
@ -29,46 +32,44 @@ a SimpleConfig instance then reads the wallet file.
# command-line options # command-line options
self.options_config = options self.options_config = options
self.wallet_config = {} # init path
self.wallet_file_exists = False self.init_path(options)
self.init_path(self.options_config.get('wallet_path'))
print_error( "path", self.path ) print "user dir", self.user_dir
if self.path:
self.read_wallet_config(self.path)
def init_path(self, options):
# Look for wallet file in the default data directory.
# Make wallet directory if it does not yet exist.
if not os.path.exists(self.user_dir):
os.mkdir(self.user_dir)
# portable wallet: use the same directory for wallet and headers file # portable wallet: use the same directory for wallet and headers file
if options.get('portable'): #if options.get('portable'):
self.wallet_config['blockchain_headers_path'] = os.path.dirname(self.path) # self.wallet_config['blockchain_headers_path'] = os.path.dirname(self.path)
def set_key(self, key, value, save = True):
def set_key(self, key, value, save = False):
# find where a setting comes from and save it there # find where a setting comes from and save it there
if self.options_config.get(key) is not None: if self.options_config.get(key) is not None:
print "Warning: not changing '%s' because it was passed as a command-line option"%key print "Warning: not changing '%s' because it was passed as a command-line option"%key
return return
elif self.user_config.get(key) is not None:
self.user_config[key] = value
if save: self.save_user_config()
elif self.system_config.get(key) is not None: elif self.system_config.get(key) is not None:
if str(self.system_config[key]) != str(value): if str(self.system_config[key]) != str(value):
print "Warning: not changing '%s' because it was set in the system configuration"%key print "Warning: not changing '%s' because it was set in the system configuration"%key
elif self.wallet_config.get(key) is not None:
self.wallet_config[key] = value
if save: self.save_wallet_config()
else: else:
# add key to wallet config self.user_config[key] = value
self.wallet_config[key] = value if save: self.save_user_config()
if save: self.save_wallet_config()
def get(self, key, default=None): def get(self, key, default=None):
"""Retrieve the filepath of the configuration file specified in the 'key' parameter."""
out = None
# 1. command-line options always override everything # 1. command-line options always override everything
if self.options_config.has_key(key) and self.options_config.get(key) is not None: if self.options_config.has_key(key) and self.options_config.get(key) is not None:
out = self.options_config.get(key) out = self.options_config.get(key)
@ -81,10 +82,6 @@ a SimpleConfig instance then reads the wallet file.
elif self.system_config.has_key(key): elif self.system_config.has_key(key):
out = self.system_config.get(key) out = self.system_config.get(key)
# 3. use the wallet file config
else:
out = self.wallet_config.get(key)
if out is None and default is not None: if out is None and default is not None:
out = default out = default
@ -135,85 +132,29 @@ a SimpleConfig instance then reads the wallet file.
"""Parse and store the user config settings in electrum.conf into user_config[].""" """Parse and store the user config settings in electrum.conf into user_config[]."""
if not self.user_dir: return if not self.user_dir: return
name = os.path.join( self.user_dir, 'electrum.conf') path = os.path.join(self.user_dir, "config")
if os.path.exists(name): if os.path.exists(path):
try: try:
import ConfigParser with open(path, "r") as f:
except ImportError: data = f.read()
print "cannot parse electrum.conf. please install ConfigParser" except IOError:
return return
p = ConfigParser.ConfigParser()
p.read(name)
try: try:
for k, v in p.items('client'): d = ast.literal_eval( data ) #parse raw data from reading wallet file
self.user_config[k] = v except:
except ConfigParser.NoSectionError: raise IOError("Cannot read config file.")
pass
def init_path(self, path):
"""Set the path of the wallet."""
if not path:
path = self.get('default_wallet_path')
if path is not None:
self.path = path
return
# Look for wallet file in the default data directory. self.user_config = d
# Make wallet directory if it does not yet exist.
if not os.path.exists(self.user_dir):
os.mkdir(self.user_dir)
self.path = os.path.join(self.user_dir, "electrum.dat")
def save_user_config(self): def save_user_config(self):
if not self.user_dir: return if not self.user_dir: return
import ConfigParser path = os.path.join(self.user_dir, "config")
config = ConfigParser.RawConfigParser() s = repr(self.user_config)
config.add_section('client') f = open(path,"w")
for k,v in self.user_config.items():
config.set('client', k, v)
with open( os.path.join( self.user_dir, 'electrum.conf'), 'wb') as configfile:
config.write(configfile)
def read_wallet_config(self, path):
"""Read the contents of the wallet file."""
try:
with open(self.path, "r") as f:
data = f.read()
except IOError:
return
try:
d = ast.literal_eval( data ) #parse raw data from reading wallet file
except:
raise IOError("Cannot read wallet file.")
self.wallet_config = d
self.wallet_file_exists = True
def save(self, key=None):
self.save_wallet_config()
def save_wallet_config(self):
# prevent the creation of incomplete wallets
#if self.wallet_config.get('master_public_keys') is None:
# return
s = repr(self.wallet_config)
f = open(self.path,"w")
f.write( s ) f.write( s )
f.close() f.close()
if self.get('gui') != 'android': if self.get('gui') != 'android':
import stat import stat
os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE) os.chmod(path, stat.S_IREAD | stat.S_IWRITE)

202
lib/wallet.py

@ -63,43 +63,112 @@ def pw_decode(s, password):
from version import ELECTRUM_VERSION, SEED_VERSION from version import ELECTRUM_VERSION, SEED_VERSION
class WalletStorage:
def __init__(self, config):
self.data = {}
self.file_exists = False
self.init_path(config)
print_error( "wallet path", self.path )
if self.path:
self.read(self.path)
def init_path(self, config):
"""Set the path of the wallet."""
path = config.get('wallet_path')
if not path:
path = config.get('default_wallet_path')
if path is not None:
self.path = path
return
# Look for wallet file in the default data directory.
# Make wallet directory if it does not yet exist.
if not os.path.exists(self.user_dir):
os.mkdir(self.user_dir)
self.path = os.path.join(self.user_dir, "electrum.dat")
def read(self, path):
"""Read the contents of the wallet file."""
try:
with open(self.path, "r") as f:
data = f.read()
except IOError:
return
try:
d = ast.literal_eval( data ) #parse raw data from reading wallet file
except:
raise IOError("Cannot read wallet file.")
self.data = d
self.file_exists = True
def get(self, key, default=None):
return self.data.get(key, default)
def put(self, key, value, save = True):
if self.data.get(key) is not None:
self.data[key] = value
else:
# add key to wallet config
self.data[key] = value
if save:
self.write()
def write(self):
s = repr(self.data)
f = open(self.path,"w")
f.write( s )
f.close()
if self.get('gui') != 'android':
import stat
os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE)
class Wallet: class Wallet:
def __init__(self, config={}):
self.config = config def __init__(self, storage):
self.storage = storage
self.electrum_version = ELECTRUM_VERSION self.electrum_version = ELECTRUM_VERSION
self.gap_limit_for_change = 3 # constant self.gap_limit_for_change = 3 # constant
# saved fields # saved fields
self.seed_version = config.get('seed_version', SEED_VERSION) self.seed_version = storage.get('seed_version', SEED_VERSION)
self.gap_limit = config.get('gap_limit', 5) self.gap_limit = storage.get('gap_limit', 5)
self.use_change = config.get('use_change',True) self.use_change = storage.get('use_change',True)
self.fee = int(config.get('fee_per_kb',20000)) self.use_encryption = storage.get('use_encryption', False)
self.num_zeros = int(config.get('num_zeros',0)) self.seed = storage.get('seed', '') # encrypted
self.use_encryption = config.get('use_encryption', False) self.labels = storage.get('labels', {})
self.seed = config.get('seed', '') # encrypted self.frozen_addresses = storage.get('frozen_addresses',[])
self.labels = config.get('labels', {}) self.prioritized_addresses = storage.get('prioritized_addresses',[])
self.frozen_addresses = config.get('frozen_addresses',[]) self.addressbook = storage.get('contacts', [])
self.prioritized_addresses = config.get('prioritized_addresses',[])
self.addressbook = config.get('contacts', [])
self.imported_keys = config.get('imported_keys',{}) self.imported_keys = storage.get('imported_keys',{})
self.history = config.get('addr_history',{}) # address -> list(txid, height) self.history = storage.get('addr_history',{}) # address -> list(txid, height)
self.master_public_keys = config.get('master_public_keys',{}) self.master_public_keys = storage.get('master_public_keys',{})
self.master_private_keys = config.get('master_private_keys', {}) self.master_private_keys = storage.get('master_private_keys', {})
self.first_addresses = config.get('first_addresses',{}) self.first_addresses = storage.get('first_addresses',{})
#if self.seed_version != SEED_VERSION: #if self.seed_version != SEED_VERSION:
# raise ValueError("This wallet seed is deprecated. Please restore from seed.") # raise ValueError("This wallet seed is deprecated. Please restore from seed.")
self.load_accounts(config) self.load_accounts()
self.transactions = {} self.transactions = {}
tx = config.get('transactions',{}) tx = storage.get('transactions',{})
try: try:
for k,v in tx.items(): self.transactions[k] = Transaction(v) for k,v in tx.items(): self.transactions[k] = Transaction(v)
except: except:
@ -153,13 +222,13 @@ class Wallet:
# store the originally requested keypair into the imported keys table # store the originally requested keypair into the imported keys table
self.imported_keys[address] = pw_encode(sec, password ) self.imported_keys[address] = pw_encode(sec, password )
self.config.set_key('imported_keys', self.imported_keys, True) self.storage.put('imported_keys', self.imported_keys, True)
return address return address
def delete_imported_key(self, addr): def delete_imported_key(self, addr):
if addr in self.imported_keys: if addr in self.imported_keys:
self.imported_keys.pop(addr) self.imported_keys.pop(addr)
self.config.set_key('imported_keys', self.imported_keys, True) self.storage.put('imported_keys', self.imported_keys, True)
def init_seed(self, seed): def init_seed(self, seed):
@ -170,8 +239,8 @@ class Wallet:
def save_seed(self): def save_seed(self):
self.config.set_key('seed', self.seed, True) self.storage.put('seed', self.seed, True)
self.config.set_key('seed_version', self.seed_version, True) self.storage.put('seed_version', self.seed_version, True)
master_k, master_c, master_K, master_cK = bip32_init(self.seed) master_k, master_c, master_K, master_cK = bip32_init(self.seed)
@ -203,8 +272,8 @@ class Wallet:
"m/5'/": k5 "m/5'/": k5
} }
self.config.set_key('master_public_keys', self.master_public_keys, True) self.storage.put('master_public_keys', self.master_public_keys, True)
self.config.set_key('master_private_keys', self.master_private_keys, True) self.storage.put('master_private_keys', self.master_private_keys, True)
# create default account # create default account
self.create_account('1','Main account') self.create_account('1','Main account')
@ -221,14 +290,14 @@ class Wallet:
# for safety, we ask the user to enter their seed # for safety, we ask the user to enter their seed
assert seed == self.decode_seed(password) assert seed == self.decode_seed(password)
self.seed = '' self.seed = ''
self.config.set_key('seed', '', True) self.storage.put('seed', '', True)
def deseed_branch(self, k): def deseed_branch(self, k):
# check that parent has no seed # check that parent has no seed
assert self.seed == '' assert self.seed == ''
self.master_private_keys.pop(k) self.master_private_keys.pop(k)
self.config.set_key('master_private_keys', self.master_private_keys, True) self.storage.put('master_private_keys', self.master_private_keys, True)
def account_id(self, account_type, i): def account_id(self, account_type, i):
@ -261,7 +330,7 @@ class Wallet:
account_id, account = self.next_account(account_type) account_id, account = self.next_account(account_type)
addr = account.first_address() addr = account.first_address()
self.first_addresses[k] = addr self.first_addresses[k] = addr
self.config.set_key('first_addresses',self.first_addresses) self.storage.put('first_addresses',self.first_addresses)
return addr return addr
@ -301,13 +370,13 @@ class Wallet:
self.save_accounts() self.save_accounts()
if name: if name:
self.labels[account_id] = name self.labels[account_id] = name
self.config.set_key('labels', self.labels, True) self.storage.put('labels', self.labels, True)
def create_old_account(self): def create_old_account(self):
print self.seed print self.seed
mpk = OldAccount.mpk_from_seed(self.seed) mpk = OldAccount.mpk_from_seed(self.seed)
self.config.set_key('master_public_key', mpk, True) self.storage.put('master_public_key', mpk, True)
self.accounts[0] = OldAccount({'mpk':mpk, 0:[], 1:[]}) self.accounts[0] = OldAccount({'mpk':mpk, 0:[], 1:[]})
self.save_accounts() self.save_accounts()
@ -316,16 +385,16 @@ class Wallet:
d = {} d = {}
for k, v in self.accounts.items(): for k, v in self.accounts.items():
d[k] = v.dump() d[k] = v.dump()
self.config.set_key('accounts', d, True) self.storage.put('accounts', d, True)
def load_accounts(self, config): def load_accounts(self):
d = config.get('accounts', {}) d = self.storage.get('accounts', {})
self.accounts = {} self.accounts = {}
for k, v in d.items(): for k, v in d.items():
if k == 0: if k == 0:
v['mpk'] = config.get('master_public_key') v['mpk'] = self.storage.get('master_public_key')
self.accounts[k] = OldAccount(v) self.accounts[k] = OldAccount(v)
elif '&' in k: elif '&' in k:
self.accounts[k] = BIP32_Account_2of2(v) self.accounts[k] = BIP32_Account_2of2(v)
@ -353,7 +422,7 @@ class Wallet:
def get_master_public_key(self): def get_master_public_key(self):
raise raise
return self.config.get("master_public_key") return self.storage.get("master_public_key")
def get_master_private_key(self, account, password): def get_master_private_key(self, account, password):
master_k = pw_decode( self.master_private_keys[account], password) master_k = pw_decode( self.master_private_keys[account], password)
@ -534,7 +603,7 @@ class Wallet:
def change_gap_limit(self, value): def change_gap_limit(self, value):
if value >= self.gap_limit: if value >= self.gap_limit:
self.gap_limit = value self.gap_limit = value
self.config.set_key('gap_limit', self.gap_limit, True) self.storage.put('gap_limit', self.gap_limit, True)
self.interface.poke('synchronizer') self.interface.poke('synchronizer')
return True return True
@ -547,7 +616,7 @@ class Wallet:
self.accounts[key][0] = addresses self.accounts[key][0] = addresses
self.gap_limit = value self.gap_limit = value
self.config.set_key('gap_limit', self.gap_limit, True) self.storage.put('gap_limit', self.gap_limit, True)
self.save_accounts() self.save_accounts()
return True return True
else: else:
@ -637,7 +706,7 @@ class Wallet:
new += self.synchronize_account(account) new += self.synchronize_account(account)
if new: if new:
self.save_accounts() self.save_accounts()
self.config.set_key('addr_history', self.history, True) self.storage.put('addr_history', self.history, True)
return new return new
@ -647,15 +716,15 @@ class Wallet:
def add_contact(self, address, label=None): def add_contact(self, address, label=None):
self.addressbook.append(address) self.addressbook.append(address)
self.config.set_key('contacts', self.addressbook, True) self.storage.put('contacts', self.addressbook, True)
if label: if label:
self.labels[address] = label self.labels[address] = label
self.config.set_key('labels', self.labels, True) self.storage.put('labels', self.labels, True)
def delete_contact(self, addr): def delete_contact(self, addr):
if addr in self.addressbook: if addr in self.addressbook:
self.addressbook.remove(addr) self.addressbook.remove(addr)
self.config.set_key('addressbook', self.addressbook, True) self.storage.put('addressbook', self.addressbook, True)
def fill_addressbook(self): def fill_addressbook(self):
@ -915,7 +984,7 @@ class Wallet:
tx = {} tx = {}
for k,v in self.transactions.items(): for k,v in self.transactions.items():
tx[k] = str(v) tx[k] = str(v)
self.config.set_key('transactions', tx, True) self.storage.put('transactions', tx, True)
def receive_history_callback(self, addr, hist): def receive_history_callback(self, addr, hist):
@ -924,7 +993,7 @@ class Wallet:
with self.lock: with self.lock:
self.history[addr] = hist self.history[addr] = hist
self.config.set_key('addr_history', self.history, True) self.storage.put('addr_history', self.history, True)
if hist != ['*']: if hist != ['*']:
for tx_hash, tx_height in hist: for tx_hash, tx_height in hist:
@ -1075,28 +1144,28 @@ class Wallet:
if new_password == '': new_password = None if new_password == '': new_password = None
# this will throw an exception if unicode cannot be converted # this will throw an exception if unicode cannot be converted
self.seed = pw_encode( seed, new_password) self.seed = pw_encode( seed, new_password)
self.config.set_key('seed', self.seed, True) self.storage.put('seed', self.seed, True)
self.use_encryption = (new_password != None) self.use_encryption = (new_password != None)
self.config.set_key('use_encryption', self.use_encryption,True) self.storage.put('use_encryption', self.use_encryption,True)
for k in self.imported_keys.keys(): for k in self.imported_keys.keys():
a = self.imported_keys[k] a = self.imported_keys[k]
b = pw_decode(a, old_password) b = pw_decode(a, old_password)
c = pw_encode(b, new_password) c = pw_encode(b, new_password)
self.imported_keys[k] = c self.imported_keys[k] = c
self.config.set_key('imported_keys', self.imported_keys, True) self.storage.put('imported_keys', self.imported_keys, True)
for k, v in self.master_private_keys.items(): for k, v in self.master_private_keys.items():
b = pw_decode(v, old_password) b = pw_decode(v, old_password)
c = pw_encode(b, new_password) c = pw_encode(b, new_password)
self.master_private_keys[k] = c self.master_private_keys[k] = c
self.config.set_key('master_private_keys', self.master_private_keys, True) self.storage.put('master_private_keys', self.master_private_keys, True)
def freeze(self,addr): def freeze(self,addr):
if self.is_mine(addr) and addr not in self.frozen_addresses: if self.is_mine(addr) and addr not in self.frozen_addresses:
self.unprioritize(addr) self.unprioritize(addr)
self.frozen_addresses.append(addr) self.frozen_addresses.append(addr)
self.config.set_key('frozen_addresses', self.frozen_addresses, True) self.storage.put('frozen_addresses', self.frozen_addresses, True)
return True return True
else: else:
return False return False
@ -1104,7 +1173,7 @@ class Wallet:
def unfreeze(self,addr): def unfreeze(self,addr):
if self.is_mine(addr) and addr in self.frozen_addresses: if self.is_mine(addr) and addr in self.frozen_addresses:
self.frozen_addresses.remove(addr) self.frozen_addresses.remove(addr)
self.config.set_key('frozen_addresses', self.frozen_addresses, True) self.storage.put('frozen_addresses', self.frozen_addresses, True)
return True return True
else: else:
return False return False
@ -1113,7 +1182,7 @@ class Wallet:
if self.is_mine(addr) and addr not in self.prioritized_addresses: if self.is_mine(addr) and addr not in self.prioritized_addresses:
self.unfreeze(addr) self.unfreeze(addr)
self.prioritized_addresses.append(addr) self.prioritized_addresses.append(addr)
self.config.set_key('prioritized_addresses', self.prioritized_addresses, True) self.storage.put('prioritized_addresses', self.prioritized_addresses, True)
return True return True
else: else:
return False return False
@ -1121,38 +1190,11 @@ class Wallet:
def unprioritize(self,addr): def unprioritize(self,addr):
if self.is_mine(addr) and addr in self.prioritized_addresses: if self.is_mine(addr) and addr in self.prioritized_addresses:
self.prioritized_addresses.remove(addr) self.prioritized_addresses.remove(addr)
self.config.set_key('prioritized_addresses', self.prioritized_addresses, True) self.storage.put('prioritized_addresses', self.prioritized_addresses, True)
return True return True
else: else:
return False return False
def set_fee(self, fee):
if self.fee != fee:
self.fee = fee
self.config.set_key('fee_per_kb', self.fee, True)
def save(self):
print_error("Warning: wallet.save() is deprecated")
tx = {}
for k,v in self.transactions.items():
tx[k] = str(v)
s = {
'use_change': self.use_change,
'fee_per_kb': self.fee,
'addr_history': self.history,
'labels': self.labels,
'contacts': self.addressbook,
'num_zeros': self.num_zeros,
'frozen_addresses': self.frozen_addresses,
'prioritized_addresses': self.prioritized_addresses,
'gap_limit': self.gap_limit,
'transactions': tx,
}
for k, v in s.items():
self.config.set_key(k,v)
self.config.save()
def set_verifier(self, verifier): def set_verifier(self, verifier):
self.verifier = verifier self.verifier = verifier
@ -1259,7 +1301,7 @@ class Wallet:
class WalletSynchronizer(threading.Thread): class WalletSynchronizer(threading.Thread):
def __init__(self, wallet, config): def __init__(self, wallet):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.daemon = True self.daemon = True
self.wallet = wallet self.wallet = wallet

Loading…
Cancel
Save