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)
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)
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)
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)
def __init__(self, data_dir, config): setup_data_folder(data_dir) self.rpc_client = RPCClient(config.get("RPC_BIND"), config.get("RPC_PORT"))
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))
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))
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")