def _on_unregister(self, message: TacMessage) -> None: """ Handle a unregister message. If the address is not registered, answer with an error message. :param message: the 'get agent state' TacMessage. :return: None """ game = cast(Game, self.context.game) if message.counterparty not in game.registration.agent_addr_to_name: self.context.logger.warning( "agent not registered: '{}'".format(message.counterparty) ) tac_msg = TacMessage( performative=TacMessage.Performative.TAC_ERROR, error_code=TacMessage.ErrorCode.AGENT_NOT_REGISTERED, ) tac_msg.counterparty = message.counterparty self.context.outbox.put_message(message=tac_msg) else: self.context.logger.debug( "agent unregistered: '{}'".format( game.conf.agent_addr_to_name[message.counterparty], ) ) game.registration.unregister_agent(message.counterparty)
def _start_tac(self): """Create a game and send the game configuration to every registered agent.""" game = cast(Game, self.context.game) game.create() self.context.logger.info( "[{}]: Started competition:\n{}".format( self.context.agent_name, game.holdings_summary ) ) self.context.logger.info( "[{}]: Computed equilibrium:\n{}".format( self.context.agent_name, game.equilibrium_summary ) ) for agent_address in game.conf.agent_addr_to_name.keys(): agent_state = game.current_agent_states[agent_address] tac_msg = TacMessage( performative=TacMessage.Performative.GAME_DATA, amount_by_currency_id=agent_state.amount_by_currency_id, exchange_params_by_currency_id=agent_state.exchange_params_by_currency_id, quantities_by_good_id=agent_state.quantities_by_good_id, utility_params_by_good_id=agent_state.utility_params_by_good_id, tx_fee=game.conf.tx_fee, currency_id_to_name=game.conf.currency_id_to_name, agent_addr_to_name=game.conf.agent_addr_to_name, good_id_to_name=game.conf.good_id_to_name, version_id=game.conf.version_id, ) self.context.logger.debug( "[{}]: sending game data to '{}': {}".format( self.context.agent_name, agent_address, str(tac_msg) ) ) tac_msg.counterparty = agent_address self.context.outbox.put_message(message=tac_msg)
def test_register_serialization(): """Test the serialization for 'register' speech-act works.""" msg = TacMessage( performative=TacMessage.Performative.REGISTER, agent_name="some_agent_name", ) 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 = TacMessage.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
def test_transaction_confirmation_serialization(): """Test the serialization for 'transaction_confirmation' speech-act works.""" msg = TacMessage( performative=TacMessage.Performative.TRANSACTION_CONFIRMATION, transaction_id="some_transaction_id", amount_by_currency_id={ "key_1": 1, "key_2": 2 }, quantities_by_good_id={ "key_1": 1, "key_2": 2 }, ) msg.to = "receiver" envelope = Envelope( to=msg.to, sender="sender", protocol_id=TacMessage.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 = TacMessage.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
def test_unregister_serialization(): """Test the serialization for 'unregister' speech-act works.""" msg = TacMessage( message_id=2, target=1, performative=TacMessage.Performative.UNREGISTER, ) msg.to = "receiver" envelope = Envelope( to=msg.to, sender="sender", protocol_id=TacMessage.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 = TacMessage.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
def test_tac_error_serialization(): """Test the serialization for 'tac_error' speech-act works.""" msg = TacMessage( performative=TacMessage.Performative.TAC_ERROR, error_code=TacMessage.ErrorCode.GENERIC_ERROR, info={ "key_1": "value_1", "key_2": "value_2" }, ) msg.to = "receiver" envelope = Envelope( to=msg.to, sender="sender", protocol_id=TacMessage.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 = TacMessage.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
def _start_tac(self, game: Game) -> None: """Create a game and send the game configuration to every registered agent.""" self.context.logger.info( "starting competition with configuration:\n{}".format( game.holdings_summary)) self.context.logger.info( "computed theoretical equilibrium:\n{}".format( game.equilibrium_summary)) for agent_address in game.conf.agent_addr_to_name.keys(): agent_state = game.current_agent_states[agent_address] tac_msg = TacMessage( performative=TacMessage.Performative.GAME_DATA, amount_by_currency_id=agent_state.amount_by_currency_id, exchange_params_by_currency_id=agent_state. exchange_params_by_currency_id, quantities_by_good_id=agent_state.quantities_by_good_id, utility_params_by_good_id=agent_state. utility_params_by_good_id, tx_fee=game.conf.tx_fee, agent_addr_to_name=game.conf.agent_addr_to_name, good_id_to_name=game.conf.good_id_to_name, currency_id_to_name=game.conf.currency_id_to_name, version_id=game.conf.version_id, info={"contract_address": game.conf.contract_address}, ) self.context.logger.debug( "sending game data to '{}'.".format(agent_address)) self.context.logger.debug("game data={}".format(str(tac_msg))) tac_msg.counterparty = agent_address self.context.outbox.put_message(message=tac_msg)
def _cancel_tac(self, game: Game): """Notify agents that the TAC is cancelled.""" self.context.logger.info("notifying agents that TAC is cancelled.") tac_dialogues = cast(TacDialogues, self.context.tac_dialogues) for agent_address in game.registration.agent_addr_to_name.keys(): tac_dialogue = tac_dialogues.dialogue_by_address.get( agent_address, None) assert tac_dialogue is not None, "Error when retrieving dialogue." last_msg = tac_dialogue.last_message assert last_msg is not None, "Error when retrieving last message." tac_msg = TacMessage( performative=TacMessage.Performative.CANCELLED, dialogue_reference=tac_dialogue.dialogue_label. dialogue_reference, message_id=last_msg.message_id + 1, target=last_msg.message_id, ) tac_msg.counterparty = agent_address tac_dialogues.update(tac_msg) self.context.outbox.put_message(message=tac_msg) if game.phase == Phase.GAME: self.context.logger.info("finished competition:\n{}".format( game.holdings_summary)) self.context.logger.info("computed equilibrium:\n{}".format( game.equilibrium_summary)) self.context.is_active = False
def _cancel_tac(self): """Notify agents that the TAC is cancelled.""" game = cast(Game, self.context.game) self.context.logger.info( "[{}]: Notifying agents that TAC is cancelled.".format( self.context.agent_name ) ) for agent_addr in game.registration.agent_addr_to_name.keys(): tac_msg = TacMessage(performative=TacMessage.Performative.CANCELLED) tac_msg.counterparty = agent_addr self.context.outbox.put_message(message=tac_msg) if game.phase == Phase.GAME: self.context.logger.info( "[{}]: Finished competition:\n{}".format( self.context.agent_name, game.holdings_summary ) ) self.context.logger.info( "[{}]: Computed equilibrium:\n{}".format( self.context.agent_name, game.equilibrium_summary ) ) self.context.is_active = False
def _end_tac(self, game: Game, reason: str) -> None: """Notify agents that the TAC is cancelled.""" self.context.logger.info( "notifying agents that TAC is {}.".format(reason)) for agent_addr in game.registration.agent_addr_to_name.keys(): tac_msg = TacMessage( performative=TacMessage.Performative.CANCELLED) tac_msg.counterparty = agent_addr self.context.outbox.put_message(message=tac_msg)
def _handle_invalid_transaction(self, message: TacMessage) -> None: """Handle an invalid transaction.""" tx_id = message.tx_id[-10:] self.context.logger.info( "[{}]: Handling invalid transaction: {}".format( self.context.agent_name, tx_id)) tac_msg = TacMessage( performative=TacMessage.Performative.TAC_ERROR, error_code=TacMessage.ErrorCode.TRANSACTION_NOT_VALID, info={"transaction_id": message.tx_id}, ) tac_msg.counterparty = message.counterparty self.context.outbox.put_message(message=tac_msg)
def _handle_valid_transaction(self, message: TacMessage, transaction: Transaction) -> None: """ Handle a valid transaction. That is: - update the game state - send a transaction confirmation both to the buyer and the seller. :param transaction: the transaction. :return: None """ game = cast(Game, self.context.game) self.context.logger.info("[{}]: Handling valid transaction: {}".format( self.context.agent_name, transaction.id[-10:])) game.settle_transaction(transaction) tx_sender_id, tx_counterparty_id = transaction.id.split("_") # send the transaction confirmation. sender_tac_msg = TacMessage( performative=TacMessage.Performative.TRANSACTION_CONFIRMATION, tx_id=tx_sender_id, amount_by_currency_id=transaction.amount_by_currency_id, quantities_by_good_id=transaction.quantities_by_good_id, ) counterparty_tac_msg = TacMessage( performative=TacMessage.Performative.TRANSACTION_CONFIRMATION, tx_id=tx_counterparty_id, amount_by_currency_id=transaction.amount_by_currency_id, quantities_by_good_id=transaction.quantities_by_good_id, ) self.context.outbox.put_message( to=transaction.sender_addr, sender=self.context.agent_address, protocol_id=TacMessage.protocol_id, message=TacSerializer().encode(sender_tac_msg), ) self.context.outbox.put_message( to=transaction.counterparty_addr, sender=self.context.agent_address, protocol_id=TacMessage.protocol_id, message=TacSerializer().encode(counterparty_tac_msg), ) # log messages self.context.logger.info( "[{}]: Transaction '{}' settled successfully.".format( self.context.agent_name, transaction.id[-10:])) self.context.logger.info("[{}]: Current state:\n{}".format( self.context.agent_name, game.holdings_summary))
def _on_unregister(self, message: TacMessage) -> None: """ Handle a unregister message. If the address is not registered, answer with an error message. :param message: the 'get agent state' TacMessage. :return: None """ game = cast(Game, self.context.game) if message.counterparty not in game.registration.agent_addr_to_name: self.context.logger.error( "[{}]: Agent not registered: '{}'".format( self.context.agent_name, message.counterparty)) tac_msg = TacMessage( performative=TacMessage.Performative.TAC_ERROR, error_code=TacMessage.ErrorCode.AGENT_NOT_REGISTERED, ) self.context.outbox.put_message( to=message.counterparty, sender=self.context.agent_address, protocol_id=TacMessage.protocol_id, message=TacSerializer().encode(tac_msg), ) else: self.context.logger.debug("[{}]: Agent unregistered: '{}'".format( self.context.agent_name, game.configuration.agent_addr_to_name[message.counterparty], )) game.registration.unregister_agent(message.counterparty)
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 ): # TODO: // Need to modify here and add the contract option in case we are using one. self.context.logger.info( "[{}]: transaction confirmed by decision maker, sending to controller.".format( self.context.agent_name ) ) game = cast(Game, self.context.game) tx_counterparty_signature = cast( bytes, tx_message.info.get("tx_counterparty_signature") ) tx_counterparty_id = cast(str, tx_message.info.get("tx_counterparty_id")) if (tx_counterparty_signature is not None) and ( tx_counterparty_id is not None ): tx_id = tx_message.tx_id + "_" + tx_counterparty_id msg = TacMessage( performative=TacMessage.Performative.TRANSACTION, tx_id=tx_id, tx_sender_addr=tx_message.tx_sender_addr, tx_counterparty_addr=tx_message.tx_counterparty_addr, amount_by_currency_id=tx_message.tx_amount_by_currency_id, tx_sender_fee=tx_message.tx_sender_fee, tx_counterparty_fee=tx_message.tx_counterparty_fee, quantities_by_good_id=tx_message.tx_quantities_by_good_id, tx_sender_signature=tx_message.signed_payload.get("tx_signature"), tx_counterparty_signature=tx_message.info.get( "tx_counterparty_signature" ), tx_nonce=tx_message.info.get("tx_nonce"), ) self.context.outbox.put_message( to=game.configuration.controller_addr, sender=self.context.agent_address, protocol_id=TacMessage.protocol_id, message=TacSerializer().encode(msg), ) else: self.context.logger.warning( "[{}]: transaction has no counterparty id or signature!".format( self.context.agent_name ) ) else: self.context.logger.info( "[{}]: transaction was not successful.".format(self.context.agent_name) )
def _cancel_tac(self): """Notify agents that the TAC is cancelled.""" game = cast(Game, self.context.game) self.context.logger.info( "[{}]: Notifying agents that TAC is cancelled.".format( self.context.agent_name ) ) for agent_addr in game.registration.agent_addr_to_name.keys(): tac_msg = TacMessage(performative=TacMessage.Type.CANCELLED) self.context.outbox.put_message( to=agent_addr, sender=self.context.agent_address, protocol_id=TacMessage.protocol_id, message=TacSerializer().encode(tac_msg), ) if game.phase == Phase.GAME: self.context.logger.info( "[{}]: Finished competition:\n{}".format( self.context.agent_name, game.holdings_summary ) ) self.context.logger.info( "[{}]: Computed equilibrium:\n{}".format( self.context.agent_name, game.equilibrium_summary ) ) self.context.is_active = False
def _start_tac(self): """Create a game and send the game configuration to every registered agent.""" game = cast(Game, self.context.game) # game.create() self.context.logger.info("[{}]: Started competition:\n{}".format( self.context.agent_name, game.holdings_summary)) self.context.logger.info("[{}]: Computed equilibrium:\n{}".format( self.context.agent_name, game.equilibrium_summary)) for agent_address in game.configuration.agent_addr_to_name.keys(): agent_state = game.current_agent_states[agent_address] tac_msg = TacMessage( type=TacMessage.Performative.GAME_DATA, amount_by_currency_id=agent_state.amount_by_currency_id, exchange_params_by_currency_id=agent_state. exchange_params_by_currency_id, quantities_by_good_id=agent_state.quantities_by_good_id, utility_params_by_good_id=agent_state. utility_params_by_good_id, tx_fee=game.configuration.tx_fee, agent_addr_to_name=game.configuration.agent_addr_to_name, good_id_to_name=game.configuration.good_id_to_name, version_id=game.configuration.version_id, contract_address=self.context.contracts.erc1155.instance. address, ) self.context.logger.debug( "[{}]: sending game data to '{}': {}".format( self.context.agent_name, agent_address, str(tac_msg))) self.context.outbox.put_message( to=agent_address, sender=self.context.agent_address, protocol_id=TacMessage.protocol_id, message=TacSerializer().encode(tac_msg), )
def _on_register(self, message: TacMessage) -> None: """ Handle a register message. If the address is not registered, answer with an error message. :param message: the 'get agent state' TacMessage. :return: None """ parameters = cast(Parameters, self.context.parameters) agent_name = message.agent_name if len(parameters.whitelist ) != 0 and agent_name not in parameters.whitelist: self.context.logger.warning( "[{}]: Agent name not in whitelist: '{}'".format( self.context.agent_name, agent_name)) tac_msg = TacMessage( performative=TacMessage.Performative.TAC_ERROR, error_code=TacMessage.ErrorCode.AGENT_NAME_NOT_IN_WHITELIST, ) tac_msg.counterparty = message.counterparty self.context.outbox.put_message(message=tac_msg) return game = cast(Game, self.context.game) if message.counterparty in game.registration.agent_addr_to_name: self.context.logger.warning( "[{}]: Agent already registered: '{}'".format( self.context.agent_name, game.registration.agent_addr_to_name[message.counterparty], )) tac_msg = TacMessage( performative=TacMessage.Performative.TAC_ERROR, error_code=TacMessage.ErrorCode.AGENT_ADDR_ALREADY_REGISTERED, ) tac_msg.counterparty = message.counterparty self.context.outbox.put_message(message=tac_msg) if agent_name in game.registration.agent_addr_to_name.values(): self.context.logger.warning( "[{}]: Agent with this name already registered: '{}'".format( self.context.agent_name, agent_name)) tac_msg = TacMessage( performative=TacMessage.Performative.TAC_ERROR, error_code=TacMessage.ErrorCode.AGENT_NAME_ALREADY_REGISTERED, ) tac_msg.counterparty = message.counterparty self.context.outbox.put_message(message=tac_msg) game.registration.register_agent(message.counterparty, agent_name) self.context.logger.info("[{}]: Agent registered: '{}'".format( self.context.agent_name, agent_name))
def test_transaction_serialization(): """Test the serialization for 'transaction' speech-act works.""" msg = TacMessage( performative=TacMessage.Performative.TRANSACTION, transaction_id="some_transaction_id", ledger_id="some_ledger_id", sender_address="some_sender_address", counterparty_address="some_counterparty_address", amount_by_currency_id={ "key_1": 1, "key_2": 2 }, fee_by_currency_id={ "key_1": 1, "key_2": 2 }, quantities_by_good_id={ "key_1": 1, "key_2": 2 }, nonce="some_nonce", sender_signature="some_sender_signature", counterparty_signature="some_counterparty_signature", ) 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 = TacMessage.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
def _register_to_tac(self, controller_addr: Address) -> None: """ Register to active TAC Controller. :param controller_addr: the address of the controller. :return: None """ game = cast(Game, self.context.game) game.update_expected_controller_addr(controller_addr) game.update_game_phase(Phase.GAME_REGISTRATION) tac_msg = TacMessage( performative=TacMessage.Performative.REGISTER, agent_name=self.context.agent_name, ) tac_msg.counterparty = controller_addr self.context.outbox.put_message(message=tac_msg) self.context.behaviours.tac.is_active = False
def _handle_invalid_transaction( self, tac_msg: TacMessage, tac_dialogue: TacDialogue ) -> None: """Handle an invalid transaction.""" self.context.logger.info( "handling invalid transaction: {}".format(tac_msg.transaction_id) ) error_msg = TacMessage( performative=TacMessage.Performative.TAC_ERROR, dialogue_reference=tac_dialogue.dialogue_label.dialogue_reference, error_code=TacMessage.ErrorCode.TRANSACTION_NOT_VALID, info={"transaction_id": tac_msg.transaction_id}, message_id=tac_msg.message_id + 1, target=tac_msg.message_id, ) error_msg.counterparty = tac_msg.counterparty assert tac_dialogue.update(error_msg) self.context.outbox.put_message(message=error_msg)
def test_encoding_unknown_performative(): """Test that we raise an exception when the performative is unknown during encoding.""" msg = TacMessage(performative=TacMessage.Performative.CANCELLED, ) with pytest.raises(ValueError, match="Performative not valid:"): with mock.patch.object(TacMessage.Performative, "__eq__", return_value=False): TacMessage.serializer.encode(msg)
def _process_transactions(self) -> None: """ Process transactions. :return: None """ game = cast(Game, self.context.game) tac_dialogue = game.tac_dialogue transactions = cast(Dict[str, Dict[str, Any]], self.context.shared_state.get("transactions", {})) tx_ids = list(transactions.keys()) for tx_id in tx_ids: self.context.logger.info( "sending transaction {} to controller.".format(tx_id)) last_msg = tac_dialogue.last_message assert last_msg is not None, "No last message available." tx_content = transactions.pop(tx_id, None) assert tx_content is not None, "Tx for id={} not found.".format( tx_id) terms = tx_content["terms"] sender_signature = tx_content["sender_signature"] counterparty_signature = tx_content["counterparty_signature"] msg = TacMessage( performative=TacMessage.Performative.TRANSACTION, dialogue_reference=tac_dialogue.dialogue_label. dialogue_reference, message_id=last_msg.message_id + 1, target=last_msg.message_id, transaction_id=tx_id, ledger_id=terms.ledger_id, sender_address=terms.sender_address, counterparty_address=terms.counterparty_address, amount_by_currency_id=terms.amount_by_currency_id, fee_by_currency_id=terms.fee_by_currency_id, quantities_by_good_id=terms.quantities_by_good_id, sender_signature=sender_signature, counterparty_signature=counterparty_signature, nonce=terms.nonce, ) msg.counterparty = game.conf.controller_addr tac_dialogue.update(msg) self.context.outbox.put_message(message=msg)
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 """ # TODO: Need to modify here and add the contract option in case we are using one. self.context.logger.info( "[{}]: transaction confirmed by decision maker, sending to controller." .format(self.context.agent_name)) game = cast(Game, self.context.game) tx_counterparty_signature = cast( str, signing_msg.skill_callback_info.get("tx_counterparty_signature")) tx_counterparty_id = cast( str, signing_msg.skill_callback_info.get("tx_counterparty_id")) tx_id = cast(str, signing_msg.skill_callback_info.get("tx_id")) if (tx_counterparty_signature is not None) and (tx_counterparty_id is not None): # tx_id = tx_message.tx_id + "_" + tx_counterparty_id msg = TacMessage( performative=TacMessage.Performative.TRANSACTION, tx_id=tx_id, tx_sender_addr=signing_msg.terms.sender_address, tx_counterparty_addr=signing_msg.terms.counterparty_address, amount_by_currency_id=signing_msg.terms.amount_by_currency_id, is_sender_payable_tx_fee=signing_msg.terms. is_sender_payable_tx_fee, quantities_by_good_id=signing_msg.terms.quantities_by_good_id, tx_sender_signature=signing_msg.signed_transaction.body, tx_counterparty_signature=tx_counterparty_signature, tx_nonce=signing_msg.terms.nonce, ) msg.counterparty = game.conf.controller_addr self.context.outbox.put_message(message=msg) else: self.context.logger.warning( "[{}]: transaction has no counterparty id or signature!". format(self.context.agent_name))
def _on_unregister(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None: """ Handle a unregister message. If the address is not registered, answer with an error message. :param tac_msg: the tac message :param tac_dialogue: the tac dialogue :return: None """ game = cast(Game, self.context.game) if not game.phase == Phase.GAME_REGISTRATION: self.context.logger.warning( "received unregister outside of game registration phase: '{}'".format( tac_msg ) ) return if tac_msg.counterparty not in game.registration.agent_addr_to_name: self.context.logger.warning( "agent not registered: '{}'".format(tac_msg.counterparty) ) error_msg = TacMessage( performative=TacMessage.Performative.TAC_ERROR, dialogue_reference=tac_dialogue.dialogue_label.dialogue_reference, error_code=TacMessage.ErrorCode.AGENT_NOT_REGISTERED, message_id=tac_msg.message_id + 1, target=tac_msg.message_id, ) error_msg.counterparty = tac_msg.counterparty assert tac_dialogue.update(error_msg) self.context.outbox.put_message(message=error_msg) else: self.context.logger.debug( "agent unregistered: '{}'".format( game.conf.agent_addr_to_name[tac_msg.counterparty], ) ) game.registration.unregister_agent(tac_msg.counterparty)
def _handle_valid_transaction( self, tac_msg: TacMessage, tac_dialogue: TacDialogue, transaction: Transaction ) -> None: """ Handle a valid transaction. That is: - update the game state - send a transaction confirmation both to the buyer and the seller. :param transaction: the transaction. :return: None """ game = cast(Game, self.context.game) self.context.logger.info( "handling valid transaction: {}".format(transaction.id[-10:]) ) game.settle_transaction(transaction) # send the transaction confirmation. sender_tac_msg = TacMessage( performative=TacMessage.Performative.TRANSACTION_CONFIRMATION, dialogue_reference=tac_dialogue.dialogue_label.dialogue_reference, transaction_id=transaction.sender_hash, amount_by_currency_id=transaction.amount_by_currency_id, quantities_by_good_id=transaction.quantities_by_good_id, message_id=tac_msg.message_id + 1, target=tac_msg.message_id, ) sender_tac_msg.counterparty = transaction.sender_address assert tac_dialogue.update(sender_tac_msg) self.context.outbox.put_message(message=sender_tac_msg) tac_dialogues = cast(TacDialogues, self.context.tac_dialogues) recovered_tac_dialogue = tac_dialogues.dialogue_by_address.get( transaction.counterparty_address, None ) assert recovered_tac_dialogue is not None, "Error when retrieving dialogue." last_msg = recovered_tac_dialogue.last_message assert last_msg is not None, "Error when retrieving last message." counterparty_tac_msg = TacMessage( performative=TacMessage.Performative.TRANSACTION_CONFIRMATION, dialogue_reference=recovered_tac_dialogue.dialogue_label.dialogue_reference, transaction_id=transaction.counterparty_hash, amount_by_currency_id=transaction.amount_by_currency_id, quantities_by_good_id=transaction.quantities_by_good_id, message_id=last_msg.message_id + 1, target=last_msg.message_id, ) counterparty_tac_msg.counterparty = transaction.counterparty_address assert recovered_tac_dialogue.update(counterparty_tac_msg) self.context.outbox.put_message(message=counterparty_tac_msg) # log messages self.context.logger.info( "transaction '{}' settled successfully.".format(transaction.id[-10:]) ) self.context.logger.info("current state:\n{}".format(game.holdings_summary))
def _start_tac(self, game: Game): """Create a game and send the game configuration to every registered agent.""" game.create() self.context.logger.info("started competition:\n{}".format( game.holdings_summary)) self.context.logger.info("computed equilibrium:\n{}".format( game.equilibrium_summary)) tac_dialogues = cast(TacDialogues, self.context.tac_dialogues) for agent_address in game.conf.agent_addr_to_name.keys(): tac_dialogue = tac_dialogues.dialogue_by_address.get( agent_address, None) assert tac_dialogue is not None, "Error when retrieving dialogue." last_msg = tac_dialogue.last_message assert last_msg is not None, "Error when retrieving last message." agent_state = game.current_agent_states[agent_address] tac_msg = TacMessage( performative=TacMessage.Performative.GAME_DATA, dialogue_reference=tac_dialogue.dialogue_label. dialogue_reference, message_id=last_msg.message_id + 1, target=last_msg.message_id, amount_by_currency_id=agent_state.amount_by_currency_id, exchange_params_by_currency_id=agent_state. exchange_params_by_currency_id, quantities_by_good_id=agent_state.quantities_by_good_id, utility_params_by_good_id=agent_state. utility_params_by_good_id, fee_by_currency_id=game.conf.fee_by_currency_id, currency_id_to_name=game.conf.currency_id_to_name, agent_addr_to_name=game.conf.agent_addr_to_name, good_id_to_name=game.conf.good_id_to_name, version_id=game.conf.version_id, ) tac_msg.counterparty = agent_address tac_dialogues.update(tac_msg) self.context.outbox.put_message(message=tac_msg) self.context.logger.debug("sending game data to '{}': {}".format( agent_address, str(tac_msg)))
def _register_to_tac(self, controller_addr: Address) -> None: """ Register to active TAC Controller. :param controller_addr: the address of the controller. :return: None """ game = cast(Game, self.context.game) game.update_expected_controller_addr(controller_addr) game.update_game_phase(Phase.GAME_REGISTRATION) tac_dialogues = cast(TacDialogues, self.context.tac_dialogues) tac_msg = TacMessage( performative=TacMessage.Performative.REGISTER, dialogue_reference=tac_dialogues.new_self_initiated_dialogue_reference(), agent_name=self.context.agent_name, ) tac_msg.counterparty = controller_addr tac_dialogue = cast(Optional[TacDialogue], tac_dialogues.update(tac_msg)) assert tac_dialogue is not None, "TacDialogue not created." game.tac_dialogue = tac_dialogue self.context.outbox.put_message(message=tac_msg) self.context.behaviours.tac_search.is_active = False
def _end_tac(self, game: Game, reason: str) -> None: """Notify agents that the TAC is cancelled.""" self.context.logger.info( "[{}]: Notifying agents that TAC is {}.".format( self.context.agent_name, reason ) ) for agent_addr in game.registration.agent_addr_to_name.keys(): tac_msg = TacMessage(performative=TacMessage.Performative.CANCELLED) self.context.outbox.put_message( to=agent_addr, sender=self.context.agent_address, protocol_id=TacMessage.protocol_id, message=TacSerializer().encode(tac_msg), )
def test_cancelled_serialization(): """Test the serialization for 'cancelled' speech-act works.""" msg = TacMessage(performative=TacMessage.Performative.CANCELLED, ) msg.to = "receiver" envelope = Envelope( to=msg.to, sender="sender", protocol_id=TacMessage.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 = TacMessage.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
def test_tac_message_instantiation(): """Test instantiation of the tac message.""" assert TacMessage( performative=TacMessage.Performative.REGISTER, agent_name="some_name" ) assert TacMessage(performative=TacMessage.Performative.UNREGISTER) assert TacMessage( performative=TacMessage.Performative.TRANSACTION, tx_id="some_id", tx_sender_addr="some_address", tx_counterparty_addr="some_other_address", amount_by_currency_id={"FET": 10}, tx_sender_fee=10, tx_counterparty_fee=10, quantities_by_good_id={"123": 0, "1234": 10}, tx_nonce=1, tx_sender_signature=b"some_signature", tx_counterparty_signature=b"some_other_signature", ) assert TacMessage(performative=TacMessage.Performative.GET_STATE_UPDATE) assert TacMessage(performative=TacMessage.Performative.CANCELLED) assert TacMessage( performative=TacMessage.Performative.GAME_DATA, amount_by_currency_id={"FET": 10}, exchange_params_by_currency_id={"FET": 10.0}, quantities_by_good_id={"123": 20, "1234": 15}, utility_params_by_good_id={"123": 30.0, "1234": 50.0}, tx_fee=20, agent_addr_to_name={"agent_1": "Agent one", "agent_2": "Agent two"}, currency_id_to_name={"FET": "currency_name"}, good_id_to_name={"123": "First good", "1234": "Second good"}, version_id="game_version_1", ) assert TacMessage( performative=TacMessage.Performative.TRANSACTION_CONFIRMATION, tx_id="some_id", amount_by_currency_id={"FET": 10}, quantities_by_good_id={"123": 20, "1234": 15}, ) assert TacMessage( performative=TacMessage.Performative.TAC_ERROR, error_code=TacMessage.ErrorCode.GENERIC_ERROR, info={"msg": "This is info msg."}, ) assert str(TacMessage.Performative.REGISTER) == "register"