예제 #1
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
        """
        game = cast(Game, self.context.game)
        logger.debug("[{}]: Handling valid transaction: {}".format(self.context.agent_name, transaction.transaction_id))
        game.transactions.add_confirmed(transaction)
        game.settle_transaction(transaction)

        # send the transaction confirmation.
        sender_tac_msg = TACMessage(tac_type=TACMessage.Type.TRANSACTION_CONFIRMATION,
                                    transaction_id=transaction.transaction_id)
        counterparty_tac_msg = TACMessage(tac_type=TACMessage.Type.TRANSACTION_CONFIRMATION,
                                          transaction_id=transaction.transaction_id)
        self.context.outbox.put_message(to=sender,
                                        sender=self.context.public_key,
                                        protocol_id=TACMessage.protocol_id,
                                        message=TACSerializer().encode(sender_tac_msg))
        self.context.outbox.put_message(to=cast(str, message.get("counterparty")),
                                        sender=self.context.agent_public_key,
                                        protocol_id=TACMessage.protocol_id,
                                        message=TACSerializer().encode(counterparty_tac_msg))

        # log messages
        logger.debug("[{}]: Transaction '{}' settled successfully.".format(self.context.agent_name, transaction.transaction_id))
        logger.debug("[{}]: Current state:\n{}".format(self.context.agent_name, game.holdings_summary))
예제 #2
0
    def _on_start(self, tac_message: TACMessage,
                  controller_pbk: Address) -> None:
        """
        Handle the 'start' event emitted by the controller.

        :param tac_message: the game data

        :return: None
        """
        logger.info(
            "[{}]: Received start event from the controller. Starting to compete..."
            .format(self.context.agent_name))
        game = cast(Game, self.context.game)
        game.init(tac_message, controller_pbk)
        game.update_game_phase(Phase.GAME)
        state_update_msg = StateUpdateMessage(
            performative=StateUpdateMessage.Performative.INITIALIZE,
            amount_by_currency=cast(Dict[str, int],
                                    tac_message.get("amount_by_currency")),
            quantities_by_good_pbk=cast(
                Dict[str, int], tac_message.get("quantities_by_good_pbk")),
            exchange_params_by_currency=cast(
                Dict[str, float],
                tac_message.get("exchange_params_by_currency")),
            utility_params_by_good_pbk=cast(
                Dict[str, float],
                tac_message.get("utility_params_by_good_pbk")),
            tx_fee=cast(int, tac_message.get("tx_fee")))
        self.context.decision_maker_message_queue.put_nowait(state_update_msg)
예제 #3
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")})
     self.context.outbox.put_message(to=sender,
                                     sender=self.context.agent_public_key,
                                     protocol_id=TACMessage.protocol_id,
                                     message=TACSerializer().encode(tac_msg))
예제 #4
0
    def _on_tac_error(self, tac_message: TACMessage, controller_pbk: Address) -> None:
        """
        Handle 'on tac error' event emitted by the controller.

        :param error: the error object

        :return: None
        """
        error_code = TACMessage.ErrorCode(tac_message.get("error_code"))
        logger.error("[{}]: Received error from the controller. error_msg={}".format(self.context.agent_name, TACMessage._from_ec_to_msg.get(error_code)))
        if error_code == TACMessage.ErrorCode.TRANSACTION_NOT_VALID:
            start_idx_of_tx_id = len("Error in checking transaction: ")
            transaction_id = cast(str, tac_message.get("error_msg"))[start_idx_of_tx_id:]
            logger.warning("[{}]: Received error on transaction id: {}".format(self.context.agent_name, transaction_id))
예제 #5
0
    def handle(self, message: Message, sender: str) -> None:
        """
        Dispatch message to relevant handler and respond.

        :param message: the message
        :param sender: the sender
        :return: None
        """
        tx_message = cast(TransactionMessage, message)
        if TransactionMessage.Performative(tx_message.get(
                "performative")) == TransactionMessage.Performative.ACCEPT:
            logger.info(
                "[{}]: transaction confirmed by decision maker, sending to controller."
                .format(self.context.agent_name))
            game = cast(Game, self.context.game)
            msg = TACMessage(
                type=TACMessage.Type.TRANSACTION,
                transaction_id=tx_message.get("transaction_digest"),
                counterparty=tx_message.get("counterparty"),
                amount_by_currency={
                    tx_message.get("currency"): tx_message.get("amount")
                },
                sender_tx_fee=tx_message.get("sender_tx_fee"),
                counterparty_tx_fee=tx_message.get("counterparty_tx_fee"),
                quantities_by_good_pbk=tx_message.get(
                    "quantities_by_good_pbk"))
            self.context.outbox.put_message(
                to=game.configuration.controller_pbk,
                sender=self.context.agent_public_key,
                protocol_id=TACMessage.protocol_id,
                message=TACSerializer().encode(msg))
        else:
            logger.info("[{}]: transaction was not successful.".format(
                self.context.agent_name))
예제 #6
0
 def _cancel_tac(self):
     """Notify agents that the TAC is cancelled."""
     game = cast(Game, self.context.game)
     logger.info("[{}]: Notifying agents that TAC is cancelled.".format(self.context.agent_name))
     for agent_pbk in game.registration.agent_pbk_to_name.keys():
         tac_msg = TACMessage(tac_type=TACMessage.Type.CANCELLED)
         self.context.outbox.put_message(to=agent_pbk,
                                         sender=self.context.agent_public_key,
                                         protocol_id=TACMessage.protocol_id,
                                         message=TACSerializer().encode(tac_msg))
예제 #7
0
    def _on_register(self, message: TACMessage, sender: Address) -> None:
        """
        Handle a register 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
        """
        parameters = cast(Parameters, self.context.parameters)
        agent_name = cast(str, message.get("agent_name"))
        if len(parameters.whitelist) != 0 and agent_name not in parameters.whitelist:
            logger.error("[{}]: Agent name not in whitelist: '{}'".format(self.context.agent_name, agent_name))
            tac_msg = TACMessage(tac_type=TACMessage.Type.TAC_ERROR,
                                 error_code=TACMessage.ErrorCode.AGENT_NAME_NOT_IN_WHITELIST)
            self.context.outbox.put_message(to=sender,
                                            sender=self.context.agent_public_key,
                                            protocol_id=TACMessage.protocol_id,
                                            message=TACSerializer().encode(tac_msg))
            return

        game = cast(Game, self.context.game)
        if sender in game.registration.agent_pbk_to_name:
            logger.error("[{}]: Agent already registered: '{}'".format(self.context.agent_name, game.registration.agent_pbk_to_name[sender]))
            tac_msg = TACMessage(tac_type=TACMessage.Type.TAC_ERROR,
                                 error_code=TACMessage.ErrorCode.AGENT_PBK_ALREADY_REGISTERED)
            self.context.outbox.put_message(to=sender,
                                            sender=self.context.agent_public_key,
                                            protocol_id=TACMessage.protocol_id,
                                            message=TACSerializer().encode(tac_msg))

        if agent_name in game.registration.agent_pbk_to_name.values():
            logger.error("[{}]: Agent with this name already registered: '{}'".format(self.context.agent_name, agent_name))
            tac_msg = TACMessage(tac_type=TACMessage.Type.TAC_ERROR,
                                 error_code=TACMessage.ErrorCode.AGENT_NAME_ALREADY_REGISTERED)
            self.context.outbox.put_message(to=sender,
                                            sender=self.context.agent_public_key,
                                            protocol_id=TACMessage.protocol_id,
                                            message=TACSerializer().encode(tac_msg))

        game.registration.register_agent(sender, agent_name)
        logger.info("[{}]: Agent registered: '{}'".format(self.context.agent_name, agent_name))
예제 #8
0
    def _on_transaction_confirmed(self, message: TACMessage,
                                  controller_pbk: Address) -> None:
        """
        Handle 'on transaction confirmed' event emitted by the controller.

        :param tx_confirmation: the transaction confirmation

        :return: None
        """
        logger.info(
            "[{}]: Received transaction confirmation from the controller: transaction_id={}"
            .format(self.context.agent_name, message.get("transaction_id")))
        state_update_msg = StateUpdateMessage(
            performative=StateUpdateMessage.Performative.APPLY,
            amount_by_currency=cast(Dict[str, int],
                                    message.get("amount_by_currency")),
            quantities_by_good_pbk=cast(Dict[str, int],
                                        message.get("quantities_by_good_pbk")))
        self.context.decision_maker_message_queue.put_nowait(state_update_msg)
예제 #9
0
    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)
        game = cast(Game, self.context.game)
        self.context.outbox.put_message(to=game.expected_controller_pbk, sender=self.context.agent_public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes)
예제 #10
0
    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
        """
        game = cast(Game, self.context.game)
        game.update_expected_controller_pbk(controller_pbk)
        game.update_game_phase(GamePhase.GAME_SETUP)
        tac_msg = TACMessage(tac_type=TACMessage.Type.GET_STATE_UPDATE)
        tac_bytes = TACSerializer().encode(tac_msg)
        self.context.outbox.put_message(to=controller_pbk, sender=self.context.agent_public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes)
예제 #11
0
    def _on_dialogue_error(self, tac_message: TACMessage,
                           controller_pbk: Address) -> None:
        """
        Handle dialogue error event emitted by the controller.

        :param message: the dialogue error message
        :param controller_pbk: the address of the controller

        :return: None
        """
        logger.warning(
            "[{}]: Received Dialogue error from: details={}, sender={}".format(
                self.context.agent_name, tac_message.get("details"),
                controller_pbk))
예제 #12
0
    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
        """
        game = cast(Game, self.context.game)
        game.update_expected_controller_pbk(controller_pbk)
        game.update_game_phase(GamePhase.GAME_SETUP)
        tac_msg = TACMessage(tac_type=TACMessage.Type.REGISTER, agent_name=self.context.agent_name)
        tac_bytes = TACSerializer().encode(tac_msg)
        self.context.outbox.put_message(to=controller_pbk, sender=self.context.agent_public_key, protocol_id=TACMessage.protocol_id, message=tac_bytes)
예제 #13
0
    def from_message(cls, message: TACMessage,
                     sender: Address) -> 'Transaction':
        """
        Create a transaction from a proposal.

        :param message: the message
        :return: Transaction
        """
        assert message.get('type') == TACMessage.Type.TRANSACTION
        return Transaction(
            cast(str, message.get("transaction_id")), sender,
            cast(str, message.get("counterparty")),
            cast(Dict[str, int], message.get("amount_by_currency")),
            cast(int, message.get("sender_tx_fee")),
            cast(int, message.get("counterparty_tx_fee")),
            cast(Dict[str, int], message.get("quantities_by_good_pbk")))
예제 #14
0
    def handle(self, message: Message, sender: str) -> None:
        """
        Implement the reaction to a message.

        :param message: the message
        :param sender: the sender
        :return: None
        """
        tac_msg = cast(TACMessage, message)
        tac_msg_type = TACMessage.Type(tac_msg.get("type"))
        game = cast(Game, self.context.game)
        logger.debug("[{}]: Handling controller response. type={}".format(
            self.context.agent_name, tac_msg_type))
        try:
            if sender != game.expected_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, sender)
            elif game.phase.value == Phase.PRE_GAME.value:
                raise ValueError(
                    "We do not expect a controller agent message in the pre game phase."
                )
            elif game.phase.value == Phase.GAME_REGISTRATION.value:
                if tac_msg_type == TACMessage.Type.GAME_DATA:
                    self._on_start(tac_msg, sender)
                elif tac_msg_type == TACMessage.Type.CANCELLED:
                    self._on_cancelled()
            elif game.phase.value == Phase.GAME.value:
                if tac_msg_type == TACMessage.Type.TRANSACTION_CONFIRMATION:
                    self._on_transaction_confirmed(tac_msg, 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, sender)
            elif game.phase.value == Phase.POST_GAME.value:
                raise ValueError(
                    "We do not expect a controller agent message in the post game phase."
                )
        except ValueError as e:
            logger.warning(str(e))
예제 #15
0
    def _on_unregister(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
        """
        game = cast(Game, self.context.game)
        if sender not in game.registration.agent_pbk_to_name:
            logger.error("[{}]: Agent not registered: '{}'".format(self.context.agent_name, sender))
            tac_msg = TACMessage(tac_type=TACMessage.Type.TAC_ERROR,
                                 error_code=TACMessage.ErrorCode.AGENT_NOT_REGISTERED)
            self.context.outbox.put_message(to=sender,
                                            sender=self.context.agent_public_key,
                                            protocol_id=TACMessage.protocol_id,
                                            message=TACSerializer().encode(tac_msg))
        else:
            logger.debug("[{}]: Agent unregistered: '{}'".format(self.context.agent_name, game.configuration.agent_pbk_to_name[sender]))
            game.registration.unregister_agent(sender)
예제 #16
0
    def init(self, tac_message: TACMessage, controller_pbk: Address) -> None:
        """
        Populate data structures with the game data.

        :param tac_message: the tac message with the game instance data
        :param controller_pbk: the public key of the controller

        :return: None
        """
        assert tac_message.get(
            "type"
        ) == TACMessage.Type.GAME_DATA, "Wrong TACMessage for initialization of TAC game."
        assert controller_pbk == self.expected_controller_pbk, "TACMessage from unexpected controller."
        assert tac_message.get(
            "version_id"
        ) == self.expected_version_id, "TACMessage for unexpected game."
        self._game_configuration = GameConfiguration(
            cast(str, tac_message.get("version_id")),
            cast(int, tac_message.get("nb_agents")),
            cast(int, tac_message.get("nb_goods")),
            cast(float, tac_message.get("tx_fee")),
            cast(Dict[str, str], tac_message.get("agent_pbk_to_name")),
            cast(Dict[str, str], tac_message.get("good_pbk_to_name")),
            controller_pbk)
예제 #17
0
 def _start_tac(self):
     """Create a game and send the game configuration to every registered agent."""
     game = cast(Game, self.context.game)
     game.create()
     logger.info("[{}]: Started competition:\n{}".format(self.context.agent_name, game.holdings_summary))
     logger.info("[{}]: Computed equilibrium:\n{}".format(self.context.agent_name, game.equilibrium_summary))
     for agent_public_key in game.configuration.agent_pbks:
         agent_state = game.current_agent_states[agent_public_key]
         tac_msg = TACMessage(tac_type=TACMessage.Type.GAME_DATA,
                              amount_by_currency=agent_state.balance_by_currency,
                              exchange_params_by_currency=agent_state.exchange_params_by_currency,
                              quantities_by_good_pbk=agent_state.quantities_by_good_pbk,
                              utility_params_by_good_pbk=agent_state.utility_params_by_good_pbk,
                              tx_fee=game.configuration.tx_fee,
                              agent_pbk_to_name=game.configuration.agent_pbk_to_name,
                              good_pbk_to_name=game.configuration.good_pbk_to_name,
                              version_id=game.configuration.version_id)
         logger.debug("[{}]: sending game data to '{}': {}"
                      .format(self.context.agent_name, agent_public_key, str(tac_msg)))
         self.context.outbox.put_message(to=agent_public_key,
                                         sender=self.context.agent_public_key,
                                         protocol_id=TACMessage.protocol_id,
                                         message=TACSerializer().encode(tac_msg))
예제 #18
0
    def handle_envelope(self, envelope: Envelope) -> None:
        """
        Implement the reaction to an envelope.

        :param envelope: the envelope
        :return: None
        """
        tac_msg = TACSerializer().decode(envelope.message)
        tac_msg_type = TACMessage.Type(tac_msg.get("type"))
        tac_msg = cast(TACMessage, tac_msg)
        game = cast(Game, self.context.game)
        logger.debug("[{}]: Handling controller response. type={}".format(self.context.agent_name, tac_msg_type))
        try:
            if envelope.sender != game.expected_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 game.game_phase == GamePhase.PRE_GAME:
                raise ValueError("We do not expect a controller agent message in the pre game phase.")
            elif game.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 game.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 game.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))
예제 #19
0
    def _on_transaction_confirmed(self, message: TACMessage, controller_pbk: 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.context.agent_name, message.get("transaction_id")))
예제 #20
0
    def decode(self, obj: bytes) -> Message:
        """
        Decode the message.

        :param obj: the bytes object
        :return: the message
        """
        tac_container = tac_pb2.TACMessage()
        tac_container.ParseFromString(obj)

        new_body = {}  # type: Dict[str, Any]
        tac_type = tac_container.WhichOneof("content")

        if tac_type == "register":
            new_body["type"] = TACMessage.Type.REGISTER
            new_body["agent_name"] = tac_container.register.agent_name
        elif tac_type == "unregister":
            new_body["type"] = TACMessage.Type.UNREGISTER
        elif tac_type == "transaction":
            new_body["type"] = TACMessage.Type.TRANSACTION
            new_body[
                "transaction_id"] = tac_container.transaction.transaction_id
            new_body[
                "is_sender_buyer"] = tac_container.transaction.is_sender_buyer
            new_body["counterparty"] = tac_container.transaction.counterparty
            new_body["amount"] = tac_container.transaction.amount
            new_body["quantities_by_good_pbk"] = _from_pairs_to_dict(
                tac_container.transaction.quantities)
        elif tac_type == "get_state_update":
            new_body["type"] = TACMessage.Type.GET_STATE_UPDATE
        elif tac_type == "cancelled":
            new_body["type"] = TACMessage.Type.CANCELLED
        elif tac_type == "game_data":
            new_body["type"] = TACMessage.Type.GAME_DATA
            new_body["money"] = tac_container.game_data.money
            new_body["endowment"] = list(tac_container.game_data.endowment)
            new_body["utility_params"] = list(
                tac_container.game_data.utility_params)
            new_body["nb_agents"] = tac_container.game_data.nb_agents
            new_body["nb_goods"] = tac_container.game_data.nb_goods
            new_body["tx_fee"] = tac_container.game_data.tx_fee
            new_body["agent_pbk_to_name"] = _from_pairs_to_dict(
                tac_container.game_data.agent_pbk_to_name)
            new_body["good_pbk_to_name"] = _from_pairs_to_dict(
                tac_container.game_data.good_pbk_to_name)
        elif tac_type == "transaction_confirmation":
            new_body["type"] = TACMessage.Type.TRANSACTION_CONFIRMATION
            new_body[
                "transaction_id"] = tac_container.transaction_confirmation.transaction_id
        elif tac_type == "state_update":
            new_body["type"] = TACMessage.Type.STATE_UPDATE
            game_data = dict(
                money=tac_container.state_update.initial_state.money,
                endowment=tac_container.state_update.initial_state.endowment,
                utility_params=tac_container.state_update.initial_state.
                utility_params,
                nb_agents=tac_container.state_update.initial_state.nb_agents,
                nb_goods=tac_container.state_update.initial_state.nb_goods,
                tx_fee=tac_container.state_update.initial_state.tx_fee,
                agent_pbk_to_name=_from_pairs_to_dict(
                    tac_container.state_update.initial_state.agent_pbk_to_name
                ),
                good_pbk_to_name=_from_pairs_to_dict(
                    tac_container.state_update.initial_state.good_pbk_to_name),
            )
            new_body["initial_state"] = game_data
            transactions = []
            for t in tac_container.state_update.txs:
                tx_json = dict(
                    transaction_id=t.transaction_id,
                    is_sender_buyer=t.is_sender_buyer,
                    counterparty=t.counterparty,
                    amount=t.amount,
                    quantities_by_good_pbk=_from_pairs_to_dict(t.quantities),
                )
                transactions.append(tx_json)
            new_body["transactions"] = transactions
        elif tac_type == "error":
            new_body["type"] = TACMessage.Type.TAC_ERROR
            new_body["error_code"] = TACMessage.ErrorCode(
                tac_container.error.error_code)
            if tac_container.error.error_msg:
                new_body["error_msg"] = tac_container.error.error_msg
            if tac_container.error.details:
                new_body["details"] = dict(tac_container.error.details)
        else:
            raise ValueError("Type not recognized.")

        tac_type = TACMessage.Type(new_body["type"])
        new_body["type"] = tac_type
        tac_message = TACMessage(tac_type=tac_type, body=new_body)
        return tac_message
예제 #21
0
    def decode(self, obj: bytes) -> Message:
        """
        Decode the message.

        :param obj: the bytes object
        :return: the message
        """
        tac_container = tac_pb2.TACMessage()
        tac_container.ParseFromString(obj)

        new_body = {}  # type: Dict[str, Any]
        tac_type = tac_container.WhichOneof("content")

        if tac_type == "register":
            new_body["type"] = TACMessage.Type.REGISTER
            new_body["agent_name"] = tac_container.register.agent_name
        elif tac_type == "unregister":
            new_body["type"] = TACMessage.Type.UNREGISTER
        elif tac_type == "transaction":
            new_body["type"] = TACMessage.Type.TRANSACTION
            new_body[
                "transaction_id"] = tac_container.transaction.transaction_id
            new_body["counterparty"] = tac_container.transaction.counterparty
            new_body["amount_by_currency"] = _from_pairs_to_dict(
                tac_container.transaction.amount_by_currency)
            new_body["sender_tx_fee"] = tac_container.transaction.sender_tx_fee
            new_body[
                "counterparty_tx_fee"] = tac_container.transaction.counterparty_tx_fee
            new_body["quantities_by_good_pbk"] = _from_pairs_to_dict(
                tac_container.transaction.quantities_by_good_pbk)
        elif tac_type == "get_state_update":
            new_body["type"] = TACMessage.Type.GET_STATE_UPDATE
        elif tac_type == "cancelled":
            new_body["type"] = TACMessage.Type.CANCELLED
        elif tac_type == "game_data":
            new_body["type"] = TACMessage.Type.GAME_DATA
            new_body["amount_by_currency"] = _from_pairs_to_dict(
                tac_container.game_data.amount_by_currency)
            new_body["exchange_params_by_currency"] = _from_pairs_to_dict(
                tac_container.game_data.exchange_params_by_currency)
            new_body["quantities_by_good_pbk"] = _from_pairs_to_dict(
                tac_container.game_data.quantities_by_good_pbk)
            new_body["utility_params_by_good_pbk"] = _from_pairs_to_dict(
                tac_container.game_data.utility_params_by_good_pbk)
            new_body["tx_fee"] = tac_container.game_data.tx_fee
            new_body["agent_pbk_to_name"] = _from_pairs_to_dict(
                tac_container.game_data.agent_pbk_to_name)
            new_body["good_pbk_to_name"] = _from_pairs_to_dict(
                tac_container.game_data.good_pbk_to_name)
            new_body["version_id"] = tac_container.game_data.version_id
        elif tac_type == "transaction_confirmation":
            new_body["type"] = TACMessage.Type.TRANSACTION_CONFIRMATION
            new_body[
                "transaction_id"] = tac_container.transaction_confirmation.transaction_id
            new_body["amount_by_currency"] = _from_pairs_to_dict(
                tac_container.transaction_confirmation.amount_by_currency)
            new_body["quantities_by_good_pbk"] = _from_pairs_to_dict(
                tac_container.transaction_confirmation.quantities_by_good_pbk)
        # elif tac_type == "state_update":
        #     new_body["type"] = TACMessage.Type.STATE_UPDATE
        #     game_data = dict(
        #         amount_by_currency=_from_pairs_to_dict(tac_container.state_update.game_data.amount_by_currency),
        #         exchange_params_by_currency=_from_pairs_to_dict(tac_container.state_update.game_data.exchange_params_by_currency),
        #         quantities_by_good_pbk=_from_pairs_to_dict(tac_container.state_update.game_data.quantities_by_good_pbk),
        #         utility_params_by_good_pbk=_from_pairs_to_dict(tac_container.state_update.game_data.utility_params_by_good_pbk),
        #         tx_fee=tac_container.state_update.game_data.tx_fee,
        #         agent_pbk_to_name=_from_pairs_to_dict(tac_container.state_update.game_data.agent_pbk_to_name),
        #         good_pbk_to_name=_from_pairs_to_dict(tac_container.state_update.game_data.good_pbk_to_name),
        #         version_id=tac_container.state_update.game_data.version_id
        #     )
        #     new_body["game_data"] = game_data
        #     transactions = []
        #     for transaction in tac_container.state_update.transactions:
        #         tx_json = dict(
        #             transaction_id=transaction.transaction_id,
        #             counterparty=transaction.counterparty,
        #             amount_by_currency=_from_pairs_to_dict(transaction.amount_by_currency),
        #             sender_tx_fee=transaction.sender_tx_fee,
        #             counterparty_tx_fee=transaction.counterparty_tx_fee,
        #             quantities_by_good_pbk=_from_pairs_to_dict(transaction.quantities_by_good_pbk),
        #         )
        #         transactions.append(tx_json)
        #     new_body["transactions"] = transactions
        elif tac_type == "error":
            new_body["type"] = TACMessage.Type.TAC_ERROR
            new_body["error_code"] = TACMessage.ErrorCode(
                tac_container.error.error_code)
            if tac_container.error.error_msg:
                new_body["error_msg"] = tac_container.error.error_msg
            if tac_container.error.details:
                new_body["details"] = dict(tac_container.error.details)
        else:
            raise ValueError("Type not recognized.")

        tac_type = TACMessage.Type(new_body["type"])
        new_body["type"] = tac_type
        tac_message = TACMessage(tac_type=tac_type, body=new_body)
        return tac_message
예제 #22
0
    def encode(self, msg: Message) -> bytes:
        """
        Decode the message.

        :param msg: the message object
        :return: the bytes
        """
        tac_type = TACMessage.Type(msg.get("type"))
        tac_container = tac_pb2.TACMessage()

        if tac_type == TACMessage.Type.REGISTER:
            agent_name = msg.get("agent_name")
            tac_msg = tac_pb2.TACAgent.Register()  # type: ignore
            tac_msg.agent_name = agent_name
            tac_container.register.CopyFrom(tac_msg)
        elif tac_type == TACMessage.Type.UNREGISTER:
            tac_msg = tac_pb2.TACAgent.Unregister()  # type: ignore
            tac_container.unregister.CopyFrom(tac_msg)
        elif tac_type == TACMessage.Type.TRANSACTION:
            tac_msg = tac_pb2.TACAgent.Transaction()  # type: ignore
            tac_msg.transaction_id = msg.get("transaction_id")
            tac_msg.counterparty = msg.get("counterparty")
            tac_msg.amount_by_currency.extend(
                _from_dict_to_pairs(msg.get("amount_by_currency")))
            tac_msg.sender_tx_fee = msg.get("sender_tx_fee")
            tac_msg.counterparty_tx_fee = msg.get("counterparty_tx_fee")
            tac_msg.quantities_by_good_pbk.extend(
                _from_dict_to_pairs(msg.get("quantities_by_good_pbk")))
            tac_container.transaction.CopyFrom(tac_msg)
        elif tac_type == TACMessage.Type.GET_STATE_UPDATE:
            tac_msg = tac_pb2.TACAgent.GetStateUpdate()  # type: ignore
            tac_container.get_state_update.CopyFrom(tac_msg)
        elif tac_type == TACMessage.Type.CANCELLED:
            tac_msg = tac_pb2.TACController.Cancelled()  # type: ignore
            tac_container.cancelled.CopyFrom(tac_msg)
        elif tac_type == TACMessage.Type.GAME_DATA:
            tac_msg = tac_pb2.TACController.GameData()  # type: ignore
            tac_msg.amount_by_currency.extend(
                _from_dict_to_pairs(msg.get("amount_by_currency")))
            tac_msg.exchange_params_by_currency.extend(
                _from_dict_to_pairs(msg.get("exchange_params_by_currency")))
            tac_msg.quantities_by_good_pbk.extend(
                _from_dict_to_pairs(msg.get("quantities_by_good_pbk")))
            tac_msg.utility_params_by_good_pbk.extend(
                _from_dict_to_pairs(msg.get("utility_params_by_good_pbk")))
            tac_msg.tx_fee = msg.get("tx_fee")
            tac_msg.agent_pbk_to_name.extend(
                _from_dict_to_pairs(msg.get("agent_pbk_to_name")))
            tac_msg.good_pbk_to_name.extend(
                _from_dict_to_pairs(msg.get("good_pbk_to_name")))
            tac_msg.version_id = msg.get("version_id")
            tac_container.game_data.CopyFrom(tac_msg)
        elif tac_type == TACMessage.Type.TRANSACTION_CONFIRMATION:
            tac_msg = tac_pb2.TACController.TransactionConfirmation(
            )  # type: ignore
            tac_msg.transaction_id = msg.get("transaction_id")
            tac_msg.amount_by_currency.extend(
                _from_dict_to_pairs(msg.get("amount_by_currency")))
            tac_msg.quantities_by_good_pbk.extend(
                _from_dict_to_pairs(msg.get("quantities_by_good_pbk")))
            tac_container.transaction_confirmation.CopyFrom(tac_msg)
        # elif tac_type == TACMessage.Type.STATE_UPDATE:
        #     tac_msg = tac_pb2.TACController.StateUpdate()  # type: ignore
        #     game_data_json = msg.get("game_data")
        #     game_data = tac_pb2.TACController.GameData()  # type: ignore
        #     game_data.amount_by_currency.extend(_from_dict_to_pairs(cast(Dict[str, str], game_data_json["amount_by_currency"])))  # type: ignore
        #     game_data.exchange_params_by_currency.extend(_from_dict_to_pairs(cast(Dict[str, str], game_data_json["exchange_params_by_currency"])))  # type: ignore
        #     game_data.quantities_by_good_pbk.extend(_from_dict_to_pairs(cast(Dict[str, str], game_data_json["quantities_by_good_pbk"])))  # type: ignore
        #     game_data.utility_params_by_good_pbk.extend(_from_dict_to_pairs(cast(Dict[str, str], game_data_json["utility_params_by_good_pbk"])))  # type: ignore
        #     game_data.tx_fee = game_data_json["tx_fee"]  # type: ignore
        #     game_data.agent_pbk_to_name.extend(_from_dict_to_pairs(cast(Dict[str, str], game_data_json["agent_pbk_to_name"])))  # type: ignore
        #     game_data.good_pbk_to_name.extend(_from_dict_to_pairs(cast(Dict[str, str], game_data_json["good_pbk_to_name"])))  # type: ignore

        #     tac_msg.initial_state.CopyFrom(game_data)

        #     transactions = []
        #     msg_transactions = cast(List[Any], msg.get("transactions"))
        #     for t in msg_transactions:
        #         tx = tac_pb2.TACAgent.Transaction()  # type: ignore
        #         tx.transaction_id = t.get("transaction_id")
        #         tx.counterparty = t.get("counterparty")
        #         tx.amount_by_currency.extend(_from_dict_to_pairs(t.get("amount_by_currency")))
        #         tx.sender_tx_fee = t.get("sender_tx_fee")
        #         tx.counterparty_tx_fee = t.get("counterparty_tx_fee")
        #         tx.quantities_by_good_pbk.extend(_from_dict_to_pairs(t.get("quantities_by_good_pbk")))
        #         transactions.append(tx)
        #     tac_msg.txs.extend(transactions)
        #     tac_container.state_update.CopyFrom(tac_msg)
        elif tac_type == TACMessage.Type.TAC_ERROR:
            tac_msg = tac_pb2.TACController.Error()  # type: ignore
            tac_msg.error_code = TACMessage.ErrorCode(
                msg.get("error_code")).value
            if msg.is_set("error_msg"):
                tac_msg.error_msg = msg.get("error_msg")
            if msg.is_set("details"):
                tac_msg.details.update(msg.get("details"))

            tac_container.error.CopyFrom(tac_msg)
        else:
            raise ValueError("Type not recognized: {}.".format(tac_type))

        tac_message_bytes = tac_container.SerializeToString()
        return tac_message_bytes
예제 #23
0
def test_tac_message_instantiation():
    """Test instantiation of the tac message."""
    assert TACMessage(tac_type=TACMessage.Type.REGISTER,
                      agent_name='some_name')
    assert TACMessage(tac_type=TACMessage.Type.UNREGISTER)
    assert TACMessage(tac_type=TACMessage.Type.TRANSACTION,
                      transaction_id='some_id',
                      counterparty='some_address',
                      amount_by_currency={'FET': 10},
                      sender_tx_fee=10,
                      counterparty_tx_fee=10,
                      quantities_by_good_pbk={
                          'good_1': 0,
                          'good_2': 10
                      })
    assert TACMessage(tac_type=TACMessage.Type.GET_STATE_UPDATE)
    assert TACMessage(tac_type=TACMessage.Type.CANCELLED)
    assert TACMessage(tac_type=TACMessage.Type.GAME_DATA,
                      amount_by_currency={'FET': 10},
                      exchange_params_by_currency={'FET': 10.0},
                      quantities_by_good_pbk={
                          'good_1': 20,
                          'good_2': 15
                      },
                      utility_params_by_good_pbk={
                          'good_1': 30.0,
                          'good_2': 50.0
                      },
                      tx_fee=20,
                      agent_pbk_to_name={
                          'agent_1': 'Agent one',
                          'agent_2': 'Agent two'
                      },
                      good_pbk_to_name={
                          'good_1': 'First good',
                          'good_2': 'Second good'
                      },
                      version_id='game_version_1')
    assert TACMessage(tac_type=TACMessage.Type.TRANSACTION_CONFIRMATION,
                      transaction_id='some_id',
                      amount_by_currency={'FET': 10},
                      quantities_by_good_pbk={
                          'good_1': 20,
                          'good_2': 15
                      })
    assert TACMessage(tac_type=TACMessage.Type.TAC_ERROR,
                      error_code=TACMessage.ErrorCode.GENERIC_ERROR)
    assert str(TACMessage.Type.REGISTER) == 'register'

    msg = TACMessage(tac_type=TACMessage.Type.REGISTER, agent_name='some_name')
    with mock.patch(
            'packages.protocols.tac.message.TACMessage.Type') as mocked_type:
        mocked_type.REGISTER.value = "unknown"
        assert not msg.check_consistency(), \
            "Expect the consistency to return False"
예제 #24
0
def test_tac_serialization():
    """Test that the serialization for the tac message works."""
    msg = TACMessage(tac_type=TACMessage.Type.REGISTER, agent_name='some_name')
    msg_bytes = TACSerializer().encode(msg)
    actual_msg = TACSerializer().decode(msg_bytes)
    expected_msg = msg
    assert expected_msg == actual_msg

    msg = TACMessage(tac_type=TACMessage.Type.UNREGISTER)
    msg_bytes = TACSerializer().encode(msg)
    actual_msg = TACSerializer().decode(msg_bytes)
    expected_msg = msg
    assert expected_msg == actual_msg

    msg = TACMessage(tac_type=TACMessage.Type.TRANSACTION,
                     transaction_id='some_id',
                     counterparty='some_address',
                     amount_by_currency={'FET': 10},
                     sender_tx_fee=10,
                     counterparty_tx_fee=10,
                     quantities_by_good_pbk={
                         'good_1': 0,
                         'good_2': 10
                     })
    msg_bytes = TACSerializer().encode(msg)
    actual_msg = TACSerializer().decode(msg_bytes)
    expected_msg = msg
    assert expected_msg == actual_msg

    msg = TACMessage(tac_type=TACMessage.Type.GET_STATE_UPDATE)
    msg_bytes = TACSerializer().encode(msg)
    actual_msg = TACSerializer().decode(msg_bytes)
    expected_msg = msg
    assert expected_msg == actual_msg

    msg = TACMessage(tac_type=TACMessage.Type.CANCELLED)
    msg_bytes = TACSerializer().encode(msg)
    actual_msg = TACSerializer().decode(msg_bytes)
    expected_msg = msg
    assert expected_msg == actual_msg

    msg = TACMessage(tac_type=TACMessage.Type.GAME_DATA,
                     amount_by_currency={'FET': 10},
                     exchange_params_by_currency={'FET': 10.0},
                     quantities_by_good_pbk={
                         'good_1': 20,
                         'good_2': 15
                     },
                     utility_params_by_good_pbk={
                         'good_1': 30.0,
                         'good_2': 50.0
                     },
                     tx_fee=20,
                     agent_pbk_to_name={
                         'agent_1': 'Agent one',
                         'agent_2': 'Agent two'
                     },
                     good_pbk_to_name={
                         'good_1': 'First good',
                         'good_2': 'Second good'
                     },
                     version_id='game_version_1')
    msg_bytes = TACSerializer().encode(msg)
    actual_msg = TACSerializer().decode(msg_bytes)
    expected_msg = msg
    assert expected_msg == actual_msg

    msg = TACMessage(tac_type=TACMessage.Type.TRANSACTION_CONFIRMATION,
                     transaction_id='some_id',
                     amount_by_currency={'FET': 10},
                     quantities_by_good_pbk={
                         'good_1': 20,
                         'good_2': 15
                     })
    msg_bytes = TACSerializer().encode(msg)
    actual_msg = TACSerializer().decode(msg_bytes)
    expected_msg = msg
    assert expected_msg == actual_msg

    with pytest.raises(ValueError, match="Type not recognized."):
        with mock.patch('packages.protocols.tac.message.TACMessage.Type'
                        ) as mocked_type:
            mocked_type.TRANSACTION_CONFIRMATION.value = "unknown"
            TACSerializer().encode(msg)

    msg = TACMessage(tac_type=TACMessage.Type.TAC_ERROR,
                     error_code=TACMessage.ErrorCode.GENERIC_ERROR)
    msg_bytes = TACSerializer().encode(msg)
    actual_msg = TACSerializer().decode(msg_bytes)
    expected_msg = msg
    assert expected_msg == actual_msg