Beispiel #1
0
def test_performative_match_accept():
    """Test the serialization - deserialization of the match_accept performative."""
    msg = FipaMessage(
        message_id=1,
        dialogue_reference=(str(0), ""),
        target=0,
        performative=FipaMessage.Performative.MATCH_ACCEPT,
    )
    msg.counterparty = "receiver"
    envelope = Envelope(
        to="receiver",
        sender="sender",
        protocol_id=FipaMessage.protocol_id,
        message=msg,
    )
    msg.counterparty = "receiver"
    envelope_bytes = envelope.encode()

    actual_envelope = Envelope.decode(envelope_bytes)
    expected_envelope = envelope
    assert expected_envelope.to == actual_envelope.to
    assert expected_envelope.sender == actual_envelope.sender
    assert expected_envelope.protocol_id == actual_envelope.protocol_id
    assert expected_envelope.message != actual_envelope.message

    actual_msg = FipaMessage.serializer.decode(actual_envelope.message)
    actual_msg.counterparty = actual_envelope.to
    expected_msg = msg
    assert expected_msg == actual_msg
Beispiel #2
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
        proposal = msg.proposal
        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,
            )
            accept_msg.counterparty = msg.counterparty
            dialogue.update(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,
            )
            decline_msg.counterparty = msg.counterparty
            dialogue.update(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),
            )
Beispiel #3
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, temp_data = strategy.generate_proposal_and_data(
                query, msg.counterparty)
            dialogue.temp_data = temp_data
            dialogue.proposal = proposal
            self.context.logger.info(
                "[{}]: sending a PROPOSE with proposal={} to sender={}".format(
                    self.context.agent_name, proposal.values,
                    msg.counterparty[-5:]))
            proposal_msg = FipaMessage(
                message_id=new_message_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=new_target,
                performative=FipaMessage.Performative.PROPOSE,
                proposal=proposal,
            )
            proposal_msg.counterparty = msg.counterparty
            dialogue.update(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,
            )
            decline_msg.counterparty = msg.counterparty
            dialogue.update(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),
            )
Beispiel #4
0
    def _handle_propose(
        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue
    ) -> None:
        """
        Handle the propose.

        :param fipa_msg: the message
        :param fipa_dialogue: the dialogue object
        :return: None
        """
        self.context.logger.info(
            "received proposal={} from sender={}".format(
                fipa_msg.proposal.values, fipa_msg.counterparty[-5:],
            )
        )
        strategy = cast(GenericStrategy, self.context.strategy)
        acceptable = strategy.is_acceptable_proposal(fipa_msg.proposal)
        affordable = strategy.is_affordable_proposal(fipa_msg.proposal)
        if acceptable and affordable:
            self.context.logger.info(
                "accepting the proposal from sender={}".format(
                    fipa_msg.counterparty[-5:]
                )
            )
            terms = strategy.terms_from_proposal(
                fipa_msg.proposal, fipa_msg.counterparty
            )
            fipa_dialogue.terms = terms
            accept_msg = FipaMessage(
                message_id=fipa_msg.message_id + 1,
                dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference,
                target=fipa_msg.message_id,
                performative=FipaMessage.Performative.ACCEPT,
            )
            accept_msg.counterparty = fipa_msg.counterparty
            fipa_dialogue.update(accept_msg)
            self.context.outbox.put_message(message=accept_msg)
        else:
            self.context.logger.info(
                "declining the proposal from sender={}".format(
                    fipa_msg.counterparty[-5:]
                )
            )
            decline_msg = FipaMessage(
                message_id=fipa_msg.message_id + 1,
                dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference,
                target=fipa_msg.message_id,
                performative=FipaMessage.Performative.DECLINE,
            )
            decline_msg.counterparty = fipa_msg.counterparty
            fipa_dialogue.update(decline_msg)
            self.context.outbox.put_message(message=decline_msg)
Beispiel #5
0
    def _handle_cfp(self, fipa_msg: FipaMessage,
                    fipa_dialogue: FipaDialogue) -> None:
        """
        Handle the CFP.

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

        :param fipa_msg: the message
        :param fipa_dialogue: the dialogue object
        :return: None
        """
        self.context.logger.info("[{}]: received CFP from sender={}".format(
            self.context.agent_name, fipa_msg.counterparty[-5:]))
        strategy = cast(GenericStrategy, self.context.strategy)
        if strategy.is_matching_supply(fipa_msg.query):
            proposal, terms, data_for_sale = strategy.generate_proposal_terms_and_data(
                fipa_msg.query, fipa_msg.counterparty)
            fipa_dialogue.data_for_sale = data_for_sale
            fipa_dialogue.terms = terms
            self.context.logger.info(
                "[{}]: sending a PROPOSE with proposal={} to sender={}".format(
                    self.context.agent_name, proposal.values,
                    fipa_msg.counterparty[-5:]))
            proposal_msg = FipaMessage(
                performative=FipaMessage.Performative.PROPOSE,
                message_id=fipa_msg.message_id + 1,
                dialogue_reference=fipa_dialogue.dialogue_label.
                dialogue_reference,
                target=fipa_msg.message_id,
                proposal=proposal,
            )
            proposal_msg.counterparty = fipa_msg.counterparty
            fipa_dialogue.update(proposal_msg)
            self.context.outbox.put_message(message=proposal_msg)
        else:
            self.context.logger.info(
                "[{}]: declined the CFP from sender={}".format(
                    self.context.agent_name, fipa_msg.counterparty[-5:]))
            decline_msg = FipaMessage(
                message_id=fipa_msg.message_id + 1,
                dialogue_reference=fipa_dialogue.dialogue_label.
                dialogue_reference,
                target=fipa_msg.message_id,
                performative=FipaMessage.Performative.DECLINE,
            )
            decline_msg.counterparty = fipa_msg.counterparty
            fipa_dialogue.update(decline_msg)
            self.context.outbox.put_message(message=decline_msg)
Beispiel #6
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)
            tx_msg = TransactionMessage(
                performative=TransactionMessage.Performative.
                PROPOSE_FOR_SETTLEMENT,
                skill_callback_ids=[self.context.skill_id],
                tx_id="transaction0",
                tx_sender_addr=self.context.agent_addresses[
                    proposal.values["ledger_id"]],
                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},
                tx_nonce=proposal.values["tx_nonce"],
            )
            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"},
            )
            inform_msg.counterparty = msg.counterparty
            dialogue.update(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:]))
Beispiel #7
0
    def _handle_transaction_digest(
            self, ledger_api_msg: LedgerApiMessage,
            ledger_api_dialogue: LedgerApiDialogue) -> None:
        """
        Handle a message of transaction_digest performative.

        :param ledger_api_message: the ledger api message
        :param ledger_api_dialogue: the ledger api dialogue
        """
        fipa_dialogue = ledger_api_dialogue.associated_fipa_dialogue
        self.context.logger.info(
            "transaction was successfully submitted. Transaction digest={}".
            format(ledger_api_msg.transaction_digest))
        fipa_msg = cast(Optional[FipaMessage],
                        fipa_dialogue.last_incoming_message)
        assert fipa_msg is not None, "Could not retrieve fipa message"
        inform_msg = FipaMessage(
            performative=FipaMessage.Performative.INFORM,
            message_id=fipa_msg.message_id + 1,
            dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference,
            target=fipa_msg.message_id,
            info={
                "transaction_digest": ledger_api_msg.transaction_digest.body
            },
        )
        inform_msg.counterparty = fipa_dialogue.dialogue_label.dialogue_opponent_addr
        fipa_dialogue.update(inform_msg)
        self.context.outbox.put_message(message=inform_msg)
        self.context.logger.info(
            "informing counterparty={} of transaction digest.".format(
                fipa_dialogue.dialogue_label.dialogue_opponent_addr[-5:], ))
Beispiel #8
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]},
        )
        match_accept_msg.counterparty = msg.counterparty
        dialogue.update(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),
        )
Beispiel #9
0
def test_fipa_propose_serialization():
    """Test that the serialization for the 'fipa' protocol works."""
    proposal = Description({"foo1": 1, "bar1": 2})
    msg = FipaMessage(
        message_id=1,
        dialogue_reference=(str(0), ""),
        target=0,
        performative=FipaMessage.Performative.PROPOSE,
        proposal=proposal,
    )
    msg.counterparty = "receiver"
    envelope = Envelope(
        to="receiver",
        sender="sender",
        protocol_id=FipaMessage.protocol_id,
        message=msg,
    )
    envelope_bytes = envelope.encode()

    actual_envelope = Envelope.decode(envelope_bytes)
    expected_envelope = envelope
    assert expected_envelope.to == actual_envelope.to
    assert expected_envelope.sender == actual_envelope.sender
    assert expected_envelope.protocol_id == actual_envelope.protocol_id
    assert expected_envelope.message != actual_envelope.message

    actual_msg = FipaMessage.serializer.decode(actual_envelope.message)
    actual_msg.counterparty = actual_envelope.to
    expected_msg = msg
    assert expected_msg == actual_msg
Beispiel #10
0
    def _handle_search(self, oef_search_msg: OefSearchMessage,
                       oef_search_dialogue: OefSearchDialogue) -> None:
        """
        Handle the search response.

        :param agents: the agents returned by the search
        :return: None
        """
        if len(oef_search_msg.agents) == 0:
            self.context.logger.info(
                "[{}]: found no agents, continue searching.".format(
                    self.context.agent_name))
            return

        self.context.logger.info(
            "[{}]: found agents={}, stopping search.".format(
                self.context.agent_name,
                list(map(lambda x: x[-5:], oef_search_msg.agents)),
            ))
        strategy = cast(Strategy, self.context.strategy)
        strategy.is_searching = False
        query = strategy.get_service_query()
        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
        for opponent_address in oef_search_msg.agents:
            cfp_msg = FipaMessage(
                dialogue_reference=fipa_dialogues.
                new_self_initiated_dialogue_reference(),
                performative=FipaMessage.Performative.CFP,
                query=query,
            )
            cfp_msg.counterparty = opponent_address
            fipa_dialogues.update(cfp_msg)
            self.context.logger.info("[{}]: sending CFP to agent={}".format(
                self.context.agent_name, opponent_address[-5:]))
            self.context.outbox.put_message(message=cfp_msg)
Beispiel #11
0
    def _handle_signed_message(self, signing_msg: SigningMessage,
                               signing_dialogue: SigningDialogue) -> None:
        """
        Handle a signed message.

        :param signing_msg: the signing message
        :param signing_dialogue: the dialogue
        :return: None
        """
        fipa_dialogue = (signing_dialogue.associated_contract_api_dialogue.
                         associated_fipa_dialogue)
        last_fipa_msg = fipa_dialogue.last_incoming_message
        assert last_fipa_msg is not None, "Could not retrieve last fipa message."
        inform_msg = FipaMessage(
            message_id=last_fipa_msg.message_id + 1,
            dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference,
            target=last_fipa_msg.message_id,
            performative=FipaMessage.Performative.ACCEPT_W_INFORM,
            info={"tx_signature": signing_msg.signed_message.body},
        )
        inform_msg.counterparty = last_fipa_msg.counterparty
        self.context.logger.info(
            "[{}]: sending ACCEPT_W_INFORM to agent={}: tx_signature={}".
            format(
                self.context.agent_name,
                last_fipa_msg.counterparty[-5:],
                signing_msg.signed_message,
            ))
        self.context.outbox.put_message(message=inform_msg)
Beispiel #12
0
    def _handle_accept(self, fipa_msg: FipaMessage,
                       fipa_dialogue: FipaDialogue) -> None:
        """
        Handle the ACCEPT.

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

        :param fipa_msg: the message
        :param fipa_dialogue: the dialogue object
        :return: None
        """
        self.context.logger.info("[{}]: received ACCEPT from sender={}".format(
            self.context.agent_name, fipa_msg.counterparty[-5:]))
        match_accept_msg = FipaMessage(
            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,
            message_id=fipa_msg.message_id + 1,
            dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference,
            target=fipa_msg.message_id,
            info={"address": fipa_dialogue.terms.sender_address},
        )
        self.context.logger.info(
            "[{}]: sending MATCH_ACCEPT_W_INFORM to sender={} with info={}".
            format(
                self.context.agent_name,
                fipa_msg.counterparty[-5:],
                match_accept_msg.info,
            ))
        match_accept_msg.counterparty = fipa_msg.counterparty
        fipa_dialogue.update(match_accept_msg)
        self.context.outbox.put_message(message=match_accept_msg)
Beispiel #13
0
    def _handle_search(self, oef_search_msg: OefSearchMessage,
                       oef_search_dialogue: OefSearchDialogue) -> None:
        """
        Handle the search response.

        :param agents: the agents returned by the search
        :return: None
        """
        if len(oef_search_msg.agents) == 0:
            self.context.logger.info("found no agents, continue searching.")
            return

        self.context.logger.info("found agents={}, stopping search.".format(
            list(map(lambda x: x[-5:], oef_search_msg.agents)), ))
        strategy = cast(GenericStrategy, self.context.strategy)
        strategy.is_searching = False  # stopping search
        query = strategy.get_service_query()
        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
        for idx, counterparty in enumerate(oef_search_msg.agents):
            if idx >= strategy.max_negotiations:
                continue
            cfp_msg = FipaMessage(
                performative=FipaMessage.Performative.CFP,
                dialogue_reference=fipa_dialogues.
                new_self_initiated_dialogue_reference(),
                query=query,
            )
            cfp_msg.counterparty = counterparty
            fipa_dialogues.update(cfp_msg)
            self.context.outbox.put_message(message=cfp_msg)
            self.context.logger.info("sending CFP to agent={}".format(
                counterparty[-5:]))
Beispiel #14
0
def test_performative_accept_with_inform():
    """Test the serialization - deserialization of the accept_with_address performative."""
    msg = FipaMessage(
        message_id=1,
        dialogue_reference=(str(0), ""),
        target=0,
        performative=FipaMessage.Performative.ACCEPT_W_INFORM,
        info={"address": "dummy_address"},
    )
    msg.counterparty = "receiver"
    envelope = Envelope(
        to="receiver",
        sender="sender",
        protocol_id=FipaMessage.protocol_id,
        message=msg,
    )
    envelope_bytes = envelope.encode()

    actual_envelope = Envelope.decode(envelope_bytes)
    expected_envelope = envelope
    assert expected_envelope.to == actual_envelope.to
    assert expected_envelope.sender == actual_envelope.sender
    assert expected_envelope.protocol_id == actual_envelope.protocol_id
    assert expected_envelope.message != actual_envelope.message

    actual_msg = FipaMessage.serializer.decode(actual_envelope.message)
    actual_msg.counterparty = actual_envelope.to
    expected_msg = msg
    assert expected_msg == actual_msg
Beispiel #15
0
    def test_error_decoding_error(self):
        """Test the decoding error."""
        self.my_aea._inbox._history = []
        msg = FipaMessage(
            message_id=1,
            dialogue_reference=(str(0), ""),
            target=0,
            performative=FipaMessage.Performative.ACCEPT,
        )
        msg.counterparty = self.address
        envelope = Envelope(
            to=self.address,
            sender=self.address,
            protocol_id=DefaultMessage.protocol_id,
            message=msg,
        )

        self.my_error_handler.send_decoding_error(envelope)
        wait_for_condition(lambda: len(self.my_aea._inbox._history) >= 1,
                           timeout=5)
        envelope = self.my_aea._inbox._history[-1]

        msg = envelope.message
        assert msg.performative == DefaultMessage.Performative.ERROR
        assert msg.error_code == DefaultMessage.ErrorCode.DECODING_ERROR
Beispiel #16
0
def test_fipa_accept_serialization():
    """Test that the serialization for the 'fipa' protocol works."""
    msg = FipaMessage(
        message_id=1,
        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
Beispiel #17
0
    def test_error_unsupported_skill(self):
        """Test the unsupported skill."""
        msg = FipaMessage(
            message_id=1,
            dialogue_reference=(str(0), ""),
            target=0,
            performative=FipaMessage.Performative.ACCEPT,
        )
        msg.counterparty = self.address
        msg.sender = self.address
        envelope = Envelope(
            to=msg.counterparty,
            sender=msg.sender,
            protocol_id=msg.protocol_id,
            message=msg,
        )

        self.my_error_handler.send_unsupported_skill(envelope=envelope)

        wait_for_condition(lambda: len(self.my_aea._inbox._history) >= 1,
                           timeout=5)
        envelope = self.my_aea._inbox._history[-1]

        msg = envelope.message
        assert msg.performative == DefaultMessage.Performative.ERROR
        assert msg.error_code == DefaultMessage.ErrorCode.UNSUPPORTED_SKILL
Beispiel #18
0
def test_fipa_cfp_serialization_bytes():
    """Test that the serialization - deserialization for the 'fipa' protocol works."""
    query = Query([Constraint("something", ConstraintType(">", 1))])
    msg = FipaMessage(
        message_id=1,
        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")
Beispiel #19
0
    def _on_propose(self, propose: FipaMessage, dialogue: Dialogue) -> None:
        """
        Handle a Propose.

        :param propose: the message containing the Propose
        :param dialogue: the dialogue
        :return: None
        """
        new_msg_id = propose.message_id + 1
        strategy = cast(Strategy, self.context.strategy)
        proposal_description = propose.proposal
        self.context.logger.debug("[{}]: on Propose as {}.".format(
            self.context.agent_name, dialogue.role))
        transactions = cast(Transactions, self.context.transactions)
        transaction_msg = transactions.generate_transaction_message(
            TransactionMessage.Performative.PROPOSE_FOR_SIGNING,
            proposal_description,
            dialogue.dialogue_label,
            cast(Dialogue.AgentRole, dialogue.role),
            self.context.agent_address,
        )

        if strategy.is_profitable_transaction(transaction_msg,
                                              role=cast(
                                                  Dialogue.AgentRole,
                                                  dialogue.role)):
            self.context.logger.info("[{}]: Accepting propose (as {}).".format(
                self.context.agent_name, dialogue.role))
            transactions.add_locked_tx(transaction_msg,
                                       role=cast(Dialogue.AgentRole,
                                                 dialogue.role))
            transactions.add_pending_initial_acceptance(
                dialogue.dialogue_label, new_msg_id, transaction_msg)
            fipa_msg = FipaMessage(
                performative=FipaMessage.Performative.ACCEPT,
                message_id=new_msg_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=propose.message_id,
            )
        else:
            self.context.logger.info("[{}]: Declining propose (as {})".format(
                self.context.agent_name, dialogue.role))
            fipa_msg = FipaMessage(
                performative=FipaMessage.Performative.DECLINE,
                message_id=new_msg_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=propose.message_id,
            )
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogues.dialogue_stats.add_dialogue_endstate(
                Dialogue.EndState.DECLINED_PROPOSE, dialogue.is_self_initiated)
        fipa_msg.counterparty = propose.counterparty
        dialogue.update(fipa_msg)
        self.context.outbox.put_message(
            to=dialogue.dialogue_label.dialogue_opponent_addr,
            sender=self.context.agent_address,
            protocol_id=FipaMessage.protocol_id,
            message=FipaSerializer().encode(fipa_msg),
        )
Beispiel #20
0
    def test_propose(self):
        """Test that a Propose can be sent correctly."""
        propose_empty = FipaMessage(
            message_id=1,
            dialogue_reference=(str(0), ""),
            target=0,
            performative=FipaMessage.Performative.PROPOSE,
            proposal=Description({"foo": "bar"}),
        )
        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=1,
            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
Beispiel #21
0
    def _on_propose(self, propose: FipaMessage,
                    fipa_dialogue: FipaDialogue) -> None:
        """
        Handle a Propose.

        :param propose: the message containing the Propose
        :param fipa_dialogue: the fipa_dialogue
        :return: None
        """
        new_msg_id = propose.message_id + 1
        strategy = cast(Strategy, self.context.strategy)
        proposal_description = propose.proposal
        self.context.logger.debug("on Propose as {}.".format(
            fipa_dialogue.role))
        transactions = cast(Transactions, self.context.transactions)
        signing_msg = transactions.generate_signing_message(
            SigningMessage.Performative.SIGN_MESSAGE,
            proposal_description,
            fipa_dialogue.dialogue_label,
            cast(FipaDialogue.Role, fipa_dialogue.role),
            self.context.agent_address,
        )

        if strategy.is_profitable_transaction(signing_msg,
                                              role=cast(
                                                  FipaDialogue.Role,
                                                  fipa_dialogue.role)):
            self.context.logger.info("accepting propose (as {}).".format(
                fipa_dialogue.role))
            transactions.add_locked_tx(signing_msg,
                                       role=cast(FipaDialogue.Role,
                                                 fipa_dialogue.role))
            transactions.add_pending_initial_acceptance(
                fipa_dialogue.dialogue_label, new_msg_id, signing_msg)
            fipa_msg = FipaMessage(
                performative=FipaMessage.Performative.ACCEPT,
                message_id=new_msg_id,
                dialogue_reference=fipa_dialogue.dialogue_label.
                dialogue_reference,
                target=propose.message_id,
            )
        else:
            self.context.logger.info("declining propose (as {})".format(
                fipa_dialogue.role))
            fipa_msg = FipaMessage(
                performative=FipaMessage.Performative.DECLINE,
                message_id=new_msg_id,
                dialogue_reference=fipa_dialogue.dialogue_label.
                dialogue_reference,
                target=propose.message_id,
            )
            fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
            fipa_dialogues.dialogue_stats.add_dialogue_endstate(
                FipaDialogue.EndState.DECLINED_PROPOSE,
                fipa_dialogue.is_self_initiated)
        fipa_msg.counterparty = propose.counterparty
        fipa_dialogue.update(fipa_msg)
        self.context.outbox.put_message(message=fipa_msg)
Beispiel #22
0
    def _handle_match_accept(
        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue
    ) -> None:
        """
        Handle the match accept.

        :param fipa_msg: the message
        :param fipa_dialogue: the dialogue object
        :return: None
        """
        self.context.logger.info(
            "received MATCH_ACCEPT_W_INFORM from sender={} with info={}".format(
                fipa_msg.counterparty[-5:], fipa_msg.info
            )
        )
        strategy = cast(GenericStrategy, self.context.strategy)
        if strategy.is_ledger_tx:
            transfer_address = fipa_msg.info.get("address", None)
            if transfer_address is not None and isinstance(transfer_address, str):
                fipa_dialogue.terms.counterparty_address = transfer_address
            ledger_api_dialogues = cast(
                LedgerApiDialogues, self.context.ledger_api_dialogues
            )
            ledger_api_msg = LedgerApiMessage(
                performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION,
                dialogue_reference=ledger_api_dialogues.new_self_initiated_dialogue_reference(),
                terms=fipa_dialogue.terms,
            )
            ledger_api_msg.counterparty = LEDGER_API_ADDRESS
            ledger_api_dialogue = cast(
                Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)
            )
            assert (
                ledger_api_dialogue is not None
            ), "Error when creating ledger api dialogue."
            ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue
            fipa_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue
            self.context.outbox.put_message(message=ledger_api_msg)
            self.context.logger.info(
                "requesting transfer transaction from ledger api..."
            )
        else:
            inform_msg = FipaMessage(
                message_id=fipa_msg.message_id + 1,
                dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference,
                target=fipa_msg.message_id,
                performative=FipaMessage.Performative.INFORM,
                info={"Done": "Sending payment via bank transfer"},
            )
            inform_msg.counterparty = fipa_msg.counterparty
            fipa_dialogue.update(inform_msg)
            self.context.outbox.put_message(message=inform_msg)
            self.context.logger.info(
                "informing counterparty={} of payment.".format(
                    fipa_msg.counterparty[-5:]
                )
            )
Beispiel #23
0
    def test_cfp(self):
        """Test that a CFP can be sent correctly."""
        cfp_message = FipaMessage(
            message_id=1,
            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=1,
            dialogue_reference=(str(0), ""),
            target=0,
            performative=FipaMessage.Performative.CFP,
            query=Query([Constraint("something", ConstraintType(">", 1))]),
        )
        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
Beispiel #24
0
 def test_error_handler_handle(self):
     """Test the handle function."""
     msg = FipaMessage(
         message_id=1,
         dialogue_reference=(str(0), ""),
         target=0,
         performative=FipaMessage.Performative.ACCEPT,
     )
     msg.counterparty = "a_counterparty"
     self.my_error_handler.handle(message=msg)
Beispiel #25
0
    def _on_accept(self, accept: FipaMessage, dialogue: Dialogue) -> None:
        """
        Handle an Accept.

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

        if strategy.is_profitable_transaction(transaction_msg,
                                              role=cast(
                                                  Dialogue.AgentRole,
                                                  dialogue.role)):
            self.context.logger.info(
                "[{}]: locking the current state (as {}).".format(
                    self.context.agent_name, dialogue.role))
            transactions.add_locked_tx(transaction_msg,
                                       role=cast(Dialogue.AgentRole,
                                                 dialogue.role))
            self.context.decision_maker_message_queue.put(transaction_msg)
        else:
            self.context.logger.debug(
                "[{}]: decline the Accept (as {}).".format(
                    self.context.agent_name, dialogue.role))
            fipa_msg = FipaMessage(
                performative=FipaMessage.Performative.DECLINE,
                message_id=new_msg_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=accept.message_id,
            )
            fipa_msg.counterparty = accept.counterparty
            dialogue.update(fipa_msg)
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogues.dialogue_stats.add_dialogue_endstate(
                Dialogue.EndState.DECLINED_ACCEPT, dialogue.is_self_initiated)
            self.context.outbox.put_message(
                to=dialogue.dialogue_label.dialogue_opponent_addr,
                sender=self.context.agent_address,
                protocol_id=FipaMessage.protocol_id,
                message=FipaSerializer().encode(fipa_msg),
            )
Beispiel #26
0
    async def test_messages(self):
        """Test that at the beginning, the search request returns an empty search result."""
        msg = FipaMessage(
            performative=FipaMessage.Performative.CFP,
            dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
            query=Query([Constraint("something", ConstraintType(">", 1))]),
        )
        msg.counterparty = str(OEFLocalConnection.connection_id)
        sending_dialogue = cast(Optional[FipaDialogue], self.dialogues.update(msg))
        assert sending_dialogue is not None
        envelope = Envelope(
            to=msg.counterparty,
            sender=msg.sender,
            protocol_id=msg.protocol_id,
            message=msg,
        )
        with pytest.raises(AEAConnectionError):
            await _make_local_connection(self.address_1, self.node,).send(envelope)

        self.multiplexer1.connect()
        msg = FipaMessage(
            performative=FipaMessage.Performative.CFP,
            dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
            query=Query([Constraint("something", ConstraintType(">", 1))]),
        )
        msg.counterparty = "this_address_does_not_exist"
        sending_dialogue = cast(Optional[FipaDialogue], self.dialogues.update(msg))
        assert sending_dialogue is not None
        envelope = Envelope(
            to=msg.counterparty,
            sender=msg.sender,
            protocol_id=msg.protocol_id,
            message=msg,
        )
        self.multiplexer1.put(envelope)

        # check the result
        response_envelope = self.multiplexer1.get(block=True, timeout=5.0)
        assert response_envelope.protocol_id == DefaultMessage.protocol_id
        assert response_envelope.sender == str(OEFLocalConnection.connection_id)
        result = response_envelope.message
        assert result.performative == DefaultMessage.Performative.ERROR
Beispiel #27
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:]))
        if self.context.behaviours.service_registration.is_items_minted:
            # simply send the same proposal, independent of the query
            strategy = cast(Strategy, self.context.strategy)
            contract = cast(ERC1155Contract, self.context.contracts.erc1155)
            trade_nonce = contract.generate_trade_nonce(
                self.context.agent_address)
            token_id = self.context.behaviours.service_registration.token_ids[
                0]
            proposal = Description({
                "contract_address": contract.instance.address,
                "token_id": str(token_id),
                "trade_nonce": str(trade_nonce),
                "from_supply": str(strategy.from_supply),
                "to_supply": str(strategy.to_supply),
                "value": str(strategy.value),
            })
            dialogue.proposal = proposal
            proposal_msg = FipaMessage(
                message_id=new_message_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=new_target,
                performative=FipaMessage.Performative.PROPOSE,
                proposal=proposal,
            )
            proposal_msg.counterparty = msg.counterparty
            dialogue.update(proposal_msg)
            self.context.logger.info(
                "[{}]: Sending PROPOSE to agent={}: proposal={}".format(
                    self.context.agent_name, msg.counterparty[-5:],
                    proposal.values))
            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(
                "Contract items not minted yet. Try again later.")
Beispiel #28
0
    def _handle_transaction_receipt(
            self, ledger_api_msg: LedgerApiMessage,
            ledger_api_dialogue: LedgerApiDialogue) -> None:
        """
        Handle a message of balance performative.

        :param ledger_api_message: the ledger api message
        :param ledger_api_dialogue: the ledger api dialogue
        """
        fipa_dialogue = ledger_api_dialogue.associated_fipa_dialogue
        is_settled = LedgerApis.is_transaction_settled(
            fipa_dialogue.terms.ledger_id,
            ledger_api_msg.transaction_receipt.receipt)
        is_valid = LedgerApis.is_transaction_valid(
            fipa_dialogue.terms.ledger_id,
            ledger_api_msg.transaction_receipt.transaction,
            fipa_dialogue.terms.sender_address,
            fipa_dialogue.terms.counterparty_address,
            fipa_dialogue.terms.nonce,
            fipa_dialogue.terms.counterparty_payable_amount,
        )
        if is_settled and is_valid:
            last_message = cast(Optional[FipaMessage],
                                fipa_dialogue.last_incoming_message)
            assert last_message is not None, "Cannot retrieve last fipa message."
            inform_msg = FipaMessage(
                message_id=last_message.message_id + 1,
                dialogue_reference=fipa_dialogue.dialogue_label.
                dialogue_reference,
                target=last_message.message_id,
                performative=FipaMessage.Performative.INFORM,
                info=fipa_dialogue.data_for_sale,
            )
            inform_msg.counterparty = last_message.counterparty
            fipa_dialogue.update(inform_msg)
            self.context.outbox.put_message(message=inform_msg)
            fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
            fipa_dialogues.dialogue_stats.add_dialogue_endstate(
                FipaDialogue.EndState.SUCCESSFUL,
                fipa_dialogue.is_self_initiated)
            self.context.logger.info(
                "[{}]: transaction confirmed, sending data={} to buyer={}.".
                format(
                    self.context.agent_name,
                    fipa_dialogue.data_for_sale,
                    last_message.counterparty[-5:],
                ))
        else:
            self.context.logger.info(
                "[{}]: transaction_receipt={} not settled or not valid, aborting"
                .format(self.context.agent_name,
                        ledger_api_msg.transaction_receipt))
Beispiel #29
0
    def _handle_search(self, agents: Tuple[str, ...]) -> None:
        """
        Handle the search response.

        :param agents: the agents returned by the search
        :return: None
        """
        strategy = cast(Strategy, self.context.strategy)
        if len(agents) > 0:
            strategy.on_search_success()

            self.context.logger.info(
                "[{}]: found agents={}, stopping search.".format(
                    self.context.agent_name, list(map(lambda x: x[-5:], agents))
                )
            )

            # pick first agent found
            opponent_addr = agents[0]
            dialogues = cast(Dialogues, self.context.dialogues)
            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=Dialogue.STARTING_MESSAGE_ID,
                dialogue_reference=dialogues.new_self_initiated_dialogue_reference(),
                performative=FipaMessage.Performative.CFP,
                target=Dialogue.STARTING_TARGET,
                query=query,
            )
            cfp_msg.counterparty = opponent_addr
            dialogues.update(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
                )
            )
            strategy.on_search_failed()
Beispiel #30
0
    def _handle_search(self, agents: Tuple[str, ...], search_id: int,
                       is_searching_for_sellers: bool) -> None:
        """
        Handle the search response.

        :param agents: the agents returned by the search
        :param is_searching_for_sellers: whether the agent is searching for sellers
        :return: None
        """
        searched_for = "sellers" if is_searching_for_sellers else "buyers"
        if len(agents) > 0:
            self.context.logger.info(
                "[{}]: found potential {} agents={} on search_id={}.".format(
                    self.context.agent_name,
                    searched_for,
                    list(map(lambda x: x[-5:], agents)),
                    search_id,
                ))
            strategy = cast(Strategy, self.context.strategy)
            dialogues = cast(Dialogues, self.context.dialogues)
            query = strategy.get_own_services_query(is_searching_for_sellers,
                                                    is_search_query=False)

            for opponent_addr in agents:
                self.context.logger.info(
                    "[{}]: sending CFP to agent={}".format(
                        self.context.agent_name, opponent_addr[-5:]))
                fipa_msg = FipaMessage(
                    message_id=Dialogue.STARTING_MESSAGE_ID,
                    dialogue_reference=dialogues.
                    new_self_initiated_dialogue_reference(),
                    performative=FipaMessage.Performative.CFP,
                    target=Dialogue.STARTING_TARGET,
                    query=query,
                )
                fipa_msg.counterparty = opponent_addr
                dialogues.update(fipa_msg)
                self.context.outbox.put_message(
                    to=opponent_addr,
                    sender=self.context.agent_address,
                    protocol_id=FipaMessage.protocol_id,
                    message=FipaSerializer().encode(fipa_msg),
                )
        else:
            self.context.logger.info(
                "[{}]: found no {} agents on search_id={}, continue searching."
                .format(self.context.agent_name, searched_for, search_id))