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
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()
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)
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
def test_2(self): payload = { "value": "{:.8f}".format(0.00002342), "feerate": "{:.8f}".format(0.00000022), "jsonrpc": "2.0" } res = JSONRPCServer._json_dumps_with_fixed_float_precision(payload) self.assertTrue( all([ '"value": 0.00002342' in res, '"feerate": 0.00000022' in res, '"jsonrpc": "2.0"' in res ]))
def test_1(self): payload = { 'error': None, 'jsonrpc': '2.0', 'id': 1, 'result': { 'bestblock': '000000000000000000084b9258ca7c4bed889bf07e2bbcb839e509b0ce2d8fc4', 'value': "0.00020000", 'confirmations': 481, 'scriptPubKey': { 'addresses': [], 'hex': '002023df98f8eada1ba8d57c06f311e33cd5dbb4fd875c8887e04e81688c527d5902', 'reqSigs': 0, 'asm': '', 'type': '' } } } res = JSONRPCServer._json_dumps_with_fixed_float_precision(payload) self.assertTrue('"jsonrpc": "2.0"' in res) self.assertTrue('"value": 0.00020000' in res)
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)
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 })
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)