Merge the network and network_proxy

This commit is contained in:
Neil Booth 2015-08-30 21:18:10 +09:00
parent 4d6a0f29ee
commit 2d05e7d891
14 changed files with 158 additions and 319 deletions

View File

@ -77,7 +77,7 @@ if is_bundle or is_local or is_android:
from electrum import util
from electrum import SimpleConfig, Network, Wallet, WalletStorage, NetworkProxy
from electrum import SimpleConfig, Network, Wallet, WalletStorage
from electrum.util import print_msg, print_error, print_stderr, print_json, set_verbosity, InvalidPassword
from electrum.plugins import init_plugins, run_hook, always_hook
from electrum.commands import get_parser, known_commands, Commands, config_variables
@ -97,12 +97,12 @@ def prompt_password(prompt, confirm=True):
def init_gui(config, network_proxy):
def init_gui(config, network):
gui_name = config.get('gui', 'qt')
if gui_name in ['lite', 'classic']:
gui_name = 'qt'
gui = __import__('electrum_gui.' + gui_name, fromlist=['electrum_gui'])
gui = gui.ElectrumGui(config, network_proxy)
gui = gui.ElectrumGui(config, network)
return gui
@ -157,8 +157,7 @@ def init_cmdline(config):
wallet = Wallet.from_seed(seed, password, storage)
if not config.get('offline'):
s = get_daemon(config, False)
network = NetworkProxy(s, config)
network = Network(config)
network.start()
wallet.start_threads(network)
print_msg("Recovering wallet...")
@ -326,19 +325,18 @@ class ClientThread(util.DaemonThread):
# send response and exit
self.client_pipe.send(response)
self.server.remove_client(self)
class NetworkServer(util.DaemonThread):
def __init__(self, config, network_proxy):
def __init__(self, config, network):
util.DaemonThread.__init__(self)
self.debug = False
self.config = config
self.pipe = util.QueuePipe()
self.network_proxy = network_proxy
self.network = self.network_proxy.network
self.network = network
self.lock = threading.RLock()
# each GUI is a client of the daemon
self.clients = []
@ -516,11 +514,11 @@ if __name__ == '__main__':
# daemon is not running
if cmd_name == 'gui':
network_proxy = NetworkProxy(None, config)
network_proxy.start()
server = NetworkServer(config, network_proxy)
network = Network(config)
network.start()
server = NetworkServer(config, network)
server.start()
server.gui = init_gui(config, network_proxy)
server.gui = init_gui(config, network)
server.gui.main()
elif cmd_name == 'daemon':
subcommand = config.get('subcommand')
@ -530,9 +528,9 @@ if __name__ == '__main__':
elif subcommand == 'start':
p = os.fork()
if p == 0:
network_proxy = NetworkProxy(None, config)
network_proxy.start()
server = NetworkServer(config, network_proxy)
network = Network(config)
network.start()
server = NetworkServer(config, network)
if config.get('websocket_server'):
import websockets
websockets.WebSocketServer(config, server).start()

View File

@ -2357,7 +2357,7 @@ class ElectrumWindow(QMainWindow):
txid, ok = QInputDialog.getText(self, _('Lookup transaction'), _('Transaction ID') + ':')
if ok and txid:
try:
r = self.network.synchronous_get([('blockchain.transaction.get',[str(txid)])])[0]
r = self.network.synchronous_get(('blockchain.transaction.get',[str(txid)]))
except BaseException as e:
self.show_message(str(e))
return

View File

@ -11,4 +11,3 @@ import transaction
from transaction import Transaction
from plugins import BasePlugin
from commands import Commands, known_commands
from network_proxy import NetworkProxy

View File

@ -148,7 +148,7 @@ class Commands:
"""Return the transaction history of any address. Note: This is a
walletless server query, results are not checked by SPV.
"""
return self.network.synchronous_get([('blockchain.address.get_history', [address])])[0]
return self.network.synchronous_get(('blockchain.address.get_history', [address]))
@command('nw')
def listunspent(self):
@ -165,16 +165,15 @@ class Commands:
"""Returns the UTXO list of any address. Note: This
is a walletless server query, results are not checked by SPV.
"""
return self.network.synchronous_get([('blockchain.address.listunspent', [address])])[0]
return self.network.synchronous_get(('blockchain.address.listunspent', [address]))
@command('n')
def getutxoaddress(self, txid, pos):
"""Get the address of a UTXO. Note: This is a walletless server query, results are
not checked by SPV.
"""
r = self.network.synchronous_get([('blockchain.utxo.get_address', [txid, pos])])
if r:
return {'address':r[0]}
r = self.network.synchronous_get(('blockchain.utxo.get_address', [txid, pos]))
return {'address': r}
@command('wp')
def createrawtx(self, inputs, outputs, unsigned=False):
@ -219,7 +218,7 @@ class Commands:
def broadcast(self, tx):
"""Broadcast a transaction to the network. """
t = Transaction(tx)
return self.network.synchronous_get([('blockchain.transaction.broadcast', [str(t)])])[0]
return self.network.synchronous_get(('blockchain.transaction.broadcast', [str(t)]))
@command('')
def createmultisig(self, num, pubkeys):
@ -287,7 +286,7 @@ class Commands:
"""Return the balance of any address. Note: This is a walletless
server query, results are not checked by SPV.
"""
out = self.network.synchronous_get([('blockchain.address.get_balance', [address])])[0]
out = self.network.synchronous_get(('blockchain.address.get_balance', [address]))
out["confirmed"] = str(Decimal(out["confirmed"])/COIN)
out["unconfirmed"] = str(Decimal(out["unconfirmed"])/COIN)
return out
@ -295,7 +294,7 @@ class Commands:
@command('n')
def getproof(self, address):
"""Get Merkle branch of an address in the UTXO set"""
p = self.network.synchronous_get([('blockchain.address.get_proof', [address])])[0]
p = self.network.synchronous_get(('blockchain.address.get_proof', [address]))
out = []
for i,s in p:
out.append(i)
@ -305,7 +304,7 @@ class Commands:
def getmerkle(self, txid, height):
"""Get Merkle branch of a transaction included in a block. Electrum
uses this to verify transactions (Simple Payment Verification)."""
return self.network.synchronous_get([('blockchain.transaction.get_merkle', [txid, int(height)])])[0]
return self.network.synchronous_get(('blockchain.transaction.get_merkle', [txid, int(height)]))
@command('n')
def getservers(self):
@ -522,7 +521,7 @@ class Commands:
"""Retrieve a transaction. """
tx = self.wallet.transactions.get(txid) if self.wallet else None
if tx is None and self.network:
raw = self.network.synchronous_get([('blockchain.transaction.get', [txid])])[0]
raw = self.network.synchronous_get(('blockchain.transaction.get', [txid]))
if raw:
tx = Transaction(raw)
else:

View File

@ -5,7 +5,8 @@ import sys
import random
import select
import traceback
from collections import deque
from collections import defaultdict, deque
from threading import Lock
import socks
import socket
@ -129,20 +130,19 @@ class Network(util.DaemonThread):
Our external API:
- Member functions get_header(), get_parameters(), get_status_value(),
new_blockchain_height(), set_parameters(), start(),
stop()
- Member functions get_header(), get_interfaces(), get_local_height(),
get_parameters(), get_server_height(), get_status_value(),
is_connected(), new_blockchain_height(), set_parameters(), start(),
stop()
"""
def __init__(self, pipe, config=None):
def __init__(self, config=None):
if config is None:
config = {} # Do not use mutables as default values!
util.DaemonThread.__init__(self)
self.config = SimpleConfig(config) if type(config) == type({}) else config
self.num_server = 8 if not self.config.get('oneserver') else 0
self.blockchain = Blockchain(self.config, self)
self.requests_queue = pipe.send_queue
self.response_queue = pipe.get_queue
# A deque of interface header requests, processed left-to-right
self.bc_requests = deque()
# Server for addresses and transactions
@ -155,6 +155,10 @@ class Network(util.DaemonThread):
if not self.default_server:
self.default_server = pick_random_server()
self.lock = Lock()
self.pending_sends = []
self.message_id = 0
self.debug = False
self.irc_servers = {} # returned by interface (list from irc)
self.recent_servers = self.read_recent_servers()
@ -163,6 +167,8 @@ class Network(util.DaemonThread):
self.heights = {}
self.merkle_roots = {}
self.utxo_roots = {}
self.subscriptions = defaultdict(list)
self.callbacks = defaultdict(list)
dir_path = os.path.join( self.config.path, 'certs')
if not os.path.exists(dir_path):
@ -188,6 +194,15 @@ class Network(util.DaemonThread):
self.start_network(deserialize_server(self.default_server)[2],
deserialize_proxy(self.config.get('proxy')))
def register_callback(self, event, callback):
with self.lock:
self.callbacks[event].append(callback)
def trigger_callback(self, event, params=()):
with self.lock:
callbacks = self.callbacks[event][:]
[callback(*params) for callback in callbacks]
def read_recent_servers(self):
if not self.config.path:
return []
@ -231,6 +246,12 @@ class Network(util.DaemonThread):
def is_connected(self):
return self.interface is not None
def is_connecting(self):
return self.connection_status == 'connecting'
def is_up_to_date(self):
return self.unanswered_requests == {}
def queue_request(self, method, params):
self.interface.queue_request({'method': method, 'params': params})
@ -263,7 +284,10 @@ class Network(util.DaemonThread):
def notify(self, key):
value = self.get_status_value(key)
self.response_queue.put({'method':'network.status', 'params':[key, value]})
if key in ['status', 'updated']:
self.trigger_callback(key)
else:
self.trigger_callback(key, (value,))
def get_parameters(self):
host, port, protocol = deserialize_server(self.default_server)
@ -337,8 +361,16 @@ class Network(util.DaemonThread):
self.socket_queue = Queue.Queue()
def set_parameters(self, host, port, protocol, proxy, auto_connect):
self.auto_connect = auto_connect
proxy_str = serialize_proxy(proxy)
server = serialize_server(host, port, protocol)
self.config.set_key('auto_connect', auto_connect, False)
self.config.set_key("proxy", proxy_str, False)
self.config.set_key("server", server, True)
# abort if changes were not allowed by config
if self.config.get('server') != server_str or self.config.get('proxy') != proxy_str:
return
self.auto_connect = auto_connect
if self.proxy != proxy or self.protocol != protocol:
# Restart the network defaulting to the given server
self.stop_network()
@ -405,7 +437,9 @@ class Network(util.DaemonThread):
self.switch_lagging_interface(i.server)
self.notify('updated')
def process_response(self, interface, response):
def process_response(self, interface, response, callback):
if self.debug:
self.print_error("<--", response)
error = response.get('error')
result = response.get('result')
method = response.get('method')
@ -437,8 +471,19 @@ class Network(util.DaemonThread):
# Cache address subscription results
if method == 'blockchain.address.subscribe' and error is None:
addr = response['params'][0]
self.addr_responses[addr] = result
self.response_queue.put(response)
self.addr_responses[addr] = response
if callback is None:
params = response['params']
with self.lock:
for k,v in self.subscriptions.items():
if (method, params) in v:
callback = k
break
if callback is None:
self.print_error("received unexpected notification",
method, params)
else:
callback(response)
def process_responses(self, interface):
notifications, responses = interface.get_responses()
@ -449,12 +494,14 @@ class Network(util.DaemonThread):
if client_id is not None:
if interface != self.interface:
continue
self.unanswered_requests.pop(client_id)
_req, callback = self.unanswered_requests.pop(client_id)
else:
callback = None
# Copy the request method and params to the response
response['method'] = request.get('method')
response['params'] = request.get('params')
response['id'] = client_id
self.process_response(interface, response)
self.process_response(interface, response, callback)
for response in notifications:
if not response: # Closed remotely
@ -466,16 +513,42 @@ class Network(util.DaemonThread):
response['result'] = response['params'][0]
response['params'] = []
elif method == 'blockchain.address.subscribe':
params = response['params']
response['params'] = [params[0]] # addr
response['result'] = params[1]
self.process_response(interface, response)
self.process_response(interface, response, None)
def handle_incoming_requests(self):
while not self.requests_queue.empty():
self.process_request(self.requests_queue.get())
def send(self, messages, callback):
'''Messages is a list of (method, value) tuples'''
with self.lock:
self.pending_sends.append((messages, callback))
def process_request(self, request):
def process_pending_sends(self):
sends = self.pending_sends
self.pending_sends = []
for messages, callback in sends:
subs = filter(lambda (m,v): m.endswith('.subscribe'), messages)
with self.lock:
for sub in subs:
if sub not in self.subscriptions[callback]:
self.subscriptions[callback].append(sub)
_id = self.message_id
self.message_id += len(messages)
unsent = []
for message in messages:
method, params = message
request = {'id': _id, 'method': method, 'params': params}
if not self.process_request(request, callback):
unsent.append(message)
_id += 1
if unsent:
with self.lock:
self.pending_sends.append((unsent, callback))
# FIXME: inline this function
def process_request(self, request, callback):
'''Returns true if the request was processed.'''
method = request['method']
params = request['params']
@ -492,14 +565,14 @@ class Network(util.DaemonThread):
out['error'] = str(e)
traceback.print_exc(file=sys.stdout)
self.print_error("network error", str(e))
self.response_queue.put(out)
callback(out)
return True
if method == 'blockchain.address.subscribe':
addr = params[0]
self.subscribed_addresses.add(addr)
if addr in self.addr_responses:
self.response_queue.put({'id':_id, 'result':self.addr_responses[addr]})
callback(self.addr_responses[addr])
return True
# This request needs connectivity. If we don't have an
@ -507,7 +580,9 @@ class Network(util.DaemonThread):
if not self.interface:
return False
self.unanswered_requests[_id] = request
if self.debug:
self.print_error("-->", request)
self.unanswered_requests[_id] = request, callback
self.interface.queue_request(request)
return True
@ -679,10 +754,12 @@ class Network(util.DaemonThread):
while self.is_running():
self.maintain_sockets()
self.wait_on_sockets()
self.handle_incoming_requests()
self.handle_bc_requests()
self.run_jobs() # Synchronizer and Verifier
self.process_pending_sends()
self.stop_network()
self.trigger_callback('stop')
self.print_error("stopped")
def on_header(self, i, header):
@ -706,3 +783,11 @@ class Network(util.DaemonThread):
def get_local_height(self):
return self.blockchain.height()
def synchronous_get(self, request, timeout=100000000):
queue = Queue.Queue()
self.send([request], queue.put)
r = queue.get(True, timeout)
if r.get('error'):
raise BaseException(r.get('error'))
return r.get('result')

View File

@ -1,235 +0,0 @@
#!/usr/bin/env python
#
# Electrum - lightweight Bitcoin client
# Copyright (C) 2014 Thomas Voegtlin
#
# 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 sys
import traceback
import threading
import Queue
import util
from network import Network, serialize_proxy, serialize_server
from simple_config import SimpleConfig
class NetworkProxy(util.DaemonThread):
def __init__(self, socket, config=None):
if config is None:
config = {} # Do not use mutables as default arguments!
util.DaemonThread.__init__(self)
self.config = SimpleConfig(config) if type(config) == type({}) else config
self.message_id = 0
self.unanswered_requests = {}
self.subscriptions = {}
self.debug = False
self.lock = threading.Lock()
self.callbacks = {}
if socket:
self.pipe = util.SocketPipe(socket)
self.network = None
else:
self.pipe = util.QueuePipe()
self.network = Network(self.pipe, config)
self.network.start()
for key in ['fee','status','banner','updated','servers','interfaces']:
value = self.network.get_status_value(key)
self.pipe.get_queue.put({'method':'network.status', 'params':[key, value]})
# status variables
self.status = 'unknown'
self.servers = {}
self.banner = ''
self.blockchain_height = 0
self.server_height = 0
self.interfaces = []
# value returned by estimatefee
self.fee = None
def run(self):
while self.is_running():
self.run_jobs() # Synchronizer and Verifier
try:
response = self.pipe.get()
except util.timeout:
continue
if response is None:
break
# Protect against ill-formed or malicious server responses
try:
self.process(response)
except:
traceback.print_exc(file=sys.stderr)
self.trigger_callback('stop')
if self.network:
self.network.stop()
self.print_error("stopped")
def process(self, response):
if self.debug:
self.print_error("<--", response)
if response.get('method') == 'network.status':
key, value = response.get('params')
if key == 'status':
self.status = value
elif key == 'banner':
self.banner = value
elif key == 'fee':
self.fee = value
elif key == 'updated':
self.blockchain_height, self.server_height = value
elif key == 'servers':
self.servers = value
elif key == 'interfaces':
self.interfaces = value
if key in ['status', 'updated']:
self.trigger_callback(key)
else:
self.trigger_callback(key, (value,))
return
msg_id = response.get('id')
result = response.get('result')
error = response.get('error')
if msg_id is not None:
with self.lock:
method, params, callback = self.unanswered_requests.pop(msg_id)
else:
method = response.get('method')
params = response.get('params')
with self.lock:
for k,v in self.subscriptions.items():
if (method, params) in v:
callback = k
break
else:
self.print_error("received unexpected notification",
method, params)
return
r = {'method':method, 'params':params, 'result':result,
'id':msg_id, 'error':error}
callback(r)
def send(self, messages, callback):
"""return the ids of the requests that we sent"""
# detect subscriptions
sub = []
for message in messages:
m, v = message
if m[-10:] == '.subscribe':
sub.append(message)
if sub:
with self.lock:
if self.subscriptions.get(callback) is None:
self.subscriptions[callback] = []
for message in sub:
if message not in self.subscriptions[callback]:
self.subscriptions[callback].append(message)
with self.lock:
requests = []
ids = []
for m in messages:
method, params = m
request = { 'id':self.message_id, 'method':method, 'params':params }
self.unanswered_requests[self.message_id] = method, params, callback
ids.append(self.message_id)
requests.append(request)
if self.debug:
self.print_error("-->", request)
self.message_id += 1
self.pipe.send_all(requests)
return ids
def synchronous_get(self, requests, timeout=100000000):
queue = Queue.Queue()
ids = self.send(requests, queue.put)
id2 = ids[:]
res = {}
while ids:
r = queue.get(True, timeout)
_id = r.get('id')
ids.remove(_id)
if r.get('error'):
raise BaseException(r.get('error'))
result = r.get('result')
res[_id] = r.get('result')
out = []
for _id in id2:
out.append(res[_id])
return out
def get_servers(self):
return self.servers
def get_interfaces(self):
return self.interfaces
def get_local_height(self):
return self.blockchain_height
def get_server_height(self):
return self.server_height
def is_connected(self):
return self.status == 'connected'
def is_connecting(self):
return self.status == 'connecting'
def is_up_to_date(self):
return self.unanswered_requests == {}
def get_parameters(self):
return self.synchronous_get([('network.get_parameters', [])])[0]
def set_parameters(self, host, port, protocol, proxy, auto_connect):
proxy_str = serialize_proxy(proxy)
server_str = serialize_server(host, port, protocol)
self.config.set_key('auto_connect', auto_connect, False)
self.config.set_key("proxy", proxy_str, False)
self.config.set_key("server", server_str, True)
# abort if changes were not allowed by config
if self.config.get('server') != server_str or self.config.get('proxy') != proxy_str:
return
return self.synchronous_get([('network.set_parameters', (host, port, protocol, proxy, auto_connect))])[0]
def stop_daemon(self):
return self.send([('daemon.stop',[])], None)
def register_callback(self, event, callback):
with self.lock:
if not self.callbacks.get(event):
self.callbacks[event] = []
self.callbacks[event].append(callback)
def trigger_callback(self, event, params=()):
with self.lock:
callbacks = self.callbacks.get(event,[])[:]
if callbacks:
[callback(*params) for callback in callbacks]

View File

@ -545,7 +545,7 @@ class Transaction:
for privkey in privkeys:
pubkey = public_key_from_private_key(privkey)
address = address_from_private_key(privkey)
u = network.synchronous_get([ ('blockchain.address.listunspent',[address])])[0]
u = network.synchronous_get(('blockchain.address.listunspent',[address]))
pay_script = klass.pay_script('address', address)
for item in u:
item['scriptPubKey'] = pay_script

View File

@ -40,9 +40,9 @@ class SPV(ThreadJob):
if tx_hash not in self.merkle_roots and tx_height <= lh:
request = ('blockchain.transaction.get_merkle',
[tx_hash, tx_height])
if self.network.send([request], self.merkle_response):
self.print_error('requested merkle', tx_hash)
self.merkle_roots[tx_hash] = None
self.network.send([request], self.merkle_response)
self.print_error('requested merkle', tx_hash)
self.merkle_roots[tx_hash] = None
def merkle_response(self, r):
if r.get('error'):

View File

@ -156,7 +156,7 @@ class Plugin(BasePlugin):
@hook
def installwizard_restore(self, wizard, storage):
if storage.get('wallet_type') != 'keepkey':
if storage.get('wallet_type') != 'keepkey':
return
seed = wizard.enter_seed_dialog("Enter your KeepKey seed", None, func=lambda x:True)
if not seed:
@ -478,7 +478,7 @@ class KeepKeyWallet(BIP32_HD_Wallet):
ptx = self.transactions.get(tx_hash)
if ptx is None:
ptx = self.network.synchronous_get([('blockchain.transaction.get', [tx_hash])])[0]
ptx = self.network.synchronous_get(('blockchain.transaction.get', [tx_hash]))
ptx = Transaction(ptx)
prev_tx[tx_hash] = ptx
@ -673,5 +673,5 @@ if KEEPKEY:
except ConnectionError:
self.bad = True
raise
return resp

View File

@ -156,7 +156,7 @@ class Plugin(BasePlugin):
@hook
def installwizard_restore(self, wizard, storage):
if storage.get('wallet_type') != 'trezor':
if storage.get('wallet_type') != 'trezor':
return
seed = wizard.enter_seed_dialog("Enter your Trezor seed", None, func=lambda x:True)
if not seed:
@ -477,7 +477,7 @@ class TrezorWallet(BIP32_HD_Wallet):
ptx = self.transactions.get(tx_hash)
if ptx is None:
ptx = self.network.synchronous_get([('blockchain.transaction.get', [tx_hash])])[0]
ptx = self.network.synchronous_get(('blockchain.transaction.get', [tx_hash]))
ptx = Transaction(ptx)
prev_tx[tx_hash] = ptx
@ -665,5 +665,5 @@ if TREZOR:
except ConnectionError:
self.bad = True
raise
return resp

View File

@ -7,8 +7,7 @@ import electrum
# start network
c = electrum.SimpleConfig()
s = electrum.daemon.get_daemon(c,True)
network = electrum.NetworkProxy(s,c)
network = electrum.Network(c)
network.start()
# wait until connected
@ -26,4 +25,3 @@ network.send([('blockchain.headers.subscribe',[])], callback)
# 3. wait for results
while network.is_connected():
time.sleep(1)

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python
import sys
from electrum import NetworkProxy, print_json
from electrum import Network, print_json
try:
addr = sys.argv[1]
@ -9,8 +9,7 @@ except Exception:
print "usage: get_history <bitcoin_address>"
sys.exit(1)
n = NetworkProxy()
n.start(start_daemon=True)
h = n.synchronous_get([ ('blockchain.address.get_history',[addr]) ])[0]
n = Network()
n.start()
h = n.synchronous_get(('blockchain.address.get_history',[addr]))
print_json(h)

View File

@ -54,7 +54,7 @@ def check_create_table(conn):
c = conn.cursor()
c.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='electrum_payments';")
data = c.fetchall()
if not data:
if not data:
c.execute("""CREATE TABLE electrum_payments (address VARCHAR(40), amount FLOAT, confirmations INT(8), received_at TIMESTAMP, expires_at TIMESTAMP, paid INT(1), processed INT(1));""")
conn.commit()
@ -95,7 +95,7 @@ def on_wallet_update():
s = (value)/1.e8
print "balance for %s:"%addr, s, requested_amount
if s>= requested_amount:
if s>= requested_amount:
print "payment accepted", addr
out_queue.put( ('payment', addr))
@ -162,7 +162,7 @@ def send_command(cmd, params):
except socket.error:
print "Server not running"
return 1
try:
out = f(*params)
except socket.error:
@ -186,9 +186,9 @@ def db_thread():
data = cur.fetchall()
# add pending requests to the wallet
for item in data:
for item in data:
addr, amount, confirmations = item
if addr in pending_requests:
if addr in pending_requests:
continue
else:
with wallet.lock:
@ -216,7 +216,7 @@ def db_thread():
print sql
cur.execute(sql)
# set paid=0 for expired requests
# set paid=0 for expired requests
cur.execute("""UPDATE electrum_payments set paid=0 WHERE expires_at < CURRENT_TIMESTAMP and paid is NULL;""")
# do callback for addresses that received payment or expired
@ -241,7 +241,7 @@ def db_thread():
except ValueError, e:
print e
print "cannot do callback", data_json
conn.commit()
conn.close()
@ -259,8 +259,7 @@ if __name__ == '__main__':
# start network
c = electrum.SimpleConfig({'wallet_path':wallet_path})
daemon_socket = electrum.daemon.get_daemon(c, True)
network = electrum.NetworkProxy(daemon_socket, config)
network = electrum.Network(config)
network.start()
# wait until connected
@ -284,7 +283,7 @@ if __name__ == '__main__':
network.register_callback('updated', on_wallet_update)
threading.Thread(target=db_thread, args=()).start()
out_queue = Queue.Queue()
# server thread
from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer
@ -299,4 +298,3 @@ if __name__ == '__main__':
server.handle_request()
except socket.timeout:
continue

View File

@ -12,8 +12,7 @@ except Exception:
# start network
c = electrum.SimpleConfig()
s = electrum.daemon.get_daemon(c,True)
network = electrum.NetworkProxy(s,c)
network = electrum.Network(c)
network.start()
# wait until connected
@ -31,4 +30,3 @@ network.send([('blockchain.address.subscribe',[addr])], callback)
# 3. wait for results
while network.is_connected():
time.sleep(1)