def run_electrum_server(rpc, txmonitor, config): logger = logging.getLogger('ELECTRUMPERSONALSERVER') logger.debug("Starting electrum server") hostport = (config.get("electrum-server", "host"), int(config.get("electrum-server", "port"))) ip_whitelist = [] for ip in config.get("electrum-server", "ip_whitelist").split(" "): if ip == "*": #matches everything ip_whitelist.append(ip_network("0.0.0.0/0")) ip_whitelist.append(ip_network("::0/0")) else: ip_whitelist.append(ip_network(ip, strict=False)) poll_interval_listening = int( config.get("bitcoin-rpc", "poll_interval_listening")) poll_interval_connected = int( config.get("bitcoin-rpc", "poll_interval_connected")) certfile, keyfile = get_certs(config) logger.debug('using cert: {}, key: {}'.format(certfile, keyfile)) disable_mempool_fee_histogram = config.getboolean( "electrum-server", "disable_mempool_fee_histogram", fallback=False) broadcast_method = config.get("electrum-server", "broadcast_method", fallback="own-node") tor_host = config.get("electrum-server", "tor_host", fallback="localhost") tor_port = int(config.get("electrum-server", "tor_port", fallback="9050")) tor_hostport = (tor_host, tor_port) protocol = ElectrumProtocol(rpc, txmonitor, logger, broadcast_method, tor_hostport, disable_mempool_fee_histogram) server_sock = create_server_socket(hostport) server_sock.settimeout(poll_interval_listening) accepting_clients = True while True: # main server loop, runs forever sock = None while sock == None: # loop waiting for a successful connection from client try: sock, addr = server_sock.accept() if not accepting_clients: logger.debug("Refusing connection from client because" + " Bitcoin node isnt reachable") raise ConnectionRefusedError() if not any( [ip_address(addr[0]) in ipnet for ipnet in ip_whitelist]): logger.debug(addr[0] + " not in whitelist, closing") raise ConnectionRefusedError() sock = ssl.wrap_socket(sock, server_side=True, certfile=certfile, keyfile=keyfile, ssl_version=ssl.PROTOCOL_SSLv23) except socket.timeout: is_node_reachable = on_heartbeat_listening(txmonitor) accepting_clients = is_node_reachable except (ConnectionRefusedError, ssl.SSLError, IOError): sock.close() sock = None logger.debug('Electrum connected from ' + str(addr[0])) def send_reply_fun(reply): line = json.dumps(reply) sock.sendall(line.encode('utf-8') + b'\n') logger.debug('<= ' + line) protocol.set_send_reply_fun(send_reply_fun) try: sock.settimeout(poll_interval_connected) recv_buffer = bytearray() while True: # loop for replying to client queries try: recv_data = sock.recv(4096) if not recv_data or len(recv_data) == 0: raise EOFError() recv_buffer.extend(recv_data) lb = recv_buffer.find(b'\n') if lb == -1: continue while lb != -1: line = recv_buffer[:lb].rstrip() recv_buffer = recv_buffer[lb + 1:] lb = recv_buffer.find(b'\n') try: line = line.decode("utf-8") query = json.loads(line) except (UnicodeDecodeError, JSONDecodeError) as e: raise IOError(repr(e)) logger.debug("=> " + line) protocol.handle_query(query) except socket.timeout: on_heartbeat_connected(rpc, txmonitor, protocol) except JsonRpcError as e: logger.debug("Error with node connection, e = " + repr(e) + "\ntraceback = " + str(traceback.format_exc())) accepting_clients = False except UnknownScripthashError as e: logger.debug("Disconnecting client due to misconfiguration. User" + " must correctly configure master public key(s)") except (IOError, EOFError) as e: if isinstance(e, (EOFError, ConnectionRefusedError)): logger.debug("Electrum wallet disconnected") else: logger.debug("IOError: " + repr(e)) try: if sock != None: sock.close() except IOError: pass protocol.on_disconnect() time.sleep(0.2)
def run_electrum_server(rpc, txmonitor, config): logger = logging.getLogger('ELECTRUMPERSONALSERVER') logger.info("Starting electrum server") hostport = (config.get("electrum-server", "host"), int(config.get("electrum-server", "port"))) ip_whitelist = [] for ip in config.get("electrum-server", "ip_whitelist").split(" "): if ip == "*": #matches everything ip_whitelist.append(ip_network("0.0.0.0/0")) ip_whitelist.append(ip_network("::0/0")) else: ip_whitelist.append(ip_network(ip, strict=False)) poll_interval_listening = int(config.get("bitcoin-rpc", "poll_interval_listening")) poll_interval_connected = int(config.get("bitcoin-rpc", "poll_interval_connected")) certfile, keyfile = get_certs(config) disable_mempool_fee_histogram = config.getboolean("electrum-server", "disable_mempool_fee_histogram", fallback=False) broadcast_method = config.get("electrum-server", "broadcast_method", fallback="own-node") tor_host = config.get("electrum-server", "tor_host", fallback="localhost") tor_port = int(config.get("electrum-server", "tor_port", fallback="9050")) tor_hostport = (tor_host, tor_port) protocol = ElectrumProtocol(rpc, txmonitor, logger, broadcast_method, tor_hostport, disable_mempool_fee_histogram) server_sock = create_server_socket(hostport) server_sock.settimeout(poll_interval_listening) while True: try: sock = None while sock == None: try: sock, addr = server_sock.accept() if not any([ip_address(addr[0]) in ipnet for ipnet in ip_whitelist]): logger.debug(addr[0] + " not in whitelist, closing") raise ConnectionRefusedError() sock = ssl.wrap_socket(sock, server_side=True, certfile=certfile, keyfile=keyfile, ssl_version=ssl.PROTOCOL_SSLv23) except socket.timeout: on_heartbeat_listening(txmonitor) except (ConnectionRefusedError, ssl.SSLError): sock.close() sock = None logger.info('Electrum connected from ' + str(addr[0])) protocol.set_send_line_fun(lambda l: sock.sendall(l + b'\n')) sock.settimeout(poll_interval_connected) recv_buffer = bytearray() while True: try: recv_data = sock.recv(4096) if not recv_data or len(recv_data) == 0: raise EOFError() recv_buffer.extend(recv_data) lb = recv_buffer.find(b'\n') if lb == -1: continue while lb != -1: line = recv_buffer[:lb].rstrip() recv_buffer = recv_buffer[lb + 1:] lb = recv_buffer.find(b'\n') protocol.handle_query(line.decode("utf-8")) except socket.timeout: on_heartbeat_connected(rpc, txmonitor, protocol) except (IOError, EOFError) as e: if isinstance(e, (EOFError, ConnectionRefusedError)): logger.info("Electrum wallet disconnected") else: logger.error("IOError: " + repr(e)) try: if sock != None: sock.close() except IOError: pass sock = None protocol.on_disconnect() time.sleep(0.2)