예제 #1
0
    def get_dialogue(self, fipa_msg: Message, agent_addr: Address) -> Dialogue:
        """
        Retrieve dialogue.

        :param fipa_msg: the fipa message
        :param agent_addr: the address of the agent

        :return: the dialogue
        """
        result = None
        fipa_msg = cast(FIPAMessage, fipa_msg)
        dialogue_reference = fipa_msg.dialogue_reference
        self_initiated_dialogue_label = DialogueLabel(
            dialogue_reference, fipa_msg.counterparty, agent_addr
        )
        other_initiated_dialogue_label = DialogueLabel(
            dialogue_reference, fipa_msg.counterparty, fipa_msg.counterparty
        )
        if other_initiated_dialogue_label in self.dialogues:
            other_initiated_dialogue = cast(
                FIPADialogue, self.dialogues[other_initiated_dialogue_label]
            )
            if other_initiated_dialogue.is_valid_next_message(fipa_msg):
                result = other_initiated_dialogue
        if self_initiated_dialogue_label in self.dialogues:
            self_initiated_dialogue = cast(
                FIPADialogue, self.dialogues[self_initiated_dialogue_label]
            )
            if self_initiated_dialogue.is_valid_next_message(fipa_msg):
                result = self_initiated_dialogue
        if result is None:
            raise ValueError("Should have found dialogue.")
        return result
예제 #2
0
    def get_dialogue(
        self, message: Message, sender: Address, agent_pbk: Address
    ) -> Dialogue:
        """
        Retrieve dialogue.

        :param message: the agent message
        :param agent_pbk: the public key of the agent

        :return: the dialogue
        """
        dialogue_id = message.get("dialogue_id")
        opponent = sender
        target = message.get("target")
        performative = message.get("performative")
        self_initiated_dialogue_label = DialogueLabel(dialogue_id, opponent, agent_pbk)
        other_initiated_dialogue_label = DialogueLabel(dialogue_id, opponent, opponent)
        if (
            performative == FIPAMessage.Performative.PROPOSE
            and target == PROPOSE_TARGET
            and self_initiated_dialogue_label in self.dialogues
        ):
            dialogue = self.dialogues[self_initiated_dialogue_label]
        elif performative == FIPAMessage.Performative.ACCEPT:
            if (
                target == ACCEPT_TARGET
                and other_initiated_dialogue_label in self.dialogues
            ):
                dialogue = self.dialogues[other_initiated_dialogue_label]
            else:
                raise ValueError("Should have found dialogue.")
        elif performative == FIPAMessage.Performative.MATCH_ACCEPT:
            if (
                target == MATCH_ACCEPT_TARGET
                and self_initiated_dialogue_label in self.dialogues
            ):
                dialogue = self.dialogues[self_initiated_dialogue_label]
            else:
                raise ValueError("Should have found dialogue.")
        elif performative == FIPAMessage.Performative.DECLINE:
            if (
                target == DECLINED_CFP_TARGET
                and self_initiated_dialogue_label in self.dialogues
            ):
                dialogue = self.dialogues[self_initiated_dialogue_label]
            elif (
                target == DECLINED_PROPOSE_TARGET
                and other_initiated_dialogue_label in self.dialogues
            ):
                dialogue = self.dialogues[other_initiated_dialogue_label]
            elif (
                target == DECLINED_ACCEPT_TARGET
                and self_initiated_dialogue_label in self.dialogues
            ):
                dialogue = self.dialogues[self_initiated_dialogue_label]
            else:
                raise ValueError("Should have found dialogue.")
        else:
            raise ValueError("Should have found dialogue.")
        return dialogue
예제 #3
0
    def get_dialogue(self, fipa_msg: Message, sender: Address,
                     agent_pbk: Address) -> Dialogue:
        """
        Retrieve dialogue.

        :param fipa_msg: the fipa message
        :param sender_pbk: the sender public key
        :param agent_pbk: the public key of the agent

        :return: the dialogue
        """
        fipa_msg = cast(FIPAMessage, fipa_msg)
        dialogue_reference = cast(Tuple[str, str],
                                  fipa_msg.get("dialogue_reference"))
        self_initiated_dialogue_label = DialogueLabel(dialogue_reference,
                                                      sender, agent_pbk)
        other_initiated_dialogue_label = DialogueLabel(dialogue_reference,
                                                       sender, sender)
        if other_initiated_dialogue_label in self.dialogues:
            other_initiated_dialogue = cast(
                FIPADialogue, self.dialogues[other_initiated_dialogue_label])
            if other_initiated_dialogue.is_valid_next_message(fipa_msg):
                result = other_initiated_dialogue
        if self_initiated_dialogue_label in self.dialogues:
            self_initiated_dialogue = cast(
                FIPADialogue, self.dialogues[self_initiated_dialogue_label])
            if self_initiated_dialogue.is_valid_next_message(fipa_msg):
                result = self_initiated_dialogue
        if result is None:
            raise ValueError('Should have found dialogue.')
        return result
예제 #4
0
    def test_dialogue_label(self):
        """Test the dialogue_label."""
        assert self.dialogue_label.dialogue_starter_reference == str(0)
        assert self.dialogue_label.dialogue_responder_reference == ''
        assert self.dialogue_label.dialogue_opponent_pbk == "opponent"
        assert self.dialogue_label.dialogue_starter_pbk == "starter"

        dialogue_label2 = DialogueLabel(dialogue_reference=(str(0), ''),
                                        dialogue_opponent_pbk="opponent",
                                        dialogue_starter_pbk="starter")

        assert dialogue_label2 == self.dialogue_label

        dialogue_label3 = "This is a test"

        assert not dialogue_label3 == self.dialogue_label

        assert hash(self.dialogue_label) == hash(self.dialogue.dialogue_label)

        assert self.dialogue_label.json == dict(
            dialogue_starter_reference=str(0),
            dialogue_responder_reference='',
            dialogue_opponent_pbk="opponent",
            dialogue_starter_pbk="starter")
        assert DialogueLabel.from_json(
            self.dialogue_label.json) == self.dialogue_label
예제 #5
0
    def test_dialogue_label(self):
        """Test the dialogue_label."""
        assert self.dialogue_label.dialogue_starter_reference == str(0)
        assert self.dialogue_label.dialogue_responder_reference == ""
        assert self.dialogue_label.dialogue_opponent_addr == "opponent"
        assert self.dialogue_label.dialogue_starter_addr == "starter"
        assert str(self.dialogue_label) == "{}_{}_{}_{}".format(
            self.dialogue_label.dialogue_starter_reference,
            self.dialogue_label.dialogue_responder_reference,
            self.dialogue_label.dialogue_opponent_addr,
            self.dialogue_label.dialogue_starter_addr,
        )

        dialogue_label2 = DialogueLabel(
            dialogue_reference=(str(0), ""),
            dialogue_opponent_addr="opponent",
            dialogue_starter_addr="starter",
        )

        assert dialogue_label2 == self.dialogue_label

        dialogue_label3 = "This is a test"

        assert not dialogue_label3 == self.dialogue_label

        assert hash(self.dialogue_label) == hash(self.dialogue.dialogue_label)

        assert self.dialogue_label.json == dict(
            dialogue_starter_reference=str(0),
            dialogue_responder_reference="",
            dialogue_opponent_addr="opponent",
            dialogue_starter_addr="starter",
        )
        assert DialogueLabel.from_json(
            self.dialogue_label.json) == self.dialogue_label
예제 #6
0
    def is_belonging_to_registered_dialogue(
        self, fipa_msg: Message, agent_addr: Address
    ) -> bool:
        """
        Check whether an agent message is part of a registered dialogue.

        :param fipa_msg: the fipa message
        :param agent_addr: the address of the agent

        :return: boolean indicating whether the message belongs to a registered dialogue
        """
        fipa_msg = cast(FIPAMessage, fipa_msg)
        dialogue_reference = fipa_msg.dialogue_reference
        alt_dialogue_reference = (dialogue_reference[0], "")
        self_initiated_dialogue_label = DialogueLabel(
            dialogue_reference, fipa_msg.counterparty, agent_addr
        )
        alt_self_initiated_dialogue_label = DialogueLabel(
            alt_dialogue_reference, fipa_msg.counterparty, agent_addr
        )
        other_initiated_dialogue_label = DialogueLabel(
            dialogue_reference, fipa_msg.counterparty, fipa_msg.counterparty
        )
        result = False
        if other_initiated_dialogue_label in self.dialogues:
            other_initiated_dialogue = cast(
                FIPADialogue, self.dialogues[other_initiated_dialogue_label]
            )
            result = other_initiated_dialogue.is_valid_next_message(fipa_msg)
        if self_initiated_dialogue_label in self.dialogues:
            self_initiated_dialogue = cast(
                FIPADialogue, self.dialogues[self_initiated_dialogue_label]
            )
            result = self_initiated_dialogue.is_valid_next_message(fipa_msg)
        if alt_self_initiated_dialogue_label in self._initiated_dialogues:
            self_initiated_dialogue = cast(
                FIPADialogue,
                self._initiated_dialogues[alt_self_initiated_dialogue_label],
            )
            result = self_initiated_dialogue.is_valid_next_message(fipa_msg)
            if result:
                self._initiated_dialogues.pop(alt_self_initiated_dialogue_label)
                final_dialogue_label = DialogueLabel(
                    dialogue_reference,
                    alt_self_initiated_dialogue_label.dialogue_opponent_addr,
                    alt_self_initiated_dialogue_label.dialogue_starter_addr,
                )
                self_initiated_dialogue.assign_final_dialogue_label(
                    final_dialogue_label
                )
                self._add(self_initiated_dialogue)
        return result
예제 #7
0
    def is_belonging_to_registered_dialogue(self, message: Message,
                                            agent_pbk: Address,
                                            sender: Address) -> bool:
        """
        Check whether an agent message is part of a registered dialogue.

        :param message: the agent message
        :param agent_pbk: the public key of the agent

        :return: boolean indicating whether the message belongs to a registered dialogue
        """
        dialogue_id = message.get("dialogue_id")
        opponent = sender
        target = message.get("target")
        performative = message.get("performative")
        self_initiated_dialogue_label = DialogueLabel(dialogue_id, opponent,
                                                      agent_pbk)
        other_initiated_dialogue_label = DialogueLabel(dialogue_id, opponent,
                                                       opponent)
        result = False
        if performative == FIPAMessage.Performative.PROPOSE and target == PROPOSE_TARGET and self_initiated_dialogue_label in self.dialogues:
            self_initiated_dialogue = self.dialogues[
                self_initiated_dialogue_label]
            result = self_initiated_dialogue.is_expecting_propose()
        elif performative == FIPAMessage.Performative.ACCEPT:
            if target == ACCEPT_TARGET and other_initiated_dialogue_label in self.dialogues:
                other_initiated_dialogue = self.dialogues[
                    other_initiated_dialogue_label]
                result = other_initiated_dialogue.is_expecting_initial_accept()
        elif performative == FIPAMessage.Performative.MATCH_ACCEPT:
            if target == MATCH_ACCEPT_TARGET and self_initiated_dialogue_label in self.dialogues:
                self_initiated_dialogue = self.dialogues[
                    self_initiated_dialogue_label]
                result = self_initiated_dialogue.is_expecting_matching_accept()
        elif performative == FIPAMessage.Performative.DECLINE:
            if target == DECLINED_CFP_TARGET and self_initiated_dialogue_label in self.dialogues:
                self_initiated_dialogue = self.dialogues[
                    self_initiated_dialogue_label]
                result = self_initiated_dialogue.is_expecting_cfp_decline()
            elif target == DECLINED_PROPOSE_TARGET and other_initiated_dialogue_label in self.dialogues:
                other_initiated_dialogue = self.dialogues[
                    other_initiated_dialogue_label]
                result = other_initiated_dialogue.is_expecting_propose_decline(
                )
            elif target == DECLINED_ACCEPT_TARGET and self_initiated_dialogue_label in self.dialogues:
                self_initiated_dialogue = self.dialogues[
                    self_initiated_dialogue_label]
                result = self_initiated_dialogue.is_expecting_accept_decline()
        return result
예제 #8
0
    def create_opponent_initiated(
        self,
        dialogue_opponent_addr: Address,
        dialogue_reference: Tuple[str, str],
        is_seller: bool,
    ) -> Dialogue:
        """
        Save an opponent initiated dialogue.

        :param dialogue_opponent_addr: the address of the agent with which the dialogue is kept.
        :param dialogue_reference: the reference of the dialogue.
        :param is_seller: keeps track if the counterparty is a seller.
        :return: the created dialogue
        """
        assert (
            dialogue_reference[0] != "" and dialogue_reference[1] == ""
        ), "Cannot initiate dialogue with preassigned dialogue_responder_reference!"
        new_dialogue_reference = (
            dialogue_reference[0],
            str(self._next_dialogue_nonce()),
        )
        dialogue_label = DialogueLabel(
            new_dialogue_reference, dialogue_opponent_addr, dialogue_opponent_addr
        )
        result = self._create(dialogue_label, is_seller)
        return result
예제 #9
0
 def setup(cls):
     """Initialise the class."""
     cls.dialogue_label = DialogueLabel(dialogue_reference=(str(0), ''),
                                        dialogue_opponent_pbk="opponent",
                                        dialogue_starter_pbk="starter")
     cls.dialogue = Dialogue(dialogue_label=cls.dialogue_label)
     cls.dialogues = Dialogues()
예제 #10
0
    def handle(self, message: Message, sender: str) -> None:
        """
        Implement the reaction to a message.

        :param message: the message
        :param sender: the sender
        :return: None
        """
        tx_msg_response = cast(TransactionMessage, message)
        if tx_msg_response is not None and \
                TransactionMessage.Performative(tx_msg_response.get("performative")) == TransactionMessage.Performative.ACCEPT:
            logger.info("[{}]: transaction was successful.".format(self.context.agent_name))
            json_data = {'transaction_digest': tx_msg_response.get("transaction_digest")}
            dialogue_label = DialogueLabel.from_json(cast(Dict[str, str], tx_msg_response.get("dialogue_label")))
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogue = dialogues.dialogues[dialogue_label]
            fipa_msg = cast(FIPAMessage, dialogue.last_incoming_message)
            new_message_id = cast(int, fipa_msg.get("message_id")) + 1
            new_target_id = cast(int, fipa_msg.get("target")) + 1
            counterparty_pbk = dialogue.dialogue_label.dialogue_opponent_pbk
            inform_msg = FIPAMessage(message_id=new_message_id,
                                     dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                                     target=new_target_id,
                                     performative=FIPAMessage.Performative.INFORM,
                                     json_data=json_data)
            dialogue.outgoing_extend(inform_msg)
            self.context.outbox.put_message(to=counterparty_pbk,
                                            sender=self.context.agent_public_key,
                                            protocol_id=FIPAMessage.protocol_id,
                                            message=FIPASerializer().encode(inform_msg))
            logger.info("[{}]: informing counterparty={} of transaction digest.".format(self.context.agent_name, counterparty_pbk[-5:]))
            self._received_tx_message = True
        else:
            logger.info("[{}]: transaction was not successful.".format(self.context.agent_name))
예제 #11
0
    def is_belonging_to_registered_dialogue(self, fipa_msg: Message,
                                            sender: Address,
                                            agent_pbk: Address) -> bool:
        """
        Check whether an agent message is part of a registered dialogue.

        :param fipa_msg: the fipa message
        :param sender: the sender
        :param agent_pbk: the public key of the agent

        :return: boolean indicating whether the message belongs to a registered dialogue
        """
        fipa_msg = cast(FIPAMessage, fipa_msg)
        dialogue_reference = cast(Tuple[str, str],
                                  fipa_msg.get("dialogue_reference"))
        alt_dialogue_reference = (dialogue_reference[0], '')
        self_initiated_dialogue_label = DialogueLabel(dialogue_reference,
                                                      sender, agent_pbk)
        alt_self_initiated_dialogue_label = DialogueLabel(
            alt_dialogue_reference, sender, agent_pbk)
        other_initiated_dialogue_label = DialogueLabel(dialogue_reference,
                                                       sender, sender)
        result = False
        if other_initiated_dialogue_label in self.dialogues:
            other_initiated_dialogue = cast(
                FIPADialogue, self.dialogues[other_initiated_dialogue_label])
            result = other_initiated_dialogue.is_valid_next_message(fipa_msg)
        if self_initiated_dialogue_label in self.dialogues:
            self_initiated_dialogue = cast(
                FIPADialogue, self.dialogues[self_initiated_dialogue_label])
            result = self_initiated_dialogue.is_valid_next_message(fipa_msg)
        if alt_self_initiated_dialogue_label in self._initiated_dialogues:
            self_initiated_dialogue = cast(
                FIPADialogue,
                self._initiated_dialogues[alt_self_initiated_dialogue_label])
            result = self_initiated_dialogue.is_valid_next_message(fipa_msg)
            if result:
                self._initiated_dialogues.pop(
                    alt_self_initiated_dialogue_label)
                final_dialogue_label = DialogueLabel(
                    dialogue_reference,
                    alt_self_initiated_dialogue_label.dialogue_opponent_pbk,
                    alt_self_initiated_dialogue_label.dialogue_starter_pbk)
                self_initiated_dialogue.assign_final_dialogue_label(
                    final_dialogue_label)
                self._add(self_initiated_dialogue)
        return result
예제 #12
0
 def setup(cls):
     """Initialise the class."""
     cls.dialogue_label = DialogueLabel(
         dialogue_reference=(str(0), ""),
         dialogue_opponent_addr="opponent",
         dialogue_starter_addr="starter",
     )
     cls.dialogue = Dialogue(dialogue_label=cls.dialogue_label)
     cls.dialogues = Dialogues("address")
예제 #13
0
def test_default_dialogues(dialogues_classes):
    """Test default dialogues initialization."""
    dialogue_class, dialogues_class = dialogues_classes
    dialogues = dialogues_class("agent_address")

    dialogue = dialogues.create_dialogue(
        DialogueLabel(("x", "y"), "opponent_addr", "starter_addr"),
        next(iter(dialogue_class.Role)),
    )
    assert isinstance(dialogue, dialogue_class)
예제 #14
0
    def handle(self, message: Message) -> None:
        """
        Dispatch message to relevant handler and respond.

        :param message: the message
        :return: None
        """
        tx_message = cast(TransactionMessage, message)
        if (tx_message.performative ==
                TransactionMessage.Performative.SUCCESSFUL_SIGNING):
            self.context.logger.info(
                "[{}]: transaction confirmed by decision maker".format(
                    self.context.agent_name))
            info = tx_message.info
            dialogue_label = DialogueLabel.from_json(
                cast(Dict[str, str], info.get("dialogue_label")))
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogue = dialogues.dialogues[dialogue_label]
            fipa_message = cast(FipaMessage, dialogue.last_incoming_message)
            if (fipa_message is not None and fipa_message.performative
                    == FipaMessage.Performative.ACCEPT):
                self.context.logger.info(
                    "[{}]: sending match accept to {}.".format(
                        self.context.agent_name,
                        dialogue.dialogue_label.dialogue_opponent_addr[-5:],
                    ))
                fipa_msg = FipaMessage(
                    performative=FipaMessage.Performative.
                    MATCH_ACCEPT_W_INFORM,
                    message_id=fipa_message.message_id + 1,
                    dialogue_reference=dialogue.dialogue_label.
                    dialogue_reference,
                    target=fipa_message.message_id,
                    info={
                        "tx_signature":
                        tx_message.signed_payload.get("tx_signature"),
                        "tx_id":
                        tx_message.tx_id,
                    },
                )
                dialogue.outgoing_extend(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),
                )
            else:
                self.context.logger.warning(
                    "[{}]: last message should be of performative accept.".
                    format(self.context.agent_name))
        else:
            self.context.logger.info(
                "[{}]: transaction was not successful.".format(
                    self.context.agent_name))
예제 #15
0
    def get_dialogue(self, fipa_msg: Message, sender: Address, agent_pbk: Address) -> Dialogue:
        """
        Retrieve dialogue.

        :param fipa_msg: the fipa message
        :param sender_pbk: the sender public key
        :param agent_pbk: the public key of the agent

        :return: the dialogue
        """
        dialogue_id = cast(int, fipa_msg.get("dialogue_id"))
        opponent = sender
        target = cast(int, fipa_msg.get("target"))
        performative = fipa_msg.get("performative")
        self_initiated_dialogue_label = DialogueLabel(dialogue_id, opponent, agent_pbk)
        other_initiated_dialogue_label = DialogueLabel(dialogue_id, opponent, opponent)
        if performative == FIPAMessage.Performative.PROPOSE and target == PROPOSE_TARGET and self_initiated_dialogue_label in self.dialogues:
            dialogue = self.dialogues[self_initiated_dialogue_label]
        elif performative == FIPAMessage.Performative.ACCEPT:
            if target == ACCEPT_TARGET and other_initiated_dialogue_label in self.dialogues:
                dialogue = self.dialogues[other_initiated_dialogue_label]
            else:
                raise ValueError('Should have found dialogue.')
        elif performative == FIPAMessage.Performative.MATCH_ACCEPT:
            if target == MATCH_ACCEPT_TARGET and self_initiated_dialogue_label in self.dialogues:
                dialogue = self.dialogues[self_initiated_dialogue_label]
            else:
                raise ValueError('Should have found dialogue.')
        elif performative == FIPAMessage.Performative.DECLINE:
            if target == DECLINED_CFP_TARGET and self_initiated_dialogue_label in self.dialogues:
                dialogue = self.dialogues[self_initiated_dialogue_label]
            elif target == DECLINED_PROPOSE_TARGET and other_initiated_dialogue_label in self.dialogues:
                dialogue = self.dialogues[other_initiated_dialogue_label]
            elif target == DECLINED_ACCEPT_TARGET and self_initiated_dialogue_label in self.dialogues:
                dialogue = self.dialogues[self_initiated_dialogue_label]
            else:
                raise ValueError('Should have found dialogue.')
        else:
            raise ValueError('Should have found dialogue.')
        dialogue = cast(Dialogue, dialogue)
        return dialogue
예제 #16
0
    def create_self_initiated(self, dialogue_opponent_pbk: Address, dialogue_starter_pbk: Address, is_seller: bool) -> Dialogue:
        """
        Create a self initiated dialogue.

        :param dialogue_opponent_pbk: the pbk of the agent with which the dialogue is kept.
        :param dialogue_starter_pbk: the pbk of the agent which started the dialogue
        :param is_seller: boolean indicating the agent role

        :return: the created dialogue.
        """
        dialogue_label = DialogueLabel(self._next_dialogue_id(), dialogue_opponent_pbk, dialogue_starter_pbk)
        result = self._create(dialogue_label, is_seller)
        return result
예제 #17
0
    def handle(self, message: Message) -> None:
        """
        Implement the reaction to a message.

        :param message: the message
        :return: None
        """
        tx_msg_response = cast(TransactionMessage, message)
        if (
            tx_msg_response is not None
            and tx_msg_response.performative
            == TransactionMessage.Performative.SUCCESSFUL_SETTLEMENT
        ):
            self.context.logger.info(
                "[{}]: transaction was successful.".format(self.context.agent_name)
            )
            json_data = {"transaction_digest": tx_msg_response.tx_digest}
            info = tx_msg_response.info
            dialogue_label = DialogueLabel.from_json(
                cast(Dict[str, str], info.get("dialogue_label"))
            )
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogue = dialogues.dialogues[dialogue_label]
            fipa_msg = cast(FipaMessage, dialogue.last_incoming_message)
            new_message_id = fipa_msg.message_id + 1
            new_target_id = fipa_msg.message_id
            counterparty_id = dialogue.dialogue_label.dialogue_opponent_addr
            inform_msg = FipaMessage(
                message_id=new_message_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=new_target_id,
                performative=FipaMessage.Performative.INFORM,
                info=json_data,
            )
            dialogue.outgoing_extend(inform_msg)
            self.context.outbox.put_message(
                to=counterparty_id,
                sender=self.context.agent_address,
                protocol_id=FipaMessage.protocol_id,
                message=FipaSerializer().encode(inform_msg),
            )
            self.context.logger.info(
                "[{}]: informing counterparty={} of transaction digest.".format(
                    self.context.agent_name, counterparty_id[-5:]
                )
            )
            self._received_tx_message = True
        else:
            self.context.logger.info(
                "[{}]: transaction was not successful.".format(self.context.agent_name)
            )
예제 #18
0
    def handle(self, message: Message) -> None:
        """
        Implement the reaction to a message.

        :param message: the message
        :return: None
        """
        tx_msg_response = cast(TransactionMessage, message)
        if (
            tx_msg_response.performative
            == TransactionMessage.Performative.SUCCESSFUL_SIGNING
            and (
                tx_msg_response.tx_id
                == ERC1155Contract.Performative.CONTRACT_SIGN_HASH_SINGLE.value
            )
        ):
            tx_signature = tx_msg_response.signed_payload.get("tx_signature")
            dialogue_label = DialogueLabel.from_json(
                cast(Dict[str, str], tx_msg_response.info.get("dialogue_label"))
            )
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogue = dialogues.dialogues[dialogue_label]
            fipa_msg = cast(FipaMessage, dialogue.last_incoming_message)
            new_message_id = fipa_msg.message_id + 1
            new_target = fipa_msg.message_id
            counterparty_addr = dialogue.dialogue_label.dialogue_opponent_addr
            inform_msg = FipaMessage(
                message_id=new_message_id,
                dialogue_reference=dialogue.dialogue_label.dialogue_reference,
                target=new_target,
                performative=FipaMessage.Performative.ACCEPT_W_INFORM,
                info={"tx_signature": tx_signature},
            )
            self.context.logger.info(
                "[{}]: sending ACCEPT_W_INFORM to agent={}: tx_signature={}".format(
                    self.context.agent_name, counterparty_addr[-5:], tx_signature
                )
            )
            self.context.outbox.put_message(
                to=counterparty_addr,
                sender=self.context.agent_address,
                protocol_id=FipaMessage.protocol_id,
                message=FipaSerializer().encode(inform_msg),
            )
        else:
            self.context.logger.info(
                "[{}]: signing failed: tx_msg_response={}".format(
                    self.context.agent_name, tx_msg_response
                )
            )
예제 #19
0
def dialogue_label_from_transaction_id(agent_pbk: Address, transaction_id: TransactionId) -> DialogueLabel:
    """
    Recover dialogue label from transaction id.

    :param agent_pbk: the pbk of the agent.
    :param transaction_id: the transaction id
    :return: a dialogue label
    """
    buyer_pbk, seller_pbk, dialogue_id, dialogue_starter_pbk = transaction_id.split('_')
    if agent_pbk == buyer_pbk:
        dialogue_opponent_pbk = seller_pbk
    else:
        dialogue_opponent_pbk = buyer_pbk
    dialogue_label = DialogueLabel(int(dialogue_id), dialogue_opponent_pbk, dialogue_starter_pbk)
    return dialogue_label
예제 #20
0
    def create_opponent_initiated(self, dialogue_opponent_pbk: Address,
                                  dialogue_id: int,
                                  is_seller: bool) -> Dialogue:
        """
        Save an opponent initiated dialogue.

        :param dialogue_opponent_pbk: the pbk of the agent with which the dialogue is kept.
        :param dialogue_id: the id of the dialogue
        :param is_seller: boolean indicating the agent role

        :return: the created dialogue
        """
        dialogue_starter_pbk = dialogue_opponent_pbk
        dialogue_label = DialogueLabel(dialogue_id, dialogue_opponent_pbk,
                                       dialogue_starter_pbk)
        result = self._create(dialogue_label, is_seller)
        return result
예제 #21
0
    def create_self_initiated(self, dialogue_opponent_pbk: Address,
                              dialogue_starter_pbk: Address,
                              is_seller: bool) -> Dialogue:
        """
        Create a self initiated dialogue.

        :param dialogue_opponent_pbk: the pbk of the agent with which the dialogue is kept.
        :param dialogue_starter_pbk: the pbk of the agent which started the dialogue
        :param is_seller: boolean indicating the agent role

        :return: the created dialogue.
        """
        dialogue_reference = (str(self._next_dialogue_nonce()), '')
        dialogue_label = DialogueLabel(dialogue_reference,
                                       dialogue_opponent_pbk,
                                       dialogue_starter_pbk)
        dialogue = FIPADialogue(dialogue_label, is_seller)
        self._initiated_dialogues.update({dialogue_label: dialogue})
        return dialogue
예제 #22
0
    def create_opponent_initiated(self, fipa_msg: FIPAMessage, sender: Address) -> Dialogue:
        """
        Save an opponent initiated dialogue.

        :param fipa_msg: the fipa message
        :param sender: the pbk of the sender

        :return: the created dialogue
        """
        dialogue_starter_pbk = sender
        dialogue_opponent_pbk = sender
        dialogue_id = fipa_msg.get("dialogue_id")
        dialogue_id = cast(int, dialogue_id)
        dialogue_label = DialogueLabel(dialogue_id, dialogue_opponent_pbk, dialogue_starter_pbk)
        query = cast(Query, fipa_msg.get("query"))
        assert query.model is not None, "Query has no data model."
        is_seller = query.model.name == DEMAND_DATAMODEL_NAME
        result = self._create(dialogue_label, is_seller)
        return result
예제 #23
0
    def handle(self, message: Message, sender: str) -> None:
        """
        Dispatch message to relevant handler and respond.

        :param message: the message
        :param sender: the sender
        :return: None
        """
        tx_message = cast(TransactionMessage, message)
        if TransactionMessage.Performative(tx_message.get(
                "performative")) == TransactionMessage.Performative.ACCEPT:
            logger.info(
                "[{}]: transaction confirmed by decision maker, sending match accept."
                .format(self.context.agent_name))
            dialogue_label = DialogueLabel.from_json(
                cast(Dict[str, str], tx_message.get("dialogue_label")))
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogue = dialogues.dialogues[dialogue_label]
            tac_message = dialogue.last_incoming_message
            if tac_message is not None and tac_message.get(
                    "performative") == FIPAMessage.Performative.ACCEPT:
                fipa_msg = FIPAMessage(
                    performative=FIPAMessage.Performative.
                    MATCH_ACCEPT_W_ADDRESS,
                    message_id=cast(int, tac_message.get("message_id")) + 1,
                    dialogue_reference=dialogue.dialogue_label.
                    dialogue_reference,
                    target=tac_message.get("message_id"),
                    address=tx_message.get("transaction_digest"))
                dialogue.outgoing_extend(fipa_msg)
                self.context.outbox.put_message(
                    to=dialogue.dialogue_label.dialogue_opponent_pbk,
                    sender=self.context.agent_public_key,
                    protocol_id=FIPAMessage.protocol_id,
                    message=FIPASerializer().encode(fipa_msg))
            else:
                logger.info(
                    "[{}]: last message should be of performative accept.".
                    format(self.context.agent_name))
        else:
            logger.info("[{}]: transaction was not successful.".format(
                self.context.agent_name))
예제 #24
0
    def create_opponent_initiated(self, dialogue_opponent_pbk: Address,
                                  dialogue_reference: Tuple[str, str],
                                  is_seller: bool) -> Dialogue:
        """
        Save an opponent initiated dialogue.

        :param dialogue_opponent_pbk: the pbk of the agent with which the dialogue is kept.
        :param dialogue_id: the id of the dialogue
        :param sender: the pbk of the sender

        :return: the created dialogue
        """
        assert dialogue_reference[0] != '' and dialogue_reference[
            1] == '', "Cannot initiate dialogue with preassigned dialogue_responder_reference!"
        new_dialogue_reference = (dialogue_reference[0],
                                  str(self._next_dialogue_nonce()))
        dialogue_label = DialogueLabel(new_dialogue_reference,
                                       dialogue_opponent_pbk,
                                       dialogue_opponent_pbk)
        result = self._create(dialogue_label, is_seller)
        return result
예제 #25
0
def test_dialogue(dialogue_classes):
    """Test dialogue initialization."""
    dialogue_class, _ = dialogue_classes
    dialogue = dialogue_class(
        DialogueLabel(("x", "y"), "opponent_addr", "starer_addr"))
    assert dialogue.is_valid(MagicMock())
예제 #26
0
    def test_generated_protocol_end_to_end(self):
        """Test that a generated protocol could be used in exchanging messages between two agents."""
        agent_name_1 = "my_aea_1"
        agent_name_2 = "my_aea_2"
        builder_1 = AEABuilder()
        builder_1.set_name(agent_name_1)
        builder_1.add_private_key(DEFAULT_LEDGER, self.private_key_path_1)
        builder_1.set_default_ledger(DEFAULT_LEDGER)
        builder_1.set_default_connection(PublicId.from_str("fetchai/oef:0.7.0"))
        builder_1.add_protocol(
            Path(ROOT_DIR, "packages", "fetchai", "protocols", "fipa")
        )
        builder_1.add_protocol(
            Path(ROOT_DIR, "packages", "fetchai", "protocols", "oef_search")
        )
        builder_1.add_component(
            ComponentType.PROTOCOL,
            Path(PATH_TO_T_PROTOCOL),
            skip_consistency_check=True,
        )
        builder_1.add_connection(
            Path(ROOT_DIR, "packages", "fetchai", "connections", "oef")
        )

        builder_2 = AEABuilder()
        builder_2.set_name(agent_name_2)
        builder_2.add_private_key(DEFAULT_LEDGER, self.private_key_path_2)
        builder_2.set_default_ledger(DEFAULT_LEDGER)
        builder_2.add_protocol(
            Path(ROOT_DIR, "packages", "fetchai", "protocols", "fipa")
        )
        builder_2.add_protocol(
            Path(ROOT_DIR, "packages", "fetchai", "protocols", "oef_search")
        )
        builder_2.set_default_connection(PublicId.from_str("fetchai/oef:0.7.0"))
        builder_2.add_component(
            ComponentType.PROTOCOL,
            Path(PATH_TO_T_PROTOCOL),
            skip_consistency_check=True,
        )
        builder_2.add_connection(
            Path(ROOT_DIR, "packages", "fetchai", "connections", "oef")
        )

        # create AEAs
        aea_1 = builder_1.build(connection_ids=[PublicId.from_str("fetchai/oef:0.7.0")])
        aea_2 = builder_2.build(connection_ids=[PublicId.from_str("fetchai/oef:0.7.0")])

        # dialogues
        dialogue_label_1 = DialogueLabel(
            (str(1), ""), aea_2.identity.address, aea_1.identity.address
        )
        aea_1_dialogue = TProtocolDialogue(
            dialogue_label_1, aea_1.identity.address, TProtocolDialogue.Role.ROLE_1
        )
        dialogue_label_2 = DialogueLabel(
            (str(1), str(1)), aea_1.identity.address, aea_1.identity.address
        )
        aea_2_dialogue = TProtocolDialogue(
            dialogue_label_2, aea_2.identity.address, TProtocolDialogue.Role.ROLE_2
        )

        # message 1
        message_1 = TProtocolMessage(
            message_id=1,
            dialogue_reference=(str(1), ""),
            target=0,
            performative=TProtocolMessage.Performative.PERFORMATIVE_PT,
            content_bytes=b"some bytes",
            content_int=42,
            content_float=42.7,
            content_bool=True,
            content_str="some string",
        )
        message_1.counterparty = aea_2.identity.address
        message_1.is_incoming = False

        # message 2
        message_2 = TProtocolMessage(
            message_id=2,
            dialogue_reference=(str(1), str(1)),
            target=1,
            performative=TProtocolMessage.Performative.PERFORMATIVE_PT,
            content_bytes=b"some other bytes",
            content_int=43,
            content_float=43.7,
            content_bool=False,
            content_str="some other string",
        )
        message_2.counterparty = aea_1.identity.address
        message_2.is_incoming = False

        # add handlers to AEA resources
        skill_context_1 = SkillContext(aea_1.context)
        skill_1 = Skill(SkillConfig("fake_skill", "fetchai", "0.1.0"), skill_context_1)
        skill_context_1._skill = skill_1

        agent_1_handler = Agent1Handler(
            skill_context=skill_context_1,
            name="fake_handler_1",
            dialogue=aea_1_dialogue,
        )
        aea_1.resources._handler_registry.register(
            (
                PublicId.from_str("fetchai/fake_skill:0.1.0"),
                TProtocolMessage.protocol_id,
            ),
            agent_1_handler,
        )
        skill_context_2 = SkillContext(aea_2.context)
        skill_2 = Skill(SkillConfig("fake_skill", "fetchai", "0.1.0"), skill_context_2)
        skill_context_2._skill = skill_2

        agent_2_handler = Agent2Handler(
            message=message_2,
            dialogue=aea_2_dialogue,
            skill_context=skill_context_2,
            name="fake_handler_2",
        )
        aea_2.resources._handler_registry.register(
            (
                PublicId.from_str("fetchai/fake_skill:0.1.0"),
                TProtocolMessage.protocol_id,
            ),
            agent_2_handler,
        )

        # Start threads
        t_1 = Thread(target=aea_1.start)
        t_2 = Thread(target=aea_2.start)
        try:
            t_1.start()
            t_2.start()
            time.sleep(1.0)
            aea_1_dialogue.update(message_1)
            aea_1.outbox.put_message(message_1)
            time.sleep(5.0)
            assert (
                agent_2_handler.handled_message.message_id == message_1.message_id
            ), "Message from Agent 1 to 2: message ids do not match"
            assert (
                agent_2_handler.handled_message.dialogue_reference
                == message_1.dialogue_reference
            ), "Message from Agent 1 to 2: dialogue references do not match"
            assert (
                agent_2_handler.handled_message.dialogue_reference[0]
                == message_1.dialogue_reference[0]
            ), "Message from Agent 1 to 2: dialogue reference[0]s do not match"
            assert (
                agent_2_handler.handled_message.dialogue_reference[1]
                == message_1.dialogue_reference[1]
            ), "Message from Agent 1 to 2: dialogue reference[1]s do not match"
            assert (
                agent_2_handler.handled_message.target == message_1.target
            ), "Message from Agent 1 to 2: targets do not match"
            assert (
                agent_2_handler.handled_message.performative == message_1.performative
            ), "Message from Agent 1 to 2: performatives do not match"
            assert (
                agent_2_handler.handled_message.content_bytes == message_1.content_bytes
            ), "Message from Agent 1 to 2: content_bytes do not match"
            assert (
                agent_2_handler.handled_message.content_int == message_1.content_int
            ), "Message from Agent 1 to 2: content_int do not match"
            # assert (
            #     agent_2_handler.handled_message.content_float == message_1.content_float
            # ), "Message from Agent 1 to 2: content_float do not match"
            assert (
                agent_2_handler.handled_message.content_bool == message_1.content_bool
            ), "Message from Agent 1 to 2: content_bool do not match"
            assert (
                agent_2_handler.handled_message.content_str == message_1.content_str
            ), "Message from Agent 1 to 2: content_str do not match"

            assert (
                agent_1_handler.handled_message.message_id == message_2.message_id
            ), "Message from Agent 1 to 2: dialogue references do not match"
            assert (
                agent_1_handler.handled_message.dialogue_reference
                == message_2.dialogue_reference
            ), "Message from Agent 2 to 1: dialogue references do not match"
            assert (
                agent_1_handler.handled_message.dialogue_reference[0]
                == message_2.dialogue_reference[0]
            ), "Message from Agent 2 to 1: dialogue reference[0]s do not match"
            assert (
                agent_1_handler.handled_message.dialogue_reference[1]
                == message_2.dialogue_reference[1]
            ), "Message from Agent 2 to 1: dialogue reference[1]s do not match"
            assert (
                agent_1_handler.handled_message.target == message_2.target
            ), "Message from Agent 2 to 1: targets do not match"
            assert (
                agent_1_handler.handled_message.performative == message_2.performative
            ), "Message from Agent 2 to 1: performatives do not match"
            assert (
                agent_1_handler.handled_message.content_bytes == message_2.content_bytes
            ), "Message from Agent 2 to 1: content_bytes do not match"
            assert (
                agent_1_handler.handled_message.content_int == message_2.content_int
            ), "Message from Agent 2 to 1: content_int do not match"
            # assert (
            #     agent_1_handler.handled_message.content_float == message_2.content_float
            # ), "Message from Agent 2 to 1: content_float do not match"
            assert (
                agent_1_handler.handled_message.content_bool == message_2.content_bool
            ), "Message from Agent 2 to 1: content_bool do not match"
            assert (
                agent_1_handler.handled_message.content_str == message_2.content_str
            ), "Message from Agent 2 to 1: content_str do not match"
            time.sleep(2.0)
        finally:
            aea_1.stop()
            aea_2.stop()
            t_1.join()
            t_2.join()
예제 #27
0
    def _handle_signed_transaction(self, signing_msg: SigningMessage,
                                   signing_dialogue: SigningDialogue) -> None:
        """
        Handle an oef search message.

        :param signing_msg: the signing message
        :param signing_dialogue: the dialogue
        :return: None
        """
        strategy = cast(Strategy, self.context.strategy)
        if not strategy.is_contract_tx:
            self.context.logger.warning(
                "signed transaction handler only for contract case.")
            return None
        self.context.logger.info("transaction signed by decision maker.")
        dialogue_label = DialogueLabel.from_str(
            cast(str, signing_msg.skill_callback_info.get("dialogue_label")))
        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
        fipa_dialogue = fipa_dialogues.dialogues[dialogue_label]
        last_fipa_message = cast(FipaMessage,
                                 fipa_dialogue.last_incoming_message)
        if (last_fipa_message is not None and last_fipa_message.performative
                == FipaMessage.Performative.ACCEPT):
            self.context.logger.info("sending match accept to {}.".format(
                fipa_dialogue.dialogue_label.dialogue_opponent_addr[-5:], ))
            fipa_msg = FipaMessage(
                performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,
                message_id=last_fipa_message.message_id + 1,
                dialogue_reference=fipa_dialogue.dialogue_label.
                dialogue_reference,
                target=last_fipa_message.message_id,
                info={
                    "tx_signature": signing_msg.signed_transaction,
                    "tx_id": signing_msg.dialogue_reference[0],
                },
            )
            fipa_msg.counterparty = fipa_dialogue.dialogue_label.dialogue_opponent_addr
            fipa_dialogue.update(fipa_msg)
            self.context.outbox.put_message(message=fipa_msg)
        elif (last_fipa_message is not None and last_fipa_message.performative
              == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM):
            self.context.logger.info("sending atomic swap tx to ledger.")
            tx_signed = signing_msg.signed_transaction
            tx_digest = self.context.ledger_apis.get_api(
                strategy.ledger_id).send_signed_transaction(
                    tx_signed=tx_signed)
            # TODO; handle case when no tx_digest returned and remove loop
            assert tx_digest is not None, "Error when submitting tx."
            self.context.logger.info("tx_digest={}.".format(tx_digest))
            count = 0
            while (not self.context.ledger_apis.get_api(
                    strategy.ledger_id).is_transaction_settled(tx_digest)
                   and count < 20):
                self.context.logger.info(
                    "waiting for tx to confirm. Sleeping for 3 seconds ...")
                time.sleep(3.0)
                count += 1
            tx_receipt = self.context.ledger_apis.get_api(
                strategy.ledger_id).get_transaction_receipt(
                    tx_digest=tx_digest)
            if tx_receipt is None:
                self.context.logger.info(
                    "failed to get tx receipt for atomic swap.")
            elif tx_receipt.status != 1:
                self.context.logger.info("failed to conduct atomic swap.")
            else:
                self.context.logger.info(
                    "successfully conducted atomic swap. Transaction digest: {}"
                    .format(tx_digest))
                # contract = cast(ERC1155Contract, self.context.contracts.erc1155)
                # result = contract.get_balances(
                #     address=self.context.agent_address,
                #     token_ids=[
                #         int(key)
                #         for key in tx_message.terms.quantities_by_good_id.keys()
                #     ]
                #     + [
                #         int(key)
                #         for key in tx_message.terms.amount_by_currency_id.keys()
                #     ],
                # )
                result = 0
                self.context.logger.info("current balances: {}".format(result))
        else:
            self.context.logger.warning(
                "last message should be of performative accept or match accept."
            )
예제 #28
0
    def handle(self, message: Message) -> None:
        """
        Dispatch message to relevant handler and respond.

        :param message: the message
        :return: None
        """
        tx_message = cast(SigningMessage, message)
        if tx_message.performative == SigningMessage.Performative.SIGNED_MESSAGE:
            self.context.logger.info(
                "[{}]: transaction confirmed by decision maker".format(
                    self.context.agent_name))
            strategy = cast(Strategy, self.context.strategy)
            dialogue_label = DialogueLabel.from_json(
                cast(Dict[str, str],
                     tx_message.skill_callback_info.get("dialogue_label")))
            dialogues = cast(Dialogues, self.context.dialogues)
            dialogue = dialogues.dialogues[dialogue_label]
            last_fipa_message = cast(FipaMessage,
                                     dialogue.last_incoming_message)
            if (last_fipa_message is not None
                    and last_fipa_message.performative
                    == FipaMessage.Performative.ACCEPT):
                self.context.logger.info(
                    "[{}]: sending match accept to {}.".format(
                        self.context.agent_name,
                        dialogue.dialogue_label.dialogue_opponent_addr[-5:],
                    ))
                fipa_msg = FipaMessage(
                    performative=FipaMessage.Performative.
                    MATCH_ACCEPT_W_INFORM,
                    message_id=last_fipa_message.message_id + 1,
                    dialogue_reference=dialogue.dialogue_label.
                    dialogue_reference,
                    target=last_fipa_message.message_id,
                    info={
                        "tx_signature": tx_message.signed_transaction,
                        "tx_id": tx_message.dialogue_reference[0],
                    },
                )
                fipa_msg.counterparty = dialogue.dialogue_label.dialogue_opponent_addr
                dialogue.update(fipa_msg)
                self.context.outbox.put_message(message=fipa_msg)
            elif (last_fipa_message is not None
                  and last_fipa_message.performative
                  == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM
                  and strategy.is_contract_tx):
                self.context.logger.info(
                    "[{}]: sending atomic swap tx to ledger.".format(
                        self.context.agent_name))
                tx_signed = tx_message.signed_transaction
                tx_digest = self.context.ledger_apis.get_api(
                    strategy.ledger_id).send_signed_transaction(
                        tx_signed=tx_signed)
                # TODO; handle case when no tx_digest returned and remove loop
                assert tx_digest is not None, "Error when submitting tx."
                self.context.logger.info("[{}]: tx_digest={}.".format(
                    self.context.agent_name, tx_digest))
                count = 0
                while (not self.context.ledger_apis.get_api(
                        strategy.ledger_id).is_transaction_settled(tx_digest)
                       and count < 20):
                    self.context.logger.info(
                        "[{}]: waiting for tx to confirm. Sleeping for 3 seconds ..."
                        .format(self.context.agent_name))
                    time.sleep(3.0)
                    count += 1
                tx_receipt = self.context.ledger_apis.get_api(
                    strategy.ledger_id).get_transaction_receipt(
                        tx_digest=tx_digest)
                if tx_receipt is None:
                    self.context.logger.info(
                        "[{}]: Failed to get tx receipt for atomic swap.".
                        format(self.context.agent_name))
                elif tx_receipt.status != 1:
                    self.context.logger.info(
                        "[{}]: Failed to conduct atomic swap.".format(
                            self.context.agent_name))
                else:
                    self.context.logger.info(
                        "[{}]: Successfully conducted atomic swap. Transaction digest: {}"
                        .format(self.context.agent_name, tx_digest))
                    # contract = cast(ERC1155Contract, self.context.contracts.erc1155)
                    # result = contract.get_balances(
                    #     address=self.context.agent_address,
                    #     token_ids=[
                    #         int(key)
                    #         for key in tx_message.terms.quantities_by_good_id.keys()
                    #     ]
                    #     + [
                    #         int(key)
                    #         for key in tx_message.terms.amount_by_currency_id.keys()
                    #     ],
                    # )
                    result = 0
                    self.context.logger.info(
                        "[{}]: Current balances: {}".format(
                            self.context.agent_name, result))
            else:
                self.context.logger.warning(
                    "[{}]: last message should be of performative accept or match accept."
                    .format(self.context.agent_name))
        else:
            self.context.logger.info(
                "[{}]: transaction was not successful.".format(
                    self.context.agent_name))
예제 #29
0
    def _handle_signed_message(self, signing_msg: SigningMessage,
                               signing_dialogue: SigningDialogue) -> None:
        """
        Handle an oef search message.

        :param signing_msg: the signing message
        :param signing_dialogue: the dialogue
        :return: None
        """
        strategy = cast(Strategy, self.context.strategy)
        if strategy.is_contract_tx:
            self.context.logger.warning(
                "signed message handler only for non-contract case.")
            return None
        self.context.logger.info("message signed by decision maker.")
        dialogue_label = DialogueLabel.from_str(
            cast(str, signing_msg.skill_callback_info.get("dialogue_label")))
        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
        fipa_dialogue = fipa_dialogues.dialogues[dialogue_label]
        last_fipa_message = cast(FipaMessage,
                                 fipa_dialogue.last_incoming_message)
        if (last_fipa_message is not None and last_fipa_message.performative
                == FipaMessage.Performative.ACCEPT):
            fipa_msg = FipaMessage(
                performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,
                message_id=last_fipa_message.message_id + 1,
                dialogue_reference=fipa_dialogue.dialogue_label.
                dialogue_reference,
                target=last_fipa_message.message_id,
                info={"signature": signing_msg.signed_message.body},
            )
            fipa_msg.counterparty = last_fipa_message.counterparty
            fipa_dialogue.update(fipa_msg)
            self.context.outbox.put_message(message=fipa_msg)
            self.context.logger.info("sending match accept to {}.".format(
                fipa_dialogue.dialogue_label.dialogue_opponent_addr[-5:], ))
        elif (last_fipa_message is not None and last_fipa_message.performative
              == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM):
            counterparty_signature = cast(
                str,
                signing_msg.skill_callback_info.get("counterparty_signature"))
            if counterparty_signature is not None:
                last_signing_msg = cast(Optional[SigningMessage],
                                        signing_dialogue.last_outgoing_message)
                assert (last_signing_msg
                        is not None), "Could not recover last signing message."
                tx_id = last_signing_msg.terms.sender_hash
                if "transactions" not in self.context.shared_state.keys():
                    self.context.shared_state["transactions"] = {}
                self.context.shared_state["transactions"][tx_id] = {
                    "terms": last_signing_msg.terms,
                    "sender_signature": signing_msg.signed_message.body,
                    "counterparty_signature": counterparty_signature,
                }
                self.context.logger.info("sending transaction to controller.")
            else:
                self.context.logger.warning(
                    "transaction has no counterparty signature!")
        else:
            self.context.logger.warning(
                "last message should be of performative accept or match accept."
            )