Exemplo n.º 1
0
    def _handle_cft(self, ml_trade_msg: MlTradeMessage,
                    ml_trade_dialogue: MlTradeDialogue) -> None:
        """
        Handle call for terms.

        :param ml_trade_msg: the ml trade message
        :param ml_trade_dialogue: the dialogue object
        :return: None
        """
        query = ml_trade_msg.query
        self.context.logger.info("got a Call for Terms from {}.".format(
            ml_trade_msg.counterparty[-5:]))
        strategy = cast(Strategy, self.context.strategy)
        if not strategy.is_matching_supply(query):
            self.context.logger.info("query does not match supply.")
            return
        terms = strategy.generate_terms()
        self.context.logger.info(
            "sending to the address={} a Terms message: {}".format(
                ml_trade_msg.counterparty[-5:], terms.values))
        terms_msg = MlTradeMessage(
            performative=MlTradeMessage.Performative.TERMS,
            dialogue_reference=ml_trade_dialogue.dialogue_label.
            dialogue_reference,
            message_id=ml_trade_msg.message_id + 1,
            target=ml_trade_msg.message_id,
            terms=terms,
        )
        terms_msg.counterparty = ml_trade_msg.counterparty
        ml_trade_dialogue.update(terms_msg)
        self.context.outbox.put_message(message=terms_msg)
Exemplo n.º 2
0
    def _handle_accept(self, ml_trade_msg: MlTradeMessage,
                       ml_trade_dialogue: MlTradeDialogue) -> None:
        """
        Handle accept.

        :param ml_trade_msg: the ml trade message
        :param ml_trade_dialogue: the dialogue object
        :return: None
        """
        terms = ml_trade_msg.terms
        self.context.logger.info("got an Accept from {}: {}".format(
            ml_trade_msg.counterparty[-5:], terms.values))
        strategy = cast(Strategy, self.context.strategy)
        if not strategy.is_valid_terms(terms):
            self.context.logger.info("terms are not valid.")
            return
        data = strategy.sample_data(terms.values["batch_size"])
        self.context.logger.info(
            "sending to address={} a Data message: shape={}".format(
                ml_trade_msg.counterparty[-5:], data[0].shape))
        payload = pickle.dumps(data)  # nosec
        data_msg = MlTradeMessage(
            performative=MlTradeMessage.Performative.DATA,
            dialogue_reference=ml_trade_dialogue.dialogue_label.
            dialogue_reference,
            message_id=ml_trade_msg.message_id + 1,
            target=ml_trade_msg.message_id,
            terms=terms,
            payload=payload,
        )
        data_msg.counterparty = ml_trade_msg.counterparty
        ml_trade_dialogue.update(data_msg)
        self.context.outbox.put_message(message=data_msg)
Exemplo n.º 3
0
def test_terms_serialization():
    """Test the serialization for 'terms' speech-act works."""
    msg = MlTradeMessage(
        message_id=2,
        target=1,
        performative=MlTradeMessage.Performative.TERMS,
        terms=Description({
            "foo1": 1,
            "bar1": 2
        }),
    )
    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 = MlTradeMessage.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
Exemplo n.º 4
0
def test_data_serialization():
    """Test the serialization for 'data' speech-act works."""
    msg = MlTradeMessage(
        performative=MlTradeMessage.Performative.DATA,
        terms=Description({
            "foo1": 1,
            "bar1": 2
        }),
        payload=b"some_payload",
    )
    msg.to = "receiver"
    envelope = Envelope(
        to=msg.to,
        sender="sender",
        protocol_id=MlTradeMessage.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 = MlTradeMessage.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
Exemplo n.º 5
0
def test_accept_serialization():
    """Test the serialization for 'accept' speech-act works."""
    msg = MlTradeMessage(
        performative=MlTradeMessage.Performative.ACCEPT,
        terms=Description({
            "foo1": 1,
            "bar1": 2
        }),
        tx_digest="some_tx_digest",
    )
    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 = MlTradeMessage.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
Exemplo n.º 6
0
def test_ml_messge_consistency():
    """Test the consistency of the message."""
    dm = DataModel("ml_datamodel", [Attribute("dataset_id", str, True)])
    query = Query([Constraint("dataset_id", ConstraintType("==", "fmnist"))], model=dm)
    msg = MlTradeMessage(performative=MlTradeMessage.Performative.CFP, query=query)
    with mock.patch.object(MlTradeMessage.Performative, "__eq__", return_value=False):
        assert not msg._is_consistent()
Exemplo n.º 7
0
    def _handle_transaction_digest(
            self, ledger_api_msg: LedgerApiMessage,
            ledger_api_dialogue: LedgerApiDialogue) -> None:
        """
        Handle a message of transaction_digest performative.

        :param ledger_api_message: the ledger api message
        :param ledger_api_dialogue: the ledger api dialogue
        """
        ml_trade_dialogue = ledger_api_dialogue.associated_ml_trade_dialogue
        self.context.logger.info(
            "transaction was successfully submitted. Transaction digest={}".
            format(ledger_api_msg.transaction_digest))
        ml_trade_msg = cast(Optional[MlTradeMessage],
                            ml_trade_dialogue.last_incoming_message)
        assert ml_trade_msg is not None, "Could not retrieve ml_trade message"
        ml_accept = MlTradeMessage(
            performative=MlTradeMessage.Performative.ACCEPT,
            message_id=ml_trade_msg.message_id + 1,
            dialogue_reference=ml_trade_dialogue.dialogue_label.
            dialogue_reference,
            target=ml_trade_msg.message_id,
            tx_digest=ledger_api_msg.transaction_digest.body,
            terms=ml_trade_msg.terms,
        )
        ml_accept.counterparty = ml_trade_msg.counterparty
        ml_trade_dialogue.update(ml_accept)
        self.context.outbox.put_message(message=ml_accept)
        self.context.logger.info(
            "informing counterparty={} of transaction digest={}.".format(
                ml_trade_msg.counterparty[-5:],
                ledger_api_msg.transaction_digest,
            ))
Exemplo n.º 8
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(Strategy, self.context.strategy)
        strategy.is_searching = False
        query = strategy.get_service_query()
        ml_trade_dialogues = cast(MlTradeDialogues,
                                  self.context.ml_trade_dialogues)
        for idx, opponent_address in enumerate(oef_search_msg.agents):
            if idx >= strategy.max_negotiations:
                continue
            self.context.logger.info("sending CFT to agent={}".format(
                opponent_address[-5:]))
            cft_msg = MlTradeMessage(
                performative=MlTradeMessage.Performative.CFP,
                dialogue_reference=ml_trade_dialogues.
                new_self_initiated_dialogue_reference(),
                query=query,
            )
            cft_msg.counterparty = opponent_address
            ml_trade_dialogues.update(cft_msg)
            self.context.outbox.put_message(message=cft_msg)
Exemplo n.º 9
0
def test_cfp_serialization():
    """Test the serialization for 'cfp' speech-act works."""
    msg = MlTradeMessage(
        performative=MlTradeMessage.Performative.CFP,
        query=Query([Constraint("something", ConstraintType(">", 1))]),
    )
    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 = MlTradeMessage.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
Exemplo n.º 10
0
    def decode(obj: bytes) -> Message:
        """
        Decode bytes into a 'MlTrade' message.

        :param obj: the bytes object.
        :return: the 'MlTrade' message.
        """
        message_pb = ProtobufMessage()
        ml_trade_pb = ml_trade_pb2.MlTradeMessage()
        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

        ml_trade_pb.ParseFromString(message_pb.dialogue_message.content)
        performative = ml_trade_pb.WhichOneof("performative")
        performative_id = MlTradeMessage.Performative(str(performative))
        performative_content = dict()  # type: Dict[str, Any]
        if performative_id == MlTradeMessage.Performative.CFP:
            pb2_query = ml_trade_pb.cfp.query
            query = Query.decode(pb2_query)
            performative_content["query"] = query
        elif performative_id == MlTradeMessage.Performative.TERMS:
            pb2_terms = ml_trade_pb.terms.terms
            terms = Description.decode(pb2_terms)
            performative_content["terms"] = terms
        elif performative_id == MlTradeMessage.Performative.ACCEPT:
            pb2_terms = ml_trade_pb.accept.terms
            terms = Description.decode(pb2_terms)
            performative_content["terms"] = terms
            tx_digest = ml_trade_pb.accept.tx_digest
            performative_content["tx_digest"] = tx_digest
        elif performative_id == MlTradeMessage.Performative.DATA:
            pb2_terms = ml_trade_pb.data.terms
            terms = Description.decode(pb2_terms)
            performative_content["terms"] = terms
            payload = ml_trade_pb.data.payload
            performative_content["payload"] = payload
        else:
            raise ValueError(
                "Performative not valid: {}.".format(performative_id))

        return MlTradeMessage(message_id=message_id,
                              dialogue_reference=dialogue_reference,
                              target=target,
                              performative=performative,
                              **performative_content)
Exemplo n.º 11
0
    def _handle_accept(self, ml_trade_msg: MlTradeMessage) -> None:
        """
        Handle accept.

        :param ml_trade_msg: the ml trade message
        :return: None
        """
        terms = ml_trade_msg.terms
        self.context.logger.info("Got an Accept from {}: {}".format(
            ml_trade_msg.counterparty[-5:], terms.values))
        strategy = cast(Strategy, self.context.strategy)
        if not strategy.is_valid_terms(terms):
            return
        batch_size = terms.values["batch_size"]
        data = strategy.sample_data(batch_size)
        self.context.logger.info(
            "[{}]: sending to address={} a Data message: shape={}".format(
                self.context.agent_name, ml_trade_msg.counterparty[-5:],
                data[0].shape))
        payload = pickle.dumps(data)  # nosec
        data_msg = MlTradeMessage(
            performative=MlTradeMessage.Performative.DATA,
            terms=terms,
            payload=payload)
        self.context.outbox.put_message(
            to=ml_trade_msg.counterparty,
            sender=self.context.agent_address,
            protocol_id=MlTradeMessage.protocol_id,
            message=MlTradeSerializer().encode(data_msg),
        )
Exemplo n.º 12
0
    def _handle_cft(self, ml_trade_msg: MlTradeMessage) -> None:
        """
        Handle call for terms.

        :param ml_trade_msg: the ml trade message
        :return: None
        """
        query = ml_trade_msg.query
        self.context.logger.info(
            "Got a Call for Terms from {}: query={}".format(
                ml_trade_msg.counterparty[-5:], query))
        strategy = cast(Strategy, self.context.strategy)
        if not strategy.is_matching_supply(query):
            return
        terms = strategy.generate_terms()
        self.context.logger.info(
            "[{}]: sending to the address={} a Terms message: {}".format(
                self.context.agent_name, ml_trade_msg.counterparty[-5:],
                terms.values))
        terms_msg = MlTradeMessage(
            performative=MlTradeMessage.Performative.TERMS, terms=terms)
        self.context.outbox.put_message(
            to=ml_trade_msg.counterparty,
            sender=self.context.agent_address,
            protocol_id=MlTradeMessage.protocol_id,
            message=MlTradeSerializer().encode(terms_msg),
        )
Exemplo n.º 13
0
    def _handle_search(self, agents: Tuple[str, ...]) -> None:
        """
        Handle the search response.

        :param agents: the agents returned by the search
        :return: None
        """
        if len(agents) == 0:
            self.context.logger.info(
                "[{}]: found 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:], agents))))
        strategy = cast(Strategy, self.context.strategy)
        strategy.is_searching = False
        query = strategy.get_service_query()
        for opponent_address in agents:
            self.context.logger.info("[{}]: sending CFT to agent={}".format(
                self.context.agent_name, opponent_address[-5:]))
            cft_msg = MlTradeMessage(
                performative=MlTradeMessage.Performative.CFP, query=query)
            self.context.outbox.put_message(
                to=opponent_address,
                sender=self.context.agent_address,
                protocol_id=MlTradeMessage.protocol_id,
                message=MlTradeSerializer().encode(cft_msg),
            )
Exemplo n.º 14
0
def test_ml_message_creation():
    """Test the creation of a ml message."""
    dm = DataModel("ml_datamodel", [Attribute("dataset_id", str, True)])
    query = Query([Constraint("dataset_id", ConstraintType("==", "fmnist"))],
                  model=dm)
    msg = MlTradeMessage(performative=MlTradeMessage.Performative.CFP,
                         query=query)
    msg_bytes = MlTradeSerializer().encode(msg)
    recovered_msg = MlTradeSerializer().decode(msg_bytes)
    assert recovered_msg == msg

    terms = Description({
        "batch_size": 5,
        "price": 10,
        "seller_tx_fee": 5,
        "buyer_tx_fee": 2,
        "currency_id": "FET",
        "ledger_id": "fetch",
        "address": "agent1",
    })

    msg = MlTradeMessage(performative=MlTradeMessage.Performative.TERMS,
                         terms=terms)
    msg_bytes = MlTradeSerializer().encode(msg)
    recovered_msg = MlTradeSerializer().decode(msg_bytes)
    assert recovered_msg == msg

    tx_digest = "This is the transaction digest."
    msg = MlTradeMessage(
        performative=MlTradeMessage.Performative.ACCEPT,
        terms=terms,
        tx_digest=tx_digest,
    )
    msg_bytes = MlTradeSerializer().encode(msg)
    recovered_msg = MlTradeSerializer().decode(msg_bytes)
    assert recovered_msg == msg

    data = np.zeros((5, 2)), np.zeros((5, 2))
    payload = pickle.dumps(data)  # nosec
    msg = MlTradeMessage(performative=MlTradeMessage.Performative.DATA,
                         terms=terms,
                         payload=payload)
    msg_bytes = MlTradeSerializer().encode(msg)
    recovered_msg = MlTradeSerializer().decode(msg_bytes)
    assert recovered_msg == msg
    recovered_data = pickle.loads(recovered_msg.payload)  # nosec
    assert np.array_equal(recovered_data, data)
Exemplo n.º 15
0
def test_fipa_incorrect_message(mocked_enforce):
    """Test that we raise an exception when the fipa message is incorrect."""
    with mock.patch.object(ml_trade_message_logger, "error") as mock_logger:
        MlTradeMessage(
            performative=MlTradeMessage.Performative.CFP,
            query=Query([Constraint("something", ConstraintType(">", 1))]),
        )

        mock_logger.assert_any_call("some error")
Exemplo n.º 16
0
def test_encoding_unknown_performative():
    """Test that we raise an exception when the performative is unknown during encoding."""
    msg = MlTradeMessage(
        performative=MlTradeMessage.Performative.CFP,
        query=Query([Constraint("something", ConstraintType(">", 1))]),
    )

    with pytest.raises(ValueError, match="Performative not valid:"):
        with mock.patch.object(MlTradeMessage.Performative,
                               "__eq__",
                               return_value=False):
            MlTradeMessage.serializer.encode(msg)
Exemplo n.º 17
0
    def _handle_unidentified_dialogue(self,
                                      ml_trade_msg: MlTradeMessage) -> None:
        """
        Handle an unidentified dialogue.

        :param fipa_msg: the message
        """
        self.context.logger.info(
            "received invalid ml_trade message={}, unidentified dialogue.".
            format(ml_trade_msg))
        default_dialogues = cast(DefaultDialogues,
                                 self.context.default_dialogues)
        default_msg, _ = default_dialogues.create(
            counterparty=ml_trade_msg.sender,
            performative=DefaultMessage.Performative.ERROR,
            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,
            error_msg="Invalid dialogue.",
            error_data={"ml_trade_message": ml_trade_msg.encode()},
        )
        self.context.outbox.put_message(message=default_msg)
Exemplo n.º 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_SETTLEMENT
        ):
            self.context.logger.info(
                "[{}]: transaction was successful.".format(self.context.agent_name)
            )
            info = tx_msg_response.info
            terms = cast(Description, info.get("terms"))
            ml_accept = MlTradeMessage(
                performative=MlTradeMessage.Performative.ACCEPT,
                tx_digest=tx_msg_response.tx_digest,
                terms=terms,
            )
            self.context.outbox.put_message(
                to=tx_msg_response.tx_counterparty_addr,
                sender=self.context.agent_address,
                protocol_id=MlTradeMessage.protocol_id,
                message=MlTradeSerializer().encode(ml_accept),
            )
            self.context.logger.info(
                "[{}]: Sending accept to counterparty={} with transaction digest={} and terms={}.".format(
                    self.context.agent_name,
                    tx_msg_response.tx_counterparty_addr[-5:],
                    tx_msg_response.tx_digest,
                    terms.values,
                )
            )
        else:
            self.context.logger.info(
                "[{}]: transaction was not successful.".format(self.context.agent_name)
            )
Exemplo n.º 19
0
    def _handle_unidentified_dialogue(self,
                                      ml_trade_msg: MlTradeMessage) -> None:
        """
        Handle an unidentified dialogue.

        :param fipa_msg: the message
        """
        self.context.logger.info(
            "[{}]: received invalid ml_trade message={}, unidentified dialogue."
            .format(self.context.agent_name, ml_trade_msg))
        default_dialogues = cast(DefaultDialogues,
                                 self.context.default_dialogues)
        default_msg = DefaultMessage(
            performative=DefaultMessage.Performative.ERROR,
            dialogue_reference=default_dialogues.
            new_self_initiated_dialogue_reference(),
            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,
            error_msg="Invalid dialogue.",
            error_data={"ml_trade_message": ml_trade_msg.encode()},
        )
        default_msg.counterparty = ml_trade_msg.counterparty
        default_dialogues.update(default_msg)
        self.context.outbox.put_message(message=default_msg)
Exemplo n.º 20
0
def test_ml_wrong_message_creation():
    """Test the creation of a ml message."""
    msg = MlTradeMessage(performative=MlTradeMessage.Performative.CFP, query="")
    assert not msg._is_consistent()
Exemplo n.º 21
0
    def _handle_terms(self, ml_trade_msg: MlTradeMessage) -> None:
        """
        Handle the terms of the request.

        :param ml_trade_msg: the ml trade message
        :return: None
        """
        terms = ml_trade_msg.terms
        self.context.logger.info(
            "Received terms message from {}: terms={}".format(
                ml_trade_msg.counterparty[-5:], terms.values
            )
        )

        strategy = cast(Strategy, self.context.strategy)
        acceptable = strategy.is_acceptable_terms(terms)
        affordable = strategy.is_affordable_terms(terms)
        if not acceptable and affordable:
            self.context.logger.info(
                "[{}]: rejecting, terms are not acceptable and/or affordable".format(
                    self.context.agent_name
                )
            )
            return

        if strategy.is_ledger_tx:
            # propose the transaction to the decision maker for settlement on the ledger
            tx_msg = TransactionMessage(
                performative=TransactionMessage.Performative.PROPOSE_FOR_SETTLEMENT,
                skill_callback_ids=[PublicId("fetchai", "ml_train", "0.1.0")],
                tx_id=strategy.get_next_transition_id(),
                tx_sender_addr=self.context.agent_addresses[terms.values["ledger_id"]],
                tx_counterparty_addr=terms.values["address"],
                tx_amount_by_currency_id={
                    terms.values["currency_id"]: -terms.values["price"]
                },
                tx_sender_fee=terms.values["buyer_tx_fee"],
                tx_counterparty_fee=terms.values["seller_tx_fee"],
                tx_quantities_by_good_id={},
                ledger_id=terms.values["ledger_id"],
                info={"terms": terms, "counterparty_addr": ml_trade_msg.counterparty},
            )  # this is used to send the terms later - because the seller is stateless and must know what terms have been accepted
            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:
            # accept directly with a dummy transaction digest, no settlement
            ml_accept = MlTradeMessage(
                performative=MlTradeMessage.Performative.ACCEPT,
                tx_digest=DUMMY_DIGEST,
                terms=terms,
            )
            self.context.outbox.put_message(
                to=ml_trade_msg.counterparty,
                sender=self.context.agent_address,
                protocol_id=MlTradeMessage.protocol_id,
                message=MlTradeSerializer().encode(ml_accept),
            )
            self.context.logger.info(
                "[{}]: sending dummy transaction digest ...".format(
                    self.context.agent_name
                )
            )
Exemplo n.º 22
0
    def _handle_terms(self, ml_trade_msg: MlTradeMessage,
                      ml_trade_dialogue: MlTradeDialogue) -> None:
        """
        Handle the terms of the request.

        :param ml_trade_msg: the ml trade message
        :param ml_trade_dialogue: the dialogue object
        :return: None
        """
        terms = ml_trade_msg.terms
        self.context.logger.info(
            "received terms message from {}: terms={}".format(
                ml_trade_msg.counterparty[-5:], terms.values))

        strategy = cast(Strategy, self.context.strategy)
        acceptable = strategy.is_acceptable_terms(terms)
        affordable = strategy.is_affordable_terms(terms)
        if not acceptable and affordable:
            self.context.logger.info(
                "rejecting, terms are not acceptable and/or affordable")
            return

        if strategy.is_ledger_tx:
            # construct a tx for settlement on the ledger
            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=Terms(
                    ledger_id=terms.values["ledger_id"],
                    sender_address=self.context.agent_addresses[
                        terms.values["ledger_id"]],
                    counterparty_address=terms.values["address"],
                    amount_by_currency_id={
                        terms.values["currency_id"]: -terms.values["price"]
                    },
                    is_sender_payable_tx_fee=True,
                    quantities_by_good_id={"ml_training_data": 1},
                    nonce=uuid.uuid4().hex,
                    fee_by_currency_id={terms.values["currency_id"]: 1},
                ),
            )
            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_ml_trade_dialogue = ml_trade_dialogue
            self.context.outbox.put_message(message=ledger_api_msg)
            self.context.logger.info(
                "requesting transfer transaction from ledger api...")
        else:
            # accept directly with a dummy transaction digest, no settlement
            ml_accept = MlTradeMessage(
                performative=MlTradeMessage.Performative.ACCEPT,
                dialogue_reference=ml_trade_dialogue.dialogue_label.
                dialogue_reference,
                message_id=ml_trade_msg.message_id + 1,
                target=ml_trade_msg.message_id,
                tx_digest=DUMMY_DIGEST,
                terms=terms,
            )
            ml_accept.counterparty = ml_trade_msg.counterparty
            ml_trade_dialogue.update(ml_accept)
            self.context.outbox.put_message(message=ml_accept)
            self.context.logger.info("sending dummy transaction digest ...")