Beispiel #1
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 #2
0
def test_end_serialization():
    """Test the serialization-deserialization of the end performative."""
    msg = FipaMessage(
        message_id=1,
        dialogue_reference=(str(0), ""),
        target=0,
        performative=FipaMessage.Performative.END,
    )
    msg.to = "receiver"
    envelope = Envelope(
        to=msg.to,
        sender="sender",
        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_specification_id ==
            actual_envelope.protocol_specification_id)
    assert expected_envelope.message != actual_envelope.message

    actual_msg = FipaMessage.serializer.decode(actual_envelope.message)
    actual_msg.to = actual_envelope.to
    actual_msg.sender = actual_envelope.sender
    expected_msg = msg
    assert expected_msg == actual_msg
Beispiel #3
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 #4
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 #5
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 #6
0
def test_cfp_serialization():
    """Test that the serialization for the 'fipa' protocol works."""
    msg = FipaMessage(
        message_id=1,
        dialogue_reference=(str(0), ""),
        target=0,
        performative=FipaMessage.Performative.CFP,
        query=Query([Constraint("something", ConstraintType(">", 1))]),
    )
    msg.to = "receiver"
    envelope = Envelope(
        to=msg.to,
        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.to = actual_envelope.to
    actual_msg.sender = actual_envelope.sender
    expected_msg = msg
    assert expected_msg == actual_msg
Beispiel #7
0
    def test_positive_message_has_attributes_valid_type(self):
        """Test the message_has_attributes method where the message is of the specified type."""
        dummy_message = FipaMessage(
            dialogue_reference=("0", "0"),
            message_id=1,
            performative=FipaMessage.Performative.CFP,
            target=0,
            query="some_query",
        )
        dummy_message.to = "some_to"
        dummy_message.sender = "some_sender"

        valid_has_attribute, valid_has_attribute_msg = self.message_has_attributes(
            actual_message=dummy_message,
            message_type=FipaMessage,
            message_id=1,
            performative=FipaMessage.Performative.CFP,
            target=0,
            query="some_query",
            to="some_to",
            sender="some_sender",
        )
        assert valid_has_attribute
        assert (valid_has_attribute_msg ==
                "The message has the provided expected attributes.")
Beispiel #8
0
def test_match_accept_with_inform_serialization():
    """Test the serialization - deserialization of the match_accept_with_address performative."""
    msg = FipaMessage(
        message_id=1,
        dialogue_reference=(str(0), ""),
        target=0,
        performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,
        info={
            "address": "dummy_address",
            "signature": "my_signature"
        },
    )
    msg.to = "receiver"
    envelope = Envelope(
        to=msg.to,
        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.to = actual_envelope.to
    actual_msg.sender = actual_envelope.sender
    expected_msg = msg
    assert expected_msg == actual_msg
Beispiel #9
0
def test_inform_serialization():
    """Test the serialization-deserialization of the inform performative."""
    msg = FipaMessage(
        message_id=1,
        dialogue_reference=(str(0), ""),
        target=0,
        performative=FipaMessage.Performative.INFORM,
        info={"foo": "bar"},
    )
    msg.to = "receiver"
    envelope = Envelope(
        to=msg.to,
        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.to = actual_envelope.to
    actual_msg.sender = actual_envelope.sender
    expected_msg = msg
    assert expected_msg == actual_msg
Beispiel #10
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 #11
0
    def test_negative_message_has_attributes_invalid_message_id(self):
        """Negative test for message_has_attributes method where the message id does NOT match."""
        dummy_message = FipaMessage(
            dialogue_reference=("0", "0"),
            message_id=1,
            performative=FipaMessage.Performative.CFP,
            target=0,
            query="some_query",
        )
        dummy_message.to = "some_to"
        dummy_message.sender = "some_sender"

        invalid_has_attribute, invalid_has_attribute_msg = self.message_has_attributes(
            actual_message=dummy_message,
            message_type=FipaMessage,
            message_id=2,
            performative=FipaMessage.Performative.CFP,
            target=0,
            query="some_query",
            to="some_to",
            sender="some_sender",
        )
        assert not invalid_has_attribute
        assert (
            invalid_has_attribute_msg ==
            "The 'message_id' fields do not match. Actual 'message_id': 1. Expected 'message_id': 2"
        )
Beispiel #12
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 #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 _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 #15
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 #16
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 #17
0
def test_propose_serialization():
    """Test that the serialization for the 'fipa' protocol works."""
    msg = FipaMessage(
        message_id=1,
        dialogue_reference=(str(0), ""),
        target=0,
        performative=FipaMessage.Performative.PROPOSE,
        proposal=Description({
            "foo1": 1,
            "bar1": 2
        }),
    )
    msg.to = "receiver"
    envelope = Envelope(
        to=msg.to,
        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.to = actual_envelope.to
    actual_msg.sender = actual_envelope.sender
    expected_msg = msg
    assert expected_msg == actual_msg
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 test_performative_match_accept_with_inform():
    """Test the serialization - deserialization of the match_accept_with_address performative."""
    msg = FipaMessage(
        message_id=1,
        dialogue_reference=(str(0), ""),
        target=0,
        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")
Beispiel #20
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 #21
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),
        )
    def decode(obj: bytes) -> Message:
        """
        Decode bytes into a 'Fipa' message.

        :param obj: the bytes object.
        :return: the 'Fipa' message.
        """
        message_pb = ProtobufMessage()
        fipa_pb = fipa_pb2.FipaMessage()
        message_pb.ParseFromString(obj)
        message_id = message_pb.dialogue_message.message_id
        dialogue_reference = (
            message_pb.dialogue_message.dialogue_starter_reference,
            message_pb.dialogue_message.dialogue_responder_reference,
        )
        target = message_pb.dialogue_message.target

        fipa_pb.ParseFromString(message_pb.dialogue_message.content)
        performative = fipa_pb.WhichOneof("performative")
        performative_id = FipaMessage.Performative(str(performative))
        performative_content = dict()  # type: Dict[str, Any]
        if performative_id == FipaMessage.Performative.CFP:
            pb2_query = fipa_pb.cfp.query
            query = Query.decode(pb2_query)
            performative_content["query"] = query
        elif performative_id == FipaMessage.Performative.PROPOSE:
            pb2_proposal = fipa_pb.propose.proposal
            proposal = Description.decode(pb2_proposal)
            performative_content["proposal"] = proposal
        elif performative_id == FipaMessage.Performative.ACCEPT_W_INFORM:
            info = fipa_pb.accept_w_inform.info
            info_dict = dict(info)
            performative_content["info"] = info_dict
        elif performative_id == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM:
            info = fipa_pb.match_accept_w_inform.info
            info_dict = dict(info)
            performative_content["info"] = info_dict
        elif performative_id == FipaMessage.Performative.INFORM:
            info = fipa_pb.inform.info
            info_dict = dict(info)
            performative_content["info"] = info_dict
        elif performative_id == FipaMessage.Performative.ACCEPT:
            pass
        elif performative_id == FipaMessage.Performative.DECLINE:
            pass
        elif performative_id == FipaMessage.Performative.MATCH_ACCEPT:
            pass
        elif performative_id == FipaMessage.Performative.END:
            pass
        else:
            raise ValueError("Performative not valid: {}.".format(performative_id))

        return FipaMessage(
            message_id=message_id,
            dialogue_reference=dialogue_reference,
            target=target,
            performative=performative,
            **performative_content
        )
Beispiel #23
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_id = 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:
            strategy.is_searching = False
            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_id,
                performative=FipaMessage.Performative.ACCEPT,
            )
            dialogue.outgoing_extend(accept_msg)
            self.context.outbox.put_message(
                to=msg.counterparty,
                sender=self.context.agent_address,
                protocol_id=FipaMessage.protocol_id,
                message=FipaSerializer().encode(accept_msg),
            )
        else:
            self.context.logger.info(
                "[{}]: declining the proposal from sender={}".format(
                    self.context.agent_name, msg.counterparty[-5:]
                )
            )
            decline_msg = FipaMessage(
                message_id=new_message_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=new_target_id,
                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),
            )
Beispiel #24
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 #25
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 #26
0
    def _handle_cfp(self, msg: FipaMessage, dialogue: Dialogue) -> None:
        """
        Handle the CFP.

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

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

        if strategy.is_matching_supply(query):
            proposal, data_for_sale = strategy.generate_proposal_and_data(
                query, msg.counterparty)
            dialogue.data_for_sale = data_for_sale
            dialogue.proposal = proposal
            self.context.logger.info(
                "[{}]: sending sender={} a PROPOSE with proposal={}".format(
                    self.context.agent_name, msg.counterparty[-5:],
                    proposal.values))
            proposal_msg = FipaMessage(
                message_id=new_message_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=new_target,
                performative=FipaMessage.Performative.PROPOSE,
                proposal=proposal,
            )
            dialogue.outgoing_extend(proposal_msg)
            self.context.outbox.put_message(
                to=msg.counterparty,
                sender=self.context.agent_address,
                protocol_id=FipaMessage.protocol_id,
                message=FipaSerializer().encode(proposal_msg),
            )
        else:
            self.context.logger.info(
                "[{}]: declined the CFP from sender={}".format(
                    self.context.agent_name, msg.counterparty[-5:]))
            decline_msg = FipaMessage(
                message_id=new_message_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=new_target,
                performative=FipaMessage.Performative.DECLINE,
            )
            dialogue.outgoing_extend(decline_msg)
            self.context.outbox.put_message(
                to=msg.counterparty,
                sender=self.context.agent_address,
                protocol_id=FipaMessage.protocol_id,
                message=FipaSerializer().encode(decline_msg),
            )
Beispiel #27
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 #28
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 #29
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 #30
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))