示例#1
0
    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))
示例#2
0
    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
            )
        )
示例#3
0
    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)
示例#4
0
    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)
示例#5
0
    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"))
示例#6
0
    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,
        )
示例#7
0
    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))
示例#8
0
    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)
示例#9
0
 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)
示例#10
0
    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)
示例#11
0
    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)