URI: 
       taccounts - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit e84d087a640bbcc878b3c235c1a3e0186562c34d
   DIR parent c871a795825c62b57008ac8f82170f5da9650ed0
  HTML Author: thomasv <thomasv@gitorious>
       Date:   Wed, 27 Feb 2013 09:04:22 +0100
       
       accounts
       
       Diffstat:
         M electrum                            |       2 +-
         M lib/bitcoin.py                      |      63 ++++++++++++++++++++++++++++---
         M lib/gui_qt.py                       |     125 ++++++++++++++++++-------------
         M lib/wallet.py                       |     218 +++++++++++++++++--------------
       
       4 files changed, 256 insertions(+), 152 deletions(-)
       ---
   DIR diff --git a/electrum b/electrum
       t@@ -284,7 +284,7 @@ if __name__ == '__main__':
                sys.exit(0)
        
        
       -                
       +
            # important warning
            if cmd in ['dumpprivkey', 'dumpprivkeys']:
                print_msg("WARNING: ALL your private keys are secret.")
   DIR diff --git a/lib/bitcoin.py b/lib/bitcoin.py
       t@@ -415,8 +415,13 @@ def CKD_prime(K, c, n):
        class DeterministicSequence:
            """  Privatekey(type,n) = Master_private_key + H(n|S|type)  """
        
       -    def __init__(self, master_public_key):
       +    def __init__(self, master_public_key, mpk2 = None):
                self.master_public_key = master_public_key
       +        if mpk2:
       +            self.mpk2 = mpk2
       +            self.is_p2sh = True
       +        else:
       +            self.is_p2sh = False
        
            @classmethod
            def from_seed(klass, seed):
       t@@ -434,9 +439,30 @@ class DeterministicSequence:
                    seed = hashlib.sha256(seed + oldseed).digest()
                return string_to_number( seed )
        
       -    def get_sequence(self,n,for_change):
       +    def get_sequence(self, n, for_change):
                return string_to_number( Hash( "%d:%d:"%(n,for_change) + self.master_public_key.decode('hex') ) )
        
       +    def get_address(self, for_change, n):
       +        if not self.is_p2sh:
       +            pubkey = self.get_pubkey(n, for_change)
       +            address = public_key_to_bc_address( pubkey.decode('hex') )
       +        else:
       +            pubkey1 = self.get_pubkey(n, for_change)
       +            pubkey2 = self.get_pubkey2(n, for_change)
       +            address = Transaction.multisig_script([pubkey1, pubkey2], 2)["address"]
       +        return address
       +
       +    #sec = self.p2sh_sequence.get_private_key(n, for_change, seed)
       +    #addr = hash_160_to_bc_address(hash_160(txin["redeemScript"].decode('hex')), 5)
       +
       +    def get_pubkey2(self, n, for_change):
       +        curve = SECP256k1
       +        z = string_to_number( Hash( "%d:%d:"%(n, for_change) + self.mpk2.decode('hex') ) )
       +        master_public_key = ecdsa.VerifyingKey.from_string( self.mpk2.decode('hex'), 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_pubkey(self, n, for_change):
                curve = SECP256k1
                z = self.get_sequence(n, for_change)
       t@@ -467,13 +493,24 @@ class DeterministicSequence:
        
                return True
        
       -################################## transactions
        
       +    def add_input_info(self, txin, account, is_change, n):
        
       +        txin['electrumKeyID'] = (account, is_change, n) # used by the server to find the key
       +        if not self.p2sh:
       +            txin['pubkeysig'] = [(None, None)]
       +            pk_addr = txin['address']
       +        else:
       +            pubkey1 = self.get_pubkey(n, is_change)
       +            pubkey2 = self.get_pubkey2(n, is_change)
       +            pk_addr = public_key_to_bc_address( pubkey1.decode('hex') ) # we need to return that address to get the right private key
       +            txin['redeemScript'] = Transaction.multisig_script([pubkey1, pubkey2], 2)['redeemScript']
       +        return pk_addr
        
        
        
        
       +################################## transactions
        
        
        class Transaction:
       t@@ -745,8 +782,24 @@ class Transaction:
                    "hex":self.raw,
                    "complete":self.is_complete
                    }
       -        if not self.is_complete and self.input_info:
       -            out['input_info'] = json.dumps(self.input_info).replace(' ','')
       +        if not self.is_complete:
       +            extras = []
       +            for i in self.inputs:
       +                e = { 'txid':i['tx_hash'], 'vout':i['index'],
       +                      'scriptPubKey':i.get('raw_output_script'),
       +                      'electrumKeyID':i.get('electrumKeyID'),
       +                      'redeemScript':i.get('redeemScript'),
       +                      'signatures':i.get('signatures'),
       +                      'pubkeys':i.get('pubkeys'),
       +                      }
       +                extras.append(e)
       +            self.input_info = extras
       +
       +            if self.input_info:
       +                out['input_info'] = json.dumps(self.input_info).replace(' ','')
       +
       +
       +        print "out", out
                return out
        
        
   DIR diff --git a/lib/gui_qt.py b/lib/gui_qt.py
       t@@ -387,7 +387,7 @@ def ok_cancel_buttons(dialog):
        
        
        default_column_widths = { "history":[40,140,350,140], "contacts":[350,330], 
       -        "receive":[[310],[50,310,200,130,130],[50,310,200,130,130]] }
       +        "receive":[[310],[310,200,130,130],[310,200,130,130]] }
        
        class ElectrumWindow(QMainWindow):
        
       t@@ -674,7 +674,7 @@ class ElectrumWindow(QMainWindow):
                        
                    self.recv_changed(item)
        
       -        if column == 3:
       +        if column == 2:
                    address = str( item.text(column_addr) )
                    text = str( item.text(3) )
                    try:
       t@@ -945,7 +945,7 @@ class ElectrumWindow(QMainWindow):
                if label: 
                    self.wallet.labels[tx.hash()] = label
        
       -        if self.wallet.seed:
       +        if tx.is_complete:
                    h = self.wallet.send_tx(tx)
                    waiting_dialog(lambda: False if self.wallet.tx_event.isSet() else _("Please wait..."))
                    status, msg = self.wallet.receive_tx( h )
       t@@ -966,6 +966,8 @@ class ElectrumWindow(QMainWindow):
                        QMessageBox.warning(self, _('Error'), _('Could not write transaction to file'), _('OK'))
        
        
       +
       +
            def set_url(self, url):
                payto, amount, label, message, signature, identity, url = self.wallet.parse_url(url, self.show_message, self.question)
                self.tabs.setCurrentIndex(1)
       t@@ -1046,11 +1048,11 @@ class ElectrumWindow(QMainWindow):
        
        
            def create_receive_tab(self):
       -        l,w,hbox = self.create_list_tab([_('Flags'), _('Address'), _('Label'), _('Requested'), _('Balance'), _('Tx')])
       +        l,w,hbox = self.create_list_tab([ _('Address'), _('Label'), _('Requested'), _('Balance'), _('Tx')])
                l.setContextMenuPolicy(Qt.CustomContextMenu)
                l.customContextMenuRequested.connect(self.create_receive_menu)
       -        self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), lambda a, b: self.address_label_clicked(a,b,l,1,2))
       -        self.connect(l, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), lambda a,b: self.address_label_changed(a,b,l,1,2))
       +        self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), lambda a, b: self.address_label_clicked(a,b,l,0,1))
       +        self.connect(l, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), lambda a,b: self.address_label_changed(a,b,l,0,1))
                self.connect(l, SIGNAL('currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)'), lambda a,b: self.recv_changed(a))
                self.receive_list = l
                self.receive_buttons_hbox = hbox
       t@@ -1069,7 +1071,7 @@ class ElectrumWindow(QMainWindow):
        
            def save_column_widths(self):
                if self.receive_tab_mode == 0:
       -            widths = [ self.receive_list.columnWidth(1) ]
       +            widths = [ self.receive_list.columnWidth(0) ]
                else:
                    widths = []
                    for i in range(self.receive_list.columnCount() -1):
       t@@ -1116,7 +1118,7 @@ class ElectrumWindow(QMainWindow):
        
                item = self.receive_list.itemAt(position)
                if not item: return
       -        addr = unicode(item.text(1))
       +        addr = unicode(item.text(0))
                menu = QMenu()
                menu.addAction(_("Copy to clipboard"), lambda: self.app.clipboard().setText(addr))
                if self.receive_tab_mode == 2:
       t@@ -1186,13 +1188,9 @@ class ElectrumWindow(QMainWindow):
        
        
            def update_receive_item(self, item):
       -        address = str( item.data(1,0).toString() )
       -
       -        flags = self.wallet.get_address_flags(address)
       -        item.setData(0,0,flags)
       -
       +        address = str(item.data(0,0).toString())
                label = self.wallet.labels.get(address,'')
       -        item.setData(2,0,label)
       +        item.setData(1,0,label)
        
                try:
                    amount, currency = self.wallet.requested_amounts.get(address, (None, None))
       t@@ -1200,60 +1198,81 @@ class ElectrumWindow(QMainWindow):
                    amount, currency = None, None
                    
                amount_str = amount + (' ' + currency if currency else '') if amount is not None  else ''
       -        item.setData(3,0,amount_str)
       +        item.setData(2,0,amount_str)
                        
                c, u = self.wallet.get_addr_balance(address)
                balance = format_satoshis( c + u, False, self.wallet.num_zeros )
       -        item.setData(4,0,balance)
       +        item.setData(3,0,balance)
        
                if self.receive_tab_mode == 1:
                    if address in self.wallet.frozen_addresses: 
       -                item.setBackgroundColor(1, QColor('lightblue'))
       +                item.setBackgroundColor(0, QColor('lightblue'))
                    elif address in self.wallet.prioritized_addresses: 
       -                item.setBackgroundColor(1, QColor('lightgreen'))
       +                item.setBackgroundColor(0, QColor('lightgreen'))
                
        
            def update_receive_tab(self):
                l = self.receive_list
                
                l.clear()
       -        l.setColumnHidden(0, not self.receive_tab_mode == 1)
       -        l.setColumnHidden(3, not self.receive_tab_mode == 2)
       -        l.setColumnHidden(4, self.receive_tab_mode == 0)
       -        l.setColumnHidden(5, not self.receive_tab_mode == 1)
       -        if self.receive_tab_mode ==0:
       +        l.setColumnHidden(2, not self.receive_tab_mode == 2)
       +        l.setColumnHidden(3, self.receive_tab_mode == 0)
       +        l.setColumnHidden(4, not self.receive_tab_mode == 1)
       +        if self.receive_tab_mode == 0:
                    width = self.column_widths['receive'][0][0]
       -            l.setColumnWidth(1, width)
       +            l.setColumnWidth(0, width)
                else:
                    for i,width in enumerate(self.column_widths['receive'][self.receive_tab_mode]):
                        l.setColumnWidth(i, width)        
        
       -        gap = 0
       -        is_red = False
       -        for address in self.wallet.all_addresses():
        
       -            if self.wallet.is_change(address) and self.receive_tab_mode != 1:
       -                continue
       +        for k, account in self.wallet.accounts.items():
       +            name = account.get('name',str(k))
       +            account_item = QTreeWidgetItem( [ name, '', '', '', ''] )
       +            l.addTopLevelItem(account_item)
       +            account_item.setExpanded(True)
        
       -            h = self.wallet.history.get(address,[])
       -            
       -            if address in self.wallet.addresses:
       -                if h == []:
       -                    gap += 1
       -                    if gap > self.wallet.gap_limit:
       -                        is_red = True
       -                else:
       -                    gap = 0
       +            for is_change in [0,1]:
       +                name = "Receiving" if not is_change else "Change"
       +                seq_item = QTreeWidgetItem( [ name, '', '', '', ''] )
       +                account_item.addChild(seq_item)
       +                if not is_change: seq_item.setExpanded(True)
       +                is_red = False
       +                gap = 0
        
       -            num_tx = '*' if h == ['*'] else "%d"%len(h)
       -            item = QTreeWidgetItem( [ '', address, '', '', '', num_tx] )
       -            item.setFont(0, QFont(MONOSPACE_FONT))
       -            item.setFont(1, QFont(MONOSPACE_FONT))
       -            item.setFont(3, QFont(MONOSPACE_FONT))
       -            self.update_receive_item(item)
       -            if is_red and address in self.wallet.addresses:
       -                item.setBackgroundColor(1, QColor('red'))
       -            l.addTopLevelItem(item)
       +                for address in account[is_change]:
       +                    h = self.wallet.history.get(address,[])
       +            
       +                    if not is_change:
       +                        if h == []:
       +                            gap += 1
       +                            if gap > self.wallet.gap_limit:
       +                                is_red = True
       +                        else:
       +                            gap = 0
       +
       +                    num_tx = '*' if h == ['*'] else "%d"%len(h)
       +                    item = QTreeWidgetItem( [ address, '', '', '', num_tx] )
       +                    item.setFont(0, QFont(MONOSPACE_FONT))
       +                    item.setFont(2, QFont(MONOSPACE_FONT))
       +                    self.update_receive_item(item)
       +                    if is_red and not is_change:
       +                        item.setBackgroundColor(1, QColor('red'))
       +                    seq_item.addChild(item)
       +
       +        if self.wallet.imported_keys:
       +            account_item = QTreeWidgetItem( [ "Imported", '', '', '', ''] )
       +            l.addTopLevelItem(account_item)
       +            account_item.setExpanded(True)
       +            for address in self.wallet.imported_keys.keys():
       +                item = QTreeWidgetItem( [ address, '', '', '', ''] )
       +                item.setFont(0, QFont(MONOSPACE_FONT))
       +                item.setFont(2, QFont(MONOSPACE_FONT))
       +                self.update_receive_item(item)
       +                if is_red and not is_change:
       +                    item.setBackgroundColor(1, QColor('red'))
       +                account_item.addChild(item)
       +                
        
                # we use column 1 because column 0 may be hidden
                l.setCurrentItem(l.topLevelItem(0),1)
       t@@ -1391,8 +1410,8 @@ class ElectrumWindow(QMainWindow):
                dialog.exec_()
                
        
       -    @staticmethod
       -    def show_seed_dialog(wallet, parent=None):
       +    @classmethod
       +    def show_seed_dialog(self, wallet, parent=None):
                if not wallet.seed:
                    QMessageBox.information(parent, _('Message'), _('No seed'), _('OK'))
                    return
       t@@ -1410,6 +1429,10 @@ class ElectrumWindow(QMainWindow):
                    QMessageBox.warning(parent, _('Error'), _('Incorrect Password'), _('OK'))
                    return
        
       +        self.show_seed(seed)
       +
       +    @classmethod
       +    def show_seed(self, seed):
                dialog = QDialog(None)
                dialog.setModal(1)
                dialog.setWindowTitle('Electrum' + ' - ' + _('Seed'))
       t@@ -1625,8 +1648,8 @@ class ElectrumWindow(QMainWindow):
                    self.qr_window.setVisible(False)
        
                #self.print_button.setHidden(self.qr_window is None or not self.qr_window.isVisible())
       -        self.receive_list.setColumnHidden(3, self.qr_window is None or not self.qr_window.isVisible())
       -        self.receive_list.setColumnWidth(2, 200)
       +        self.receive_list.setColumnHidden(2, self.qr_window is None or not self.qr_window.isVisible())
       +        self.receive_list.setColumnWidth(1, 200)
        
        
            def question(self, msg):
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -80,8 +80,6 @@ class Wallet:
                self.fee                   = int(config.get('fee',100000))
                self.num_zeros             = int(config.get('num_zeros',0))
                self.use_encryption        = config.get('use_encryption', False)
       -        self.addresses             = config.get('addresses', [])          # receiving addresses visible for user
       -        self.change_addresses      = config.get('change_addresses', [])   # addresses used as change
                self.seed                  = config.get('seed', '')               # encrypted
                self.labels                = config.get('labels', {})
                self.aliases               = config.get('aliases', {})            # aliases for addresses
       t@@ -93,9 +91,15 @@ class Wallet:
                self.imported_keys         = config.get('imported_keys',{})
                self.history               = config.get('addr_history',{})        # address -> list(txid, height)
                self.tx_height             = config.get('tx_height',{})
       +        self.requested_amounts     = config.get('requested_amounts',{}) 
       +        self.accounts              = config.get('accounts', {})   # this should not include public keys
       +        self.sequences = {}
       +
       +        mpk1 = self.config.get('master_public_key')
       +        self.sequences[0] = DeterministicSequence(mpk1)
       +        if self.accounts.get(0) is None:
       +            self.accounts[0] = { 0:[], 1:[], 'name':'Main account' }
        
       -        master_public_key     = config.get('master_public_key','')
       -        self.sequence = DeterministicSequence(master_public_key)
        
                self.transactions = {}
                tx = config.get('transactions',{})
       t@@ -105,7 +109,6 @@ class Wallet:
                    print_msg("Warning: Cannot deserialize transactions. skipping")
                
        
       -        self.requested_amounts     = config.get('requested_amounts',{}) 
        
                # not saved
                self.prevout_values = {}     # my own transaction outputs
       t@@ -162,21 +165,33 @@ class Wallet:
                self.seed = seed 
                self.config.set_key('seed', self.seed, True)
                self.config.set_key('seed_version', self.seed_version, True)
       -        self.init_mpk(self.seed)
        
       -    def init_mpk(self,seed):
       +        self.init_main_account(self.seed)
       +        
       +
       +    def init_main_account(self, seed):
                # public key
       -        self.sequence = DeterministicSequence.from_seed(seed)
       -        self.config.set_key('master_public_key', self.sequence.master_public_key, True)
       +        sequence = DeterministicSequence.from_seed(seed)
       +        self.accounts[0] = { 0:[], 1:[], 'name':'Main account' }
       +        self.sequences[0] = sequence
       +        self.config.set_key('accounts', self.accounts, True)
       +
       +
        
            def all_addresses(self):
       -        return self.addresses + self.change_addresses + self.imported_keys.keys()
       +        o = self.imported_keys.keys()
       +        for a in self.accounts.values():
       +            o += a[0]
       +            o += a[1]
       +        return o
       +
        
            def is_mine(self, address):
                return address in self.all_addresses()
        
            def is_change(self, address):
       -        return address in self.change_addresses
       +        #return address in self.change_addresses
       +        return False
        
            def get_master_public_key(self):
                return self.sequence.master_public_key
       t@@ -184,47 +199,40 @@ class Wallet:
            def get_address_index(self, address):
                if address in self.imported_keys.keys():
                    raise BaseException("imported key")
       -
       -        if address in self.addresses:
       -            n = self.addresses.index(address)
       -            for_change = False
       -        elif address in self.change_addresses:
       -            n = self.change_addresses.index(address)
       -            for_change = True
       -        return n,for_change
       +        for account in self.accounts.keys():
       +            for for_change in [0,1]:
       +                addresses = self.accounts[account][for_change]
       +                for addr in addresses:
       +                    if address == addr:
       +                        return account, for_change, addresses.index(addr)
       +        raise BaseException("not found")
       +        
        
            def get_public_key(self, address):
       -        n, for_change = self.get_address_index(address)
       -        return self.sequence.get_pubkey(n, for_change)
       +        account, n, for_change = self.get_address_index(address)
       +        return self.sequences[account].get_pubkey(n, for_change)
        
        
            def decode_seed(self, password):
                seed = pw_decode(self.seed, password)
       -        self.sequence.check_seed(seed)
       +        self.sequences[0].check_seed(seed)
                return seed
                
            def get_private_key(self, address, password):
       -        return self.get_private_keys([address], password)[address]
       +        return self.get_private_keys([address], password).get(address)
        
            def get_private_keys(self, addresses, password):
                # decode seed in any case, in order to test the password
                seed = self.decode_seed(password)
       -        secexp = self.sequence.stretch_key(seed)
       +        secexp = self.sequences[0].stretch_key(seed)
                out = {}
                for address in addresses:
                    if address in self.imported_keys.keys():
       -                pk = pw_decode( self.imported_keys[address], password )
       +                out[address] = pw_decode( self.imported_keys[address], password )
                    else:
       -                if address in self.addresses:
       -                    n = self.addresses.index(address)
       -                    for_change = False
       -                elif address in self.change_addresses:
       -                    n = self.change_addresses.index(address)
       -                    for_change = True
       -                else:
       -                    raise BaseException("unknown address", address)
       -                pk = self.sequence.get_private_key_from_stretched_exponent(n, for_change, secexp)
       -            out[address] = pk
       +                account, for_change, n = self.get_address_index(address)
       +                if account == 0:
       +                    out[address] = self.sequences[0].get_private_key_from_stretched_exponent(n, for_change, secexp)
                return out
        
        
       t@@ -261,11 +269,11 @@ class Wallet:
        
                    # find the address:
                    if txin.get('electrumKeyID'):
       -                n, for_change = txin.get('electrumKeyID')
       -                sec = self.sequence.get_private_key(n, for_change, seed)
       -                address = address_from_private_key(sec)
       -                txin['address'] = address
       -                private_keys[address] = sec
       +                account, for_change, n = txin.get('electrumKeyID')
       +                sec = self.sequences[account].get_private_key(n, for_change, seed)
       +                addr = self.sequences[account].get_address(n, for_change)
       +                txin['address'] = addr
       +                private_keys[addr] = sec
        
                    elif txin.get("redeemScript"):
                        txin['address'] = hash_160_to_bc_address(hash_160(txin.get("redeemScript").decode('hex')), 5)
       t@@ -280,26 +288,24 @@ class Wallet:
        
                tx.sign( private_keys )
        
       -
            def sign_message(self, address, message, password):
                sec = self.get_private_key(address, password)
                key = regenerate_key(sec)
                compressed = is_compressed(sec)
                return key.sign_message(message, compressed, address)
       -        
       -    def create_new_address(self, for_change):
       -        n = len(self.change_addresses) if for_change else len(self.addresses)
       -        address = self.get_new_address(n, for_change)
       -        if for_change:
       -            self.change_addresses.append(address)
       -        else:
       -            self.addresses.append(address)
       +
       +
       +    def create_new_address(self, account, for_change):
       +        addresses = self.accounts[account][for_change]
       +        n = len(addresses)
       +        address = self.get_new_address( account, for_change, n)
       +        self.accounts[account][for_change].append(address)
                self.history[address] = []
                return address
                
       -    def get_new_address(self, n, for_change):
       -        pubkey = self.sequence.get_pubkey(n, for_change)
       -        address = public_key_to_bc_address( pubkey.decode('hex') )
       +
       +    def get_new_address(self, account, for_change, n):
       +        return self.sequences[account].get_address(for_change, n)
                print_msg( address )
                return address
        
       t@@ -311,18 +317,22 @@ class Wallet:
                    return True
        
                elif value >= self.min_acceptable_gap():
       -            k = self.num_unused_trailing_addresses()
       -            n = len(self.addresses) - k + value
       -            self.addresses = self.addresses[0:n]
       +            for key, account in self.accounts.items():
       +                addresses = account[0]
       +                k = self.num_unused_trailing_addresses(addresses)
       +                n = len(addresses) - k + value
       +                addresses = addresses[0:n]
       +                self.accounts[key][0] = addresses
       +
                    self.gap_limit = value
                    self.save()
                    return True
                else:
                    return False
        
       -    def num_unused_trailing_addresses(self):
       +    def num_unused_trailing_addresses(self, addresses):
                k = 0
       -        for a in self.addresses[::-1]:
       +        for a in addresses[::-1]:
                    if self.history.get(a):break
                    k = k + 1
                return k
       t@@ -331,13 +341,16 @@ class Wallet:
                # fixme: this assumes wallet is synchronized
                n = 0
                nmax = 0
       -        k = self.num_unused_trailing_addresses()
       -        for a in self.addresses[0:-k]:
       -            if self.history.get(a):
       -                n = 0
       -            else:
       -                n += 1
       -                if n > nmax: nmax = n
       +
       +        for account in self.accounts.values():
       +            addresses = account[0]
       +            k = self.num_unused_trailing_addresses(addresses)
       +            for a in addresses[0:-k]:
       +                if self.history.get(a):
       +                    n = 0
       +                else:
       +                    n += 1
       +                    if n > nmax: nmax = n
                return nmax + 1
        
        
       t@@ -356,26 +369,32 @@ class Wallet:
                return age > 2
        
        
       -    def synchronize_sequence(self, addresses, n, for_change):
       +    def synchronize_sequence(self, account, for_change):
       +        limit = self.gap_limit_for_change if for_change else self.gap_limit
       +        addresses = self.accounts[account][for_change]
                new_addresses = []
                while True:
       -            if len(self.addresses) < n:
       -                new_addresses.append( self.create_new_address(for_change) )
       +            if len(addresses) < limit:
       +                new_addresses.append( self.create_new_address(account, for_change) )
                        continue
       -            if map( lambda a: self.address_is_old(a), addresses[-n:] ) == n*[False]:
       +            if map( lambda a: self.address_is_old(a), addresses[-limit:] ) == limit*[False]:
                        break
                    else:
       -                new_addresses.append( self.create_new_address(for_change) )
       +                new_addresses.append( self.create_new_address(account, for_change) )
                return new_addresses
                
        
       +    def synchronize_account(self, account):
       +        new = []
       +        new += self.synchronize_sequence(account, 0)
       +        new += self.synchronize_sequence(account, 1)
       +        return new
       +
            def synchronize(self):
       -        if not self.sequence.master_public_key:
       -            return []
       -        new_addresses = []
       -        new_addresses += self.synchronize_sequence(self.addresses, self.gap_limit, False)
       -        new_addresses += self.synchronize_sequence(self.change_addresses, self.gap_limit_for_change, True)
       -        return new_addresses
       +        new = []
       +        for account in self.accounts.keys():
       +            new += self.synchronize_account(account)
       +        return new
        
        
            def is_found(self):
       t@@ -506,14 +525,27 @@ class Wallet:
                        u += v
                return c, u
        
       -    def get_balance(self):
       +    def get_account_addresses(self, a):
       +        ac = self.accounts[a]
       +        return ac[0] + ac[1]
       +        
       +
       +    def get_account_balance(self, account):
                conf = unconf = 0
       -        for addr in self.all_addresses(): 
       +        for addr in self.get_account_addresses(account): 
                    c, u = self.get_addr_balance(addr)
                    conf += c
                    unconf += u
                return conf, unconf
        
       +    def get_balance(self):
       +        cc = uu = 0
       +        for a in self.accounts.keys():
       +            c, u = self.get_account_balance(a)
       +            cc += c
       +            uu += u
       +        return cc, uu
       +
        
            def get_unspent_coins(self, domain=None):
                coins = []
       t@@ -557,7 +589,7 @@ class Wallet:
                    addr = item.get('address')
                    v = item.get('value')
                    total += v
       -            item['pubkeysig'] = [(None, None)]
       +
                    inputs.append( item )
                    fee = self.fee*len(inputs) if fixed_fee is None else fixed_fee
                    if total >= amount + fee: break
       t@@ -718,15 +750,18 @@ class Wallet:
                outputs = self.add_tx_change(outputs, amount, fee, total, change_addr)
        
                tx = Transaction.from_io(inputs, outputs)
       -        for i in range(len(tx.inputs)):
       -            addr = tx.inputs[i]['address']
       -            n, is_change = self.get_address_index(addr)
       -            tx.input_info[i]['electrumKeyID'] = (n, is_change)
        
       -        if not self.seed:
       -            return tx
       -        
       -        self.sign_tx(tx, password)
       +        pk_addresses = []
       +        for i in range(len(tx.inputs)):
       +            txin = tx.inputs[i]
       +            account, is_change, n = self.get_address_index(txin['address'])
       +            pk_addr = self.sequences[account].add_input_info(txin, account, is_change, n)
       +            pk_addresses.append(pk_addr)
       +
       +        # get all private keys at once.
       +        private_keys = self.get_private_keys(pk_addresses, password)
       +        print "private keys", private_keys
       +        tx.sign(private_keys)
        
                for address, x in outputs:
                    if address not in self.addressbook and not self.is_mine(address):
       t@@ -734,13 +769,7 @@ class Wallet:
        
                return tx
        
       -    def sign_tx(self, tx, password):
       -        private_keys = {}
       -        for txin in tx.inputs:
       -            addr = txin['address']
       -            sec = self.get_private_key(addr, password)
       -            private_keys[addr] = sec
       -        tx.sign(private_keys)
       +
        
            def sendtx(self, tx):
                # synchronous
       t@@ -954,8 +983,7 @@ class Wallet:
                    'use_encryption': self.use_encryption,
                    'use_change': self.use_change,
                    'fee': self.fee,
       -            'addresses': self.addresses,
       -            'change_addresses': self.change_addresses,
       +            'accounts': self.accounts,
                    'addr_history': self.history, 
                    'labels': self.labels,
                    'contacts': self.addressbook,