URI: 
       tMerge the network and network_proxy - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 2d05e7d891f13dc07dacb57b11a32ff14d3500b4
   DIR parent 4d6a0f29ee99969585294a2a22bc45385659a3c3
  HTML Author: Neil Booth <kyuupichan@gmail.com>
       Date:   Sun, 30 Aug 2015 21:18:10 +0900
       
       Merge the network and network_proxy
       
       Diffstat:
         M electrum                            |      30 ++++++++++++++----------------
         M gui/qt/main_window.py               |       2 +-
         M lib/__init__.py                     |       1 -
         M lib/commands.py                     |      19 +++++++++----------
         M lib/network.py                      |     137 +++++++++++++++++++++++++------
         D lib/network_proxy.py                |     235 -------------------------------
         M lib/transaction.py                  |       2 +-
         M lib/verifier.py                     |       6 +++---
         M plugins/keepkey.py                  |       6 +++---
         M plugins/trezor.py                   |       6 +++---
         M scripts/block_headers               |       4 +---
         M scripts/get_history                 |       9 ++++-----
         M scripts/merchant/merchant.py        |      20 +++++++++-----------
         M scripts/watch_address               |       4 +---
       
       14 files changed, 160 insertions(+), 321 deletions(-)
       ---
   DIR diff --git a/electrum b/electrum
       t@@ -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
       t@@ -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
        
        
       t@@ -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...")
       t@@ -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 = []
       t@@ -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')
       t@@ -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()
   DIR diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
       t@@ -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
   DIR diff --git a/lib/__init__.py b/lib/__init__.py
       t@@ -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
   DIR diff --git a/lib/commands.py b/lib/commands.py
       t@@ -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):
       t@@ -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):
       t@@ -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):
       t@@ -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
       t@@ -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)
       t@@ -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):
       t@@ -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:
   DIR diff --git a/lib/network.py b/lib/network.py
       t@@ -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
       t@@ -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
       t@@ -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()
        
       t@@ -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):
       t@@ -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 []
       t@@ -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})
        
       t@@ -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)
       t@@ -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()
       t@@ -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')
       t@@ -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()
       t@@ -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
       t@@ -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']
       t@@ -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
       t@@ -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
        
       t@@ -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):
       t@@ -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')
   DIR diff --git a/lib/network_proxy.py b/lib/network_proxy.py
       t@@ -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]
   DIR diff --git a/lib/transaction.py b/lib/transaction.py
       t@@ -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
   DIR diff --git a/lib/verifier.py b/lib/verifier.py
       t@@ -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'):
   DIR diff --git a/plugins/keepkey.py b/plugins/keepkey.py
       t@@ -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:
       t@@ -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
        
       t@@ -673,5 +673,5 @@ if KEEPKEY:
                    except ConnectionError:
                        self.bad = True
                        raise
       -    
       +
                    return resp
   DIR diff --git a/plugins/trezor.py b/plugins/trezor.py
       t@@ -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:
       t@@ -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
        
       t@@ -665,5 +665,5 @@ if TREZOR:
                    except ConnectionError:
                        self.bad = True
                        raise
       -    
       +
                    return resp
   DIR diff --git a/scripts/block_headers b/scripts/block_headers
       t@@ -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
       t@@ -26,4 +25,3 @@ network.send([('blockchain.headers.subscribe',[])], callback)
        # 3. wait for results
        while network.is_connected():
            time.sleep(1)
       -
   DIR diff --git a/scripts/get_history b/scripts/get_history
       t@@ -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]
       t@@ -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)
       -
   DIR diff --git a/scripts/merchant/merchant.py b/scripts/merchant/merchant.py
       t@@ -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()
        
       t@@ -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))
        
       t@@ -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:
       t@@ -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:
       t@@ -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
       t@@ -241,7 +241,7 @@ def db_thread():
                    except ValueError, e:
                        print e
                        print "cannot do callback", data_json
       -        
       +
                conn.commit()
        
            conn.close()
       t@@ -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
       t@@ -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
       t@@ -299,4 +298,3 @@ if __name__ == '__main__':
                    server.handle_request()
                except socket.timeout:
                    continue
       -
   DIR diff --git a/scripts/watch_address b/scripts/watch_address
       t@@ -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
       t@@ -31,4 +30,3 @@ network.send([('blockchain.address.subscribe',[addr])], callback)
        # 3. wait for results
        while network.is_connected():
            time.sleep(1)
       -