Beispiel #1
0
def test_setup_data_folder():
    # This method should create a folder if it does not exist, and do nothing otherwise
    test_folder = "test_folder"
    assert not os.path.isdir(test_folder)

    setup_data_folder(test_folder)

    assert os.path.isdir(test_folder)

    os.rmdir(test_folder)
Beispiel #2
0
    def __init__(self, data_dir, command_line_conf):
        # Loads config and sets up the data folder and log file
        config_loader = ConfigLoader(data_dir, CONF_FILE_NAME, DEFAULT_CONF,
                                     command_line_conf)
        config = config_loader.build_config()

        setup_data_folder(data_dir)

        teos_rpc_host = config.get("RPC_BIND")
        teos_rpc_port = config.get("RPC_PORT")

        self.rpc_client = RPCClient(teos_rpc_host, teos_rpc_port)
Beispiel #3
0
def main(config):
    setup_data_folder(config.get("DATA_DIR"))

    logging_server_ready = multiprocessing.Event()
    stop_logging_server = multiprocessing.Event()
    logging_port = multiprocessing.Value("i")
    logging_process = multiprocessing.Process(
        target=serve_logging,
        daemon=True,
        args=(config.get("LOG_FILE"), logging_port, config.get("DAEMON"),
              logging_server_ready, stop_logging_server),
    )
    logging_process.start()
    logging_server_ready.wait()

    setup_logging(logging_port.value)
    logger = get_logger(component="Daemon")

    if not os.path.exists(
            config.get("TEOS_SECRET_KEY")) or config.get("OVERWRITE_KEY"):
        logger.info("Generating a new key pair")
        sk = Cryptographer.generate_key()
        Cryptographer.save_key_file(sk.to_der(), "teos_sk",
                                    config.get("DATA_DIR"))

    else:
        logger.info("Tower identity found. Loading keys")
        secret_key_der = Cryptographer.load_key_file(
            config.get("TEOS_SECRET_KEY"))

        if not secret_key_der:
            raise IOError("TEOS private key cannot be loaded")
        sk = Cryptographer.load_private_key_der(secret_key_der)

    # Windows cannot run gunicorn
    if os.name == "nt" and config.get("WSGI") == "gunicorn":
        logger.warning(
            "Windows cannot run gunicorn as WSGI. Changing to waitress")
        config["WSGI"] = "waitress"

    try:
        TeosDaemon(config, sk, logger, logging_port.value, stop_logging_server,
                   logging_process).start()
    except Exception as e:
        logger.error("An error occurred: {}. Shutting down".format(e))
        stop_logging_server.set()
        logging_process.join()
        exit(1)
Beispiel #4
0
def main(command_line_conf):
    global db_manager, chain_monitor

    signal(SIGINT, handle_signals)
    signal(SIGTERM, handle_signals)
    signal(SIGQUIT, handle_signals)

    # Loads config and sets up the data folder and log file
    config_loader = ConfigLoader(DATA_DIR, CONF_FILE_NAME, DEFAULT_CONF,
                                 command_line_conf)
    config = config_loader.build_config()
    setup_data_folder(DATA_DIR)
    setup_logging(config.get("LOG_FILE"), LOG_PREFIX)

    logger.info("Starting TEOS")
    db_manager = DBManager(config.get("DB_PATH"))

    bitcoind_connect_params = {
        k: v
        for k, v in config.items() if k.startswith("BTC")
    }
    bitcoind_feed_params = {
        k: v
        for k, v in config.items() if k.startswith("FEED")
    }

    if not can_connect_to_bitcoind(bitcoind_connect_params):
        logger.error("Can't connect to bitcoind. Shutting down")

    elif not in_correct_network(bitcoind_connect_params,
                                config.get("BTC_NETWORK")):
        logger.error(
            "bitcoind is running on a different network, check conf.py and bitcoin.conf. Shutting down"
        )

    else:
        try:
            secret_key_der = Cryptographer.load_key_file(
                config.get("TEOS_SECRET_KEY"))
            if not secret_key_der:
                raise IOError("TEOS private key can't be loaded")

            block_processor = BlockProcessor(bitcoind_connect_params)
            carrier = Carrier(bitcoind_connect_params)

            responder = Responder(db_manager, carrier, block_processor)
            watcher = Watcher(
                db_manager,
                block_processor,
                responder,
                secret_key_der,
                config.get("MAX_APPOINTMENTS"),
                config.get("EXPIRY_DELTA"),
            )

            # Create the chain monitor and start monitoring the chain
            chain_monitor = ChainMonitor(watcher.block_queue,
                                         watcher.responder.block_queue,
                                         block_processor, bitcoind_feed_params)

            watcher_appointments_data = db_manager.load_watcher_appointments()
            responder_trackers_data = db_manager.load_responder_trackers()

            if len(watcher_appointments_data) == 0 and len(
                    responder_trackers_data) == 0:
                logger.info("Fresh bootstrap")

                watcher.awake()
                watcher.responder.awake()

            else:
                logger.info("Bootstrapping from backed up data")

                # Update the Watcher backed up data if found.
                if len(watcher_appointments_data) != 0:
                    watcher.appointments, watcher.locator_uuid_map = Builder.build_appointments(
                        watcher_appointments_data)

                # Update the Responder with backed up data if found.
                if len(responder_trackers_data) != 0:
                    watcher.responder.trackers, watcher.responder.tx_tracker_map = Builder.build_trackers(
                        responder_trackers_data)

                # Awaking components so the states can be updated.
                watcher.awake()
                watcher.responder.awake()

                last_block_watcher = db_manager.load_last_block_hash_watcher()
                last_block_responder = db_manager.load_last_block_hash_responder(
                )

                # Populate the block queues with data if they've missed some while offline. If the blocks of both match
                # we don't perform the search twice.

                # FIXME: 32-reorgs-offline dropped txs are not used at this point.
                last_common_ancestor_watcher, dropped_txs_watcher = block_processor.find_last_common_ancestor(
                    last_block_watcher)
                missed_blocks_watcher = block_processor.get_missed_blocks(
                    last_common_ancestor_watcher)

                if last_block_watcher == last_block_responder:
                    dropped_txs_responder = dropped_txs_watcher
                    missed_blocks_responder = missed_blocks_watcher

                else:
                    last_common_ancestor_responder, dropped_txs_responder = block_processor.find_last_common_ancestor(
                        last_block_responder)
                    missed_blocks_responder = block_processor.get_missed_blocks(
                        last_common_ancestor_responder)

                # If only one of the instances needs to be updated, it can be done separately.
                if len(missed_blocks_watcher
                       ) == 0 and len(missed_blocks_responder) != 0:
                    Builder.populate_block_queue(watcher.responder.block_queue,
                                                 missed_blocks_responder)
                    watcher.responder.block_queue.join()

                elif len(missed_blocks_responder
                         ) == 0 and len(missed_blocks_watcher) != 0:
                    Builder.populate_block_queue(watcher.block_queue,
                                                 missed_blocks_watcher)
                    watcher.block_queue.join()

                # Otherwise they need to be updated at the same time, block by block
                elif len(missed_blocks_responder) != 0 and len(
                        missed_blocks_watcher) != 0:
                    Builder.update_states(watcher, missed_blocks_watcher,
                                          missed_blocks_responder)

            # Fire the API and the ChainMonitor
            # FIXME: 92-block-data-during-bootstrap-db
            chain_monitor.monitor_chain()
            API(Inspector(block_processor, config.get("MIN_TO_SELF_DELAY")),
                watcher).start()
        except Exception as e:
            logger.error("An error occurred: {}. Shutting down".format(e))
            exit(1)
Beispiel #5
0
 def __init__(self, data_dir, config):
     setup_data_folder(data_dir)
     self.rpc_client = RPCClient(config.get("RPC_BIND"),
                                 config.get("RPC_PORT"))
Beispiel #6
0
def main(command, args, command_line_conf):
    # Loads config and sets up the data folder and log file
    config_loader = ConfigLoader(DATA_DIR, CONF_FILE_NAME, DEFAULT_CONF,
                                 command_line_conf)
    config = config_loader.build_config()

    setup_data_folder(DATA_DIR)
    setup_logging(config.get("LOG_FILE"), LOG_PREFIX)

    # Set the teos url
    teos_url = "{}:{}".format(config.get("API_CONNECT"),
                              config.get("API_PORT"))
    # If an http or https prefix if found, leaves the server as is. Otherwise defaults to http.
    if not teos_url.startswith("http"):
        teos_url = "http://" + teos_url

    try:
        teos_id, user_sk, user_id = load_keys(config.get("TEOS_PUBLIC_KEY"),
                                              config.get("CLI_PRIVATE_KEY"))

        if command == "register":
            register_data = register(user_id, teos_url)
            logger.info("Registration succeeded. Available slots: {}".format(
                register_data.get("available_slots")))

        if command == "add_appointment":
            appointment_data = parse_add_appointment_args(args)
            appointment, signature = add_appointment(appointment_data, user_sk,
                                                     teos_id, teos_url)
            save_appointment_receipt(appointment.to_dict(), signature,
                                     config.get("APPOINTMENTS_FOLDER_NAME"))

        elif command == "get_appointment":
            if not args:
                logger.error("No arguments were given")

            else:
                arg_opt = args.pop(0)

                if arg_opt in ["-h", "--help"]:
                    sys.exit(help_get_appointment())

                appointment_data = get_appointment(arg_opt, user_sk, teos_id,
                                                   teos_url)
                if appointment_data:
                    print(appointment_data)

        elif command == "get_all_appointments":
            appointment_data = get_all_appointments(teos_url)
            if appointment_data:
                print(appointment_data)

        elif command == "help":
            if args:
                command = args.pop(0)

                if command == "register":
                    sys.exit(help_register())

                if command == "add_appointment":
                    sys.exit(help_add_appointment())

                elif command == "get_appointment":
                    sys.exit(help_get_appointment())

                elif command == "get_all_appointments":
                    sys.exit(help_get_all_appointments())

                else:
                    logger.error(
                        "Unknown command. Use help to check the list of available commands"
                    )

            else:
                sys.exit(show_usage())

    except (FileNotFoundError, IOError, ConnectionError, ValueError) as e:
        logger.error(str(e))
    except (InvalidKey, InvalidParameter, TowerResponseError,
            SignatureError) as e:
        logger.error(e.msg, **e.kwargs)
    except Exception as e:
        logger.error("Unknown error occurred", error=str(e))
Beispiel #7
0
def main(command, args, config):
    setup_data_folder(config.get("DATA_DIR"))

    # Set the teos url
    teos_url = "{}:{}".format(config.get("API_CONNECT"),
                              config.get("API_PORT"))
    # If an http or https prefix if found, leaves the server as is. Otherwise defaults to http.
    if not teos_url.startswith("http"):
        teos_url = "http://" + teos_url

    try:
        if os.path.exists(config.get("USER_PRIVATE_KEY")):
            logger.debug("Client id found. Loading keys")
            user_sk, user_id = load_keys(config.get("USER_PRIVATE_KEY"))

        else:
            logger.info("Client id not found. Generating new keys")
            user_sk = Cryptographer.generate_key()
            Cryptographer.save_key_file(user_sk.to_der(), "user_sk",
                                        config.get("DATA_DIR"))
            user_id = Cryptographer.get_compressed_pk(user_sk.public_key)

        if command == "register":
            if not args:
                raise InvalidParameter(
                    "Cannot register. No tower id was given")
            else:
                teos_id = args.pop(0)
                if not is_compressed_pk(teos_id):
                    raise InvalidParameter(
                        "Cannot register. Tower id has invalid format")

                available_slots, subscription_expiry = register(
                    user_id, teos_id, teos_url)
                logger.info(
                    "Registration succeeded. Available slots: {}".format(
                        available_slots))
                logger.info("Subscription expires at block {}".format(
                    subscription_expiry))

                teos_id_file = os.path.join(config.get("DATA_DIR"), "teos_pk")
                Cryptographer.save_key_file(bytes.fromhex(teos_id),
                                            teos_id_file,
                                            config.get("DATA_DIR"))

        if command == "add_appointment":
            teos_id = load_teos_id(config.get("TEOS_PUBLIC_KEY"))
            appointment_data = parse_add_appointment_args(args)
            appointment = create_appointment(appointment_data)
            start_block, signature = add_appointment(appointment, user_sk,
                                                     teos_id, teos_url)
            save_appointment_receipt(appointment.to_dict(), start_block,
                                     signature,
                                     config.get("APPOINTMENTS_FOLDER_NAME"))

        elif command == "get_appointment":
            if not args:
                logger.error("No arguments were given")

            else:
                arg_opt = args.pop(0)

                if arg_opt in ["-h", "--help"]:
                    sys.exit(help_get_appointment())

                teos_id = load_teos_id(config.get("TEOS_PUBLIC_KEY"))
                appointment_data = get_appointment(arg_opt, user_sk, teos_id,
                                                   teos_url)
                if appointment_data:
                    logger.info(json.dumps(appointment_data, indent=4))

        elif command == "get_subscription_info":
            if args:
                arg_opt = args.pop(0)

                if arg_opt in ["-h", "--help"]:
                    sys.exit(help_get_subscription_info())

            teos_id = load_teos_id(config.get("TEOS_PUBLIC_KEY"))
            subscription_info = get_subscription_info(user_sk, teos_id,
                                                      teos_url)
            if subscription_info:
                logger.info(json.dumps(subscription_info, indent=4))

        elif command == "help":
            if args:
                command = args.pop(0)

                if command == "register":
                    sys.exit(help_register())

                if command == "add_appointment":
                    sys.exit(help_add_appointment())

                if command == "get_subscription_info":
                    sys.exit(help_get_subscription_info())

                elif command == "get_appointment":
                    sys.exit(help_get_appointment())

                else:
                    logger.error(
                        "Unknown command. Use help to check the list of available commands"
                    )

            else:
                sys.exit(show_usage())

    except (
            FileNotFoundError,
            IOError,
            ConnectionError,
            ValueError,
            BasicException,
    ) as e:
        logger.error(str(e))
    except Exception as e:
        logger.error("Unknown error occurred", error=str(e))
Beispiel #8
0
def main(args, command_line_conf):
    # Loads config and sets up the data folder and log file
    config_loader = ConfigLoader(DATA_DIR, CONF_FILE_NAME, DEFAULT_CONF,
                                 command_line_conf)
    config = config_loader.build_config()

    setup_data_folder(DATA_DIR)
    setup_logging(config.get("LOG_FILE"), LOG_PREFIX)

    # Set the teos url
    teos_url = "{}:{}".format(config.get("TEOS_SERVER"),
                              config.get("TEOS_PORT"))
    # If an http or https prefix if found, leaves the server as is. Otherwise defaults to http.
    if not teos_url.startswith("http"):
        teos_url = "http://" + teos_url

    try:
        if args:
            command = args.pop(0)

            if command in commands:
                if command == "add_appointment":
                    add_appointment(args, teos_url, config)

                elif command == "get_appointment":
                    if not args:
                        logger.error("No arguments were given")

                    else:
                        arg_opt = args.pop(0)

                        if arg_opt in ["-h", "--help"]:
                            sys.exit(help_get_appointment())

                        get_appointment_endpoint = "{}/get_appointment".format(
                            teos_url)
                        appointment_data = get_appointment(
                            arg_opt, get_appointment_endpoint)
                        if appointment_data:
                            print(appointment_data)

                elif command == "help":
                    if args:
                        command = args.pop(0)

                        if command == "add_appointment":
                            sys.exit(help_add_appointment())

                        elif command == "get_appointment":
                            sys.exit(help_get_appointment())

                        else:
                            logger.error(
                                "Unknown command. Use help to check the list of available commands"
                            )

                    else:
                        sys.exit(show_usage())

            else:
                logger.error(
                    "Unknown command. Use help to check the list of available commands"
                )

        else:
            logger.error(
                "No command provided. Use help to check the list of available commands"
            )

    except json.JSONDecodeError:
        logger.error("Non-JSON encoded appointment passed as parameter")