def node_from_node_config(node_config: NodeConfig): # Test connection and match-up chain name log_and_print('Trying to retrieve data from the API of {}'.format( node_config.node_name)) try: actual_chain = polkadot_api_data_wrapper.get_system_chain( node_config.node_ws_url) log_and_print('Success.') if actual_chain != node_config.chain_name: log_and_print( 'WARNING: actual chain name of {} is \"{}\" not \"{}\". PANIC ' 'will continue using the supplied chain name \"{}\".'.format( node_config.node_name, actual_chain, node_config.chain_name, node_config.chain_name)) except Exception as e: logger_general.error(e) raise InitialisationException( 'Failed to retrieve data from the API of {}'.format( node_config.node_name)) # Get node type node_type = NodeType.VALIDATOR_FULL_NODE \ if node_config.node_is_validator \ else NodeType.NON_VALIDATOR_FULL_NODE # Check if validator stash account address exists by querying some data # which requires the validator's address. If address does not exist, an # exception is thrown. if node_config.node_is_validator: try: polkadot_api_data_wrapper.get_eras_stakers( node_config.node_ws_url, node_config.stash_account_address) except InvalidStashAccountAddressException as e: logger_general.error(e.message) raise InitialisationException(e.message) except Exception as e: logger_general.error(e) raise InitialisationException( 'Failed validating stash account address {}'.format( node_config.stash_account_address)) # Initialise node and load any state node = Node(node_config.node_name, node_config.node_ws_url, node_type, node_config.stash_account_address, node_config.chain_name, REDIS, node_config.is_archive_node, internal_conf=InternalConf) node.load_state(logger_general) # Return node return node
def setUp(self) -> None: self.logger = logging.getLogger('dummy') self.monitor_name = 'testblockchainmonitor' self.counter_channel = CounterChannel(self.logger) self.channel_set = ChannelSet([self.counter_channel], TestInternalConf) self.redis = None self.data_sources = [] self.polkadot_api_endpoint = 'api_endpoint' self.dummy_ws_url_1 = "11.22.33.11:9944" self.dummy_ws_url_2 = "11.22.33.12:9944" self.dummy_ws_url_3 = "11.22.33.13:9944" self.dummy_ws_url_4 = "11.22.33.14:9944" self.dummy_node_name_1 = "testnode1" self.dummy_node_name_2 = "testnode2" self.dummy_node_name_3 = "testnode3" self.dummy_node_name_4 = "testnode4" self.dummy_chain_name = "testchain" self.validator_stash_account_address = "DFJGDF8G898fdghb98dg9wetg9we00w" self.dummy_full_node_1 = Node(name=self.dummy_node_name_1, ws_url=self.dummy_ws_url_1, node_type=NodeType.NON_VALIDATOR_FULL_NODE, stash_account_address='', chain=self.dummy_chain_name, redis=None, is_archive_node=True, internal_conf=TestInternalConf) self.dummy_full_node_2 = Node(name=self.dummy_node_name_2, ws_url=self.dummy_ws_url_2, node_type=NodeType.NON_VALIDATOR_FULL_NODE, stash_account_address='', chain=self.dummy_chain_name, redis=None, is_archive_node=True, internal_conf=TestInternalConf) self.dummy_full_node_3 = Node(name=self.dummy_node_name_3, ws_url=self.dummy_ws_url_3, node_type=NodeType.NON_VALIDATOR_FULL_NODE, stash_account_address='', chain=self.dummy_chain_name, redis=None, is_archive_node=True, internal_conf=TestInternalConf) self.dummy_validator_node_1 = Node( name=self.dummy_node_name_4, ws_url=self.dummy_ws_url_4, node_type=NodeType.VALIDATOR_FULL_NODE, stash_account_address=self.validator_stash_account_address, chain=self.dummy_chain_name, redis=None, is_archive_node=False, internal_conf=TestInternalConf) self.dummy_blockchain = Blockchain(self.dummy_chain_name, None) self.monitor = BlockchainMonitor(self.monitor_name, self.dummy_blockchain, self.channel_set, self.logger, self.redis, self.data_sources, self.polkadot_api_endpoint, TestInternalConf) self.dummy_referendum_count = 10 self.dummy_public_prop_count = 10 self.dummy_council_prop_count = 10 self.dummy_validator_set_size = 120
def node_from_node_config(node_config: NodeConfig): # Test connection and match-up chain name log_and_print('Trying to retrieve data from the API of {}'.format( node_config.node_name)) # Try to ping the API to see if configuration is correct try: pong_response = oasis_api_data_wrapper.ping_api( node_config.node_api_url) if pong_response != "pong": log_and_print('WARNING: API of node {} is not reachable.'.format( node_config.node_name)) log_and_print('Success. API is configured correctly') except Exception as e: logger_general.error(e) raise InitialisationException( 'Failed to retrieve data from the API of {}'.format( node_config.node_name)) # Test connection and match-up chain name log_and_print('Trying to retrieve node name {} from API'.format( node_config.node_name)) # Check if the node name exists by Pinging the node # If it doesn't then it is miss configured. try: pong_response = oasis_api_data_wrapper.ping_node( node_config.node_api_url, node_config.node_name) if pong_response != "pong": log_and_print( 'WARNING: Node {} is not configured properly, PANIC node' \ 'name should match that set in the API Server.'.format( node_config.node_name)) log_and_print('Success. node name is configured correctly') except Exception as e: logger_general.error(e) raise InitialisationException( 'Failed to retrieve data from the API of {}'.format( node_config.node_name)) # Get node type node_type = NodeType.VALIDATOR_FULL_NODE \ if node_config.node_is_validator \ else NodeType.NON_VALIDATOR_FULL_NODE # Check if the node public key exists by calling the API to retrieve the # node successfully. # Test connection and match-up chain name if node_config.node_is_validator: log_and_print('Trying to retrieve Node Public Key {} from'.format( node_config.node_name)) try: node_details = oasis_api_data_wrapper.get_node( node_config.node_api_url, node_config.node_name, node_config.node_public_key) entity_public_key = node_details['entity_id'] staking_address = oasis_api_data_wrapper.get_staking_address( node_config.node_api_url, entity_public_key) except Exception as e: logger_general.error(e) raise InitialisationException( 'Failed validating node public key {}'.format( node_config.node_public_key)) else: entity_public_key = EMPTY_URL staking_address = EMPTY_URL # Prometheus configuration should be checked on start up if Peers monitoring # is enabled. try: peers_response = oasis_api_data_wrapper.get_prometheus_gauge( node_config.node_api_url, node_config.node_name, \ "tendermint_p2p_peers") if isinstance(peers_response, int): log_and_print( 'WARNING: Node {} does not have prometheus enabled. Please ' \ 'enable Prometheus to monitor data such as no of Peers'.format( node_config.node_name)) log_and_print('Success. Prometheus is configured correctly') except Exception as e: logger_general.error(e) raise InitialisationException( 'Failed to retrieve Prometheus Data from API of {}'.format( node_config.node_name)) # Node Exporter should be an optional tool for System Monitoring if node_config.node_exporter_url != "": try: metric_to_test = ['process_cpu_seconds_total'] prometheus_data = get_oasis_prometheus( \ node_config.node_exporter_url, metric_to_test, logger_general) process_cpu_seconds_total = ( \ prometheus_data['process_cpu_seconds_total']) node_exporter_url = node_config.node_exporter_url log_and_print('Success. Node Exporter is configured correctly') except Exception as e: log_and_print(e) logger_general.error(e) raise InitialisationException( 'Failed to retrieve Node Exporter Data from URL of {}'.format( node_config.node_name)) else: node_exporter_url = EMPTY_URL # Test connection and match-up chain name log_and_print('Trying to convert the Node {} Key into a Consensus ' \ 'Public Key and a Tendermint Address key '.format( node_config.node_name)) # Retrieve the Consensus Public Key and the Tendermint Address if node_config.node_is_validator: try: consensus_public_key = oasis_api_data_wrapper. \ get_registry_node(node_config.node_api_url, \ node_config.node_name, \ node_config.node_public_key) tendermint_address_key = oasis_api_data_wrapper. \ get_tendermint_address(node_config.node_api_url, \ str(consensus_public_key['consensus'][ 'id'])) log_and_print('Successfully converted node public key into ' \ 'Consensus Public Key and Tendermint Address') except Exception as e: logger_general.error(e) raise InitialisationException( 'Failed to convert a node public key for the node {}'.format( node_config.node_name)) else: consensus_public_key = EMPTY_URL tendermint_address_key = EMPTY_URL chain_id = node_config.chain_name # Initialise node and load any state node = Node(node_config.node_name, node_config.node_api_url, node_exporter_url, node_type, node_config.node_public_key, chain_id, REDIS, node_config.is_archive_node, consensus_public_key, tendermint_address_key, staking_address, entity_public_key, internal_conf=InternalConf) node.load_state(logger_general) # Return node return node
class TestBlockchainMonitorWithoutRedis(unittest.TestCase): def setUp(self) -> None: self.logger = logging.getLogger('dummy') self.monitor_name = 'testblockchainmonitor' self.counter_channel = CounterChannel(self.logger) self.channel_set = ChannelSet([self.counter_channel], TestInternalConf) self.redis = None self.data_sources = [] self.polkadot_api_endpoint = 'api_endpoint' self.dummy_ws_url_1 = "11.22.33.11:9944" self.dummy_ws_url_2 = "11.22.33.12:9944" self.dummy_ws_url_3 = "11.22.33.13:9944" self.dummy_ws_url_4 = "11.22.33.14:9944" self.dummy_node_name_1 = "testnode1" self.dummy_node_name_2 = "testnode2" self.dummy_node_name_3 = "testnode3" self.dummy_node_name_4 = "testnode4" self.dummy_chain_name = "testchain" self.validator_stash_account_address = "DFJGDF8G898fdghb98dg9wetg9we00w" self.dummy_full_node_1 = Node( name=self.dummy_node_name_1, ws_url=self.dummy_ws_url_1, node_type=NodeType.NON_VALIDATOR_FULL_NODE, stash_account_address='', chain=self.dummy_chain_name, redis=None, is_archive_node=True, internal_conf=TestInternalConf) self.dummy_full_node_2 = Node( name=self.dummy_node_name_2, ws_url=self.dummy_ws_url_2, node_type=NodeType.NON_VALIDATOR_FULL_NODE, stash_account_address='', chain=self.dummy_chain_name, redis=None, is_archive_node=True, internal_conf=TestInternalConf) self.dummy_full_node_3 = Node( name=self.dummy_node_name_3, ws_url=self.dummy_ws_url_3, node_type=NodeType.NON_VALIDATOR_FULL_NODE, stash_account_address='', chain=self.dummy_chain_name, redis=None, is_archive_node=True, internal_conf=TestInternalConf) self.dummy_validator_node_1 = Node( name=self.dummy_node_name_4, ws_url=self.dummy_ws_url_4, node_type=NodeType.VALIDATOR_FULL_NODE, stash_account_address=self.validator_stash_account_address, chain=self.dummy_chain_name, redis=None, is_archive_node=False, internal_conf=TestInternalConf) self.dummy_blockchain = Blockchain(self.dummy_chain_name, None) self.monitor = BlockchainMonitor(self.monitor_name, self.dummy_blockchain, self.channel_set, self.logger, self.redis, self.data_sources, self.polkadot_api_endpoint, TestInternalConf) self.dummy_referendum_count = 10 self.dummy_public_prop_count = 10 self.dummy_council_prop_count = 10 self.dummy_validator_set_size = 120 @patch(PING_NODE_FUNCTION, return_value=None) @patch(GET_WEB_SOCKETS_FUNCTION) def test_data_source_chooses_an_online_full_node_connected_to_the_API( self, mock_get_web_sockets, _) -> None: self.dummy_full_node_1.set_as_down(self.channel_set, self.logger) self.dummy_validator_node_1.set_as_down(self.channel_set, self.logger) self.monitor.data_sources = [ self.dummy_full_node_1, self.dummy_validator_node_1, self.dummy_full_node_2, self.dummy_full_node_3 ] mock_get_web_sockets.return_value = [ self.dummy_ws_url_1, self.dummy_ws_url_2 ] node = self.monitor.data_source self.assertEqual(node.name, self.dummy_node_name_2) @patch(PING_NODE_FUNCTION, return_value=None) @patch(GET_WEB_SOCKETS_FUNCTION) def test_data_source_chooses_an_online_validator_node_connected_to_the_API( self, mock_get_web_sockets, _) -> None: self.dummy_full_node_1.set_as_down(self.channel_set, self.logger) self.dummy_full_node_2.set_as_down(self.channel_set, self.logger) self.monitor.data_sources = [ self.dummy_full_node_1, self.dummy_validator_node_1, self.dummy_full_node_2, self.dummy_full_node_3 ] mock_get_web_sockets.return_value = [ self.dummy_ws_url_1, self.dummy_ws_url_4 ] node = self.monitor.data_source self.assertEqual(node.name, self.dummy_validator_node_1.name) @patch(GET_WEB_SOCKETS_FUNCTION) def test_data_source_raises_exception_if_no_node_is_eligible_for_choosing( self, mock_get_web_sockets) -> None: self.dummy_full_node_1.set_as_down(self.channel_set, self.logger) self.dummy_full_node_3.set_as_down(self.channel_set, self.logger) self.monitor.data_sources = [ self.dummy_full_node_1, self.dummy_full_node_2, self.dummy_full_node_3, self.dummy_validator_node_1 ] mock_get_web_sockets.return_value = [self.dummy_ws_url_1] try: _ = self.monitor.data_source self.fail('Expected NoLiveNodeConnectedWithAnApiServerException' ' exception to be thrown.') except NoLiveNodeConnectedWithAnApiServerException: pass def test_status_returns_as_expected(self) -> None: self.dummy_blockchain.set_referendum_count(self.dummy_referendum_count, self.channel_set, self.logger) self.dummy_blockchain.set_validator_set_size( self.dummy_validator_set_size, self.channel_set, self.logger) self.dummy_blockchain.set_public_prop_count( self.dummy_public_prop_count, self.channel_set, self.logger) self.dummy_blockchain.set_council_prop_count( self.dummy_council_prop_count, self.channel_set, self.logger) expected_output = "referendum_count={}, public_prop_count={}, " \ "council_prop_count={}, validator_set_size ={}" \ .format(self.dummy_referendum_count, self.dummy_public_prop_count, self.dummy_council_prop_count, self.dummy_validator_set_size) self.assertEqual(expected_output, self.monitor.status()) def test_check_for_new_referendums_calls_ref_setter_once_if_ref_count_None( self) -> None: self.dummy_blockchain.set_referendum_count = MagicMock( side_effect=self.dummy_blockchain.set_referendum_count) self.monitor._check_for_new_referendums(self.dummy_referendum_count) self.assertEqual(self.dummy_blockchain.set_referendum_count.call_count, 1) @patch(GET_REFERENDUM_INFO_OF_FUNCTION, return_value=None) def test_check_for_new_referendums_calls_ref_setter_5_times_if_5_new_refs( self, _) -> None: with mock.patch(DATA_SOURCE_PATH, new_callable=PropertyMock) \ as mock_data_source: mock_data_source.return_value = self.dummy_full_node_1 self.dummy_blockchain.set_referendum_count( self.dummy_referendum_count, self.channel_set, self.logger) new_referendum_count = self.dummy_referendum_count + 5 self.dummy_blockchain.set_referendum_count = MagicMock( side_effect=self.dummy_blockchain.set_referendum_count) self.monitor._check_for_new_referendums(new_referendum_count) self.assertEqual( self.dummy_blockchain.set_referendum_count.call_count, 5) def test_check_for_new_referendums_calls_ref_setter_0_times_if_same_count( self) -> None: self.dummy_blockchain.set_referendum_count(self.dummy_referendum_count, self.channel_set, self.logger) new_referendum_count = self.dummy_referendum_count self.dummy_blockchain.set_referendum_count = MagicMock( side_effect=self.dummy_blockchain.set_referendum_count) self.monitor._check_for_new_referendums(new_referendum_count) self.assertEqual(self.dummy_blockchain.set_referendum_count.call_count, 0) @patch(GET_REFERENDUM_COUNT_FUNCTION) @patch(GET_COUNCIL_PROPOSAL_COUNT_FUNCTION) @patch(GET_PUBLIC_PROPOSAL_COUNT_FUNCTION) @patch(GET_SESSION_VALIDATORS_FUNCTION) def test_monitor_sets_blockchain_state_to_retrieved_data( self, mock_session_val, mock_public_prop, mock_council_prop, mock_ref_count) -> None: with mock.patch(DATA_SOURCE_PATH, new_callable=PropertyMock) \ as mock_data_source: mock_data_source.return_value = self.dummy_full_node_1 mock_session_val.return_value = ['7DG7fdgfd', 'dgtdFG884'] mock_public_prop.return_value = self.dummy_public_prop_count mock_council_prop.return_value = self.dummy_council_prop_count mock_ref_count.return_value = self.dummy_referendum_count self.monitor.last_data_source_used = self.dummy_full_node_1 self.monitor.monitor() self.assertEqual(self.dummy_blockchain.referendum_count, self.dummy_referendum_count) self.assertEqual(self.dummy_blockchain.public_prop_count, self.dummy_public_prop_count) self.assertEqual(self.dummy_blockchain.council_prop_count, self.dummy_council_prop_count) self.assertEqual(self.dummy_blockchain.validator_set_size, 2) @patch(GET_REFERENDUM_COUNT_FUNCTION, return_value=None) @patch(GET_COUNCIL_PROPOSAL_COUNT_FUNCTION, return_value=None) @patch(GET_PUBLIC_PROPOSAL_COUNT_FUNCTION, return_value=None) @patch(GET_SESSION_VALIDATORS_FUNCTION, return_value=[]) def test_monitor_sets_API_as_up_if_entire_data_obtained_successfully( self, _1, _2, _3, _4) -> None: with mock.patch(DATA_SOURCE_PATH, new_callable=PropertyMock) \ as mock_data_source: mock_data_source.return_value = self.dummy_full_node_1 self.monitor.last_data_source_used = self.dummy_full_node_1 self.monitor.monitor() self.assertFalse(self.monitor.data_wrapper.is_api_down) @patch(GET_REFERENDUM_COUNT_FUNCTION, return_value=None) @patch(GET_COUNCIL_PROPOSAL_COUNT_FUNCTION, return_value=None) @patch(GET_PUBLIC_PROPOSAL_COUNT_FUNCTION, return_value=None) @patch(GET_SESSION_VALIDATORS_FUNCTION, return_value=[]) def test_monitor_connects_data_source_with_api_if_entire_data_obtained_successfully( self, _1, _2, _3, _4) -> None: with mock.patch(DATA_SOURCE_PATH, new_callable=PropertyMock) \ as mock_data_source: mock_data_source.return_value = self.dummy_full_node_1 self.monitor.last_data_source_used = self.dummy_full_node_1 self.monitor.last_data_source_used.disconnect_from_api( self.channel_set, self.logger) self.assertFalse( self.monitor.last_data_source_used.is_connected_to_api_server) self.monitor.monitor() self.assertTrue( self.monitor.last_data_source_used.is_connected_to_api_server)
def setUp(self) -> None: self.logger = logging.getLogger('dummy') self.monitor_name = 'testnodemonitor' self.counter_channel = CounterChannel(self.logger) self.channel_set = ChannelSet([self.counter_channel], TestInternalConf) self.node_monitor_max_catch_up_blocks = \ TestInternalConf.node_monitor_max_catch_up_blocks self.redis = None self.archive_alerts_disabled = False self.data_sources = [] self.chain = 'testchain' self.full_node_name = 'testfullnode' self.full_node_api_url = '123.123.123.11:9944' self.full_node_consensus_key = "ANDSAdisadjasdaANDAsa" self.full_node_tendermint_key = "ASFLNAFIISDANNSDAKKS2313AA" self.full_node_entity_public_key = "a98dabsfkjabfkjabsf9j" self.full_node_staking_address = "asdsasdsdsaasdsdaswwad" self.full_node = Node( self.full_node_name, self.full_node_api_url, None, NodeType.NON_VALIDATOR_FULL_NODE, '', self.chain, None, True, self.full_node_consensus_key, self.full_node_tendermint_key, self.full_node_staking_address, self.full_node_entity_public_key, TestInternalConf) self.full_node_monitor = NodeMonitor( self.monitor_name, self.channel_set, self.logger, self.node_monitor_max_catch_up_blocks, self.redis, self.full_node, self.archive_alerts_disabled, self.data_sources, TestInternalConf) self.validator_name = 'testvalidator' self.validator_api_url = '13.13.14.11:9944' self.validator_consensus_key = "KASDB01923udlakd19sad" self.validator_tendermint_key = "ALSFNF9)901jjelakNALKNDLKA" self.validator_node_public_key = "DFJGDF8G898fdghb98dg9wetg9we00w" self.validator_node_entity_public_key = "s12adsdghas9as0sa9dhnaskdlan" self.validator_node_staking_address = "jujuujsmjmsjmaklzsdjsdnanz" self.validator = Node( self.validator_name, self.validator_api_url, None, NodeType.VALIDATOR_FULL_NODE, self.validator_node_public_key, self.chain, None, True, self.validator_consensus_key, self.validator_tendermint_key, self.validator_node_staking_address, self.validator_node_entity_public_key, TestInternalConf) self.validator_monitor = NodeMonitor( self.monitor_name, self.channel_set, self.logger, self.node_monitor_max_catch_up_blocks, self.redis, self.validator, self.archive_alerts_disabled, self.data_sources, TestInternalConf) self.dummy_last_height_checked = 1000 self.dummy_bonded_balance = scale_to_giga(5) self.dummy_debonding_balance = scale_to_giga(5) self.dummy_shares_balance = scale_to_giga(5) self.dummy_height_to_check = 1000 self.dummy_no_of_peers = 100 self.dummy_is_missing_blocks = False self.dummy_active = True self.dummy_finalized_block_height = 34535 self.dummy_api_url_1 = "11.22.33.11:9944" self.dummy_api_url_2 = "11.22.33.12:9944" self.dummy_api_url_3 = "11.22.33.13:9944" self.dummy_api_url_4 = "11.22.33.14:9944" self.dummy_api_url_5 = "11.22.33.15:9944" self.dummy_node_name_1 = "testnode1" self.dummy_node_name_2 = "testnode2" self.dummy_node_name_3 = "testnode3" self.dummy_node_name_4 = "testnode4" self.dummy_node_name_5 = "testnode5" self.dummy_validator_node_name_2 = "testvalidatornode2" self.dummy_validator_node_name_3 = "testvalidatornode3" self.dummy_node_consensus_key_1 = "consensus_key_1" self.dummy_node_consensus_key_2 = "consensus_key_2" self.dummy_node_consensus_key_3 = "consensus_key_3" self.dummy_node_tendermint_key_1 = "consensus_key_1" self.dummy_node_tendermint_key_2 = "consensus_key_2" self.dummy_node_tendermint_key_3 = "consensus_key_3" self.dummy_node_entity_public_key_1 = "entity_key_1" self.dummy_node_entity_public_key_2 = "entity_key_2" self.dummy_node_entity_public_key_3 = "entity_key_3" self.dummy_node_staking_address_1 = "staking-key_1" self.dummy_node_staking_address_2 = "staking_key_2" self.dummy_node_staking_address_3 = "staking_key_3" self.dummy_full_node_1 = Node( name=self.dummy_node_name_1, api_url=self.dummy_api_url_1, prometheus_endpoint=None, node_type=NodeType.NON_VALIDATOR_FULL_NODE, node_public_key='', chain=self.chain, redis=None, is_archive_node=True, consensus_public_key='', tendermint_address_key='', staking_address='', entity_public_key='', internal_conf=TestInternalConf) self.dummy_full_node_2 = Node( name=self.dummy_node_name_2, api_url=self.dummy_api_url_2, prometheus_endpoint=None, node_type=NodeType.NON_VALIDATOR_FULL_NODE, node_public_key='', chain=self.chain, redis=None, is_archive_node=True, consensus_public_key='', tendermint_address_key='', staking_address='', entity_public_key='', internal_conf=TestInternalConf) self.dummy_full_node_3 = Node( name=self.dummy_node_name_3, api_url=self.dummy_api_url_3, prometheus_endpoint=None, node_type=NodeType.NON_VALIDATOR_FULL_NODE, node_public_key='', chain=self.chain, redis=None, is_archive_node=True, consensus_public_key='', tendermint_address_key='', staking_address='', entity_public_key='', internal_conf=TestInternalConf) self.dummy_full_node_4 = Node( name=self.dummy_node_name_5, api_url=self.dummy_api_url_5, prometheus_endpoint=None, node_type=NodeType.NON_VALIDATOR_FULL_NODE, node_public_key='', chain=self.chain, redis=None, is_archive_node=False, consensus_public_key='', tendermint_address_key='', staking_address='', entity_public_key='', internal_conf=TestInternalConf) self.dummy_take_event_owner = { "escrow": { "take": { "owner": self.dummy_node_entity_public_key_1, "tokens": "2000000000" } } } self.dummy_validator_node_1 = Node( name=self.dummy_node_name_4, api_url=self.dummy_api_url_4, prometheus_endpoint=None, node_type=NodeType.VALIDATOR_FULL_NODE, node_public_key=self.validator_node_public_key, chain=self.chain, redis=None, is_archive_node=True, consensus_public_key=self.dummy_node_consensus_key_1, tendermint_address_key=self.dummy_node_tendermint_key_1, staking_address=self.dummy_node_staking_address_1, entity_public_key=self.dummy_node_entity_public_key_1, internal_conf=TestInternalConf) self.dummy_validator_node_2 = Node( name=self.dummy_validator_node_name_2, api_url=self.dummy_api_url_4, prometheus_endpoint=None, node_type=NodeType.VALIDATOR_FULL_NODE, node_public_key=self.validator_node_public_key, chain=self.chain, redis=None, is_archive_node=True, consensus_public_key=self.dummy_node_consensus_key_2, tendermint_address_key=self.dummy_node_tendermint_key_2, staking_address=self.dummy_node_staking_address_2, entity_public_key=self.dummy_node_entity_public_key_2, internal_conf=TestInternalConf) self.dummy_validator_node_3 = Node( name=self.dummy_validator_node_name_3, api_url=self.dummy_api_url_4, prometheus_endpoint=None, node_type=NodeType.VALIDATOR_FULL_NODE, node_public_key=self.validator_node_public_key, chain=self.chain, redis=None, is_archive_node=True, consensus_public_key=self.dummy_node_consensus_key_3, tendermint_address_key=self.dummy_node_tendermint_key_3, staking_address=self.dummy_node_staking_address_3, entity_public_key=self.dummy_node_entity_public_key_3, internal_conf=TestInternalConf)
class TestNodeMonitorWithoutRedis(unittest.TestCase): def setUp(self) -> None: self.logger = logging.getLogger('dummy') self.monitor_name = 'testnodemonitor' self.counter_channel = CounterChannel(self.logger) self.channel_set = ChannelSet([self.counter_channel], TestInternalConf) self.node_monitor_max_catch_up_blocks = \ TestInternalConf.node_monitor_max_catch_up_blocks self.redis = None self.archive_alerts_disabled = False self.data_sources = [] self.chain = 'testchain' self.full_node_name = 'testfullnode' self.full_node_api_url = '123.123.123.11:9944' self.full_node_consensus_key = "ANDSAdisadjasdaANDAsa" self.full_node_tendermint_key = "ASFLNAFIISDANNSDAKKS2313AA" self.full_node_entity_public_key = "a98dabsfkjabfkjabsf9j" self.full_node_staking_address = "asdsasdsdsaasdsdaswwad" self.full_node = Node( self.full_node_name, self.full_node_api_url, None, NodeType.NON_VALIDATOR_FULL_NODE, '', self.chain, None, True, self.full_node_consensus_key, self.full_node_tendermint_key, self.full_node_staking_address, self.full_node_entity_public_key, TestInternalConf) self.full_node_monitor = NodeMonitor( self.monitor_name, self.channel_set, self.logger, self.node_monitor_max_catch_up_blocks, self.redis, self.full_node, self.archive_alerts_disabled, self.data_sources, TestInternalConf) self.validator_name = 'testvalidator' self.validator_api_url = '13.13.14.11:9944' self.validator_consensus_key = "KASDB01923udlakd19sad" self.validator_tendermint_key = "ALSFNF9)901jjelakNALKNDLKA" self.validator_node_public_key = "DFJGDF8G898fdghb98dg9wetg9we00w" self.validator_node_entity_public_key = "s12adsdghas9as0sa9dhnaskdlan" self.validator_node_staking_address = "jujuujsmjmsjmaklzsdjsdnanz" self.validator = Node( self.validator_name, self.validator_api_url, None, NodeType.VALIDATOR_FULL_NODE, self.validator_node_public_key, self.chain, None, True, self.validator_consensus_key, self.validator_tendermint_key, self.validator_node_staking_address, self.validator_node_entity_public_key, TestInternalConf) self.validator_monitor = NodeMonitor( self.monitor_name, self.channel_set, self.logger, self.node_monitor_max_catch_up_blocks, self.redis, self.validator, self.archive_alerts_disabled, self.data_sources, TestInternalConf) self.dummy_last_height_checked = 1000 self.dummy_bonded_balance = scale_to_giga(5) self.dummy_debonding_balance = scale_to_giga(5) self.dummy_shares_balance = scale_to_giga(5) self.dummy_height_to_check = 1000 self.dummy_no_of_peers = 100 self.dummy_is_missing_blocks = False self.dummy_active = True self.dummy_finalized_block_height = 34535 self.dummy_api_url_1 = "11.22.33.11:9944" self.dummy_api_url_2 = "11.22.33.12:9944" self.dummy_api_url_3 = "11.22.33.13:9944" self.dummy_api_url_4 = "11.22.33.14:9944" self.dummy_api_url_5 = "11.22.33.15:9944" self.dummy_node_name_1 = "testnode1" self.dummy_node_name_2 = "testnode2" self.dummy_node_name_3 = "testnode3" self.dummy_node_name_4 = "testnode4" self.dummy_node_name_5 = "testnode5" self.dummy_validator_node_name_2 = "testvalidatornode2" self.dummy_validator_node_name_3 = "testvalidatornode3" self.dummy_node_consensus_key_1 = "consensus_key_1" self.dummy_node_consensus_key_2 = "consensus_key_2" self.dummy_node_consensus_key_3 = "consensus_key_3" self.dummy_node_tendermint_key_1 = "consensus_key_1" self.dummy_node_tendermint_key_2 = "consensus_key_2" self.dummy_node_tendermint_key_3 = "consensus_key_3" self.dummy_node_entity_public_key_1 = "entity_key_1" self.dummy_node_entity_public_key_2 = "entity_key_2" self.dummy_node_entity_public_key_3 = "entity_key_3" self.dummy_node_staking_address_1 = "staking-key_1" self.dummy_node_staking_address_2 = "staking_key_2" self.dummy_node_staking_address_3 = "staking_key_3" self.dummy_full_node_1 = Node( name=self.dummy_node_name_1, api_url=self.dummy_api_url_1, prometheus_endpoint=None, node_type=NodeType.NON_VALIDATOR_FULL_NODE, node_public_key='', chain=self.chain, redis=None, is_archive_node=True, consensus_public_key='', tendermint_address_key='', staking_address='', entity_public_key='', internal_conf=TestInternalConf) self.dummy_full_node_2 = Node( name=self.dummy_node_name_2, api_url=self.dummy_api_url_2, prometheus_endpoint=None, node_type=NodeType.NON_VALIDATOR_FULL_NODE, node_public_key='', chain=self.chain, redis=None, is_archive_node=True, consensus_public_key='', tendermint_address_key='', staking_address='', entity_public_key='', internal_conf=TestInternalConf) self.dummy_full_node_3 = Node( name=self.dummy_node_name_3, api_url=self.dummy_api_url_3, prometheus_endpoint=None, node_type=NodeType.NON_VALIDATOR_FULL_NODE, node_public_key='', chain=self.chain, redis=None, is_archive_node=True, consensus_public_key='', tendermint_address_key='', staking_address='', entity_public_key='', internal_conf=TestInternalConf) self.dummy_full_node_4 = Node( name=self.dummy_node_name_5, api_url=self.dummy_api_url_5, prometheus_endpoint=None, node_type=NodeType.NON_VALIDATOR_FULL_NODE, node_public_key='', chain=self.chain, redis=None, is_archive_node=False, consensus_public_key='', tendermint_address_key='', staking_address='', entity_public_key='', internal_conf=TestInternalConf) self.dummy_take_event_owner = { "escrow": { "take": { "owner": self.dummy_node_entity_public_key_1, "tokens": "2000000000" } } } self.dummy_validator_node_1 = Node( name=self.dummy_node_name_4, api_url=self.dummy_api_url_4, prometheus_endpoint=None, node_type=NodeType.VALIDATOR_FULL_NODE, node_public_key=self.validator_node_public_key, chain=self.chain, redis=None, is_archive_node=True, consensus_public_key=self.dummy_node_consensus_key_1, tendermint_address_key=self.dummy_node_tendermint_key_1, staking_address=self.dummy_node_staking_address_1, entity_public_key=self.dummy_node_entity_public_key_1, internal_conf=TestInternalConf) self.dummy_validator_node_2 = Node( name=self.dummy_validator_node_name_2, api_url=self.dummy_api_url_4, prometheus_endpoint=None, node_type=NodeType.VALIDATOR_FULL_NODE, node_public_key=self.validator_node_public_key, chain=self.chain, redis=None, is_archive_node=True, consensus_public_key=self.dummy_node_consensus_key_2, tendermint_address_key=self.dummy_node_tendermint_key_2, staking_address=self.dummy_node_staking_address_2, entity_public_key=self.dummy_node_entity_public_key_2, internal_conf=TestInternalConf) self.dummy_validator_node_3 = Node( name=self.dummy_validator_node_name_3, api_url=self.dummy_api_url_4, prometheus_endpoint=None, node_type=NodeType.VALIDATOR_FULL_NODE, node_public_key=self.validator_node_public_key, chain=self.chain, redis=None, is_archive_node=True, consensus_public_key=self.dummy_node_consensus_key_3, tendermint_address_key=self.dummy_node_tendermint_key_3, staking_address=self.dummy_node_staking_address_3, entity_public_key=self.dummy_node_entity_public_key_3, internal_conf=TestInternalConf) def test_indirect_monitoring_data_sources_field_set_correctly( self) -> None: self.data_sources = [ self.dummy_full_node_1, self.dummy_full_node_2, self.dummy_full_node_3, self.dummy_full_node_4, self.dummy_validator_node_1 ] test_monitor = NodeMonitor(self.monitor_name, self.channel_set, self.logger, self.node_monitor_max_catch_up_blocks, self.redis, self.validator, self.archive_alerts_disabled, self.data_sources, TestInternalConf) self.assertEqual(test_monitor.indirect_monitoring_data_sources, self.data_sources) def test_archive_monitoring_data_sources_field_set_correctly(self) -> None: self.data_sources = [ self.dummy_full_node_1, self.dummy_full_node_2, self.dummy_full_node_3, self.dummy_full_node_4, self.dummy_validator_node_1 ] test_monitor = NodeMonitor(self.monitor_name, self.channel_set, self.logger, self.node_monitor_max_catch_up_blocks, self.redis, self.validator, self.archive_alerts_disabled, self.data_sources, TestInternalConf) expected_result = [ self.dummy_full_node_1, self.dummy_full_node_2, self.dummy_full_node_3, self.dummy_validator_node_1 ] self.assertEqual(test_monitor.archive_monitoring_data_sources, expected_result) def test_is_catching_up_false_by_default(self) -> None: self.assertFalse(self.validator_monitor.is_catching_up()) def test_is_indirect_monitoring_disabled_true_if_no_data_sources( self) -> None: self.assertTrue(self.validator_monitor.indirect_monitoring_disabled) def test_is_indirect_monitoring_disabled_false_if_data_sources_given( self) -> None: self.data_sources = [self.dummy_full_node_1, self.dummy_full_node_2] test_monitor = NodeMonitor(self.monitor_name, self.channel_set, self.logger, self.node_monitor_max_catch_up_blocks, self.redis, self.validator, self.archive_alerts_disabled, self.data_sources, TestInternalConf) self.assertFalse(test_monitor.indirect_monitoring_disabled) def test_last_height_checked_NONE_by_default(self) -> None: self.assertEqual(NONE, self.validator_monitor.last_height_checked) def test_no_live_archive_node_alert_sent_false_by_default(self) -> None: self.assertFalse( self.validator_monitor.no_live_archive_node_alert_sent) @patch(PING_NODE_FUNCTION, return_value=None) @patch(GET_WEB_SOCKETS_FUNCTION, return_value=["testnode1", "testnode2", "testnode3", "testnode4"]) def test_data_source_chooses_an_online_full_node_connected_to_the_API( self, mock_get_web_sockets, _) -> None: self.dummy_full_node_1.set_as_down(self.channel_set, self.logger) self.dummy_validator_node_1.set_as_down(self.channel_set, self.logger) self.validator_monitor._indirect_monitoring_data_sources = [ self.dummy_full_node_1, self.dummy_validator_node_1, self.dummy_full_node_2, self.dummy_full_node_3 ] mock_get_web_sockets.return_value = [ self.dummy_node_name_1, self.dummy_node_name_4, self.dummy_node_name_3, self.dummy_node_name_5 ] node = self.validator_monitor.data_source_indirect self.assertEqual(node.name, self.dummy_node_name_3) @patch(PING_NODE_FUNCTION, return_value=None) @patch(GET_WEB_SOCKETS_FUNCTION, return_value=["testnode1", "testnode2", "testnode3", "testnode4"]) def test_data_source_chooses_an_online_validator_node_connected_to_the_API( self, mock_get_web_sockets, _) -> None: self.dummy_full_node_1.set_as_down(self.channel_set, self.logger) self.dummy_full_node_2.set_as_down(self.channel_set, self.logger) self.validator_monitor._indirect_monitoring_data_sources = [ self.dummy_full_node_1, self.dummy_validator_node_1, self.dummy_full_node_2, self.dummy_full_node_3 ] mock_get_web_sockets.return_value = [ self.dummy_node_name_1, self.dummy_node_name_4, self.dummy_node_name_3, self.dummy_node_name_5 ] node = self.validator_monitor.data_source_indirect self.assertEqual(node.name, self.dummy_node_name_4) @patch(GET_WEB_SOCKETS_FUNCTION) def test_data_source_indirect_raises_exception_if_no_node_is_eligible_for_choosing( self, mock_get_web_sockets) -> None: self.dummy_full_node_1.set_as_down(self.channel_set, self.logger) self.dummy_full_node_3.set_as_down(self.channel_set, self.logger) self.validator_monitor._indirect_monitoring_data_sources = [ self.dummy_full_node_1, self.dummy_full_node_2, self.dummy_full_node_3, self.dummy_validator_node_1 ] mock_get_web_sockets.return_value = [self.dummy_api_url_1] try: _ = self.validator_monitor.data_source_indirect self.fail('Expected NoLiveNodeConnectedWithAnApiServerException' ' exception to be thrown.') except NoLiveNodeConnectedWithAnApiServerException: pass @patch(PING_NODE_FUNCTION, return_value=None) @patch(GET_WEB_SOCKETS_FUNCTION, return_value=["testnode1", "testnode5"]) def test_data_source_archive_chooses_an_online_archive_full_node_connected_to_the_API( self, mock_get_web_sockets, _) -> None: self.dummy_full_node_1.set_as_down(self.channel_set, self.logger) self.dummy_full_node_3.set_as_down(self.channel_set, self.logger) self.validator_monitor._archive_monitoring_data_sources = [ self.dummy_full_node_1, self.dummy_full_node_2, self.dummy_full_node_3, self.dummy_validator_node_1, self.dummy_full_node_4 ] mock_get_web_sockets.return_value = [ self.dummy_node_name_1, self.dummy_node_name_5 ] node = self.validator_monitor.data_source_archive self.assertEqual(node.name, self.dummy_node_name_5) @patch(PING_NODE_FUNCTION, return_value=None) @patch(GET_WEB_SOCKETS_FUNCTION, return_value=["testnode1", "testnode4", "testnode5"]) def test_data_source_archive_chooses_an_online_archive_validator_node_connected_to_the_API( self, mock_get_web_sockets, _) -> None: self.dummy_full_node_1.set_as_down(self.channel_set, self.logger) self.dummy_full_node_3.set_as_down(self.channel_set, self.logger) self.dummy_full_node_2.set_as_down(self.channel_set, self.logger) self.validator_monitor._archive_monitoring_data_sources = [ self.dummy_full_node_1, self.dummy_full_node_2, self.dummy_full_node_3, self.dummy_validator_node_1, self.dummy_full_node_4 ] mock_get_web_sockets.return_value = [ self.dummy_node_name_1, self.dummy_node_name_4, self.dummy_node_name_5 ] node = self.validator_monitor.data_source_archive self.assertEqual(node.name, self.dummy_node_name_4) @patch(GET_FINALIZED_HEAD_FUNCTION, return_value={"height": "523686"}) @patch(PING_NODE_FUNCTION, return_value="pong") @patch(GET_SYNCING_FUNCTION, return_value="true") @patch(GET_PEERS_FUNCTION, return_value="92") def test_monitor_direct_sets_node_state_to_retrieved_data( self, _1, _2, _3, _4) -> None: self.validator_monitor.monitor_direct() self.assertFalse(self.validator.is_down) self.assertFalse(self.validator.is_syncing) self.assertEqual(self.validator.no_of_peers, 92) self.assertEqual(self.validator.finalized_block_height, 523686) @patch(GET_FINALIZED_HEAD_FUNCTION, return_value={"height": "523686"}) @patch(PING_NODE_FUNCTION, return_value="pong") @patch(GET_SYNCING_FUNCTION, return_value="true") @patch(GET_PEERS_FUNCTION, return_value="92") @patch(PING_NODE_FUNCTION, return_value=None) def test_monitor_direct_connects_node_to_api_if_monitoring_successful( self, _1, _2, _3_, _4, _5) -> None: self.validator.disconnect_from_api(self.channel_set, self.logger) self.assertFalse(self.validator.is_connected_to_api_server) self.counter_channel.reset() self.validator_monitor.monitor_direct() self.assertTrue(self.validator.is_connected_to_api_server) @patch(GET_WEB_SOCKETS_FUNCTION) def test_data_source_archive_raises_exception_if_no_archive_node_is_eligible_for_choosing( self, mock_get_web_sockets) -> None: self.dummy_full_node_1.set_as_down(self.channel_set, self.logger) self.dummy_full_node_3.set_as_down(self.channel_set, self.logger) self.dummy_validator_node_1.set_as_down(self.channel_set, self.logger) self.validator_monitor._archive_monitoring_data_sources = [ self.dummy_full_node_1, self.dummy_full_node_2, self.dummy_full_node_3, self.dummy_validator_node_1 ] mock_get_web_sockets.return_value = [ self.dummy_api_url_1, self.dummy_api_url_5 ] try: _ = self.validator_monitor.data_source_archive self.fail('Expected ' 'NoLiveArchiveNodeConnectedWithAnApiServerException' ' exception to be thrown.') except NoLiveArchiveNodeConnectedWithAnApiServerException: pass def test_status_returns_as_expected_for_validator_monitor(self) -> None: self.validator_monitor._last_height_checked = \ self.dummy_last_height_checked self.validator._bonded_balance = self.dummy_bonded_balance self.validator._debonding_balance = self.dummy_debonding_balance self.validator._shares_balance = self.dummy_shares_balance self.validator._no_of_peers = self.dummy_no_of_peers self.validator._active = self.dummy_active self.validator._finalized_block_height = \ self.dummy_finalized_block_height self.validator._is_missing_blocks = self.dummy_is_missing_blocks expected_output = "bonded_balance={}, debonding_balance={}, " \ "shares_balance={}, "\ "is_syncing=False, " \ "no_of_peers={}, active={}, " \ "finalized_block_height={}, " \ "is_missing_blocks={}, " \ "last_height_checked={}".format( self.dummy_bonded_balance, self.dummy_debonding_balance, self.dummy_shares_balance, self.dummy_no_of_peers, self.dummy_active, self.dummy_finalized_block_height, self.dummy_is_missing_blocks, self.dummy_last_height_checked) self.assertEqual(expected_output, self.validator_monitor.status()) def test_status_returns_as_expected_for_full_node_monitor(self) -> None: self.full_node._no_of_peers = self.dummy_no_of_peers self.full_node._finalized_block_height = \ self.dummy_finalized_block_height expected_output = "bonded_balance={}, debonding_balance={}, " \ "shares_balance={}, " \ "is_syncing=False, " \ "no_of_peers={}, active={}, " \ "finalized_block_height={}, " \ "is_missing_blocks=False" \ .format( None, None, None, self.dummy_no_of_peers, None, self.dummy_finalized_block_height) self.assertEqual(expected_output, self.full_node_monitor.status()) @patch(GET_FINALIZED_HEAD_FUNCTION, return_value={"height": "523686"}) @patch(PING_NODE_FUNCTION, return_value="pong") @patch(GET_SYNCING_FUNCTION, return_value="true") @patch(GET_PEERS_FUNCTION, return_value="92") def test_monitor_direct_sets_node_state_to_retrieved_data( self, _1, _2, _3, _4) -> None: self.validator_monitor.monitor_direct() self.assertFalse(self.validator.is_down) self.assertFalse(self.validator.is_syncing) self.assertEqual(self.validator.no_of_peers, 92) self.assertEqual(self.validator.finalized_block_height, 523686) @patch(GET_FINALIZED_HEAD_FUNCTION, return_value={"height": "523686"}) @patch(PING_NODE_FUNCTION, return_value="pong") @patch(GET_SYNCING_FUNCTION, return_value="true") @patch(GET_PEERS_FUNCTION, return_value="92") def test_monitor_direct_sets_API_as_up_if_monitoring_successful( self, _1, _2, _3, _4) -> None: self.validator_monitor.monitor_direct() self.assertFalse(self.validator_monitor.data_wrapper.is_api_down) @patch(GET_STAKING_EVENTS_BY_HEIGHT_FUNCTION, return_value=None) @patch(GET_STAKING_ACCOUNT_FUNCTION, return_value={ "escrow": { "active": { "balance": "9999999999993" }, "debonding": { "balance": "9999999999993" } } }) @patch(GET_SIGNED_BLOCKS_FUNCTION, return_value={ "signatures": [ { "validator_address": "06140E5B1FE5D72BAA12AED7815A7E19BC7BDABA" }, { "validator_address": "7C87340EFE4BE695E80099AE3B0CAE545381925D" }, { "validator_address": "0D73013810841C092B8ACB1A9646F412B62EE14C" }, ] }) @patch(GET_BLOCK_HEADER_AT_HEIGHT_FUNCTION, return_value={"height": "55666"}) @patch(GET_CONSENSUS_BLOCK_FUNCTION, return_value={"height":"55666", \ "meta": "asndiasbdiabsidjbasjiaslnlasndlkandlkasldknasdlknaskbda"}) @patch(GET_SESSION_VALIDATORS_FUNCTION, return_value=[]) @patch(GET_STAKING_DELEGATIONS_INFO_FUNCTION, return_value={ "Xq2d4D43YmBdUAOd3q6A0n1kaHUY766RE24xznk1Sgc=": { "shares": "27681494143232" } }) def test_monitor_indirect_sets_API_up_when_validator_indirect_monitoring_succesfull( self, _1, _2, _3, _4, _5, _6, _7) -> None: with mock.patch(DATA_SOURCE_INDIRECT_PATH, new_callable=PropertyMock) \ as mock_data_source_indirect: mock_data_source_indirect.return_value = self.dummy_full_node_1 self.validator_monitor.last_data_source_used = \ self.dummy_full_node_1 self.validator_monitor._archive_alerts_disabled = True self.validator_monitor.monitor_indirect() self.assertFalse(self.validator_monitor.data_wrapper.is_api_down) @patch(GET_STAKING_EVENTS_BY_HEIGHT_FUNCTION, return_value=None) @patch(GET_STAKING_ACCOUNT_FUNCTION, return_value={ "escrow": { "active": { "balance": "9999999999993" }, "debonding": { "balance": "9999999999993" } } }) @patch(GET_SIGNED_BLOCKS_FUNCTION, return_value={ "signatures": [ { "validator_address": "06140E5B1FE5D72BAA12AED7815A7E19BC7BDABA" }, { "validator_address": "7C87340EFE4BE695E80099AE3B0CAE545381925D" }, { "validator_address": "0D73013810841C092B8ACB1A9646F412B62EE14C" }, ] }) @patch(GET_BLOCK_HEADER_AT_HEIGHT_FUNCTION, return_value={"height": "55666"}) @patch(GET_CONSENSUS_BLOCK_FUNCTION, return_value={"height":"55666", \ "meta": "asndiasbdiabsidjbasjiaslnlasndlkandlkasldknasdlknaskbda"}) @patch(GET_SESSION_VALIDATORS_FUNCTION, return_value=[]) @patch(GET_STAKING_DELEGATIONS_INFO_FUNCTION, return_value={ "Xq2d4D43YmBdUAOd3q6A0n1kaHUY766RE24xznk1Sgc=": { "shares": "27681494143232" } }) def test_monitor_indirect_connects_data_source_with_api_if_monitoring_succesfull( self, _1, _2, _3, _4, _5, _6, _7) -> None: with mock.patch(DATA_SOURCE_INDIRECT_PATH, new_callable=PropertyMock) \ as mock_data_source_indirect: mock_data_source_indirect.return_value = self.dummy_full_node_1 self.validator_monitor.last_data_source_used = \ self.dummy_full_node_1 self.validator_monitor.last_data_source_used.disconnect_from_api( self.channel_set, self.logger) self.validator_monitor._archive_alerts_disabled = True self.validator_monitor.monitor_indirect() self.assertTrue(self.validator_monitor.last_data_source_used. is_connected_to_api_server) def test_monitor_indirect_full_node_sets_values_as_expected(self) -> None: self.full_node_monitor.monitor_indirect() self.assertEqual(self.full_node_monitor.node.bonded_balance, 0) self.assertFalse(self.full_node_monitor.node.is_active) @patch(GET_STAKING_DELEGATIONS_INFO_FUNCTION, return_value={ "Xq2d4D43YmBdUAOd3q6A0n1kaHUY766RE24xznk1Sgc=": { "shares": "27681494143232" } }) @patch(GET_STAKING_EVENTS_BY_HEIGHT_FUNCTION, return_value=None) @patch(GET_STAKING_ACCOUNT_FUNCTION, return_value={ "escrow": { "active": { "balance": "9999999999993" }, "debonding": { "balance": "9999999999993" } } }) @patch(GET_SIGNED_BLOCKS_FUNCTION, return_value={ "signatures": [ { "validator_address": "06140E5B1FE5D72BAA12AED7815A7E19BC7BDABA" }, { "validator_address": "7C87340EFE4BE695E80099AE3B0CAE545381925D" }, { "validator_address": "0D73013810841C092B8ACB1A9646F412B62EE14C" }, ] }) @patch(GET_BLOCK_HEADER_AT_HEIGHT_FUNCTION, return_value={"height": "55666"}) @patch(GET_CONSENSUS_BLOCK_FUNCTION, return_value={"height":"55666", \ "meta": "asndiasbdiabsidjbasjiaslnlasndlkandlkasldknasdlknaskbda"}) @patch(GET_SESSION_VALIDATORS_FUNCTION, return_value=[]) def test_monitor_indirect_validator_calls_monitor_archive_if_not_disabled( self, _1, _2, _3, _4, _5, _6, _7) -> None: with mock.patch(DATA_SOURCE_INDIRECT_PATH, new_callable=PropertyMock) \ as mock_data_source_indirect: mock_data_source_indirect.return_value = self.dummy_full_node_1 self.validator_monitor._monitor_archive_state = MagicMock() self.validator_monitor._monitor_indirect_validator() self.assertEqual( self.validator_monitor._monitor_archive_state.call_count, 1) @patch(GET_STAKING_EVENTS_BY_HEIGHT_FUNCTION, return_value=None) def test_monitor_archive_sets_catching_up_true_if_more_than_2_blocks_late( self, _1) -> None: with mock.patch(DATA_SOURCE_ARCHIVE_PATH, new_callable=PropertyMock) \ as mock_data_source_indirect: mock_data_source_indirect.return_value = self.dummy_full_node_1 # To make the monitor catch up archive_node_height = self.dummy_finalized_block_height + 4 self.dummy_full_node_1.update_finalized_block_height( archive_node_height, self.logger, self.channel_set) self.validator_monitor._last_height_checked = \ self.dummy_finalized_block_height self.validator_monitor._monitor_archive_state() self.assertTrue(self.validator_monitor._monitor_is_catching_up) @patch(GET_STAKING_EVENTS_BY_HEIGHT_FUNCTION, return_value=None) def test_monitor_archive_sets_catching_up_false_if_less_than_2_blocks_late( self, _1) -> None: with mock.patch(DATA_SOURCE_ARCHIVE_PATH, new_callable=PropertyMock) \ as mock_data_source_indirect: mock_data_source_indirect.return_value = self.dummy_full_node_1 self.dummy_full_node_1.update_finalized_block_height( self.dummy_finalized_block_height, self.logger, self.channel_set) self.validator_monitor._monitor_archive_state() self.assertFalse(self.validator_monitor._monitor_is_catching_up) @patch(GET_STAKING_EVENTS_BY_HEIGHT_FUNCTION, return_value=None) def test_monitor_archive_sets_catching_up_false_if_2_blocks_late( self, _1) -> None: with mock.patch(DATA_SOURCE_ARCHIVE_PATH, new_callable=PropertyMock) \ as mock_data_source_indirect: mock_data_source_indirect.return_value = self.dummy_full_node_1 self.dummy_full_node_1.update_finalized_block_height( self.dummy_finalized_block_height, self.logger, self.channel_set) self.validator_monitor._last_height_checked = \ self.dummy_finalized_block_height - 2 self.validator_monitor._monitor_archive_state() self.assertFalse(self.validator_monitor._monitor_is_catching_up) @patch(GET_STAKING_EVENTS_BY_HEIGHT_FUNCTION, return_value=None) def test_monitor_archive_raises_info_alert_if_monitoring_round_successful_and_error_alert_sent( self, _1) -> None: with mock.patch(DATA_SOURCE_ARCHIVE_PATH, new_callable=PropertyMock) \ as mock_data_source_indirect: mock_data_source_indirect.return_value = self.dummy_full_node_1 self.validator_monitor._no_live_archive_node_alert_sent = True self.validator_monitor._monitor_archive_state() self.assertEqual(self.counter_channel.info_count, 1) self.assertFalse( self.validator_monitor._no_live_archive_node_alert_sent) self.assertIsInstance(self.counter_channel.latest_alert, FoundLiveArchiveNodeAgainAlert) @patch(GET_STAKING_EVENTS_BY_HEIGHT_FUNCTION, return_value=None) def test_monitor_archive_no_alerts_if_monitoring_round_successful_error_alert_not_sent_previously( self, _1) -> None: with mock.patch(DATA_SOURCE_ARCHIVE_PATH, new_callable=PropertyMock) \ as mock_data_source_indirect: mock_data_source_indirect.return_value = self.dummy_full_node_1 self.validator_monitor._monitor_archive_state() self.assertTrue(self.counter_channel.no_alerts()) self.assertFalse( self.validator_monitor._no_live_archive_node_alert_sent) @patch(GET_STAKING_EVENTS_BY_HEIGHT_FUNCTION, return_value= \ [{"escrow" : {"take" : {"owner" : "entity_key_1", "tokens": "2000000000"}}}]) def test_monitor_archive_if_a_slashing_event_occurs_for_1_node(self, _1) -> None: with mock.patch(DATA_SOURCE_ARCHIVE_PATH, new_callable=PropertyMock) \ as mock_data_source_indirect: mock_data_source_indirect.return_value = self.dummy_full_node_1 self.data_sources = [self.dummy_validator_node_1] test_monitor = NodeMonitor(self.monitor_name, self.channel_set, self.logger, self.node_monitor_max_catch_up_blocks, self.redis, self.validator, self.archive_alerts_disabled, self.data_sources, TestInternalConf) # To make the monitor catch up archive_node_height = self.dummy_finalized_block_height + 4 self.dummy_full_node_1.update_finalized_block_height( archive_node_height, self.logger, self.channel_set) test_monitor._last_height_checked = \ self.dummy_finalized_block_height test_monitor._monitor_archive_state() self.assertEqual(self.counter_channel.critical_count, 1) @patch(GET_STAKING_EVENTS_BY_HEIGHT_FUNCTION, return_value= \ [{"escrow" : {"take" : {"owner" : "entity_key_1", "tokens": "2000000000"}}}, {"escrow" : {"take" : {"owner" : "entity_key_2", "tokens": "2000000000"}}}, {"escrow" : {"take" : {"owner" : "entity_key_3", "tokens": "2000000000"}}}]) def test_monitor_archive_if_a_slashing_event_occurs_for_3_nodes( self, _1) -> None: with mock.patch(DATA_SOURCE_ARCHIVE_PATH, new_callable=PropertyMock) \ as mock_data_source_indirect: mock_data_source_indirect.return_value = self.dummy_full_node_1 self.data_sources = [ self.dummy_validator_node_1, self.dummy_validator_node_2, self.dummy_validator_node_3 ] test_monitor = NodeMonitor(self.monitor_name, self.channel_set, self.logger, self.node_monitor_max_catch_up_blocks, self.redis, self.validator, self.archive_alerts_disabled, self.data_sources, TestInternalConf) # To make the monitor catch up archive_node_height = self.dummy_finalized_block_height + 4 self.dummy_full_node_1.update_finalized_block_height( archive_node_height, self.logger, self.channel_set) test_monitor._last_height_checked = \ self.dummy_finalized_block_height test_monitor._monitor_archive_state() self.assertEqual(self.counter_channel.critical_count, 3)