コード例 #1
0
 def setUp(self):
     self.servers = [['hostname{}'.format(x), 's'] for x in range(0, 10)]
     self.electrod_loop = Mock()
     self.delayer = Mock()
     self.electrod_loop = Mock()
     self.network_checker = Mock()
     self.connection_factory = Mock()
     self.sut = ElectrodConnectionPool(
         connections=3,
         loop=self.electrod_loop,
         delayer=self.delayer,
         peers=self.servers,
         network_checker=self.network_checker,
         connection_factory=self.connection_factory)
     self.loop = asyncio.get_event_loop()
コード例 #2
0
def build(ctx, loop=asyncio.get_event_loop()):  # pragma: no cover
    from spruned.daemon.electrod.electrod_connection import ElectrodConnectionPool
    from spruned.daemon.electrod.electrod_interface import ElectrodInterface
    from spruned.daemon.electrod.electrod_fee_estimation import EstimateFeeConsensusProjector, \
        EstimateFeeConsensusCollector
    network = ctx.get_network()
    peers = load_electrum_servers(ctx)
    fees_collector = EstimateFeeConsensusCollector(proxy=ctx.proxy)
    _ = [
        fees_collector.add_peer(peer)
        for peer in [x[0] + '/' + x[1] for x in peers]
    ]
    electrod_pool = ElectrodConnectionPool(
        connections=network['electrum_concurrency'],
        peers=peers,
        ipv6=False,
        proxy=ctx.proxy,
        tor=ctx.tor)
    electrod_interface = ElectrodInterface(
        electrod_pool,
        loop,
        fees_projector=EstimateFeeConsensusProjector(),
        fees_collector=fees_collector)
    electrod_interface.add_on_connected_callback(
        electrod_interface.bootstrap_collector)
    return electrod_pool, electrod_interface
コード例 #3
0
ファイル: __init__.py プロジェクト: yashbhutwala/spruned
def build(ctx, loop=asyncio.get_event_loop()):  # pragma: no cover
    from spruned.daemon.electrod.electrod_connection import ElectrodConnectionPool
    from spruned.daemon.electrod.electrod_interface import ElectrodInterface
    network = ctx.get_network()
    electrod_pool = ElectrodConnectionPool(
        connections=network["electrum_concurrency"],
        peers=load_electrum_servers(ctx))
    electrod_interface = ElectrodInterface(electrod_pool, loop)
    return electrod_pool, electrod_interface
コード例 #4
0
ファイル: __init__.py プロジェクト: romanz/spruned
def build(network, loop=asyncio.get_event_loop()):  # pragma: no cover
    def load_electrum_servers(network):
        _current_path = os.path.dirname(os.path.abspath(__file__))
        with open(_current_path + '/electrum_servers.json', 'r') as f:
            servers = json.load(f)
        return servers[network]

    electrod_pool = ElectrodConnectionPool(
        connections=network["electrum_concurrency"],
        peers=load_electrum_servers(network["electrum_servers"]))
    electrod_interface = ElectrodInterface(electrod_pool, loop)
    return electrod_pool, electrod_interface
コード例 #5
0
class TestElectrodConnectionPool(unittest.TestCase):
    def setUp(self):
        self.servers = [['hostname{}'.format(x), 's'] for x in range(0, 10)]
        self.electrod_loop = Mock()
        self.delayer = Mock()
        self.electrod_loop = Mock()
        self.network_checker = Mock()
        self.connection_factory = Mock()
        self.servers_storage = Mock()
        self.sut = ElectrodConnectionPool(
            connections=3,
            loop=self.electrod_loop,
            delayer=self.delayer,
            peers=self.servers,
            network_checker=self.network_checker,
            connection_factory=self.connection_factory,
            servers_storage=self.servers_storage)
        self.loop = asyncio.get_event_loop()

    async def stop_keepalive(self, n):
        await asyncio.sleep(n)
        self.sut._keepalive = False

    def test_connect_no_internet_connectivity(self):
        self.sut._sleep_on_no_internet_connectivity = 2
        self.network_checker.return_value = False
        self.loop.run_until_complete(
            asyncio.gather(self.stop_keepalive(4.1), self.sut.connect()))
        self.sut._sleep_on_no_internet_connectivity = 30

        self.assertEqual(0, len(self.sut.connections))
        self.assertEqual(4, self.network_checker.call_count)

    def test_connect_success(self):
        self.sut.loop = self.loop
        self.network_checker.return_value = True
        conn1 = Mock(connected=False, score=0)
        conn1.connect = lambda: connect(conn1)
        conn2 = Mock(connected=False, score=0)
        conn2.connect = lambda: connect(conn2)
        conn3 = Mock(connected=False, score=0)
        conn3.connect = lambda: connect(conn3)
        self.connection_factory.side_effect = [conn1, conn2, conn3]
        on_connected_observer = Mock()
        on_connected_observer.return_value = async_coro(True)
        self.sut.add_on_connected_observer(on_connected_observer)
        self.loop.run_until_complete(
            asyncio.gather(self.stop_keepalive(7), self.sut.connect()))
        self.sut.loop = self.electrod_loop

        for conn in [conn1, conn2, conn3]:
            self.assertEqual(conn.add_on_connect_callback.call_count, 1)
            self.assertEqual(conn.add_on_header_callbacks.call_count, 1)
            self.assertEqual(conn.add_on_peers_callback.call_count, 1)
            self.assertEqual(conn.add_on_error_callback.call_count, 1)
            self.assertTrue(conn.connected)
        self.assertEqual(on_connected_observer.call_count, 1)
        self.assertEqual(3, len(self.sut.connections))
        self.assertEqual(3, len(self.sut.established_connections))

    def test_connect_too_much_peers(self):
        """
        I didn't tracked with an issue when this happened,
        but it did, maybe asyncio lag\race conditions
        """
        self.sut.loop = self.loop
        self.network_checker.return_value = True
        self.sut._required_connections = 2
        conn1 = Mock(score=10, connected=False, start_score=10)
        conn1.connect = lambda: connect(conn1)
        conn1.disconnect = lambda: disconnect(conn1)
        conn2 = Mock(score=10, connected=False, start_score=10)
        conn1.score = 10
        conn2.connect = lambda: connect(conn2)
        conn2.disconnect = lambda: disconnect(conn2)
        self.connection_factory.side_effect = [conn1, conn2]
        on_connected_observer = Mock()
        on_connected_observer.return_value = async_coro(True)
        self.sut.add_on_connected_observer(on_connected_observer)

        async def _change_behaviour(n):
            await asyncio.sleep(n)
            self.assertEqual(len(self.sut.connections), 2)
            self.sut._required_connections = 1

        self.loop.run_until_complete(
            asyncio.gather(self.stop_keepalive(15), _change_behaviour(6),
                           self.sut.connect()))

        self.assertEqual(1, len(self.sut.connections))
        self.assertEqual(1, len(self.sut.established_connections))
        d = 0
        c = 0
        for conn in [conn1, conn2]:
            c += conn._connect.call_count
            d += conn._disconnect.call_count
        self.assertEqual(d, 1)
        self.assertEqual(c, 2)
        self.assertEqual(1, len([c for c in [conn1, conn2] if c.connected]))

    def test_call_corners(self):
        with self.assertRaises(ValueError):
            self.loop.run_until_complete(
                self.sut.call('cafe', {'par': 'ams'},
                              get_peer=True,
                              agreement=2))
        with self.assertRaises(ValueError):
            self.sut._required_connections = 2
            self.loop.run_until_complete(
                self.sut.call('cafe', {'par': 'ams'},
                              agreement=self.sut._required_connections + 1))
        with self.assertRaises(exceptions.NoPeersException):
            self.loop.run_until_complete(self.sut.call('cafe', 'babe'))

    def test_call_success(self):
        response = 'some response'
        conn = Mock(connected=True, protocol=True, score=10)
        self.sut._connections = [conn]
        conn.rpc_call.return_value = async_coro(response)
        res = self.loop.run_until_complete(self.sut.call('cafe', 'babe'))
        self.assertEqual(res, response)

        conn.rpc_call.return_value = async_coro(response)
        peer, res = self.loop.run_until_complete(
            self.sut.call('cafe', 'babe', get_peer=True))
        self.assertEqual(peer, conn)
        self.assertEqual(res, response)

    def test_call_success_multiple_agreement(self):
        response = 'some response'
        conn = Mock(connected=True, protocol=True, score=10)
        conn.rpc_call.return_value = async_coro(response)
        conn2 = Mock(connected=True, protocol=True, score=10)
        conn2.rpc_call.return_value = async_coro(response)
        self.sut._connections = [conn, conn2]
        res = self.loop.run_until_complete(
            self.sut.call('cafe', 'babe', agreement=2))
        self.assertEqual(res, response)

    def test_call_failure_not_enough_responses(self):
        response = 'some response'
        conn = Mock(connected=True, protocol=True, score=10)
        conn.rpc_call.return_value = async_coro(response)
        conn2 = Mock(connected=True, protocol=True, score=10)
        conn2.rpc_call.return_value = async_coro(None)
        self.sut._connections = [conn, conn2]
        with self.assertRaises(exceptions.ElectrodMissingResponseException):
            self.loop.run_until_complete(
                self.sut.call('cafe', 'babe', agreement=2))

        conn.rpc_call.return_value = async_coro(response)
        conn2.rpc_call.return_value = async_coro(None)
        self.assertIsNone(
            self.loop.run_until_complete(
                self.sut.call('cafe', 'babe', agreement=2, fail_silent=True)))

    def test_call_failure_disagreement_on_responses(self):
        response = 'some response'
        response2 = 'another response'
        conn = Mock(connected=True, protocol=True, score=10)
        conn.rpc_call.return_value = async_coro(response)
        conn2 = Mock(connected=True, protocol=True, score=10)
        conn2.rpc_call.return_value = async_coro(response2)
        self.sut._connections = [conn, conn2]
        with self.assertRaises(exceptions.NoQuorumOnResponsesException):
            self.loop.run_until_complete(
                self.sut.call('cafe', 'babe', agreement=2))

        conn.rpc_call.return_value = async_coro(response)
        conn2.rpc_call.return_value = async_coro(response2)
        self.assertIsNone(
            self.loop.run_until_complete(
                self.sut.call('cafe', 'babe', agreement=2, fail_silent=True)))

    def test_call_missing_response(self):
        conn = Mock(connected=True, protocol=True, score=10)
        conn2 = Mock(connected=True, protocol=True, score=10)
        conn.rpc_call.return_value = async_coro(None)
        conn2.rpc_call.return_value = async_coro(None)
        self.sut._connections = [conn, conn2]
        with self.assertRaises(exceptions.ElectrodMissingResponseException):
            self.loop.run_until_complete(
                self.sut.call('cafe', 'babe', agreement=2))

    def test_corners(self):
        s = [s for s in self.sut._peers]
        self.sut._peers = []
        with self.assertRaises(exceptions.NoServersException):
            self.sut._pick_peer()
        with self.assertRaises(exceptions.NoServersException):
            self.sut._pick_multiple_peers(2)
        self.sut._peers = s
        with self.assertRaises(exceptions.NoPeersException):
            self.sut._pick_connection()
        with self.assertRaises(exceptions.NoPeersException):
            self.sut._pick_multiple_connections(2)
        self.assertIsNone(self.sut._pick_connection(fail_silent=True))
        self.sut._peers = ['cafebabe']
        self.sut._connections.append(
            Mock(hostname='cafebabe', connected=True, score=1))
        with self.assertRaises(exceptions.NoServersException):
            self.sut._pick_peer()
        with self.assertRaises(exceptions.NoServersException):
            self.sut._pick_multiple_peers(1)

    def test__handle_peer_error_disconnected(self):
        conn = Mock(connected=False)
        res = self.loop.run_until_complete(self.sut._handle_peer_error(conn))
        self.assertIsNone(res)

    def test_handle_peer_error_noscore(self):
        conn = Mock(connected=True, score=0)
        conn.disconnect.return_value = 'disconnect'
        self.delayer.return_value = 'delayer'
        res = self.loop.run_until_complete(self.sut._handle_peer_error(conn))
        self.assertIsNone(res)
        Mock.assert_called_with(self.electrod_loop.create_task, 'delayer')
        Mock.assert_called_with(self.delayer, 'disconnect')

    def test_handle_peer_error_ping_timeout(self):
        conn = Mock(connected=True, score=10)
        conn.ping.return_value = async_coro(None)
        conn.disconnect.return_value = 'disconnect'
        self.delayer.return_value = 'delayer'

        res = self.loop.run_until_complete(self.sut._handle_peer_error(conn))
        self.assertIsNone(res)
        Mock.assert_called_with(self.electrod_loop.create_task, 'delayer')
        Mock.assert_called_with(self.delayer, 'disconnect')

    def test_on_connected_callback(self):
        peer = Mock()
        cob = Mock()
        self.network_checker.return_value = True
        self.sut.add_on_connected_observer(cob)
        peer.subscribe.return_value = 'subscriberrr'
        self.delayer.return_value = 'delayerrr'
        self.loop.run_until_complete(self.sut.on_peer_connected(peer))
        Mock.assert_called_with(
            peer.subscribe,
            'blockchain.headers.subscribe',
            self.sut.on_peer_received_header,
            self.sut.on_peer_received_header,
        )
        Mock.assert_has_calls(self.electrod_loop.create_task,
                              calls=[call('delayerrr'),
                                     call(ANY)])
        Mock.assert_called_once_with(self.delayer, 'subscriberrr')

    def test_on_headers_callback(self):
        peer = Mock(last_header='header')
        hob = Mock()
        hob.return_value = 'observing'
        self.delayer.return_value = 'delayerr'
        self.network_checker.return_value = True
        self.sut.add_header_observer(hob)
        self.loop.run_until_complete(self.sut.on_peer_received_header(peer))
        Mock.assert_called_once_with(self.electrod_loop.create_task,
                                     'delayerr')
        Mock.assert_called_once_with(hob, peer, 'header')
        Mock.assert_called_once_with(self.delayer, 'observing')

    def test_on_peer_error(self):
        peer = Mock(is_online=True, connected=False, _errors=[])
        peer.add_error = lambda *x: peer._errors.append(x[
            0]) if x else peer._errors.append(int(time.time()))
        self.loop.run_until_complete(self.sut.on_peer_error(peer))
        self.assertEqual(len(peer._errors), 1)

    def test_on_peer_error_during_connection(self):
        peer = Mock(is_online=True, connected=False, _errors=[])
        peer.add_error = lambda *x: peer._errors.append(x[
            0]) if x else peer._errors.append(int(time.time()))
        self.network_checker.return_value = False
        self.loop.run_until_complete(
            self.sut.on_peer_error(peer, error_type='connect'))
        self.assertEqual(len(peer._errors), 0)

        self.network_checker.return_value = True
        self.loop.run_until_complete(
            self.sut.on_peer_error(peer, error_type='connect'))
        self.assertEqual(len(peer._errors), 1)