async def send_request(network: Network, servers: List[str], method: str, params: Sequence): print(f"contacting {len(servers)} servers") num_connecting = len(network.connecting) for server in servers: network._start_interface(server) # sleep a bit for _ in range(10): if len(network.connecting) < num_connecting: break await asyncio.sleep(1) print( f"connected to {len(network.interfaces)} servers. sending request to all." ) responses = dict() async def get_response(iface: Interface): try: res = await iface.session.send_request(method, params, timeout=10) except Exception as e: print(f"server {iface.server} errored or timed out: ({repr(e)})") res = e responses[iface.server] = res async with TaskGroup() as group: for interface in network.interfaces.values(): await group.spawn(get_response(interface)) print("%d answers" % len(responses)) return responses
def send_request(self, method, relative_url, data=None): network = Network.get_instance() if not network: raise ErrorConnectingServer('You are offline.') url = urljoin(self.base_url, relative_url) if self.debug: self.print_error(f'<-- {method} {url} {data}') headers = {} if self.user_agent: headers['user-agent'] = self.user_agent try: if method == 'get': response = Network.send_http_on_proxy( method, url, params=data, headers=headers, on_finish=self.handle_response) elif method == 'post': response = Network.send_http_on_proxy( method, url, json=data, headers=headers, on_finish=self.handle_response) else: assert False except TrustedCoinException: raise except Exception as e: raise ErrorConnectingServer(e) else: if self.debug: self.print_error(f'--> {response}') return response
class FakeDaemon: def __init__(self, nursery, config): self.network = Network(nursery, config) self.network.start() self.fx = FxThread(config, self.network) self.wallets = {} def load_wallet(self, path, password): # wizard will be launched if we return if path in self.wallets: wallet = self.wallets[path] return wallet storage = WalletStorage(path, manual_upgrades=True) if not storage.file_exists(): return if storage.is_encrypted(): if not password: return storage.decrypt(password) if storage.requires_split(): return if storage.get_action(): return wallet = Wallet(storage) wallet.start_threads(self.network) self.wallets[path] = wallet return wallet def stop_wallet(self, path): pass
def send_request(self, method, relative_url, data=None): network = Network.get_instance() if not network: raise ErrorConnectingServer('You are offline.') url = urljoin(self.base_url, relative_url) if self.debug: self.print_error(f'<-- {method} {url} {data}') headers = {} if self.user_agent: headers['user-agent'] = self.user_agent try: if method == 'get': response = Network.send_http_on_proxy(method, url, params=data, headers=headers, on_finish=self.handle_response) elif method == 'post': response = Network.send_http_on_proxy(method, url, json=data, headers=headers, on_finish=self.handle_response) else: assert False except TrustedCoinException: raise except Exception as e: raise ErrorConnectingServer(e) else: if self.debug: self.print_error(f'--> {response}') return response
def __init__(self, name, config): """ Initializes new electrum wallet instance @param name: Name of the wallet @param config: Configuration dictionary e.g { 'server': 'localhost:7777:s', 'rpc_user': '******', 'rpc_pass_': 'pass', 'electrum_path': '/opt/var/data/electrum', 'seed': '....', 'fee': 10000, 'testnet': 1 } """ self._name = name self._config = config self._config['testnet'] = bool(self._config['testnet']) if self._config['testnet'] is True: constants.set_testnet() self._config['verbos'] = False self._electrum_config = SimpleConfig(self._config) self._wallet_path = os.path.join(self._electrum_config.path, 'wallets', self._name) self._storage = WalletStorage(path=self._wallet_path) if not self._storage.file_exists(): self._electrum_config.set_key('default_wallet_path', self._wallet_path) k = keystore.from_seed(self._config['seed'], self._config['passphrase'], False) k.update_password(None, self._config['password']) self._storage.put('keystore', k.dump()) self._storage.put('wallet_type', 'standard') self._storage.put('use_encryption', bool(self._config['password'])) self._storage.write() self._wallet = Wallet(self._storage) # self._server = daemon.get_server(self._electrum_config) self._network = Network(self._electrum_config) self._network.start() self._wallet.start_threads(self._network) self._wallet.synchronize() self._wallet.wait_until_synchronized() self._wallet.stop_threads() self._wallet.storage.write() else: self._network = None self._wallet = self._wallet = Wallet(self._storage) self._commands = Commands(config=self._electrum_config, wallet=self._wallet, network=self._network) self._init_commands()
def __init__(self, parent: QWidget, get_account_xpub, on_account_select): self.get_account_xpub = get_account_xpub self.on_account_select = on_account_select WindowModalDialog.__init__(self, parent, _('BIP39 Recovery')) self.setMinimumWidth(400) vbox = QVBoxLayout(self) self.content = QVBoxLayout() self.content.addWidget( QLabel(_('Scanning common paths for existing accounts...'))) vbox.addLayout(self.content) self.thread = TaskThread(self) self.thread.finished.connect(self.deleteLater) # see #3956 network = Network.get_instance() coro = account_discovery(network, self.get_account_xpub) fut = asyncio.run_coroutine_threadsafe(coro, network.asyncio_loop) self.thread.add( fut.result, on_success=self.on_recovery_success, on_error=self.on_recovery_error, cancel=fut.cancel, ) self.ok_button = OkButton(self) self.ok_button.clicked.connect(self.on_ok_button_click) self.ok_button.setEnabled(False) cancel_button = CancelButton(self) cancel_button.clicked.connect(fut.cancel) vbox.addLayout(Buttons(cancel_button, self.ok_button)) self.finished.connect(self.on_finished) self.show()
def _lnurl_get_invoice(self) -> None: assert self.lnurl_data try: amount = self.app.get_amount(self.amount) except: self.app.show_error(_('Invalid amount') + ':\n' + self.amount) return if not (self.lnurl_data.min_sendable_sat <= amount <= self.lnurl_data.max_sendable_sat): self.app.show_error( f'Amount must be between {self.lnurl_data.min_sendable_sat} and {self.lnurl_data.max_sendable_sat} sat.' ) return try: # FIXME network request blocking GUI thread: invoice_data = Network.run_from_another_thread( callback_lnurl( self.lnurl_data.callback_url, params={'amount': amount * 1000}, )) except LNURLError as e: self.app.show_error(f"LNURL request encountered error: {e}") self.do_clear() return invoice = invoice_data.get('pr') self.set_bolt11(invoice) self.lnurl_data = None self.is_lnurl = False
def do_verify(self, d): tx = d.tx wallet = d.wallet window = d.main_window if wallet.is_watching_only(): d.show_critical( _('This feature is not available for watch-only wallets.')) return # 1. get the password and sign the verification request password = None if wallet.has_keystore_encryption(): msg = _('GreenAddress requires your signature \n' 'to verify that transaction is instant.\n' 'Please enter your password to sign a\n' 'verification request.') password = window.password_dialog(msg, parent=d) if not password: return try: d.verify_button.setText(_('Verifying...')) QApplication.processEvents() # update the button label addr = self.get_my_addr(d) message = "Please verify if %s is GreenAddress instant confirmed" % tx.txid( ) sig = wallet.sign_message(addr, message, password) sig = base64.b64encode(sig).decode('ascii') # 2. send the request async def handle_request(resp: 'ClientResponse'): resp.raise_for_status() return await resp.json() url = "https://greenaddress.it/verify/?signature=%s&txhash=%s" % ( urllib.parse.quote(sig), tx.txid()) response = Network.send_http_on_proxy( 'get', url, headers={'User-Agent': 'Electrum'}, on_finish=handle_request) # 3. display the result if response.get('verified'): d.show_message( _('{} is covered by GreenAddress instant confirmation' ).format(tx.txid()), title=_('Verification successful!')) else: d.show_warning( _('{} is not covered by GreenAddress instant confirmation' ).format(tx.txid()), title=_('Verification failed!')) except BaseException as e: import traceback traceback.print_exc(file=sys.stdout) d.show_error(str(e)) finally: d.verify_button.setText(self.button_label)
def update(self, network: Network): self.clear() self.addChild = self.addTopLevelItem chains = network.get_blockchains() n_chains = len(chains) for chain_id, interfaces in chains.items(): b = blockchain.blockchains.get(chain_id) if b is None: continue name = b.get_name() if n_chains > 1: x = QTreeWidgetItem([name + '@%d'%b.get_max_forkpoint(), '%d'%b.height()]) x.setData(0, Qt.UserRole, 1) x.setData(1, Qt.UserRole, b.get_id()) else: x = self for i in interfaces: star = ' *' if i == network.interface else '' item = QTreeWidgetItem([i.host + star, '%d'%i.tip]) item.setData(0, Qt.UserRole, 0) item.setData(1, Qt.UserRole, i.server) x.addChild(item) if n_chains > 1: self.addTopLevelItem(x) x.setExpanded(True) h = self.header() h.setStretchLastSection(False) h.setSectionResizeMode(0, QHeaderView.Stretch) h.setSectionResizeMode(1, QHeaderView.ResizeToContents) super().update()
async def do_get(self, url="/labels"): url = 'https://' + self.target_host + url network = Network.get_instance() proxy = network.proxy if network else None async with make_aiohttp_session(proxy) as session: async with session.get(url) as result: return await result.json()
def _http_request(params): # Use the first non-onion url url = [url for url in params['urls'] if not url.endswith('.onion')][0] method = params['method'].lower() json_payload = params.get('data') json_response = Network.send_http_on_proxy(method, url, json=json_payload) return {'body': json.loads(json_response)}
def update(self, network: Network): self.clear() self.addChild = self.addTopLevelItem chains = network.get_blockchains() n_chains = len(chains) for chain_id, interfaces in chains.items(): b = blockchain.blockchains.get(chain_id) if b is None: continue name = b.get_name() if n_chains > 1: x = QTreeWidgetItem( [name + '@%d' % b.get_max_forkpoint(), '%d' % b.height()]) x.setData(0, Qt.UserRole, 1) x.setData(1, Qt.UserRole, b.get_id()) else: x = self for i in interfaces: star = ' *' if i == network.interface else '' item = QTreeWidgetItem([i.host + star, '%d' % i.tip]) item.setData(0, Qt.UserRole, 0) item.setData(1, Qt.UserRole, i.server) x.addChild(item) if n_chains > 1: self.addTopLevelItem(x) x.setExpanded(True) h = self.header() h.setStretchLastSection(False) h.setSectionResizeMode(0, QHeaderView.Stretch) h.setSectionResizeMode(1, QHeaderView.ResizeToContents) super().update()
def set_server(self): _logger.info('Configuring server to 127.0.0.1:%s', self.rpc_port) # first, remove the `server` config to allow `set_parameters()` below to update it and trigger the connection mechanism del self.config.cmdline_options['server'] network = Network.get_instance() net_params = network.get_parameters() try: # Electrum v4 server = ServerAddr('127.0.0.1', self.rpc_port, protocol='t') net_params = net_params._replace(server=server, oneserver=True) except: # Electrum v3 net_params = net_params._replace( host='127.0.0.1', port=self.rpc_port, protocol='t', oneserver=True, ) network.run_from_another_thread(network.set_parameters(net_params)) # now set the server in `cmdline_options` to lock it in self.config.cmdline_options[ 'server'] = '127.0.0.1:%s:t' % self.rpc_port
def __init__(self, config: 'SimpleConfig', exctype, value, tb): BaseCrashReporter.__init__(self, exctype, value, tb) self.network = Network.get_instance() self.config = config QWidget.__init__(self) self.setWindowTitle('NavCash - ' + _('An Error Occurred')) self.setMinimumSize(600, 300) Logger.__init__(self) main_box = QVBoxLayout() heading = QLabel('<h2>' + BaseCrashReporter.CRASH_TITLE + '</h2>') main_box.addWidget(heading) main_box.addWidget(QLabel(BaseCrashReporter.CRASH_MESSAGE)) main_box.addWidget(QLabel(BaseCrashReporter.REQUEST_HELP_MESSAGE)) collapse_info = QPushButton(_("Show report contents")) collapse_info.clicked.connect( lambda: self.msg_box(QMessageBox.NoIcon, self, _("Report contents"), self.get_report_string(), rich_text=True)) main_box.addWidget(collapse_info) main_box.addWidget(QLabel(BaseCrashReporter.DESCRIBE_ERROR_MESSAGE)) self.description_textfield = QTextEdit() self.description_textfield.setFixedHeight(50) self.description_textfield.setPlaceholderText( _("Do not enter sensitive/private information here. " "The report will be visible on the public issue tracker.")) main_box.addWidget(self.description_textfield) main_box.addWidget(QLabel(BaseCrashReporter.ASK_CONFIRM_SEND)) buttons = QHBoxLayout() report_button = QPushButton(_('Send Bug Report')) report_button.clicked.connect(self.send_report) report_button.setIcon(read_QIcon("tab_send.png")) buttons.addWidget(report_button) never_button = QPushButton(_('Never')) never_button.clicked.connect(self.show_never) buttons.addWidget(never_button) close_button = QPushButton(_('Not Now')) close_button.clicked.connect(self.close) buttons.addWidget(close_button) main_box.addLayout(buttons) self.setLayout(main_box) self.show()
def send_request(self, method, relative_url, data=None): network = Network.get_instance() if network: return asyncio.run_coroutine_threadsafe( self._send_request(method, relative_url, data), network.asyncio_loop).result() else: raise ErrorConnectingServer('You are offline.')
def set_server(self): network = Network.get_instance() net_params = network.get_parameters()._replace( host='127.0.0.1', port=self.rpc_port, protocol='t', oneserver=True, ) network.run_from_another_thread(network.set_parameters(net_params))
async def do_post(self, url = "/labels", data=None): url = 'https://' + self.target_host + url network = Network.get_instance() proxy = network.proxy if network else None async with make_aiohttp_session(proxy) as session: async with session.post(url, json=data) as result: try: return await result.json() except Exception as e: raise Exception('Could not decode: ' + await result.text()) from e
async def get_peers(network: Network): while not network.is_connected(): await asyncio.sleep(1) print("waiting for network to get connected...") interface = network.interface session = interface.session print(f"asking server {interface.server} for its peers") peers = parse_servers(await session.send_request('server.peers.subscribe')) print(f"got {len(peers)} servers") return peers
def comserver_post_notification(self, payload): assert self.is_mobile_paired(), "unexpected mobile pairing error" url = 'https://digitalbitbox.com/smartverification/index.php' key_s = base64.b64decode(self.digitalbitbox_config[ENCRYPTION_PRIVKEY_KEY]) args = 'c=data&s=0&dt=0&uuid=%s&pl=%s' % ( self.digitalbitbox_config[CHANNEL_ID_KEY], EncodeAES_base64(key_s, json.dumps(payload).encode('ascii')).decode('ascii'), ) try: text = Network.send_http_on_proxy('post', url, body=args.encode('ascii'), headers={'content-type': 'application/x-www-form-urlencoded'}) _logger.info(f'digitalbitbox reply from server {text}') except Exception as e: self.handler.show_error(repr(e)) # repr because str(Exception()) == ''
def comserver_post_notification(self, payload): assert self.is_mobile_paired(), "unexpected mobile pairing error" url = 'https://digitalbitbox.com/smartverification/index.php' key_s = base64.b64decode(self.digitalbitbox_config[ENCRYPTION_PRIVKEY_KEY]) args = 'c=data&s=0&dt=0&uuid=%s&pl=%s' % ( self.digitalbitbox_config[CHANNEL_ID_KEY], EncodeAES_base64(key_s, json.dumps(payload).encode('ascii')).decode('ascii'), ) try: text = Network.send_http_on_proxy('post', url, body=args.encode('ascii'), headers={'content-type': 'application/x-www-form-urlencoded'}) print_error('digitalbitbox reply from server', text) except Exception as e: self.handler.show_error(repr(e)) # repr because str(Exception()) == ''
def set_lnurl6(self, lnurl: str): url = decode_lnurl(lnurl) domain = urlparse(url).netloc # FIXME network request blocking GUI thread: lnurl_data = Network.run_from_another_thread(request_lnurl(url)) if not lnurl_data: return self.lnurl_data = lnurl_data self.address = "invoice from lnurl" self.message = f"lnurl: {domain}: {lnurl_data.metadata_plaintext}" self.amount = self.app.format_amount_and_units( lnurl_data.min_sendable_sat) self.is_lightning = True self.is_lnurl = True # `bool(self.lnurl_data)` should be equivalent, this is only here as it is a kivy Property
async def send_request(network: Network, servers: List[str], method: str, params: Sequence): print(f"contacting {len(servers)} servers") num_connecting = len(network.connecting) for server in servers: network._start_interface(server) # sleep a bit for _ in range(10): if len(network.connecting) < num_connecting: break await asyncio.sleep(1) print(f"connected to {len(network.interfaces)} servers. sending request to all.") responses = dict() async def get_response(iface: Interface): try: res = await iface.session.send_request(method, params, timeout=10) except Exception as e: print(f"server {iface.server} errored or timed out: ({repr(e)})") res = e responses[iface.server] = res async with TaskGroup() as group: for interface in network.interfaces.values(): await group.spawn(get_response(interface)) print("%d answers" % len(responses)) return responses
def do_verify(self, d): tx = d.tx wallet = d.wallet window = d.main_window if wallet.is_watching_only(): d.show_critical(_('This feature is not available for watch-only wallets.')) return # 1. get the password and sign the verification request password = None if wallet.has_keystore_encryption(): msg = _('GreenAddress requires your signature \n' 'to verify that transaction is instant.\n' 'Please enter your password to sign a\n' 'verification request.') password = window.password_dialog(msg, parent=d) if not password: return try: d.verify_button.setText(_('Verifying...')) QApplication.processEvents() # update the button label addr = self.get_my_addr(d) message = "Please verify if %s is GreenAddress instant confirmed" % tx.txid() sig = wallet.sign_message(addr, message, password) sig = base64.b64encode(sig).decode('ascii') # 2. send the request async def handle_request(resp: 'ClientResponse'): resp.raise_for_status() return await resp.json() url = "https://greenaddress.it/verify/?signature=%s&txhash=%s" % (urllib.parse.quote(sig), tx.txid()) response = Network.send_http_on_proxy('get', url, headers = {'User-Agent': 'Electrum'}, on_finish=handle_request) # 3. display the result if response.get('verified'): d.show_message(_('{} is covered by GreenAddress instant confirmation').format(tx.txid()), title=_('Verification successful!')) else: d.show_warning(_('{} is not covered by GreenAddress instant confirmation').format(tx.txid()), title=_('Verification failed!')) except BaseException as e: import traceback traceback.print_exc(file=sys.stdout) d.show_error(str(e)) finally: d.verify_button.setText(self.button_label)
async def _send_request(self, method, relative_url, data): url = urljoin(self.base_url, relative_url) if self.debug: print('%s %s %s' % (method, url, data)) headers = {} if self.user_agent: headers['user-agent'] = self.user_agent try: proxy = Network.get_instance().proxy async with make_aiohttp_session(proxy) as session: if method == 'get': async with session.get(url, params=data, headers=headers) as resp: return await self.handle_response(resp) elif method == 'post': async with session.post(url, json=data, headers=headers) as resp: return await self.handle_response(resp) else: assert False except TrustedCoinException: raise except Exception as e: raise ErrorConnectingServer(e)
class ElectrumWallet: """ An Electrum wallet wrapper """ def __init__(self, name, config): """ Initializes new electrum wallet instance @param name: Name of the wallet @param config: Configuration dictionary e.g { 'server': 'localhost:7777:s', 'rpc_user': '******', 'rpc_pass_': 'pass', 'electrum_path': '/opt/var/data/electrum', 'seed': '....', 'fee': 10000, 'testnet': 1 } """ self._name = name self._config = config self._config['testnet'] = bool(self._config['testnet']) if self._config['testnet'] is True: constants.set_testnet() self._config['verbos'] = False self._electrum_config = SimpleConfig(self._config) self._wallet_path = os.path.join(self._electrum_config.path, 'wallets', self._name) self._storage = WalletStorage(path=self._wallet_path) if not self._storage.file_exists(): self._electrum_config.set_key('default_wallet_path', self._wallet_path) k = keystore.from_seed(self._config['seed'], self._config['passphrase'], False) k.update_password(None, self._config['password']) self._storage.put('keystore', k.dump()) self._storage.put('wallet_type', 'standard') self._storage.put('use_encryption', bool(self._config['password'])) self._storage.write() self._wallet = Wallet(self._storage) # self._server = daemon.get_server(self._electrum_config) self._network = Network(self._electrum_config) self._network.start() self._wallet.start_threads(self._network) self._wallet.synchronize() self._wallet.wait_until_synchronized() self._wallet.stop_threads() self._wallet.storage.write() else: self._network = None self._wallet = self._wallet = Wallet(self._storage) self._commands = Commands(config=self._electrum_config, wallet=self._wallet, network=self._network) self._init_commands() def _init_commands(self): """ Scans the electrum commands class and binds all its methods to this class """ execlude_cmd = lambda item: (not item[0].startswith('_')) and item[ 0] not in EXECLUDED_COMMANDS for name, func in filter( execlude_cmd, inspect.getmembers(self._commands, inspect.ismethod)): setattr(self, name, func)
def __init__(self, nursery, config): self.network = Network(nursery, config) self.network.start() self.fx = FxThread(config, self.network) self.wallets = {}
def __init__(self, network: Network, config, wizard=False): self.network = network self.config = config self.protocol = None self.tor_proxy = None self.tabs = tabs = QTabWidget() server_tab = QWidget() proxy_tab = QWidget() blockchain_tab = QWidget() tabs.addTab(blockchain_tab, _('Overview')) tabs.addTab(server_tab, _('Server')) tabs.addTab(proxy_tab, _('Proxy')) fixed_width_hostname = 24 * char_width_in_lineedit() fixed_width_port = 6 * char_width_in_lineedit() # server tab grid = QGridLayout(server_tab) grid.setSpacing(8) self.server_host = QLineEdit() self.server_host.setFixedWidth(fixed_width_hostname) self.server_port = QLineEdit() self.server_port.setFixedWidth(fixed_width_port) self.autoconnect_cb = QCheckBox(_('Select server automatically')) self.autoconnect_cb.setEnabled( self.config.is_modifiable('auto_connect')) self.server_host.editingFinished.connect(self.set_server) self.server_port.editingFinished.connect(self.set_server) self.autoconnect_cb.clicked.connect(self.set_server) self.autoconnect_cb.clicked.connect(self.update) msg = ' '.join([ _("If auto-connect is enabled, Electrum-CHI will always use a server that is on the longest blockchain." ), _("If it is disabled, you have to choose a server you want to use. Electrum-CHI will warn you if your server is lagging." ) ]) grid.addWidget(self.autoconnect_cb, 0, 0, 1, 3) grid.addWidget(HelpButton(msg), 0, 4) grid.addWidget(QLabel(_('Server') + ':'), 1, 0) grid.addWidget(self.server_host, 1, 1, 1, 2) grid.addWidget(self.server_port, 1, 3) label = _('Server peers') if network.is_connected() else _( 'Default Servers') grid.addWidget(QLabel(label), 2, 0, 1, 5) self.servers_list = ServerListWidget(self) grid.addWidget(self.servers_list, 3, 0, 1, 5) # Proxy tab grid = QGridLayout(proxy_tab) grid.setSpacing(8) # proxy setting self.proxy_cb = QCheckBox(_('Use proxy')) self.proxy_cb.clicked.connect(self.check_disable_proxy) self.proxy_cb.clicked.connect(self.set_proxy) self.proxy_mode = QComboBox() self.proxy_mode.addItems(['SOCKS4', 'SOCKS5']) self.proxy_host = QLineEdit() self.proxy_host.setFixedWidth(fixed_width_hostname) self.proxy_port = QLineEdit() self.proxy_port.setFixedWidth(fixed_width_port) self.proxy_user = QLineEdit() self.proxy_user.setPlaceholderText(_("Proxy user")) self.proxy_password = QLineEdit() self.proxy_password.setPlaceholderText(_("Password")) self.proxy_password.setEchoMode(QLineEdit.Password) self.proxy_password.setFixedWidth(fixed_width_port) self.proxy_mode.currentIndexChanged.connect(self.set_proxy) self.proxy_host.editingFinished.connect(self.set_proxy) self.proxy_port.editingFinished.connect(self.set_proxy) self.proxy_user.editingFinished.connect(self.set_proxy) self.proxy_password.editingFinished.connect(self.set_proxy) self.proxy_mode.currentIndexChanged.connect( self.proxy_settings_changed) self.proxy_host.textEdited.connect(self.proxy_settings_changed) self.proxy_port.textEdited.connect(self.proxy_settings_changed) self.proxy_user.textEdited.connect(self.proxy_settings_changed) self.proxy_password.textEdited.connect(self.proxy_settings_changed) self.tor_cb = QCheckBox(_("Use Tor Proxy")) self.tor_cb.setIcon(read_QIcon("tor_logo.png")) self.tor_cb.hide() self.tor_cb.clicked.connect(self.use_tor_proxy) grid.addWidget(self.tor_cb, 1, 0, 1, 3) grid.addWidget(self.proxy_cb, 2, 0, 1, 3) grid.addWidget( HelpButton( _('Proxy settings apply to all connections: with Electrum-CHI servers, but also with third-party services.' )), 2, 4) grid.addWidget(self.proxy_mode, 4, 1) grid.addWidget(self.proxy_host, 4, 2) grid.addWidget(self.proxy_port, 4, 3) grid.addWidget(self.proxy_user, 5, 2) grid.addWidget(self.proxy_password, 5, 3) grid.setRowStretch(7, 1) # Blockchain Tab grid = QGridLayout(blockchain_tab) msg = ' '.join([ _("Electrum-CHI connects to several nodes in order to download block headers and find out the longest blockchain." ), _("This blockchain is used to verify the transactions sent by your transaction server." ) ]) self.status_label = QLabel('') grid.addWidget(QLabel(_('Status') + ':'), 0, 0) grid.addWidget(self.status_label, 0, 1, 1, 3) grid.addWidget(HelpButton(msg), 0, 4) self.server_label = QLabel('') msg = _( "Electrum-CHI sends your wallet addresses to a single server, in order to receive your transaction history." ) grid.addWidget(QLabel(_('Server') + ':'), 1, 0) grid.addWidget(self.server_label, 1, 1, 1, 3) grid.addWidget(HelpButton(msg), 1, 4) self.height_label = QLabel('') msg = _('This is the height of your local copy of the blockchain.') grid.addWidget(QLabel(_('Blockchain') + ':'), 2, 0) grid.addWidget(self.height_label, 2, 1) grid.addWidget(HelpButton(msg), 2, 4) self.split_label = QLabel('') grid.addWidget(self.split_label, 3, 0, 1, 3) self.nodes_list_widget = NodesListWidget(self) grid.addWidget(self.nodes_list_widget, 5, 0, 1, 5) vbox = QVBoxLayout() vbox.addWidget(tabs) self.layout_ = vbox # tor detector self.td = td = TorDetector() td.found_proxy.connect(self.suggest_proxy) td.start() self.fill_in_proxy_settings() self.update()
#!/usr/bin/env python3 import json import asyncio from electrum.simple_config import SimpleConfig from electrum.network import filter_version, Network from electrum.util import create_and_start_event_loop, log_exceptions from electrum import constants import util # testnet? #constants.set_testnet() config = SimpleConfig({'testnet': False}) loop, stopping_fut, loop_thread = create_and_start_event_loop() network = Network(config) network.start() @log_exceptions async def f(): try: peers = await util.get_peers(network) peers = filter_version(peers) print(json.dumps(peers, sort_keys=True, indent=4)) finally: stopping_fut.set_result(1) asyncio.run_coroutine_threadsafe(f(), loop)
def recovery(self): network = Network.get_instance() coroutine = account_discovery(network, self.get_account_xpub) return network.run_from_another_thread(coroutine)
from electrum import bitgesell from electrum.network import Network from electrum.util import json_encode, print_msg, create_and_start_event_loop, log_exceptions from electrum.simple_config import SimpleConfig try: addr = sys.argv[1] except Exception: print("usage: get_history <bitgesell_address>") sys.exit(1) config = SimpleConfig() loop, stopping_fut, loop_thread = create_and_start_event_loop() network = Network(config) network.start() @log_exceptions async def f(): try: sh = bitgesell.address_to_scripthash(addr) hist = await network.get_history_for_scripthash(sh) print_msg(json_encode(hist)) finally: stopping_fut.set_result(1) asyncio.run_coroutine_threadsafe(f(), loop)
import sys import asyncio from electrum import bitcoin from electrum.network import Network from electrum.util import json_encode, print_msg, create_and_start_event_loop, log_exceptions try: addr = sys.argv[1] except Exception: print("usage: get_history <raycoin_address>") sys.exit(1) loop, stopping_fut, loop_thread = create_and_start_event_loop() network = Network() network.start() @log_exceptions async def f(): try: sh = bitcoin.address_to_scripthash(addr) hist = await network.get_history_for_scripthash(sh) print_msg(json_encode(hist)) finally: stopping_fut.set_result(1) asyncio.run_coroutine_threadsafe(f(), loop)
def __init__(self): QThread.__init__(self) Logger.__init__(self) self.network = Network.get_instance()
def __init__(self, network: Network, config, wizard=False): self.network = network self.config = config self.protocol = None self.tor_proxy = None self.tabs = tabs = QTabWidget() server_tab = QWidget() proxy_tab = QWidget() blockchain_tab = QWidget() tabs.addTab(blockchain_tab, _('Overview')) tabs.addTab(server_tab, _('Server')) tabs.addTab(proxy_tab, _('Proxy')) # server tab grid = QGridLayout(server_tab) grid.setSpacing(8) self.server_host = QLineEdit() self.server_host.setFixedWidth(200) self.server_port = QLineEdit() self.server_port.setFixedWidth(60) self.autoconnect_cb = QCheckBox(_('Select server automatically')) self.autoconnect_cb.setEnabled(self.config.is_modifiable('auto_connect')) self.server_host.editingFinished.connect(self.set_server) self.server_port.editingFinished.connect(self.set_server) self.autoconnect_cb.clicked.connect(self.set_server) self.autoconnect_cb.clicked.connect(self.update) msg = ' '.join([ _("If auto-connect is enabled, Electrum will always use a server that is on the longest blockchain."), _("If it is disabled, you have to choose a server you want to use. Electrum will warn you if your server is lagging.") ]) grid.addWidget(self.autoconnect_cb, 0, 0, 1, 3) grid.addWidget(HelpButton(msg), 0, 4) grid.addWidget(QLabel(_('Server') + ':'), 1, 0) grid.addWidget(self.server_host, 1, 1, 1, 2) grid.addWidget(self.server_port, 1, 3) label = _('Server peers') if network.is_connected() else _('Default Servers') grid.addWidget(QLabel(label), 2, 0, 1, 5) self.servers_list = ServerListWidget(self) grid.addWidget(self.servers_list, 3, 0, 1, 5) # Proxy tab grid = QGridLayout(proxy_tab) grid.setSpacing(8) # proxy setting self.proxy_cb = QCheckBox(_('Use proxy')) self.proxy_cb.clicked.connect(self.check_disable_proxy) self.proxy_cb.clicked.connect(self.set_proxy) self.proxy_mode = QComboBox() self.proxy_mode.addItems(['SOCKS4', 'SOCKS5']) self.proxy_host = QLineEdit() self.proxy_host.setFixedWidth(200) self.proxy_port = QLineEdit() self.proxy_port.setFixedWidth(60) self.proxy_user = QLineEdit() self.proxy_user.setPlaceholderText(_("Proxy user")) self.proxy_password = QLineEdit() self.proxy_password.setPlaceholderText(_("Password")) self.proxy_password.setEchoMode(QLineEdit.Password) self.proxy_password.setFixedWidth(60) self.proxy_mode.currentIndexChanged.connect(self.set_proxy) self.proxy_host.editingFinished.connect(self.set_proxy) self.proxy_port.editingFinished.connect(self.set_proxy) self.proxy_user.editingFinished.connect(self.set_proxy) self.proxy_password.editingFinished.connect(self.set_proxy) self.proxy_mode.currentIndexChanged.connect(self.proxy_settings_changed) self.proxy_host.textEdited.connect(self.proxy_settings_changed) self.proxy_port.textEdited.connect(self.proxy_settings_changed) self.proxy_user.textEdited.connect(self.proxy_settings_changed) self.proxy_password.textEdited.connect(self.proxy_settings_changed) self.tor_cb = QCheckBox(_("Use Tor Proxy")) self.tor_cb.setIcon(QIcon(":icons/tor_logo.png")) self.tor_cb.hide() self.tor_cb.clicked.connect(self.use_tor_proxy) grid.addWidget(self.tor_cb, 1, 0, 1, 3) grid.addWidget(self.proxy_cb, 2, 0, 1, 3) grid.addWidget(HelpButton(_('Proxy settings apply to all connections: with Electrum servers, but also with third-party services.')), 2, 4) grid.addWidget(self.proxy_mode, 4, 1) grid.addWidget(self.proxy_host, 4, 2) grid.addWidget(self.proxy_port, 4, 3) grid.addWidget(self.proxy_user, 5, 2) grid.addWidget(self.proxy_password, 5, 3) grid.setRowStretch(7, 1) # Blockchain Tab grid = QGridLayout(blockchain_tab) msg = ' '.join([ _("Electrum connects to several nodes in order to download block headers and find out the longest blockchain."), _("This blockchain is used to verify the transactions sent by your transaction server.") ]) self.status_label = QLabel('') grid.addWidget(QLabel(_('Status') + ':'), 0, 0) grid.addWidget(self.status_label, 0, 1, 1, 3) grid.addWidget(HelpButton(msg), 0, 4) self.server_label = QLabel('') msg = _("Electrum sends your wallet addresses to a single server, in order to receive your transaction history.") grid.addWidget(QLabel(_('Server') + ':'), 1, 0) grid.addWidget(self.server_label, 1, 1, 1, 3) grid.addWidget(HelpButton(msg), 1, 4) self.height_label = QLabel('') msg = _('This is the height of your local copy of the blockchain.') grid.addWidget(QLabel(_('Blockchain') + ':'), 2, 0) grid.addWidget(self.height_label, 2, 1) grid.addWidget(HelpButton(msg), 2, 4) self.split_label = QLabel('') grid.addWidget(self.split_label, 3, 0, 1, 3) self.nodes_list_widget = NodesListWidget(self) grid.addWidget(self.nodes_list_widget, 5, 0, 1, 5) vbox = QVBoxLayout() vbox.addWidget(tabs) self.layout_ = vbox # tor detector self.td = td = TorDetector() td.found_proxy.connect(self.suggest_proxy) td.start() self.fill_in_proxy_settings() self.update()
def send_request(self, method, relative_url, data=None): network = Network.get_instance() if network: return asyncio.run_coroutine_threadsafe(self._send_request(method, relative_url, data), network.asyncio_loop).result() else: raise ErrorConnectingServer('You are offline.')
def update(self, *, network: Network, servers: dict, use_tor: bool): self.clear() # connected servers connected_servers_item = QTreeWidgetItem([_("Connected nodes"), '']) connected_servers_item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.TOPLEVEL) chains = network.get_blockchains() n_chains = len(chains) for chain_id, interfaces in chains.items(): b = blockchain.blockchains.get(chain_id) if b is None: continue name = b.get_name() if n_chains > 1: x = QTreeWidgetItem([name + '@%d'%b.get_max_forkpoint(), '%d'%b.height()]) x.setData(0, self.ITEMTYPE_ROLE, self.ItemType.CHAIN) x.setData(0, self.CHAIN_ID_ROLE, b.get_id()) else: x = connected_servers_item for i in interfaces: star = ' *' if i == network.interface else '' item = QTreeWidgetItem([f"{i.server.to_friendly_name()}" + star, '%d'%i.tip]) item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.CONNECTED_SERVER) item.setData(0, self.SERVER_ADDR_ROLE, i.server) item.setToolTip(0, str(i.server)) x.addChild(item) if n_chains > 1: connected_servers_item.addChild(x) # disconnected servers disconnected_servers_item = QTreeWidgetItem([_("Other known servers"), ""]) disconnected_servers_item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.TOPLEVEL) connected_hosts = set([iface.host for ifaces in chains.values() for iface in ifaces]) protocol = PREFERRED_NETWORK_PROTOCOL for _host, d in sorted(servers.items()): if _host in connected_hosts: continue if _host.endswith('.onion') and not use_tor: continue port = d.get(protocol) if port: server = ServerAddr(_host, port, protocol=protocol) item = QTreeWidgetItem([server.net_addr_str(), ""]) item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.DISCONNECTED_SERVER) item.setData(0, self.SERVER_ADDR_ROLE, server) disconnected_servers_item.addChild(item) self.addTopLevelItem(connected_servers_item) self.addTopLevelItem(disconnected_servers_item) connected_servers_item.setExpanded(True) for i in range(connected_servers_item.childCount()): connected_servers_item.child(i).setExpanded(True) disconnected_servers_item.setExpanded(True) # headers h = self.header() h.setStretchLastSection(False) h.setSectionResizeMode(0, QHeaderView.Stretch) h.setSectionResizeMode(1, QHeaderView.ResizeToContents) super().update()
#!/usr/bin/env python3 # A simple script that connects to a server and displays block headers import time import asyncio from electrum.network import Network from electrum.util import print_msg, json_encode, create_and_start_event_loop, log_exceptions # start network loop, stopping_fut, loop_thread = create_and_start_event_loop() network = Network() network.start() # wait until connected while not network.is_connected(): time.sleep(1) print_msg("waiting for network to get connected...") header_queue = asyncio.Queue() @log_exceptions async def f(): try: await network.interface.session.subscribe( 'blockchain.headers.subscribe', [], header_queue) # 3. wait for results while network.is_connected(): header = await header_queue.get()