def _on_decline(self, decline: FIPAMessage, dialogue: Dialogue) -> None: """ Handle a Decline. :param decline: the Decline message :param dialogue: the dialogue :return: None """ logger.debug("[{}]: on_decline: msg_id={}, dialogue_id={}, origin={}, target={}" .format(self.context.agent_name, decline.get("id"), decline.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, decline.get("target"))) target = decline.get("target") dialogues = cast(Dialogues, self.context.dialogues) if target == 1: dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_CFP, dialogue.is_self_initiated) elif target == 2: dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_PROPOSE, dialogue.is_self_initiated) transactions = cast(Transactions, self.context.transactions) transaction_msg = transactions.pop_pending_proposal(dialogue.dialogue_label, target) strategy = cast(Strategy, self.context.strategy) if strategy.is_world_modeling: pass # TODO # strategy.world_state.update_on_declined_propose(transaction_msg) elif target == 3: dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_ACCEPT, dialogue.is_self_initiated) transactions = cast(Transactions, self.context.transactions) transaction_msg = transactions.pop_pending_initial_acceptance(dialogue.dialogue_label, target) transactions.pop_locked_tx(transaction_msg)
def is_valid_next_message(self, fipa_msg: FIPAMessage) -> bool: """ Check whether this is a valid next message in the dialogue. :return: True if yes, False otherwise. """ this_message_id = fipa_msg.get("message_id") this_target = fipa_msg.get("target") this_performative = cast(FIPAMessage.Performative, fipa_msg.get("performative")) last_outgoing_message = self.last_outgoing_message if last_outgoing_message is None: result = this_message_id == FIPAMessage.STARTING_MESSAGE_ID and \ this_target == FIPAMessage.STARTING_TARGET and \ this_performative == FIPAMessage.Performative.CFP else: last_message_id = cast(int, last_outgoing_message.get("message_id")) last_target = cast(int, last_outgoing_message.get("target")) last_performative = cast(FIPAMessage.Performative, last_outgoing_message.get("performative")) result = this_message_id == last_message_id + 1 and \ this_target == last_target + 1 and \ last_performative in VALID_PREVIOUS_PERFORMATIVES[this_performative] return result
def _on_services_search_result(self, agent_pbks: List[str], is_searching_for_sellers: bool) -> None: """ Process the search result for services. :param agent_pbks: the agent public keys matching the search query :param is_searching_for_sellers: whether it is searching for sellers or not :return: None """ agent_pbks_set = set(agent_pbks) if self.crypto.public_key in agent_pbks_set: agent_pbks_set.remove(self.crypto.public_key) agent_pbks = list(agent_pbks_set) searched_for = "sellers" if is_searching_for_sellers else "buyers" logger.debug("[{}]: Found potential {}: {}".format( self.agent_name, searched_for, agent_pbks)) services = self.game_instance.build_services_dict( is_supply=not is_searching_for_sellers) if services is None: response = "demanding" if is_searching_for_sellers else "supplying" logger.debug("[{}]: No longer {} any goods...".format( self.agent_name, response)) return for agent_pbk in agent_pbks: dialogue = self.game_instance.dialogues.create_self_initiated( agent_pbk, self.crypto.public_key, not is_searching_for_sellers) cfp = FIPAMessage( message_id=STARTING_MESSAGE_ID, dialogue_id=dialogue.dialogue_label.dialogue_id, target=STARTING_MESSAGE_TARGET, performative=FIPAMessage.Performative.CFP, query=json.dumps(services).encode("utf-8"), ) dialogue.outgoing_extend([cfp]) cfp_bytes = FIPASerializer().encode(cfp) logger.debug( "[{}]: send_cfp_as_{}: msg_id={}, dialogue_id={}, destination={}, target={}, services={}" .format( self.agent_name, dialogue.role, cfp.get("id"), cfp.get("dialogue_id"), agent_pbk, cfp.get("target"), services, )) self.mailbox.outbox.put_message( to=agent_pbk, sender=self.crypto.public_key, protocol_id=FIPAMessage.protocol_id, message=cfp_bytes, )
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 = cast(int, propose.get("message_id")) + 1 strategy = cast(Strategy, self.context.strategy) proposals = cast(List[Description], propose.get("proposal")) logger.debug("[{}]: on Propose as {}.".format(self.context.agent_name, dialogue.role)) for num, proposal_description in enumerate(proposals): if num > 0: continue # TODO: allow for dialogue branching with multiple proposals transaction_msg = generate_transaction_message( proposal_description, dialogue.dialogue_label, dialogue.is_seller, self.context.agent_public_key) if strategy.is_profitable_transaction( transaction_msg, is_seller=dialogue.is_seller): logger.info("[{}]: Accepting propose (as {}).".format( self.context.agent_name, dialogue.role)) transactions = cast(Transactions, self.context.transactions) transactions.add_locked_tx(transaction_msg, as_seller=dialogue.is_seller) 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.get("message_id")) else: 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.get("message_id")) dialogues = cast(Dialogues, self.context.dialogues) dialogues.dialogue_stats.add_dialogue_endstate( Dialogue.EndState.DECLINED_PROPOSE, dialogue.is_self_initiated) 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))
def _on_match_accept(self, match_accept: FIPAMessage, dialogue: Dialogue) -> None: """ Handle a matching Accept. :param match_accept: the MatchAccept message :param dialogue: the dialogue :return: None """ transactions = cast(Transactions, self.context.transactions) assert dialogue.dialogue_label in transactions.pending_initial_acceptances \ and match_accept.get("target") in transactions.pending_initial_acceptances[dialogue.dialogue_label] logger.debug("[{}]: on_match_accept: msg_id={}, dialogue_id={}, origin={}, target={}" .format(self.context.agent_name, match_accept.get("id"), match_accept.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, match_accept.get("target"))) transaction_msg = transactions.pop_pending_initial_acceptance(dialogue.dialogue_label, cast(int, match_accept.get("target"))) self.context.decision_maker_message_queue.put(transaction_msg)
def test_fipa_cfp_serialization_bytes(): """Test that the serialization - deserialization for the 'fipa' protocol works.""" query = b'Hello' msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=0, performative=FIPAMessage.Performative.CFP, query=query) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to="receiver", sender="sender", protocol_id=FIPAMessage.protocol_id, message=msg_bytes) envelope_bytes = envelope.encode() actual_envelope = Envelope.decode(envelope_bytes) expected_envelope = envelope assert expected_envelope == actual_envelope actual_msg = FIPASerializer().decode(actual_envelope.message) expected_msg = msg assert expected_msg == actual_msg deserialised_msg = FIPASerializer().decode(envelope.message) assert msg.get("performative") == deserialised_msg.get("performative")
def _handle_propose(self, msg: FIPAMessage, sender: str, message_id: int, dialogue: Dialogue) -> None: """ Handle the propose. :param msg: the message :param sender: the sender :param message_id: the message id :param dialogue: the dialogue object :return: None """ new_message_id = message_id + 1 new_target_id = message_id proposals = cast(List[Description], msg.get("proposal")) if proposals is not []: # only take the first proposal proposal = proposals[0] logger.info("[{}]: received proposal={} from sender={}".format( self.context.agent_name, proposal.values, sender[-5:])) strategy = cast(Strategy, self.context.strategy) acceptable = strategy.is_acceptable_proposal(proposal) affordable = self.context.ledger_apis.token_balance( 'fetchai', cast(str, self.context.agent_addresses.get('fetchai'))) >= cast( int, proposal.values.get('price')) if acceptable and affordable: logger.info( "[{}]: accepting the proposal from sender={}".format( self.context.agent_name, sender[-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=sender, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(accept_msg)) else: logger.info( "[{}]: declining the proposal from sender={}".format( self.context.agent_name, sender[-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=sender, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(decline_msg))
def _handle_match_accept(self, msg: FIPAMessage, sender: str, message_id: int, dialogue: Dialogue) -> None: """ Handle the match accept. :param msg: the message :param sender: the sender :param message_id: the message id :param dialogue: the dialogue object :return: None """ logger.info( "[{}]: received MATCH_ACCEPT_W_ADDRESS from sender={}".format( self.context.agent_name, sender[-5:])) address = cast(str, msg.get("address")) proposal = cast(Description, dialogue.proposal) tx_msg = TransactionMessage( performative=TransactionMessage.Performative.PROPOSE, skill_id="carpark_client", transaction_id="transaction0", sender=self.context.agent_public_keys['fetchai'], counterparty=address, is_sender_buyer=True, currency_pbk="FET", amount=proposal.values['price'], sender_tx_fee=0, counterparty_tx_fee=0, quantities_by_good_pbk={}, dialogue_label=dialogue.dialogue_label.json, ledger_id='fetchai') self.context.decision_maker_message_queue.put_nowait(tx_msg) logger.info( "[{}]: proposing the transaction to the decision maker. Waiting for confirmation ..." .format(self.context.agent_name))
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
def test_error_skill_unsupported_protocol(self): """Test the unsupported error message.""" msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=0, performative=FIPAMessage.Performative.ACCEPT) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to=self.public_key, sender=self.public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) self.my_error_handler.send_unsupported_protocol(envelope) envelope = self.my_aea.inbox.get(block=True, timeout=1.0) msg = DefaultSerializer().decode(envelope.message) assert msg.get("type") == DefaultMessage.Type.ERROR assert msg.get("error_code" ) == DefaultMessage.ErrorCode.UNSUPPORTED_PROTOCOL.value
def test_error_invalid_message(self): """Test the invalid message.""" msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=0, performative=FIPAMessage.Performative.ACCEPT) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to=self.public_key, sender=self.public_key, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.my_error_handler.send_invalid_message(envelope) envelope = self.my_aea.inbox.get(block=True, timeout=1.0) msg = DefaultSerializer().decode(envelope.message) assert msg.get("type") == DefaultMessage.Type.ERROR assert msg.get( "error_code") == DefaultMessage.ErrorCode.INVALID_MESSAGE.value
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 """ logger.debug("[{}]: on propose as {}.".format(self.context.agent_name, dialogue.role)) proposals = cast(List[Description], propose.get("proposal")) for num, proposal_description in enumerate(proposals): if num > 0: continue # TODO: allow for dialogue branching with multiple proposals transaction_id = generate_transaction_id(self.context.agent_public_key, dialogue.dialogue_label.dialogue_opponent_pbk, dialogue.dialogue_label, dialogue.is_seller) transaction_msg = TransactionMessage(transaction_id=transaction_id, sender=self.context.agent_public_key, counterparty=dialogue.dialogue_label.dialogue_opponent_pbk, currency='FET', amount=proposal_description.values['amount'], is_sender_buyer=not dialogue.is_seller, sender_tx_fee=1, counterparty_tx_fee=1, quantities_by_good_pbk=proposal_description.values['description']) new_msg_id = cast(int, propose.get("id")) + 1 strategy = cast(Strategy, self.context.strategy) transactions = cast(Transactions, self.context.transactions) ownership_state_after_locks = transactions.ownership_state_after_locks(self.context.ownership_state, is_seller=dialogue.is_seller) if strategy.is_profitable_transaction(self.context.preferences, ownership_state_after_locks, transaction_msg): logger.debug("[{}]: Accepting propose (as {}).".format(self.context.agent_name, dialogue.role)) transactions.add_locked_tx(transaction_msg, as_seller=dialogue.is_seller) transactions.add_pending_initial_acceptance(dialogue.dialogue_label, new_msg_id, transaction_msg) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=propose.get("dialogue_id"), target=propose.get("id"), performative=FIPAMessage.Performative.ACCEPT) dialogue.outgoing_extend(msg) msg_bytes = FIPASerializer().encode(msg) result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) else: logger.debug("[{}]: Declining propose (as {})".format(self.context.agent_name, dialogue.role)) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=propose.get("dialogue_id"), target=propose.get("id"), performative=FIPAMessage.Performative.DECLINE) dialogue.outgoing_extend(msg) msg_bytes = FIPASerializer().encode(msg) result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) dialogues = cast(Dialogues, self.context.dialogues) dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_PROPOSE, dialogue.is_self_initiated) self.context.outbox.put(result)
def _on_match_accept(self, match_accept: FIPAMessage, dialogue: Dialogue) -> None: """ Handle a matching Accept. :param match_accept: the MatchAccept message :param dialogue: the dialogue :return: None """ logger.debug( "[{}]: on_match_accept: msg_id={}, dialogue_id={}, origin={}, target={}" .format(self.context.agent_name, match_accept.get("message_id"), match_accept.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, match_accept.get("target"))) transactions = cast(Transactions, self.context.transactions) transaction_msg = transactions.pop_pending_initial_acceptance( dialogue.dialogue_label, cast(int, match_accept.get("target"))) # update skill id to route back to tac participation skill transaction_msg.set('skill_id', 'tac_participation_skill') self.context.decision_maker_message_queue.put(transaction_msg)
def _handle_cfp(self, msg: FIPAMessage, sender: str, message_id: int, 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 sender: the sender :param message_id: the message id :param dialogue: the dialogue object :return: None """ new_message_id = message_id + 1 new_target = message_id logger.info("[{}]: received CFP from sender={}".format( self.context.agent_name, sender[-5:])) query = cast(Query, msg.get("query")) strategy = cast(Strategy, self.context.strategy) if strategy.is_matching_supply(query): proposal, weather_data = strategy.generate_proposal_and_data(query) dialogue.weather_data = weather_data dialogue.proposal = proposal logger.info( "[{}]: sending sender={} a PROPOSE with proposal={}".format( self.context.agent_name, sender[-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=sender, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(proposal_msg)) else: logger.info("[{}]: declined the CFP from sender={}".format( self.context.agent_name, sender[-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=sender, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(decline_msg))
def test_serialisation_fipa(self): """Tests a Value Error flag for wrong CFP query.""" with pytest.raises(ValueError): msg = FIPAMessage(performative=FIPAMessage.Performative.CFP, message_id=0, dialogue_reference=(str(0), ''), target=1, query=None) with mock.patch( "aea.protocols.fipa.message.FIPAMessage.Performative" ) as mock_performative_enum: mock_performative_enum.CFP.value = "unknown" FIPASerializer().encode(msg), "Raises Value Error" with pytest.raises(ValueError): msg.set("query", "Hello") # query type is not supported FIPASerializer().encode(msg) with pytest.raises(ValueError): cfp_msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=0, performative=FIPAMessage.Performative.CFP, query=b"hello") cfp_msg.set("query", "hello") fipa_msg = fipa_pb2.FIPAMessage() fipa_msg.message_id = cfp_msg.get("message_id") dialogue_reference = cast(Dict[str, str], cfp_msg.get("dialogue_reference")) fipa_msg.dialogue_starter_reference = dialogue_reference[0] fipa_msg.dialogue_responder_reference = dialogue_reference[1] fipa_msg.target = cfp_msg.get("target") performative = fipa_pb2.FIPAMessage.CFP() fipa_msg.cfp.CopyFrom(performative) fipa_bytes = fipa_msg.SerializeToString() # The encoded message is not a valid FIPA message. FIPASerializer().decode(fipa_bytes) with pytest.raises(ValueError): cfp_msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=0, performative=FIPAMessage.Performative.CFP, query=b"hello") with mock.patch( "aea.protocols.fipa.message.FIPAMessage.Performative" ) as mock_performative_enum: mock_performative_enum.CFP.value = "unknown" fipa_msg = fipa_pb2.FIPAMessage() fipa_msg.message_id = cfp_msg.get("message_id") dialogue_reference = cast(Dict[str, str], cfp_msg.get("dialogue_reference")) fipa_msg.dialogue_starter_reference = dialogue_reference[0] fipa_msg.dialogue_responder_reference = dialogue_reference[1] fipa_msg.target = cfp_msg.get("target") performative = fipa_pb2.FIPAMessage.CFP() fipa_msg.cfp.CopyFrom(performative) fipa_bytes = fipa_msg.SerializeToString() # The encoded message is not a FIPA message FIPASerializer().decode(fipa_bytes)
def test_performative_match_accept(): """Test the serialization - deserialization of the match_accept performative.""" msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=1, performative=FIPAMessage.Performative.MATCH_ACCEPT) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to="receiver", sender="sender", protocol_id=FIPAMessage.protocol_id, message=msg_bytes) 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")
def test_serialisation_fipa(self): """Tests a Value Error flag for wrong CFP query.""" with pytest.raises(ValueError): msg = FIPAMessage(performative=FIPAMessage.Performative.CFP, message_id=0, dialogue_id=0, destination="publicKey", target=1) with mock.patch("aea.protocols.fipa.message.FIPAMessage.Performative")\ as mock_performative_enum: mock_performative_enum.CFP.value = "unknown" assert FIPASerializer().encode(msg), "Raises Value Error" with pytest.raises(ValueError): msg.set("query", "Hello") assert FIPASerializer().encode(msg), "Query type is Supported!" with pytest.raises(ValueError): cfp_msg = FIPAMessage(message_id=0, dialogue_id=0, target=0, performative=FIPAMessage.Performative.CFP, query=b"hello") cfp_msg.set("query", "hello") fipa_msg = fipa_pb2.FIPAMessage() fipa_msg.message_id = cfp_msg.get("id") fipa_msg.dialogue_id = cfp_msg.get("dialogue_id") fipa_msg.target = cfp_msg.get("target") performative = fipa_pb2.FIPAMessage.CFP() fipa_msg.cfp.CopyFrom(performative) fipa_bytes = fipa_msg.SerializeToString() assert FIPASerializer().decode(fipa_bytes),\ "The encoded message is a valid FIPA message." with pytest.raises(ValueError): cfp_msg = FIPAMessage(message_id=0, dialogue_id=0, target=0, performative=FIPAMessage.Performative.CFP, query=b"hello") with mock.patch("aea.protocols.fipa.message.FIPAMessage.Performative")\ as mock_performative_enum: mock_performative_enum.CFP.value = "unknown" fipa_msg = fipa_pb2.FIPAMessage() fipa_msg.message_id = cfp_msg.get("id") fipa_msg.dialogue_id = cfp_msg.get("dialogue_id") fipa_msg.target = cfp_msg.get("target") performative = fipa_pb2.FIPAMessage.CFP() fipa_msg.cfp.CopyFrom(performative) fipa_bytes = fipa_msg.SerializeToString() assert FIPASerializer().decode(fipa_bytes),\ "The encoded message is a FIPA message"
def test_performative_inform(): """Test the serialization-deserialization of the inform performative.""" msg = FIPAMessage(message_id=0, dialogue_reference=(str(0), ''), target=1, performative=FIPAMessage.Performative.INFORM, json_data={"foo": "bar"}) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to="receiver", sender="sender", protocol_id=FIPAMessage.protocol_id, message=msg_bytes) envelope_bytes = envelope.encode() actual_envelope = Envelope.decode(envelope_bytes) expected_envelope = envelope assert expected_envelope == actual_envelope deserialised_msg = FIPASerializer().decode(envelope.message) assert msg.get("performative") == deserialised_msg.get("performative")
def _handle_inform(self, msg: FIPAMessage, sender: str, message_id: int, dialogue: Dialogue) -> None: """ Handle the match inform. :param msg: the message :param sender: the sender :param message_id: the message id :param dialogue: the dialogue object :return: None """ logger.info("[{}]: received INFORM from sender={}".format( self.context.agent_name, sender[-5:])) json_data = cast(dict, msg.get("json_data")) if 'weather_data' in json_data.keys(): weather_data = json_data['weather_data'] logger.info("[{}]: received the following weather data={}".format( self.context.agent_name, pprint.pformat(weather_data))) else: logger.info("[{}]: received no data from sender={}".format( self.context.agent_name, sender[-5:]))
def _handle_inform(self, msg: FIPAMessage, sender: str, message_id: int, dialogue: Dialogue) -> None: """ Handle the INFORM. If the INFORM message contains the transaction_digest then verify that it is settled, otherwise do nothing. If the transaction is settled send the weather data, otherwise do nothing. :param msg: the message :param sender: the sender :param message_id: the message id :param dialogue: the dialogue object :return: None """ new_message_id = message_id + 1 new_target = message_id logger.info("[{}]: received INFORM from sender={}".format( self.context.agent_name, sender[-5:])) json_data = cast(dict, msg.get("json_data")) if "Done" in json_data: inform_msg = FIPAMessage( message_id=new_message_id, dialogue_reference=dialogue.dialogue_label.dialogue_reference, target=new_target, performative=FIPAMessage.Performative.INFORM, json_data=dialogue.weather_data) dialogue.outgoing_extend(inform_msg) # import pdb; pdb.set_trace() self.context.outbox.put_message( to=sender, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(inform_msg)) # dialogues = cast(Dialogues, self.context.dialogues) # dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.SUCCESSFUL) else: logger.warning("I didn't receive the transaction digest!")
def _handle_inform(self, msg: FIPAMessage, sender: str, message_id: int, dialogue: Dialogue) -> None: """ Handle the match inform. :param msg: the message :param sender: the sender :param message_id: the message id :param dialogue: the dialogue object :return: None """ logger.info("[{}]: received INFORM from sender={}".format( self.context.agent_name, sender[-5:])) json_data = cast(dict, msg.get("json_data")) if 'message_type' in json_data and json_data[ 'message_type'] == 'car_park_data': logger.info("[{}]: received the following carpark data={}".format( self.context.agent_name, pprint.pformat(json_data))) # dialogues = cast(Dialogues, self.context.dialogues) # dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.SUCCESSFUL) else: logger.info("[{}]: received no data from sender={}".format( self.context.agent_name, sender[-5:]))
def _on_accept(self, accept: FIPAMessage, dialogue: Dialogue) -> None: """ Handle an Accept. :param accept: the Accept message :param dialogue: the dialogue :return: None """ logger.debug( "[{}]: on_accept: msg_id={}, dialogue_id={}, origin={}, target={}". format(self.context.agent_name, accept.get("message_id"), accept.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, accept.get("target"))) new_msg_id = cast(int, accept.get("message_id")) + 1 transactions = cast(Transactions, self.context.transactions) transaction_msg = transactions.pop_pending_proposal( dialogue.dialogue_label, cast(int, accept.get("target"))) strategy = cast(Strategy, self.context.strategy) if strategy.is_profitable_transaction(transaction_msg, is_seller=dialogue.is_seller): logger.info("[{}]: locking the current state (as {}).".format( self.context.agent_name, dialogue.role)) transactions.add_locked_tx(transaction_msg, as_seller=dialogue.is_seller) self.context.decision_maker_message_queue.put(transaction_msg) else: 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.get("message_id"), ) dialogue.outgoing_extend(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_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(fipa_msg))
def _on_accept(self, accept: FIPAMessage, dialogue: Dialogue) -> None: """ Handle an Accept. :param accept: the Accept message :param dialogue: the dialogue :return: None """ transactions = cast(Transactions, self.context.transactions) assert dialogue.dialogue_label in transactions.pending_proposals \ and accept.get("target") in transactions.pending_proposals[dialogue.dialogue_label] logger.debug("[{}]: on_accept: msg_id={}, dialogue_id={}, origin={}, target={}" .format(self.context.agent_name, accept.get("id"), accept.get("dialogue_id"), dialogue.dialogue_label.dialogue_opponent_pbk, accept.get("target"))) new_msg_id = cast(int, accept.get("id")) + 1 transaction_msg = transactions.pop_pending_proposal(dialogue.dialogue_label, cast(int, accept.get("target"))) strategy = cast(Strategy, self.context.strategy) ownership_state_after_locks = transactions.ownership_state_after_locks(self.context.ownership_state, is_seller=dialogue.is_seller) if strategy.is_profitable_transaction(self.context.preferences, ownership_state_after_locks, transaction_msg): if strategy.is_world_modeling: pass # TODO # strategy.world_state.update_on_initial_accept(transaction_msg) logger.debug("[{}]: Locking the current state (as {}).".format(self.context.agent_name, dialogue.role)) transactions.add_locked_tx(transaction_msg, as_seller=dialogue.is_seller) self.context.decision_maker_message_queue.put(transaction_msg) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=accept.get("dialogue_id"), target=accept.get("id"), performative=FIPAMessage.Performative.MATCH_ACCEPT) dialogue.outgoing_extend(msg) msg_bytes = FIPASerializer().encode(msg) result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) else: logger.debug("[{}]: Decline the accept (as {}).".format(self.context.agent_name, dialogue.role)) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=accept.get("dialogue_id"), target=accept.get("id"), performative=FIPAMessage.Performative.DECLINE) dialogue.outgoing_extend(msg) msg_bytes = FIPASerializer().encode(msg) result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) dialogues = cast(Dialogues, self.context.dialogues) dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_ACCEPT, dialogue.is_self_initiated) self.context.outbox.put(result)
def _on_cfp(self, cfp: FIPAMessage, dialogue: Dialogue) -> None: """ Handle a CFP. :param cfp: the fipa message containing the CFP :param dialogue: the dialogue :return: None """ strategy = cast(Strategy, self.context.strategy) transactions = cast(Transactions, self.context.transactions) ownership_state_after_locks = transactions.ownership_state_after_locks(self.context.ownership_state, is_seller=dialogue.is_seller) own_service_description = strategy.get_own_service_description(ownership_state_after_locks, is_supply=dialogue.is_seller) new_msg_id = cast(int, cfp.get("id")) + 1 cfp_query = cfp.get("query") cfp_query = cast(Query, cfp_query) decline = False if not cfp_query.check(own_service_description): decline = True logger.debug("[{}]: Current holdings do not satisfy CFP query.".format(self.context.agent_name)) else: proposal_description = strategy.get_proposal_for_query(cfp_query, self.context.preferences, ownership_state_after_locks, is_seller=dialogue.is_seller, tx_fee=1.0) if proposal_description is None: decline = True logger.debug("[{}]: Current strategy does not generate proposal that satisfies CFP query.".format(self.context.agent_name)) if decline: logger.debug("[{}]: sending to {} a Decline{}".format(self.context.agent_name, dialogue.dialogue_label.dialogue_opponent_pbk, pprint.pformat({ "msg_id": new_msg_id, "dialogue_id": cfp.get("dialogue_id"), "origin": dialogue.dialogue_label.dialogue_opponent_pbk, "target": cfp.get("target") }))) msg = FIPAMessage(message_id=new_msg_id, dialogue_id=cfp.get("dialogue_id"), performative=FIPAMessage.Performative.DECLINE, target=cfp.get("id")) dialogue.outgoing_extend(msg) msg_bytes = FIPASerializer().encode(msg) result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) dialogues = cast(Dialogues, self.context.dialogues) dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.DECLINED_CFP, dialogue.is_self_initiated) else: assert proposal_description is not None transaction_id = generate_transaction_id(self.context.agent_public_key, dialogue.dialogue_label.dialogue_opponent_pbk, dialogue.dialogue_label, dialogue.is_seller) transaction_msg = TransactionMessage(transaction_id=transaction_id, sender=self.context.agent_public_key, counterparty=dialogue.dialogue_label.dialogue_opponent_pbk, currency='FET', amount=proposal_description.values['amount'], is_sender_buyer=not dialogue.is_seller, sender_tx_fee=1, counterparty_tx_fee=1, quantities_by_good_pbk=proposal_description.values['description']) transactions = cast(Transactions, self.context.transactions) transactions.add_pending_proposal(dialogue.dialogue_label, new_msg_id, transaction_msg) logger.debug("[{}]: sending to {} a Propose{}".format(self.context.agent_name, dialogue.dialogue_label.dialogue_opponent_pbk, pprint.pformat({ "msg_id": new_msg_id, "dialogue_id": cfp.get("dialogue_id"), "origin": dialogue.dialogue_label.dialogue_opponent_pbk, "target": cfp.get("id"), "propose": proposal_description.values }))) msg = FIPAMessage(performative=FIPAMessage.Performative.PROPOSE, message_id=new_msg_id, dialogue_id=cfp.get("dialogue_id"), target=cfp.get("id"), proposal=[proposal_description]) dialogue.outgoing_extend(msg) msg_bytes = FIPASerializer().encode(msg) result = Envelope(to=dialogue.dialogue_label.dialogue_opponent_pbk, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) self.context.outbox.put(result)
def _handle_inform(self, msg: FIPAMessage, sender: str, message_id: int, dialogue: Dialogue) -> None: """ Handle the INFORM. If the INFORM message contains the transaction_digest then verify that it is settled, otherwise do nothing. If the transaction is settled send the weather data, otherwise do nothing. :param msg: the message :param sender: the sender :param message_id: the message id :param dialogue: the dialogue object :return: None """ new_message_id = message_id + 1 new_target = message_id logger.info("[{}]: received INFORM from sender={}".format( self.context.agent_name, sender[-5:])) json_data = cast(dict, msg.get("json_data")) if "transaction_digest" in json_data.keys(): tx_digest = json_data['transaction_digest'] logger.info( "[{}]: checking whether transaction={} has been received ...". format(self.context.agent_name, tx_digest)) proposal = cast(Description, dialogue.proposal) total_price = cast(int, proposal.values.get("price")) is_settled = self.context.ledger_apis.is_tx_settled( 'fetchai', tx_digest, total_price) if is_settled: token_balance = self.context.ledger_apis.token_balance( 'fetchai', cast(str, self.context.agent_addresses.get('fetchai'))) strategy = cast(Strategy, self.context.strategy) strategy.record_balance(token_balance) logger.info( "[{}]: transaction={} settled, new balance={}. Sending data to sender={}" .format(self.context.agent_name, tx_digest, token_balance, sender[-5:])) inform_msg = FIPAMessage( message_id=new_message_id, dialogue_reference=dialogue.dialogue_label. dialogue_reference, target=new_target, performative=FIPAMessage.Performative.INFORM, json_data=dialogue.carpark_data) dialogue.outgoing_extend(inform_msg) # import pdb; pdb.set_trace() self.context.outbox.put_message( to=sender, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(inform_msg)) # dialogues = cast(Dialogues, self.context.dialogues) # dialogues.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.SUCCESSFUL) strategy.db.add_in_progress_transaction( tx_digest, sender[-5:], self.context.agent_name, total_price) strategy.db.set_transaction_complete(tx_digest) strategy.db.set_dialogue_status(str(dialogue.dialogue_label), sender[-5:], "transaction_complete", "send_request_data") else: logger.info( "[{}]: transaction={} not settled, aborting".format( self.context.agent_name, tx_digest)) else: logger.info( "[{}]: did not receive transaction digest from sender={}.". format(self.context.agent_name, sender[-5:]))
def _on_cfp(self, cfp: FIPAMessage, dialogue: Dialogue) -> None: """ Handle a CFP. :param cfp: the fipa message containing the CFP :param dialogue: the dialogue :return: None """ new_msg_id = cast(int, cfp.get("message_id")) + 1 query = cast(Query, cfp.get("query")) strategy = cast(Strategy, self.context.strategy) proposal_description = strategy.get_proposal_for_query( query, dialogue.is_seller) if proposal_description is None: logger.debug("[{}]: sending to {} a Decline{}".format( self.context.agent_name, dialogue.dialogue_label.dialogue_opponent_pbk, pprint.pformat({ "msg_id": new_msg_id, "dialogue_id": cfp.get("dialogue_id"), "origin": dialogue.dialogue_label.dialogue_opponent_pbk, "target": cfp.get("target") }))) fipa_msg = FIPAMessage( performative=FIPAMessage.Performative.DECLINE, message_id=new_msg_id, dialogue_reference=dialogue.dialogue_label.dialogue_reference, target=cfp.get("message_id")) dialogues = cast(Dialogues, self.context.dialogues) dialogues.dialogue_stats.add_dialogue_endstate( Dialogue.EndState.DECLINED_CFP, dialogue.is_self_initiated) else: transaction_msg = generate_transaction_message( proposal_description, dialogue.dialogue_label, dialogue.is_seller, self.context.agent_public_key) transactions = cast(Transactions, self.context.transactions) transactions.add_pending_proposal(dialogue.dialogue_label, new_msg_id, transaction_msg) logger.info("[{}]: sending to {} a Propose{}".format( self.context.agent_name, dialogue.dialogue_label.dialogue_opponent_pbk, pprint.pformat({ "msg_id": new_msg_id, "dialogue_id": cfp.get("dialogue_id"), "origin": dialogue.dialogue_label.dialogue_opponent_pbk, "target": cfp.get("message_id"), "propose": proposal_description.values }))) fipa_msg = FIPAMessage( performative=FIPAMessage.Performative.PROPOSE, message_id=new_msg_id, dialogue_reference=dialogue.dialogue_label.dialogue_reference, target=cfp.get("message_id"), proposal=[proposal_description]) 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))