def _update_ownership_and_preferences( self, tac_msg: TacMessage, tac_dialogue: TacDialogue ) -> None: """ Update ownership and preferences. :param tac_msg: the game data :param tac_dialogue: the tac dialogue :return: None """ state_update_dialogues = cast( StateUpdateDialogues, self.context.state_update_dialogues ) state_update_msg = StateUpdateMessage( performative=StateUpdateMessage.Performative.INITIALIZE, dialogue_reference=state_update_dialogues.new_self_initiated_dialogue_reference(), amount_by_currency_id=tac_msg.amount_by_currency_id, quantities_by_good_id=tac_msg.quantities_by_good_id, exchange_params_by_currency_id=tac_msg.exchange_params_by_currency_id, utility_params_by_good_id=tac_msg.utility_params_by_good_id, ) self.context.shared_state["fee_by_currency_id"] = tac_msg.fee_by_currency_id state_update_msg.counterparty = "decision_maker" state_update_dialogue = cast( Optional[StateUpdateDialogue], state_update_dialogues.update(state_update_msg), ) assert state_update_dialogue is not None, "StateUpdateDialogue not created." game = cast(Game, self.context.game) game.state_update_dialogue = state_update_dialogue self.context.decision_maker_message_queue.put_nowait(state_update_msg)
def decode(obj: bytes) -> Message: """ Decode bytes into a 'StateUpdate' message. :param obj: the bytes object. :return: the 'StateUpdate' message. """ state_update_pb = state_update_pb2.StateUpdateMessage() state_update_pb.ParseFromString(obj) message_id = state_update_pb.message_id dialogue_reference = ( state_update_pb.dialogue_starter_reference, state_update_pb.dialogue_responder_reference, ) target = state_update_pb.target performative = state_update_pb.WhichOneof("performative") performative_id = StateUpdateMessage.Performative(str(performative)) performative_content = dict() # type: Dict[str, Any] if performative_id == StateUpdateMessage.Performative.INITIALIZE: exchange_params_by_currency_id = ( state_update_pb.initialize.exchange_params_by_currency_id ) exchange_params_by_currency_id_dict = dict(exchange_params_by_currency_id) performative_content[ "exchange_params_by_currency_id" ] = exchange_params_by_currency_id_dict utility_params_by_good_id = ( state_update_pb.initialize.utility_params_by_good_id ) utility_params_by_good_id_dict = dict(utility_params_by_good_id) performative_content[ "utility_params_by_good_id" ] = utility_params_by_good_id_dict amount_by_currency_id = state_update_pb.initialize.amount_by_currency_id amount_by_currency_id_dict = dict(amount_by_currency_id) performative_content["amount_by_currency_id"] = amount_by_currency_id_dict quantities_by_good_id = state_update_pb.initialize.quantities_by_good_id quantities_by_good_id_dict = dict(quantities_by_good_id) performative_content["quantities_by_good_id"] = quantities_by_good_id_dict elif performative_id == StateUpdateMessage.Performative.APPLY: amount_by_currency_id = state_update_pb.apply.amount_by_currency_id amount_by_currency_id_dict = dict(amount_by_currency_id) performative_content["amount_by_currency_id"] = amount_by_currency_id_dict quantities_by_good_id = state_update_pb.apply.quantities_by_good_id quantities_by_good_id_dict = dict(quantities_by_good_id) performative_content["quantities_by_good_id"] = quantities_by_good_id_dict else: raise ValueError("Performative not valid: {}.".format(performative_id)) return StateUpdateMessage( message_id=message_id, dialogue_reference=dialogue_reference, target=target, performative=performative, **performative_content )
def test_serialization_apply(self): """Test serialization of apply message.""" currency_change = {"FET": 10} good_change = {"a_good": 1} msg = StateUpdateMessage( performative=StateUpdateMessage.Performative.APPLY, amount_by_currency_id=currency_change, quantities_by_good_id=good_change, ) assert msg._is_consistent() assert len(msg.valid_performatives) == 2 encoded_msg = msg.serializer.encode(msg) decoded_msg = msg.serializer.decode(encoded_msg) assert msg == decoded_msg
def test_message_inconsistency(self): """Test for an error in consistency of a message.""" currency_endowment = {"FET": 100} good_endowment = {"a_good": 2} exchange_params = {"UNKNOWN": 10.0} utility_params = {"a_good": 20.0} tx_fee = 10 stum = StateUpdateMessage( performative=StateUpdateMessage.Performative.INITIALIZE, amount_by_currency_id=currency_endowment, quantities_by_good_id=good_endowment, exchange_params_by_currency_id=exchange_params, utility_params_by_good_id=utility_params, tx_fee=tx_fee, ) assert not stum._is_consistent()
def test_serialization_negative(): """Test serialization when performative is not recognized.""" currency_change = {"FET": 10} good_change = {"a_good": 1} msg = StateUpdateMessage( performative=StateUpdateMessage.Performative.APPLY, amount_by_currency_id=currency_change, quantities_by_good_id=good_change, ) with patch.object(StateUpdateMessage.Performative, "__eq__", return_value=False): with pytest.raises( ValueError, match=f"Performative not valid: {msg.performative}"): msg.serializer.encode(msg) encoded_tx_bytes = msg.serializer.encode(msg) with patch.object(StateUpdateMessage.Performative, "__eq__", return_value=False): with pytest.raises( ValueError, match=f"Performative not valid: {msg.performative}"): msg.serializer.decode(encoded_tx_bytes)
def _on_transaction_confirmed( self, tac_msg: TacMessage, tac_dialogue: TacDialogue ) -> None: """ Handle 'on transaction confirmed' event emitted by the controller. :param tac_msg: the TacMessage. :param tac_dialogue: the tac dialogue :return: None """ game = cast(Game, self.context.game) if game.phase.value != Phase.GAME.value: self.context.logger.warning( "we do not expect a tranasaction in game phase={}".format( game.phase.value ) ) return self.context.logger.info( "received transaction confirmation from the controller: transaction_id={}".format( tac_msg.transaction_id ) ) state_update_dialogue = game.state_update_dialogue last_msg = state_update_dialogue.last_message assert last_msg is not None, "Could not retrieve last message." state_update_msg = StateUpdateMessage( performative=StateUpdateMessage.Performative.APPLY, dialogue_reference=state_update_dialogue.dialogue_label.dialogue_reference, message_id=last_msg.message_id + 1, target=last_msg.message_id, amount_by_currency_id=tac_msg.amount_by_currency_id, quantities_by_good_id=tac_msg.quantities_by_good_id, ) state_update_msg.counterparty = "decision_maker" state_update_dialogue.update(state_update_msg) self.context.decision_maker_message_queue.put_nowait(state_update_msg) if "confirmed_tx_ids" not in self.context.shared_state.keys(): self.context.shared_state["confirmed_tx_ids"] = [] self.context.shared_state["confirmed_tx_ids"].append(tac_msg.transaction_id)
def test_message_consistency(self): """Test for an error in consistency of a message.""" currency_endowment = {"FET": 100} good_endowment = {"a_good": 2} exchange_params = {"FET": 10.0} utility_params = {"a_good": 20.0} assert StateUpdateMessage( performative=StateUpdateMessage.Performative.INITIALIZE, amount_by_currency_id=currency_endowment, quantities_by_good_id=good_endowment, exchange_params_by_currency_id=exchange_params, utility_params_by_good_id=utility_params, ) currency_change = {"FET": 10} good_change = {"a_good": 1} stum = StateUpdateMessage( performative=StateUpdateMessage.Performative.APPLY, amount_by_currency_id=currency_change, quantities_by_good_id=good_change, ) assert stum._is_consistent() assert len(stum.valid_performatives) == 2
def test_serialization_initialize(self): """Test serialization of initialize message.""" currency_endowment = {"FET": 100} good_endowment = {"a_good": 2} exchange_params = {"FET": 10.0} utility_params = {"a_good": 20.0} msg = StateUpdateMessage( performative=StateUpdateMessage.Performative.INITIALIZE, amount_by_currency_id=currency_endowment, quantities_by_good_id=good_endowment, exchange_params_by_currency_id=exchange_params, utility_params_by_good_id=utility_params, ) encoded_msg = msg.serializer.encode(msg) decoded_msg = msg.serializer.decode(encoded_msg) assert msg == decoded_msg
def _update_ownership_and_preferences(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None: """ Update ownership and preferences. :param tac_msg: the game data :param tac_dialogue: the tac dialogue :return: None """ state_update_msg = StateUpdateMessage( performative=StateUpdateMessage.Performative.INITIALIZE, amount_by_currency_id=tac_msg.amount_by_currency_id, quantities_by_good_id=tac_msg.quantities_by_good_id, exchange_params_by_currency_id=tac_msg. exchange_params_by_currency_id, utility_params_by_good_id=tac_msg.utility_params_by_good_id, tx_fee=tac_msg.tx_fee, ) self.context.decision_maker_message_queue.put_nowait(state_update_msg)
def _on_transaction_confirmed(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None: """ Handle 'on transaction confirmed' event emitted by the controller. :param tac_msg: the TacMessage. :param tac_dialogue: the tac dialogue :return: None """ self.context.logger.info( "[{}]: Received transaction confirmation from the controller: transaction_id={}" .format(self.context.agent_name, tac_msg.tx_id[-10:])) state_update_msg = StateUpdateMessage( performative=StateUpdateMessage.Performative.APPLY, amount_by_currency_id=tac_msg.amount_by_currency_id, quantities_by_good_id=tac_msg.quantities_by_good_id, ) self.context.decision_maker_message_queue.put_nowait(state_update_msg) if "confirmed_tx_ids" not in self.context.shared_state.keys(): self.context.shared_state["confirmed_tx_ids"] = [] self.context.shared_state["confirmed_tx_ids"].append(tac_msg.tx_id)
def test_light_protocol_rule_3_target_less_than_message_id(): """Test that if message_id is not 1, target must be > message_id""" with patch.object(aea.protocols.state_update.message.logger, "error") as mock_logger: currency_endowment = {"FET": 100} good_endowment = {"a_good": 2} exchange_params = {"FET": 10.0} utility_params = {"a_good": 20.0} message_id = 2 target = 2 assert StateUpdateMessage( message_id=message_id, target=target, performative=StateUpdateMessage.Performative.INITIALIZE, amount_by_currency_id=currency_endowment, quantities_by_good_id=good_endowment, exchange_params_by_currency_id=exchange_params, utility_params_by_good_id=utility_params, ) mock_logger.assert_any_call( f"Invalid 'target'. Expected an integer between 1 and {message_id - 1} inclusive. Found {target}." )
def test_decision_maker_handle_state_update_initialize_and_apply(self): """Test the handle method for a stateUpdate message with Initialize and Apply performative.""" good_holdings = {"good_id": 2} currency_holdings = {"FET": 100} utility_params = {"good_id": 20.0} exchange_params = {"FET": 10.0} currency_deltas = {"FET": -10} good_deltas = {"good_id": 1} state_update_dialogues = StateUpdateDialogues("agent") state_update_message_1 = StateUpdateMessage( performative=StateUpdateMessage.Performative.INITIALIZE, dialogue_reference=state_update_dialogues.new_self_initiated_dialogue_reference(), amount_by_currency_id=currency_holdings, quantities_by_good_id=good_holdings, exchange_params_by_currency_id=exchange_params, utility_params_by_good_id=utility_params, ) state_update_message_1.counterparty = "decision_maker" state_update_dialogue = cast( Optional[StateUpdateDialogue], state_update_dialogues.update(state_update_message_1), ) assert state_update_dialogue is not None, "StateUpdateDialogue not created" self.decision_maker.handle(state_update_message_1) assert ( self.decision_maker_handler.context.ownership_state.amount_by_currency_id is not None ) assert ( self.decision_maker_handler.context.ownership_state.quantities_by_good_id is not None ) assert ( self.decision_maker_handler.context.preferences.exchange_params_by_currency_id is not None ) assert ( self.decision_maker_handler.context.preferences.utility_params_by_good_id is not None ) state_update_message_2 = StateUpdateMessage( performative=StateUpdateMessage.Performative.APPLY, dialogue_reference=state_update_dialogue.dialogue_label.dialogue_reference, message_id=state_update_message_1.message_id + 1, target=state_update_message_1.message_id, amount_by_currency_id=currency_deltas, quantities_by_good_id=good_deltas, ) state_update_message_2.counterparty = "decision_maker" assert state_update_dialogue.update(state_update_message_2) self.decision_maker.handle(state_update_message_2) expected_amount_by_currency_id = { key: currency_holdings.get(key, 0) + currency_deltas.get(key, 0) for key in set(currency_holdings) | set(currency_deltas) } expected_quantities_by_good_id = { key: good_holdings.get(key, 0) + good_deltas.get(key, 0) for key in set(good_holdings) | set(good_deltas) } assert ( self.decision_maker_handler.context.ownership_state.amount_by_currency_id == expected_amount_by_currency_id ), "The amount_by_currency_id must be equal with the expected amount." assert ( self.decision_maker_handler.context.ownership_state.quantities_by_good_id == expected_quantities_by_good_id )