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)
    def test_propose(self):
        """Test that a Propose can be sent correctly."""
        propose_empty = FIPAMessage(
            message_id=0,
            dialogue_id=0,
            target=0,
            performative=FIPAMessage.Performative.PROPOSE,
            proposal=[])
        self.mailbox1.outbox.put_message(
            to=self.crypto2.public_key,
            sender=self.crypto1.public_key,
            protocol_id=FIPAMessage.protocol_id,
            message=FIPASerializer().encode(propose_empty))
        envelope = self.mailbox2.inbox.get(block=True, timeout=2.0)
        expected_propose_empty = FIPASerializer().decode(envelope.message)
        assert expected_propose_empty == propose_empty

        propose_descriptions = FIPAMessage(
            message_id=0,
            dialogue_id=0,
            target=0,
            performative=FIPAMessage.Performative.PROPOSE,
            proposal=[
                Description({"foo": "bar"},
                            DataModel("foobar", [Attribute("foo", str, True)]))
            ])
        self.mailbox1.outbox.put_message(
            to=self.crypto2.public_key,
            sender=self.crypto1.public_key,
            protocol_id=FIPAMessage.protocol_id,
            message=FIPASerializer().encode(propose_descriptions))
        envelope = self.mailbox2.inbox.get(block=True, timeout=2.0)
        expected_propose_descriptions = FIPASerializer().decode(
            envelope.message)
        assert expected_propose_descriptions == propose_descriptions
Beispiel #3
0
    def on_propose(self, propose: Message, dialogue: Dialogue) -> Envelope:
        """
        Handle a Propose.

        :param propose: the message containing the Propose
        :param dialogue: the dialogue

        :return: an Accept or a Decline
        """
        logger.debug("[{}]: on propose as {}.".format(self.agent_name,
                                                      dialogue.role))
        assert propose.get("performative") == FIPAMessage.Performative.PROPOSE
        proposal = propose.get("proposal")[0]
        transaction_id = generate_transaction_id(
            self.crypto.public_key,
            dialogue.dialogue_label.dialogue_opponent_pbk,
            dialogue.dialogue_label, dialogue.is_seller)
        transaction = Transaction.from_proposal(
            proposal=proposal,
            transaction_id=transaction_id,
            is_sender_buyer=not dialogue.is_seller,
            counterparty=dialogue.dialogue_label.dialogue_opponent_pbk,
            sender=self.crypto.public_key)
        new_msg_id = propose.get("id") + 1
        is_profitable_transaction, propose_log_msg = self.game_instance.is_profitable_transaction(
            transaction, dialogue)
        logger.debug(propose_log_msg)
        if is_profitable_transaction:
            logger.debug("[{}]: Accepting propose (as {}).".format(
                self.agent_name, dialogue.role))
            self.game_instance.transaction_manager.add_locked_tx(
                transaction, as_seller=dialogue.is_seller)
            self.game_instance.transaction_manager.add_pending_initial_acceptance(
                dialogue.dialogue_label, new_msg_id, transaction)
            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.crypto.public_key,
                              protocol_id=FIPAMessage.protocol_id,
                              message=msg_bytes)
        else:
            logger.debug("[{}]: Declining propose (as {})".format(
                self.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.crypto.public_key,
                              protocol_id=FIPAMessage.protocol_id,
                              message=msg_bytes)
            self.game_instance.stats_manager.add_dialogue_endstate(
                EndState.DECLINED_PROPOSE, dialogue.is_self_initiated)
        return result
    def test_cfp(self):
        """Test that a CFP can be sent correctly."""
        cfp_bytes = FIPAMessage(
            message_id=0,
            dialogue_id=0,
            target=0,
            performative=FIPAMessage.Performative.CFP,
            query=Query([Constraint('something', ConstraintType('>', 1))]))
        self.mailbox1.outbox.put_message(
            to=self.crypto2.public_key,
            sender=self.crypto1.public_key,
            protocol_id=FIPAMessage.protocol_id,
            message=FIPASerializer().encode(cfp_bytes))
        envelope = self.mailbox2.inbox.get(block=True, timeout=5.0)
        expected_cfp_bytes = FIPASerializer().decode(envelope.message)
        assert expected_cfp_bytes == cfp_bytes

        cfp_none = FIPAMessage(message_id=0,
                               dialogue_id=0,
                               target=0,
                               performative=FIPAMessage.Performative.CFP,
                               query=None)
        self.mailbox1.outbox.put_message(
            to=self.crypto2.public_key,
            sender=self.crypto1.public_key,
            protocol_id=FIPAMessage.protocol_id,
            message=FIPASerializer().encode(cfp_none))
        envelope = self.mailbox2.inbox.get(block=True, timeout=5.0)
        expected_cfp_none = FIPASerializer().decode(envelope.message)
        assert expected_cfp_none == cfp_none
Beispiel #5
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 #6
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 #7
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))
Beispiel #8
0
    def handle_cfp(self, msg: FIPAMessage, sender: str, message_id: int,
                   dialogue_id: int) -> None:
        """
        Handle the CFP calls.

        :param msg: the message
        :param sender: the sender
        :param message_id: the message id
        :param dialogue_id: the dialogue id
        :return: None
        """
        new_message_id = message_id + 1
        new_target = message_id
        fetched_data = self.db.get_data_for_specific_dates(DATE_ONE, DATE_TWO)

        if len(fetched_data) >= 1:
            self.fetched_data = fetched_data
            total_price = self.fet_price * len(fetched_data)
            proposal = [
                Description({
                    "Rows": len(fetched_data),
                    "Price": total_price
                })
            ]
            logger.info(
                "[{}]: sending sender={} a proposal at price={}".format(
                    self.context.agent_name, sender, total_price))
            proposal_msg = FIPAMessage(
                message_id=new_message_id,
                dialogue_id=dialogue_id,
                target=new_target,
                performative=FIPAMessage.Performative.PROPOSE,
                proposal=proposal)
            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))
            decline_msg = FIPAMessage(
                message_id=new_message_id,
                dialogue_id=dialogue_id,
                target=new_target,
                performative=FIPAMessage.Performative.DECLINE)
            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_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 #10
0
    def on_cfp(self, msg_id: int, dialogue_id: int, origin: str, target: int,
               query: CFP_TYPES) -> None:
        """
        On cfp event handler.

        :param msg_id: the message id.
        :param dialogue_id: the dialogue id.
        :param origin: the public key of the sender.
        :param target: the message target.
        :param query: the query.
        :return: None
        """
        assert self.in_queue is not None
        assert self.loop is not None
        logger.warning(
            'Accepting on_cfp from deprecated API: msg_id={}, dialogue_id={}, origin={}, target={}. Continuing dialogue via envelopes!'
            .format(msg_id, dialogue_id, origin, target))
        try:
            query = pickle.loads(query)
        except Exception:
            pass
        msg = FIPAMessage(message_id=msg_id,
                          dialogue_reference=(str(dialogue_id), ''),
                          target=target,
                          performative=FIPAMessage.Performative.CFP,
                          query=query if query != b"" else None)
        msg_bytes = FIPASerializer().encode(msg)
        envelope = Envelope(to=self.public_key,
                            sender=origin,
                            protocol_id=FIPAMessage.protocol_id,
                            message=msg_bytes)
        asyncio.run_coroutine_threadsafe(self.in_queue.put(envelope),
                                         self.loop).result()
Beispiel #11
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
        """
        tx_msg_response = cast(TransactionMessage, message)
        if tx_msg_response is not None and \
                TransactionMessage.Performative(tx_msg_response.get("performative")) == TransactionMessage.Performative.ACCEPT:
            logger.info("[{}]: transaction was successful.".format(self.context.agent_name))
            json_data = {'transaction_digest': tx_msg_response.get("transaction_digest")}
            dialogue_label = DialogueLabel.from_json(cast(Dict[str, str], tx_msg_response.get("dialogue_label")))
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogue = dialogues.dialogues[dialogue_label]
            fipa_msg = cast(FIPAMessage, dialogue.last_incoming_message)
            new_message_id = cast(int, fipa_msg.get("message_id")) + 1
            new_target_id = cast(int, fipa_msg.get("target")) + 1
            counterparty_pbk = dialogue.dialogue_label.dialogue_opponent_pbk
            inform_msg = FIPAMessage(message_id=new_message_id,
                                     dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                                     target=new_target_id,
                                     performative=FIPAMessage.Performative.INFORM,
                                     json_data=json_data)
            dialogue.outgoing_extend(inform_msg)
            self.context.outbox.put_message(to=counterparty_pbk,
                                            sender=self.context.agent_public_key,
                                            protocol_id=FIPAMessage.protocol_id,
                                            message=FIPASerializer().encode(inform_msg))
            logger.info("[{}]: informing counterparty={} of transaction digest.".format(self.context.agent_name, counterparty_pbk[-5:]))
            self._received_tx_message = True
        else:
            logger.info("[{}]: transaction was not successful.".format(self.context.agent_name))
Beispiel #12
0
    def _handle_search(self, agents: List[str]) -> None:
        """
        Handle the search response.

        :param agents: the agents returned by the search
        :return: None
        """
        if len(agents) > 0:
            logger.info("[{}]: found agents={}, stopping search.".format(self.context.agent_name, list(map(lambda x: x[-5:], agents))))
            strategy = cast(Strategy, self.context.strategy)
            # stopping search
            strategy.is_searching = False
            # pick first agent found
            opponent_pbk = agents[0]
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogue = dialogues.create_self_initiated(opponent_pbk, self.context.agent_public_key, is_seller=False)
            query = strategy.get_service_query()
            logger.info("[{}]: sending CFP to agent={}".format(self.context.agent_name, opponent_pbk[-5:]))
            cfp_msg = FIPAMessage(message_id=FIPAMessage.STARTING_MESSAGE_ID,
                                  dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                                  performative=FIPAMessage.Performative.CFP,
                                  target=FIPAMessage.STARTING_TARGET,
                                  query=query)
            dialogue.outgoing_extend(cfp_msg)
            self.context.outbox.put_message(to=opponent_pbk,
                                            sender=self.context.agent_public_key,
                                            protocol_id=FIPAMessage.protocol_id,
                                            message=FIPASerializer().encode(cfp_msg))
        else:
            logger.info("[{}]: found no agents, continue searching.".format(self.context.agent_name))
Beispiel #13
0
    def _handle_accept(self, msg: FIPAMessage, sender: str, message_id: int,
                       dialogue: Dialogue) -> None:
        """
        Handle the ACCEPT.

        Respond with a MATCH_ACCEPT_W_ADDRESS which contains the address to send the funds to.

        :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 ACCEPT from sender={}".format(
            self.context.agent_name, sender[-5:]))
        logger.info("[{}]: sending MATCH_ACCEPT_W_ADDRESS to sender={}".format(
            self.context.agent_name, sender[-5:]))
        match_accept_msg = FIPAMessage(
            message_id=new_message_id,
            dialogue_reference=dialogue.dialogue_label.dialogue_reference,
            target=new_target,
            performative=FIPAMessage.Performative.MATCH_ACCEPT_W_ADDRESS,
            address=self.context.agent_addresses['fetchai'])
        dialogue.outgoing_extend(match_accept_msg)
        self.context.outbox.put_message(
            to=sender,
            sender=self.context.agent_public_key,
            protocol_id=FIPAMessage.protocol_id,
            message=FIPASerializer().encode(match_accept_msg))
        strategy = cast(Strategy, self.context.strategy)
        strategy.db.set_dialogue_status(str(dialogue.dialogue_label),
                                        sender[-5:], "received_accept",
                                        "send_match_accept")
Beispiel #14
0
def test_fipa_cfp_serialization():
    """Test that the serialization for the 'fipa' protocol works."""
    query = Query([Constraint('something', ConstraintType('>', 1))])
    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

    msg.set("query", "not_supported_query")
    with pytest.raises(ValueError, match="Query type not supported:"):
        FIPASerializer().encode(msg)
Beispiel #15
0
    def on_propose(self, msg_id: int, dialogue_id: int, origin: str,
                   target: int, b_proposals: PROPOSE_TYPES) -> None:
        """
        On propose event handler.

        :param msg_id: the message id.
        :param dialogue_id: the dialogue id.
        :param origin: the public key of the sender.
        :param target: the message target.
        :param b_proposals: the proposals.
        :return: None
        """
        if type(b_proposals) == bytes:
            proposals = pickle.loads(b_proposals)  # type: List[Description]
        else:
            raise ValueError("No support for non-bytes proposals.")

        msg = FIPAMessage(message_id=msg_id,
                          dialogue_id=dialogue_id,
                          target=target,
                          performative=FIPAMessage.Performative.PROPOSE,
                          proposal=proposals)
        msg_bytes = FIPASerializer().encode(msg)
        envelope = Envelope(to=self.public_key,
                            sender=origin,
                            protocol_id=FIPAMessage.protocol_id,
                            message=msg_bytes)
        self.in_queue.put(envelope)
Beispiel #16
0
    def _handle_accept(self, msg: FIPAMessage, sender: str, message_id: int,
                       dialogue: Dialogue) -> None:
        """
        Handle the ACCEPT.

        Respond with a MATCH_ACCEPT_W_ADDRESS which contains the address to send the funds to.

        :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 ACCEPT from sender={}".format(
            self.context.agent_name, sender[-5:]))
        logger.info("[{}]: sending MATCH_ACCEPT_W_ADDRESS to sender={}".format(
            self.context.agent_name, sender[-5:]))
        # proposal = cast(Description, dialogue.proposal)
        # identifier = cast(str, proposal.values.get("ledger_id"))
        match_accept_msg = FIPAMessage(
            message_id=new_message_id,
            dialogue_reference=dialogue.dialogue_label.dialogue_reference,
            target=new_target,
            performative=FIPAMessage.Performative.MATCH_ACCEPT_W_ADDRESS,
            address="no_address")
        dialogue.outgoing_extend(match_accept_msg)
        self.context.outbox.put_message(
            to=sender,
            sender=self.context.agent_public_key,
            protocol_id=FIPAMessage.protocol_id,
            message=FIPASerializer().encode(match_accept_msg))
Beispiel #17
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 #18
0
    def handle_envelope(self, envelope: Envelope) -> None:
        """
        Implement the reaction to an envelope.

        :param envelope: the envelope
        :return: None
        """
        msg = OEFSerializer().decode(envelope.message)
        msg_type = OEFMessage.Type(msg.get("type"))

        if msg_type is OEFMessage.Type.SEARCH_RESULT:
            agents = cast(List[str], msg.get("agents"))
            logger.info("[{}]: found agents={}".format(self.context.agent_name,
                                                       agents))
            for agent in agents:
                msg = FIPAMessage(message_id=STARTING_MESSAGE_ID,
                                  dialogue_id=self.dialogue_id,
                                  performative=FIPAMessage.Performative.CFP,
                                  target=STARTING_TARGET_ID,
                                  query=None)
                self.dialogue_id += 1
                self.context.outbox.put_message(
                    to=agent,
                    sender=self.context.agent_public_key,
                    protocol_id=FIPAMessage.protocol_id,
                    message=FIPASerializer().encode(msg))
Beispiel #19
0
def test_fipa_propose_serialization():
    """Test that the serialization for the 'fipa' protocol works."""
    proposal = [
        Description({"foo1": 1, "bar1": 2}),
        Description({"foo2": 1, "bar2": 2}),
    ]
    msg = FIPAMessage(message_id=0,
                      dialogue_reference=(str(0), ''),
                      target=0,
                      performative=FIPAMessage.Performative.PROPOSE,
                      proposal=proposal)
    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

    p1 = actual_msg.get("proposal")
    p2 = expected_msg.get("proposal")
    assert p1[0].values == p2[0].values
    assert p1[1].values == p2[1].values
Beispiel #20
0
    def on_cfp(self, msg_id: int, dialogue_id: int, origin: str, target: int,
               query: CFP_TYPES) -> None:
        """
        On cfp event handler.

        :param msg_id: the message id.
        :param dialogue_id: the dialogue id.
        :param origin: the public key of the sender.
        :param target: the message target.
        :param query: the query.
        :return: None
        """
        try:
            query = pickle.loads(query)
        except Exception:
            pass
        msg = FIPAMessage(message_id=msg_id,
                          dialogue_id=dialogue_id,
                          target=target,
                          performative=FIPAMessage.Performative.CFP,
                          query=query if query != b"" else None)
        msg_bytes = FIPASerializer().encode(msg)
        envelope = Envelope(to=self.public_key,
                            sender=origin,
                            protocol_id=FIPAMessage.protocol_id,
                            message=msg_bytes)
        self.in_queue.put(envelope)
Beispiel #21
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
        """
        new_message_id = message_id + 1
        new_target_id = message_id
        counterparty_pbk = dialogue.dialogue_label.dialogue_opponent_pbk
        inform_msg = FIPAMessage(
            message_id=new_message_id,
            dialogue_reference=dialogue.dialogue_label.dialogue_reference,
            target=new_target_id,
            performative=FIPAMessage.Performative.INFORM,
            json_data={"Done": "Sending payment via bank transfer"})
        dialogue.outgoing_extend(inform_msg)
        self.context.outbox.put_message(
            to=counterparty_pbk,
            sender=self.context.agent_public_key,
            protocol_id=FIPAMessage.protocol_id,
            message=FIPASerializer().encode(inform_msg))
        logger.info("[{}]: informing counterparty={} of payment.".format(
            self.context.agent_name, counterparty_pbk[-5:]))
        self._received_tx_message = True
Beispiel #22
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 #23
0
def test_fipa_encoding_unknown_performative():
    """Test that we raise an exception when the performative is unknown during encoding."""
    msg = FIPAMessage(message_id=0,
                      dialogue_reference=(str(0), ''),
                      target=1,
                      performative=FIPAMessage.Performative.ACCEPT)

    with pytest.raises(ValueError, match="Performative not valid:"):
        with mock.patch.object(FIPAMessage.Performative, "__eq__", return_value=False):
            FIPASerializer().encode(msg)
Beispiel #24
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,
            )
    async def test_messages(self):
        """Test that at the beginning, the search request returns an empty search result."""
        msg = FIPAMessage((str(0), ''), 0, 0, FIPAMessage.Performative.CFP, query=None)
        msg_bytes = FIPASerializer().encode(msg)
        envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)
        with pytest.raises(AEAConnectionError):
            await OEFLocalConnection(self.public_key_1, self.node).send(envelope)

        self.multiplexer1.connect()
        msg = FIPAMessage((str(0), str(1)), 0, 0, FIPAMessage.Performative.CFP, query=None)
        msg_bytes = FIPASerializer().encode(msg)
        envelope = Envelope(to="this_public_key_does_not_exist",
                            sender=self.public_key_1, protocol_id=FIPAMessage.protocol_id, message=msg_bytes)
        self.multiplexer1.put(envelope)

        # check the result
        response_envelope = self.multiplexer1.get(block=True, timeout=5.0)
        assert response_envelope.protocol_id == OEFMessage.protocol_id
        assert response_envelope.sender == DEFAULT_OEF
        result = OEFSerializer().decode(response_envelope.message)
        assert result.get("type") == OEFMessage.Type.DIALOGUE_ERROR
Beispiel #26
0
 def test_error_handler_handle(self):
     """Test the handle function."""
     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.handle(message=msg, sender=envelope.sender)
Beispiel #27
0
def test_performative_not_recognized():
    """Tests an unknown Performative."""
    msg = FIPAMessage(
        performative=FIPAMessage.Performative.ACCEPT,
        message_id=0,
        dialogue_reference=(str(0), ''),
        target=1)

    with mock.patch("aea.protocols.fipa.message.FIPAMessage.Performative")\
            as mock_performative_enum:
        mock_performative_enum.ACCEPT.value = "unknown"
        assert not msg.check_consistency(),\
            "We expect that the check_consistency will return False"
Beispiel #28
0
def test_handle():
    """Tests handle method of an agent."""
    node = LocalNode()
    agent_name = "MyAgent"
    private_key_pem_path = os.path.join(CUR_PATH, "data", "priv.pem")
    crypto = Crypto(private_key_pem_path=private_key_pem_path)
    public_key = crypto.public_key
    mailbox = MailBox(OEFLocalConnection(public_key, node))

    msg = DefaultMessage(type=DefaultMessage.Type.BYTES, content=b"hello")
    message_bytes = DefaultSerializer().encode(msg)

    envelope = Envelope(to="Agent1",
                        sender=public_key,
                        protocol_id="unknown_protocol",
                        message=message_bytes)

    agent = AEA(agent_name,
                mailbox,
                private_key_pem_path=private_key_pem_path,
                directory=str(Path(CUR_PATH, "data", "dummy_aea")))
    t = Thread(target=agent.start)
    try:
        t.start()
        agent.mailbox.inbox._queue.put(envelope)
        env = agent.mailbox.outbox._queue.get(block=True, timeout=5.0)
        assert env.protocol_id == "default", \
            "The envelope is not the expected protocol (Unsupported protocol)"

        #   DECODING ERROR
        msg = "hello".encode("utf-8")
        envelope = Envelope(to=public_key,
                            sender=public_key,
                            protocol_id='default',
                            message=msg)
        agent.mailbox.inbox._queue.put(envelope)
        #   UNSUPPORTED SKILL
        msg = FIPASerializer().encode(
            FIPAMessage(performative=FIPAMessage.Performative.ACCEPT,
                        message_id=0,
                        dialogue_id=0,
                        destination=public_key,
                        target=1))
        envelope = Envelope(to=public_key,
                            sender=public_key,
                            protocol_id="fipa",
                            message=msg)
        agent.mailbox.inbox._queue.put(envelope)
    finally:
        agent.stop()
        t.join()
 def test_decline(self):
     """Test that a Decline can be sent correctly."""
     decline = FIPAMessage(message_id=0,
                           dialogue_id=0,
                           target=0,
                           performative=FIPAMessage.Performative.DECLINE)
     self.mailbox1.outbox.put_message(
         to=self.crypto2.public_key,
         sender=self.crypto1.public_key,
         protocol_id=FIPAMessage.protocol_id,
         message=FIPASerializer().encode(decline))
     envelope = self.mailbox2.inbox.get(block=True, timeout=2.0)
     expected_decline = FIPASerializer().decode(envelope.message)
     assert expected_decline == decline
 def test_accept(self):
     """Test that an Accept can be sent correctly."""
     accept = FIPAMessage(message_id=0,
                          dialogue_id=0,
                          target=0,
                          performative=FIPAMessage.Performative.ACCEPT)
     self.mailbox1.outbox.put_message(
         to=self.crypto2.public_key,
         sender=self.crypto1.public_key,
         protocol_id=FIPAMessage.protocol_id,
         message=FIPASerializer().encode(accept))
     envelope = self.mailbox2.inbox.get(block=True, timeout=2.0)
     expected_accept = FIPASerializer().decode(envelope.message)
     assert expected_accept == accept