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 = async_coro(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 = async_coro(True) self.loop.run_until_complete(self.sut.on_peer_error(peer, error_type='connect')) self.assertEqual(len(peer._errors), 1)
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_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_connect_ok(self): callback = Mock() callback_blocks = Mock() self.sut.add_on_blocks_callback(callback_blocks) self.sut.add_on_connect_callback(callback) reader, writer = Mock(), Mock() self.peer_factory().perform_handshake.return_value = async_coro('the peer version answer') self.connector.return_value = async_coro((reader, writer)) self.peer_factory().next_message.return_value = async_coro(None) self.loop.run_until_complete(self.sut.connect()) self.assertEqual(self.sut._version, 'the peer version answer') self.assertEqual(len(self.loopmock.method_calls), 1) Mock.assert_not_called(callback_blocks) self.assertTrue(self.sut.connected)
def test_getrawtransaction_verbose_in_block_invalid_pow(self): header_hex = '010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051' \ 'fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299' block_json = { "hash": "00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048", "height": 1, "version": 1, "versionHex": "", "merkleroot": "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098", "time": 1231469665, "mediantime": 1231469665, "nonce": 2573394689, "bits": 486604799, "difficulty": 0, 'chainwork': '00' * 32, "previousblockhash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", "nextblockhash": "000000006a625f06636b8bb6ac7b960a8d03705d1ace08b1a19da3fdcc99ddbd", "tx": [ "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098" ] } self.repository.headers.get_best_header.return_value = {'block_height': 513980} self.repository.headers.get_block_header.return_value = { 'block_hash': block_json['hash'], 'block_height': block_json['height'], 'header_bytes': binascii.unhexlify(header_hex.encode()), 'next_block_hash': block_json['nextblockhash'] } self.repository.get_block_header.return_value = self.header self.repository.blockchain.get_json_transaction.return_value = None tx = { 'hex': '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff00' '1d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7' '947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000', 'blockhash': '00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048', 'confirmations': 6, 'vout': [] } self.repository.get_best_header.return_value = {'block_height': 513980} self.electrod.getrawtransaction.return_value = async_coro(tx) self.electrod.get_merkleproof.return_value = async_coro({'block_height': 1, 'merkle': ['ff' * 32], 'pos': 0}) with self.assertRaises(InvalidPOWException): self.loop.run_until_complete( self.sut.getrawtransaction( '0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098', verbose=True ) )
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_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 } ) # 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.getblockheader)
def test_check_new_header_same_header(self): """ test on fallback method check_headers no new header received """ header_timestamp = int(time.time()) - 100 loc_header = net_header = { "block_height": 1, "block_hash": "ff" * 32, "timestamp": header_timestamp - 700, 'header_bytes': b'', 'prev_block_hash': '00' * 32 } peer = Mock(server_info='mock_peer') self.interface.get_header.side_effect = [ async_coro((peer, net_header)) ] self.sut.synced = True self.sut.set_last_processed_header(loc_header) self.assertFalse(self.sut.lock.locked()) self.loop.run_until_complete(self.sut.check_headers()) Mock.assert_called_once_with(self.delay_task_runner, coro_call('check_headers'), in_range(655, 660)) Mock.assert_has_calls(self.interface.get_header, calls=[ call(2, fail_silent_out_of_range=True, get_peer=True), ], any_order=True) self.assertEqual(1, len(self.interface.method_calls)) self.assertEqual(1, len(self.electrod_loop.method_calls)) self.assertEqual(0, len(self.repo.method_calls))
def test_no_new_network_best_header(self): """ test reactor.check_headers method interface didn't returned any best header. will try again in """ header_timestamp = int( time.time()) - self.sut.new_headers_fallback_poll_interval - 1 loc_header = { "block_height": 1, "block_hash": "ff" * 32, "timestamp": header_timestamp } self.interface.get_header.return_value = async_coro(None) self.sut.synced = True self.sut.set_last_processed_header(loc_header) self.loop.run_until_complete(self.sut.check_headers()) self.assertFalse(self.sut.lock.locked()) Mock.assert_called_once_with(self.delay_task_runner, coro_call('check_headers'), 660) Mock.assert_called_with(self.interface.get_header, 2, fail_silent_out_of_range=True, get_peer=True) Mock.assert_called_once_with(self.electrod_loop.create_task, self.delay_task_runner()) self.assertEqual(1, len(self.interface.method_calls)) self.assertEqual(1, len(self.electrod_loop.method_calls)) self.assertEqual(0, len(self.repo.method_calls))
def test_on_new_headers_new_header(self): """ test on fallback method check_headers new header received """ header_timestamp = int(time.time()) - 100 loc_header = { "block_height": 1, "block_hash": "ff" * 32, "timestamp": header_timestamp - 700, 'header_bytes': b'', 'prev_block_hash': '00' * 32 } net_header = { "block_height": 2, "block_hash": "aa" * 32, "timestamp": header_timestamp, 'header_bytes': b'', 'prev_block_hash': 'ff' * 32 } self.interface.get_header.side_effect = [async_coro(net_header)] self.sut.synced = True self.sut.set_last_processed_header(loc_header) self.assertFalse(self.sut.lock.locked()) peer = Mock(server_info='mock_peer') self.repo.get_best_header.return_value = loc_header self.repo.save_header.side_effect = lambda a, b, c, d: True self.loop.run_until_complete(self.sut.on_new_header(peer, net_header)) self.assertEqual(self.repo.get_best_header.call_count, 1) Mock.assert_called_once_with(self.repo.save_header, net_header['block_hash'], net_header['block_height'], net_header['header_bytes'], net_header['prev_block_hash'])
def test_received_new_single_header(self): """ test reactor.on_header method header ff*32 is saved at height 2020 received a new header at height 2021 with hash aa*32 header is saved to disk best header is updated at height 2021 """ self.sut.synced = False peer = Mock(server_info='mock_peer') loc_header = {'block_height': 2020, 'block_hash': 'ff' * 32} net_header = { 'block_height': 2021, 'block_hash': 'aa' * 32, 'prev_block_hash': 'ff' * 32, 'header_bytes': b'' } self.interface.get_header.return_value = async_coro(net_header) self.repo.get_best_header.return_value = loc_header self.loop.run_until_complete(self.sut.on_new_header(peer, net_header)) Mock.assert_called_once_with(self.repo.get_best_header) Mock.assert_called_once_with(self.repo.save_header, net_header['block_hash'], net_header['block_height'], net_header['header_bytes'], net_header['prev_block_hash']) self.assertEqual(0, len(self.interface.method_calls)) self.assertEqual(0, len(self.electrod_loop.method_calls)) self.assertEqual(2, len(self.repo.method_calls))
def test_network_header_behind(self): """ test reactor.on_header method network header behind: remote peer outdated, skip """ self.sut.synced = True now = int(time.time()) net_header = { 'block_height': 1, 'block_hash': 'aa' * 32, 'timestamp': now - self.sut.new_headers_fallback_poll_interval + 10 } loc_header = { 'block_height': 2, 'block_hash': 'ff' * 32, 'timestamp': now - self.sut.new_headers_fallback_poll_interval + 10 } peer = Mock(server_info='mock_peer') peer.close.return_value = True self.repo.get_best_header.return_value = loc_header self.repo.get_header_at_height.return_value = net_header self.interface.disconnect_from_peer.return_value = async_coro(True) self.loop.run_until_complete(self.sut.on_new_header(peer, net_header)) Mock.assert_called_once_with(self.repo.get_header_at_height, 1) self.assertEqual(1, len(self.interface.method_calls)) self.assertEqual(0, len(self.electrod_loop.method_calls)) self.assertEqual(2, len(self.repo.method_calls))
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_connection_error(self): transport, protocol = Mock(), Mock() self.mock_loop.create_connection.return_value = async_coro( (transport, protocol)) with self.assertRaises(ConnectionRefusedError) as e: self.loop.run_until_complete(self.sut.connect(self.server_info))
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' }) self.assertEqual( res2, { 'error': { 'code': -8, 'message': 'spruned error: Verbose mode not supported' }, 'id': 1, 'jsonrpc': '2.0', 'result': None }) Mock.assert_has_calls(self.vo_service.getrawtransaction, calls=[call('00' * 32, False)])
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)
def test_estimatefee(self): self.electrod.estimatefee.side_effect = [ ElectrodMissingResponseException(), async_coro(3) ] res = self.loop.run_until_complete(self.sut.estimatefee(6)) self.assertEqual(res, 3)
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_gettxout(self): tx = '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff00' \ '1d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7' \ '947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000' self.repository.get_best_header.return_value = {'block_height': 513980} self.electrod.getrawtransaction.return_value = async_coro(tx) self.repository.blockchain.get_transaction.return_value = None self.electrod.listunspents_by_scripthash.side_effect = [ ElectrodMissingResponseException, async_coro([{ 'tx_hash': '0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098', 'tx_pos': 0, 'height': 0, 'value': 1 }]) ] self.repository.headers.get_best_header.return_value = { 'block_height': 513980, 'block_hash': '0000000000000000001a0822fbaef92ef048967fa32c68f96e3d57d13183ef2b' } res = self.loop.run_until_complete( self.sut.gettxout( '0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098', 0)) self.assertEqual( res, { "bestblock": "0000000000000000001a0822fbaef92ef048967fa32c68f96e3d57d13183ef2b", "confirmations": 513981, "value": "0.00000001", "scriptPubKey": { "asm": "", "hex": "410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7" "589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac", "reqSigs": 0, "type": "", "addresses": [] } })
def test_connect_ok(self): async def parallel(): await asyncio.sleep(3) for peer in self.peers: self.sut.add_peer(peer) await asyncio.sleep(5) self.sut._keepalive = False self.online_checker.side_effect = [async_coro(False), async_coro(True)] self.loop.run_until_complete( asyncio.gather(parallel(), self.sut.connect())) Mock.assert_has_calls(self.loopmock.create_task, calls=[ call(coro_call('_connect_peer')), call(coro_call('_connect_peer')) ])
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_check_blockchain_local_a_lot_behind(self): """ something bad happened around block 16, we saved it, we didn't tracked it and we start over 5 blocks later. also, the last block tracked by the blockheader reactor was stuck ad block 9. basically, everything is screwed up, but we recover and download the needed blocks. """ self.sut.set_last_processed_block({'block_hash': 'cafe', 'block_height': 9}) self.repo.headers.get_best_header.return_value = {'block_hash': 'babe', 'block_height': 20} self.interface.get_blocks.return_value = async_coro( { 'block17': {'block_hash': 'block17', 'block_bytes': b'raw'}, 'block18': {'block_hash': 'block18', 'block_bytes': b'raw'}, 'block19': {'block_hash': 'block19', 'block_bytes': b'raw'}, 'block20': {'block_hash': 'block20', 'block_bytes': b'raw'} } ) self.repo.headers.get_headers_since_height.return_value = [ {'block_hash': 'block16', 'block_height': 16}, {'block_hash': 'block17', 'block_height': 17}, {'block_hash': 'block18', 'block_height': 18}, {'block_hash': 'block19', 'block_height': 19}, {'block_hash': 'block20', 'block_height': 20} ] self.repo.blockchain.get_block.side_effect = [ {'block_hash': 'block16', 'block_bytes': b'raw'}, None, None, None, None ] self.repo.blockchain.save_blocks.side_effect = [ {'block_hash': 'block17', 'block_bytes': b'raw'}, {'block_hash': 'block18', 'block_bytes': b'raw'}, {'block_hash': 'block19', 'block_bytes': b'raw'}, {'block_hash': 'block20', 'block_bytes': b'raw'} ] self.repo.blockchain.save_blocks.side_effect = lambda *x: x self.loop.run_until_complete(self.sut.check()) Mock.assert_called_once_with(self.repo.headers.get_best_header) Mock.assert_called_once_with(self.repo.headers.get_headers_since_height, 15, limit=10) Mock.assert_has_calls( self.repo.blockchain.get_block, calls=[ call('block16'), call('block17'), call('block18'), call('block19'), call('block20') ] ) Mock.assert_called_once_with(self.interface.get_blocks, 'block17', 'block18', 'block19', 'block20') Mock.assert_called_once_with( self.repo.blockchain.save_blocks, {'block_hash': 'block17', 'block_bytes': b'raw'}, {'block_hash': 'block18', 'block_bytes': b'raw'}, {'block_hash': 'block19', 'block_bytes': b'raw'}, {'block_hash': 'block20', 'block_bytes': b'raw'} ) self.assertEqual(self.sut._last_processed_block, {'block_hash': 'block20', 'block_height': 20})
def test_local_db_behind_100_headers(self): """ test reactor.on_new_header header ff*32 is saved at height 2020 received a new header at height 2120 with hash aa*32 chunk from header 2016 is requested headers from 2021 to 2120 are saved in the db best header is updated at height 2120 :return: """ header_timestamp = int(time.time()) peer = Mock(server_info='mock_peer') loc_header = { "block_height": 2020, "block_hash": "ff" * 32, "timestamp": header_timestamp - 6000 } net_header = { "block_height": 2120, "block_hash": "aa" * 32, "timestamp": header_timestamp } self.sut.synced = True self.sut.set_last_processed_header(loc_header) self.repo.get_best_header.return_value = loc_header _headers = make_headers(2017, 2120, '00' * 32) self.interface.get_headers_in_range_from_chunks.side_effect = [ async_coro((Mock(), _headers)), async_coro(None) ] self.interface.get_header.return_value = async_coro(net_header) self.repo.save_headers.side_effect = lambda x, **k: x self.loop.run_until_complete(self.sut.on_new_header(peer, net_header)) Mock.assert_called_with( self.repo.save_headers, [h for h in _headers if h['block_height'] > 2020]) Mock.assert_not_called(peer.close) self.assertEqual(self.sut._last_processed_header, _headers[-1]) self.assertEqual(self.sut.synced, True) self.assertEqual(1, len(self.interface.method_calls)) self.assertEqual(2, len(self.repo.method_calls)) self.assertEqual(0, len(self.electrod_loop.method_calls))
def test_mempool_observer(self): connection = Mock() from pycoin.tx.Tx import Tx tx = Tx.from_hex( '01000000000101112a649fd72656cf572259cb7cb61bd31ccdbdf0944070e73401565affbe629d0100000000ffffffff02608' 'de2110000000017a914d52b516c1a094462959ed6facebb94429d2cebf487d3135b0b00000000220020701a8d401c84fb13e6' 'baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d0400473044022006b149e0cf031f57fd443bd1210b381e9b1b15094' '57ba1f49e48b803696f56e802203d66bd974ad3ac5b7591cc84e706b78d139c61e2bf1995a89c4dc0758984a2b70148304502' '2100fe7275d601080e1870517774a3ad6accaa7f8ad144addec3251e98685d4fefad02207792c2b0ed6ab42ed2ba6d12e6bd3' '4db8c6f4ac6f15e604f70ea85a735c450b1016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd' '92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e' '046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000') self.loop.run_until_complete( self.sut.on_transaction(connection, {'tx': tx})) self.assertEqual(tx.w_id(), [x for x in self.mempool_repository.get_txids()][0]) self.repository.blockchain.get_transactions_by_block_hash.return_value = [], None block = Block(1, b'0' * 32, merkle_root=merkle([tx.hash()]), timestamp=123456789, difficulty=3000000, nonce=1 * 137) block.txs.append(tx) as_bin = block.as_bin() Block.from_bin(as_bin) block_header = {'block_hash': block.id()} self.batcher_factory.add_peer.return_value = async_coro(True) self.batcher_factory.inv_item_to_future.return_value = block.as_bin() mempool_response = self.mempool_repository.get_raw_mempool(True) self.assertEqual( { '41867301a6cff5c47951aa1a4eef0be910db0cb5f154eaeb469732e1f9b54548': { 'size': 381, 'fee': 0, 'modifiedfee': 0, 'time': ANY, 'height': 0, 'descendantcount': 0, 'descendantsize': 0, 'descendantfees': 0, 'ancestorcount': 0, 'ancestorsize': 0, 'ancestorfees': 0, 'depends': [] } }, mempool_response) self.repository.blockchain.save_block.side_effect = lambda a: { 'block_object': Block.from_bin(a['block_bytes']) } self.repository.blockchain.get_transactions_by_block_hash.return_value = [], None self.loop.run_until_complete(self.sut.on_block_header(block_header)) self.assertEqual(self.mempool_repository.get_raw_mempool(True), {}) self.assertEqual([x for x in self.mempool_repository.get_txids()], [])
def test_getblock_p2p_non_verbose_network_error(self): self.repository.headers.get_best_header.return_value = {'block_height': 513980} self.repository.headers.get_block_header.return_value = self.header self.repository.blockchain.get_transactions_by_block_hash.return_value = [], None self.p2p.get_block.side_effect = lambda *a, **kw: async_coro(None) with self.assertRaises(ServiceException): self.loop.run_until_complete( self.sut.getblock('000000000000000000376267d342878f869cb68192ff5d73f5f1953ae83e3e1e', 0) )
def test_on_new_headers_5_blocks_behind(self): """ local height is 10 remote height is 15 5 headers are requested with interface.get_headers_in_range api (no chunks) due race conditions, two errors are triggered: no peers, empty response the third retry headers are fetched headers are saved best height is 15 sync true """ header_timestamp = int(time.time()) net_header = { "block_height": 15, "block_hash": "55" * 32, "timestamp": header_timestamp, "prev_block_hash": "54" * 32, "header_bytes": b"0" * 80 } peer = Mock(server_info='mock_peer') loc_header = { "block_height": 10, "block_hash": "bb" * 32, "timestamp": header_timestamp - 600 * 5, "prev_block_hash": "aa" * 32, "header_bytes": b"0" * 80 } self.repo.get_best_header.return_value = loc_header headers = make_headers(11, 15, 'bb' * 32) + [net_header] self.interface.get_headers_in_range.side_effect = [ exceptions.NoPeersException, async_coro(None), async_coro(headers), ] self.interface.get_header.return_value = async_coro(net_header) self.repo.save_headers.side_effect = lambda x, **k: x self.loop.run_until_complete(self.sut.on_new_header(peer, net_header)) self.assertEqual(self.sut._last_processed_header, net_header) self.assertTrue(self.sut.synced) self.assertEqual(3, len(self.interface.method_calls)) self.assertEqual(4, len(self.repo.method_calls)) self.assertEqual(0, len(self.electrod_loop.method_calls))
def test_get_header_ok(self): peer = Mock() self.connectionpool.call.return_value = async_coro( (peer, self.electrum_header)) res = self.loop.run_until_complete(self.sut.get_header(513526)) self.assertEqual(res, self.parsed_header) bitcoind_header = "00000020fe52010fa7c798b97621508b772142dfc7b594df7a3a3200000000000000000097db2dc9" \ "4e2799bcdd7259f0876467b379fe44b69342df38a8ec2f350722f9a73367a95aa38955173732b883" self.assertEqual(binascii.unhexlify(bitcoind_header), self.parsed_header['header_bytes'])
def test_callbacks(self): hcb = Mock(return_value=async_coro(True)) ccb = Mock(return_value=async_coro(True)) dcb = Mock(return_value=async_coro(True)) pcb = Mock(return_value=async_coro(True)) ecb = Mock(return_value=async_coro(True)) self.sut.add_on_header_callbacks(hcb) self.sut.add_on_error_callback(ecb) self.sut.add_on_connect_callback(ccb) self.sut.add_on_disconnect_callback(dcb) self.sut.add_on_peers_callback(pcb) self.loop.run_until_complete( asyncio.gather(self.sut.on_header('header'), self.sut.on_connect(), self.sut.on_error('error'), self.sut.on_peers())) self.sut.on_connectrum_disconnect() for m in [hcb, ccb, dcb, pcb]: Mock.assert_called_with(m, self.sut) Mock.assert_called_with(ecb, self.sut, error_type='error') self.assertEqual(self.sut.last_header, 'header')
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_get_block(self): block = b'block' self.pool.get.return_value = async_coro(block) response = self.loop.run_until_complete(self.sut.get_block('aa' * 32)) self.assertEqual( response, { "block_hash": "aa" * 32, "header_bytes": b"block", "block_bytes": b"block" })