electrum

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

commit 2d05e7d891f13dc07dacb57b11a32ff14d3500b4
parent 4d6a0f29ee99969585294a2a22bc45385659a3c3
Author: Neil Booth <kyuupichan@gmail.com>
Date:   Sun, 30 Aug 2015 21:18:10 +0900

Merge the network and network_proxy

Diffstat:
Melectrum | 30++++++++++++++----------------
Mgui/qt/main_window.py | 2+-
Mlib/__init__.py | 1-
Mlib/commands.py | 19+++++++++----------
Mlib/network.py | 137++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Dlib/network_proxy.py | 235-------------------------------------------------------------------------------
Mlib/transaction.py | 2+-
Mlib/verifier.py | 6+++---
Mplugins/keepkey.py | 6+++---
Mplugins/trezor.py | 6+++---
Mscripts/block_headers | 4+---
Mscripts/get_history | 9++++-----
Mscripts/merchant/merchant.py | 20+++++++++-----------
Mscripts/watch_address | 4+---
14 files changed, 160 insertions(+), 321 deletions(-)

diff --git a/electrum b/electrum @@ -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() diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py @@ -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 diff --git a/lib/__init__.py b/lib/__init__.py @@ -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 diff --git a/lib/commands.py b/lib/commands.py @@ -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: diff --git a/lib/network.py b/lib/network.py @@ -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) - - def handle_incoming_requests(self): - while not self.requests_queue.empty(): - self.process_request(self.requests_queue.get()) - - def process_request(self, request): + self.process_response(interface, response, None) + + def send(self, messages, callback): + '''Messages is a list of (method, value) tuples''' + with self.lock: + self.pending_sends.append((messages, callback)) + + 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') diff --git a/lib/network_proxy.py b/lib/network_proxy.py @@ -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] diff --git a/lib/transaction.py b/lib/transaction.py @@ -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 diff --git a/lib/verifier.py b/lib/verifier.py @@ -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'): diff --git a/plugins/keepkey.py b/plugins/keepkey.py @@ -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 diff --git a/plugins/trezor.py b/plugins/trezor.py @@ -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 diff --git a/scripts/block_headers b/scripts/block_headers @@ -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) - diff --git a/scripts/get_history b/scripts/get_history @@ -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) - diff --git a/scripts/merchant/merchant.py b/scripts/merchant/merchant.py @@ -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 - diff --git a/scripts/watch_address b/scripts/watch_address @@ -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) -