Example #1
0
    def _handle_propose(self, msg: FIPAMessage, dialogue: Dialogue) -> None:
        """
        Handle the propose.

        :param msg: the message
        :param dialogue: the dialogue object
        :return: None
        """
        new_message_id = msg.message_id + 1
        new_target = msg.message_id
        proposals = msg.proposal

        if proposals is not []:
            # only take the first proposal
            proposal = proposals[0]
            self.context.logger.info(
                "[{}]: received proposal={} from sender={}".format(
                    self.context.agent_name, proposal.values,
                    msg.counterparty[-5:]))
            strategy = cast(Strategy, self.context.strategy)

            acceptable = strategy.is_acceptable_proposal(proposal)
            affordable = strategy.is_affordable_proposal(proposal)
            if acceptable and affordable:
                self.context.logger.info(
                    "[{}]: accepting the proposal from sender={}".format(
                        self.context.agent_name, msg.counterparty[-5:]))
                dialogue.proposal = proposal
                accept_msg = FIPAMessage(
                    message_id=new_message_id,
                    dialogue_reference=dialogue.dialogue_label.
                    dialogue_reference,
                    target=new_target,
                    performative=FIPAMessage.Performative.ACCEPT,
                )
                dialogue.outgoing_extend(accept_msg)
                self.context.outbox.put_message(
                    to=msg.counterparty,
                    sender=self.context.agent_address,
                    protocol_id=FIPAMessage.protocol_id,
                    message=FIPASerializer().encode(accept_msg),
                )
            else:
                self.context.logger.info(
                    "[{}]: declining the proposal from sender={}".format(
                        self.context.agent_name, msg.counterparty[-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=msg.counterparty,
                    sender=self.context.agent_address,
                    protocol_id=FIPAMessage.protocol_id,
                    message=FIPASerializer().encode(decline_msg),
                )
Example #2
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.counterparty = "sender"
    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)
    actual_msg.counterparty = "sender"
    expected_msg = msg
    assert expected_msg == actual_msg

    deserialised_msg = FIPASerializer().decode(envelope.message)
    deserialised_msg.counterparty = "sender"
    assert msg.get("performative") == deserialised_msg.get("performative")
Example #3
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
Example #4
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)
Example #5
0
def test_fipa_accept_serialization():
    """Test that the serialization for the 'fipa' protocol works."""
    msg = FIPAMessage(
        message_id=0,
        dialogue_reference=(str(0), ""),
        target=0,
        performative=FIPAMessage.Performative.ACCEPT,
    )
    msg.counterparty = "sender"
    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)
    actual_msg.counterparty = "sender"
    expected_msg = msg
    assert expected_msg == actual_msg
Example #6
0
    def _handle_cfp(self, msg: FIPAMessage, 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 dialogue: the dialogue object
        :return: None
        """
        new_message_id = msg.message_id + 1
        new_target = msg.message_id
        self.context.logger.info("[{}]: received CFP from sender={}".format(
            self.context.agent_name, msg.counterparty[-5:]))
        query = cast(Query, msg.query)
        strategy = cast(Strategy, self.context.strategy)

        if strategy.is_matching_supply(query):
            proposal, data_for_sale = strategy.generate_proposal_and_data(
                query, msg.counterparty)
            dialogue.data_for_sale = data_for_sale
            dialogue.proposal = proposal
            self.context.logger.info(
                "[{}]: sending sender={} a PROPOSE with proposal={}".format(
                    self.context.agent_name, msg.counterparty[-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=msg.counterparty,
                sender=self.context.agent_address,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(proposal_msg),
            )
        else:
            self.context.logger.info(
                "[{}]: declined the CFP from sender={}".format(
                    self.context.agent_name, msg.counterparty[-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=msg.counterparty,
                sender=self.context.agent_address,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(decline_msg),
            )
Example #7
0
def test_fipa_decoding_unknown_performative():
    """Test that we raise an exception when the performative is unknown during decoding."""
    msg = FIPAMessage(
        message_id=0,
        dialogue_reference=(str(0), ""),
        target=1,
        performative=FIPAMessage.Performative.ACCEPT,
    )

    encoded_msg = FIPASerializer().encode(msg)
    with pytest.raises(ValueError, match="Performative not valid:"):
        with mock.patch.object(FIPAMessage.Performative, "__eq__", return_value=False):
            FIPASerializer().decode(encoded_msg)
    def test_propose(self):
        """Test that a Propose can be sent correctly."""
        propose_empty = FIPAMessage(
            message_id=0,
            dialogue_reference=(str(0), ""),
            target=0,
            performative=FIPAMessage.Performative.PROPOSE,
            proposal=[],
        )
        propose_empty.counterparty = self.crypto2.address
        self.multiplexer1.put(
            Envelope(
                to=self.crypto2.address,
                sender=self.crypto1.address,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(propose_empty),
            )
        )
        envelope = self.multiplexer2.get(block=True, timeout=2.0)
        expected_propose_empty = FIPASerializer().decode(envelope.message)
        expected_propose_empty.counterparty = self.crypto2.address
        assert expected_propose_empty == propose_empty

        propose_descriptions = FIPAMessage(
            message_id=0,
            dialogue_reference=(str(0), ""),
            target=0,
            performative=FIPAMessage.Performative.PROPOSE,
            proposal=[
                Description(
                    {"foo": "bar"}, DataModel("foobar", [Attribute("foo", str, True)])
                )
            ],
        )

        propose_descriptions.counterparty = self.crypto2.address
        self.multiplexer1.put(
            Envelope(
                to=self.crypto2.address,
                sender=self.crypto1.address,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(propose_descriptions),
            )
        )
        envelope = self.multiplexer2.get(block=True, timeout=2.0)
        expected_propose_descriptions = FIPASerializer().decode(envelope.message)
        expected_propose_descriptions.counterparty = self.crypto2.address
        assert expected_propose_descriptions == propose_descriptions
Example #9
0
    def _handle_accept(self, msg: FIPAMessage, dialogue: Dialogue) -> None:
        """
        Handle the ACCEPT.

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

        :param msg: the message
        :param dialogue: the dialogue object
        :return: None
        """
        new_message_id = msg.message_id + 1
        new_target = msg.message_id
        self.context.logger.info("[{}]: received ACCEPT from sender={}".format(
            self.context.agent_name, msg.counterparty[-5:]))
        self.context.logger.info(
            "[{}]: sending MATCH_ACCEPT_W_INFORM to sender={}".format(
                self.context.agent_name, msg.counterparty[-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_INFORM,
            info={"address": self.context.agent_addresses[identifier]},
        )
        dialogue.outgoing_extend(match_accept_msg)
        self.context.outbox.put_message(
            to=msg.counterparty,
            sender=self.context.agent_address,
            protocol_id=FIPAMessage.protocol_id,
            message=FIPASerializer().encode(match_accept_msg),
        )
Example #10
0
    def _handle_match_accept(self, msg: FIPAMessage,
                             dialogue: Dialogue) -> None:
        """
        Handle the match accept.

        :param msg: the message
        :param dialogue: the dialogue object
        :return: None
        """
        strategy = cast(Strategy, self.context.strategy)
        if strategy.is_ledger_tx:
            self.context.logger.info(
                "[{}]: received MATCH_ACCEPT_W_INFORM from sender={}".format(
                    self.context.agent_name, msg.counterparty[-5:]))
            info = msg.info
            address = cast(str, info.get("address"))
            proposal = cast(Description, dialogue.proposal)
            strategy = cast(Strategy, self.context.strategy)
            tx_msg = TransactionMessage(
                performative=TransactionMessage.Performative.
                PROPOSE_FOR_SETTLEMENT,
                skill_callback_ids=[
                    PublicId("fetchai", "carpark_client", "0.1.0")
                ],
                tx_id="transaction0",
                tx_sender_addr=self.context.agent_addresses["fetchai"],
                tx_counterparty_addr=address,
                tx_amount_by_currency_id={
                    proposal.values["currency_id"]: -proposal.values["price"]
                },
                tx_sender_fee=strategy.max_buyer_tx_fee,
                tx_counterparty_fee=proposal.values["seller_tx_fee"],
                tx_quantities_by_good_id={},
                ledger_id=proposal.values["ledger_id"],
                info={"dialogue_label": dialogue.dialogue_label.json},
            )
            self.context.decision_maker_message_queue.put_nowait(tx_msg)
            self.context.logger.info(
                "[{}]: proposing the transaction to the decision maker. Waiting for confirmation ..."
                .format(self.context.agent_name))
        else:
            new_message_id = msg.message_id + 1
            new_target = msg.message_id
            inform_msg = FIPAMessage(
                message_id=new_message_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=new_target,
                performative=FIPAMessage.Performative.INFORM,
                info={"Done": "Sending payment via bank transfer"},
            )
            dialogue.outgoing_extend(inform_msg)
            self.context.outbox.put_message(
                to=msg.counterparty,
                sender=self.context.agent_address,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(inform_msg),
            )
            self.context.logger.info(
                "[{}]: informing counterparty={} of payment.".format(
                    self.context.agent_name, msg.counterparty[-5:]))
    def test_cfp(self):
        """Test that a CFP can be sent correctly."""
        cfp_message = FIPAMessage(
            message_id=0,
            dialogue_reference=(str(0), ""),
            target=0,
            performative=FIPAMessage.Performative.CFP,
            query=Query([Constraint("something", ConstraintType(">", 1))]),
        )
        cfp_message.counterparty = self.crypto2.address
        self.multiplexer1.put(
            Envelope(
                to=self.crypto2.address,
                sender=self.crypto1.address,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(cfp_message),
            )
        )
        envelope = self.multiplexer2.get(block=True, timeout=5.0)
        expected_cfp_message = FIPASerializer().decode(envelope.message)
        expected_cfp_message.counterparty = self.crypto2.address

        assert expected_cfp_message == cfp_message

        cfp_none = FIPAMessage(
            message_id=0,
            dialogue_reference=(str(0), ""),
            target=0,
            performative=FIPAMessage.Performative.CFP,
            query=None,
        )
        cfp_none.counterparty = self.crypto2.address
        self.multiplexer1.put(
            Envelope(
                to=self.crypto2.address,
                sender=self.crypto1.address,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(cfp_none),
            )
        )
        envelope = self.multiplexer2.get(block=True, timeout=5.0)
        expected_cfp_none = FIPASerializer().decode(envelope.message)
        expected_cfp_none.counterparty = self.crypto2.address
        assert expected_cfp_none == cfp_none
 def test_decline(self):
     """Test that a Decline can be sent correctly."""
     decline = FIPAMessage(
         message_id=0,
         dialogue_reference=(str(0), ""),
         target=0,
         performative=FIPAMessage.Performative.DECLINE,
     )
     decline.counterparty = self.crypto2.address
     self.multiplexer1.put(
         Envelope(
             to=self.crypto2.address,
             sender=self.crypto1.address,
             protocol_id=FIPAMessage.protocol_id,
             message=FIPASerializer().encode(decline),
         )
     )
     envelope = self.multiplexer2.get(block=True, timeout=2.0)
     expected_decline = FIPASerializer().decode(envelope.message)
     expected_decline.counterparty = self.crypto2.address
     assert expected_decline == decline
 def test_accept(self):
     """Test that an Accept can be sent correctly."""
     accept = FIPAMessage(
         message_id=0,
         dialogue_reference=(str(0), ""),
         target=0,
         performative=FIPAMessage.Performative.ACCEPT,
     )
     accept.counterparty = self.crypto2.address
     self.multiplexer1.put(
         Envelope(
             to=self.crypto2.address,
             sender=self.crypto1.address,
             protocol_id=FIPAMessage.protocol_id,
             message=FIPASerializer().encode(accept),
         )
     )
     envelope = self.multiplexer2.get(block=True, timeout=2.0)
     expected_accept = FIPASerializer().decode(envelope.message)
     expected_accept.counterparty = self.crypto2.address
     assert expected_accept == accept
 def test_accept_w_inform(self):
     """Test that an accept with address can be sent correctly."""
     accept_w_inform = FIPAMessage(
         message_id=0,
         dialogue_reference=(str(0), ""),
         target=0,
         performative=FIPAMessage.Performative.ACCEPT_W_INFORM,
         info={"address": "my_address"},
     )
     accept_w_inform.counterparty = self.crypto2.address
     self.multiplexer1.put(
         Envelope(
             to=self.crypto2.address,
             sender=self.crypto1.address,
             protocol_id=FIPAMessage.protocol_id,
             message=FIPASerializer().encode(accept_w_inform),
         )
     )
     envelope = self.multiplexer2.get(block=True, timeout=2.0)
     returned_accept_w_inform = FIPASerializer().decode(envelope.message)
     returned_accept_w_inform.counterparty = self.crypto2.address
     assert returned_accept_w_inform == accept_w_inform
 def test_match_accept(self):
     """Test that a match accept can be sent correctly."""
     # NOTE since the OEF SDK doesn't support the match accept, we have to use a fixed message id!
     match_accept = FIPAMessage(
         message_id=4,
         dialogue_reference=(str(0), ""),
         target=3,
         performative=FIPAMessage.Performative.MATCH_ACCEPT,
     )
     match_accept.counterparty = self.crypto2.address
     self.multiplexer1.put(
         Envelope(
             to=self.crypto2.address,
             sender=self.crypto1.address,
             protocol_id=FIPAMessage.protocol_id,
             message=FIPASerializer().encode(match_accept),
         )
     )
     envelope = self.multiplexer2.get(block=True, timeout=2.0)
     expected_match_accept = FIPASerializer().decode(envelope.message)
     expected_match_accept.counterparty = self.crypto2.address
     assert expected_match_accept == match_accept
Example #16
0
    def handle(self, message: Message) -> None:
        """
        Implement the reaction to a message.

        :param message: the message
        :return: None
        """
        tx_msg_response = cast(TransactionMessage, message)
        if (
            tx_msg_response is not None
            and tx_msg_response.performative
            == TransactionMessage.Performative.SUCCESSFUL_SETTLEMENT
        ):
            self.context.logger.info(
                "[{}]: transaction was successful.".format(self.context.agent_name)
            )
            json_data = {"transaction_digest": tx_msg_response.tx_digest}
            info = cast(Dict[str, Any], tx_msg_response.info)
            dialogue_label = DialogueLabel.from_json(
                cast(Dict[str, str], info.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 = fipa_msg.message_id + 1
            new_target_id = fipa_msg.message_id
            counterparty_addr = dialogue.dialogue_label.dialogue_opponent_addr
            inform_msg = FIPAMessage(
                message_id=new_message_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=new_target_id,
                performative=FIPAMessage.Performative.INFORM,
                info=json_data,
            )
            dialogue.outgoing_extend(inform_msg)
            self.context.outbox.put_message(
                to=counterparty_addr,
                sender=self.context.agent_address,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(inform_msg),
            )
            self.context.logger.info(
                "[{}]: informing counterparty={} of transaction digest.".format(
                    self.context.agent_name, counterparty_addr[-5:]
                )
            )
        else:
            self.context.logger.info(
                "[{}]: transaction was not successful.".format(self.context.agent_name)
            )
 def test_inform(self):
     """Test that an inform can be sent correctly."""
     payload = {"foo": "bar"}
     inform = FIPAMessage(
         message_id=0,
         dialogue_reference=(str(0), ""),
         target=0,
         performative=FIPAMessage.Performative.INFORM,
         info=payload,
     )
     inform.counterparty = self.crypto2.address
     self.multiplexer1.put(
         Envelope(
             to=self.crypto2.address,
             sender=self.crypto1.address,
             protocol_id=FIPAMessage.protocol_id,
             message=FIPASerializer().encode(inform),
         )
     )
     envelope = self.multiplexer2.get(block=True, timeout=2.0)
     returned_inform = FIPASerializer().decode(envelope.message)
     returned_inform.counterparty = self.crypto2.address
     assert returned_inform == inform
Example #18
0
    def on_cfp(
        self,
        msg_id: int,
        dialogue_id: int,
        origin: Address,
        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 address 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)  # nosec
        except Exception as e:
            logger.debug(
                "When trying to unpickle the query the following exception occured: {}".format(
                    e
                )
            )
        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.address,
            sender=origin,
            protocol_id=FIPAMessage.protocol_id,
            message=msg_bytes,
        )
        asyncio.run_coroutine_threadsafe(
            self.in_queue.put(envelope), self.loop
        ).result()
Example #19
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,
    )
    msg.counterparty = "sender"
    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")
Example #20
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,
        info={"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")
Example #21
0
def test_performative_match_accept_with_inform():
    """Test the serialization - deserialization of the match_accept_with_address performative."""
    msg = FIPAMessage(
        message_id=0,
        dialogue_reference=(str(0), ""),
        target=1,
        performative=FIPAMessage.Performative.MATCH_ACCEPT_W_INFORM,
        info={"address": "dummy_address", "signature": "my_signature"},
    )

    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")
Example #22
0
    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.address_1,
            protocol_id=FIPAMessage.protocol_id,
            message=msg_bytes,
        )
        with pytest.raises(AEAConnectionError):
            await OEFLocalConnection(
                self.address_1,
                self.node,
                connection_id=PublicId("fetchai", "local", "0.1.0"),
            ).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_address_does_not_exist",
            sender=self.address_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
Example #23
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:
            self.context.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_addr = agents[0]
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogue = dialogues.create_self_initiated(
                opponent_addr, self.context.agent_address, is_seller=False
            )
            query = strategy.get_service_query()
            self.context.logger.info(
                "[{}]: sending CFP to agent={}".format(
                    self.context.agent_name, opponent_addr[-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_addr,
                sender=self.context.agent_address,
                protocol_id=FIPAMessage.protocol_id,
                message=FIPASerializer().encode(cfp_msg),
            )
        else:
            self.context.logger.info(
                "[{}]: found no agents, continue searching.".format(
                    self.context.agent_name
                )
            )
Example #24
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.address,
            sender=self.address,
            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.performative == DefaultMessage.Performative.ERROR
        assert msg.error_code == DefaultMessage.ErrorCode.INVALID_MESSAGE
Example #25
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.address,
            sender=self.address,
            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.performative == DefaultMessage.Performative.ERROR
        assert msg.error_code == DefaultMessage.ErrorCode.UNSUPPORTED_PROTOCOL
Example #26
0
async def test_handle():
    """Tests handle method of an agent."""
    with LocalNode() as node:
        agent_name = "MyAgent"
        private_key_path = os.path.join(CUR_PATH, "data",
                                        "fet_private_key.txt")
        wallet = Wallet({FETCHAI: private_key_path})
        ledger_apis = LedgerApis({}, FETCHAI)
        identity = Identity(agent_name, address=wallet.addresses[FETCHAI])
        connection = OEFLocalConnection(identity.address,
                                        node,
                                        connection_id=DUMMY_SKILL_PUBLIC_ID)
        connections = [connection]
        resources = Resources(str(Path(CUR_PATH, "data", "dummy_aea")))

        msg = DefaultMessage(
            dialogue_reference=("", ""),
            message_id=1,
            target=0,
            performative=DefaultMessage.Performative.BYTES,
            content=b"hello",
        )
        msg.counterparty = agent_name
        message_bytes = DefaultSerializer().encode(msg)

        envelope = Envelope(
            to=identity.address,
            sender=identity.address,
            protocol_id=UNKNOWN_PROTOCOL_PUBLIC_ID,
            message=message_bytes,
        )

        agent = AEA(identity,
                    connections,
                    wallet,
                    ledger_apis,
                    resources,
                    is_programmatic=False)
        t = Thread(target=agent.start)
        try:
            t.start()
            time.sleep(2.0)
            dummy_skill = agent.resources.get_skill(DUMMY_SKILL_PUBLIC_ID)
            dummy_handler = dummy_skill.handlers["dummy"]

            expected_envelope = envelope
            agent.outbox.put(expected_envelope)
            time.sleep(2.0)
            assert len(dummy_handler.handled_messages) == 1

            #   DECODING ERROR
            msg = "hello".encode("utf-8")
            envelope = Envelope(
                to=identity.address,
                sender=identity.address,
                protocol_id=DefaultMessage.protocol_id,
                message=msg,
            )
            expected_envelope = envelope
            agent.outbox.put(expected_envelope)
            time.sleep(2.0)
            assert len(dummy_handler.handled_messages) == 2

            #   UNSUPPORTED SKILL
            msg = FIPASerializer().encode(
                FIPAMessage(
                    performative=FIPAMessage.Performative.ACCEPT,
                    message_id=0,
                    dialogue_reference=(str(0), ""),
                    target=1,
                ))
            envelope = Envelope(
                to=identity.address,
                sender=identity.address,
                protocol_id=FIPAMessage.protocol_id,
                message=msg,
            )
            expected_envelope = envelope
            agent.outbox.put(expected_envelope)
            time.sleep(2.0)
            assert len(dummy_handler.handled_messages) == 3

        finally:
            agent.stop()
            t.join()
    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(
                "packages.fetchai.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(
                "packages.fetchai.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)
Example #28
0
def test_communication():
    """Test that two multiplexer can communicate through the node."""
    with LocalNode() as node:

        local_public_id = PublicId("fetchai", "local", "0.1.0")
        multiplexer1 = Multiplexer([
            OEFLocalConnection("multiplexer1",
                               node,
                               connection_id=local_public_id)
        ])
        multiplexer2 = Multiplexer([
            OEFLocalConnection("multiplexer2",
                               node,
                               connection_id=local_public_id)
        ])

        multiplexer1.connect()
        multiplexer2.connect()

        msg = DefaultMessage(
            dialogue_reference=("", ""),
            message_id=1,
            target=0,
            performative=DefaultMessage.Performative.BYTES,
            content=b"hello",
        )
        msg_bytes = DefaultSerializer().encode(msg)
        envelope = Envelope(
            to="multiplexer2",
            sender="multiplexer1",
            protocol_id=DefaultMessage.protocol_id,
            message=msg_bytes,
        )
        multiplexer1.put(envelope)

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

        msg = FIPAMessage(
            (str(0), str(1)),
            0,
            0,
            FIPAMessage.Performative.PROPOSE,
            proposal=[],
        )
        msg_bytes = FIPASerializer().encode(msg)
        envelope = Envelope(
            to="multiplexer2",
            sender="multiplexer1",
            protocol_id=FIPAMessage.protocol_id,
            message=msg_bytes,
        )
        multiplexer1.put(envelope)

        msg = FIPAMessage((str(0), str(1)), 0, 0,
                          FIPAMessage.Performative.ACCEPT)
        msg_bytes = FIPASerializer().encode(msg)
        envelope = Envelope(
            to="multiplexer2",
            sender="multiplexer1",
            protocol_id=FIPAMessage.protocol_id,
            message=msg_bytes,
        )
        multiplexer1.put(envelope)

        msg = FIPAMessage((str(0), str(1)), 0, 0,
                          FIPAMessage.Performative.DECLINE)
        msg_bytes = FIPASerializer().encode(msg)
        envelope = Envelope(
            to="multiplexer2",
            sender="multiplexer1",
            protocol_id=FIPAMessage.protocol_id,
            message=msg_bytes,
        )
        multiplexer1.put(envelope)

        envelope = multiplexer2.get(block=True, timeout=1.0)
        msg = DefaultSerializer().decode(envelope.message)
        assert envelope.protocol_id == DefaultMessage.protocol_id
        assert msg.get("content") == b"hello"
        envelope = multiplexer2.get(block=True, timeout=1.0)
        msg = FIPASerializer().decode(envelope.message)
        assert envelope.protocol_id == FIPAMessage.protocol_id
        assert msg.get("performative") == FIPAMessage.Performative.CFP
        envelope = multiplexer2.get(block=True, timeout=1.0)
        msg = FIPASerializer().decode(envelope.message)
        assert envelope.protocol_id == FIPAMessage.protocol_id
        assert msg.get("performative") == FIPAMessage.Performative.PROPOSE
        envelope = multiplexer2.get(block=True, timeout=1.0)
        msg = FIPASerializer().decode(envelope.message)
        assert envelope.protocol_id == FIPAMessage.protocol_id
        assert msg.get("performative") == FIPAMessage.Performative.ACCEPT
        envelope = multiplexer2.get(block=True, timeout=1.0)
        msg = FIPASerializer().decode(envelope.message)
        assert envelope.protocol_id == FIPAMessage.protocol_id
        assert msg.get("performative") == FIPAMessage.Performative.DECLINE
        multiplexer1.disconnect()
        multiplexer2.disconnect()
Example #29
0
    def _handle_inform(self, msg: FIPAMessage, 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 data, otherwise do nothing.

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

        strategy = cast(Strategy, self.context.strategy)
        if strategy.is_ledger_tx and ("transaction_digest" in msg.info.keys()):
            tx_digest = msg.info["transaction_digest"]
            self.context.logger.info(
                "[{}]: checking whether transaction={} has been received ...".
                format(self.context.agent_name, tx_digest))
            proposal = cast(Description, dialogue.proposal)
            ledger_id = cast(str, proposal.values.get("ledger_id"))
            is_valid = self.context.ledger_apis.is_tx_valid(
                ledger_id,
                tx_digest,
                self.context.agent_addresses[ledger_id],
                msg.counterparty,
                cast(str, proposal.values.get("tx_nonce")),
                cast(int, proposal.values.get("price")),
            )
            # TODO: check the tx_digest references a transaction with the correct terms
            if is_valid:
                token_balance = self.context.ledger_apis.token_balance(
                    ledger_id,
                    cast(str, self.context.agent_addresses.get(ledger_id)))
                self.context.logger.info(
                    "[{}]: transaction={} settled, new balance={}. Sending data to sender={}"
                    .format(
                        self.context.agent_name,
                        tx_digest,
                        token_balance,
                        msg.counterparty[-5:],
                    ))
                inform_msg = FIPAMessage(
                    message_id=new_message_id,
                    dialogue_reference=dialogue.dialogue_label.
                    dialogue_reference,
                    target=new_target,
                    performative=FIPAMessage.Performative.INFORM,
                    info=dialogue.data_for_sale,
                )
                dialogue.outgoing_extend(inform_msg)
                self.context.outbox.put_message(
                    to=msg.counterparty,
                    sender=self.context.agent_address,
                    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, dialogue.is_self_initiated)
            else:
                self.context.logger.info(
                    "[{}]: transaction={} not settled, aborting".format(
                        self.context.agent_name, tx_digest))
        elif "Done" in msg.info.keys():
            inform_msg = FIPAMessage(
                message_id=new_message_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=new_target,
                performative=FIPAMessage.Performative.INFORM,
                info=dialogue.data_for_sale,
            )
            dialogue.outgoing_extend(inform_msg)
            self.context.outbox.put_message(
                to=msg.counterparty,
                sender=self.context.agent_address,
                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, dialogue.is_self_initiated)
        else:
            self.context.logger.warning(
                "[{}]: did not receive transaction digest from sender={}.".
                format(self.context.agent_name, msg.counterparty[-5:]))
Example #30
0
    def _handle_inform(self, msg: FIPAMessage, 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 dialogue: the dialogue object
        :return: None
        """
        new_message_id = msg.message_id + 1
        new_target = msg.message_id
        self.context.logger.info("[{}]: received INFORM from sender={}".format(
            self.context.agent_name, msg.counterparty[-5:]))

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

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

                self.context.logger.info(
                    "[{}]: transaction={} settled, new balance={}. Sending data to sender={}"
                    .format(
                        self.context.agent_name,
                        tx_digest,
                        token_balance,
                        msg.counterparty[-5:],
                    ))
                inform_msg = FIPAMessage(
                    message_id=new_message_id,
                    dialogue_reference=dialogue.dialogue_label.
                    dialogue_reference,
                    target=new_target,
                    performative=FIPAMessage.Performative.INFORM,
                    info=dialogue.carpark_data,
                )
                dialogue.outgoing_extend(inform_msg)
                self.context.outbox.put_message(
                    to=msg.counterparty,
                    sender=self.context.agent_address,
                    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,
                    msg.counterparty[-5:],
                    self.context.agent_name,
                    total_price,
                )
                strategy.db.set_transaction_complete(tx_digest)
                strategy.db.set_dialogue_status(
                    str(dialogue.dialogue_label),
                    msg.counterparty[-5:],
                    "transaction_complete",
                    "send_request_data",
                )
            else:
                self.context.logger.info(
                    "[{}]: transaction={} not settled, aborting".format(
                        self.context.agent_name, tx_digest))
        else:
            self.context.logger.info(
                "[{}]: did not receive transaction digest from sender={}.".
                format(self.context.agent_name, msg.counterparty[-5:]))