Beispiel #1
0
    def _on_decline(self, decline: FIPAMessage, dialogue: Dialogue) -> None:
        """
        Handle a Decline.

        :param decline: the Decline message
        :param dialogue: the dialogue
        :return: None
        """
        logger.debug("[{}]: on_decline: msg_id={}, dialogue_id={}, origin={}, target={}"
                     .format(self.context.agent_name, decline.get("id"), decline.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, decline.get("target")))
        target = decline.get("target")
        dialogues = cast(Dialogues, self.context.dialogues)
        if target == 1:
            dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_CFP, dialogue.is_self_initiated)
        elif target == 2:
            dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_PROPOSE, dialogue.is_self_initiated)
            transactions = cast(Transactions, self.context.transactions)
            transaction_msg = transactions.pop_pending_proposal(dialogue.dialogue_label, target)
            strategy = cast(Strategy, self.context.strategy)
            if strategy.is_world_modeling:
                pass  # TODO
                # strategy.world_state.update_on_declined_propose(transaction_msg)
        elif target == 3:
            dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_ACCEPT, dialogue.is_self_initiated)
            transactions = cast(Transactions, self.context.transactions)
            transaction_msg = transactions.pop_pending_initial_acceptance(dialogue.dialogue_label, target)
            transactions.pop_locked_tx(transaction_msg)
Beispiel #2
0
    def is_valid_next_message(self, fipa_msg: FIPAMessage) -> bool:
        """
        Check whether this is a valid next message in the dialogue.

        :return: True if yes, False otherwise.
        """
        this_message_id = fipa_msg.get("message_id")
        this_target = fipa_msg.get("target")
        this_performative = cast(FIPAMessage.Performative,
                                 fipa_msg.get("performative"))
        last_outgoing_message = self.last_outgoing_message
        if last_outgoing_message is None:
            result = this_message_id == FIPAMessage.STARTING_MESSAGE_ID and \
                this_target == FIPAMessage.STARTING_TARGET and \
                this_performative == FIPAMessage.Performative.CFP
        else:
            last_message_id = cast(int,
                                   last_outgoing_message.get("message_id"))
            last_target = cast(int, last_outgoing_message.get("target"))
            last_performative = cast(FIPAMessage.Performative,
                                     last_outgoing_message.get("performative"))
            result = this_message_id == last_message_id + 1 and \
                this_target == last_target + 1 and \
                last_performative in VALID_PREVIOUS_PERFORMATIVES[this_performative]
        return result
Beispiel #3
0
    def _on_services_search_result(self, agent_pbks: List[str],
                                   is_searching_for_sellers: bool) -> None:
        """
        Process the search result for services.

        :param agent_pbks: the agent public keys matching the search query
        :param is_searching_for_sellers: whether it is searching for sellers or not

        :return: None
        """
        agent_pbks_set = set(agent_pbks)
        if self.crypto.public_key in agent_pbks_set:
            agent_pbks_set.remove(self.crypto.public_key)
        agent_pbks = list(agent_pbks_set)
        searched_for = "sellers" if is_searching_for_sellers else "buyers"
        logger.debug("[{}]: Found potential {}: {}".format(
            self.agent_name, searched_for, agent_pbks))

        services = self.game_instance.build_services_dict(
            is_supply=not is_searching_for_sellers)
        if services is None:
            response = "demanding" if is_searching_for_sellers else "supplying"
            logger.debug("[{}]: No longer {} any goods...".format(
                self.agent_name, response))
            return
        for agent_pbk in agent_pbks:
            dialogue = self.game_instance.dialogues.create_self_initiated(
                agent_pbk, self.crypto.public_key,
                not is_searching_for_sellers)
            cfp = FIPAMessage(
                message_id=STARTING_MESSAGE_ID,
                dialogue_id=dialogue.dialogue_label.dialogue_id,
                target=STARTING_MESSAGE_TARGET,
                performative=FIPAMessage.Performative.CFP,
                query=json.dumps(services).encode("utf-8"),
            )
            dialogue.outgoing_extend([cfp])
            cfp_bytes = FIPASerializer().encode(cfp)
            logger.debug(
                "[{}]: send_cfp_as_{}: msg_id={}, dialogue_id={}, destination={}, target={}, services={}"
                .format(
                    self.agent_name,
                    dialogue.role,
                    cfp.get("id"),
                    cfp.get("dialogue_id"),
                    agent_pbk,
                    cfp.get("target"),
                    services,
                ))
            self.mailbox.outbox.put_message(
                to=agent_pbk,
                sender=self.crypto.public_key,
                protocol_id=FIPAMessage.protocol_id,
                message=cfp_bytes,
            )
Beispiel #4
0
    def _on_propose(self, propose: FIPAMessage, dialogue: Dialogue) -> None:
        """
        Handle a Propose.

        :param propose: the message containing the Propose
        :param dialogue: the dialogue
        :return: None
        """
        new_msg_id = cast(int, propose.get("message_id")) + 1
        strategy = cast(Strategy, self.context.strategy)
        proposals = cast(List[Description], propose.get("proposal"))
        logger.debug("[{}]: on Propose as {}.".format(self.context.agent_name,
                                                      dialogue.role))

        for num, proposal_description in enumerate(proposals):
            if num > 0:
                continue  # TODO: allow for dialogue branching with multiple proposals
            transaction_msg = generate_transaction_message(
                proposal_description, dialogue.dialogue_label,
                dialogue.is_seller, self.context.agent_public_key)

            if strategy.is_profitable_transaction(
                    transaction_msg, is_seller=dialogue.is_seller):
                logger.info("[{}]: Accepting propose (as {}).".format(
                    self.context.agent_name, dialogue.role))
                transactions = cast(Transactions, self.context.transactions)
                transactions.add_locked_tx(transaction_msg,
                                           as_seller=dialogue.is_seller)
                transactions.add_pending_initial_acceptance(
                    dialogue.dialogue_label, new_msg_id, transaction_msg)
                fipa_msg = FIPAMessage(
                    performative=FIPAMessage.Performative.ACCEPT,
                    message_id=new_msg_id,
                    dialogue_reference=dialogue.dialogue_label.
                    dialogue_reference,
                    target=propose.get("message_id"))
            else:
                logger.info("[{}]: Declining propose (as {})".format(
                    self.context.agent_name, dialogue.role))
                fipa_msg = FIPAMessage(
                    performative=FIPAMessage.Performative.DECLINE,
                    message_id=new_msg_id,
                    dialogue_reference=dialogue.dialogue_label.
                    dialogue_reference,
                    target=propose.get("message_id"))
                dialogues = cast(Dialogues, self.context.dialogues)
                dialogues.dialogue_stats.add_dialogue_endstate(
                    Dialogue.EndState.DECLINED_PROPOSE,
                    dialogue.is_self_initiated)
            dialogue.outgoing_extend(fipa_msg)
            self.context.outbox.put_message(
                to=dialogue.dialogue_label.dialogue_opponent_pbk,
                sender=self.context.agent_public_key,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(fipa_msg))
Beispiel #5
0
    def _on_match_accept(self, match_accept: FIPAMessage, dialogue: Dialogue) -> None:
        """
        Handle a matching Accept.

        :param match_accept: the MatchAccept message
        :param dialogue: the dialogue
        :return: None
        """
        transactions = cast(Transactions, self.context.transactions)
        assert dialogue.dialogue_label in transactions.pending_initial_acceptances \
            and match_accept.get("target") in transactions.pending_initial_acceptances[dialogue.dialogue_label]
        logger.debug("[{}]: on_match_accept: msg_id={}, dialogue_id={}, origin={}, target={}"
                     .format(self.context.agent_name, match_accept.get("id"), match_accept.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, match_accept.get("target")))
        transaction_msg = transactions.pop_pending_initial_acceptance(dialogue.dialogue_label, cast(int, match_accept.get("target")))
        self.context.decision_maker_message_queue.put(transaction_msg)
Beispiel #6
0
def test_fipa_cfp_serialization_bytes():
    """Test that the serialization - deserialization for the 'fipa' protocol works."""
    query = b'Hello'
    msg = FIPAMessage(message_id=0,
                      dialogue_reference=(str(0), ''),
                      target=0,
                      performative=FIPAMessage.Performative.CFP,
                      query=query)
    msg_bytes = FIPASerializer().encode(msg)
    envelope = Envelope(to="receiver",
                        sender="sender",
                        protocol_id=FIPAMessage.protocol_id,
                        message=msg_bytes)
    envelope_bytes = envelope.encode()

    actual_envelope = Envelope.decode(envelope_bytes)
    expected_envelope = envelope
    assert expected_envelope == actual_envelope

    actual_msg = FIPASerializer().decode(actual_envelope.message)
    expected_msg = msg
    assert expected_msg == actual_msg

    deserialised_msg = FIPASerializer().decode(envelope.message)
    assert msg.get("performative") == deserialised_msg.get("performative")
Beispiel #7
0
    def _handle_propose(self, msg: FIPAMessage, sender: str, message_id: int,
                        dialogue: Dialogue) -> None:
        """
        Handle the propose.

        :param msg: the message
        :param sender: the sender
        :param message_id: the message id
        :param dialogue: the dialogue object
        :return: None
        """
        new_message_id = message_id + 1
        new_target_id = message_id
        proposals = cast(List[Description], msg.get("proposal"))

        if proposals is not []:
            # only take the first proposal
            proposal = proposals[0]
            logger.info("[{}]: received proposal={} from sender={}".format(
                self.context.agent_name, proposal.values, sender[-5:]))
            strategy = cast(Strategy, self.context.strategy)
            acceptable = strategy.is_acceptable_proposal(proposal)
            affordable = self.context.ledger_apis.token_balance(
                'fetchai',
                cast(str,
                     self.context.agent_addresses.get('fetchai'))) >= cast(
                         int, proposal.values.get('price'))
            if acceptable and affordable:
                logger.info(
                    "[{}]: accepting the proposal from sender={}".format(
                        self.context.agent_name, sender[-5:]))
                dialogue.proposal = proposal
                accept_msg = FIPAMessage(
                    message_id=new_message_id,
                    dialogue_reference=dialogue.dialogue_label.
                    dialogue_reference,
                    target=new_target_id,
                    performative=FIPAMessage.Performative.ACCEPT)
                dialogue.outgoing_extend(accept_msg)
                self.context.outbox.put_message(
                    to=sender,
                    sender=self.context.agent_public_key,
                    protocol_id=FIPAMessage.protocol_id,
                    message=FIPASerializer().encode(accept_msg))
            else:
                logger.info(
                    "[{}]: declining the proposal from sender={}".format(
                        self.context.agent_name, sender[-5:]))
                decline_msg = FIPAMessage(
                    message_id=new_message_id,
                    dialogue_reference=dialogue.dialogue_label.
                    dialogue_reference,
                    target=new_target_id,
                    performative=FIPAMessage.Performative.DECLINE)
                dialogue.outgoing_extend(decline_msg)
                self.context.outbox.put_message(
                    to=sender,
                    sender=self.context.agent_public_key,
                    protocol_id=FIPAMessage.protocol_id,
                    message=FIPASerializer().encode(decline_msg))
Beispiel #8
0
    def _handle_match_accept(self, msg: FIPAMessage, sender: str,
                             message_id: int, dialogue: Dialogue) -> None:
        """
        Handle the match accept.

        :param msg: the message
        :param sender: the sender
        :param message_id: the message id
        :param dialogue: the dialogue object
        :return: None
        """
        logger.info(
            "[{}]: received MATCH_ACCEPT_W_ADDRESS from sender={}".format(
                self.context.agent_name, sender[-5:]))
        address = cast(str, msg.get("address"))
        proposal = cast(Description, dialogue.proposal)
        tx_msg = TransactionMessage(
            performative=TransactionMessage.Performative.PROPOSE,
            skill_id="carpark_client",
            transaction_id="transaction0",
            sender=self.context.agent_public_keys['fetchai'],
            counterparty=address,
            is_sender_buyer=True,
            currency_pbk="FET",
            amount=proposal.values['price'],
            sender_tx_fee=0,
            counterparty_tx_fee=0,
            quantities_by_good_pbk={},
            dialogue_label=dialogue.dialogue_label.json,
            ledger_id='fetchai')
        self.context.decision_maker_message_queue.put_nowait(tx_msg)
        logger.info(
            "[{}]: proposing the transaction to the decision maker. Waiting for confirmation ..."
            .format(self.context.agent_name))
Beispiel #9
0
    def create_opponent_initiated(self, fipa_msg: FIPAMessage, sender: Address) -> Dialogue:
        """
        Save an opponent initiated dialogue.

        :param fipa_msg: the fipa message
        :param sender: the pbk of the sender

        :return: the created dialogue
        """
        dialogue_starter_pbk = sender
        dialogue_opponent_pbk = sender
        dialogue_id = fipa_msg.get("dialogue_id")
        dialogue_id = cast(int, dialogue_id)
        dialogue_label = DialogueLabel(dialogue_id, dialogue_opponent_pbk, dialogue_starter_pbk)
        query = cast(Query, fipa_msg.get("query"))
        assert query.model is not None, "Query has no data model."
        is_seller = query.model.name == DEMAND_DATAMODEL_NAME
        result = self._create(dialogue_label, is_seller)
        return result
Beispiel #10
0
    def test_error_skill_unsupported_protocol(self):
        """Test the unsupported error message."""
        msg = FIPAMessage(message_id=0,
                          dialogue_reference=(str(0), ''),
                          target=0,
                          performative=FIPAMessage.Performative.ACCEPT)
        msg_bytes = FIPASerializer().encode(msg)
        envelope = Envelope(to=self.public_key,
                            sender=self.public_key,
                            protocol_id=FIPAMessage.protocol_id,
                            message=msg_bytes)

        self.my_error_handler.send_unsupported_protocol(envelope)

        envelope = self.my_aea.inbox.get(block=True, timeout=1.0)
        msg = DefaultSerializer().decode(envelope.message)
        assert msg.get("type") == DefaultMessage.Type.ERROR
        assert msg.get("error_code"
                       ) == DefaultMessage.ErrorCode.UNSUPPORTED_PROTOCOL.value
Beispiel #11
0
    def test_error_invalid_message(self):
        """Test the invalid message."""
        msg = FIPAMessage(message_id=0,
                          dialogue_reference=(str(0), ''),
                          target=0,
                          performative=FIPAMessage.Performative.ACCEPT)
        msg_bytes = FIPASerializer().encode(msg)
        envelope = Envelope(to=self.public_key,
                            sender=self.public_key,
                            protocol_id=OEFMessage.protocol_id,
                            message=msg_bytes)

        self.my_error_handler.send_invalid_message(envelope)

        envelope = self.my_aea.inbox.get(block=True, timeout=1.0)
        msg = DefaultSerializer().decode(envelope.message)
        assert msg.get("type") == DefaultMessage.Type.ERROR
        assert msg.get(
            "error_code") == DefaultMessage.ErrorCode.INVALID_MESSAGE.value
Beispiel #12
0
    def _on_propose(self, propose: FIPAMessage, dialogue: Dialogue) -> None:
        """
        Handle a Propose.

        :param propose: the message containing the Propose
        :param dialogue: the dialogue
        :return: None
        """
        logger.debug("[{}]: on propose as {}.".format(self.context.agent_name, dialogue.role))
        proposals = cast(List[Description], propose.get("proposal"))
        for num, proposal_description in enumerate(proposals):
            if num > 0: continue  # TODO: allow for dialogue branching with multiple proposals
            transaction_id = generate_transaction_id(self.context.agent_public_key, dialogue.dialogue_label.dialogue_opponent_pbk, dialogue.dialogue_label, dialogue.is_seller)
            transaction_msg = TransactionMessage(transaction_id=transaction_id,
                                                 sender=self.context.agent_public_key,
                                                 counterparty=dialogue.dialogue_label.dialogue_opponent_pbk,
                                                 currency='FET',
                                                 amount=proposal_description.values['amount'],
                                                 is_sender_buyer=not dialogue.is_seller,
                                                 sender_tx_fee=1,
                                                 counterparty_tx_fee=1,
                                                 quantities_by_good_pbk=proposal_description.values['description'])
            new_msg_id = cast(int, propose.get("id")) + 1
            strategy = cast(Strategy, self.context.strategy)
            transactions = cast(Transactions, self.context.transactions)
            ownership_state_after_locks = transactions.ownership_state_after_locks(self.context.ownership_state, is_seller=dialogue.is_seller)
            if strategy.is_profitable_transaction(self.context.preferences, ownership_state_after_locks, transaction_msg):
                logger.debug("[{}]: Accepting propose (as {}).".format(self.context.agent_name, dialogue.role))
                transactions.add_locked_tx(transaction_msg, as_seller=dialogue.is_seller)
                transactions.add_pending_initial_acceptance(dialogue.dialogue_label, new_msg_id, transaction_msg)
                msg = FIPAMessage(message_id=new_msg_id, dialogue_id=propose.get("dialogue_id"), target=propose.get("id"), performative=FIPAMessage.Performative.ACCEPT)
                dialogue.outgoing_extend(msg)
                msg_bytes = FIPASerializer().encode(msg)
                result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)
            else:
                logger.debug("[{}]: Declining propose (as {})".format(self.context.agent_name, dialogue.role))
                msg = FIPAMessage(message_id=new_msg_id, dialogue_id=propose.get("dialogue_id"), target=propose.get("id"), performative=FIPAMessage.Performative.DECLINE)
                dialogue.outgoing_extend(msg)
                msg_bytes = FIPASerializer().encode(msg)
                result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)
                dialogues = cast(Dialogues, self.context.dialogues)
                dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_PROPOSE, dialogue.is_self_initiated)
        self.context.outbox.put(result)
Beispiel #13
0
    def _on_match_accept(self, match_accept: FIPAMessage,
                         dialogue: Dialogue) -> None:
        """
        Handle a matching Accept.

        :param match_accept: the MatchAccept message
        :param dialogue: the dialogue
        :return: None
        """
        logger.debug(
            "[{}]: on_match_accept: msg_id={}, dialogue_id={}, origin={}, target={}"
            .format(self.context.agent_name, match_accept.get("message_id"),
                    match_accept.get("dialogue_id"),
                    dialogue.dialogue_label.dialogue_opponent_pbk,
                    match_accept.get("target")))
        transactions = cast(Transactions, self.context.transactions)
        transaction_msg = transactions.pop_pending_initial_acceptance(
            dialogue.dialogue_label, cast(int, match_accept.get("target")))
        # update skill id to route back to tac participation skill
        transaction_msg.set('skill_id', 'tac_participation_skill')
        self.context.decision_maker_message_queue.put(transaction_msg)
Beispiel #14
0
    def _handle_cfp(self, msg: FIPAMessage, sender: str, message_id: int,
                    dialogue: Dialogue) -> None:
        """
        Handle the CFP.

        If the CFP matches the supplied services then send a PROPOSE, otherwise send a DECLINE.

        :param msg: the message
        :param sender: the sender
        :param message_id: the message id
        :param dialogue: the dialogue object
        :return: None
        """
        new_message_id = message_id + 1
        new_target = message_id
        logger.info("[{}]: received CFP from sender={}".format(
            self.context.agent_name, sender[-5:]))
        query = cast(Query, msg.get("query"))
        strategy = cast(Strategy, self.context.strategy)

        if strategy.is_matching_supply(query):
            proposal, weather_data = strategy.generate_proposal_and_data(query)
            dialogue.weather_data = weather_data
            dialogue.proposal = proposal
            logger.info(
                "[{}]: sending sender={} a PROPOSE with proposal={}".format(
                    self.context.agent_name, sender[-5:], proposal.values))
            proposal_msg = FIPAMessage(
                message_id=new_message_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=new_target,
                performative=FIPAMessage.Performative.PROPOSE,
                proposal=[proposal])
            dialogue.outgoing_extend(proposal_msg)
            self.context.outbox.put_message(
                to=sender,
                sender=self.context.agent_public_key,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(proposal_msg))
        else:
            logger.info("[{}]: declined the CFP from sender={}".format(
                self.context.agent_name, sender[-5:]))
            decline_msg = FIPAMessage(
                message_id=new_message_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=new_target,
                performative=FIPAMessage.Performative.DECLINE)
            dialogue.outgoing_extend(decline_msg)
            self.context.outbox.put_message(
                to=sender,
                sender=self.context.agent_public_key,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(decline_msg))
    def test_serialisation_fipa(self):
        """Tests a Value Error flag for wrong CFP query."""
        with pytest.raises(ValueError):
            msg = FIPAMessage(performative=FIPAMessage.Performative.CFP,
                              message_id=0,
                              dialogue_reference=(str(0), ''),
                              target=1,
                              query=None)
            with mock.patch(
                    "aea.protocols.fipa.message.FIPAMessage.Performative"
            ) as mock_performative_enum:
                mock_performative_enum.CFP.value = "unknown"
                FIPASerializer().encode(msg), "Raises Value Error"
        with pytest.raises(ValueError):
            msg.set("query", "Hello")
            # query type is not supported
            FIPASerializer().encode(msg)
        with pytest.raises(ValueError):
            cfp_msg = FIPAMessage(message_id=0,
                                  dialogue_reference=(str(0), ''),
                                  target=0,
                                  performative=FIPAMessage.Performative.CFP,
                                  query=b"hello")
            cfp_msg.set("query", "hello")
            fipa_msg = fipa_pb2.FIPAMessage()
            fipa_msg.message_id = cfp_msg.get("message_id")
            dialogue_reference = cast(Dict[str, str],
                                      cfp_msg.get("dialogue_reference"))
            fipa_msg.dialogue_starter_reference = dialogue_reference[0]
            fipa_msg.dialogue_responder_reference = dialogue_reference[1]
            fipa_msg.target = cfp_msg.get("target")
            performative = fipa_pb2.FIPAMessage.CFP()
            fipa_msg.cfp.CopyFrom(performative)
            fipa_bytes = fipa_msg.SerializeToString()

            # The encoded message is not a valid FIPA message.
            FIPASerializer().decode(fipa_bytes)
        with pytest.raises(ValueError):
            cfp_msg = FIPAMessage(message_id=0,
                                  dialogue_reference=(str(0), ''),
                                  target=0,
                                  performative=FIPAMessage.Performative.CFP,
                                  query=b"hello")
            with mock.patch(
                    "aea.protocols.fipa.message.FIPAMessage.Performative"
            ) as mock_performative_enum:
                mock_performative_enum.CFP.value = "unknown"
                fipa_msg = fipa_pb2.FIPAMessage()
                fipa_msg.message_id = cfp_msg.get("message_id")
                dialogue_reference = cast(Dict[str, str],
                                          cfp_msg.get("dialogue_reference"))
                fipa_msg.dialogue_starter_reference = dialogue_reference[0]
                fipa_msg.dialogue_responder_reference = dialogue_reference[1]
                fipa_msg.target = cfp_msg.get("target")
                performative = fipa_pb2.FIPAMessage.CFP()
                fipa_msg.cfp.CopyFrom(performative)
                fipa_bytes = fipa_msg.SerializeToString()

                # The encoded message is not a FIPA message
                FIPASerializer().decode(fipa_bytes)
Beispiel #16
0
def test_performative_match_accept():
    """Test the serialization - deserialization of the match_accept performative."""
    msg = FIPAMessage(message_id=0,
                      dialogue_reference=(str(0), ''),
                      target=1,
                      performative=FIPAMessage.Performative.MATCH_ACCEPT)

    msg_bytes = FIPASerializer().encode(msg)
    envelope = Envelope(to="receiver",
                        sender="sender",
                        protocol_id=FIPAMessage.protocol_id,
                        message=msg_bytes)
    envelope_bytes = envelope.encode()

    actual_envelope = Envelope.decode(envelope_bytes)
    expected_envelope = envelope
    assert expected_envelope == actual_envelope
    deserialised_msg = FIPASerializer().decode(envelope.message)
    assert msg.get("performative") == deserialised_msg.get("performative")
 def test_serialisation_fipa(self):
     """Tests a Value Error flag for wrong CFP query."""
     with pytest.raises(ValueError):
         msg = FIPAMessage(performative=FIPAMessage.Performative.CFP,
                           message_id=0,
                           dialogue_id=0,
                           destination="publicKey",
                           target=1)
         with mock.patch("aea.protocols.fipa.message.FIPAMessage.Performative")\
                 as mock_performative_enum:
             mock_performative_enum.CFP.value = "unknown"
             assert FIPASerializer().encode(msg), "Raises Value Error"
     with pytest.raises(ValueError):
         msg.set("query", "Hello")
         assert FIPASerializer().encode(msg), "Query type is Supported!"
     with pytest.raises(ValueError):
         cfp_msg = FIPAMessage(message_id=0,
                               dialogue_id=0,
                               target=0,
                               performative=FIPAMessage.Performative.CFP,
                               query=b"hello")
         cfp_msg.set("query", "hello")
         fipa_msg = fipa_pb2.FIPAMessage()
         fipa_msg.message_id = cfp_msg.get("id")
         fipa_msg.dialogue_id = cfp_msg.get("dialogue_id")
         fipa_msg.target = cfp_msg.get("target")
         performative = fipa_pb2.FIPAMessage.CFP()
         fipa_msg.cfp.CopyFrom(performative)
         fipa_bytes = fipa_msg.SerializeToString()
         assert FIPASerializer().decode(fipa_bytes),\
             "The encoded message is a valid FIPA message."
     with pytest.raises(ValueError):
         cfp_msg = FIPAMessage(message_id=0,
                               dialogue_id=0,
                               target=0,
                               performative=FIPAMessage.Performative.CFP,
                               query=b"hello")
         with mock.patch("aea.protocols.fipa.message.FIPAMessage.Performative")\
                 as mock_performative_enum:
             mock_performative_enum.CFP.value = "unknown"
             fipa_msg = fipa_pb2.FIPAMessage()
             fipa_msg.message_id = cfp_msg.get("id")
             fipa_msg.dialogue_id = cfp_msg.get("dialogue_id")
             fipa_msg.target = cfp_msg.get("target")
             performative = fipa_pb2.FIPAMessage.CFP()
             fipa_msg.cfp.CopyFrom(performative)
             fipa_bytes = fipa_msg.SerializeToString()
             assert FIPASerializer().decode(fipa_bytes),\
                 "The encoded message is a FIPA message"
Beispiel #18
0
def test_performative_inform():
    """Test the serialization-deserialization of the inform performative."""
    msg = FIPAMessage(message_id=0,
                      dialogue_reference=(str(0), ''),
                      target=1,
                      performative=FIPAMessage.Performative.INFORM,
                      json_data={"foo": "bar"})

    msg_bytes = FIPASerializer().encode(msg)
    envelope = Envelope(to="receiver",
                        sender="sender",
                        protocol_id=FIPAMessage.protocol_id,
                        message=msg_bytes)
    envelope_bytes = envelope.encode()

    actual_envelope = Envelope.decode(envelope_bytes)
    expected_envelope = envelope
    assert expected_envelope == actual_envelope
    deserialised_msg = FIPASerializer().decode(envelope.message)
    assert msg.get("performative") == deserialised_msg.get("performative")
Beispiel #19
0
    def _handle_inform(self, msg: FIPAMessage, sender: str, message_id: int,
                       dialogue: Dialogue) -> None:
        """
        Handle the match inform.

        :param msg: the message
        :param sender: the sender
        :param message_id: the message id
        :param dialogue: the dialogue object
        :return: None
        """
        logger.info("[{}]: received INFORM from sender={}".format(
            self.context.agent_name, sender[-5:]))
        json_data = cast(dict, msg.get("json_data"))
        if 'weather_data' in json_data.keys():
            weather_data = json_data['weather_data']
            logger.info("[{}]: received the following weather data={}".format(
                self.context.agent_name, pprint.pformat(weather_data)))
        else:
            logger.info("[{}]: received no data from sender={}".format(
                self.context.agent_name, sender[-5:]))
Beispiel #20
0
    def _handle_inform(self, msg: FIPAMessage, sender: str, message_id: int,
                       dialogue: Dialogue) -> None:
        """
        Handle the INFORM.

        If the INFORM message contains the transaction_digest then verify that it is settled, otherwise do nothing.
        If the transaction is settled send the weather data, otherwise do nothing.

        :param msg: the message
        :param sender: the sender
        :param message_id: the message id
        :param dialogue: the dialogue object
        :return: None
        """
        new_message_id = message_id + 1
        new_target = message_id
        logger.info("[{}]: received INFORM from sender={}".format(
            self.context.agent_name, sender[-5:]))

        json_data = cast(dict, msg.get("json_data"))
        if "Done" in json_data:
            inform_msg = FIPAMessage(
                message_id=new_message_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=new_target,
                performative=FIPAMessage.Performative.INFORM,
                json_data=dialogue.weather_data)
            dialogue.outgoing_extend(inform_msg)
            # import pdb; pdb.set_trace()
            self.context.outbox.put_message(
                to=sender,
                sender=self.context.agent_public_key,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(inform_msg))
            # dialogues = cast(Dialogues, self.context.dialogues)
            # dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.SUCCESSFUL)
        else:
            logger.warning("I didn't receive the transaction digest!")
Beispiel #21
0
    def _handle_inform(self, msg: FIPAMessage, sender: str, message_id: int,
                       dialogue: Dialogue) -> None:
        """
        Handle the match inform.

        :param msg: the message
        :param sender: the sender
        :param message_id: the message id
        :param dialogue: the dialogue object
        :return: None
        """
        logger.info("[{}]: received INFORM from sender={}".format(
            self.context.agent_name, sender[-5:]))
        json_data = cast(dict, msg.get("json_data"))
        if 'message_type' in json_data and json_data[
                'message_type'] == 'car_park_data':
            logger.info("[{}]: received the following carpark data={}".format(
                self.context.agent_name, pprint.pformat(json_data)))
            # dialogues = cast(Dialogues, self.context.dialogues)
            # dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.SUCCESSFUL)
        else:
            logger.info("[{}]: received no data from sender={}".format(
                self.context.agent_name, sender[-5:]))
Beispiel #22
0
    def _on_accept(self, accept: FIPAMessage, dialogue: Dialogue) -> None:
        """
        Handle an Accept.

        :param accept: the Accept message
        :param dialogue: the dialogue
        :return: None
        """
        logger.debug(
            "[{}]: on_accept: msg_id={}, dialogue_id={}, origin={}, target={}".
            format(self.context.agent_name, accept.get("message_id"),
                   accept.get("dialogue_id"),
                   dialogue.dialogue_label.dialogue_opponent_pbk,
                   accept.get("target")))
        new_msg_id = cast(int, accept.get("message_id")) + 1
        transactions = cast(Transactions, self.context.transactions)
        transaction_msg = transactions.pop_pending_proposal(
            dialogue.dialogue_label, cast(int, accept.get("target")))
        strategy = cast(Strategy, self.context.strategy)

        if strategy.is_profitable_transaction(transaction_msg,
                                              is_seller=dialogue.is_seller):
            logger.info("[{}]: locking the current state (as {}).".format(
                self.context.agent_name, dialogue.role))
            transactions.add_locked_tx(transaction_msg,
                                       as_seller=dialogue.is_seller)
            self.context.decision_maker_message_queue.put(transaction_msg)
        else:
            logger.debug("[{}]: decline the Accept (as {}).".format(
                self.context.agent_name, dialogue.role))
            fipa_msg = FIPAMessage(
                performative=FIPAMessage.Performative.DECLINE,
                message_id=new_msg_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=accept.get("message_id"),
            )
            dialogue.outgoing_extend(fipa_msg)
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogues.dialogue_stats.add_dialogue_endstate(
                Dialogue.EndState.DECLINED_ACCEPT, dialogue.is_self_initiated)
            self.context.outbox.put_message(
                to=dialogue.dialogue_label.dialogue_opponent_pbk,
                sender=self.context.agent_public_key,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(fipa_msg))
Beispiel #23
0
    def _on_accept(self, accept: FIPAMessage, dialogue: Dialogue) -> None:
        """
        Handle an Accept.

        :param accept: the Accept message
        :param dialogue: the dialogue
        :return: None
        """
        transactions = cast(Transactions, self.context.transactions)
        assert dialogue.dialogue_label in transactions.pending_proposals \
            and accept.get("target") in transactions.pending_proposals[dialogue.dialogue_label]
        logger.debug("[{}]: on_accept: msg_id={}, dialogue_id={}, origin={}, target={}"
                     .format(self.context.agent_name, accept.get("id"), accept.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, accept.get("target")))
        new_msg_id = cast(int, accept.get("id")) + 1
        transaction_msg = transactions.pop_pending_proposal(dialogue.dialogue_label, cast(int, accept.get("target")))
        strategy = cast(Strategy, self.context.strategy)
        ownership_state_after_locks = transactions.ownership_state_after_locks(self.context.ownership_state, is_seller=dialogue.is_seller)
        if strategy.is_profitable_transaction(self.context.preferences, ownership_state_after_locks, transaction_msg):
            if strategy.is_world_modeling:
                pass  # TODO
                # strategy.world_state.update_on_initial_accept(transaction_msg)
            logger.debug("[{}]: Locking the current state (as {}).".format(self.context.agent_name, dialogue.role))
            transactions.add_locked_tx(transaction_msg, as_seller=dialogue.is_seller)
            self.context.decision_maker_message_queue.put(transaction_msg)
            msg = FIPAMessage(message_id=new_msg_id, dialogue_id=accept.get("dialogue_id"), target=accept.get("id"), performative=FIPAMessage.Performative.MATCH_ACCEPT)
            dialogue.outgoing_extend(msg)
            msg_bytes = FIPASerializer().encode(msg)
            result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)
        else:
            logger.debug("[{}]: Decline the accept (as {}).".format(self.context.agent_name, dialogue.role))
            msg = FIPAMessage(message_id=new_msg_id, dialogue_id=accept.get("dialogue_id"), target=accept.get("id"), performative=FIPAMessage.Performative.DECLINE)
            dialogue.outgoing_extend(msg)
            msg_bytes = FIPASerializer().encode(msg)
            result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_ACCEPT, dialogue.is_self_initiated)
        self.context.outbox.put(result)
Beispiel #24
0
    def _on_cfp(self, cfp: FIPAMessage, dialogue: Dialogue) -> None:
        """
        Handle a CFP.

        :param cfp: the fipa message containing the CFP
        :param dialogue: the dialogue

        :return: None
        """
        strategy = cast(Strategy, self.context.strategy)
        transactions = cast(Transactions, self.context.transactions)
        ownership_state_after_locks = transactions.ownership_state_after_locks(self.context.ownership_state, is_seller=dialogue.is_seller)
        own_service_description = strategy.get_own_service_description(ownership_state_after_locks, is_supply=dialogue.is_seller)
        new_msg_id = cast(int, cfp.get("id")) + 1
        cfp_query = cfp.get("query")
        cfp_query = cast(Query, cfp_query)
        decline = False
        if not cfp_query.check(own_service_description):
            decline = True
            logger.debug("[{}]: Current holdings do not satisfy CFP query.".format(self.context.agent_name))
        else:
            proposal_description = strategy.get_proposal_for_query(cfp_query, self.context.preferences, ownership_state_after_locks, is_seller=dialogue.is_seller, tx_fee=1.0)
            if proposal_description is None:
                decline = True
                logger.debug("[{}]: Current strategy does not generate proposal that satisfies CFP query.".format(self.context.agent_name))

        if decline:
            logger.debug("[{}]: sending to {} a Decline{}".format(self.context.agent_name, dialogue.dialogue_label.dialogue_opponent_pbk,
                                                                  pprint.pformat({
                                                                      "msg_id": new_msg_id,
                                                                      "dialogue_id": cfp.get("dialogue_id"),
                                                                      "origin": dialogue.dialogue_label.dialogue_opponent_pbk,
                                                                      "target": cfp.get("target")
                                                                  })))
            msg = FIPAMessage(message_id=new_msg_id, dialogue_id=cfp.get("dialogue_id"), performative=FIPAMessage.Performative.DECLINE, target=cfp.get("id"))
            dialogue.outgoing_extend(msg)
            msg_bytes = FIPASerializer().encode(msg)
            result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_CFP, dialogue.is_self_initiated)
        else:
            assert proposal_description is not None
            transaction_id = generate_transaction_id(self.context.agent_public_key, dialogue.dialogue_label.dialogue_opponent_pbk, dialogue.dialogue_label, dialogue.is_seller)
            transaction_msg = TransactionMessage(transaction_id=transaction_id,
                                                 sender=self.context.agent_public_key,
                                                 counterparty=dialogue.dialogue_label.dialogue_opponent_pbk,
                                                 currency='FET',
                                                 amount=proposal_description.values['amount'],
                                                 is_sender_buyer=not dialogue.is_seller,
                                                 sender_tx_fee=1,
                                                 counterparty_tx_fee=1,
                                                 quantities_by_good_pbk=proposal_description.values['description'])
            transactions = cast(Transactions, self.context.transactions)
            transactions.add_pending_proposal(dialogue.dialogue_label, new_msg_id, transaction_msg)
            logger.debug("[{}]: sending to {} a Propose{}".format(self.context.agent_name, dialogue.dialogue_label.dialogue_opponent_pbk,
                                                                  pprint.pformat({
                                                                      "msg_id": new_msg_id,
                                                                      "dialogue_id": cfp.get("dialogue_id"),
                                                                      "origin": dialogue.dialogue_label.dialogue_opponent_pbk,
                                                                      "target": cfp.get("id"),
                                                                      "propose": proposal_description.values
                                                                  })))
            msg = FIPAMessage(performative=FIPAMessage.Performative.PROPOSE, message_id=new_msg_id, dialogue_id=cfp.get("dialogue_id"), target=cfp.get("id"), proposal=[proposal_description])
            dialogue.outgoing_extend(msg)
            msg_bytes = FIPASerializer().encode(msg)
            result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)
        self.context.outbox.put(result)
Beispiel #25
0
    def _handle_inform(self, msg: FIPAMessage, sender: str, message_id: int,
                       dialogue: Dialogue) -> None:
        """
        Handle the INFORM.

        If the INFORM message contains the transaction_digest then verify that it is settled, otherwise do nothing.
        If the transaction is settled send the weather data, otherwise do nothing.

        :param msg: the message
        :param sender: the sender
        :param message_id: the message id
        :param dialogue: the dialogue object
        :return: None
        """
        new_message_id = message_id + 1
        new_target = message_id
        logger.info("[{}]: received INFORM from sender={}".format(
            self.context.agent_name, sender[-5:]))

        json_data = cast(dict, msg.get("json_data"))
        if "transaction_digest" in json_data.keys():
            tx_digest = json_data['transaction_digest']
            logger.info(
                "[{}]: checking whether transaction={} has been received ...".
                format(self.context.agent_name, tx_digest))
            proposal = cast(Description, dialogue.proposal)
            total_price = cast(int, proposal.values.get("price"))
            is_settled = self.context.ledger_apis.is_tx_settled(
                'fetchai', tx_digest, total_price)
            if is_settled:
                token_balance = self.context.ledger_apis.token_balance(
                    'fetchai',
                    cast(str, self.context.agent_addresses.get('fetchai')))

                strategy = cast(Strategy, self.context.strategy)
                strategy.record_balance(token_balance)

                logger.info(
                    "[{}]: transaction={} settled, new balance={}. Sending data to sender={}"
                    .format(self.context.agent_name, tx_digest, token_balance,
                            sender[-5:]))
                inform_msg = FIPAMessage(
                    message_id=new_message_id,
                    dialogue_reference=dialogue.dialogue_label.
                    dialogue_reference,
                    target=new_target,
                    performative=FIPAMessage.Performative.INFORM,
                    json_data=dialogue.carpark_data)
                dialogue.outgoing_extend(inform_msg)
                # import pdb; pdb.set_trace()
                self.context.outbox.put_message(
                    to=sender,
                    sender=self.context.agent_public_key,
                    protocol_id=FIPAMessage.protocol_id,
                    message=FIPASerializer().encode(inform_msg))
                # dialogues = cast(Dialogues, self.context.dialogues)
                # dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.SUCCESSFUL)
                strategy.db.add_in_progress_transaction(
                    tx_digest, sender[-5:], self.context.agent_name,
                    total_price)
                strategy.db.set_transaction_complete(tx_digest)
                strategy.db.set_dialogue_status(str(dialogue.dialogue_label),
                                                sender[-5:],
                                                "transaction_complete",
                                                "send_request_data")
            else:
                logger.info(
                    "[{}]: transaction={} not settled, aborting".format(
                        self.context.agent_name, tx_digest))
        else:
            logger.info(
                "[{}]: did not receive transaction digest from sender={}.".
                format(self.context.agent_name, sender[-5:]))
Beispiel #26
0
    def _on_cfp(self, cfp: FIPAMessage, dialogue: Dialogue) -> None:
        """
        Handle a CFP.

        :param cfp: the fipa message containing the CFP
        :param dialogue: the dialogue

        :return: None
        """
        new_msg_id = cast(int, cfp.get("message_id")) + 1
        query = cast(Query, cfp.get("query"))
        strategy = cast(Strategy, self.context.strategy)
        proposal_description = strategy.get_proposal_for_query(
            query, dialogue.is_seller)

        if proposal_description is None:
            logger.debug("[{}]: sending to {} a Decline{}".format(
                self.context.agent_name,
                dialogue.dialogue_label.dialogue_opponent_pbk,
                pprint.pformat({
                    "msg_id": new_msg_id,
                    "dialogue_id": cfp.get("dialogue_id"),
                    "origin": dialogue.dialogue_label.dialogue_opponent_pbk,
                    "target": cfp.get("target")
                })))
            fipa_msg = FIPAMessage(
                performative=FIPAMessage.Performative.DECLINE,
                message_id=new_msg_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=cfp.get("message_id"))
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogues.dialogue_stats.add_dialogue_endstate(
                Dialogue.EndState.DECLINED_CFP, dialogue.is_self_initiated)
        else:
            transaction_msg = generate_transaction_message(
                proposal_description, dialogue.dialogue_label,
                dialogue.is_seller, self.context.agent_public_key)
            transactions = cast(Transactions, self.context.transactions)
            transactions.add_pending_proposal(dialogue.dialogue_label,
                                              new_msg_id, transaction_msg)
            logger.info("[{}]: sending to {} a Propose{}".format(
                self.context.agent_name,
                dialogue.dialogue_label.dialogue_opponent_pbk,
                pprint.pformat({
                    "msg_id": new_msg_id,
                    "dialogue_id": cfp.get("dialogue_id"),
                    "origin": dialogue.dialogue_label.dialogue_opponent_pbk,
                    "target": cfp.get("message_id"),
                    "propose": proposal_description.values
                })))
            fipa_msg = FIPAMessage(
                performative=FIPAMessage.Performative.PROPOSE,
                message_id=new_msg_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=cfp.get("message_id"),
                proposal=[proposal_description])
        dialogue.outgoing_extend(fipa_msg)
        self.context.outbox.put_message(
            to=dialogue.dialogue_label.dialogue_opponent_pbk,
            sender=self.context.agent_public_key,
            protocol_id=FIPAMessage.protocol_id,
            message=FIPASerializer().encode(fipa_msg))