Ejemplo n.º 1
0
def main():
    parser = argparse.ArgumentParser(description='Interact with an electrum server')
    parser.add_argument('method', default=None,
                        help='"blockchain.numblocks.subscribe" or similar')
    parser.add_argument('args', nargs="*", default=[],
                        help='Arguments for method')
    parser.add_argument('--server', default='cluelessperson.com',
                        help='Hostname of Electrum server to use')
    parser.add_argument('--protocol', default='s',
                        help='Protocol code: t=TCP Cleartext, s=SSL, etc')
    parser.add_argument('--port', default=None,
                        help='Port number to override default for protocol')
    parser.add_argument('--tor', default=False, action="store_true",
                        help='Use local Tor proxy to connect')

    args = parser.parse_args()

    import logging
    logging.getLogger('connectrum').setLevel(logging.DEBUG)

    # convert to our datastruct about servers.
    svr = ServerInfo(args.server, args.server,
                    ports=((args.protocol+str(args.port)) if args.port else args.protocol))

    loop = asyncio.get_event_loop()  

    conn = StratumClient()
    connector = conn.connect(svr, args.protocol, use_tor=svr.is_onion, disable_cert_verify=True)

    loop.run_until_complete(interact(conn, svr, connector, args.method, args.args))

    loop.close()
Ejemplo n.º 2
0
async def setup_client() -> StratumClient:
    try:
        return CLIENT
    except NameError:
        pass

    server = ServerInfo({
        "nickname": None,
        "hostname": "fortress.qtornado.com",
        "ip_addr": None,
        "ports": ["s50002", "t50001"],
        "version": "1.4",
        "pruning_limit": 0,
        "seen_at": 1533670768.8676858
    })

    client = StratumClient()

    await asyncio.wait_for(client.connect(server_info=server,
                                          proto_code='s',
                                          use_tor=False,
                                          disable_cert_verify=True),
                           timeout=5)
    #
    # await asyncio.wait_for(
    #     client.RPC(
    #         'server.version',
    #         'bitcoin-spv-merkle',
    #         '1.2'),
    #     timeout=5)

    return client
Ejemplo n.º 3
0
async def setup_client():
    if CLIENT is not None:
        return CLIENT
    server = ServerInfo({
        "nickname": None,
        "hostname": "bitcoin.cluelessperson.com",
        "ip_addr": "172.92.140.254",
        "ports": ["s50002", "t50001"],
        "version": "1.2",
        "pruning_limit": 0,
        "seen_at": 1533670768.588772
    })

    client = StratumClient()

    await asyncio.wait_for(client.connect(server_info=server,
                                          proto_code='s',
                                          use_tor=False,
                                          disable_cert_verify=True),
                           timeout=5)

    await asyncio.wait_for(client.RPC('server.version', 'bitcoin-spv-merkle',
                                      '1.2'),
                           timeout=5)

    return client
Ejemplo n.º 4
0
    async def new_client(self, network: str) -> StratumClient:
        while True:
            server = self._get_server_info(network)
            try:

                client = StratumClient()

                await asyncio.wait_for(
                    client.connect(
                        server_info=server,
                        proto_code='s',
                        use_tor=False,
                        disable_cert_verify=True),
                    timeout=self._timeout_seconds)

                await asyncio.wait_for(
                    client.RPC(
                        'server.version',
                        self.user_agent,
                        self.protocol_version),
                    timeout=self._timeout_seconds)

                asyncio.ensure_future(self._keepalive(client, network))
                self._servers.append(str(server))
                return client

            except Exception as e:
                print('failed:', server)
                print(e, str(e))
                # fall back to top of loop and try a new server
                pass
Ejemplo n.º 5
0
def main():
    svr = ServerInfo("test-net", "testnet.hsmiths.com", ports="s50002")
    loop = asyncio.get_event_loop()
    conn = StratumClient()
    connector = conn.connect(svr, disable_cert_verify=True)
    loop.run_until_complete(
        interact(conn, svr, connector, "blockchain.address.get_balance",
                 ["3KF9nXowQ4asSGxRRzeiTpDjMuwM2nypAN"]))
    loop.close()
Ejemplo n.º 6
0
def main():
    parser = argparse.ArgumentParser(description='Subscribe to BTC events')
    parser.add_argument('method',
                        help='"blockchain.numblocks.subscribe" or similar')
    parser.add_argument('args',
                        nargs="*",
                        default=[],
                        help='Arguments for method')
    parser.add_argument('--server',
                        default='cluelessperson.com',
                        help='Hostname of Electrum server to use')
    parser.add_argument('--protocol',
                        default='s',
                        help='Protocol code: t=TCP Cleartext, s=SSL, etc')
    parser.add_argument('--port',
                        default=None,
                        help='Port number to override default for protocol')
    parser.add_argument('--tor',
                        default=False,
                        action="store_true",
                        help='Use local Tor proxy to connect')
    parser.add_argument('--debug',
                        default=False,
                        action="store_true",
                        help='Enable debug output from connectrum library')

    args = parser.parse_args()

    if args.debug:
        import logging
        logging.getLogger('connectrum').setLevel(logging.DEBUG)

    # convert to our datastruct about servers.
    svr = ServerInfo(args.server,
                     args.server,
                     ports=((args.protocol +
                             str(args.port)) if args.port else args.protocol))

    loop = asyncio.get_event_loop()

    conn = StratumClient()
    connector = conn.connect(svr,
                             args.protocol,
                             use_tor=svr.is_onion,
                             disable_cert_verify=True)

    loop.run_until_complete(
        listen(conn, svr, connector, args.method, args.args))

    loop.close()
Ejemplo n.º 7
0
class Connection:
    """ Connection object. Connects to an Electrum server, and handles all
    Stratum protocol messages.
    """

    #  pylint: disable=E1111
    def __init__(self, loop: asyncio.AbstractEventLoop, server: str, port: int,
                 proto: str) -> None:
        """ Connection object constructor.

        :param loop: an asyncio event loop
        :param server: a string containing a hostname
        :param port: port number that the server listens on
        :returns: A new Connection object
        """
        logging.info("Connecting...")

        self.server_info = ServerInfo(server, hostname=server,
                                      ports=port)  # type: ServerInfo

        logging.info(str(self.server_info.get_port(proto)))

        self.client = StratumClient(loop)  # type: StratumClient
        self.connection = self.client.connect(
            self.server_info,
            proto_code=proto,
            use_tor=True,
            disable_cert_verify=(proto != "s"))  # type: asyncio.Future

        self.queue = None  # type: asyncio.Queue

    async def do_connect(self) -> None:
        """ Coroutine. Establishes a persistent connection to an Electrum server.
        Awaits the connection because AFAIK an init method can't be async.
        """
        await self.connection
        logging.info("Connected to server")

    async def listen_rpc(self, method: str, args: List) -> Any:
        """ Coroutine. Sends a normal RPC message to the server and awaits response.

        :param method: The Electrum API method to use
        :param args: Params associated with current method
        :returns: Future. Response from server for this method(args)
        """
        return await self.client.RPC(method, *args)

    def listen_subscribe(self, method: str, args: List) -> None:
        """ Sends a "subscribe" message to the server and adds to the queue.
        Throws away the immediate future containing the "history" hash.

        :param method: The Electrum API method to use
        :param args: Params associated with current method
        """
        t = self.client.subscribe(
            method, *args)  # type: Tuple[asyncio.Future, asyncio.Queue]
        future, queue = t

        self.queue = queue
        return future

    async def consume_queue(
            self, queue_func: Callable[[List[str]], Awaitable[None]]) -> None:
        """ Coroutine. Infinite loop that consumes the current subscription queue.
        :param queue_func: A function to call when new responses arrive
        """
        while True:
            result = await self.queue.get()  # type: List[str]
            await queue_func(result)
Ejemplo n.º 8
0
class Server:
    def __init__(self, _chain):
        self.chain = _chain
        self.client = None
        self.connection = None
        self.server_list = None
        self.app = web.Application()
        self.app.router.add_get('/servers', self.handle)
        self.app.on_startup.append(self.start_background_tasks)
        self.app.on_cleanup.append(self.cleanup_background_tasks)
        self.load_server_list()
        self.connected = False

    def load_server_list(self):
        try:
            with open("servers.json", "r") as infile:
                self.server_list = json.load(infile)
        except Exception:
            self.server_list = list()

    async def connect(self):
        server_info = ServerInfo("", hostname="mdw.ddns.net", ports=50001)
        self.client = StratumClient(self.app.loop)
        self.connection = self.client.connect(
            server_info, proto_code="t")  # type: asyncio.Future
        try:
            await self.connection
            self.connected = True
        except Exception:
            print("Unable to connect to server:", server_info)

    async def get_peers(self):
        server_list = list()
        peers = await self.client.RPC("server.peers.subscribe")
        for peer in peers:
            host, info = peer[1:]
            if info[0] not in ("v1.1", "v1.2"):
                continue
            proto_port = info[1]
            proto, port = proto_port[0], int(proto_port[1:])
            server = [host, port, proto]
            server_list.append(server)
        return server_list

    async def update_server_list(self):
        if self.connected:
            self.server_list = await self.get_peers()
        else:
            self.server_list = await scrape_electrum_servers(
                self.chain, loop=self.app.loop)
        with open("servers.json", "w") as outfile:
            json.dump(self.server_list, outfile)

    async def update_loop(self):
        while True:
            if self.connected and not self.client.protocol:
                self.connected = False
            if not self.connected:
                pass  # await self.connect()
            await self.update_server_list()
            await asyncio.sleep(600)

    async def start_background_tasks(self, app):
        app['dispatch'] = asyncio.ensure_future(self.update_loop())

    async def cleanup_background_tasks(self, app):
        app['dispatch'].cancel()
        await app['dispatch']

    async def handle(self, request):
        response_obj = {'servers': self.server_list}
        return web.json_response(response_obj)