def is_connected_to_primary_validator(*, primary_validator_address, self_configuration): """Return boolean to indicate if self is connected to primary validator""" url = f'{primary_validator_address}/validators/{self_configuration.node_identifier}' try: fetch(url=url, headers={}) return True except Exception as e: capture_exception(e) logger.exception(e) return False
def create_validators(*, known_nodes, results): """ For each unknown validator, attempt to: - fetch config data - create new Validator object """ for validator in get_unknown_nodes(known_nodes=known_nodes, results=results): try: address = format_address(ip_address=validator.get('ip_address'), port=validator.get('port'), protocol=validator.get('protocol')) config_address = f'{address}/config' config_data = fetch(url=config_address, headers={}) serializer = ValidatorConfigurationSerializer(data=config_data) if serializer.is_valid(): create_validator_from_config_data(config_data=config_data) continue logger.exception(serializer.errors) except Exception as e: capture_exception(e) logger.exception(e)
def crawl_banks(*, primary_validator_address, self_node_identifier): """ Crawl all banks from primary validator and create any new banks """ known_nodes = get_known_nodes(node_class=Bank) next_url = f'{primary_validator_address}/banks' while next_url: if cache.get(CRAWL_STATUS) == CRAWL_STATUS_STOP_REQUESTED: break try: response = fetch(url=next_url, headers={}) next_url = response.get('next') results = response.get('results') results = [ i for i in results if i['node_identifier'] != self_node_identifier ] create_banks(known_nodes=known_nodes, results=results) except Exception as e: capture_exception(e) logger.exception(e) break
def get_node_config(data): """ Attempt to connect to node Return nodes config data after validation """ ip_address = data['ip_address'] protocol = data['protocol'] try: address = format_address( ip_address=ip_address, port=data.get('port'), protocol=protocol ) config_address = f'{address}/config' config_data = fetch(url=config_address, headers={}) if config_data['node_type'] == BANK: config_serializer = BankConfigurationSerializer(data=config_data) elif config_data['node_type'] == CONFIRMATION_VALIDATOR: config_serializer = ValidatorConfigurationSerializer(data=config_data) elif config_data['node_type'] == PRIMARY_VALIDATOR: raise serializers.ValidationError('Unable to accept connection requests from primary validators') else: raise serializers.ValidationError('Invalid node_type') except Exception as e: logger.exception(e) raise e if config_serializer.is_valid(): return config_data else: logger.exception(config_serializer.errors) raise serializers.ValidationError(config_serializer.errors)
def is_self_known_to_node(*, node, self_configuration): """Return boolean to indicate if self is known to node""" node_address = format_address( ip_address=node.ip_address, port=node.port, protocol=node.protocol, ) url = f'{node_address}/banks/{self_configuration.node_identifier}' try: fetch(url=url, headers={}) return True except Exception as e: logger.debug(e) return False
def create(self, validated_data): """ Handle banks primary validator updated notice A response of True indicates to the requesting bank that self (this validator) will remain on the same network Delete banks switching to different networks """ bank = validated_data['node_identifier'] ip_address = validated_data['ip_address'] port = validated_data['port'] protocol = validated_data['protocol'] self_configuration = get_self_configuration( exception_class=RuntimeError) if self.primary_validator_synchronized( ip_address=ip_address, self_configuration=self_configuration): return True if (self_configuration.node_type == CONFIRMATION_VALIDATOR and bank == get_most_trusted_bank()): address = format_address(ip_address=ip_address, port=port, protocol=protocol) try: config = fetch(url=f'{address}/config', headers={}) except Exception as e: capture_exception(e) logger.exception(e) else: sync_with_primary_validator.delay(config=config) return True bank.delete() raise serializers.ValidationError('Networks out of sync')
def get_confirmation_block(*, address, block_identifier): """ Return confirmation block chain segment """ url = f'{address}/confirmation_blocks/{block_identifier}' results = fetch(url=url, headers={}) return results
def get_validator_config(self): """ Return config """ address = self.get_primary_validator_address() url = f'{address}/config' results = fetch(url=url, headers={}) return results
def get_account_balance_lock(*, account_number): """ Return the balance lock for the given account """ bank_address = format_address(ip_address='192.168.1.75', port=8000, protocol='http') url = f'{bank_address}/account_balance_lock/{account_number}' results = fetch(url=url, headers={}) return results['balance_lock']
def get_confirmation_block_chain_segment(*, address, block_identifier): """ Return confirmation block chain segment """ url = f'{address}/confirmation_block_chain_segment/{block_identifier}' try: results = fetch(url=url, headers={}) return results except JSONDecodeError: return [] except Exception as e: print(e) return []
def fetch_valid_confirmation_block(*, primary_validator, block_identifier): """ Return valid confirmation block """ address = format_address(ip_address=primary_validator.ip_address, port=primary_validator.port, protocol=primary_validator.protocol) url = f'{address}/valid_confirmation_blocks/{block_identifier}' try: results = fetch(url=url, headers={}) return results except Exception as e: logger.exception(e)
def crawl_validators(*, primary_validator_address): """Crawl all validators from primary validator and create any new validators""" known_nodes = get_known_nodes(node_class=Validator) next_url = f'{primary_validator_address}/validators' while next_url: if cache.get(CRAWL_STATUS) == CRAWL_STATUS_STOP_REQUESTED: break try: response = fetch(url=next_url, headers={}) next_url = response.get('next') results = response.get('results') create_validators(known_nodes=known_nodes, results=results) except Exception as e: logger.exception(e) break
def fetch_account_data(): """ Fetch all account data from primary validator Return list of accounts """ results = [] next_url = f'http://{PRIMARY_VALIDATOR_IP}/accounts' while next_url: print(next_url) data = fetch(url=next_url, headers={}) accounts = data['results'] results += accounts next_url = data['next'] return results
def get_account_balance_lock(*, account_number, live_pv=False): """ Return the balance lock for the given account """ if live_pv: pv_address = format_address( ip_address='64.225.47.205', port=None, protocol='http' ) else: pv_address = format_address( ip_address='192.168.1.75', port=8000, protocol='http' ) url = f'{pv_address}/account_balance_lock/{account_number}' results = fetch(url=url, headers={}) return results['balance_lock']
def create_banks(*, known_nodes, results): """ For each unknown bank, attempt to: - fetch config data - create new Bank object """ for bank in get_unknown_nodes(known_nodes=known_nodes, results=results): try: address = format_address(ip_address=bank.get('ip_address'), port=bank.get('port'), protocol=bank.get('protocol')) config_address = f'{address}/config' config_data = fetch(url=config_address, headers={}) serializer = BankConfigurationSerializer(data=config_data) if serializer.is_valid(): create_bank_from_config_data(config_data=config_data) continue logger.exception(serializer.errors) except Exception as e: logger.exception(e)
def clean_nodes(*, nodes_type): """ Clean nodes: delete or update nodes of type BANK or CONFIRMATION_VALIDATOR """ self_configuration = get_self_configuration(exception_class=RuntimeError) primary_validator = self_configuration.primary_validator excluded_node_identifiers = [ self_configuration.node_identifier, primary_validator.node_identifier ] if nodes_type == BANK: model = Bank elif nodes_type == CONFIRMATION_VALIDATOR: model = Validator else: raise RuntimeError(f'Invalid nodes_type of {nodes_type}') nodes = model.objects.all().exclude( node_identifier__in=excluded_node_identifiers) nodes_to_delete = [] for node in nodes: if cache.get(CLEAN_STATUS) == CLEAN_STATUS_STOP_REQUESTED: break try: address = format_address(ip_address=node.ip_address, port=node.port, protocol=node.protocol) config_address = f'{address}/config' config_data = fetch(url=config_address, headers={}) except Exception as e: capture_exception(e) logger.exception(e) nodes_to_delete.append(node.id) continue for field in ['ip_address', 'port', 'protocol', 'node_identifier']: if config_data.get(field) != getattr(node, field): nodes_to_delete.append(node.id) continue if nodes_type == BANK: serializer = BankConfigurationSerializer(data=config_data) if serializer.is_valid(): update_bank_from_config_data(bank=node, config_data=config_data) else: logger.exception(serializer.errors) nodes_to_delete.append(node.id) continue if nodes_type == CONFIRMATION_VALIDATOR: serializer = ValidatorConfigurationSerializer(data=config_data) if serializer.is_valid(): update_validator_from_config_data(validator=node, config_data=config_data) else: logger.exception(serializer.errors) nodes_to_delete.append(node.id) continue nodes.filter(id__in=nodes_to_delete).delete()