def on_tac_error(self, message: TACMessage, sender: Address) -> None: """ Handle 'on tac error' event emitted by the controller. :param error: the error object :return: None """ error_code = TACMessage.ErrorCode(message.get("error_code")) logger.error( "[{}]: Received error from the controller. error_msg={}".format( self.agent_name, TACMessage._from_ec_to_msg.get(error_code))) if error_code == TACMessage.ErrorCode.TRANSACTION_NOT_VALID: # if error in checking transaction, remove it from the pending transactions. start_idx_of_tx_id = len("Error in checking transaction: ") transaction_id = message.get("error_msg")[start_idx_of_tx_id:] if transaction_id in self.game_instance.transaction_manager.locked_txs: self.game_instance.transaction_manager.pop_locked_tx( transaction_id) else: logger.warning( "[{}]: Received error on unknown transaction id: {}". format(self.agent_name, transaction_id)) pass elif error_code == TACMessage.ErrorCode.TRANSACTION_NOT_MATCHING: pass elif error_code == TACMessage.ErrorCode.AGENT_PBK_ALREADY_REGISTERED or error_code == TACMessage.ErrorCode.AGENT_NAME_ALREADY_REGISTERED or error_code == TACMessage.ErrorCode.AGENT_NOT_REGISTERED: self.liveness._is_stopped = True elif error_code == TACMessage.ErrorCode.REQUEST_NOT_VALID or error_code == TACMessage.ErrorCode.GENERIC_ERROR: logger.warning( "[{}]: Check last request sent and investigate!".format( self.agent_name))
def _handle_valid_transaction( self, message: TACMessage, sender: Address, transaction: Transaction ) -> None: """ Handle a valid transaction. That is: - update the game state - send a transaction confirmation both to the buyer and the seller. :param tx: the transaction. :return: None """ logger.debug( "[{}]: Handling valid transaction: {}".format( self.controller_agent.name, message.get("transaction_id") ) ) # update the game state. self.controller_agent.game_handler.current_game.settle_transaction(transaction) # update the dashboard monitor self.controller_agent.game_handler.monitor.update() # send the transaction confirmation. tac_msg = TACMessage( tac_type=TACMessage.Type.TRANSACTION_CONFIRMATION, transaction_id=message.get("transaction_id"), ) tac_bytes = TACSerializer().encode(tac_msg) self.controller_agent.outbox.put_message( to=sender, sender=self.controller_agent.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes, ) self.controller_agent.outbox.put_message( to=message.get("counterparty"), sender=self.controller_agent.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes, ) # log messages logger.debug( "[{}]: Transaction '{}' settled successfully.".format( self.controller_agent.name, message.get("transaction_id") ) ) holdings_summary = ( self.controller_agent.game_handler.current_game.get_holdings_summary() ) logger.debug( "[{}]: Current state:\n{}".format( self.controller_agent.name, holdings_summary ) )
def handle_agent_message(self, envelope: Envelope) -> None: """ Dispatch the TACMessage to the right handler. If no handler is found for the provided type of TACMessage, return an "invalid TACMessage" error. If something bad happen, return a "generic" error. :param envelope: the envelope to handle :return: None """ assert envelope.protocol_id == "tac" tac_msg = TACSerializer().decode(envelope.message) logger.debug( "[{}] on_message: origin={}".format( self.controller_agent.name, envelope.sender ) ) tac_msg_type = tac_msg.get("type") handle_tac_message = self.handlers.get( TACMessage.Type(tac_msg_type), None ) # type: Optional[TACMessageHandler] if handle_tac_message is None: logger.debug( "[{}]: Unknown message from {}".format( self.controller_agent.name, envelope.sender ) ) tac_error = TACMessage( tac_type=TACMessage.Type.TAC_ERROR, error_code=TACMessage.ErrorCode.REQUEST_NOT_VALID.value, ) tac_bytes = TACSerializer().encode(tac_error) self.controller_agent.mailbox.outbox.put_message( to=envelope.sender, sender=self.controller_agent.crypto.public_key, protocol_id=tac_error.protocol_id, message=tac_bytes, ) return else: try: handle_tac_message(tac_msg, envelope.sender) except Exception as e: logger.debug( "[{}]: Error caught: {}".format(self.controller_agent.name, str(e)) ) logger.exception(e) tac_error = TACMessage( tac_type=TACMessage.Type.TAC_ERROR, error_code=TACMessage.ErrorCode.GENERIC_ERROR.value, ) tac_bytes = TACSerializer().encode(tac_error) self.controller_agent.mailbox.outbox.put_message( to=envelope.sender, sender=self.controller_agent.crypto.public_key, protocol_id=tac_error.protocol_id, message=tac_bytes, )
def handle(self, message: TACMessage, sender: Address) -> None: """ Handle a transaction TACMessage message. If the transaction is invalid (e.g. because the state of the game are not consistent), reply with an error. :param message: the 'get agent state' TACMessage. :param sender: the public key of the sender :return: None """ transaction = Transaction.from_message(message, sender) logger.debug( "[{}]: Handling transaction: {}".format( self.controller_agent.name, transaction ) ) # if transaction arrives first time then put it into the pending pool if message.get("transaction_id") not in self._pending_transaction_requests: if self.controller_agent.game_handler.current_game.is_transaction_valid( transaction ): logger.debug( "[{}]: Put transaction TACMessage in the pool: {}".format( self.controller_agent.name, message.get("transaction_id") ) ) self._pending_transaction_requests[ message.get("transaction_id") ] = transaction else: self._handle_invalid_transaction(message, sender) # if transaction arrives second time then process it else: pending_tx = self._pending_transaction_requests.pop( message.get("transaction_id") ) if transaction.matches(pending_tx): if self.controller_agent.game_handler.current_game.is_transaction_valid( transaction ): self.controller_agent.game_handler.confirmed_transaction_per_participant[ pending_tx.sender ].append( pending_tx ) self.controller_agent.game_handler.confirmed_transaction_per_participant[ transaction.sender ].append( transaction ) self._handle_valid_transaction(message, sender, transaction) else: self._handle_invalid_transaction(message, sender) else: self._handle_non_matching_transaction(message, sender)
def on_start(self, message: TACMessage, sender: Address) -> None: """ Handle the 'start' event emitted by the controller. :param game_data: the game data :return: None """ logger.debug( "[{}]: Received start event from the controller. Starting to compete..." .format(self.agent_name)) game_data = GameData( sender, message.get("money"), message.get("endowment"), message.get("utility_params"), message.get("nb_agents"), message.get("nb_goods"), message.get("tx_fee"), message.get("agent_pbk_to_name"), message.get("good_pbk_to_name"), message.get("version_id"), ) self.game_instance.init(game_data, self.crypto.public_key) self.game_instance._game_phase = GamePhase.GAME dashboard = self.game_instance.dashboard if dashboard is not None: dashboard.init() dashboard.update_from_agent_state(self.game_instance.agent_state, append=False)
def handle(self, message: TACMessage, sender: Address) -> None: """ Handle a 'get agent state' TACMessage. If the public key is not registered, answer with an error message. :param message: the 'get agent state' TACMessage. :param sender: the public key of the sender :return: None """ logger.debug( "[{}]: Handling the 'get agent state' TACMessage: {}".format( self.controller_agent.name, message ) ) if not self.controller_agent.game_handler.is_game_running: logger.error( "[{}]: GetStateUpdate TACMessage is not valid while the competition is not running.".format( self.controller_agent.name ) ) tac_msg = TACMessage( tac_type=TACMessage.Type.TAC_ERROR, error_code=TACMessage.ErrorCode.COMPETITION_NOT_RUNNING, ) if sender not in self.controller_agent.game_handler.registered_agents: logger.error( "[{}]: Agent not registered: '{}'".format( self.controller_agent.name, message.get("agent_name") ) ) tac_msg = TACMessage( tac_type=TACMessage.Type.TAC_ERROR, error_code=TACMessage.ErrorCode.AGENT_NOT_REGISTERED, ) else: transactions = self.controller_agent.game_handler.confirmed_transaction_per_participant[ sender ] # type: List[Transaction] initial_game_data = self.controller_agent.game_handler.game_data_per_participant[ sender ] # type: GameData tac_msg = TACMessage( tac_type=TACMessage.Type.STATE_UPDATE, initial_state=initial_game_data, transactions=transactions, ) tac_bytes = TACSerializer().encode(tac_msg) self.controller_agent.mailbox.outbox.put_message( to=sender, sender=self.controller_agent.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes, )
def _handle_invalid_transaction(self, message: TACMessage, sender: Address) -> None: """Handle an invalid transaction.""" tac_msg = TACMessage( tac_type=TACMessage.Type.TAC_ERROR, error_code=TACMessage.ErrorCode.TRANSACTION_NOT_VALID, details={"transaction_id": message.get("transaction_id")}) tac_bytes = TACSerializer().encode(tac_msg) self.controller_agent.mailbox.outbox.put_message( to=sender, sender=self.controller_agent.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes)
def on_state_update(self, message: TACMessage, agent_pbk: Address) -> None: """ Update the game instance with a State Update from the controller. :param state_update: the state update :param agent_pbk: the public key of the agent :return: None """ self.init(message.get("initial_state"), agent_pbk) self._game_phase = GamePhase.GAME for tx in message.get("transactions"): self.agent_state.update(tx, message.get("initial_state").get("tx_fee"))
def handle(self, message: TACMessage, sender: Address) -> None: """ Handle a unregister message. If the public key is not registered, answer with an error message. :param message: the 'get agent state' TACMessage. :param sender: the public key of the sender :return: None """ if sender not in self.controller_agent.game_handler.registered_agents: logger.error("[{}]: Agent not registered: '{}'".format( self.controller_agent.name, sender)) tac_msg = TACMessage( tac_type=TACMessage.Type.TAC_ERROR, error_code=TACMessage.ErrorCode.AGENT_NOT_REGISTERED) tac_bytes = TACSerializer().encode(tac_msg) self.controller_agent.mailbox.outbox.put_message( to=sender, sender=self.controller_agent.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes) else: logger.debug("[{}]: Agent unregistered: '{}'".format( self.controller_agent.name, self.controller_agent.game_handler.agent_pbk_to_name[sender])) self.controller_agent.game_handler.registered_agents.remove(sender) self.controller_agent.game_handler.agent_pbk_to_name.pop(sender)
def request_state_update(self) -> None: """ Request current agent state from TAC Controller. :return: None """ tac_msg = TACMessage(tac_type=TACMessage.Type.GET_STATE_UPDATE) tac_bytes = TACSerializer().encode(tac_msg) self.mailbox.outbox.put_message(to=self.game_instance.controller_pbk, sender=self.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes)
def on_dialogue_error(self, message: TACMessage, sender: Address) -> None: """ Handle dialogue error event emitted by the controller. :param message: the dialogue error message :param sender: the address of the sender :return: None """ logger.warning( "[{}]: Received Dialogue error from: details={}, sender={}".format( self.agent_name, message.get("details"), sender))
def _handle_non_matching_transaction(self, message: TACMessage, sender: Address) -> None: """Handle non-matching transaction.""" tac_msg = TACMessage( tac_type=TACMessage.Type.TAC_ERROR, error_code=TACMessage.ErrorCode.TRANSACTION_NOT_MATCHING) tac_bytes = TACSerializer().encode(tac_msg) self.controller_agent.mailbox.outbox.put_message( to=sender, sender=self.controller_agent.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes)
def on_transaction_confirmed(self, message: TACMessage, sender: Address) -> None: """ Handle 'on transaction confirmed' event emitted by the controller. :param tx_confirmation: the transaction confirmation :return: None """ logger.debug( "[{}]: Received transaction confirmation from the controller: transaction_id={}" .format(self.agent_name, message.get("transaction_id"))) if (message.get("transaction_id") not in self.game_instance.transaction_manager.locked_txs): logger.debug( "[{}]: transaction not found - ask the controller an update of the state." .format(self.agent_name)) self._request_state_update() return transaction = self.game_instance.transaction_manager.pop_locked_tx( message.get("transaction_id")) self.game_instance.agent_state.update( transaction, self.game_instance.game_configuration.tx_fee) dialogue_label = dialogue_label_from_transaction_id( self.crypto.public_key, message.get("transaction_id")) self.game_instance.stats_manager.add_dialogue_endstate( EndState.SUCCESSFUL, self.crypto.public_key == dialogue_label.dialogue_starter_pbk, ) dashboard = self.game_instance.dashboard if dashboard is not None: dashboard.update_from_agent_state(self.game_instance.agent_state, append=True) # recover agent agent_name from public key agent_name = self.game_instance.game_configuration.agent_names[ list(self.game_instance.game_configuration.agent_pbks).index( transaction.counterparty)] dashboard.add_transaction(transaction, agent_name=agent_name)
def notify_competition_cancelled(self): """Notify agents that the TAC is cancelled.""" logger.debug("[{}]: Notifying agents that TAC is cancelled.".format( self.agent_name)) for agent_pbk in self.registered_agents: tac_msg = TACMessage(tac_type=TACMessage.Type.CANCELLED) tac_bytes = TACSerializer().encode(tac_msg) self.mailbox.outbox.put_message(to=agent_pbk, sender=self.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes) # wait some time to make sure the connection delivers the messages time.sleep(2.0) self._game_phase = GamePhase.POST_GAME
def on_state_update(self, message: TACMessage, sender: Address) -> None: """ Handle 'on state update' event emitted by the controller. :param state_update: StateUpdate :return: None """ self.game_instance.on_state_update(message.get("state_update"), self.crypto.public_key) dashboard = self.game_instance.dashboard if dashboard is not None: dashboard.update_from_agent_state(self.game_instance.agent_state, append=False)
def _send_game_data_to_agents(self) -> None: """ Send the data of every agent about the game (e.g. endowments, preferences, scores). Assuming that the agent labels are public keys of the OEF Agents. :return: None. """ for public_key in self.current_game.configuration.agent_pbks: agent_state = self.current_game.get_agent_state_from_agent_pbk(public_key) game_data_response = GameData( public_key, agent_state.balance, agent_state.current_holdings, agent_state.utility_params, self.current_game.configuration.nb_agents, self.current_game.configuration.nb_goods, self.current_game.configuration.tx_fee, self.current_game.configuration.agent_pbk_to_name, self.current_game.configuration.good_pbk_to_name, self.current_game.configuration.version_id, ) logger.debug( "[{}]: sending GameData to '{}': {}".format( self.agent_name, public_key, str(game_data_response) ) ) self.game_data_per_participant[public_key] = game_data_response msg = TACMessage( tac_type=TACMessage.Type.GAME_DATA, money=agent_state.balance, endowment=agent_state.current_holdings, utility_params=agent_state.utility_params, nb_agents=self.current_game.configuration.nb_agents, nb_goods=self.current_game.configuration.nb_goods, tx_fee=self.current_game.configuration.tx_fee, agent_pbk_to_name=self.current_game.configuration.agent_pbk_to_name, good_pbk_to_name=self.current_game.configuration.good_pbk_to_name, version_id=self.current_game.configuration.version_id, ) tac_bytes = TACSerializer().encode(msg) self.mailbox.outbox.put_message( to=public_key, sender=self.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes, )
def _rejoin_tac(self, controller_pbk: Address) -> None: """ Rejoin the TAC run by a Controller. :param controller_pbk: the public key of the controller. :return: None """ self.game_instance.controller_pbk = controller_pbk self.game_instance._game_phase = GamePhase.GAME_SETUP tac_msg = TACMessage(tac_type=TACMessage.Type.GET_STATE_UPDATE) tac_bytes = TACSerializer().encode(tac_msg) self.mailbox.outbox.put_message(to=self.game_instance.controller_pbk, sender=self.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes)
def _register_to_tac(self, controller_pbk: Address) -> None: """ Register to active TAC Controller. :param controller_pbk: the public key of the controller. :return: None """ self.game_instance.controller_pbk = controller_pbk self.game_instance._game_phase = GamePhase.GAME_SETUP tac_msg = TACMessage(tac_type=TACMessage.Type.REGISTER, agent_name=self.agent_name) tac_bytes = TACSerializer().encode(tac_msg) self.mailbox.outbox.put_message(to=self.game_instance.controller_pbk, sender=self.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes)
def on_match_accept(self, match_accept: Message, dialogue: Dialogue) -> List[Envelope]: """ Handle a matching Accept. :param match_accept: the envelope containing the MatchAccept :param dialogue: the dialogue :return: a Transaction """ assert (match_accept.get("performative") == FIPAMessage.Performative.MATCH_ACCEPT and dialogue.dialogue_label in self.game_instance. transaction_manager.pending_initial_acceptances and match_accept.get("target") in self.game_instance.transaction_manager. pending_initial_acceptances[dialogue.dialogue_label]) logger.debug( "[{}]: on_match_accept: msg_id={}, dialogue_id={}, origin={}, target={}" .format( self.agent_name, match_accept.get("id"), match_accept.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, match_accept.get("target"), )) results = [] transaction = self.game_instance.transaction_manager.pop_pending_initial_acceptance( dialogue.dialogue_label, match_accept.get("target")) tac_msg = TACMessage( tac_type=TACMessage.Type.TRANSACTION, transaction_id=transaction.transaction_id, is_sender_buyer=transaction.is_sender_buyer, counterparty=transaction.counterparty, amount=transaction.amount, quantities_by_good_pbk=transaction.quantities_by_good_pbk, ) dialogue.outgoing_extend([tac_msg]) tac_bytes = TACSerializer().encode(tac_msg) results.append( Envelope( to=self.game_instance.controller_pbk, sender=self.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes, )) return results
def handle_controller_message(self, envelope: Envelope) -> None: """ Handle messages from the controller. The controller does not expect a response for any of these messages. :param envelope: the controller message :return: None """ assert envelope.protocol_id == "tac" tac_msg = TACSerializer().decode(envelope.message) tac_msg_type = TACMessage.Type(tac_msg.get("type")) logger.debug("[{}]: Handling controller response. type={}".format( self.agent_name, tac_msg_type)) try: if envelope.sender != self.game_instance.controller_pbk: raise ValueError( "The sender of the message is not the controller agent we registered with." ) if tac_msg_type == TACMessage.Type.TAC_ERROR: self.on_tac_error(tac_msg, envelope.sender) elif self.game_instance.game_phase == GamePhase.PRE_GAME: raise ValueError( "We do not expect a controller agent message in the pre game phase." ) elif self.game_instance.game_phase == GamePhase.GAME_SETUP: if tac_msg_type == TACMessage.Type.GAME_DATA: self.on_start(tac_msg, envelope.sender) elif tac_msg_type == TACMessage.Type.CANCELLED: self.on_cancelled() elif self.game_instance.game_phase == GamePhase.GAME: if tac_msg_type == TACMessage.Type.TRANSACTION_CONFIRMATION: self.on_transaction_confirmed(tac_msg, envelope.sender) elif tac_msg_type == TACMessage.Type.CANCELLED: self.on_cancelled() elif tac_msg_type == TACMessage.Type.STATE_UPDATE: self.on_state_update(tac_msg, envelope.sender) elif self.game_instance.game_phase == GamePhase.POST_GAME: raise ValueError( "We do not expect a controller agent message in the post game phase." ) except ValueError as e: logger.warning(str(e))
def on_accept(self, accept: Message, dialogue: Dialogue) -> List[Envelope]: """ Handle an Accept. :param accept: the message containing the Accept :param dialogue: the dialogue :return: a Decline, or an Accept and a Transaction, or a Transaction (in a Message object) """ assert accept.get("performative") == FIPAMessage.Performative.ACCEPT \ and dialogue.dialogue_label in self.game_instance.transaction_manager.pending_proposals \ and accept.get("target") in self.game_instance.transaction_manager.pending_proposals[dialogue.dialogue_label] logger.debug( "[{}]: on_accept: msg_id={}, dialogue_id={}, origin={}, target={}". format(self.agent_name, accept.get("id"), accept.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, accept.get("target"))) new_msg_id = accept.get("id") + 1 results = [] transaction = self.game_instance.transaction_manager.pop_pending_proposal( dialogue.dialogue_label, accept.get("target")) is_profitable_transaction, accept_log_msg = self.game_instance.is_profitable_transaction( transaction, dialogue) logger.debug(accept_log_msg) if is_profitable_transaction: if self.game_instance.strategy.is_world_modeling: self.game_instance.world_state.update_on_initial_accept( transaction) logger.debug("[{}]: Locking the current state (as {}).".format( self.agent_name, dialogue.role)) self.game_instance.transaction_manager.add_locked_tx( transaction, as_seller=dialogue.is_seller) tac_msg = TACMessage( tac_type=TACMessage.Type.TRANSACTION, transaction_id=transaction.transaction_id, is_sender_buyer=transaction.is_sender_buyer, counterparty=transaction.counterparty, amount=transaction.amount, quantities_by_good_pbk=transaction.quantities_by_good_pbk) dialogue.outgoing_extend([tac_msg]) tac_bytes = TACSerializer().encode(tac_msg) results.append( Envelope(to=self.game_instance.controller_pbk, sender=self.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes)) msg = FIPAMessage( message_id=new_msg_id, dialogue_id=accept.get("dialogue_id"), target=accept.get("id"), performative=FIPAMessage.Performative.MATCH_ACCEPT) dialogue.outgoing_extend([msg]) msg_bytes = FIPASerializer().encode(msg) results.append( Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)) else: logger.debug("[{}]: Decline the accept (as {}).".format( self.agent_name, dialogue.role)) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=accept.get("dialogue_id"), target=accept.get("id"), performative=FIPAMessage.Performative.DECLINE) dialogue.outgoing_extend([msg]) msg_bytes = FIPASerializer().encode(msg) results.append( Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)) self.game_instance.stats_manager.add_dialogue_endstate( EndState.DECLINED_ACCEPT, dialogue.is_self_initiated) return results
def handle(self, message: TACMessage, sender: Address) -> None: """ Handle a register message. If the public key is already registered, answer with an error message. :param message: the 'get agent state' TACMessage. :param sender: the public key of the sender :return: None """ whitelist = self.controller_agent.game_handler.tac_parameters.whitelist agent_name = message.get("agent_name") if whitelist is not None and agent_name not in whitelist: logger.error("[{}]: Agent name not in whitelist: '{}'".format( self.controller_agent.name, agent_name)) tac_msg = TACMessage( tac_type=TACMessage.Type.TAC_ERROR, error_code=TACMessage.ErrorCode.AGENT_NAME_NOT_IN_WHITELIST) tac_bytes = TACSerializer().encode(tac_msg) self.controller_agent.mailbox.outbox.put_message( to=sender, sender=self.controller_agent.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes) if sender in self.controller_agent.game_handler.registered_agents: logger.error("[{}]: Agent already registered: '{}'".format( self.controller_agent.name, self.controller_agent.game_handler.agent_pbk_to_name[sender])) tac_msg = TACMessage( tac_type=TACMessage.Type.TAC_ERROR, error_code=TACMessage.ErrorCode.AGENT_PBK_ALREADY_REGISTERED) tac_bytes = TACSerializer().encode(tac_msg) self.controller_agent.mailbox.outbox.put_message( to=sender, sender=self.controller_agent.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes) if agent_name in self.controller_agent.game_handler.agent_pbk_to_name.values( ): logger.error( "[{}]: Agent with this name already registered: '{}'".format( self.controller_agent.name, agent_name)) tac_msg = TACMessage( tac_type=TACMessage.Type.TAC_ERROR, error_code=TACMessage.ErrorCode.AGENT_NAME_ALREADY_REGISTERED) tac_bytes = TACSerializer().encode(tac_msg) self.controller_agent.mailbox.outbox.put_message( to=sender, sender=self.controller_agent.crypto.public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes) try: self.controller_agent.game_handler.monitor.dashboard.agent_pbk_to_name.update( {sender: agent_name}) # type: ignore self.controller_agent.game_handler.monitor.update() except Exception as e: logger.error(str(e)) self.controller_agent.game_handler.agent_pbk_to_name[ sender] = agent_name logger.debug("[{}]: Agent registered: '{}'".format( self.controller_agent.name, self.controller_agent.game_handler.agent_pbk_to_name[sender])) self.controller_agent.game_handler.registered_agents.add(sender)