Merge branch 'master' of gitorious.org:electrum/electrum
This commit is contained in:
commit
8fabc5bb2d
|
@ -216,6 +216,88 @@ def raw_tx( inputs, outputs, for_sig = None ):
|
||||||
|
|
||||||
from version import ELECTRUM_VERSION, SEED_VERSION
|
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:
|
class Wallet:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -224,10 +306,7 @@ class Wallet:
|
||||||
self.seed_version = SEED_VERSION
|
self.seed_version = SEED_VERSION
|
||||||
|
|
||||||
self.gap_limit = 5 # configuration
|
self.gap_limit = 5 # configuration
|
||||||
self.port = 50000
|
|
||||||
self.fee = 100000
|
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 = ''
|
self.master_public_key = ''
|
||||||
|
|
||||||
# saved fields
|
# saved fields
|
||||||
|
@ -239,15 +318,14 @@ class Wallet:
|
||||||
self.history = {}
|
self.history = {}
|
||||||
self.labels = {} # labels for addresses and transactions
|
self.labels = {} # labels for addresses and transactions
|
||||||
self.addressbook = [] # outgoing addresses, for payments
|
self.addressbook = [] # outgoing addresses, for payments
|
||||||
self.blocks = 0
|
|
||||||
|
|
||||||
# not saved
|
# not saved
|
||||||
self.message = ''
|
|
||||||
self.tx_history = {}
|
self.tx_history = {}
|
||||||
self.rtime = 0
|
|
||||||
|
|
||||||
self.imported_keys = {}
|
self.imported_keys = {}
|
||||||
|
|
||||||
|
self.interface = Interface()
|
||||||
|
|
||||||
|
|
||||||
def set_path(self, wallet_path):
|
def set_path(self, wallet_path):
|
||||||
|
|
||||||
|
@ -359,7 +437,7 @@ class Wallet:
|
||||||
|
|
||||||
# updates
|
# updates
|
||||||
print address
|
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
|
self.status[address] = h[-1]['blk_hash'] if h else None
|
||||||
return address
|
return address
|
||||||
|
|
||||||
|
@ -410,8 +488,8 @@ class Wallet:
|
||||||
'use_encryption':self.use_encryption,
|
'use_encryption':self.use_encryption,
|
||||||
'master_public_key': self.master_public_key.encode('hex'),
|
'master_public_key': self.master_public_key.encode('hex'),
|
||||||
'fee':self.fee,
|
'fee':self.fee,
|
||||||
'host':self.host,
|
'host':self.interface.host,
|
||||||
'port':self.port,
|
'port':self.interface.port,
|
||||||
'blocks':self.blocks,
|
'blocks':self.blocks,
|
||||||
'seed':self.seed,
|
'seed':self.seed,
|
||||||
'addresses':self.addresses,
|
'addresses':self.addresses,
|
||||||
|
@ -440,8 +518,8 @@ class Wallet:
|
||||||
self.master_public_key = d.get('master_public_key').decode('hex')
|
self.master_public_key = d.get('master_public_key').decode('hex')
|
||||||
self.use_encryption = d.get('use_encryption')
|
self.use_encryption = d.get('use_encryption')
|
||||||
self.fee = int( d.get('fee') )
|
self.fee = int( d.get('fee') )
|
||||||
self.host = d.get('host')
|
self.interface.host = d.get('host')
|
||||||
self.port = d.get('port')
|
self.interface.set_port( d.get('port') )
|
||||||
self.blocks = d.get('blocks')
|
self.blocks = d.get('blocks')
|
||||||
self.seed = d.get('seed')
|
self.seed = d.get('seed')
|
||||||
self.addresses = d.get('addresses')
|
self.addresses = d.get('addresses')
|
||||||
|
@ -493,66 +571,13 @@ class Wallet:
|
||||||
unconf += u
|
unconf += u
|
||||||
return conf, unconf
|
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):
|
def update(self):
|
||||||
is_new = False
|
is_new = False
|
||||||
blocks, changed_addresses = self.poll()
|
changed_addresses = self.interface.poll()
|
||||||
if blocks == -1: raise BaseException("session not found")
|
|
||||||
self.blocks = int(blocks)
|
|
||||||
for addr, blk_hash in changed_addresses.items():
|
for addr, blk_hash in changed_addresses.items():
|
||||||
if self.status.get(addr) != blk_hash:
|
if self.status.get(addr) != blk_hash:
|
||||||
print "updating history for", addr
|
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
|
self.status[addr] = blk_hash
|
||||||
is_new = True
|
is_new = True
|
||||||
|
|
||||||
|
@ -702,7 +727,7 @@ class Wallet:
|
||||||
|
|
||||||
def sendtx(self, tx):
|
def sendtx(self, tx):
|
||||||
tx_hash = Hash(tx.decode('hex') )[::-1].encode('hex')
|
tx_hash = Hash(tx.decode('hex') )[::-1].encode('hex')
|
||||||
out = self.send_tx(tx)
|
out = self.interface.send_tx(tx)
|
||||||
if out != tx_hash:
|
if out != tx_hash:
|
||||||
return False, "error: " + out
|
return False, "error: " + out
|
||||||
return True, out
|
return True, out
|
||||||
|
@ -806,7 +831,7 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
# open session
|
# open session
|
||||||
if cmd not in ['password', 'mktx', 'history', 'label', 'contacts', 'help', 'validateaddress']:
|
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.update()
|
||||||
wallet.save()
|
wallet.save()
|
||||||
|
|
||||||
|
|
|
@ -214,7 +214,7 @@ def run_settings_dialog(wallet, is_create, is_recovery, parent):
|
||||||
host_label.show()
|
host_label.show()
|
||||||
host.pack_start(host_label,False, False, 10)
|
host.pack_start(host_label,False, False, 10)
|
||||||
host_entry = gtk.Entry()
|
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_entry.show()
|
||||||
host.pack_start(host_entry,False,False, 10)
|
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.')
|
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
|
return
|
||||||
|
|
||||||
if is_create:
|
if is_create:
|
||||||
wallet.host = host
|
wallet.interface.host = host
|
||||||
wallet.port = port
|
wallet.interface.port = port
|
||||||
if is_recovery:
|
if is_recovery:
|
||||||
wallet.seed = seed
|
wallet.seed = seed
|
||||||
wallet.gap_limit = gap
|
wallet.gap_limit = gap
|
||||||
|
@ -494,10 +494,10 @@ class BitcoinGUI:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
self.is_connected = False
|
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.is_connected = True
|
||||||
self.update_session = False
|
self.update_session = False
|
||||||
self.info.set_text( self.wallet.message)
|
self.info.set_text( self.wallet.interface.message)
|
||||||
except:
|
except:
|
||||||
traceback.print_exc(file=sys.stdout)
|
traceback.print_exc(file=sys.stdout)
|
||||||
time.sleep(self.period)
|
time.sleep(self.period)
|
||||||
|
@ -507,22 +507,23 @@ class BitcoinGUI:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
if self.is_connected and self.update_session:
|
if self.is_connected and self.update_session:
|
||||||
self.wallet.update_session()
|
self.wallet.interface.update_session()
|
||||||
self.update_session = False
|
self.update_session = False
|
||||||
|
|
||||||
if time.time() - get_servers_time > 5*60:
|
if time.time() - get_servers_time > 5*60:
|
||||||
wallet.get_servers()
|
wallet.interface.get_servers()
|
||||||
get_servers_time = time.time()
|
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():
|
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_history_tab )
|
||||||
gobject.idle_add( self.update_receiving_tab )
|
gobject.idle_add( self.update_receiving_tab )
|
||||||
# addressbook too...
|
# addressbook too...
|
||||||
|
|
||||||
time.sleep(self.period)
|
time.sleep(self.period)
|
||||||
except BaseException:
|
except BaseException:
|
||||||
|
traceback.print_exc(file=sys.stdout)
|
||||||
print "starting new session"
|
print "starting new session"
|
||||||
break
|
break
|
||||||
except socket.gaierror:
|
except socket.gaierror:
|
||||||
|
@ -909,10 +910,10 @@ class BitcoinGUI:
|
||||||
c, u = self.wallet.get_balance()
|
c, u = self.wallet.get_balance()
|
||||||
if self.is_connected:
|
if self.is_connected:
|
||||||
self.status_image.set_from_stock(gtk.STOCK_YES, gtk.ICON_SIZE_MENU)
|
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:
|
else:
|
||||||
self.status_image.set_from_stock(gtk.STOCK_NO, gtk.ICON_SIZE_MENU)
|
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) )
|
text = "Balance: %s "%( format_satoshis(c) )
|
||||||
if u: text += "[+ %s unconfirmed]"%( format_satoshis(u) )
|
if u: text += "[+ %s unconfirmed]"%( format_satoshis(u) )
|
||||||
if self.error: text = self.error
|
if self.error: text = self.error
|
||||||
|
@ -1034,7 +1035,7 @@ class BitcoinGUI:
|
||||||
image = gtk.Image()
|
image = gtk.Image()
|
||||||
image.set_from_stock(gtk.STOCK_NETWORK, gtk.ICON_SIZE_DIALOG)
|
image.set_from_stock(gtk.STOCK_NETWORK, gtk.ICON_SIZE_DIALOG)
|
||||||
if self.is_connected:
|
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:
|
else:
|
||||||
status = "Not connected"
|
status = "Not connected"
|
||||||
|
|
||||||
|
@ -1052,14 +1053,14 @@ class BitcoinGUI:
|
||||||
host.pack_start(host_label, False, False, 10)
|
host.pack_start(host_label, False, False, 10)
|
||||||
host_entry = gtk.Entry()
|
host_entry = gtk.Entry()
|
||||||
host_entry.set_size_request(200,-1)
|
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_entry.show()
|
||||||
host.pack_start(host_entry, False, False, 10)
|
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)')
|
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()
|
host.show()
|
||||||
|
|
||||||
server_list = gtk.ListStore(str)
|
server_list = gtk.ListStore(str)
|
||||||
for item in wallet.servers:
|
for item in wallet.interface.servers:
|
||||||
server_list.append([item])
|
server_list.append([item])
|
||||||
|
|
||||||
treeview = gtk.TreeView(model=server_list)
|
treeview = gtk.TreeView(model=server_list)
|
||||||
|
@ -1103,9 +1104,9 @@ class BitcoinGUI:
|
||||||
self.show_message("error")
|
self.show_message("error")
|
||||||
return
|
return
|
||||||
|
|
||||||
if host!= wallet.host or port!=wallet.port:
|
if host!= wallet.interface.host or port!=wallet.interface.port:
|
||||||
wallet.host = host
|
wallet.interface.host = host
|
||||||
wallet.port = port
|
wallet.interface.set_port( port )
|
||||||
wallet.save()
|
wallet.save()
|
||||||
self.is_connected = False
|
self.is_connected = False
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue