diff --git a/client/electrum b/client/electrum index fbee56ac5..5ff454c22 100755 --- a/client/electrum +++ b/client/electrum @@ -61,6 +61,7 @@ if __name__ == '__main__': import gui gui.init_wallet(wallet) gui = gui.BitcoinGUI(wallet) + interface.start(wallet) if re.match('^bitcoin:', cmd): @@ -111,12 +112,12 @@ if __name__ == '__main__': else: password = None - host = raw_input("server (default:%s):"%wallet.interface.host) - port = raw_input("port (default:%d):"%wallet.interface.port) + host = raw_input("server (default:%s):"%interface.host) + port = raw_input("port (default:%d):"%interface.port) fee = raw_input("fee (default:%s):"%( str(Decimal(wallet.fee)/100000000)) ) if fee: wallet.fee = float(fee) - if host: wallet.interface.host = host - if port: wallet.interface.port = int(port) + if host: interface.host = host + if port: interface.port = int(port) seed = raw_input("if you are restoring an existing wallet, enter the seed. otherwise just press enter: ") wallet.gap_limit = 5 if seed: @@ -153,8 +154,8 @@ if __name__ == '__main__': # open session if cmd not in ['password', 'mktx', 'history', 'label', 'contacts', 'help', 'validateaddress', 'signmessage', 'verifymessage', 'eval']: - wallet.interface.new_session(wallet.all_addresses(), wallet.electrum_version) - wallet.update() + interface.new_session(wallet.all_addresses(), wallet.electrum_version) + interface.update_wallet(wallet) wallet.save() # commands needing password @@ -311,7 +312,7 @@ if __name__ == '__main__': print "invalid key pair" exit(1) addr = wallet.imported_keys.keys()[0] - wallet.history[addr] = wallet.interface.retrieve_history(addr) + wallet.history[addr] = interface.retrieve_history(addr) wallet.synchronize() wallet.update_tx_history() wallet.addresses = [] diff --git a/client/gui.py b/client/gui.py index d2db96500..b13d9499b 100644 --- a/client/gui.py +++ b/client/gui.py @@ -486,10 +486,8 @@ class BitcoinGUI: show_message(msg, self.window) def __init__(self, wallet): - self.error = '' self.wallet = wallet - self.wallet.interface.is_connected = False - self.period = 5 + self.funds_error = False # True if not enough funds self.window = MyWindow(gtk.WINDOW_TOPLEVEL) self.window.set_title(APP_NAME + " " + self.wallet.electrum_version) @@ -596,52 +594,6 @@ class BitcoinGUI: gobject.idle_add( lambda: self.payto_entry.set_text(s) ) - def update_wallet_thread(): - while True: - try: - self.wallet.interface.is_connected = False - self.wallet.interface.new_session(self.wallet.all_addresses(), self.wallet.electrum_version) - self.update_session = False - self.info.set_text( self.wallet.interface.message) - except: - traceback.print_exc(file=sys.stdout) - time.sleep(self.period) - continue - - get_servers_time = 0 - while True: - try: - if self.wallet.interface.is_connected and self.update_session: - self.wallet.interface.update_session( self.wallet.all_addresses() ) - self.update_session = False - - if time.time() - get_servers_time > 5*60: - wallet.interface.get_servers() - get_servers_time = time.time() - - self.period = 15 if self.wallet.interface.use_http() else 5 - if self.wallet.update(): - self.wallet.interface.update_session( self.wallet.all_addresses() ) - gobject.idle_add( self.update_history_tab ) - gobject.idle_add( self.update_receiving_tab ) - # addressbook too... - - time.sleep(self.period) - except BaseException: - traceback.print_exc(file=sys.stdout) - print "starting new session" - break - except socket.gaierror: - self.wallet.interface.is_connected = False - break - except: - self.wallet.interface.is_connected = False - print "error" - traceback.print_exc(file=sys.stdout) - break - self.error = '' if self.wallet.interface.is_connected else "Not connected" - - thread.start_new_thread(update_wallet_thread, ()) thread.start_new_thread(update_status_bar_thread, ()) thread.start_new_thread(check_recipient_thread, ()) self.notebook.set_current_page(0) @@ -719,11 +671,11 @@ class BitcoinGUI: self.user_fee = False def entry_changed( entry, is_fee ): + self.funds_error = False amount = numbify(amount_entry) fee = numbify(fee_entry) if not is_fee: fee = None - if amount is None: - #self.fee_box.hide(); + if amount is None: return inputs, total, fee = self.wallet.choose_tx_inputs( amount, fee ) if not is_fee: @@ -733,12 +685,11 @@ class BitcoinGUI: amount_entry.modify_text(gtk.STATE_NORMAL, gtk.gdk.color_parse("#000000")) fee_entry.modify_text(gtk.STATE_NORMAL, gtk.gdk.color_parse("#000000")) send_button.set_sensitive(True) - self.error = '' else: send_button.set_sensitive(False) amount_entry.modify_text(gtk.STATE_NORMAL, gtk.gdk.color_parse("#cc0000")) fee_entry.modify_text(gtk.STATE_NORMAL, gtk.gdk.color_parse("#cc0000")) - self.error = 'Not enough funds' + self.funds_error = True amount_entry.connect('changed', entry_changed, False) fee_entry.connect('changed', entry_changed, True) @@ -1173,18 +1124,35 @@ class BitcoinGUI: return vbox def update_status_bar(self): - c, u = self.wallet.get_balance() - if self.wallet.interface.is_connected: - self.status_image.set_from_stock(gtk.STOCK_YES, gtk.ICON_SIZE_MENU) - self.network_button.set_tooltip_text("Connected to %s.\n%d blocks\nresponse time: %f"%(self.wallet.interface.host, self.wallet.interface.blocks, self.wallet.interface.rtime)) + + if self.funds_error: + text = "Not enough funds" + elif self.wallet.interface.is_connected: + if self.wallet.interface.blocks > 0: + self.status_image.set_from_stock(gtk.STOCK_YES, gtk.ICON_SIZE_MENU) + self.network_button.set_tooltip_text("Connected to %s.\n%d blocks\nresponse time: %f"%(self.wallet.interface.host, self.wallet.interface.blocks, self.wallet.interface.rtime)) + c, u = self.wallet.get_balance() + text = "Balance: %s "%( format_satoshis(c) ) + if u: text += "[%s unconfirmed]"%( format_satoshis(u,True) ) + else: + self.status_image.set_from_stock(gtk.STOCK_STOP, gtk.ICON_SIZE_MENU) + self.network_button.set_tooltip_text("Connected to %s.\n%d blocks\nresponse time: %f"%(self.wallet.interface.host, self.wallet.interface.blocks, self.wallet.interface.rtime)) + text = "Server not ready" else: self.status_image.set_from_stock(gtk.STOCK_NO, gtk.ICON_SIZE_MENU) self.network_button.set_tooltip_text("Trying to contact %s.\n%d blocks"%(self.wallet.interface.host, self.wallet.interface.blocks)) - text = "Balance: %s "%( format_satoshis(c) ) - if u: text += "[%s unconfirmed]"%( format_satoshis(u,True) ) - if self.error: text = self.error + text = "Not connected" + self.status_bar.pop(self.context_id) - self.status_bar.push(self.context_id, text) + self.status_bar.push(self.context_id, text) + + if self.wallet.interface.was_updated: + self.update_history_tab() + self.update_receiving_tab() + # addressbook too... + self.info.set_text( self.wallet.interface.message ) + self.wallet.interface.was_updated = False + def update_receiving_tab(self): self.recv_list.clear() diff --git a/client/interface.py b/client/interface.py index b9aa2979a..d9e651e49 100644 --- a/client/interface.py +++ b/client/interface.py @@ -20,6 +20,7 @@ import random, socket, ast +import thread, traceback, sys, time class Interface: @@ -31,6 +32,7 @@ class Interface: self.message = '' self.set_port(50000) self.is_connected = False + self.was_updated = True # fixme: use a semaphore def set_port(self, port_number): self.port = port_number @@ -105,6 +107,7 @@ class Interface: def new_session(self, addresses, version): out = self.handler('session.new', [ version, addresses ] ) self.session_id, self.message = ast.literal_eval( out ) + self.was_updated = True def update_session(self, addresses): out = self.handler('session.update', [ self.session_id, addresses ] ) @@ -113,3 +116,69 @@ class Interface: def get_servers(self): out = self.handler('peers') self.servers = map( lambda x:x[1], out ) + + def poll_interval(self): + return 15 if self.use_http() else 5 + + def update_wallet(self, wallet): + is_new = False + changed_addresses = self.poll() + for addr, blk_hash in changed_addresses.items(): + if wallet.status.get(addr) != blk_hash: + print "updating history for", addr + wallet.history[addr] = self.retrieve_history(addr) + wallet.status[addr] = blk_hash + is_new = True + + if is_new: + wallet.synchronize() + wallet.update_tx_history() + wallet.save() + return True + else: + return False + + def update_thread(self, wallet): + while True: + try: + self.is_connected = False + self.new_session(wallet.all_addresses(), wallet.electrum_version) + self.update_session = False + except: + traceback.print_exc(file=sys.stdout) + time.sleep(self.poll_interval()) + continue + + get_servers_time = 0 + while True: + try: + if self.is_connected and self.update_session: + self.update_session( wallet.all_addresses() ) + self.update_session = False + + if time.time() - get_servers_time > 5*60: + self.get_servers() + get_servers_time = time.time() + + # define a method to update the list + if self.update_wallet(wallet): + self.update_session( wallet.all_addresses() ) + self.was_updated = True # for gui + + time.sleep(self.poll_interval()) + except BaseException: + traceback.print_exc(file=sys.stdout) + print "starting new session" + break + except socket.gaierror: + self.is_connected = False + break + except: + self.is_connected = False + print "error" + traceback.print_exc(file=sys.stdout) + break + + + def start(self, wallet): + thread.start_new_thread(self.update_thread, (wallet,)) diff --git a/client/wallet.py b/client/wallet.py index 9123e5028..2f3aa6615 100644 --- a/client/wallet.py +++ b/client/wallet.py @@ -573,23 +573,6 @@ class Wallet: unconf += u return conf, unconf - def update(self): - is_new = False - changed_addresses = self.interface.poll() - for addr, blk_hash in changed_addresses.items(): - if self.status.get(addr) != blk_hash: - print "updating history for", addr - self.history[addr] = self.interface.retrieve_history(addr) - self.status[addr] = blk_hash - is_new = True - - if is_new: - self.synchronize() - self.update_tx_history() - self.save() - return True - else: - return False def choose_tx_inputs( self, amount, fixed_fee ): """ todo: minimize tx size """