electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 8fabc5bb2df92b4fac107143ed6464c454355ca3
parent 7bb58271af91831b5e548441475d71cc90ccb894
Author: ThomasV <thomasv@gitorious>
Date:   Wed, 11 Jan 2012 19:36:58 +0300

Merge branch 'master' of gitorious.org:electrum/electrum

Diffstat:
Mclient/electrum.py | 161++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mclient/gui.py | 35++++++++++++++++++-----------------
2 files changed, 111 insertions(+), 85 deletions(-)

diff --git a/client/electrum.py b/client/electrum.py @@ -216,6 +216,88 @@ def raw_tx( inputs, outputs, for_sig = None ): from version import ELECTRUM_VERSION, SEED_VERSION +class Interface: + def __init__(self): + self.servers = ['ecdsa.org','electrum.novit.ro'] # list of default servers + self.host = random.choice( self.servers ) # random choice when the wallet is created + self.rtime = 0 + self.blocks = 0 + self.message = '' + self.set_port(50000) + + def set_port(self, port_number): + self.port = port_number + if self.use_http(): + import jsonrpclib + self.http_json_server = jsonrpclib.Server('http://%s:%d'%(self.host,self.port)) + + def use_http(self): + return self.port in [80,81,8080,8081] + + def request(self, request ): + import time + t1 = time.time() + request += "#" + s = socket.socket( socket.AF_INET, socket.SOCK_STREAM) + s.connect(( self.host, self.port)) + s.send( request ) + out = '' + while 1: + msg = s.recv(1024) + if msg: out += msg + else: break + s.close() + self.rtime = time.time() - t1 + return out + + def send_tx(self, data): + if self.use_http(): + out = self.http_json_server.blockchain.transaction.broadcast(data) + else: + out = self.request( repr ( ('tx', data ))) + return out + + def retrieve_history(self, address): + if self.use_http(): + out = self.http_json_server.blockchain.address.get_history(address) + else: + out = ast.literal_eval( self.request( repr ( ('h', address ))) ) + return out + + def poll(self): + if self.use_http(): + out = ast.literal_eval( self.http_json_server.session.poll( self.session_id ) ) + else: + out = ast.literal_eval( self.request( repr ( ('poll', self.session_id )))) + + blocks, changed_addr = out + if blocks == -1: raise BaseException("session not found") + self.blocks = int(blocks) + return changed_addr + + def new_session(self, addresses, version): + if self.use_http(): + out = ast.literal_eval( self.http_json_server.session.new(addresses, version) ) + else: + out = ast.literal_eval( self.request( repr ( ('new_session', repr( ( version, addresses)) )))) + self.session_id, self.message = out + + def update_session(self): + if self.use_http(): + out = self.http_json_server.session.update(self.session_id, self.all_addresses()) + else: + out = self.request( repr ( ('update_session', repr((self.session_id, self.all_addresses()))))) + return out + + def get_servers(self): + if self.use_http(): + out = self.http_json_server.peers() + else: + out = ast.literal_eval( self.request( repr ( ('peers', '' )))) + self.servers = map( lambda x:x[1], out ) + + + class Wallet: def __init__(self): @@ -224,10 +306,7 @@ class Wallet: self.seed_version = SEED_VERSION self.gap_limit = 5 # configuration - self.port = 50000 self.fee = 100000 - self.servers = ['ecdsa.org','electrum.novit.ro'] # list of default servers - self.host = random.choice( self.servers ) # random choice when the wallet is created self.master_public_key = '' # saved fields @@ -239,15 +318,14 @@ class Wallet: self.history = {} self.labels = {} # labels for addresses and transactions self.addressbook = [] # outgoing addresses, for payments - self.blocks = 0 # not saved - self.message = '' self.tx_history = {} - self.rtime = 0 self.imported_keys = {} + self.interface = Interface() + def set_path(self, wallet_path): @@ -359,7 +437,7 @@ class Wallet: # updates print address - self.history[address] = h = self.retrieve_history(address) + self.history[address] = h = self.interface.retrieve_history(address) self.status[address] = h[-1]['blk_hash'] if h else None return address @@ -410,8 +488,8 @@ class Wallet: 'use_encryption':self.use_encryption, 'master_public_key': self.master_public_key.encode('hex'), 'fee':self.fee, - 'host':self.host, - 'port':self.port, + 'host':self.interface.host, + 'port':self.interface.port, 'blocks':self.blocks, 'seed':self.seed, 'addresses':self.addresses, @@ -440,8 +518,8 @@ class Wallet: self.master_public_key = d.get('master_public_key').decode('hex') self.use_encryption = d.get('use_encryption') self.fee = int( d.get('fee') ) - self.host = d.get('host') - self.port = d.get('port') + self.interface.host = d.get('host') + self.interface.set_port( d.get('port') ) self.blocks = d.get('blocks') self.seed = d.get('seed') self.addresses = d.get('addresses') @@ -493,66 +571,13 @@ class Wallet: unconf += u return conf, unconf - def use_http(self): - return self.port in [80,8080,443] - - def request(self, request ): - import time - t1 = time.time() - - if self.use_http(): - import httplib, urllib - params = urllib.urlencode({'q':request}) - headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"} - conn = httplib.HTTPSConnection(self.host) if self.port == 443 else httplib.HTTPConnection(self.host) - conn.request("POST", "/electrum.php", params, headers) - response = conn.getresponse() - if response.status == 200: - out = response.read() - else: out = '' - conn.close() - else: - request += "#" - s = socket.socket( socket.AF_INET, socket.SOCK_STREAM) - s.connect(( self.host, self.port)) - s.send( request ) - out = '' - while 1: - msg = s.recv(1024) - if msg: out += msg - else: break - s.close() - - self.rtime = time.time() - t1 - return out - - def send_tx(self, data): - return self.request( repr ( ('tx', data ))) - - def retrieve_history(self, address): - return ast.literal_eval( self.request( repr ( ('h', address ))) ) - - def poll(self): - return ast.literal_eval( self.request( repr ( ('poll', self.session_id )))) - - def new_session(self): - self.session_id, self.message = ast.literal_eval( self.request( repr ( ('new_session', repr( (self.electrum_version, self.all_addresses())) )))) - - def update_session(self): - return self.request( repr ( ('update_session', repr((self.session_id, self.all_addresses()))))) - - def get_servers(self): - self.servers = map( lambda x:x[1], ast.literal_eval( self.request( repr ( ('peers', '' )))) ) - def update(self): is_new = False - blocks, changed_addresses = self.poll() - if blocks == -1: raise BaseException("session not found") - self.blocks = int(blocks) + 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.retrieve_history(addr) + self.history[addr] = self.interface.retrieve_history(addr) self.status[addr] = blk_hash is_new = True @@ -702,7 +727,7 @@ class Wallet: def sendtx(self, tx): tx_hash = Hash(tx.decode('hex') )[::-1].encode('hex') - out = self.send_tx(tx) + out = self.interface.send_tx(tx) if out != tx_hash: return False, "error: " + out return True, out @@ -806,7 +831,7 @@ if __name__ == '__main__': # open session if cmd not in ['password', 'mktx', 'history', 'label', 'contacts', 'help', 'validateaddress']: - wallet.new_session() + wallet.interface.new_session(wallet.all_addresses(), wallet.electrum_version) wallet.update() wallet.save() diff --git a/client/gui.py b/client/gui.py @@ -214,7 +214,7 @@ def run_settings_dialog(wallet, is_create, is_recovery, parent): host_label.show() host.pack_start(host_label,False, False, 10) host_entry = gtk.Entry() - host_entry.set_text(wallet.host+":%d"%wallet.port) + host_entry.set_text(wallet.interface.host+":%d"%wallet.interface.port) host_entry.show() host.pack_start(host_entry,False,False, 10) add_help_button(host, 'The name and port number of your Electrum server, separated by a colon. Example: "ecdsa.org:50000". If no port number is provided, the http port 80 will be tried.') @@ -275,8 +275,8 @@ def run_settings_dialog(wallet, is_create, is_recovery, parent): return if is_create: - wallet.host = host - wallet.port = port + wallet.interface.host = host + wallet.interface.port = port if is_recovery: wallet.seed = seed wallet.gap_limit = gap @@ -494,10 +494,10 @@ class BitcoinGUI: while True: try: self.is_connected = False - self.wallet.new_session() + self.wallet.interface.new_session(self.wallet.all_addresses(), self.wallet.electrum_version) self.is_connected = True self.update_session = False - self.info.set_text( self.wallet.message) + self.info.set_text( self.wallet.interface.message) except: traceback.print_exc(file=sys.stdout) time.sleep(self.period) @@ -507,22 +507,23 @@ class BitcoinGUI: while True: try: if self.is_connected and self.update_session: - self.wallet.update_session() + self.wallet.interface.update_session() self.update_session = False if time.time() - get_servers_time > 5*60: - wallet.get_servers() + wallet.interface.get_servers() get_servers_time = time.time() - self.period = 15 if self.wallet.use_http() else 5 + self.period = 15 if self.wallet.interface.use_http() else 5 if self.wallet.update(): - self.wallet.update_session() + self.wallet.interface.update_session() 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: @@ -909,10 +910,10 @@ class BitcoinGUI: c, u = self.wallet.get_balance() if self.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.host, self.wallet.blocks, self.wallet.rtime)) + self.network_button.set_tooltip_text("Connected to %s.\n%d blocks\nresponse time: %f"%(self.wallet.interface.host, self.wallet.blocks, self.wallet.interface.rtime)) 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.host, self.wallet.blocks)) + self.network_button.set_tooltip_text("Trying to contact %s.\n%d blocks"%(self.wallet.interface.host, self.wallet.blocks)) text = "Balance: %s "%( format_satoshis(c) ) if u: text += "[+ %s unconfirmed]"%( format_satoshis(u) ) if self.error: text = self.error @@ -1034,7 +1035,7 @@ class BitcoinGUI: image = gtk.Image() image.set_from_stock(gtk.STOCK_NETWORK, gtk.ICON_SIZE_DIALOG) if self.is_connected: - status = "Connected to %s.\n%d blocks\nresponse time: %f"%(wallet.host, wallet.blocks, wallet.rtime) + status = "Connected to %s.\n%d blocks\nresponse time: %f"%(wallet.interface.host, wallet.blocks, wallet.interface.rtime) else: status = "Not connected" @@ -1052,14 +1053,14 @@ class BitcoinGUI: host.pack_start(host_label, False, False, 10) host_entry = gtk.Entry() host_entry.set_size_request(200,-1) - host_entry.set_text(wallet.host+":%d"%wallet.port) + host_entry.set_text(wallet.interface.host+":%d"%wallet.interface.port) host_entry.show() host.pack_start(host_entry, False, False, 10) add_help_button(host, 'The name and port number of your Electrum server, separated by a colon. Example: "ecdsa.org:50000". If no port number is provided, port 50000 will be tried. Some servers allow you to connect through http (port 80) or https (port 443)') host.show() server_list = gtk.ListStore(str) - for item in wallet.servers: + for item in wallet.interface.servers: server_list.append([item]) treeview = gtk.TreeView(model=server_list) @@ -1103,9 +1104,9 @@ class BitcoinGUI: self.show_message("error") return - if host!= wallet.host or port!=wallet.port: - wallet.host = host - wallet.port = port + if host!= wallet.interface.host or port!=wallet.interface.port: + wallet.interface.host = host + wallet.interface.set_port( port ) wallet.save() self.is_connected = False