URI: 
       tMerge branch '1.9' of git://github.com/spesmilo/electrum into 1.9 - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 9d1c31255c235a7506d29514b90628c3927d83be
   DIR parent cde1d0f6c07c9c340dcd89c937e8c3c0c2526c8d
  HTML Author: thomasv <thomasv@gitorious>
       Date:   Mon,  2 Sep 2013 11:16:35 +0200
       
       Merge branch '1.9' of git://github.com/spesmilo/electrum into 1.9
       
       Diffstat:
         M electrum                            |      47 +++++++++++++++----------------
         M gui/gui_classic.py                  |     180 +++++++++++++++++--------------
         M gui/gui_text.py                     |      16 +++++++++++++---
         M gui/installwizard.py                |      24 +++++++++++++++---------
         M gui/network_dialog.py               |       2 +-
         M gui/password_dialog.py              |       4 ----
         M lib/__init__.py                     |       5 +++--
         M lib/account.py                      |      74 ++++++++++---------------------
         A lib/blockchain.py                   |     329 +++++++++++++++++++++++++++++++
         M lib/interface.py                    |       2 +-
         M lib/simple_config.py                |     135 +++++++++----------------------
         M lib/verifier.py                     |     301 ++-----------------------------
         M lib/version.py                      |       2 +-
         M lib/wallet.py                       |     256 +++++++++++++++++++++----------
         M setup.py                            |       1 +
       
       15 files changed, 738 insertions(+), 640 deletions(-)
       ---
   DIR diff --git a/electrum b/electrum
       t@@ -107,7 +107,7 @@ if __name__ == '__main__':
                util.check_windows_wallet_migration()
        
            config = SimpleConfig(config_options)
       -
       +    storage = WalletStorage(config)
        
            if len(args)==0:
                url = None
       t@@ -133,10 +133,14 @@ if __name__ == '__main__':
                interface.start(wait = False)
                interface.send([('server.peers.subscribe',[])])
        
       -        gui = gui.ElectrumGui(config,interface)
       +        blockchain = BlockchainVerifier(interface, config)
       +        blockchain.start()
       +
       +        gui = gui.ElectrumGui(config, interface, blockchain)
                gui.main(url)
                
                interface.stop()
       +        blockchain.stop()
        
                # we use daemon threads, their termination is enforced.
                # this sleep command gives them time to terminate cleanly. 
       t@@ -145,12 +149,12 @@ if __name__ == '__main__':
        
        
            # instanciate wallet for command-line
       -    wallet = Wallet(config)
       +    wallet = Wallet(storage)
        
            if cmd not in known_commands:
                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("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option")
                sys.exit(0)
       t@@ -197,13 +201,11 @@ if __name__ == '__main__':
                        if not interface.start(wait=True):
                            print_msg("Not connected, aborting. Try option -o if you want to restore offline.")
                            sys.exit(1)
       -                wallet.interface = interface
       -                verifier = WalletVerifier(interface, config)
       -                verifier.start()
       -                wallet.set_verifier(verifier)
        
       +                blockchain = BlockchainVerifier(interface, config)
       +                blockchain.start()
       +                wallet.start_threads(interface, blockchain)
                        print_msg("Recovering wallet...")
       -                WalletSynchronizer(wallet, config).start()
                        wallet.update()
                        if wallet.is_found():
                            print_msg("Recovery successful")
       t@@ -317,26 +319,21 @@ if __name__ == '__main__':
                    message = ' '.join(args[min_args:])
                    print_msg("Warning: Final argument was reconstructed from several arguments:", repr(message))
                    args = args[0:min_args] + [ message ]
       -        
       -
       -
        
        
            # open session
            if cmd not in offline_commands and not options.offline:
                interface = Interface(config)
                interface.register_callback('connected', lambda: sys.stderr.write("Connected to " + interface.connection_msg + "\n"))
       +
                if not interface.start(wait=True):
                    print_msg("Not connected, aborting.")
                    sys.exit(1)
       -        wallet.interface = interface
       -        verifier = WalletVerifier(interface, config)
       -        verifier.start()
       -        wallet.set_verifier(verifier)
       -        synchronizer = WalletSynchronizer(wallet, config)
       -        synchronizer.start()
       +        blockchain = BlockchainVerifier(interface, config)
       +        blockchain.start()
       +        wallet.start_threads(interface, blockchain)
                wallet.update()
       -        #wallet.save()
       +
        
        
            # run the command
       t@@ -350,9 +347,9 @@ if __name__ == '__main__':
                    if raw_input("Are you sure you want to continue? (y/n) ") in ['y','Y','yes']:
                        wallet.config.path = ns
                        wallet.seed = ''
       -                wallet.config.set_key('seed', '', True)
       +                wallet.storage.put('seed', '', True)
                        wallet.use_encryption = False
       -                wallet.config.set_key('use_encryption', wallet.use_encryption, True)
       +                wallet.storage.put('use_encryption', wallet.use_encryption, True)
                        for k in wallet.imported_keys.keys(): wallet.imported_keys[k] = ''
                        wallet.config.set_key('imported_keys',wallet.imported_keys, True)
                        print_msg("Done.")
       t@@ -361,12 +358,12 @@ if __name__ == '__main__':
        
            elif cmd == 'getconfig':
                key = args[1]
       -        print_msg(wallet.config.get(key))
       +        print_msg(config.get(key))
        
            elif cmd == 'setconfig':
                key, value = args[1:3]
                if key not in ['seed', 'seed_version', 'master_public_key', 'use_encryption']:
       -            wallet.config.set_key(key, value, True)
       +            config.set_key(key, value, True)
                    print_msg(True)
                else:
                    print_msg(False)
       t@@ -394,8 +391,8 @@ if __name__ == '__main__':
                
        
            if cmd not in offline_commands and not options.offline:
       -        verifier.stop()
       -        synchronizer.stop()
       +        wallet.stop_threads()
                interface.stop()
       +        blockchain.stop()
                time.sleep(0.1)
                sys.exit(0)
   DIR diff --git a/gui/gui_classic.py b/gui/gui_classic.py
       t@@ -42,7 +42,9 @@ except:
        from electrum.wallet import format_satoshis
        from electrum.bitcoin import Transaction, is_valid
        from electrum import mnemonic
       -from electrum import util, bitcoin, commands, Interface, Wallet, WalletVerifier, WalletSynchronizer
       +from electrum import util, bitcoin, commands, Interface, Wallet
       +from electrum import SimpleConfig, Wallet, WalletStorage
       +
        
        import bmp, pyqrnative
        import exchange_rate
       t@@ -225,9 +227,12 @@ class ElectrumWindow(QMainWindow):
        
            def __init__(self, config):
                QMainWindow.__init__(self)
       +
       +        self.config = config
       +        self.init_plugins()
       +
                self._close_electrum = False
                self.lite = None
       -        self.config = config
                self.current_account = self.config.get("current_account", None)
        
                self.icon = QIcon(os.getcwd() + '/icons/electrum.png')
       t@@ -237,14 +242,13 @@ class ElectrumWindow(QMainWindow):
        
                self.build_menu()
                self.tray.show()
       -
       -        self.init_plugins()
                self.create_status_bar()
        
                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.num_zeros     = int(config.get('num_zeros',0))
        
                set_language(config.get('language'))
        
       t@@ -287,11 +291,12 @@ class ElectrumWindow(QMainWindow):
                    tabs.setCurrentIndex (n)
                    tabs.setCurrentIndex (0)
        
       -
                # plugins that need to change the GUI do it here
                self.run_hook('init')
        
        
       +
       +
            def load_wallet(self, wallet):
                import electrum
                self.wallet = wallet
       t@@ -301,7 +306,7 @@ class ElectrumWindow(QMainWindow):
                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('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.wallet.storage.path
                if not self.wallet.seed: title += ' [%s]' % (_('seedless'))
                self.setWindowTitle( title )
                self.update_wallet()
       t@@ -312,59 +317,59 @@ class ElectrumWindow(QMainWindow):
        
                # account selector
                accounts = self.wallet.get_accounts()
       +        self.account_selector.clear()
                if len(accounts) > 1:
                    self.account_selector.addItems([_("All accounts")] + accounts.values())
                    self.account_selector.setCurrentIndex(0)
       +            self.account_selector.show()
       +        else:
       +            self.account_selector.hide()
        
       +        self.update_lock_icon()
       +        self.update_buttons_on_seed()
       +        self.update_console()
        
        
            def select_wallet_file(self):
       -        wallet_folder = self.wallet.config.path
       +        wallet_folder = self.wallet.storage.path
                re.sub("(\/\w*.dat)$", "", wallet_folder)
                file_name = unicode( QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder, "*.dat") )
                return file_name
        
        
            def open_wallet(self):
       -        from electrum import SimpleConfig, Wallet, WalletSynchronizer
        
                filename = self.select_wallet_file()
                if not filename:
                    return
        
       -        config = SimpleConfig({'wallet_path': filename})
       -        if not config.wallet_file_exists:
       +        storage = WalletStorage({'wallet_path': filename})
       +        if not storage.file_exists:
                    self.show_message("file not found "+ filename)
                    return
        
                interface = self.wallet.interface
       -        verifier = self.wallet.verifier
       -        self.wallet.synchronizer.stop()
       +        blockchain = self.wallet.verifier.blockchain
       +        self.wallet.stop_threads()
                
       -        self.config = config
       -
       -        # create wallet 
       -        wallet = Wallet(config)
       -        wallet.interface = interface
       -        wallet.verifier = verifier
       -        synchronizer = WalletSynchronizer(wallet, config)
       -        synchronizer.start()
       +        # create new wallet 
       +        wallet = Wallet(storage)
       +        wallet.start_threads(interface, blockchain)
        
                self.load_wallet(wallet)
        
        
            def new_wallet(self):
       -        from electrum import SimpleConfig, Wallet, WalletSynchronizer
                import installwizard
        
       -        wallet_folder = self.wallet.config.path
       +        wallet_folder = self.wallet.storage.path
                re.sub("(\/\w*.dat)$", "", wallet_folder)
                filename = self.getSaveFileName("Select your wallet file", wallet_folder, "*.dat")
        
       -        config = SimpleConfig({'wallet_path': filename})
       -        assert not config.wallet_file_exists
       +        storage = WalletStorage({'wallet_path': filename})
       +        assert not storage.file_exists
        
       -        wizard = installwizard.InstallWizard(config, self.wallet.interface)
       +        wizard = installwizard.InstallWizard(self.config, self.wallet.interface, self.wallet.verifier.blockchain, storage)
                wallet = wizard.run()
                if wallet: 
                    self.load_wallet(wallet)
       t@@ -374,22 +379,29 @@ class ElectrumWindow(QMainWindow):
            def init_menubar(self):
                menubar = QMenuBar()
        
       -        electrum_menu = menubar.addMenu(_("&File"))
       -        open_wallet_action = electrum_menu.addAction(_("Open wallet"))
       +        file_menu = menubar.addMenu(_("&File"))
       +        open_wallet_action = file_menu.addAction(_("&Open"))
                open_wallet_action.triggered.connect(self.open_wallet)
        
       -        new_wallet_action = electrum_menu.addAction(_("New wallet"))
       +        new_wallet_action = file_menu.addAction(_("&Create/Restore"))
                new_wallet_action.triggered.connect(self.new_wallet)
        
       -        preferences_name = _("Preferences")
       -        if sys.platform == 'darwin':
       -            preferences_name = _("Electrum preferences") # Settings / Preferences are all reserved keywords in OSX using this as work around
       +        wallet_backup = file_menu.addAction(_("&Copy"))
       +        wallet_backup.triggered.connect(lambda: backup_wallet(self.wallet.storage.path))
       +
       +        quit_item = file_menu.addAction(_("&Close"))
       +        quit_item.triggered.connect(self.close)
       +
       +        wallet_menu = menubar.addMenu(_("&Wallet"))
        
       -        preferences_menu = electrum_menu.addAction(preferences_name)
       +        # Settings / Preferences are all reserved keywords in OSX using this as work around
       +        preferences_name = _("Electrum preferences") if sys.platform == 'darwin' else _("Preferences")
       +        preferences_menu = wallet_menu.addAction(preferences_name)
                preferences_menu.triggered.connect(self.settings_dialog)
       -        electrum_menu.addSeparator()
        
       -        raw_transaction_menu = electrum_menu.addMenu(_("&Load raw transaction"))
       +        wallet_menu.addSeparator()
       +
       +        raw_transaction_menu = wallet_menu.addMenu(_("&Load raw transaction"))
        
                raw_transaction_file = raw_transaction_menu.addAction(_("&From file"))
                raw_transaction_file.triggered.connect(self.do_process_from_file)
       t@@ -397,13 +409,7 @@ class ElectrumWindow(QMainWindow):
                raw_transaction_text = raw_transaction_menu.addAction(_("&From text"))
                raw_transaction_text.triggered.connect(self.do_process_from_text)
        
       -        electrum_menu.addSeparator()
       -        quit_item = electrum_menu.addAction(_("&Close"))
       -        quit_item.triggered.connect(self.close)
       -
       -        wallet_menu = menubar.addMenu(_("&Wallet"))
       -        wallet_backup = wallet_menu.addAction(_("&Create backup"))
       -        wallet_backup.triggered.connect(lambda: backup_wallet(self.config.path))
       +        wallet_menu.addSeparator()
        
                show_menu = wallet_menu.addMenu(_("Show"))
        
       t@@ -514,14 +520,15 @@ class ElectrumWindow(QMainWindow):
                        
                return
        
       -        
       +
       +
            def set_label(self, name, text = None):
                changed = False
                old_text = self.wallet.labels.get(name)
                if text:
                    if old_text != text:
                        self.wallet.labels[name] = text
       -                self.wallet.config.set_key('labels', self.wallet.labels)
       +                self.wallet.storage.put('labels', self.wallet.labels)
                        changed = True
                else:
                    if old_text:
       t@@ -564,7 +571,7 @@ class ElectrumWindow(QMainWindow):
                self.run_hook('timer_actions')
            
            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):
                if x in['.', '']: return None
       t@@ -850,14 +857,10 @@ class ElectrumWindow(QMainWindow):
                        _('Bitcoin transactions are in general not free. A transaction fee is paid by the sender of the funds.') + '\n\n'\
                            + _('The amount of fee can be decided freely by the sender. However, transactions with low fees take more time to be processed.') + '\n\n'\
                            + _('A suggested fee is automatically added to this field. You may override it. The suggested fee increases with the size of the transaction.')), 4, 3)
       -        b = ''
        
       -        if 1:#self.wallet.seed: 
       -            b = EnterButton(_("Send"), self.do_send)
       -        else:
       -            b = EnterButton(_("Create unsigned transaction"), self.do_send)
        
       -        grid.addWidget(b, 6, 1)
       +        self.send_button = EnterButton(_("Send"), self.do_send)
       +        grid.addWidget(self.send_button, 6, 1)
        
                b = EnterButton(_("Clear"),self.do_clear)
                grid.addWidget(b, 6, 2)
       t@@ -1339,10 +1342,12 @@ class ElectrumWindow(QMainWindow):
                from qt_console import Console
                self.console = console = Console()
                return console
       -    #
        
       -        self.console.history = self.config.get("console-history",[])
       -        self.console.history_index = len(self.console.history)
       +
       +    def update_console(self):
       +        console = self.console
       +        console.history = self.config.get("console-history",[])
       +        console.history_index = len(console.history)
        
                console.updateNamespace({'wallet' : self.wallet, 'interface' : self.wallet.interface, 'gui':self})
                console.updateNamespace({'util' : util, 'bitcoin':bitcoin})
       t@@ -1356,7 +1361,7 @@ class ElectrumWindow(QMainWindow):
                    methods[m] = mkfunc(c._run, m)
                    
                console.updateNamespace(methods)
       -        return console
       +
        
            def change_account(self,s):
                if s == _("All accounts"):
       t@@ -1389,13 +1394,14 @@ class ElectrumWindow(QMainWindow):
        
                if (int(qtVersion[0]) >= 4 and int(qtVersion[2]) >= 7):
                    sb.addPermanentWidget( StatusBarButton( QIcon(":icons/switchgui.png"), _("Switch to Lite Mode"), self.go_lite ) )
       -        if 1:#self.wallet.seed:
       -            self.lock_icon = QIcon(":icons/lock.png") #if self.wallet.use_encryption else QIcon(":icons/unlock.png")
       -            self.password_button = StatusBarButton( self.lock_icon, _("Password"), self.change_password_dialog )
       -            sb.addPermanentWidget( self.password_button )
       +
       +        self.lock_icon = QIcon()
       +        self.password_button = StatusBarButton( self.lock_icon, _("Password"), self.change_password_dialog )
       +        sb.addPermanentWidget( self.password_button )
       +            
                sb.addPermanentWidget( StatusBarButton( QIcon(":icons/preferences.png"), _("Preferences"), self.settings_dialog ) )
       -        if 1:#self.wallet.seed:
       -            sb.addPermanentWidget( StatusBarButton( QIcon(":icons/seed.png"), _("Seed"), self.show_seed_dialog ) )
       +        self.seed_button = StatusBarButton( QIcon(":icons/seed.png"), _("Seed"), self.show_seed_dialog ) 
       +        sb.addPermanentWidget( self.seed_button )
                self.status_button = StatusBarButton( QIcon(":icons/status_disconnected.png"), _("Network"), self.run_network_dialog ) 
                sb.addPermanentWidget( self.status_button )
        
       t@@ -1404,10 +1410,27 @@ class ElectrumWindow(QMainWindow):
                self.setStatusBar(sb)
        
        
       +    def update_lock_icon(self):
       +        icon = QIcon(":icons/lock.png") if self.wallet.use_encryption else QIcon(":icons/unlock.png")
       +        self.password_button.setIcon( icon )
       +
       +
       +    def update_buttons_on_seed(self):
       +        if self.wallet.seed:
       +           self.seed_button.show()
       +           self.password_button.show()
       +           self.send_button.setText(_("Send"))
       +        else:
       +           self.password_button.hide()
       +           self.seed_button.hide()
       +           self.send_button.setText(_("Create unsigned transaction"))
       +
       +
            def change_password_dialog(self):
                from password_dialog import PasswordDialog
                d = PasswordDialog(self.wallet, self)
                d.run()
       +        self.update_lock_icon()
        
                
            def go_lite(self):
       t@@ -1420,6 +1443,7 @@ class ElectrumWindow(QMainWindow):
                    self.lite = gui_lite.ElectrumGui(self.wallet, self.config, self)
                    self.lite.main(None)
        
       +
            def new_contact_dialog(self):
                text, ok = QInputDialog.getText(self, _('New Contact'), _('Address') + ':')
                address = unicode(text)
       t@@ -1441,7 +1465,7 @@ class ElectrumWindow(QMainWindow):
        
                addr = self.wallet.new_account_address()
                vbox = QVBoxLayout()
       -        vbox.addWidget(QLabel("To add another account, please send bitcoins to the following address:"))
       +        vbox.addWidget(QLabel(_("To create a new account, please send coins to the first address of that account:")))
                e = QLineEdit(addr)
                e.setReadOnly(True)
                vbox.addWidget(e)
       t@@ -1941,7 +1965,7 @@ class ElectrumWindow(QMainWindow):
                nz_label = QLabel(_('Display zeros'))
                grid_ui.addWidget(nz_label, 0, 0)
                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)
                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)
       t@@ -2097,8 +2121,8 @@ class ElectrumWindow(QMainWindow):
                    QMessageBox.warning(self, _('Error'), _('Invalid value')+':%s'%nz, _('OK'))
                    return
        
       -        if self.wallet.num_zeros != nz:
       -            self.wallet.num_zeros = nz
       +        if self.num_zeros != nz:
       +            self.num_zeros = nz
                    self.config.set_key('num_zeros', nz, True)
                    self.update_history_tab()
                    self.update_receive_tab()
       t@@ -2155,7 +2179,7 @@ class ElectrumWindow(QMainWindow):
                g = self.geometry()
                self.config.set_key("winpos-qt", [g.left(),g.top(),g.width(),g.height()], True)
                self.save_column_widths()
       -        self.config.set_key("console-history",self.console.history[-50:])
       +        self.config.set_key("console-history", self.console.history[-50:], True)
                event.accept()
        
        class OpenFileEventFilter(QObject):
       t@@ -2175,9 +2199,10 @@ class OpenFileEventFilter(QObject):
        
        class ElectrumGui:
        
       -    def __init__(self, config, interface, app=None):
       +    def __init__(self, config, interface, blockchain, app=None):
                self.interface = interface
                self.config = config
       +        self.blockchain = blockchain
                self.windows = []
                self.efilter = OpenFileEventFilter(self.windows)
                if app is None:
       t@@ -2186,24 +2211,18 @@ class ElectrumGui:
        
        
            def main(self, url):
       -            
       -        found = self.config.wallet_file_exists
       -        if not found:
       +
       +        storage = WalletStorage(self.config)
       +        if not storage.file_exists:
                    import installwizard
       -            wizard = installwizard.InstallWizard(self.config, self.interface)
       +            wizard = installwizard.InstallWizard(self.config, self.interface, self.blockchain, storage)
                    wallet = wizard.run()
                    if not wallet: 
                        exit()
                else:
       -            wallet = Wallet(self.config)
       -
       -        wallet.interface = self.interface
       +            wallet = Wallet(storage)
        
       -        verifier = WalletVerifier(self.interface, self.config)
       -        verifier.start()
       -        wallet.set_verifier(verifier)
       -        synchronizer = WalletSynchronizer(wallet, self.config)
       -        synchronizer.start()
       +        wallet.start_threads(self.interface, self.blockchain)
        
                s = Timer()
                s.start()
       t@@ -2219,7 +2238,6 @@ class ElectrumGui:
        
                self.app.exec_()
        
       -        verifier.stop()
       -        synchronizer.stop()
       +        wallet.stop_threads()
        
        
   DIR diff --git a/gui/gui_text.py b/gui/gui_text.py
       t@@ -5,12 +5,24 @@ _ = lambda x:x
        from electrum.util import format_satoshis, set_verbosity
        from electrum.bitcoin import is_valid
        
       +from electrum import Wallet, WalletStorage
       +
        import tty, sys
        
        
        class ElectrumGui:
        
       -    def __init__(self, wallet, config, app=None):
       +    def __init__(self, config, interface, blockchain):
       +
       +        self.config = config
       +        storage = WalletStorage(config)
       +        if not storage.file_exists:
       +            print "Wallet not found. try 'electrum create'"
       +            exit()
       +
       +        self.wallet = Wallet(storage)
       +        self.wallet.start_threads(interface, blockchain)
       +
                self.stdscr = curses.initscr()
                curses.noecho()
                curses.cbreak()
       t@@ -24,8 +36,6 @@ class ElectrumGui:
                self.set_cursor(0)
                self.w = curses.newwin(10, 50, 5, 5)
        
       -        self.wallet = wallet
       -        self.config = config
                set_verbosity(False)
                self.tab = 0
                self.pos = 0
   DIR diff --git a/gui/installwizard.py b/gui/installwizard.py
       t@@ -3,7 +3,7 @@ from PyQt4.QtCore import *
        import PyQt4.QtCore as QtCore
        from i18n import _
        
       -from electrum import Wallet, mnemonic, WalletVerifier, WalletSynchronizer
       +from electrum import Wallet, mnemonic
        
        from seed_dialog import SeedDialog
        from network_dialog import NetworkDialog
       t@@ -14,10 +14,12 @@ import sys
        
        class InstallWizard(QDialog):
        
       -    def __init__(self, config, interface):
       +    def __init__(self, config, interface, blockchain, storage):
                QDialog.__init__(self)
                self.config = config
                self.interface = interface
       +        self.blockchain = blockchain
       +        self.storage = storage
        
        
            def restore_or_create(self):
       t@@ -124,6 +126,15 @@ class InstallWizard(QDialog):
                wallet.set_up_to_date(False)
                wallet.interface.poke('synchronizer')
                waiting_dialog(waiting)
       +
       +        # try to restore old account
       +        if not wallet.is_found():
       +            print "trying old method"
       +            wallet.create_old_account()
       +            wallet.set_up_to_date(False)
       +            wallet.interface.poke('synchronizer')
       +            waiting_dialog(waiting)
       +
                if wallet.is_found():
                    QMessageBox.information(None, _('Information'), _("Recovery successful"), _('OK'))
                else:
       t@@ -137,8 +148,7 @@ class InstallWizard(QDialog):
                a = self.restore_or_create()
                if not a: exit()
        
       -        wallet = Wallet(self.config)
       -        wallet.interface = self.interface
       +        wallet = Wallet(self.storage)
        
                if a =='create':
                    wallet.init_seed(None)
       t@@ -170,11 +180,7 @@ class InstallWizard(QDialog):
                #self.interface.start(wait = False)
        
                # start wallet threads
       -        verifier = WalletVerifier(self.interface, self.config)
       -        verifier.start()
       -        wallet.set_verifier(verifier)
       -        synchronizer = WalletSynchronizer(wallet, self.config)
       -        synchronizer.start()
       +        wallet.start_threads(self.interface, self.blockchain)
        
        
                # generate the first addresses, in case we are offline
   DIR diff --git a/gui/network_dialog.py b/gui/network_dialog.py
       t@@ -44,7 +44,7 @@ class NetworkDialog(QDialog):
        
                if parent:
                    if interface.is_connected:
       -                status = _("Connected to")+" %s"%(interface.host) + "\n%d "%(parent.wallet.verifier.height)+_("blocks")
       +                status = _("Connected to")+" %s"%(interface.host) + "\n%d "%(parent.wallet.verifier.blockchain.height)+_("blocks")
                    else:
                        status = _("Not connected")
                    server = interface.server
   DIR diff --git a/gui/password_dialog.py b/gui/password_dialog.py
       t@@ -96,9 +96,5 @@ class PasswordDialog(QDialog):
        
                QMessageBox.information(self.parent, _('Success'), _('Password was updated successfully'), _('OK'))
        
       -        if self.parent: 
       -            icon = QIcon(":icons/lock.png") if wallet.use_encryption else QIcon(":icons/unlock.png")
       -            self.parent.password_button.setIcon( icon )
       -
        
        
   DIR diff --git a/lib/__init__.py b/lib/__init__.py
       t@@ -1,8 +1,9 @@
        from version import ELECTRUM_VERSION
        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 verifier import WalletVerifier
       +from verifier import TxVerifier
       +from blockchain import BlockchainVerifier
        from interface import Interface, pick_random_server, DEFAULT_SERVERS
        from simple_config import SimpleConfig
        import bitcoin
   DIR diff --git a/lib/account.py b/lib/account.py
       t@@ -48,10 +48,13 @@ class Account(object):
        class OldAccount(Account):
            """  Privatekey(type,n) = Master_private_key + H(n|S|type)  """
        
       -    def __init__(self, mpk, mpk2 = None, mpk3 = None):
       -        self.mpk = mpk
       -        self.mpk2 = mpk2
       -        self.mpk3 = mpk3
       +    def __init__(self, v):
       +        self.addresses = v.get(0, [])
       +        self.change = v.get(1, [])
       +        self.mpk = v['mpk'].decode('hex')
       +
       +    def dump(self):
       +        return {0:self.addresses, 1:self.change}
        
            @classmethod
            def mpk_from_seed(klass, seed):
       t@@ -68,48 +71,34 @@ class OldAccount(Account):
                    seed = hashlib.sha256(seed + oldseed).digest()
                return string_to_number( seed )
        
       -    def get_sequence(self, sequence, mpk):
       -        for_change, n = sequence
       -        return string_to_number( Hash( "%d:%d:"%(n,for_change) + mpk.decode('hex') ) )
       -
       -    def get_address(self, sequence):
       -        if not self.mpk2:
       -            pubkey = self.get_pubkey(sequence)
       -            address = public_key_to_bc_address( pubkey.decode('hex') )
       -        elif not self.mpk3:
       -            pubkey1 = self.get_pubkey(sequence)
       -            pubkey2 = self.get_pubkey(sequence, mpk = self.mpk2)
       -            address = Transaction.multisig_script([pubkey1, pubkey2], 2)["address"]
       -        else:
       -            pubkey1 = self.get_pubkey(sequence)
       -            pubkey2 = self.get_pubkey(sequence, mpk = self.mpk2)
       -            pubkey3 = self.get_pubkey(sequence, mpk = self.mpk3)
       -            address = Transaction.multisig_script([pubkey1, pubkey2, pubkey3], 2)["address"]
       +    def get_sequence(self, for_change, n):
       +        return string_to_number( Hash( "%d:%d:"%(n,for_change) + self.mpk ) )
       +
       +    def get_address(self, for_change, n):
       +        pubkey = self.get_pubkey(for_change, n)
       +        address = public_key_to_bc_address( pubkey.decode('hex') )
                return address
        
       -    def get_pubkey(self, sequence, mpk=None):
       +    def get_pubkey(self, for_change, n):
                curve = SECP256k1
       -        if mpk is None: mpk = self.mpk
       -        z = self.get_sequence(sequence, mpk)
       -        master_public_key = ecdsa.VerifyingKey.from_string( mpk.decode('hex'), curve = SECP256k1 )
       +        mpk = self.mpk
       +        z = self.get_sequence(for_change, n)
       +        master_public_key = ecdsa.VerifyingKey.from_string( mpk, curve = SECP256k1 )
                pubkey_point = master_public_key.pubkey.point + z*curve.generator
                public_key2 = ecdsa.VerifyingKey.from_public_point( pubkey_point, curve = SECP256k1 )
                return '04' + public_key2.to_string().encode('hex')
        
       -    def get_private_key_from_stretched_exponent(self, sequence, secexp):
       +    def get_private_key_from_stretched_exponent(self, for_change, n, secexp):
                order = generator_secp256k1.order()
       -        secexp = ( secexp + self.get_sequence(sequence, self.mpk) ) % order
       +        secexp = ( secexp + self.get_sequence(for_change, n) ) % order
                pk = number_to_string( secexp, generator_secp256k1.order() )
                compressed = False
                return SecretToASecret( pk, compressed )
                
       -    def get_private_key(self, sequence, seed):
       -        secexp = self.stretch_key(seed)
       -        return self.get_private_key_from_stretched_exponent(sequence, secexp)
       -
       -    def get_private_keys(self, sequence_list, seed):
       +    def get_private_key(self, seed, sequence):
       +        for_change, n = sequence
                secexp = self.stretch_key(seed)
       -        return [ self.get_private_key_from_stretched_exponent( sequence, secexp) for sequence in sequence_list]
       +        return self.get_private_key_from_stretched_exponent(for_change, n, secexp)
        
            def check_seed(self, seed):
                curve = SECP256k1
       t@@ -121,23 +110,8 @@ class OldAccount(Account):
                    raise BaseException('Invalid password')
                return True
        
       -    def get_input_info(self, sequence):
       -        if not self.mpk2:
       -            pk_addr = self.get_address(sequence)
       -            redeemScript = None
       -        elif not self.mpk3:
       -            pubkey1 = self.get_pubkey(sequence)
       -            pubkey2 = self.get_pubkey(sequence,mpk=self.mpk2)
       -            pk_addr = public_key_to_bc_address( pubkey1.decode('hex') ) # we need to return that address to get the right private key
       -            redeemScript = Transaction.multisig_script([pubkey1, pubkey2], 2)['redeemScript']
       -        else:
       -            pubkey1 = self.get_pubkey(sequence)
       -            pubkey2 = self.get_pubkey(sequence, mpk=self.mpk2)
       -            pubkey3 = self.get_pubkey(sequence, mpk=self.mpk3)
       -            pk_addr = public_key_to_bc_address( pubkey1.decode('hex') ) # we need to return that address to get the right private key
       -            redeemScript = Transaction.multisig_script([pubkey1, pubkey2, pubkey3], 2)['redeemScript']
       -        return pk_addr, redeemScript
       -
       +    def redeem_script(self, sequence):
       +        return None
        
        
        class BIP32_Account(Account):
   DIR diff --git a/lib/blockchain.py b/lib/blockchain.py
       t@@ -0,0 +1,329 @@
       +#!/usr/bin/env python
       +#
       +# Electrum - lightweight Bitcoin client
       +# Copyright (C) 2012 thomasv@ecdsa.org
       +#
       +# This program is free software: you can redistribute it and/or modify
       +# it under the terms of the GNU General Public License as published by
       +# the Free Software Foundation, either version 3 of the License, or
       +# (at your option) any later version.
       +#
       +# This program is distributed in the hope that it will be useful,
       +# but WITHOUT ANY WARRANTY; without even the implied warranty of
       +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
       +# GNU General Public License for more details.
       +#
       +# You should have received a copy of the GNU General Public License
       +# along with this program. If not, see <http://www.gnu.org/licenses/>.
       +
       +
       +import threading, time, Queue, os, sys, shutil
       +from util import user_dir, appdata_dir, print_error
       +from bitcoin import *
       +
       +
       +class BlockchainVerifier(threading.Thread):
       +    """ Simple Payment Verification """
       +
       +    def __init__(self, interface, config):
       +        threading.Thread.__init__(self)
       +        self.daemon = True
       +        self.config = config
       +        self.interface = interface
       +        self.interface.register_channel('verifier')
       +        self.lock = threading.Lock()
       +        self.pending_headers = [] # headers that have not been verified
       +        self.height = 0
       +        self.local_height = 0
       +        self.running = False
       +        self.headers_url = 'http://headers.electrum.org/blockchain_headers'
       +
       +
       +    def stop(self):
       +        with self.lock: self.running = False
       +        self.interface.poke('verifier')
       +
       +    def is_running(self):
       +        with self.lock: return self.running
       +
       +    def run(self):
       +
       +        self.init_headers_file()
       +        self.set_local_height()
       +
       +        with self.lock:
       +            self.running = True
       +        requested_chunks = []
       +        requested_headers = []
       +        all_chunks = False
       +        
       +        # subscribe to block headers
       +        self.interface.send([ ('blockchain.headers.subscribe',[])], 'verifier')
       +
       +        while self.is_running():
       +            # request missing chunks
       +            if not all_chunks and self.height and not requested_chunks:
       +
       +                if self.local_height + 50 < self.height:
       +                    min_index = (self.local_height + 1)/2016
       +                    max_index = (self.height + 1)/2016
       +                    for i in range(min_index, max_index + 1):
       +                        print_error( "requesting chunk", i )
       +                        self.interface.send([ ('blockchain.block.get_chunk',[i])], 'verifier')
       +                        requested_chunks.append(i)
       +                        break
       +                else:
       +                    all_chunks = True
       +                    print_error("downloaded all chunks")
       +
       +
       +            # process pending headers
       +            if self.pending_headers and all_chunks:
       +                done = []
       +                for header in self.pending_headers:
       +                    if self.verify_header(header):
       +                        done.append(header)
       +                    else:
       +                        # request previous header
       +                        i = header.get('block_height') - 1
       +                        if i not in requested_headers:
       +                            print_error("requesting header %d"%i)
       +                            self.interface.send([ ('blockchain.block.get_header',[i])], 'verifier')
       +                            requested_headers.append(i)
       +                        # no point continuing
       +                        break
       +                if done:
       +                    self.interface.trigger_callback('updated')
       +                    for header in done: 
       +                        self.pending_headers.remove(header)
       +
       +            try:
       +                r = self.interface.get_response('verifier',timeout=1)
       +            except Queue.Empty:
       +                continue
       +            if not r: continue
       +
       +            if r.get('error'):
       +                print_error('Verifier received an error:', r)
       +                continue
       +
       +            # 3. handle response
       +            method = r['method']
       +            params = r['params']
       +            result = r['result']
       +
       +            if method == 'blockchain.block.get_chunk':
       +                index = params[0]
       +                self.verify_chunk(index, result)
       +                requested_chunks.remove(index)
       +
       +            elif method in ['blockchain.headers.subscribe', 'blockchain.block.get_header']:
       +
       +                self.pending_headers.append(result)
       +                if method == 'blockchain.block.get_header':
       +                    requested_headers.remove(result.get('block_height'))
       +                else:
       +                    self.height = result.get('block_height')
       +                    ## fixme # self.interface.poke('synchronizer')
       +                
       +                self.pending_headers.sort(key=lambda x: x.get('block_height'))
       +                # print "pending headers", map(lambda x: x.get('block_height'), self.pending_headers)
       +
       +
       +
       +
       +
       +    def verify_chunk(self, index, hexdata):
       +        data = hexdata.decode('hex')
       +        height = index*2016
       +        num = len(data)/80
       +        print_error("validating headers %d"%height)
       +
       +        if index == 0:  
       +            previous_hash = ("0"*64)
       +        else:
       +            prev_header = self.read_header(index*2016-1)
       +            if prev_header is None: raise
       +            previous_hash = self.hash_header(prev_header)
       +
       +        bits, target = self.get_target(index)
       +
       +        for i in range(num):
       +            height = index*2016 + i
       +            raw_header = data[i*80:(i+1)*80]
       +            header = self.header_from_string(raw_header)
       +            _hash = self.hash_header(header)
       +            assert previous_hash == header.get('prev_block_hash')
       +            assert bits == header.get('bits')
       +            assert eval('0x'+_hash) < target
       +
       +            previous_header = header
       +            previous_hash = _hash 
       +
       +        self.save_chunk(index, data)
       +
       +
       +    def verify_header(self, header):
       +        # add header to the blockchain file
       +        # if there is a reorg, push it in a stack
       +
       +        height = header.get('block_height')
       +
       +        prev_header = self.read_header(height -1)
       +        if not prev_header:
       +            # return False to request previous header
       +            return False
       +
       +        prev_hash = self.hash_header(prev_header)
       +        bits, target = self.get_target(height/2016)
       +        _hash = self.hash_header(header)
       +        try:
       +            assert prev_hash == header.get('prev_block_hash')
       +            assert bits == header.get('bits')
       +            assert eval('0x'+_hash) < target
       +        except:
       +            # this can be caused by a reorg.
       +            print_error("verify header failed"+ repr(header))
       +            # undo verifications
       +            with self.lock:
       +                items = self.verified_tx.items()[:]
       +            for tx_hash, item in items:
       +                tx_height, timestamp, pos = item
       +                if tx_height >= height:
       +                    print_error("redoing", tx_hash)
       +                    with self.lock:
       +                        self.verified_tx.pop(tx_hash)
       +                        if tx_hash in self.merkle_roots:
       +                            self.merkle_roots.pop(tx_hash)
       +            # return False to request previous header.
       +            return False
       +
       +        self.save_header(header)
       +        print_error("verify header:", _hash, height)
       +        return True
       +        
       +
       +            
       +
       +    def header_to_string(self, res):
       +        s = int_to_hex(res.get('version'),4) \
       +            + rev_hex(res.get('prev_block_hash')) \
       +            + rev_hex(res.get('merkle_root')) \
       +            + int_to_hex(int(res.get('timestamp')),4) \
       +            + int_to_hex(int(res.get('bits')),4) \
       +            + int_to_hex(int(res.get('nonce')),4)
       +        return s
       +
       +
       +    def header_from_string(self, s):
       +        hex_to_int = lambda s: eval('0x' + s[::-1].encode('hex'))
       +        h = {}
       +        h['version'] = hex_to_int(s[0:4])
       +        h['prev_block_hash'] = hash_encode(s[4:36])
       +        h['merkle_root'] = hash_encode(s[36:68])
       +        h['timestamp'] = hex_to_int(s[68:72])
       +        h['bits'] = hex_to_int(s[72:76])
       +        h['nonce'] = hex_to_int(s[76:80])
       +        return h
       +
       +    def hash_header(self, header):
       +        return rev_hex(Hash(self.header_to_string(header).decode('hex')).encode('hex'))
       +
       +    def path(self):
       +        wdir = self.config.get('blockchain_headers_path', user_dir())
       +        if wdir and not os.path.exists( wdir ): os.mkdir(wdir)
       +        return os.path.join( wdir, 'blockchain_headers')
       +
       +    def init_headers_file(self):
       +        filename = self.path()
       +        if os.path.exists(filename):
       +            return
       +        
       +        try:
       +            import urllib, socket
       +            socket.setdefaulttimeout(30)
       +            print_error("downloading ", self.headers_url )
       +            urllib.urlretrieve(self.headers_url, filename)
       +        except:
       +            print_error( "download failed. creating file", filename )
       +            open(filename,'wb+').close()
       +
       +    def save_chunk(self, index, chunk):
       +        filename = self.path()
       +        f = open(filename,'rb+')
       +        f.seek(index*2016*80)
       +        h = f.write(chunk)
       +        f.close()
       +        self.set_local_height()
       +
       +    def save_header(self, header):
       +        data = self.header_to_string(header).decode('hex')
       +        assert len(data) == 80
       +        height = header.get('block_height')
       +        filename = self.path()
       +        f = open(filename,'rb+')
       +        f.seek(height*80)
       +        h = f.write(data)
       +        f.close()
       +        self.set_local_height()
       +
       +
       +    def set_local_height(self):
       +        name = self.path()
       +        if os.path.exists(name):
       +            h = os.path.getsize(name)/80 - 1
       +            if self.local_height != h:
       +                self.local_height = h
       +
       +
       +    def read_header(self, block_height):
       +        name = self.path()
       +        if os.path.exists(name):
       +            f = open(name,'rb')
       +            f.seek(block_height*80)
       +            h = f.read(80)
       +            f.close()
       +            if len(h) == 80:
       +                h = self.header_from_string(h)
       +                return h 
       +
       +
       +    def get_target(self, index):
       +
       +        max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
       +        if index == 0: return 0x1d00ffff, max_target
       +
       +        first = self.read_header((index-1)*2016)
       +        last = self.read_header(index*2016-1)
       +        
       +        nActualTimespan = last.get('timestamp') - first.get('timestamp')
       +        nTargetTimespan = 14*24*60*60
       +        nActualTimespan = max(nActualTimespan, nTargetTimespan/4)
       +        nActualTimespan = min(nActualTimespan, nTargetTimespan*4)
       +
       +        bits = last.get('bits') 
       +        # convert to bignum
       +        MM = 256*256*256
       +        a = bits%MM
       +        if a < 0x8000:
       +            a *= 256
       +        target = (a) * pow(2, 8 * (bits/MM - 3))
       +
       +        # new target
       +        new_target = min( max_target, (target * nActualTimespan)/nTargetTimespan )
       +        
       +        # convert it to bits
       +        c = ("%064X"%new_target)[2:]
       +        i = 31
       +        while c[0:2]=="00":
       +            c = c[2:]
       +            i -= 1
       +
       +        c = eval('0x'+c[0:6])
       +        if c > 0x800000: 
       +            c /= 256
       +            i += 1
       +
       +        new_bits = c + MM * i
       +        return new_bits, new_target
       +
   DIR diff --git a/lib/interface.py b/lib/interface.py
       t@@ -396,7 +396,7 @@ class Interface(threading.Thread):
                    self.unanswered_requests[self.message_id] = method, params, channel
                    ids.append(self.message_id)
                    # uncomment to debug
       -            # print "-->",request
       +            # print "-->", request
                    self.message_id += 1
                    out += request + '\n'
                while out:
   DIR diff --git a/lib/simple_config.py b/lib/simple_config.py
       t@@ -6,6 +6,9 @@ from version import ELECTRUM_VERSION, SEED_VERSION
        
        
        
       +
       +
       +
        class SimpleConfig:
            """
        The SimpleConfig class is responsible for handling operations involving
       t@@ -29,46 +32,44 @@ a SimpleConfig instance then reads the wallet file.
                # command-line options
                self.options_config = options
        
       -        self.wallet_config = {}
       -        self.wallet_file_exists = False
       -        self.init_path(self.options_config.get('wallet_path'))
       -        print_error( "path", self.path )
       -        if self.path:
       -            self.read_wallet_config(self.path)
       +        # init path
       +        self.init_path(options)
       +
       +        print_error( "user dir", self.user_dir)
       +
       +
       +    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
       -        if options.get('portable'):
       -            self.wallet_config['blockchain_headers_path'] = os.path.dirname(self.path)
       +        #if options.get('portable'):
       +        #    self.wallet_config['blockchain_headers_path'] = os.path.dirname(self.path)
                    
       -            
       -        
       -
       -    def set_key(self, key, value, save = False):
       +    def set_key(self, key, value, save = True):
                # find where a setting comes from and save it there
                if self.options_config.get(key) is not None:
                    print "Warning: not changing '%s' because it was passed as a command-line option"%key
                    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:
                    if str(self.system_config[key]) != str(value):
                        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:
       -            # add key to wallet config
       -            self.wallet_config[key] = value
       -            if save: self.save_wallet_config()
       +            self.user_config[key] = value
       +            if save: self.save_user_config()
       +
        
        
            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
                if self.options_config.has_key(key) and self.options_config.get(key) is not None:
                    out = self.options_config.get(key)
       t@@ -81,10 +82,6 @@ a SimpleConfig instance then reads the wallet file.
                elif self.system_config.has_key(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:
                    out = default
        
       t@@ -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[]."""
                if not self.user_dir: return
        
       -        name = os.path.join( self.user_dir, 'electrum.conf')
       -        if os.path.exists(name):
       +        path = os.path.join(self.user_dir, "config")
       +        if os.path.exists(path):
                    try:
       -                import ConfigParser
       -            except ImportError:
       -                print "cannot parse electrum.conf. please install ConfigParser"
       +                with open(path, "r") as f:
       +                    data = f.read()
       +            except IOError:
                        return
       -                
       -            p = ConfigParser.ConfigParser()
       -            p.read(name)
                    try:
       -                for k, v in p.items('client'):
       -                    self.user_config[k] = v
       -            except ConfigParser.NoSectionError:
       -                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
       +                d = ast.literal_eval( data )  #parse raw data from reading wallet file
       +            except:
       +                raise IOError("Cannot read config file.")
        
       -        # 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")
       +            self.user_config = d
        
        
            def save_user_config(self):
                if not self.user_dir: return
        
       -        import ConfigParser
       -        config = ConfigParser.RawConfigParser()
       -        config.add_section('client')
       -        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")
       +        path = os.path.join(self.user_dir, "config")
       +        s = repr(self.user_config)
       +        f = open(path,"w")
                f.write( s )
                f.close()
                if self.get('gui') != 'android':
                    import stat
       -            os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE)
       -
       +            os.chmod(path, stat.S_IREAD | stat.S_IWRITE)
   DIR diff --git a/lib/verifier.py b/lib/verifier.py
       t@@ -24,34 +24,29 @@ from bitcoin import *
        
        
        
       -class WalletVerifier(threading.Thread):
       +class TxVerifier(threading.Thread):
            """ Simple Payment Verification """
        
       -    def __init__(self, interface, config):
       +    def __init__(self, interface, blockchain, storage):
                threading.Thread.__init__(self)
                self.daemon = True
       -        self.config = config
       +        self.storage = storage
       +        self.blockchain = blockchain
                self.interface = interface
                self.transactions    = {}                                 # requested verifications (with height sent by the requestor)
       -        self.interface.register_channel('verifier')
       -
       -        self.verified_tx     = config.get('verified_tx3',{})      # height, timestamp of verified transactions
       -        self.merkle_roots    = config.get('merkle_roots',{})      # hashed by me
       -        
       -        self.targets         = config.get('targets',{})           # compute targets
       +        self.interface.register_channel('txverifier')
       +        self.verified_tx     = storage.get('verified_tx3',{})      # height, timestamp of verified transactions
       +        self.merkle_roots    = storage.get('merkle_roots',{})      # hashed by me
                self.lock = threading.Lock()
       -        self.pending_headers = [] # headers that have not been verified
       -        self.height = 0
       -        self.local_height = 0
                self.running = False
       -        self.headers_url = 'http://headers.electrum.org/blockchain_headers'
       +
        
            def get_confirmations(self, tx):
                """ return the number of confirmations of a monitored transaction. """
                with self.lock:
                    if tx in self.verified_tx:
                        height, timestamp, pos = self.verified_tx[tx]
       -                conf = (self.local_height - height + 1)
       +                conf = (self.blockchain.local_height - height + 1)
                        if conf <= 0: timestamp = None
        
                    elif tx in self.transactions:
       t@@ -101,67 +96,21 @@ class WalletVerifier(threading.Thread):
                with self.lock: return self.running
        
            def run(self):
       -
       -        self.init_headers_file()
       -        self.set_local_height()
       -
                with self.lock:
                    self.running = True
                requested_merkle = []
       -        requested_chunks = []
       -        requested_headers = []
       -        all_chunks = False
       -        
       -        # subscribe to block headers
       -        self.interface.send([ ('blockchain.headers.subscribe',[])], 'verifier')
        
                while self.is_running():
       -            # request missing chunks
       -            if not all_chunks and self.height and not requested_chunks:
       -
       -                if self.local_height + 50 < self.height:
       -                    min_index = (self.local_height + 1)/2016
       -                    max_index = (self.height + 1)/2016
       -                    for i in range(min_index, max_index + 1):
       -                        print_error( "requesting chunk", i )
       -                        self.interface.send([ ('blockchain.block.get_chunk',[i])], 'verifier')
       -                        requested_chunks.append(i)
       -                        break
       -                else:
       -                    all_chunks = True
       -                    print_error("downloaded all chunks")
       -
                    # request missing tx
       -            if all_chunks:
       -                for tx_hash, tx_height in self.transactions.items():
       -                    if tx_hash not in self.verified_tx:
       -                        if self.merkle_roots.get(tx_hash) is None and tx_hash not in requested_merkle:
       -                            print_error('requesting merkle', tx_hash)
       -                            self.interface.send([ ('blockchain.transaction.get_merkle',[tx_hash, tx_height]) ], 'verifier')
       -                            requested_merkle.append(tx_hash)
       -
       -            # process pending headers
       -            if self.pending_headers and all_chunks:
       -                done = []
       -                for header in self.pending_headers:
       -                    if self.verify_header(header):
       -                        done.append(header)
       -                    else:
       -                        # request previous header
       -                        i = header.get('block_height') - 1
       -                        if i not in requested_headers:
       -                            print_error("requesting header %d"%i)
       -                            self.interface.send([ ('blockchain.block.get_header',[i])], 'verifier')
       -                            requested_headers.append(i)
       -                        # no point continuing
       -                        break
       -                if done:
       -                    self.interface.trigger_callback('updated')
       -                    for header in done: 
       -                        self.pending_headers.remove(header)
       +            for tx_hash, tx_height in self.transactions.items():
       +                if tx_hash not in self.verified_tx:
       +                    if self.merkle_roots.get(tx_hash) is None and tx_hash not in requested_merkle:
       +                        print_error('requesting merkle', tx_hash)
       +                        self.interface.send([ ('blockchain.transaction.get_merkle',[tx_hash, tx_height]) ], 'txverifier')
       +                        requested_merkle.append(tx_hash)
        
                    try:
       -                r = self.interface.get_response('verifier',timeout=1)
       +                r = self.interface.get_response('txverifier',timeout=1)
                    except Queue.Empty:
                        continue
                    if not r: continue
       t@@ -180,138 +129,23 @@ class WalletVerifier(threading.Thread):
                        self.verify_merkle(tx_hash, result)
                        requested_merkle.remove(tx_hash)
        
       -            elif method == 'blockchain.block.get_chunk':
       -                index = params[0]
       -                self.verify_chunk(index, result)
       -                requested_chunks.remove(index)
       -
       -            elif method in ['blockchain.headers.subscribe', 'blockchain.block.get_header']:
       -
       -                self.pending_headers.append(result)
       -                if method == 'blockchain.block.get_header':
       -                    requested_headers.remove(result.get('block_height'))
       -                else:
       -                    self.height = result.get('block_height')
       -                    self.interface.poke('synchronizer')
       -                
       -                self.pending_headers.sort(key=lambda x: x.get('block_height'))
       -                # print "pending headers", map(lambda x: x.get('block_height'), self.pending_headers)
       -
       -
        
            def verify_merkle(self, tx_hash, result):
                tx_height = result.get('block_height')
                pos = result.get('pos')
                self.merkle_roots[tx_hash] = self.hash_merkle_root(result['merkle'], tx_hash, pos)
       -        header = self.read_header(tx_height)
       +        header = self.blockchain.read_header(tx_height)
                if not header: return
                assert header.get('merkle_root') == self.merkle_roots[tx_hash]
                # we passed all the tests
       -        header = self.read_header(tx_height)
                timestamp = header.get('timestamp')
                with self.lock:
                    self.verified_tx[tx_hash] = (tx_height, timestamp, pos)
                print_error("verified %s"%tx_hash)
       -        self.config.set_key('verified_tx3', self.verified_tx, True)
       +        self.storage.put('verified_tx3', self.verified_tx, True)
                self.interface.trigger_callback('updated')
        
        
       -    def verify_chunk(self, index, hexdata):
       -        data = hexdata.decode('hex')
       -        height = index*2016
       -        num = len(data)/80
       -        print_error("validating headers %d"%height)
       -
       -        if index == 0:  
       -            previous_hash = ("0"*64)
       -        else:
       -            prev_header = self.read_header(index*2016-1)
       -            if prev_header is None: raise
       -            previous_hash = self.hash_header(prev_header)
       -
       -        bits, target = self.get_target(index)
       -
       -        for i in range(num):
       -            height = index*2016 + i
       -            raw_header = data[i*80:(i+1)*80]
       -            header = self.header_from_string(raw_header)
       -            _hash = self.hash_header(header)
       -            assert previous_hash == header.get('prev_block_hash')
       -            assert bits == header.get('bits')
       -            assert eval('0x'+_hash) < target
       -
       -            previous_header = header
       -            previous_hash = _hash 
       -
       -        self.save_chunk(index, data)
       -
       -
       -    def verify_header(self, header):
       -        # add header to the blockchain file
       -        # if there is a reorg, push it in a stack
       -
       -        height = header.get('block_height')
       -
       -        prev_header = self.read_header(height -1)
       -        if not prev_header:
       -            # return False to request previous header
       -            return False
       -
       -        prev_hash = self.hash_header(prev_header)
       -        bits, target = self.get_target(height/2016)
       -        _hash = self.hash_header(header)
       -        try:
       -            assert prev_hash == header.get('prev_block_hash')
       -            assert bits == header.get('bits')
       -            assert eval('0x'+_hash) < target
       -        except:
       -            # this can be caused by a reorg.
       -            print_error("verify header failed"+ repr(header))
       -            # undo verifications
       -            with self.lock:
       -                items = self.verified_tx.items()[:]
       -            for tx_hash, item in items:
       -                tx_height, timestamp, pos = item
       -                if tx_height >= height:
       -                    print_error("redoing", tx_hash)
       -                    with self.lock:
       -                        self.verified_tx.pop(tx_hash)
       -                        if tx_hash in self.merkle_roots:
       -                            self.merkle_roots.pop(tx_hash)
       -            # return False to request previous header.
       -            return False
       -
       -        self.save_header(header)
       -        print_error("verify header:", _hash, height)
       -        return True
       -        
       -
       -            
       -
       -    def header_to_string(self, res):
       -        s = int_to_hex(res.get('version'),4) \
       -            + rev_hex(res.get('prev_block_hash')) \
       -            + rev_hex(res.get('merkle_root')) \
       -            + int_to_hex(int(res.get('timestamp')),4) \
       -            + int_to_hex(int(res.get('bits')),4) \
       -            + int_to_hex(int(res.get('nonce')),4)
       -        return s
       -
       -
       -    def header_from_string(self, s):
       -        hex_to_int = lambda s: eval('0x' + s[::-1].encode('hex'))
       -        h = {}
       -        h['version'] = hex_to_int(s[0:4])
       -        h['prev_block_hash'] = hash_encode(s[4:36])
       -        h['merkle_root'] = hash_encode(s[36:68])
       -        h['timestamp'] = hex_to_int(s[68:72])
       -        h['bits'] = hex_to_int(s[72:76])
       -        h['nonce'] = hex_to_int(s[76:80])
       -        return h
       -
       -    def hash_header(self, header):
       -        return rev_hex(Hash(self.header_to_string(header).decode('hex')).encode('hex'))
       -
            def hash_merkle_root(self, merkle_s, target_hash, pos):
                h = hash_decode(target_hash)
                for i in range(len(merkle_s)):
       t@@ -319,101 +153,6 @@ class WalletVerifier(threading.Thread):
                    h = Hash( hash_decode(item) + h ) if ((pos >> i) & 1) else Hash( h + hash_decode(item) )
                return hash_encode(h)
        
       -    def path(self):
       -        wdir = self.config.get('blockchain_headers_path', user_dir())
       -        if wdir and not os.path.exists( wdir ): os.mkdir(wdir)
       -        return os.path.join( wdir, 'blockchain_headers')
       -
       -    def init_headers_file(self):
       -        filename = self.path()
       -        if os.path.exists(filename):
       -            return
       -        
       -        try:
       -            import urllib, socket
       -            socket.setdefaulttimeout(30)
       -            print_error("downloading ", self.headers_url )
       -            urllib.urlretrieve(self.headers_url, filename)
       -        except:
       -            print_error( "download failed. creating file", filename )
       -            open(filename,'wb+').close()
       -
       -    def save_chunk(self, index, chunk):
       -        filename = self.path()
       -        f = open(filename,'rb+')
       -        f.seek(index*2016*80)
       -        h = f.write(chunk)
       -        f.close()
       -        self.set_local_height()
       -
       -    def save_header(self, header):
       -        data = self.header_to_string(header).decode('hex')
       -        assert len(data) == 80
       -        height = header.get('block_height')
       -        filename = self.path()
       -        f = open(filename,'rb+')
       -        f.seek(height*80)
       -        h = f.write(data)
       -        f.close()
       -        self.set_local_height()
       -
       -
       -    def set_local_height(self):
       -        name = self.path()
       -        if os.path.exists(name):
       -            h = os.path.getsize(name)/80 - 1
       -            if self.local_height != h:
       -                self.local_height = h
       -
       -
       -    def read_header(self, block_height):
       -        name = self.path()
       -        if os.path.exists(name):
       -            f = open(name,'rb')
       -            f.seek(block_height*80)
       -            h = f.read(80)
       -            f.close()
       -            if len(h) == 80:
       -                h = self.header_from_string(h)
       -                return h 
       -
       -
       -    def get_target(self, index):
       -
       -        max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
       -        if index == 0: return 0x1d00ffff, max_target
       -
       -        first = self.read_header((index-1)*2016)
       -        last = self.read_header(index*2016-1)
       -        
       -        nActualTimespan = last.get('timestamp') - first.get('timestamp')
       -        nTargetTimespan = 14*24*60*60
       -        nActualTimespan = max(nActualTimespan, nTargetTimespan/4)
       -        nActualTimespan = min(nActualTimespan, nTargetTimespan*4)
       -
       -        bits = last.get('bits') 
       -        # convert to bignum
       -        MM = 256*256*256
       -        a = bits%MM
       -        if a < 0x8000:
       -            a *= 256
       -        target = (a) * pow(2, 8 * (bits/MM - 3))
       -
       -        # new target
       -        new_target = min( max_target, (target * nActualTimespan)/nTargetTimespan )
       -        
       -        # convert it to bits
       -        c = ("%064X"%new_target)[2:]
       -        i = 31
       -        while c[0:2]=="00":
       -            c = c[2:]
       -            i -= 1
       -
       -        c = eval('0x'+c[0:6])
       -        if c > 0x800000: 
       -            c /= 256
       -            i += 1
       -
       -        new_bits = c + MM * i
       -        return new_bits, new_target
       +
       +
        
   DIR diff --git a/lib/version.py b/lib/version.py
       t@@ -1,4 +1,4 @@
        ELECTRUM_VERSION = "1.9"    # version of the client package
        PROTOCOL_VERSION = '0.6'    # protocol version requested
       -SEED_VERSION     = 4        # bump this every time the seed generation is modified
       +SEED_VERSION     = 5        # bump this every time the seed generation is modified
        TRANSLATION_ID   = 4101     # version of the wiki page 
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -63,39 +63,113 @@ def pw_decode(s, password):
        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:
       -    def __init__(self, config={}):
        
       -        self.config = config
       +    def __init__(self, storage):
       +
       +        self.storage = storage
                self.electrum_version = ELECTRUM_VERSION
                self.gap_limit_for_change = 3 # constant
        
                # saved fields
       -        self.seed_version          = config.get('seed_version', SEED_VERSION)
       -        self.gap_limit             = config.get('gap_limit', 5)
       -        self.use_change            = config.get('use_change',True)
       -        self.fee                   = int(config.get('fee_per_kb',20000))
       -        self.num_zeros             = int(config.get('num_zeros',0))
       -        self.use_encryption        = config.get('use_encryption', False)
       -        self.seed                  = config.get('seed', '')               # encrypted
       -        self.labels                = config.get('labels', {})
       -        self.frozen_addresses      = config.get('frozen_addresses',[])
       -        self.prioritized_addresses = config.get('prioritized_addresses',[])
       -        self.addressbook           = config.get('contacts', [])
       +        self.seed_version          = storage.get('seed_version', SEED_VERSION)
       +
       +        self.gap_limit             = storage.get('gap_limit', 5)
       +        self.use_change            = storage.get('use_change',True)
       +        self.use_encryption        = storage.get('use_encryption', False)
       +        self.seed                  = storage.get('seed', '')               # encrypted
       +        self.labels                = storage.get('labels', {})
       +        self.frozen_addresses      = storage.get('frozen_addresses',[])
       +        self.prioritized_addresses = storage.get('prioritized_addresses',[])
       +        self.addressbook           = storage.get('contacts', [])
        
       -        self.imported_keys         = config.get('imported_keys',{})
       -        self.history               = config.get('addr_history',{})        # address -> list(txid, height)
       +        self.imported_keys         = storage.get('imported_keys',{})
       +        self.history               = storage.get('addr_history',{})        # address -> list(txid, height)
        
       +        self.fee                   = int(storage.get('fee_per_kb',20000))
        
       -        self.master_public_keys = config.get('master_public_keys',{})
       -        self.master_private_keys = config.get('master_private_keys', {})
       +        self.master_public_keys = storage.get('master_public_keys',{})
       +        self.master_private_keys = storage.get('master_private_keys', {})
        
       -        self.first_addresses = config.get('first_addresses',{})
       +        self.first_addresses = storage.get('first_addresses',{})
        
       -        self.load_accounts(config)
       +        #if self.seed_version != SEED_VERSION:
       +        #    raise ValueError("This wallet seed is deprecated. Please restore from seed.")
       +
       +        self.load_accounts()
        
                self.transactions = {}
       -        tx = config.get('transactions',{})
       +        tx = storage.get('transactions',{})
                try:
                    for k,v in tx.items(): self.transactions[k] = Transaction(v)
                except:
       t@@ -117,9 +191,6 @@ class Wallet:
                self.transaction_lock = threading.Lock()
                self.tx_event = threading.Event()
        
       -        if self.seed_version != SEED_VERSION:
       -            raise ValueError("This wallet seed is deprecated. Please run upgrade.py for a diagnostic.")
       -
                for tx_hash, tx in self.transactions.items():
                    if self.check_new_tx(tx_hash, tx):
                        self.update_tx_outputs(tx_hash)
       t@@ -152,13 +223,13 @@ class Wallet:
                
                # store the originally requested keypair into the imported keys table
                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
                
            def delete_imported_key(self, addr):
                if addr in self.imported_keys:
                    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):
       t@@ -169,8 +240,8 @@ class Wallet:
        
        
            def save_seed(self):
       -        self.config.set_key('seed', self.seed, True)
       -        self.config.set_key('seed_version', self.seed_version, True)
       +        self.storage.put('seed', self.seed, True)
       +        self.storage.put('seed_version', self.seed_version, True)
        
                master_k, master_c, master_K, master_cK = bip32_init(self.seed)
                
       t@@ -202,8 +273,8 @@ class Wallet:
                    "m/5'/": k5
                    }
                
       -        self.config.set_key('master_public_keys', self.master_public_keys, True)
       -        self.config.set_key('master_private_keys', self.master_private_keys, True)
       +        self.storage.put('master_public_keys', self.master_public_keys, True)
       +        self.storage.put('master_private_keys', self.master_private_keys, True)
        
                # create default account
                self.create_account('1','Main account')
       t@@ -220,14 +291,14 @@ class Wallet:
                # for safety, we ask the user to enter their seed
                assert seed == self.decode_seed(password)
                self.seed = ''
       -        self.config.set_key('seed', '', True)
       +        self.storage.put('seed', '', True)
        
        
            def deseed_branch(self, k):
                # check that parent has no seed
                assert self.seed == ''
                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):
       t@@ -260,7 +331,7 @@ class Wallet:
                    account_id, account = self.next_account(account_type)
                    addr = account.first_address()
                    self.first_addresses[k] = addr
       -            self.config.set_key('first_addresses',self.first_addresses)
       +            self.storage.put('first_addresses',self.first_addresses)
        
                return addr
        
       t@@ -294,26 +365,39 @@ class Wallet:
                return account_id, account
        
        
       -    def create_account(self, account_type = '1', name = 'unnamed'):
       +    def create_account(self, account_type = '1', name = None):
                account_id, account = self.next_account(account_type)
                self.accounts[account_id] = account
                self.save_accounts()
       -        self.labels[account_id] = name
       -        self.config.set_key('labels', self.labels, True)
       +        if name: 
       +            self.labels[account_id] = name
       +        self.storage.put('labels', self.labels, True)
       +
       +
       +    def create_old_account(self):
       +        print self.seed
       +        mpk = OldAccount.mpk_from_seed(self.seed)
       +        self.storage.put('master_public_key', mpk, True)
       +        self.accounts[0] = OldAccount({'mpk':mpk, 0:[], 1:[]})
       +        self.save_accounts()
        
        
            def save_accounts(self):
                d = {}
                for k, v in self.accounts.items():
                    d[k] = v.dump()
       -        self.config.set_key('accounts', d, True)
       +        self.storage.put('accounts', d, True)
        
       +    
        
       -    def load_accounts(self, config):
       -        d = config.get('accounts', {})
       +    def load_accounts(self):
       +        d = self.storage.get('accounts', {})
                self.accounts = {}
                for k, v in d.items():
       -            if '&' in k:
       +            if k == 0:
       +                v['mpk'] = self.storage.get('master_public_key')
       +                self.accounts[k] = OldAccount(v)
       +            elif '&' in k:
                        self.accounts[k] = BIP32_Account_2of2(v)
                    else:
                        self.accounts[k] = BIP32_Account(v)
       t@@ -339,7 +423,7 @@ class Wallet:
        
            def get_master_public_key(self):
                raise
       -        return self.config.get("master_public_key")
       +        return self.storage.get("master_public_key")
        
            def get_master_private_key(self, account, password):
                master_k = pw_decode( self.master_private_keys[account], password)
       t@@ -379,6 +463,9 @@ class Wallet:
                
        
            def get_keyID(self, account, sequence):
       +        if account == 0:
       +            return 'old'
       +
                rs = self.rebase_sequence(account, sequence)
                dd = []
                for root, public_sequence in rs:
       t@@ -405,6 +492,12 @@ class Wallet:
                    out.append( pw_decode( self.imported_keys[address], password ) )
                else:
                    account, sequence = self.get_address_index(address)
       +            if account == 0:
       +                seed = self.decode_seed(password)
       +                pk = self.accounts[account].get_private_key(seed, sequence)
       +                out.append(pk)
       +                return out
       +
                    # assert address == self.accounts[account].get_address(*sequence)
                    rs = self.rebase_sequence( account, sequence)
                    for root, public_sequence in rs:
       t@@ -520,7 +613,7 @@ class Wallet:
            def change_gap_limit(self, value):
                if value >= self.gap_limit:
                    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')
                    return True
        
       t@@ -533,7 +626,7 @@ class Wallet:
                        self.accounts[key][0] = addresses
        
                    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()
                    return True
                else:
       t@@ -616,13 +709,14 @@ class Wallet:
        
        
            def synchronize(self):
       -        self.create_pending_accounts()
       +        if self.master_public_keys:
       +            self.create_pending_accounts()
                new = []
                for account in self.accounts.values():
                    new += self.synchronize_account(account)
                if new:
                    self.save_accounts()
       -            self.config.set_key('addr_history', self.history, True)
       +            self.storage.put('addr_history', self.history, True)
                return new
        
        
       t@@ -632,15 +726,15 @@ class Wallet:
        
            def add_contact(self, address, label=None):
                self.addressbook.append(address)
       -        self.config.set_key('contacts', self.addressbook, True)
       +        self.storage.put('contacts', self.addressbook, True)
                if 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):
                if addr in self.addressbook:
                    self.addressbook.remove(addr)
       -            self.config.set_key('addressbook', self.addressbook, True)
       +            self.storage.put('addressbook', self.addressbook, True)
        
        
            def fill_addressbook(self):
       t@@ -837,6 +931,11 @@ class Wallet:
                return inputs, total, fee
        
        
       +    def set_fee(self, fee):
       +        if self.fee != fee:
       +            self.fee = fee
       +            self.storage.put('fee_per_kb', self.fee, True)
       +        
            def estimated_fee(self, inputs):
                estimated_size =  len(inputs) * 180 + 80     # this assumes non-compressed keys
                fee = self.fee * int(round(estimated_size/1024.))
       t@@ -900,7 +999,7 @@ class Wallet:
                tx = {}
                for k,v in self.transactions.items():
                    tx[k] = str(v)
       -        self.config.set_key('transactions', tx, True)
       +        self.storage.put('transactions', tx, True)
        
            def receive_history_callback(self, addr, hist):
        
       t@@ -909,7 +1008,7 @@ class Wallet:
                    
                with self.lock:
                    self.history[addr] = hist
       -            self.config.set_key('addr_history', self.history, True)
       +            self.storage.put('addr_history', self.history, True)
        
                if hist != ['*']:
                    for tx_hash, tx_height in hist:
       t@@ -1060,28 +1159,28 @@ class Wallet:
                if new_password == '': new_password = None
                # this will throw an exception if unicode cannot be converted
                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.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():
                    a = self.imported_keys[k]
                    b = pw_decode(a, old_password)
                    c = pw_encode(b, new_password)
                    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():
                    b = pw_decode(v, old_password)
                    c = pw_encode(b, new_password)
                    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):
                if self.is_mine(addr) and addr not in self.frozen_addresses:
                    self.unprioritize(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
                else:
                    return False
       t@@ -1089,7 +1188,7 @@ class Wallet:
            def unfreeze(self,addr):
                if self.is_mine(addr) and addr in self.frozen_addresses:
                    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
                else:
                    return False
       t@@ -1098,7 +1197,7 @@ class Wallet:
                if self.is_mine(addr) and addr not in self.prioritized_addresses:
                    self.unfreeze(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
                else:
                    return False
       t@@ -1106,38 +1205,11 @@ class Wallet:
            def unprioritize(self,addr):
                if self.is_mine(addr) and addr in self.prioritized_addresses:
                    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
                else:
                    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):
                self.verifier = verifier
       t@@ -1239,12 +1311,26 @@ class Wallet:
                return True
        
        
       +    def start_threads(self, interface, blockchain):
       +        from verifier import TxVerifier
       +        self.interface = interface
       +        self.verifier = TxVerifier(interface, blockchain, self.storage)
       +        self.verifier.start()
       +        self.set_verifier(self.verifier)
       +        self.synchronizer = WalletSynchronizer(self)
       +        self.synchronizer.start()
       +
       +    def stop_threads(self):
       +        self.verifier.stop()
       +        self.synchronizer.stop()
       +
       +
        
        
        class WalletSynchronizer(threading.Thread):
        
        
       -    def __init__(self, wallet, config):
       +    def __init__(self, wallet):
                threading.Thread.__init__(self)
                self.daemon = True
                self.wallet = wallet
   DIR diff --git a/setup.py b/setup.py
       t@@ -58,6 +58,7 @@ setup(name = "Electrum",
                          'electrum.wallet_bitkey',
                          'electrum.wallet_factory',
                          'electrum.interface',
       +                  'electrum.blockchain',
                          'electrum.commands',
                          'electrum.mnemonic',
                          'electrum.simple_config',