示例#1
0
def builder(ctx: Context):  # pragma: no cover
    from spruned.application.cache import CacheAgent
    from spruned.repositories.repository import Repository
    from spruned.daemon.tasks.blocks_reactor import BlocksReactor
    from spruned.daemon.tasks.headers_reactor import HeadersReactor
    from spruned.application import spruned_vo_service
    from spruned.application.jsonrpc_server import JSONRPCServer
    from spruned.daemon.electrod import build as electrod_builder
    from spruned.daemon.bitcoin_p2p import build as p2p_builder

    electrod_connectionpool, electrod_interface = electrod_builder(ctx)
    p2p_connectionpool, p2p_interface = p2p_builder(ctx.get_network())

    repository = Repository.instance()
    cache = CacheAgent(repository, int(ctx.cache_size))
    repository.set_cache(cache)

    service = spruned_vo_service.SprunedVOService(electrod_interface,
                                                  p2p_interface,
                                                  repository=repository,
                                                  cache=cache)
    jsonrpc_server = JSONRPCServer(ctx.rpcbind, ctx.rpcport, ctx.rpcuser,
                                   ctx.rpcpassword)
    jsonrpc_server.set_vo_service(service)
    headers_reactor = HeadersReactor(repository.headers, electrod_interface)
    blocks_reactor = BlocksReactor(repository,
                                   p2p_interface,
                                   prune=int(ctx.keep_blocks))
    return jsonrpc_server, headers_reactor, blocks_reactor, repository, cache
示例#2
0
class TestJSONRPCServerSendrawtransaction(TestCase):
    def setUp(self):
        bindport = random.randint(11337, 41337)
        self.sut = JSONRPCServer('127.0.0.1', bindport, 'testuser',
                                 'testpassword')
        self.vo_service = Mock()
        self.sut.set_vo_service(self.vo_service)
        self.client = JSONClient(b'testuser', b'testpassword', '127.0.0.1',
                                 bindport)
        self.loop = asyncio.get_event_loop()

    def test_sendrawtransaction_success(self):
        self.vo_service.sendrawtransaction.side_effect = [
            async_coro(
                'bedf6b43cf9a9278b8637d89f378a8f25b8f0e1be729325f7eea74a3096d9520'
            )
        ]

        async def test():
            await self.sut.start()
            response = await self.client.call('sendrawtransaction',
                                              params=['cafebabe'])
            return response

        res = self.loop.run_until_complete(test())
        self.assertEqual(
            res, {
                'error':
                None,
                'id':
                1,
                'jsonrpc':
                '2.0',
                'result':
                'bedf6b43cf9a9278b8637d89f378a8f25b8f0e1be729325f7eea74a3096d9520'
            })

    def test_getrawtransaction_error_decode(self):
        async def test():
            await self.sut.start()
            response = await self.client.call('sendrawtransaction',
                                              params=["nonhex"])
            return response

        res = self.loop.run_until_complete(test())
        self.assertEqual(
            res, {
                'error': {
                    'code': -22,
                    'message': 'TX decode failed'
                },
                'id': 1,
                'jsonrpc': '2.0',
                'result': None
            })
        Mock.assert_not_called(self.vo_service.getblock)
示例#3
0
def builder(ctx: Context):  # pragma: no cover
    from spruned.application.cache import CacheAgent
    from spruned.repositories.repository import Repository
    from spruned.daemon.tasks.blocks_reactor import BlocksReactor
    from spruned.daemon.tasks.headers_reactor import HeadersReactor
    from spruned.application import spruned_vo_service
    from spruned.application.jsonrpc_server import JSONRPCServer
    from spruned.daemon.electrod import build as electrod_builder
    from spruned.daemon.bitcoin_p2p import build as p2p_builder

    electrod_connectionpool, electrod_interface = electrod_builder(ctx)
    p2p_connectionpool, p2p_interface = p2p_builder(ctx)
    repository = Repository.instance()
    cache = CacheAgent(repository, int(ctx.cache_size))
    repository.set_cache(cache)
    service = spruned_vo_service.SprunedVOService(
        electrod_interface,
        p2p_interface,
        repository=repository,
        cache_agent=cache,
        context=ctx,
        fallback_non_segwit_blocks=True)
    jsonrpc_server = JSONRPCServer(ctx.rpcbind, ctx.rpcport, ctx.rpcuser,
                                   ctx.rpcpassword)
    jsonrpc_server.set_vo_service(service)
    headers_reactor = HeadersReactor(repository.headers, electrod_interface)

    if ctx.mempool_size:
        from spruned.application.mempool_observer import MempoolObserver
        mempool_observer = MempoolObserver(repository, p2p_interface)
        headers_reactor.add_on_new_header_callback(
            mempool_observer.on_block_header)
        p2p_interface.mempool = repository.mempool
        p2p_connectionpool.add_on_transaction_callback(
            mempool_observer.on_transaction)
        p2p_connectionpool.add_on_transaction_hash_callback(
            mempool_observer.on_transaction_hash)
    else:
        mempool_observer = None
    zmq_context = zmq_observer = None
    if ctx.is_zmq_enabled():
        zmq_context, zmq_observer = build_zmq(ctx, mempool_observer,
                                              headers_reactor,
                                              ctx.mempool_size, service)
    blocks_reactor = BlocksReactor(repository,
                                   p2p_interface,
                                   keep_blocks=int(ctx.keep_blocks))
    headers_reactor.add_on_best_height_hit_persistent_callbacks(
        p2p_connectionpool.set_best_header)
    return jsonrpc_server, headers_reactor, blocks_reactor, repository, \
           cache, zmq_context, zmq_observer, p2p_interface
class TestJSONRPCServerGetblock(TestCase):
    def setUp(self):
        bindport = random.randint(31337, 41337)
        self.sut = JSONRPCServer('127.0.0.1', bindport, 'testuser',
                                 'testpassword')
        self.vo_service = Mock()
        self.sut.set_vo_service(self.vo_service)
        self.client = JSONClient(b'testuser', b'testpassword', '127.0.0.1',
                                 bindport)
        self.loop = asyncio.get_event_loop()

    def test_getblock_success(self):
        self.vo_service.getblock.side_effect = [
            async_coro({'block': 'header'}),
            async_coro('cafebabe')
        ]

        async def test():
            await self.sut.start()
            response = await self.client.call('getblock', params=['00' * 32])
            response2 = await self.client.call('getblock',
                                               params=['00' * 32, False])
            return response, response2

        res, res2 = self.loop.run_until_complete(test())
        self.assertEqual(
            res, {
                'error': None,
                'id': 1,
                'jsonrpc': '2.0',
                'result': {
                    'block': 'header'
                }
            })
        self.assertEqual(res2, {
            'error': None,
            'id': 1,
            'jsonrpc': '2.0',
            'result': 'cafebabe'
        })
        Mock.assert_has_calls(
            self.vo_service.getblock,
            calls=[call('00' * 32, 1),
                   call('00' * 32, False)])

    def test_getblock_error_missing(self):
        response = None
        self.vo_service.getblock.return_value = async_coro(response)

        async def test():
            await self.sut.start()
            response = await self.client.call('getblock', params=['00' * 32])
            return response

        res = self.loop.run_until_complete(test())
        self.assertEqual(
            res, {
                'error': {
                    'code': -5,
                    'message': 'Block not found'
                },
                'id': 1,
                'jsonrpc': '2.0',
                'result': None
            })
        Mock.assert_called_with(self.vo_service.getblock, '00' * 32, 1)

    def test_getblock_error_error_params(self):
        response = None
        self.vo_service.getblock.return_value = async_coro(response)

        async def test():
            await self.sut.start()
            response1 = await self.client.call('getblock',
                                               params=['wrong_blockhash'])
            response2 = await self.client.call('getblock')
            return response1, response2

        res, res2 = self.loop.run_until_complete(test())
        self.assertEqual(
            res, {
                'jsonrpc': '2.0',
                'error': {
                    'code': -5,
                    'message': 'Error parsing JSON:wrong_blockhash'
                },
                'id': 1,
                'result': None
            })

        # Really should be code: -32602, but that'll cause bitcoin-cli not to
        # error out correctly, so we use -1 instead
        self.assertEqual(
            res2, {
                'jsonrpc': '2.0',
                'error': {
                    'code': -1,
                    'message': 'Invalid params'
                },
                'id': 1,
                'result': None
            })
        Mock.assert_not_called(self.vo_service.getblock)
示例#5
0
class TestJSONRPCServerGetblock(TestCase):
    def setUp(self):
        bindport = random.randint(31337, 41337)
        self.sut = JSONRPCServer('127.0.0.1', bindport, 'testuser',
                                 'testpassword')
        self.vo_service = Mock()
        self.sut.set_vo_service(self.vo_service)
        self.client = JSONClient(b'testuser', b'testpassword', '127.0.0.1',
                                 bindport)
        self.loop = asyncio.get_event_loop()

    def test_getblockhash_success(self):
        self.vo_service.getblockhash.side_effect = [async_coro('cafebabe')]

        async def test():
            await self.sut.start()
            response = await self.client.call('getblockhash', params=[1000])
            return response

        res = self.loop.run_until_complete(test())
        self.assertEqual(res, {
            'id': 1,
            'result': 'cafebabe',
            'error': None,
            'jsonrpc': '2.0'
        })

        Mock.assert_has_calls(self.vo_service.getblockhash, calls=[call(1000)])

    def test_getblockhash_error_missing(self):
        response = None
        self.vo_service.getblockhash.return_value = async_coro(response)

        async def test():
            await self.sut.start()
            response = await self.client.call('getblockhash', params=[1000])
            return response

        res = self.loop.run_until_complete(test())
        self.assertEqual(
            res, {
                'error': {
                    'code': -8,
                    'message': 'Block height out of range'
                },
                'id': 1,
                'jsonrpc': '2.0',
                'result': None
            })
        Mock.assert_called_with(self.vo_service.getblockhash, 1000)

    def test_getblock_error_error_params(self):
        response = None
        self.vo_service.getblockhash.return_value = async_coro(response)

        async def test():
            await self.sut.start()
            response1 = await self.client.call('getblockhash',
                                               params=['non_int'])
            response2 = await self.client.call('getblockhash')
            return response1, response2

        res, res2 = self.loop.run_until_complete(test())
        self.assertEqual(
            res, {
                'jsonrpc': '2.0',
                'error': {
                    'code': -5,
                    'message': 'Error parsing JSON:non_int'
                },
                'id': 1,
                'result': None
            })
        self.assertEqual(
            res2, {
                'jsonrpc': '2.0',
                'error': {
                    'code': -32602,
                    'message': 'Invalid params'
                },
                'id': 1,
                'result': None
            })
        Mock.assert_not_called(self.vo_service.getblock)
class TestJSONRPCServerGetrawtransaction(TestCase):
    def setUp(self):
        bindport = random.randint(31337, 41337)
        self.sut = JSONRPCServer('127.0.0.1', bindport, 'testuser',
                                 'testpassword')
        self.vo_service = Mock()
        self.sut.set_vo_service(self.vo_service)
        self.client = JSONClient(b'testuser', b'testpassword', '127.0.0.1',
                                 bindport)
        self.loop = asyncio.get_event_loop()

    def test_getrawtransaction_success(self):
        self.vo_service.getrawtransaction.side_effect = [
            async_coro('cafebabe')
        ]

        async def test():
            await self.sut.start()
            response = await self.client.call('getrawtransaction',
                                              params=['00' * 32])
            response2 = await self.client.call('getrawtransaction',
                                               params=['00' * 32, True])
            return response, response2

        res, res2 = self.loop.run_until_complete(test())
        self.assertEqual(res, {
            'error': None,
            'id': 1,
            'jsonrpc': '2.0',
            'result': 'cafebabe'
        })
        Mock.assert_has_calls(self.vo_service.getrawtransaction,
                              calls=[call('00' * 32, False)])

    def test_getrawtransaction_error_missing(self):
        self.vo_service.getrawtransaction.side_effect = ItemNotFoundException

        async def test():
            await self.sut.start()
            response = await self.client.call('getrawtransaction',
                                              params=['00' * 32])
            return response

        res = self.loop.run_until_complete(test())
        self.assertEqual(
            res, {
                'error': {
                    'code':
                    -5,
                    'message':
                    'No such mempool or blockchain transaction. [maybe try again]'
                },
                'id': 1,
                'jsonrpc': '2.0',
                'result': None
            })

    def test_getrawtransaction_error_params(self):
        response = None
        self.vo_service.getrawtransaction.return_value = async_coro(response)

        async def test():
            await self.sut.start()
            response1 = await self.client.call('getrawtransaction',
                                               params=['wrong_hash'])
            response2 = await self.client.call('getrawtransaction',
                                               params=['cafebabe'])
            return response1, response2

        res, res2 = self.loop.run_until_complete(test())
        self.assertEqual(
            res, {
                'error': {
                    'code':
                    -8,
                    'message':
                    'parameter 1 must be hexadecimal string (not '
                    "'wrong_hash')"
                },
                'id': 1,
                'jsonrpc': '2.0',
                'result': None
            })
        self.assertEqual(
            res2, {
                'error': {
                    'code': -8,
                    'message': "parameter 1 must be of length 64 (not '8')"
                },
                'id': 1,
                'jsonrpc': '2.0',
                'result': None
            })
        Mock.assert_not_called(self.vo_service.getblockheader)

    def test_getrawtransaction_error_genesis(self):
        self.vo_service.getrawtransaction.side_effect = exceptions.GenesisTransactionRequestedException

        async def test():
            await self.sut.start()
            response1 = await self.client.call(
                'getrawtransaction',
                params=[
                    '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'
                ])
            return response1

        res = self.loop.run_until_complete(test())
        self.assertEqual(
            res, {
                'error': {
                    'code':
                    -5,
                    'message':
                    'The genesis block coinbase is not considered an '
                    'ordinary transaction and cannot be retrieved'
                },
                'id': 1,
                'jsonrpc': '2.0',
                'result': None
            })
示例#7
0
class TestJSONRPCServerGetblockheader(TestCase):
    def setUp(self):
        bindport = self.bindport = random.randint(31337, 41337)
        self.sut = JSONRPCServer('127.0.0.1', bindport, 'testuser',
                                 'testpassword')
        self.vo_service = Mock()
        self.sut.set_vo_service(self.vo_service)
        self.client = JSONClient(b'testuser', b'testpassword', '127.0.0.1',
                                 bindport)
        self.loop = asyncio.get_event_loop()

    def test_auth_failed(self):
        client = JSONClient(b'testuser', b'testpassworda', '127.0.0.1',
                            self.bindport)

        async def test():
            await self.sut.start()
            response = await client.call('getblockheader', params=['00' * 32])
            return response

        res = self.loop.run_until_complete(test())
        self.assertEqual(res, {})
        Mock.assert_not_called(self.vo_service.getblockheader)

    def test_echo(self):
        async def test():
            await self.sut.start()
            response = await self.client.call('echo')
            return response

        res = self.loop.run_until_complete(test())
        self.assertEqual(res, {
            'id': 1,
            'result': '',
            'error': None,
            'jsonrpc': '2.0'
        })

    def test_help(self):
        from spruned import __version__ as spruned_version
        from spruned import __bitcoind_version_emulation__ as bitcoind_version

        async def test():
            await self.sut.start()
            response = await self.client.call('help')
            return response

        res = self.loop.run_until_complete(test())
        print(res)
        self.assertTrue('spruned %s, emulating bitcoind %s' %
                        (spruned_version, bitcoind_version) in res['result'],
                        msg=res['result'])

    def test_getblockheader_success(self):
        self.vo_service.getblockheader.side_effect = [
            async_coro({'block': 'header'}),
            async_coro('cafebabe')
        ]

        async def test():
            await self.sut.start()
            response = await self.client.call('getblockheader',
                                              params=['00' * 32])
            response2 = await self.client.call('getblockheader',
                                               params=['00' * 32, False])
            return response, response2

        res, res2 = self.loop.run_until_complete(test())
        self.assertEqual(
            res, {
                'error': None,
                'id': 1,
                'jsonrpc': '2.0',
                'result': {
                    'block': 'header'
                }
            })
        self.assertEqual(res2, {
            'error': None,
            'id': 1,
            'jsonrpc': '2.0',
            'result': 'cafebabe'
        })
        Mock.assert_has_calls(self.vo_service.getblockheader,
                              calls=[
                                  call('00' * 32, verbose=True),
                                  call('00' * 32, verbose=False)
                              ])

    def test_getblockheader_error_missing(self):
        response = None
        self.vo_service.getblockheader.return_value = async_coro(response)

        async def test():
            await self.sut.start()
            response = await self.client.call('getblockheader',
                                              params=['00' * 32])
            return response

        res = self.loop.run_until_complete(test())
        self.assertEqual(
            res, {
                'error': {
                    'code': -5,
                    'message': 'Block not found'
                },
                'id': 1,
                'jsonrpc': '2.0',
                'result': None
            })
        Mock.assert_called_with(self.vo_service.getblockheader,
                                '00' * 32,
                                verbose=True)

    def test_getblockheader_error_params(self):
        response = None
        self.vo_service.getblockheader.return_value = async_coro(response)

        async def test():
            await self.sut.start()
            response1 = await self.client.call('getblockheader',
                                               params=['wrong_blockhash'])
            response2 = await self.client.call('getblockheader')
            return response1, response2

        res, res2 = self.loop.run_until_complete(test())
        self.assertEqual(
            res, {
                'jsonrpc': '2.0',
                'error': {
                    'code': -5,
                    'message': 'Error parsing JSON:wrong_blockhash'
                },
                'id': 1,
                'result': None
            })
        self.assertEqual(
            res2, {
                'jsonrpc': '2.0',
                'error': {
                    'code': -32602,
                    'message': 'Invalid params'
                },
                'id': 1,
                'result': None
            })
        Mock.assert_not_called(self.vo_service.getblockheader)