Exemple #1
0
    def _handle_valid_transaction(self, message: TacMessage,
                                  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 transaction: the transaction.
        :return: None
        """
        game = cast(Game, self.context.game)
        self.context.logger.info("[{}]: Handling valid transaction: {}".format(
            self.context.agent_name, transaction.id[-10:]))
        game.settle_transaction(transaction)

        tx_sender_id, tx_counterparty_id = transaction.id.split("_")
        # send the transaction confirmation.
        sender_tac_msg = TacMessage(
            performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,
            tx_id=tx_sender_id,
            amount_by_currency_id=transaction.amount_by_currency_id,
            quantities_by_good_id=transaction.quantities_by_good_id,
        )
        counterparty_tac_msg = TacMessage(
            performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,
            tx_id=tx_counterparty_id,
            amount_by_currency_id=transaction.amount_by_currency_id,
            quantities_by_good_id=transaction.quantities_by_good_id,
        )
        self.context.outbox.put_message(
            to=transaction.sender_addr,
            sender=self.context.agent_address,
            protocol_id=TacMessage.protocol_id,
            message=TacSerializer().encode(sender_tac_msg),
        )
        self.context.outbox.put_message(
            to=transaction.counterparty_addr,
            sender=self.context.agent_address,
            protocol_id=TacMessage.protocol_id,
            message=TacSerializer().encode(counterparty_tac_msg),
        )

        # log messages
        self.context.logger.info(
            "[{}]: Transaction '{}' settled successfully.".format(
                self.context.agent_name, transaction.id[-10:]))
        self.context.logger.info("[{}]: Current state:\n{}".format(
            self.context.agent_name, game.holdings_summary))
Exemple #2
0
    def _on_unregister(self, message: TacMessage) -> None:
        """
        Handle a unregister message.

        If the address is not registered, answer with an error message.

        :param message: the 'get agent state' TacMessage.
        :return: None
        """
        game = cast(Game, self.context.game)
        if message.counterparty not in game.registration.agent_addr_to_name:
            self.context.logger.error(
                "[{}]: Agent not registered: '{}'".format(
                    self.context.agent_name, message.counterparty))
            tac_msg = TacMessage(
                performative=TacMessage.Performative.TAC_ERROR,
                error_code=TacMessage.ErrorCode.AGENT_NOT_REGISTERED,
            )
            self.context.outbox.put_message(
                to=message.counterparty,
                sender=self.context.agent_address,
                protocol_id=TacMessage.protocol_id,
                message=TacSerializer().encode(tac_msg),
            )
        else:
            self.context.logger.debug("[{}]: Agent unregistered: '{}'".format(
                self.context.agent_name,
                game.configuration.agent_addr_to_name[message.counterparty],
            ))
            game.registration.unregister_agent(message.counterparty)
Exemple #3
0
    def _cancel_tac(self):
        """Notify agents that the TAC is cancelled."""
        game = cast(Game, self.context.game)
        self.context.logger.info(
            "[{}]: Notifying agents that TAC is cancelled.".format(
                self.context.agent_name
            )
        )
        for agent_addr in game.registration.agent_addr_to_name.keys():
            tac_msg = TacMessage(performative=TacMessage.Type.CANCELLED)
            self.context.outbox.put_message(
                to=agent_addr,
                sender=self.context.agent_address,
                protocol_id=TacMessage.protocol_id,
                message=TacSerializer().encode(tac_msg),
            )
        if game.phase == Phase.GAME:
            self.context.logger.info(
                "[{}]: Finished competition:\n{}".format(
                    self.context.agent_name, game.holdings_summary
                )
            )
            self.context.logger.info(
                "[{}]: Computed equilibrium:\n{}".format(
                    self.context.agent_name, game.equilibrium_summary
                )
            )

            self.context.is_active = False
Exemple #4
0
    def handle(self, message: Message) -> None:
        """
        Dispatch message to relevant handler and respond.

        :param message: the message
        :return: None
        """
        tx_message = cast(TransactionMessage, message)
        if (
            tx_message.performative
            == TransactionMessage.Performative.SUCCESSFUL_SIGNING
        ):

            # TODO: // Need to modify here and add the contract option in case we are using one.

            self.context.logger.info(
                "[{}]: transaction confirmed by decision maker, sending to controller.".format(
                    self.context.agent_name
                )
            )
            game = cast(Game, self.context.game)
            tx_counterparty_signature = cast(
                bytes, tx_message.info.get("tx_counterparty_signature")
            )
            tx_counterparty_id = cast(str, tx_message.info.get("tx_counterparty_id"))
            if (tx_counterparty_signature is not None) and (
                tx_counterparty_id is not None
            ):
                tx_id = tx_message.tx_id + "_" + tx_counterparty_id
                msg = TacMessage(
                    performative=TacMessage.Performative.TRANSACTION,
                    tx_id=tx_id,
                    tx_sender_addr=tx_message.tx_sender_addr,
                    tx_counterparty_addr=tx_message.tx_counterparty_addr,
                    amount_by_currency_id=tx_message.tx_amount_by_currency_id,
                    tx_sender_fee=tx_message.tx_sender_fee,
                    tx_counterparty_fee=tx_message.tx_counterparty_fee,
                    quantities_by_good_id=tx_message.tx_quantities_by_good_id,
                    tx_sender_signature=tx_message.signed_payload.get("tx_signature"),
                    tx_counterparty_signature=tx_message.info.get(
                        "tx_counterparty_signature"
                    ),
                    tx_nonce=tx_message.info.get("tx_nonce"),
                )
                self.context.outbox.put_message(
                    to=game.configuration.controller_addr,
                    sender=self.context.agent_address,
                    protocol_id=TacMessage.protocol_id,
                    message=TacSerializer().encode(msg),
                )
            else:
                self.context.logger.warning(
                    "[{}]: transaction has no counterparty id or signature!".format(
                        self.context.agent_name
                    )
                )
        else:
            self.context.logger.info(
                "[{}]: transaction was not successful.".format(self.context.agent_name)
            )
Exemple #5
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()

        self.context.logger.info("[{}]: Started competition:\n{}".format(
            self.context.agent_name, game.holdings_summary))
        self.context.logger.info("[{}]: Computed equilibrium:\n{}".format(
            self.context.agent_name, game.equilibrium_summary))
        for agent_address in game.configuration.agent_addr_to_name.keys():
            agent_state = game.current_agent_states[agent_address]
            tac_msg = TacMessage(
                type=TacMessage.Performative.GAME_DATA,
                amount_by_currency_id=agent_state.amount_by_currency_id,
                exchange_params_by_currency_id=agent_state.
                exchange_params_by_currency_id,
                quantities_by_good_id=agent_state.quantities_by_good_id,
                utility_params_by_good_id=agent_state.
                utility_params_by_good_id,
                tx_fee=game.configuration.tx_fee,
                agent_addr_to_name=game.configuration.agent_addr_to_name,
                good_id_to_name=game.configuration.good_id_to_name,
                version_id=game.configuration.version_id,
                contract_address=self.context.contracts.erc1155.instance.
                address,
            )
            self.context.logger.debug(
                "[{}]: sending game data to '{}': {}".format(
                    self.context.agent_name, agent_address, str(tac_msg)))
            self.context.outbox.put_message(
                to=agent_address,
                sender=self.context.agent_address,
                protocol_id=TacMessage.protocol_id,
                message=TacSerializer().encode(tac_msg),
            )
Exemple #6
0
 def _end_tac(self, game: Game, reason: str) -> None:
     """Notify agents that the TAC is cancelled."""
     self.context.logger.info(
         "[{}]: Notifying agents that TAC is {}.".format(
             self.context.agent_name, reason
         )
     )
     for agent_addr in game.registration.agent_addr_to_name.keys():
         tac_msg = TacMessage(performative=TacMessage.Performative.CANCELLED)
         self.context.outbox.put_message(
             to=agent_addr,
             sender=self.context.agent_address,
             protocol_id=TacMessage.protocol_id,
             message=TacSerializer().encode(tac_msg),
         )
Exemple #7
0
 def _handle_invalid_transaction(self, message: TacMessage) -> None:
     """Handle an invalid transaction."""
     tx_id = message.tx_id[-10:]
     self.context.logger.info(
         "[{}]: Handling invalid transaction: {}".format(
             self.context.agent_name, tx_id))
     tac_msg = TacMessage(
         performative=TacMessage.Performative.TAC_ERROR,
         error_code=TacMessage.ErrorCode.TRANSACTION_NOT_VALID,
         info={"transaction_id": message.tx_id},
     )
     self.context.outbox.put_message(
         to=message.counterparty,
         sender=self.context.agent_address,
         protocol_id=TacMessage.protocol_id,
         message=TacSerializer().encode(tac_msg),
     )
Exemple #8
0
 def _start_tac(self, game: Game) -> None:
     """Create a game and send the game configuration to every registered agent."""
     self.context.logger.info(
         "[{}]: Starting competition with configuration:\n{}".format(
             self.context.agent_name, game.holdings_summary
         )
     )
     self.context.logger.info(
         "[{}]: Computed theoretical equilibrium:\n{}".format(
             self.context.agent_name, game.equilibrium_summary
         )
     )
     for agent_address in game.conf.agent_addr_to_name.keys():
         agent_state = game.current_agent_states[agent_address]
         tac_msg = TacMessage(
             performative=TacMessage.Performative.GAME_DATA,
             amount_by_currency_id=agent_state.amount_by_currency_id,
             exchange_params_by_currency_id=agent_state.exchange_params_by_currency_id,
             quantities_by_good_id=agent_state.quantities_by_good_id,
             utility_params_by_good_id=agent_state.utility_params_by_good_id,
             tx_fee=game.conf.tx_fee,
             agent_addr_to_name=game.conf.agent_addr_to_name,
             good_id_to_name=game.conf.good_id_to_name,
             currency_id_to_name=game.conf.currency_id_to_name,
             version_id=game.conf.version_id,
             info={"contract_address": game.conf.contract_address},
         )
         self.context.logger.debug(
             "[{}]: sending game data to '{}'.".format(
                 self.context.agent_name, agent_address
             )
         )
         self.context.logger.debug(
             "[{}]: game data={}".format(self.context.agent_name, str(tac_msg))
         )
         self.context.outbox.put_message(
             to=agent_address,
             sender=self.context.agent_address,
             protocol_id=TacMessage.protocol_id,
             message=TacSerializer().encode(tac_msg),
         )
Exemple #9
0
    def _register_to_tac(self, controller_addr: Address) -> None:
        """
        Register to active TAC Controller.

        :param controller_addr: the address of the controller.

        :return: None
        """
        game = cast(Game, self.context.game)
        game.update_expected_controller_addr(controller_addr)
        game.update_game_phase(Phase.GAME_REGISTRATION)
        tac_msg = TacMessage(
            performative=TacMessage.Performative.REGISTER,
            agent_name=self.context.agent_name,
        )
        tac_bytes = TacSerializer().encode(tac_msg)
        self.context.outbox.put_message(
            to=controller_addr,
            sender=self.context.agent_address,
            protocol_id=TacMessage.protocol_id,
            message=tac_bytes,
        )
Exemple #10
0
    def _on_register(self, message: TacMessage) -> None:
        """
        Handle a register message.

        If the address is not registered, answer with an error message.

        :param message: the 'get agent state' TacMessage.
        :return: None
        """
        parameters = cast(Parameters, self.context.parameters)
        agent_name = message.agent_name
        if len(parameters.whitelist
               ) != 0 and agent_name not in parameters.whitelist:
            self.context.logger.error(
                "[{}]: Agent name not in whitelist: '{}'".format(
                    self.context.agent_name, agent_name))
            tac_msg = TacMessage(
                performative=TacMessage.Performative.TAC_ERROR,
                error_code=TacMessage.ErrorCode.AGENT_NAME_NOT_IN_WHITELIST,
            )
            self.context.outbox.put_message(
                to=message.counterparty,
                sender=self.context.agent_address,
                protocol_id=TacMessage.protocol_id,
                message=TacSerializer().encode(tac_msg),
            )
            return

        game = cast(Game, self.context.game)
        if message.counterparty in game.registration.agent_addr_to_name:
            self.context.logger.error(
                "[{}]: Agent already registered: '{}'".format(
                    self.context.agent_name,
                    game.registration.agent_addr_to_name[message.counterparty],
                ))
            tac_msg = TacMessage(
                performative=TacMessage.Performative.TAC_ERROR,
                error_code=TacMessage.ErrorCode.AGENT_ADDR_ALREADY_REGISTERED,
            )
            self.context.outbox.put_message(
                to=message.counterparty,
                sender=self.context.agent_address,
                protocol_id=TacMessage.protocol_id,
                message=TacSerializer().encode(tac_msg),
            )

        if agent_name in game.registration.agent_addr_to_name.values():
            self.context.logger.error(
                "[{}]: Agent with this name already registered: '{}'".format(
                    self.context.agent_name, agent_name))
            tac_msg = TacMessage(
                performative=TacMessage.Performative.TAC_ERROR,
                error_code=TacMessage.ErrorCode.AGENT_NAME_ALREADY_REGISTERED,
            )
            self.context.outbox.put_message(
                to=message.counterparty,
                sender=self.context.agent_address,
                protocol_id=TacMessage.protocol_id,
                message=TacSerializer().encode(tac_msg),
            )
        self.context.shared_state["agents_participants_counter"] += 1
        game.registration.register_agent(message.counterparty, agent_name)
        self.context.logger.info("[{}]: Agent registered: '{}'".format(
            self.context.agent_name, agent_name))
Exemple #11
0
def test_tac_serialization():
    """Test that the serialization for the tac message works."""
    msg = TacMessage(
        performative=TacMessage.Performative.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(performative=TacMessage.Performative.UNREGISTER)
    msg_bytes = TacSerializer().encode(msg)
    actual_msg = TacSerializer().decode(msg_bytes)
    expected_msg = msg
    assert expected_msg == actual_msg

    msg = TacMessage(
        performative=TacMessage.Performative.TRANSACTION,
        tx_id="some_id",
        tx_sender_addr="some_address",
        tx_counterparty_addr="some_other_address",
        amount_by_currency_id={"FET": -10},
        tx_sender_fee=10,
        tx_counterparty_fee=10,
        quantities_by_good_id={"123": 0, "1234": 10},
        tx_nonce=1,
        tx_sender_signature=b"some_signature",
        tx_counterparty_signature=b"some_other_signature",
    )
    msg_bytes = TacSerializer().encode(msg)
    actual_msg = TacSerializer().decode(msg_bytes)
    expected_msg = msg
    assert expected_msg == actual_msg

    msg = TacMessage(performative=TacMessage.Performative.GET_STATE_UPDATE)
    msg_bytes = TacSerializer().encode(msg)
    actual_msg = TacSerializer().decode(msg_bytes)
    expected_msg = msg
    assert expected_msg == actual_msg

    msg = TacMessage(performative=TacMessage.Performative.CANCELLED)
    msg_bytes = TacSerializer().encode(msg)
    actual_msg = TacSerializer().decode(msg_bytes)
    expected_msg = msg
    assert expected_msg == actual_msg

    msg = TacMessage(
        performative=TacMessage.Performative.GAME_DATA,
        amount_by_currency_id={"FET": 10},
        exchange_params_by_currency_id={"FET": 10.0},
        quantities_by_good_id={"123": 20, "1234": 15},
        utility_params_by_good_id={"123": 30.0, "1234": 50.0},
        tx_fee=20,
        agent_addr_to_name={"agent_1": "Agent one", "agent_2": "Agent two"},
        currency_id_to_name={"FET": "currency_name"},
        good_id_to_name={"123": "First good", "1234": "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(
        performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,
        tx_id="some_id",
        amount_by_currency_id={"FET": 10},
        quantities_by_good_id={"123": 20, "1234": 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="Performative not valid: transaction_confirmation"
    ):
        with mock.patch(
            "packages.fetchai.protocols.tac.message.TacMessage.Performative"
        ) as mocked_type:
            mocked_type.TRANSACTION_CONFIRMATION.value = "unknown"
            TacSerializer().encode(msg)

    msg = TacMessage(
        performative=TacMessage.Performative.TAC_ERROR,
        error_code=TacMessage.ErrorCode.GENERIC_ERROR,
        info={"msg": "This is info msg."},
    )
    msg_bytes = TacSerializer().encode(msg)
    actual_msg = TacSerializer().decode(msg_bytes)
    expected_msg = msg
    assert expected_msg == actual_msg