Merge the network and network_proxy
This commit is contained in:
parent
4d6a0f29ee
commit
2d05e7d891
28
electrum
28
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...")
|
||||
|
@ -332,13 +331,12 @@ class ClientThread(util.DaemonThread):
|
|||
|
||||
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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
131
lib/network.py
131
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(),
|
||||
- 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')
|
||||
|
|
|
@ -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]
|
|
@ -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
|
||||
|
|
|
@ -40,7 +40,7 @@ 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.network.send([request], self.merkle_response)
|
||||
self.print_error('requested merkle', tx_hash)
|
||||
self.merkle_roots[tx_hash] = None
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -299,4 +298,3 @@ if __name__ == '__main__':
|
|||
server.handle_request()
|
||||
except socket.timeout:
|
||||
continue
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue