Example #1
0
    def test_to_dict(self):
        """Test that conversion into dict works as expected."""
        nb_agents = 3
        nb_goods = 3
        tx_fee = 1.0
        agent_pbk_to_name = {
            'tac_agent_0_pbk': 'tac_agent_0',
            'tac_agent_1_pbk': 'tac_agent_1',
            'tac_agent_2_pbk': 'tac_agent_2'
        }
        good_pbk_to_name = {
            'tac_good_0_pbk': 'tac_good_0',
            'tac_good_1_pbk': 'tac_good_1',
            'tac_good_2_pbk': 'tac_good_2'
        }
        money_amounts = [20, 20, 20]
        endowments = [[1, 1, 1], [2, 1, 1], [1, 1, 2]]
        utility_params = [[20.0, 40.0, 40.0], [10.0, 50.0, 40.0],
                          [40.0, 30.0, 30.0]]
        eq_prices = [1.0, 1.0, 4.0]
        eq_good_holdings = [[1.0, 1.0, 4.0], [1.0, 5.0, 1.0], [6.0, 1.0, 2.0]]
        eq_money_holdings = [20.0, 20.0, 20.0]

        game_configuration = GameConfiguration(nb_agents, nb_goods, tx_fee,
                                               agent_pbk_to_name,
                                               good_pbk_to_name)
        game_initialization = GameInitialization(money_amounts, endowments,
                                                 utility_params, eq_prices,
                                                 eq_good_holdings,
                                                 eq_money_holdings)

        game = Game(game_configuration, game_initialization)

        tx_id = 'some_tx_id'
        sender_pbk = 'tac_agent_0_pbk'
        counterparty_pbk = 'tac_agent_1_pbk'
        transaction_1 = Transaction(tx_id, True, counterparty_pbk,
                                    10, {'tac_good_0_pbk': 1}, sender_pbk,
                                    Crypto())
        transaction_2 = Transaction(tx_id, False, counterparty_pbk,
                                    10, {'tac_good_0_pbk': 1}, sender_pbk,
                                    Crypto())
        game.settle_transaction(transaction_1)
        game.settle_transaction(transaction_2)

        actual_game_dict = game.to_dict()
        expected_game_dict = {
            "configuration": game_configuration.to_dict(),
            "initialization": game_initialization.to_dict(),
            "transactions": [transaction_1.to_dict(),
                             transaction_2.to_dict()]
        }

        assert actual_game_dict == expected_game_dict
    def test_competition_stops_too_few_registered_agents(self, network_node):
        """Test that if the controller agent does not receive enough registrations, it stops."""
        controller_agent = ControllerAgent(version=1)
        controller_agent.connect()

        parameters = TACParameters(min_nb_agents=2,
                                   start_time=datetime.datetime.now(),
                                   registration_timeout=5)
        job = Thread(target=controller_agent.handle_competition,
                     args=(parameters, ))
        job.start()

        crypto = Crypto()
        agent1 = OEFAgent(crypto.public_key,
                          "127.0.0.1",
                          10000,
                          loop=asyncio.new_event_loop())
        agent1.connect()
        agent1.send_message(
            0, 0, controller_agent.public_key,
            Register(agent1.public_key, crypto, 'agent_name').serialize())

        job.join()

        assert len(controller_agent.game_handler.registered_agents) == 1
Example #3
0
    def __init__(self,
                 name: str,
                 oef_addr: str,
                 oef_port: int = 10000,
                 private_key_pem_path: Optional[str] = None,
                 timeout: Optional[float] = 1.0) -> None:
        """
        Instantiate the agent.

        :param name: the name of the agent
        :param oef_addr: TCP/IP address of the OEF Agent
        :param oef_port: TCP/IP port of the OEF Agent
        :param private_key_pem_path: the path to the private key of the agent.
        :param timeout: the time in (fractions of) seconds to time out an agent between act and react

        :return: None
        """
        self._name = name
        self._crypto = Crypto(private_key_pem_path=private_key_pem_path)
        self._liveness = Liveness()
        self._timeout = timeout

        self.mail_box = None  # type: Optional[MailBox]
        self.in_box = None  # type: Optional[InBox]
        self.out_box = None  # type: Optional[OutBox]
Example #4
0
    def from_pb(cls, obj, public_key: str, crypto: Crypto) -> 'Request':
        """
        Parse a string of bytes associated to a request message to the TAC controller.

        :param obj: the string of bytes to be parsed.
        :param public_key: the public key of the request sender.
        :param crypto: the Crypto object
        :raises TacError: if the string of bytes cannot be parsed as a Response from the TAC Controller.

        :return: a :class:`~tac.protocol.Response` object.
        """
        signed_msg = tac_pb2.TACAgent.SignedMessage()
        signed_msg.ParseFromString(obj)

        if crypto.is_confirmed_integrity(signed_msg.message,
                                         signed_msg.signature, public_key):
            msg = tac_pb2.TACAgent.Message()
            msg.ParseFromString(signed_msg.message)
            case = msg.WhichOneof("msg")
            if case == "register":
                return Register.from_pb(msg.register, public_key, crypto)
            elif case == "unregister":
                return Unregister(public_key, crypto)
            elif case == "transaction":
                return Transaction.from_pb(msg.transaction, public_key, crypto)
            elif case == "get_state_update":
                return GetStateUpdate(public_key, crypto)
            else:
                raise TacError("Unrecognized type of Request.")
        else:
            raise ValueError("Bad signature. Do not trust!")
Example #5
0
    def __init__(self, name: str = "controller",
                 oef_addr: str = "127.0.0.1",
                 oef_port: int = 10000,
                 version: int = 1,
                 monitor: Optional[Monitor] = None,
                 **kwargs):
        """
        Initialize a Controller Agent for TAC.

        :param name: The name of the OEF Agent.
        :param oef_addr: the OEF address.
        :param oef_port: the OEF listening port.
        :param version: the version of the TAC controller.
        :param monitor: the GUI monitor. If None, defaults to a null (dummy) monitor.
        """
        self.name = name
        self.crypto = Crypto()
        super().__init__(self.crypto.public_key, oef_addr, oef_port, loop=asyncio.new_event_loop())
        logger.debug("[{}]: Initialized myself as Controller Agent :\n{}".format(self.name, pprint.pformat(vars())))

        self.dispatcher = ControllerDispatcher(self)
        self.monitor = NullMonitor() if monitor is None else monitor  # type: Monitor

        self.version = version
        self.game_handler = None  # type: Optional[GameHandler]

        self.last_activity = datetime.datetime.now()

        self._message_processing_task = None
        self._timeout_checker_task = None

        self._is_running = False
        self._terminated = False
Example #6
0
def test_initialization_from_existing_private_key():
    """Test that the initialization from an existing private key works correctly."""
    private_key_pem_path = ROOT_DIR + "/tests/data/priv.pem"

    private_key = load_pem_private_key(
        open(private_key_pem_path, "rb").read(), None, default_backend())

    c = Crypto(private_key_pem_path=private_key_pem_path)

    expected_public_key = private_key.public_key().public_bytes(
        encoding=Encoding.PEM, format=PublicFormat.SubjectPublicKeyInfo)
    actual_public_key = c.public_key_pem
    assert expected_public_key == actual_public_key
Example #7
0
    def _load(self) -> List[GameStats]:
        """Load all game statistics from iterated TAC output."""
        result = []  # type: List[GameStats]

        game_dirs = sorted(os.listdir(self.competition_directory))
        for game_dir in game_dirs:
            game_data_json_filepath = os.path.join(self.competition_directory,
                                                   game_dir, "game.json")
            game_data = json.load(open(game_data_json_filepath))
            game = Game.from_dict(game_data, Crypto())
            game_stats = GameStats(game)
            result.append(game_stats)

        return result
Example #8
0
    def from_datadir(datadir: str, env_name: str) -> 'ControllerDashboard':
        """
        Return a ControllerDashboard from a data directory.

        :param datadir: the data directory
        :param env_name: the environment name
        :return: controller dashboard
        """
        game_data_json_filepath = os.path.join(datadir, "game.json")
        print("Loading data from {}".format(game_data_json_filepath))
        game_data = json.load(open(game_data_json_filepath))
        game = Game.from_dict(game_data,
                              Crypto())  # any crypto object will do here
        game_stats = GameStats(game)
        return ControllerDashboard(game_stats, env_name=env_name)
Example #9
0
    def test_transaction_invalid_if_seller_does_not_have_enough_quantities(
            self):
        """Test that a transaction is invalid if the seller does not have enough quantities."""
        nb_agents = 3
        nb_goods = 3
        tx_fee = 1.0
        agent_pbk_to_name = {
            'tac_agent_0_pbk': 'tac_agent_0',
            'tac_agent_1_pbk': 'tac_agent_1',
            'tac_agent_2_pbk': 'tac_agent_2'
        }
        good_pbk_to_name = {
            'tac_good_0_pbk': 'tac_good_0',
            'tac_good_1_pbk': 'tac_good_1',
            'tac_good_2_pbk': 'tac_good_2'
        }
        money_amounts = [20, 20, 20]
        endowments = [[1, 1, 1], [2, 1, 1], [1, 1, 2]]
        utility_params = [[20.0, 40.0, 40.0], [10.0, 50.0, 40.0],
                          [40.0, 30.0, 30.0]]
        eq_prices = [1.0, 1.0, 4.0]
        eq_good_holdings = [[1.0, 1.0, 4.0], [1.0, 5.0, 1.0], [6.0, 1.0, 2.0]]
        eq_money_holdings = [20.0, 20.0, 20.0]

        game_configuration = GameConfiguration(nb_agents, nb_goods, tx_fee,
                                               agent_pbk_to_name,
                                               good_pbk_to_name)
        game_initialization = GameInitialization(money_amounts, endowments,
                                                 utility_params, eq_prices,
                                                 eq_good_holdings,
                                                 eq_money_holdings)

        game = Game(game_configuration, game_initialization)

        tx_id = 'some_tx_id'
        sender_pbk = 'tac_agent_0_pbk'
        is_sender_buyer = True
        counterparty_pbk = 'tac_agent_1_pbk'
        amount = 20
        quantities_by_good = {0: 3, 1: 0, 2: 0}
        invalid_transaction = Transaction(tx_id, is_sender_buyer,
                                          counterparty_pbk, amount,
                                          quantities_by_good, sender_pbk,
                                          Crypto())

        assert not game.is_transaction_valid(invalid_transaction)
Example #10
0
    def from_pb(cls, obj, public_key: str, crypto: Crypto) -> 'Response':
        """
        Parse a string of bytes associated to a response message from the TAC controller.

        :param obj: the string of bytes to be parsed.
        :param public_key: the public key of the recipient.
        :param crypto: the crypto module
        :raises TacError: if the string of bytes cannot be parsed as a Response from the TAC Controller.

        :return: a :class:`~tac.protocol.Response` object.
        """
        try:
            signed_msg = tac_pb2.TACAgent.SignedMessage()
            signed_msg.ParseFromString(obj)

            if crypto.is_confirmed_integrity(signed_msg.message,
                                             signed_msg.signature, public_key):
                msg = tac_pb2.TACController.Message()
                msg.ParseFromString(signed_msg.message)
                case = msg.WhichOneof("msg")
                if case == "cancelled":
                    return Cancelled(public_key, crypto)
                elif case == "game_data":
                    return GameData.from_pb(msg.game_data, public_key, crypto)
                elif case == "tx_confirmation":
                    return TransactionConfirmation(
                        public_key, crypto, msg.tx_confirmation.transaction_id)
                elif case == "state_update":
                    return StateUpdate.from_pb(msg.state_update, public_key,
                                               crypto)
                elif case == "error":
                    return Error.from_pb(msg.error, public_key, crypto)
                else:
                    raise TacError("Unrecognized type of Response.")
            else:
                raise ValueError("Bad signature. Do not trust!")
        except DecodeError as e:
            logger.exception(str(e))
            raise TacError("Error in decoding the message.")
Example #11
0
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#
# ------------------------------------------------------------------------------
"""
Generate a private key to be used for the Trading Agent Competition.

It prints the key in PEM format to the specified file.
"""

from tac.helpers.crypto import Crypto
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption

import argparse
parser = argparse.ArgumentParser("generate_private_key", description=__doc__)
parser.add_argument("out_file",
                    type=str,
                    help="Where to save the private key.")

if __name__ == '__main__':
    args = parser.parse_args()
    crypto = Crypto()
    pem = crypto._private_key.private_bytes(Encoding.PEM,
                                            PrivateFormat.TraditionalOpenSSL,
                                            NoEncryption())
    file = open(args.out_file, "wb")
    file.write(pem)
    file.close()
Example #12
0
 def from_json(cls, d: Dict[str, Any]):
     """Read from json."""
     game = Game.from_dict(d, Crypto())  # any crypto object will do here
     return GameStats(game)