Example #1
0
 async def test_delete_file_during_reflector_upload(self):
     stop = asyncio.Event()
     incoming = asyncio.Event()
     not_incoming = asyncio.Event()
     reflector = ReflectorServer(self.server_blob_manager,
                                 response_chunk_size=50,
                                 stop_event=stop,
                                 incoming_event=incoming,
                                 not_incoming_event=not_incoming)
     reflector.start_server(5566, '127.0.0.1')
     await reflector.started_listening.wait()
     self.addCleanup(reflector.stop_server)
     self.assertEqual(0, self.stream.reflector_progress)
     reflect_task = asyncio.create_task(
         self.stream.upload_to_reflector('127.0.0.1', 5566))
     await incoming.wait()
     await not_incoming.wait()
     await incoming.wait()
     await self.stream_manager.delete(self.stream, delete_file=True)
     # this used to raise OSError when it can't read the deleted blob for the upload
     sent = await reflect_task
     self.assertListEqual([self.stream.sd_hash], sent)
     self.assertTrue(
         self.server_blob_manager.get_blob(
             self.stream.sd_hash).get_is_verified())
     self.assertFalse(
         self.server_blob_manager.get_blob(
             self.stream.descriptor.blobs[0].blob_hash).get_is_verified())
     self.assertFalse(self.stream.is_fully_reflected)
Example #2
0
 async def test_result_from_disconnect_mid_data_transfer(self):
     stop = asyncio.Event()
     incoming = asyncio.Event()
     not_incoming = asyncio.Event()
     reflector = ReflectorServer(self.server_blob_manager,
                                 response_chunk_size=50,
                                 stop_event=stop,
                                 incoming_event=incoming,
                                 not_incoming_event=not_incoming)
     reflector.start_server(5566, '127.0.0.1')
     await reflector.started_listening.wait()
     self.addCleanup(reflector.stop_server)
     self.assertEqual(0, self.stream.reflector_progress)
     reflect_task = asyncio.create_task(
         self.stream.upload_to_reflector('127.0.0.1', 5566))
     await incoming.wait()
     await not_incoming.wait()
     await incoming.wait()
     stop.set()
     self.assertListEqual(await reflect_task, [self.stream.sd_hash])
     self.assertTrue(
         self.server_blob_manager.get_blob(
             self.stream.sd_hash).get_is_verified())
     self.assertFalse(
         self.server_blob_manager.get_blob(
             self.stream.descriptor.blobs[0].blob_hash).get_is_verified())
     self.assertFalse(self.stream.is_fully_reflected)
Example #3
0
    async def _test_reflect_stream(self, response_chunk_size):
        reflector = ReflectorServer(self.server_blob_manager,
                                    response_chunk_size=response_chunk_size)
        reflector.start_server(5566, '127.0.0.1')
        await reflector.started_listening.wait()
        self.addCleanup(reflector.stop_server)
        self.assertEqual(0, self.stream.reflector_progress)
        sent = await self.stream.upload_to_reflector('127.0.0.1', 5566)
        self.assertEqual(100, self.stream.reflector_progress)
        self.assertSetEqual(
            set(sent),
            set(
                map(
                    lambda b: b.blob_hash, self.stream.descriptor.blobs[:-1] +
                    [self.blob_manager.get_blob(self.stream.sd_hash)])))
        self.assertTrue(self.stream.is_fully_reflected)
        server_sd_blob = self.server_blob_manager.get_blob(self.stream.sd_hash)
        self.assertTrue(server_sd_blob.get_is_verified())
        self.assertEqual(server_sd_blob.length, server_sd_blob.length)
        for blob in self.stream.descriptor.blobs[:-1]:
            server_blob = self.server_blob_manager.get_blob(blob.blob_hash)
            self.assertTrue(server_blob.get_is_verified())
            self.assertEqual(server_blob.length, blob.length)

        sent = await self.stream.upload_to_reflector('127.0.0.1', 5566)
        self.assertListEqual(sent, [])
Example #4
0
    async def _test_reflect_stream(self,
                                   response_chunk_size=50,
                                   partial_needs=False):
        reflector = ReflectorServer(self.server_blob_manager,
                                    response_chunk_size=response_chunk_size,
                                    partial_needs=partial_needs)
        reflector.start_server(5566, '127.0.0.1')
        if partial_needs:
            server_blob = self.server_blob_manager.get_blob(
                self.stream.sd_hash)
            client_blob = self.blob_manager.get_blob(self.stream.sd_hash)
            with client_blob.reader_context() as handle:
                server_blob.set_length(client_blob.get_length())
                writer = server_blob.get_blob_writer('nobody', 0)
                writer.write(handle.read())
            self.server_blob_manager.blob_completed(server_blob)
        await reflector.started_listening.wait()
        self.addCleanup(reflector.stop_server)
        self.assertEqual(0, self.stream.reflector_progress)
        sent = await self.stream.upload_to_reflector('127.0.0.1', 5566)
        self.assertEqual(100, self.stream.reflector_progress)
        if partial_needs:
            self.assertFalse(self.stream.is_fully_reflected)
            send_more = await self.stream.upload_to_reflector(
                '127.0.0.1', 5566)
            self.assertGreater(len(send_more), 0)
            sent.extend(send_more)
            sent.append(self.stream.sd_hash)
        self.assertSetEqual(
            set(sent),
            set(
                map(
                    lambda b: b.blob_hash, self.stream.descriptor.blobs[:-1] +
                    [self.blob_manager.get_blob(self.stream.sd_hash)])))
        send_more = await self.stream.upload_to_reflector('127.0.0.1', 5566)
        self.assertEqual(len(send_more), 0)
        self.assertTrue(self.stream.is_fully_reflected)
        server_sd_blob = self.server_blob_manager.get_blob(self.stream.sd_hash)
        self.assertTrue(server_sd_blob.get_is_verified())
        self.assertEqual(server_sd_blob.length, server_sd_blob.length)
        for blob in self.stream.descriptor.blobs[:-1]:
            server_blob = self.server_blob_manager.get_blob(blob.blob_hash)
            self.assertTrue(server_blob.get_is_verified())
            self.assertEqual(server_blob.length, blob.length)

        sent = await self.stream.upload_to_reflector('127.0.0.1', 5566)
        self.assertListEqual(sent, [])
Example #5
0
 async def test_result_from_disconnect_mid_sd_transfer(self):
     stop = asyncio.Event()
     incoming = asyncio.Event()
     reflector = ReflectorServer(self.server_blob_manager,
                                 response_chunk_size=50,
                                 stop_event=stop,
                                 incoming_event=incoming)
     reflector.start_server(5566, '127.0.0.1')
     await reflector.started_listening.wait()
     self.addCleanup(reflector.stop_server)
     self.assertEqual(0, self.stream.reflector_progress)
     reflect_task = asyncio.create_task(
         self.stream.upload_to_reflector('127.0.0.1', 5566))
     await incoming.wait()
     stop.set()
     # this used to raise (and then propagate) a CancelledError
     self.assertListEqual(await reflect_task, [])
     self.assertFalse(self.stream.is_fully_reflected)
Example #6
0
class CommandTestCase(IntegrationTestCase):

    VERBOSITY = logging.WARN
    blob_lru_cache_size = 0

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.daemon = None
        self.daemons = []
        self.server_config = None
        self.server_storage = None
        self.extra_wallet_nodes = []
        self.extra_wallet_node_port = 5280
        self.server_blob_manager = None
        self.server = None
        self.reflector = None

    async def asyncSetUp(self):
        await super().asyncSetUp()

        logging.getLogger('lbry.blob_exchange').setLevel(self.VERBOSITY)
        logging.getLogger('lbry.daemon').setLevel(self.VERBOSITY)
        logging.getLogger('lbry.stream').setLevel(self.VERBOSITY)
        logging.getLogger('lbry.wallet').setLevel(self.VERBOSITY)

        self.daemon = await self.add_daemon(self.wallet_node)

        await self.account.ensure_address_gap()
        address = (await
                   self.account.receiving.get_addresses(limit=1,
                                                        only_usable=True))[0]
        sendtxid = await self.blockchain.send_to_address(address, 10)
        await self.confirm_tx(sendtxid)
        await self.generate(5)

        server_tmp_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, server_tmp_dir)
        self.server_config = Config()
        self.server_storage = SQLiteStorage(self.server_config, ':memory:')
        await self.server_storage.open()

        self.server_blob_manager = BlobManager(self.loop, server_tmp_dir,
                                               self.server_storage,
                                               self.server_config)
        self.server = BlobServer(self.loop, self.server_blob_manager,
                                 'bQEaw42GXsgCAGio1nxFncJSyRmnztSCjP')
        self.server.start_server(5567, '127.0.0.1')
        await self.server.started_listening.wait()

        self.reflector = ReflectorServer(self.server_blob_manager)
        self.reflector.start_server(5566, '127.0.0.1')
        await self.reflector.started_listening.wait()
        self.addCleanup(self.reflector.stop_server)

    async def asyncTearDown(self):
        await super().asyncTearDown()
        for wallet_node in self.extra_wallet_nodes:
            await wallet_node.stop(cleanup=True)
        for daemon in self.daemons:
            daemon.component_manager.get_component('wallet')._running = False
            await daemon.stop()

    async def add_daemon(self, wallet_node=None, seed=None):
        if wallet_node is None:
            wallet_node = WalletNode(self.wallet_node.manager_class,
                                     self.wallet_node.ledger_class,
                                     port=self.extra_wallet_node_port)
            self.extra_wallet_node_port += 1
            await wallet_node.start(self.conductor.spv_node, seed=seed)
            self.extra_wallet_nodes.append(wallet_node)

        upload_dir = os.path.join(wallet_node.data_path, 'uploads')
        os.mkdir(upload_dir)

        conf = Config()
        conf.data_dir = wallet_node.data_path
        conf.wallet_dir = wallet_node.data_path
        conf.download_dir = wallet_node.data_path
        conf.upload_dir = upload_dir  # not a real conf setting
        conf.share_usage_data = False
        conf.use_upnp = False
        conf.reflect_streams = True
        conf.blockchain_name = 'lbrycrd_regtest'
        conf.lbryum_servers = [('127.0.0.1', 50001)]
        conf.reflector_servers = [('127.0.0.1', 5566)]
        conf.known_dht_nodes = []
        conf.blob_lru_cache_size = self.blob_lru_cache_size
        conf.components_to_skip = [
            DHT_COMPONENT, UPNP_COMPONENT, HASH_ANNOUNCER_COMPONENT,
            PEER_PROTOCOL_SERVER_COMPONENT
        ]
        wallet_node.manager.config = conf

        def wallet_maker(component_manager):
            wallet_component = WalletComponent(component_manager)
            wallet_component.wallet_manager = wallet_node.manager
            wallet_component._running = True
            return wallet_component

        daemon = Daemon(
            conf,
            ComponentManager(conf,
                             skip_components=conf.components_to_skip,
                             wallet=wallet_maker,
                             exchange_rate_manager=partial(
                                 ExchangeRateManagerComponent,
                                 rates={
                                     'BTCLBC': 1.0,
                                     'USDBTC': 2.0
                                 })))
        await daemon.initialize()
        self.daemons.append(daemon)
        wallet_node.manager.old_db = daemon.storage
        return daemon

    async def confirm_tx(self, txid, ledger=None):
        """ Wait for tx to be in mempool, then generate a block, wait for tx to be in a block. """
        await self.on_transaction_id(txid, ledger)
        await self.generate(1)
        await self.on_transaction_id(txid, ledger)
        return txid

    async def on_transaction_dict(self, tx):
        await self.ledger.wait(Transaction(unhexlify(tx['hex'])))

    @staticmethod
    def get_all_addresses(tx):
        addresses = set()
        for txi in tx['inputs']:
            addresses.add(txi['address'])
        for txo in tx['outputs']:
            addresses.add(txo['address'])
        return list(addresses)

    async def generate(self, blocks):
        """ Ask lbrycrd to generate some blocks and wait until ledger has them. """
        await self.blockchain.generate(blocks)
        await self.ledger.on_header.where(self.blockchain.is_expected_block)

    async def blockchain_claim_name(self,
                                    name: str,
                                    value: str,
                                    amount: str,
                                    confirm=True):
        txid = await self.blockchain._cli_cmnd('claimname', name, value,
                                               amount)
        if confirm:
            await self.generate(1)
        return txid

    async def blockchain_update_name(self,
                                     txid: str,
                                     value: str,
                                     amount: str,
                                     confirm=True):
        txid = await self.blockchain._cli_cmnd('updateclaim', txid, value,
                                               amount)
        if confirm:
            await self.generate(1)
        return txid

    async def out(self, awaitable):
        """ Serializes lbrynet API results to JSON then loads and returns it as dictionary. """
        return json.loads(
            jsonrpc_dumps_pretty(await awaitable,
                                 ledger=self.ledger))['result']

    def sout(self, value):
        """ Synchronous version of `out` method. """
        return json.loads(jsonrpc_dumps_pretty(value,
                                               ledger=self.ledger))['result']

    async def confirm_and_render(self, awaitable, confirm) -> Transaction:
        tx = await awaitable
        if confirm:
            await self.ledger.wait(tx)
            await self.generate(1)
            await self.ledger.wait(tx, self.blockchain.block_expected)
        return self.sout(tx)

    def create_upload_file(self, data, prefix=None, suffix=None):
        file_path = tempfile.mktemp(prefix=prefix or "tmp",
                                    suffix=suffix or "",
                                    dir=self.daemon.conf.upload_dir)
        with open(file_path, 'w+b') as file:
            file.write(data)
            file.flush()
            return file.name

    async def stream_create(self,
                            name='hovercraft',
                            bid='1.0',
                            file_path=None,
                            data=b'hi!',
                            confirm=True,
                            prefix=None,
                            suffix=None,
                            **kwargs):
        if file_path is None:
            file_path = self.create_upload_file(data=data,
                                                prefix=prefix,
                                                suffix=suffix)
        return await self.confirm_and_render(
            self.daemon.jsonrpc_stream_create(name,
                                              bid,
                                              file_path=file_path,
                                              **kwargs), confirm)

    async def stream_update(self,
                            claim_id,
                            data=None,
                            prefix=None,
                            suffix=None,
                            confirm=True,
                            **kwargs):
        if data is not None:
            file_path = self.create_upload_file(data=data,
                                                prefix=prefix,
                                                suffix=suffix)
            return await self.confirm_and_render(
                self.daemon.jsonrpc_stream_update(claim_id,
                                                  file_path=file_path,
                                                  **kwargs), confirm)
        return await self.confirm_and_render(
            self.daemon.jsonrpc_stream_update(claim_id, **kwargs), confirm)

    def stream_repost(self,
                      claim_id,
                      name='repost',
                      bid='1.0',
                      confirm=True,
                      **kwargs):
        return self.confirm_and_render(
            self.daemon.jsonrpc_stream_repost(claim_id=claim_id,
                                              name=name,
                                              bid=bid,
                                              **kwargs), confirm)

    async def stream_abandon(self, *args, confirm=True, **kwargs):
        if 'blocking' not in kwargs:
            kwargs['blocking'] = False
        return await self.confirm_and_render(
            self.daemon.jsonrpc_stream_abandon(*args, **kwargs), confirm)

    async def publish(self, name, *args, confirm=True, **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_publish(name, *args, **kwargs), confirm)

    async def channel_create(self,
                             name='@arena',
                             bid='1.0',
                             confirm=True,
                             **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_channel_create(name, bid, **kwargs), confirm)

    async def channel_update(self, claim_id, confirm=True, **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_channel_update(claim_id, **kwargs), confirm)

    async def channel_abandon(self, *args, confirm=True, **kwargs):
        if 'blocking' not in kwargs:
            kwargs['blocking'] = False
        return await self.confirm_and_render(
            self.daemon.jsonrpc_channel_abandon(*args, **kwargs), confirm)

    async def collection_create(self,
                                name='firstcollection',
                                bid='1.0',
                                confirm=True,
                                **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_collection_create(name, bid, **kwargs),
            confirm)

    async def collection_update(self, claim_id, confirm=True, **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_collection_update(claim_id, **kwargs), confirm)

    async def collection_abandon(self, *args, confirm=True, **kwargs):
        if 'blocking' not in kwargs:
            kwargs['blocking'] = False
        return await self.confirm_and_render(
            self.daemon.jsonrpc_stream_abandon(*args, **kwargs), confirm)

    async def support_create(self,
                             claim_id,
                             bid='1.0',
                             confirm=True,
                             **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_support_create(claim_id, bid, **kwargs),
            confirm)

    async def resolve(self, uri):
        return (await self.out(self.daemon.jsonrpc_resolve(uri)))[uri]

    async def claim_search(self, **kwargs):
        return (await
                self.out(self.daemon.jsonrpc_claim_search(**kwargs)))['items']

    async def file_list(self, *args, **kwargs):
        return (await
                self.out(self.daemon.jsonrpc_file_list(*args,
                                                       **kwargs)))['items']

    async def claim_list(self, *args, **kwargs):
        return (await
                self.out(self.daemon.jsonrpc_claim_list(*args,
                                                        **kwargs)))['items']

    async def stream_list(self, *args, **kwargs):
        return (await
                self.out(self.daemon.jsonrpc_stream_list(*args,
                                                         **kwargs)))['items']

    async def channel_list(self, *args, **kwargs):
        return (await
                self.out(self.daemon.jsonrpc_channel_list(*args,
                                                          **kwargs)))['items']

    @staticmethod
    def get_claim_id(tx):
        return tx['outputs'][0]['claim_id']

    def assertItemCount(self, result, count):  # pylint: disable=invalid-name
        self.assertEqual(count, result['total_items'])
Example #7
0
class CommandTestCase(IntegrationTestCase):

    LEDGER = lbry.wallet
    MANAGER = LbryWalletManager
    VERBOSITY = logging.WARN
    blob_lru_cache_size = 0

    account: Account

    async def asyncSetUp(self):
        await super().asyncSetUp()

        logging.getLogger('lbry.blob_exchange').setLevel(self.VERBOSITY)
        logging.getLogger('lbry.daemon').setLevel(self.VERBOSITY)
        logging.getLogger('lbry.stream').setLevel(self.VERBOSITY)

        self.daemons = []
        self.extra_wallet_nodes = []
        self.extra_wallet_node_port = 5280
        self.daemon = await self.add_daemon(self.wallet_node)

        await self.account.ensure_address_gap()
        address = (await
                   self.account.receiving.get_addresses(limit=1,
                                                        only_usable=True))[0]
        sendtxid = await self.blockchain.send_to_address(address, 10)
        await self.confirm_tx(sendtxid)
        await self.generate(5)

        server_tmp_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, server_tmp_dir)
        self.server_config = Config()
        self.server_storage = SQLiteStorage(self.server_config, ':memory:')
        await self.server_storage.open()

        self.server_blob_manager = BlobManager(self.loop, server_tmp_dir,
                                               self.server_storage,
                                               self.server_config)
        self.server = BlobServer(self.loop, self.server_blob_manager,
                                 'bQEaw42GXsgCAGio1nxFncJSyRmnztSCjP')
        self.server.start_server(5567, '127.0.0.1')
        await self.server.started_listening.wait()

        self.reflector = ReflectorServer(self.server_blob_manager)
        self.reflector.start_server(5566, '127.0.0.1')
        await self.reflector.started_listening.wait()
        self.addCleanup(self.reflector.stop_server)

    async def asyncTearDown(self):
        await super().asyncTearDown()
        for wallet_node in self.extra_wallet_nodes:
            await wallet_node.stop(cleanup=True)
        for daemon in self.daemons:
            daemon.component_manager.get_component('wallet')._running = False
            await daemon.stop(shutdown_runner=False)

    async def add_daemon(self, wallet_node=None, seed=None):
        if wallet_node is None:
            wallet_node = WalletNode(self.wallet_node.manager_class,
                                     self.wallet_node.ledger_class,
                                     port=self.extra_wallet_node_port)
            self.extra_wallet_node_port += 1
            await wallet_node.start(self.conductor.spv_node, seed=seed)
            self.extra_wallet_nodes.append(wallet_node)

        conf = Config()
        conf.data_dir = wallet_node.data_path
        conf.wallet_dir = wallet_node.data_path
        conf.download_dir = wallet_node.data_path
        conf.share_usage_data = False
        conf.use_upnp = False
        conf.reflect_streams = True
        conf.blockchain_name = 'lbrycrd_regtest'
        conf.lbryum_servers = [('127.0.0.1', 50001)]
        conf.reflector_servers = [('127.0.0.1', 5566)]
        conf.known_dht_nodes = []
        conf.blob_lru_cache_size = self.blob_lru_cache_size
        conf.components_to_skip = [
            DHT_COMPONENT, UPNP_COMPONENT, HASH_ANNOUNCER_COMPONENT,
            PEER_PROTOCOL_SERVER_COMPONENT
        ]

        def wallet_maker(component_manager):
            wallet_component = WalletComponent(component_manager)
            wallet_component.wallet_manager = wallet_node.manager
            wallet_component._running = True
            return wallet_component

        daemon = Daemon(
            conf,
            ComponentManager(
                conf,
                skip_components=conf.components_to_skip,
                wallet=wallet_maker,
                exchange_rate_manager=ExchangeRateManagerComponent))
        await daemon.initialize()
        self.daemons.append(daemon)
        wallet_node.manager.old_db = daemon.storage
        return daemon

    async def confirm_tx(self, txid):
        """ Wait for tx to be in mempool, then generate a block, wait for tx to be in a block. """
        await self.on_transaction_id(txid)
        await self.generate(1)
        await self.on_transaction_id(txid)

    async def on_transaction_dict(self, tx):
        await self.ledger.wait(
            self.ledger.transaction_class(unhexlify(tx['hex'])))

    @staticmethod
    def get_all_addresses(tx):
        addresses = set()
        for txi in tx['inputs']:
            addresses.add(txi['address'])
        for txo in tx['outputs']:
            addresses.add(txo['address'])
        return list(addresses)

    async def generate(self, blocks):
        """ Ask lbrycrd to generate some blocks and wait until ledger has them. """
        await self.blockchain.generate(blocks)
        await self.ledger.on_header.where(self.blockchain.is_expected_block)

    async def blockchain_claim_name(self,
                                    name: str,
                                    value: str,
                                    amount: str,
                                    confirm=True):
        txid = await self.blockchain._cli_cmnd('claimname', name, value,
                                               amount)
        if confirm:
            await self.generate(1)
        return txid

    async def blockchain_update_name(self,
                                     txid: str,
                                     value: str,
                                     amount: str,
                                     confirm=True):
        txid = await self.blockchain._cli_cmnd('updateclaim', txid, value,
                                               amount)
        if confirm:
            await self.generate(1)
        return txid

    async def out(self, awaitable):
        """ Serializes lbrynet API results to JSON then loads and returns it as dictionary. """
        return json.loads(
            jsonrpc_dumps_pretty(await awaitable,
                                 ledger=self.ledger))['result']

    def sout(self, value):
        """ Synchronous version of `out` method. """
        return json.loads(jsonrpc_dumps_pretty(value,
                                               ledger=self.ledger))['result']

    async def stream_create(self,
                            name='hovercraft',
                            bid='1.0',
                            data=b'hi!',
                            confirm=True,
                            **kwargs):
        file = tempfile.NamedTemporaryFile()

        def cleanup():
            try:
                file.close()
            except FileNotFoundError:
                pass

        self.addCleanup(cleanup)
        file.write(data)
        file.flush()
        claim = await self.out(
            self.daemon.jsonrpc_stream_create(name,
                                              bid,
                                              file_path=file.name,
                                              **kwargs))
        self.assertEqual(claim['outputs'][0]['name'], name)
        if confirm:
            await self.on_transaction_dict(claim)
            await self.generate(1)
            await self.on_transaction_dict(claim)
        return claim

    async def stream_update(self, claim_id, data=None, confirm=True, **kwargs):
        if data:
            file = tempfile.NamedTemporaryFile()
            file.write(data)
            file.flush()

            def cleanup():
                try:
                    file.close()
                except FileNotFoundError:
                    pass

            self.addCleanup(cleanup)
            claim = await self.out(
                self.daemon.jsonrpc_stream_update(claim_id,
                                                  file_path=file.name,
                                                  **kwargs))
        else:
            claim = await self.out(
                self.daemon.jsonrpc_stream_update(claim_id, **kwargs))
        self.assertIsNotNone(claim['outputs'][0]['name'])
        if confirm:
            await self.on_transaction_dict(claim)
            await self.generate(1)
            await self.on_transaction_dict(claim)
        return claim

    async def stream_abandon(self, *args, confirm=True, **kwargs):
        if 'blocking' not in kwargs:
            kwargs['blocking'] = False
        tx = await self.out(self.daemon.jsonrpc_stream_abandon(
            *args, **kwargs))
        if confirm:
            await self.on_transaction_dict(tx)
            await self.generate(1)
            await self.on_transaction_dict(tx)
        return tx

    async def publish(self, name, *args, confirm=True, **kwargs):
        claim = await self.out(
            self.daemon.jsonrpc_publish(name, *args, **kwargs))
        self.assertEqual(claim['outputs'][0]['name'], name)
        if confirm:
            await self.on_transaction_dict(claim)
            await self.generate(1)
            await self.on_transaction_dict(claim)
        return claim

    async def channel_create(self,
                             name='@arena',
                             bid='1.0',
                             confirm=True,
                             **kwargs):
        channel = await self.out(
            self.daemon.jsonrpc_channel_create(name, bid, **kwargs))
        self.assertEqual(channel['outputs'][0]['name'], name)
        if confirm:
            await self.on_transaction_dict(channel)
            await self.generate(1)
            await self.on_transaction_dict(channel)
        return channel

    async def channel_update(self, claim_id, confirm=True, **kwargs):
        channel = await self.out(
            self.daemon.jsonrpc_channel_update(claim_id, **kwargs))
        self.assertTrue(channel['outputs'][0]['name'].startswith('@'))
        if confirm:
            await self.on_transaction_dict(channel)
            await self.generate(1)
            await self.on_transaction_dict(channel)
        return channel

    async def channel_abandon(self, *args, confirm=True, **kwargs):
        if 'blocking' not in kwargs:
            kwargs['blocking'] = False
        tx = await self.out(
            self.daemon.jsonrpc_channel_abandon(*args, **kwargs))
        if confirm:
            await self.on_transaction_dict(tx)
            await self.generate(1)
            await self.on_transaction_dict(tx)
        return tx

    async def support_create(self,
                             claim_id,
                             bid='1.0',
                             confirm=True,
                             **kwargs):
        tx = await self.out(
            self.daemon.jsonrpc_support_create(claim_id, bid, **kwargs))
        if confirm:
            await self.on_transaction_dict(tx)
            await self.generate(1)
            await self.on_transaction_dict(tx)
        return tx

    async def resolve(self, uri):
        return await self.out(self.daemon.jsonrpc_resolve(uri))

    async def claim_search(self, **kwargs):
        return (await
                self.out(self.daemon.jsonrpc_claim_search(**kwargs)))['items']

    @staticmethod
    def get_claim_id(tx):
        return tx['outputs'][0]['claim_id']
Example #8
0
class CommandTestCase(IntegrationTestCase):

    VERBOSITY = logging.WARN
    blob_lru_cache_size = 0

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.daemon = None
        self.daemons = []
        self.server_config = None
        self.server_storage = None
        self.extra_wallet_nodes = []
        self.extra_wallet_node_port = 5280
        self.server_blob_manager = None
        self.server = None
        self.reflector = None
        self.skip_libtorrent = True

    async def asyncSetUp(self):

        logging.getLogger('lbry.blob_exchange').setLevel(self.VERBOSITY)
        logging.getLogger('lbry.daemon').setLevel(self.VERBOSITY)
        logging.getLogger('lbry.stream').setLevel(self.VERBOSITY)
        logging.getLogger('lbry.wallet').setLevel(self.VERBOSITY)

        await super().asyncSetUp()

        self.daemon = await self.add_daemon(self.wallet_node)

        await self.account.ensure_address_gap()
        address = (await self.account.receiving.get_addresses(limit=1, only_usable=True))[0]
        await self.send_to_address_and_wait(address, 10, 6)

        server_tmp_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, server_tmp_dir)
        self.server_config = Config(
            data_dir=server_tmp_dir,
            wallet_dir=server_tmp_dir,
            save_files=True,
            download_dir=server_tmp_dir
        )
        self.server_config.transaction_cache_size = 10000
        self.server_storage = SQLiteStorage(self.server_config, ':memory:')
        await self.server_storage.open()

        self.server_blob_manager = BlobManager(self.loop, server_tmp_dir, self.server_storage, self.server_config)
        self.server = BlobServer(self.loop, self.server_blob_manager, 'bQEaw42GXsgCAGio1nxFncJSyRmnztSCjP')
        self.server.start_server(5567, '127.0.0.1')
        await self.server.started_listening.wait()

        self.reflector = ReflectorServer(self.server_blob_manager)
        self.reflector.start_server(5566, '127.0.0.1')
        await self.reflector.started_listening.wait()
        self.addCleanup(self.reflector.stop_server)

    async def asyncTearDown(self):
        await super().asyncTearDown()
        for wallet_node in self.extra_wallet_nodes:
            await wallet_node.stop(cleanup=True)
        for daemon in self.daemons:
            daemon.component_manager.get_component('wallet')._running = False
            await daemon.stop()

    async def add_daemon(self, wallet_node=None, seed=None):
        start_wallet_node = False
        if wallet_node is None:
            wallet_node = WalletNode(
                self.wallet_node.manager_class,
                self.wallet_node.ledger_class,
                port=self.extra_wallet_node_port
            )
            self.extra_wallet_node_port += 1
            start_wallet_node = True

        upload_dir = os.path.join(wallet_node.data_path, 'uploads')
        os.mkdir(upload_dir)

        conf = Config(
            # needed during instantiation to access known_hubs path
            data_dir=wallet_node.data_path,
            wallet_dir=wallet_node.data_path,
            save_files=True,
            download_dir=wallet_node.data_path
        )
        conf.upload_dir = upload_dir  # not a real conf setting
        conf.share_usage_data = False
        conf.use_upnp = False
        conf.reflect_streams = True
        conf.blockchain_name = 'lbrycrd_regtest'
        conf.lbryum_servers = [(self.conductor.spv_node.hostname, self.conductor.spv_node.port)]
        conf.reflector_servers = [('127.0.0.1', 5566)]
        conf.fixed_peers = [('127.0.0.1', 5567)]
        conf.known_dht_nodes = []
        conf.blob_lru_cache_size = self.blob_lru_cache_size
        conf.transaction_cache_size = 10000
        conf.components_to_skip = [
            DHT_COMPONENT, UPNP_COMPONENT, HASH_ANNOUNCER_COMPONENT,
            PEER_PROTOCOL_SERVER_COMPONENT
        ]
        if self.skip_libtorrent:
            conf.components_to_skip.append(LIBTORRENT_COMPONENT)

        if start_wallet_node:
            await wallet_node.start(self.conductor.spv_node, seed=seed, config=conf)
            self.extra_wallet_nodes.append(wallet_node)
        else:
            wallet_node.manager.config = conf
            wallet_node.manager.ledger.config['known_hubs'] = conf.known_hubs

        def wallet_maker(component_manager):
            wallet_component = WalletComponent(component_manager)
            wallet_component.wallet_manager = wallet_node.manager
            wallet_component._running = True
            return wallet_component

        daemon = Daemon(conf, ComponentManager(
            conf, skip_components=conf.components_to_skip, wallet=wallet_maker,
            exchange_rate_manager=partial(ExchangeRateManagerComponent, rates={
                'BTCLBC': 1.0, 'USDLBC': 2.0
            })
        ))
        await daemon.initialize()
        self.daemons.append(daemon)
        wallet_node.manager.old_db = daemon.storage
        return daemon

    async def confirm_tx(self, txid, ledger=None):
        """ Wait for tx to be in mempool, then generate a block, wait for tx to be in a block. """
        # await (ledger or self.ledger).on_transaction.where(lambda e: e.tx.id == txid)
        on_tx = (ledger or self.ledger).on_transaction.where(lambda e: e.tx.id == txid)
        await asyncio.wait([self.generate(1), on_tx], timeout=5)

        # # actually, if it's in the mempool or in the block we're fine
        # await self.generate_and_wait(1, [txid], ledger=ledger)
        # return txid

        return txid

    async def on_transaction_dict(self, tx):
        await self.ledger.wait(Transaction(unhexlify(tx['hex'])))

    @staticmethod
    def get_all_addresses(tx):
        addresses = set()
        for txi in tx['inputs']:
            addresses.add(txi['address'])
        for txo in tx['outputs']:
            addresses.add(txo['address'])
        return list(addresses)

    async def blockchain_claim_name(self, name: str, value: str, amount: str, confirm=True):
        txid = await self.blockchain._cli_cmnd('claimname', name, value, amount)
        if confirm:
            await self.generate(1)
        return txid

    async def blockchain_update_name(self, txid: str, value: str, amount: str, confirm=True):
        txid = await self.blockchain._cli_cmnd('updateclaim', txid, value, amount)
        if confirm:
            await self.generate(1)
        return txid

    async def out(self, awaitable):
        """ Serializes lbrynet API results to JSON then loads and returns it as dictionary. """
        return json.loads(jsonrpc_dumps_pretty(await awaitable, ledger=self.ledger))['result']

    def sout(self, value):
        """ Synchronous version of `out` method. """
        return json.loads(jsonrpc_dumps_pretty(value, ledger=self.ledger))['result']

    async def confirm_and_render(self, awaitable, confirm, return_tx=False) -> Transaction:
        tx = await awaitable
        if confirm:
            await self.ledger.wait(tx)
            await self.generate(1)
            await self.ledger.wait(tx, self.blockchain.block_expected)
        if not return_tx:
            return self.sout(tx)
        return tx

    async def create_nondeterministic_channel(self, name, price, pubkey_bytes, daemon=None, blocking=False):
        account = (daemon or self.daemon).wallet_manager.default_account
        claim_address = await account.receiving.get_or_create_usable_address()
        claim = Claim()
        claim.channel.public_key_bytes = pubkey_bytes
        tx = await Transaction.claim_create(
            name, claim, lbc_to_dewies(price),
            claim_address, [self.account], self.account
        )
        await tx.sign([self.account])
        await (daemon or self.daemon).broadcast_or_release(tx, blocking)
        return self.sout(tx)

    def create_upload_file(self, data, prefix=None, suffix=None):
        file_path = tempfile.mktemp(prefix=prefix or "tmp", suffix=suffix or "", dir=self.daemon.conf.upload_dir)
        with open(file_path, 'w+b') as file:
            file.write(data)
            file.flush()
            return file.name

    async def stream_create(
            self, name='hovercraft', bid='1.0', file_path=None,
            data=b'hi!', confirm=True, prefix=None, suffix=None, return_tx=False, **kwargs):
        if file_path is None and data is not None:
            file_path = self.create_upload_file(data=data, prefix=prefix, suffix=suffix)
        return await self.confirm_and_render(
            self.daemon.jsonrpc_stream_create(name, bid, file_path=file_path, **kwargs), confirm, return_tx
        )

    async def stream_update(
            self, claim_id, data=None, prefix=None, suffix=None, confirm=True, return_tx=False, **kwargs):
        if data is not None:
            file_path = self.create_upload_file(data=data, prefix=prefix, suffix=suffix)
            return await self.confirm_and_render(
                self.daemon.jsonrpc_stream_update(claim_id, file_path=file_path, **kwargs), confirm, return_tx
            )
        return await self.confirm_and_render(
            self.daemon.jsonrpc_stream_update(claim_id, **kwargs), confirm
        )

    async def stream_repost(self, claim_id, name='repost', bid='1.0', confirm=True, **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_stream_repost(claim_id=claim_id, name=name, bid=bid, **kwargs), confirm
        )

    async def stream_abandon(self, *args, confirm=True, **kwargs):
        if 'blocking' not in kwargs:
            kwargs['blocking'] = False
        return await self.confirm_and_render(
            self.daemon.jsonrpc_stream_abandon(*args, **kwargs), confirm
        )

    async def purchase_create(self, *args, confirm=True, **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_purchase_create(*args, **kwargs), confirm
        )

    async def publish(self, name, *args, confirm=True, **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_publish(name, *args, **kwargs), confirm
        )

    async def channel_create(self, name='@arena', bid='1.0', confirm=True, **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_channel_create(name, bid, **kwargs), confirm
        )

    async def channel_update(self, claim_id, confirm=True, **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_channel_update(claim_id, **kwargs), confirm
        )

    async def channel_abandon(self, *args, confirm=True, **kwargs):
        if 'blocking' not in kwargs:
            kwargs['blocking'] = False
        return await self.confirm_and_render(
            self.daemon.jsonrpc_channel_abandon(*args, **kwargs), confirm
        )

    async def collection_create(
            self, name='firstcollection', bid='1.0', confirm=True, **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_collection_create(name, bid, **kwargs), confirm
        )

    async def collection_update(
            self, claim_id, confirm=True, **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_collection_update(claim_id, **kwargs), confirm
        )

    async def collection_abandon(self, *args, confirm=True, **kwargs):
        if 'blocking' not in kwargs:
            kwargs['blocking'] = False
        return await self.confirm_and_render(
            self.daemon.jsonrpc_stream_abandon(*args, **kwargs), confirm
        )

    async def support_create(self, claim_id, bid='1.0', confirm=True, **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_support_create(claim_id, bid, **kwargs), confirm
        )

    async def support_abandon(self, *args, confirm=True, **kwargs):
        if 'blocking' not in kwargs:
            kwargs['blocking'] = False
        return await self.confirm_and_render(
            self.daemon.jsonrpc_support_abandon(*args, **kwargs), confirm
        )

    async def account_send(self, *args, confirm=True, **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_account_send(*args, **kwargs), confirm
        )

    async def wallet_send(self, *args, confirm=True, **kwargs):
        return await self.confirm_and_render(
            self.daemon.jsonrpc_wallet_send(*args, **kwargs), confirm
        )

    async def txo_spend(self, *args, confirm=True, **kwargs):
        txs = await self.daemon.jsonrpc_txo_spend(*args, **kwargs)
        if confirm:
            await asyncio.wait([self.ledger.wait(tx) for tx in txs])
            await self.generate(1)
            await asyncio.wait([self.ledger.wait(tx, self.blockchain.block_expected) for tx in txs])
        return self.sout(txs)

    async def blob_clean(self):
        return await self.out(self.daemon.jsonrpc_blob_clean())

    async def status(self):
        return await self.out(self.daemon.jsonrpc_status())

    async def resolve(self, uri, **kwargs):
        return (await self.out(self.daemon.jsonrpc_resolve(uri, **kwargs)))[uri]

    async def claim_search(self, **kwargs):
        return (await self.out(self.daemon.jsonrpc_claim_search(**kwargs)))['items']

    async def get_claim_by_claim_id(self, claim_id):
        return await self.out(self.ledger.get_claim_by_claim_id(claim_id))

    async def file_list(self, *args, **kwargs):
        return (await self.out(self.daemon.jsonrpc_file_list(*args, **kwargs)))['items']

    async def txo_list(self, *args, **kwargs):
        return (await self.out(self.daemon.jsonrpc_txo_list(*args, **kwargs)))['items']

    async def txo_sum(self, *args, **kwargs):
        return await self.out(self.daemon.jsonrpc_txo_sum(*args, **kwargs))

    async def txo_plot(self, *args, **kwargs):
        return await self.out(self.daemon.jsonrpc_txo_plot(*args, **kwargs))

    async def claim_list(self, *args, **kwargs):
        return (await self.out(self.daemon.jsonrpc_claim_list(*args, **kwargs)))['items']

    async def stream_list(self, *args, **kwargs):
        return (await self.out(self.daemon.jsonrpc_stream_list(*args, **kwargs)))['items']

    async def channel_list(self, *args, **kwargs):
        return (await self.out(self.daemon.jsonrpc_channel_list(*args, **kwargs)))['items']

    async def transaction_list(self, *args, **kwargs):
        return (await self.out(self.daemon.jsonrpc_transaction_list(*args, **kwargs)))['items']

    async def blob_list(self, *args, **kwargs):
        return (await self.out(self.daemon.jsonrpc_blob_list(*args, **kwargs)))['items']

    @staticmethod
    def get_claim_id(tx):
        return tx['outputs'][0]['claim_id']

    def assertItemCount(self, result, count):  # pylint: disable=invalid-name
        self.assertEqual(count, result['total_items'])