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(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 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 '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 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 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 _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, 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 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)