コード例 #1
0
    def decode(self, obj: bytes) -> Message:
        """Decode bytes into a FIPA message."""
        fipa_pb = fipa_pb2.FIPAMessage()
        fipa_pb.ParseFromString(obj)
        message_id = fipa_pb.message_id
        dialogue_reference = (
            fipa_pb.dialogue_starter_reference,
            fipa_pb.dialogue_responder_reference,
        )
        target = fipa_pb.target

        performative = fipa_pb.WhichOneof("performative")
        performative_id = FIPAMessage.Performative(str(performative))
        performative_content = dict()
        if performative_id == FIPAMessage.Performative.CFP:
            query_type = fipa_pb.cfp.WhichOneof("query")
            if query_type == "nothing":
                query = None
            elif query_type == "query_bytes":
                query = pickle.loads(fipa_pb.cfp.query_bytes)  # nosec
            elif query_type == "bytes":
                query = fipa_pb.cfp.bytes
            else:
                raise ValueError("Query type not recognized.")  # pragma: no cover
            performative_content["query"] = query
        elif performative_id == FIPAMessage.Performative.PROPOSE:
            descriptions = []
            for p_bytes in fipa_pb.propose.proposal:
                p = pickle.loads(p_bytes)  # nosec
                p = cast(Description, p)
                descriptions.append(p)
            performative_content["proposal"] = descriptions
        elif performative_id == FIPAMessage.Performative.ACCEPT:
            pass
        elif performative_id == FIPAMessage.Performative.MATCH_ACCEPT:
            pass
        elif performative_id == FIPAMessage.Performative.ACCEPT_W_INFORM:
            info = pickle.loads(fipa_pb.accept_w_inform.bytes)  # nosec
            performative_content["info"] = info
        elif performative_id == FIPAMessage.Performative.MATCH_ACCEPT_W_INFORM:
            info = pickle.loads(fipa_pb.match_accept_w_inform.bytes)  # nosec
            performative_content["info"] = info
        elif performative_id == FIPAMessage.Performative.DECLINE:
            pass
        elif performative_id == FIPAMessage.Performative.INFORM:
            info = pickle.loads(fipa_pb.inform.bytes)  # nosec
            performative_content["info"] = info
        else:
            raise ValueError("Performative not valid: {}.".format(performative))

        return FIPAMessage(
            message_id=message_id,
            dialogue_reference=dialogue_reference,
            target=target,
            performative=performative,
            **performative_content
        )
コード例 #2
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, weather_data = strategy.generate_proposal_and_data(
                query, msg.counterparty)
            dialogue.weather_data = weather_data
            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),
            )
コード例 #3
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.counterparty = "a_counterparty"
     self.my_error_handler.handle(message=msg)
コード例 #4
0
def test_unknown_performative():
    """Test that we raise an exception when the performative is unknown during check_consistency."""
    msg = FIPAMessage(
        message_id=0,
        dialogue_reference=(str(0), ""),
        target=1,
        performative=FIPAMessage.Performative.ACCEPT,
    )
    with mock.patch.object(FIPAMessage.Performative, "__eq__", return_value=False):
        assert not msg._is_consistent()
コード例 #5
0
    def handle(self, message: Message) -> None:
        """
        Implement the reaction to a message.

        :param message: the message
        :return: None
        """
        # convenience representations
        fipa_msg = cast(FIPAMessage, message)
        msg_performative = FIPAMessage.Performative(
            message.get("performative"))

        # recover dialogue
        dialogues = cast(Dialogues, self.context.dialogues)
        if dialogues.is_belonging_to_registered_dialogue(
                fipa_msg, self.context.agent_address):
            dialogue = cast(
                Dialogue,
                dialogues.get_dialogue(fipa_msg, self.context.agent_address))
            dialogue.incoming_extend(fipa_msg)
        else:
            self._handle_unidentified_dialogue(fipa_msg)
            return

        # handle message
        if msg_performative == FIPAMessage.Performative.PROPOSE:
            self._handle_propose(fipa_msg, dialogue)
        elif msg_performative == FIPAMessage.Performative.DECLINE:
            self._handle_decline(fipa_msg, dialogue)
        elif msg_performative == FIPAMessage.Performative.MATCH_ACCEPT_W_INFORM:
            self._handle_match_accept(fipa_msg, dialogue)
        elif msg_performative == FIPAMessage.Performative.INFORM:
            self._handle_inform(fipa_msg, dialogue)
コード例 #6
0
ファイル: handlers.py プロジェクト: greencultureai/agents-aea
    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),
        )
コード例 #7
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
コード例 #8
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:]))
コード例 #9
0
 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
コード例 #10
0
 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
コード例 #11
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)
コード例 #12
0
 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
コード例 #13
0
 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
コード例 #14
0
ファイル: handlers.py プロジェクト: greencultureai/agents-aea
    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)
            )
コード例 #15
0
 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
コード例 #16
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()
コード例 #17
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")
コード例 #18
0
def test_performative_inform():
    """Test the serialization-deserialization of the inform performative."""
    msg = FIPAMessage(
        message_id=0,
        dialogue_reference=(str(0), ""),
        target=1,
        performative=FIPAMessage.Performative.INFORM,
        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")
コード例 #19
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")
コード例 #20
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
コード例 #21
0
ファイル: handlers.py プロジェクト: greencultureai/agents-aea
    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
                )
            )
コード例 #22
0
    def _handle_decline(self, msg: FIPAMessage, dialogue: Dialogue) -> None:
        """
        Handle the decline.

        :param msg: the message
        :param dialogue: the dialogue object
        :return: None
        """
        self.context.logger.info(
            "[{}]: received DECLINE from sender={}".format(
                self.context.agent_name, msg.counterparty[-5:]))
        target = msg.get("target")
        dialogues = cast(Dialogues, self.context.dialogues)
        if target == 1:
            dialogues.dialogue_stats.add_dialogue_endstate(
                Dialogue.EndState.DECLINED_CFP, dialogue.is_self_initiated)
        elif target == 3:
            dialogues.dialogue_stats.add_dialogue_endstate(
                Dialogue.EndState.DECLINED_ACCEPT, dialogue.is_self_initiated)
コード例 #23
0
    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
コード例 #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
コード例 #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
コード例 #26
0
    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
コード例 #27
0
    def test_dialogues_self_initiated_is_seller(self):
        """Test an end to end scenario of seller-client dialogue."""
        # Initialise a dialogue
        seller_dialogue = self.seller_dialogues.create_self_initiated(
            dialogue_opponent_addr=self.client_addr,
            dialogue_starter_addr=self.seller_addr,
            is_seller=True,
        )

        # Register the dialogue to the dictionary of dialogues.
        self.seller_dialogues.dialogues[seller_dialogue.dialogue_label] = cast(
            FIPADialogue, seller_dialogue
        )

        # Send a message to the client.
        cfp_msg = FIPAMessage(
            message_id=1,
            dialogue_reference=seller_dialogue.dialogue_label.dialogue_reference,
            target=0,
            performative=FIPAMessage.Performative.CFP,
            query=None,
        )
        cfp_msg.counterparty = self.seller_addr

        seller_dialogue.outgoing_extend(cfp_msg)

        # Creates a new dialogue for the client side based on the income message.
        client_dialogue = self.client_dialogues.create_opponent_initiated(
            dialogue_opponent_addr=cfp_msg.counterparty,
            dialogue_reference=cfp_msg.dialogue_reference,
            is_seller=False,
        )

        # Register the dialogue to the dictionary of dialogues.
        self.client_dialogues.dialogues[client_dialogue.dialogue_label] = cast(
            FIPADialogue, client_dialogue
        )

        # Extend the incoming list of messages.
        client_dialogue.incoming_extend(cfp_msg)

        # Checks if the message we received is permitted for a new dialogue or if it is a registered dialogue.
        assert self.client_dialogues.is_permitted_for_new_dialogue(
            client_dialogue.last_incoming_message
        ), "Should be permitted since the first incoming msg is CFP"

        # Generate a proposal message to send to the seller.
        proposal = [
            Description({"foo1": 1, "bar1": 2}),
            Description({"foo2": 1, "bar2": 2}),
        ]
        message_id = cfp_msg.message_id + 1
        target = cfp_msg.message_id
        proposal_msg = FIPAMessage(
            message_id=message_id,
            dialogue_reference=client_dialogue.dialogue_label.dialogue_reference,
            target=target,
            performative=FIPAMessage.Performative.PROPOSE,
            proposal=proposal,
        )
        proposal_msg.counterparty = self.client_addr

        # Extends the outgoing list of messages.
        client_dialogue.outgoing_extend(proposal_msg)

        # Seller received the message and we extend the incoming messages list.
        seller_dialogue.incoming_extend(proposal_msg)

        assert not self.seller_dialogues.is_permitted_for_new_dialogue(
            seller_dialogue.last_incoming_message
        ), "Should not be permitted since we registered the cfp message."

        response = self.seller_dialogues.is_belonging_to_registered_dialogue(
            proposal_msg, agent_addr=self.seller_addr
        )
        assert response, "We expect the response from the function to be true."

        # Test the self_initiated_dialogue explicitly
        message_id = proposal_msg.message_id + 1
        target = proposal_msg.message_id
        accept_msg = FIPAMessage(
            message_id=message_id,
            dialogue_reference=seller_dialogue.dialogue_label.dialogue_reference,
            target=target,
            performative=FIPAMessage.Performative.ACCEPT_W_INFORM,
            info={"address": "dummy_address"},
        )
        accept_msg.counterparty = self.client_addr

        # Adds the message to the client outgoing list.
        seller_dialogue.outgoing_extend(accept_msg)
        # Adds the message to the seller incoming message list.
        client_dialogue.incoming_extend(accept_msg)
        # Check if this message is registered to a dialogue.
        response = self.seller_dialogues.is_belonging_to_registered_dialogue(
            accept_msg, agent_addr=self.seller_addr
        )
        assert not response, "We expect the response from the function to be true."
コード例 #28
0
    def test_dialogues_self_initiated_no_seller(self):
        """Test an end to end scenario of client-seller dialogue."""
        # Initialise a dialogue
        client_dialogue = self.client_dialogues.create_self_initiated(
            dialogue_opponent_addr=self.seller_addr,
            dialogue_starter_addr=self.client_addr,
            is_seller=False,
        )

        # Register the dialogue to the dictionary of dialogues.
        self.client_dialogues.dialogues[client_dialogue.dialogue_label] = cast(
            FIPADialogue, client_dialogue
        )

        # Send a message to the seller.
        cfp_msg = FIPAMessage(
            message_id=1,
            dialogue_reference=client_dialogue.dialogue_label.dialogue_reference,
            target=0,
            performative=FIPAMessage.Performative.CFP,
            query=None,
        )
        cfp_msg.counterparty = self.client_addr

        # Checking that I cannot retrieve the dialogue.
        retrieved_dialogue = self.client_dialogues.is_belonging_to_registered_dialogue(
            cfp_msg, "client"
        )
        assert not retrieved_dialogue, "Should not belong to registered dialogue"

        # Checking the value error when we are trying to retrieve an un-existing dialogue.
        with pytest.raises(ValueError, match="Should have found dialogue."):
            self.client_dialogues.get_dialogue(cfp_msg, self.client_addr)

        # Extends the outgoing list of messages.
        client_dialogue.outgoing_extend(cfp_msg)

        # Creates a new dialogue for the seller side based on the income message.
        seller_dialogue = self.seller_dialogues.create_opponent_initiated(
            dialogue_opponent_addr=cfp_msg.counterparty,
            dialogue_reference=cfp_msg.dialogue_reference,
            is_seller=True,
        )

        # Register the dialogue to the dictionary of dialogues.
        self.seller_dialogues.dialogues[seller_dialogue.dialogue_label] = cast(
            FIPADialogue, seller_dialogue
        )

        # Extend the incoming list of messages.
        seller_dialogue.incoming_extend(cfp_msg)

        # Check that both fields in the dialogue_reference are set.
        last_msg = seller_dialogue.last_incoming_message
        assert last_msg == cfp_msg, "The messages must be equal"
        dialogue_reference = cast(
            Tuple[str, str], last_msg.body.get("dialogue_reference")
        )
        assert (
            dialogue_reference[0] != "" and dialogue_reference[1] == ""
        ), "The dialogue_reference is not set correctly."

        # Checks if the message we received is permitted for a new dialogue or if it is a registered dialogue.
        assert self.seller_dialogues.is_permitted_for_new_dialogue(
            seller_dialogue.last_incoming_message
        ), "Should be permitted since the first incoming msg is CFP"

        # Generate a proposal message to send to the client.
        proposal = [
            Description({"foo1": 1, "bar1": 2}),
            Description({"foo2": 1, "bar2": 2}),
        ]
        message_id = cfp_msg.message_id + 1
        target = cfp_msg.message_id
        proposal_msg = FIPAMessage(
            message_id=message_id,
            dialogue_reference=seller_dialogue.dialogue_label.dialogue_reference,
            target=target,
            performative=FIPAMessage.Performative.PROPOSE,
            proposal=proposal,
        )
        proposal_msg.counterparty = self.seller_addr

        # Extends the outgoing list of messages.
        seller_dialogue.outgoing_extend(proposal_msg)

        # Client received the message and we extend the incoming messages list.
        client_dialogue.incoming_extend(proposal_msg)

        # Check that both fields in the dialogue_reference are set.
        last_msg = client_dialogue.last_incoming_message
        assert last_msg == proposal_msg, "The two messages must be equal."
        dialogue_reference = cast(
            Tuple[str, str], last_msg.body.get("dialogue_reference")
        )
        assert (
            dialogue_reference[0] != "" and dialogue_reference[1] != ""
        ), "The dialogue_reference is not setup properly."

        assert not self.client_dialogues.is_permitted_for_new_dialogue(
            client_dialogue.last_incoming_message
        ), "Should not be permitted since we registered the cfp message."

        response = self.client_dialogues.is_belonging_to_registered_dialogue(
            proposal_msg, agent_addr=self.client_addr
        )
        assert response, "We expect the response from the function to be true."

        # Retrieve the dialogue based on the received message.
        retrieved_dialogue = self.client_dialogues.get_dialogue(
            proposal_msg, self.client_addr
        )
        assert retrieved_dialogue.dialogue_label is not None

        # Create an accept_w_inform message to send seller.
        message_id = proposal_msg.message_id + 1
        target = proposal_msg.message_id
        accept_msg = FIPAMessage(
            message_id=message_id,
            dialogue_reference=client_dialogue.dialogue_label.dialogue_reference,
            target=target,
            performative=FIPAMessage.Performative.ACCEPT_W_INFORM,
            info={"address": "dummy_address"},
        )
        accept_msg.counterparty = self.client_addr

        # Adds the message to the client outgoing list.
        client_dialogue.outgoing_extend(accept_msg)
        # Adds the message to the seller incoming message list.
        seller_dialogue.incoming_extend(accept_msg)
        # Check if this message is registered to a dialogue.
        response = self.seller_dialogues.is_belonging_to_registered_dialogue(
            accept_msg, agent_addr=self.seller_addr
        )
        assert response, "We expect the response from the function to be true."

        retrieved_dialogue = self.seller_dialogues.get_dialogue(
            accept_msg, self.seller_addr
        )
        assert retrieved_dialogue.dialogue_label in self.seller_dialogues.dialogues
コード例 #29
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()
コード例 #30
0
ファイル: handlers.py プロジェクト: greencultureai/agents-aea
    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:]))