Example #1
0
def get_beacon_shell_context(database_dir: Path,
                             trinity_config: TrinityConfig) -> Dict[str, Any]:
    app_config = trinity_config.get_app_config(BeaconAppConfig)

    ipc_path = trinity_config.database_ipc_path

    db: DatabaseAPI

    trinity_already_running = ipc_path.exists()
    if trinity_already_running:
        db = DBClient.connect(ipc_path)
    else:
        db = LevelDB(database_dir)

    chain_config = app_config.get_chain_config()
    chain = chain_config.beacon_chain_class(db, chain_config.genesis_config)

    chaindb = BeaconChainDB(db, chain_config.genesis_config)
    head = chaindb.get_canonical_head(BeaconBlock)
    return {
        'db': db,
        'chaindb': chaindb,
        'trinity_config': trinity_config,
        'chain_config': chain_config,
        'chain': chain,
        'block_number': head.slot,
        'hex_hash': head.hash_tree_root.hex(),
        'state_root_hex': encode_hex(head.state_root),
        'trinity_already_running': trinity_already_running
    }
def database_server_ipc_path():
    core_db = AtomicDB()
    core_db[b'key-a'] = b'value-a'

    chaindb = ChainDB(core_db)
    # TODO: use a custom chain class only for testing.
    chaindb.persist_header(ROPSTEN_GENESIS_HEADER)

    with tempfile.TemporaryDirectory() as temp_dir:
        trinity_config = TrinityConfig(
            network_id=ROPSTEN_NETWORK_ID,
            data_dir=temp_dir,
        )

        manager = get_chaindb_manager(trinity_config, core_db)
        chaindb_server_process = multiprocessing.Process(
            target=serve_chaindb,
            args=(manager, ),
        )
        chaindb_server_process.start()

        wait_for_ipc(trinity_config.database_ipc_path)

        try:
            yield trinity_config.database_ipc_path
        finally:
            kill_process_gracefully(chaindb_server_process,
                                    logging.getLogger())
Example #3
0
def create_db_server_manager(trinity_config: TrinityConfig,
                             base_db: BaseAtomicDB) -> BaseManager:
    app_config = trinity_config.get_app_config(BeaconAppConfig)
    chain_config = app_config.get_chain_config()
    chaindb = BeaconChainDB(base_db, chain_config.genesis_config)

    if not is_beacon_database_initialized(chaindb, BeaconBlock):
        initialize_beacon_database(chain_config, chaindb, base_db, BeaconBlock)

    # This enables connection when clients launch from another process on the shell
    multiprocessing.current_process().authkey = AUTH_KEY

    class DBManager(BaseManager):
        pass

    DBManager.register('get_db',
                       callable=lambda: TracebackRecorder(base_db),
                       proxytype=AsyncDBProxy)

    DBManager.register(
        'get_chaindb',
        callable=lambda: TracebackRecorder(chaindb),
        proxytype=AsyncBeaconChainDBProxy,
    )

    manager = DBManager(address=str(
        trinity_config.database_ipc_path))  # type: ignore
    return manager
Example #4
0
def create_db_server_manager(trinity_config: TrinityConfig,
                             base_db: BaseAtomicDB) -> BaseManager:
    app_config = trinity_config.get_app_config(BeaconAppConfig)
    chain_config = app_config.get_chain_config()
    chaindb = BeaconChainDB(base_db, chain_config.eth2_config)

    if not is_beacon_database_initialized(chaindb, BeaconBlock):
        initialize_beacon_database(chain_config, chaindb, base_db, BeaconBlock)

    class DBManager(BaseManager):
        pass

    DBManager.register('get_db',
                       callable=lambda: TracebackRecorder(base_db),
                       proxytype=AsyncDBProxy)

    DBManager.register(
        'get_chaindb',
        callable=lambda: TracebackRecorder(chaindb),
        proxytype=AsyncBeaconChainDBProxy,
    )

    manager = DBManager(address=str(
        trinity_config.database_ipc_path))  # type: ignore
    return manager
Example #5
0
def chain_for_config(
    trinity_config: TrinityConfig,
    event_bus: EndpointAPI,
) -> Iterator[Union[AsyncChainAPI, AsyncBeaconChainDB]]:
    if trinity_config.has_app_config(BeaconAppConfig):
        beacon_app_config = trinity_config.get_app_config(BeaconAppConfig)
        with chain_for_beacon_config(trinity_config,
                                     beacon_app_config) as beacon_chain:
            yield beacon_chain
    elif trinity_config.has_app_config(Eth1AppConfig):
        eth1_app_config = trinity_config.get_app_config(Eth1AppConfig)
        with chain_for_eth1_config(trinity_config, eth1_app_config,
                                   event_bus) as eth1_chain:
            yield eth1_chain
    else:
        raise Exception("Unsupported Node Type")
Example #6
0
def trinity_boot(
        args: Namespace, trinity_config: TrinityConfig,
        extra_kwargs: Dict[str, Any], listener: logging.handlers.QueueListener,
        logger: logging.Logger) -> Tuple[multiprocessing.Process, ...]:
    # start the listener thread to handle logs produced by other processes in
    # the local logger.
    listener.start()

    ensure_beacon_dirs(trinity_config.get_app_config(BeaconAppConfig))

    # First initialize the database process.
    database_server_process = ctx.Process(
        name="DB",
        target=run_database_process,
        args=(
            trinity_config,
            LevelDB,
        ),
        kwargs=extra_kwargs,
    )

    # start the processes
    database_server_process.start()
    logger.info("Started DB server process (pid=%d)",
                database_server_process.pid)

    try:
        wait_for_ipc(trinity_config.database_ipc_path)
    except TimeoutError as e:
        logger.error("Timeout waiting for database to start.  Exiting...")
        kill_process_gracefully(database_server_process, logger)
        ArgumentParser().error(message="Timed out waiting for database start")
        return None

    return (database_server_process, )
Example #7
0
async def launch_node_coro(args: Namespace,
                           trinity_config: TrinityConfig) -> None:
    endpoint = TrinityEventBusEndpoint()
    NodeClass = trinity_config.get_app_config(Eth1AppConfig).node_class
    node = NodeClass(endpoint, trinity_config)

    networking_connection_config = ConnectionConfig.from_name(
        NETWORKING_EVENTBUS_ENDPOINT, trinity_config.ipc_dir)

    await endpoint.start_serving(networking_connection_config)
    endpoint.auto_connect_new_announced_endpoints()
    await endpoint.connect_to_endpoints(
        ConnectionConfig.from_name(MAIN_EVENTBUS_ENDPOINT,
                                   trinity_config.ipc_dir),
        # Plugins that run within the networking process broadcast and receive on the
        # the same endpoint
        networking_connection_config,
    )
    await endpoint.announce_endpoint()

    # This is a second PluginManager instance governing plugins in a shared process.
    plugin_manager = PluginManager(SharedProcessScope(endpoint),
                                   get_all_plugins())
    plugin_manager.prepare(args, trinity_config)

    asyncio.ensure_future(
        handle_networking_exit(node, plugin_manager, endpoint))
    asyncio.ensure_future(node.run())
def create_db_server_manager(trinity_config: TrinityConfig,
                             base_db: BaseAtomicDB) -> BaseManager:

    chain_config = trinity_config.get_chain_config()
    chaindb = ChainDB(base_db)

    if not is_database_initialized(chaindb):
        initialize_database(chain_config, chaindb, base_db)

    headerdb = HeaderDB(base_db)

    class DBManager(BaseManager):
        pass

    DBManager.register('get_db',
                       callable=lambda: TracebackRecorder(base_db),
                       proxytype=AsyncDBProxy)

    DBManager.register(
        'get_chaindb',
        callable=lambda: TracebackRecorder(chaindb),
        proxytype=AsyncChainDBProxy,
    )

    DBManager.register(
        'get_headerdb',
        callable=lambda: TracebackRecorder(headerdb),
        proxytype=AsyncHeaderDBProxy,
    )

    manager = DBManager(address=str(
        trinity_config.database_ipc_path))  # type: ignore
    return manager
Example #9
0
async def test_logger_configuration(command,
                                    expected_stderr_logs,
                                    unexpected_stderr_logs,
                                    expected_file_logs,
                                    unexpected_file_logs,
                                    unused_tcp_port):

    command = amend_command_for_unused_port(command, unused_tcp_port)

    def contains_substring(iterable, substring):
        return any(substring in x for x in iterable)

    # Saw occasional (<25%, >5%) failures in CI at 30s because of slow machines or bad luck
    async with AsyncProcessRunner.run(command, timeout_sec=45) as runner:

        stderr_logs = []

        # Collect logs up to the point when the sync begins so that we have enough logs
        # for assertions
        marker_seen_at = 0
        async for line in runner.stderr:
            if marker_seen_at != 0 and time.time() - marker_seen_at > 3:
                break
            if "DiscoveryService" in line:
                marker_seen_at = time.time()
            stderr_logs.append(line)

        for log in expected_stderr_logs:
            if not contains_substring(stderr_logs, log):
                raise AssertionError(f"Log should contain `{log}` but does not")

        for log in unexpected_stderr_logs:
            if contains_substring(stderr_logs, log):
                raise AssertionError(f"Log should not contain `{log}` but does")

        log_dir = TrinityConfig(app_identifier="eth1", network_id=1).log_dir
        log_file_path = max(log_dir.glob('*'), key=os.path.getctime)
        with open(log_file_path) as log_file:
            file_content = log_file.read()

            for log in expected_file_logs:
                if log not in file_content:
                    raise AssertionError(f"Logfile should contain `{log}` but does not")

            for log in unexpected_file_logs:
                if log in file_content:
                    raise AssertionError(f"Logfile should not contain `{log}` but does")
Example #10
0
def get_protocol(trinity_config: TrinityConfig) -> Type[Protocol]:
    # For now DiscoveryByTopicProtocol supports a single topic, so we use the latest
    # version of our supported protocols. Maybe this could be more generic?
    eth1_config = trinity_config.get_app_config(Eth1AppConfig)
    if eth1_config.database_mode is Eth1DbMode.LIGHT:
        return LESProtocolV2
    else:
        return ETHProtocol
Example #11
0
def run_database_process(trinity_config: TrinityConfig, db_class: Type[LevelDB]) -> None:
    with trinity_config.process_id_file('database'):
        app_config = trinity_config.get_app_config(BeaconAppConfig)
        chain_config = app_config.get_chain_config()

        base_db = db_class(db_path=app_config.database_dir)
        chaindb = BeaconChainDB(base_db, chain_config.genesis_config)

        if not is_beacon_database_initialized(chaindb, BeaconBlock):
            initialize_beacon_database(chain_config, chaindb, base_db, BeaconBlock)

        manager = DBManager(base_db)
        with manager.run(trinity_config.database_ipc_path):
            try:
                manager.wait_stopped()
            except KeyboardInterrupt:
                pass
Example #12
0
 def run_monitoring(cls, args: argparse.Namespace,
                    trinity_config: TrinityConfig):
     normalized_name = friendly_filename_or_url("monitoring_ui")
     with trinity_config.process_id_file(normalized_name):
         loop = asyncio.get_event_loop()
         asyncio.ensure_future(monitoring(normalized_name, trinity_config))
         loop.run_forever()
         loop.close()
Example #13
0
def load_trinity_config_from_parser_args(
        parser: argparse.ArgumentParser, args: argparse.Namespace,
        app_identifier: str, sub_configs: SubConfigs) -> TrinityConfig:
    try:
        return TrinityConfig.from_parser_args(args, app_identifier,
                                              sub_configs)
    except AmbigiousFileSystem:
        parser.error(TRINITY_AMBIGIOUS_FILESYSTEM_INFO)
Example #14
0
def test_trinity_config_computed_properties(xdg_trinity_root):
    data_dir = get_local_data_dir('muffin', xdg_trinity_root)
    trinity_config = TrinityConfig(network_id=1, data_dir=data_dir)

    assert trinity_config.network_id == 1
    assert trinity_config.data_dir == data_dir
    assert trinity_config.database_dir == data_dir / DATABASE_DIR_NAME / "full"
    assert trinity_config.nodekey_path == get_nodekey_path(data_dir)
Example #15
0
    def run_shell(cls, args: Namespace, trinity_config: TrinityConfig) -> None:
        config: BaseAppConfig

        if trinity_config.has_app_config(Eth1AppConfig):
            config = trinity_config.get_app_config(Eth1AppConfig)
            context = get_eth1_shell_context(config.database_dir,
                                             trinity_config)
            db_shell(is_ipython_available(), context)
        elif trinity_config.has_app_config(BeaconAppConfig):
            config = trinity_config.get_app_config(BeaconAppConfig)
            context = get_beacon_shell_context(config.database_dir,
                                               trinity_config)
            db_shell(is_ipython_available(), context)
        else:
            cls.get_logger().error(
                "DB Shell only supports the Ethereum 1 and Beacon nodes at this time"
            )
Example #16
0
def run_database_process(trinity_config: TrinityConfig,
                         db_class: Type[AtomicDatabaseAPI]) -> None:
    with trinity_config.process_id_file('database'):
        app_config = trinity_config.get_app_config(Eth1AppConfig)

        base_db = db_class(db_path=app_config.database_dir)
        chaindb = ChainDB(base_db)

        if not is_database_initialized(chaindb):
            chain_config = app_config.get_chain_config()
            initialize_database(chain_config, chaindb, base_db)

        manager = DBManager(base_db)
        with manager.run(trinity_config.database_ipc_path):
            try:
                manager.wait_stopped()
            except KeyboardInterrupt:
                pass
Example #17
0
def test_trinity_config_explicit_properties():
    trinity_config = TrinityConfig(
        network_id=1,
        data_dir='./data-dir',
        nodekey_path='./nodekey'
    )

    assert trinity_config.data_dir == Path('./data-dir').resolve()
    assert trinity_config.nodekey_path == Path('./nodekey').resolve()
Example #18
0
    def setup_eth1_modules(self, trinity_config: TrinityConfig) -> Tuple[BaseRPCModule, ...]:
        db_manager = create_db_consumer_manager(trinity_config.database_ipc_path)

        eth1_app_config = trinity_config.get_app_config(Eth1AppConfig)
        chain_config = trinity_config.get_chain_config()

        chain: BaseAsyncChain

        if eth1_app_config.database_mode is Eth1DbMode.LIGHT:
            header_db = db_manager.get_headerdb()  # type: ignore
            event_bus_light_peer_chain = EventBusLightPeerChain(self.context.event_bus)
            chain = chain_config.light_chain_class(header_db, peer_chain=event_bus_light_peer_chain)
        elif eth1_app_config.database_mode is Eth1DbMode.FULL:
            db = db_manager.get_db()  # type: ignore
            chain = chain_config.full_chain_class(db)
        else:
            raise Exception(f"Unsupported Database Mode: {eth1_app_config.database_mode}")

        return initialize_eth1_modules(chain, self.event_bus)
Example #19
0
def launch_node(args: Namespace, trinity_config: TrinityConfig) -> None:
    with trinity_config.process_id_file('networking'):
        # The `networking` process creates a process pool executor to offload cpu intensive
        # tasks. We should revisit that when we move the sync in its own process
        ensure_global_asyncio_executor()

        asyncio.ensure_future(launch_node_coro(args, trinity_config))
        loop = asyncio.get_event_loop()
        loop.run_forever()
        loop.close()
def test_trinity_config_computed_properties_custom_xdg(tmpdir, xdg_trinity_root):
    alt_xdg_root = tmpdir.mkdir('trinity-custom')
    assert not is_under_path(alt_xdg_root, xdg_trinity_root)

    data_dir = get_data_dir_for_network_id(1, alt_xdg_root)
    trinity_config = TrinityConfig(trinity_root_dir=alt_xdg_root, network_id=1)

    assert trinity_config.network_id == 1
    assert trinity_config.data_dir == data_dir
    assert trinity_config.nodekey_path == get_nodekey_path(data_dir)
Example #21
0
    def __init__(self, event_bus: Endpoint,
                 trinity_config: TrinityConfig) -> None:
        super().__init__(event_bus, trinity_config)
        self._bootstrap_nodes = trinity_config.bootstrap_nodes
        self._preferred_nodes = trinity_config.preferred_nodes
        self._node_key = trinity_config.nodekey
        self._node_port = trinity_config.port
        self._max_peers = trinity_config.max_peers

        app_config = trinity_config.get_app_config(Eth1AppConfig)
        self._nodedb_path = app_config.nodedb_path
Example #22
0
def run_database_process(trinity_config: TrinityConfig,
                         db_class: Type[BaseDB]) -> None:
    with trinity_config.process_id_file('database'):
        app_config = trinity_config.get_app_config(Eth1AppConfig)

        base_db = db_class(db_path=app_config.database_dir)

        manager = get_chaindb_manager(trinity_config, base_db)
        server = manager.get_server()  # type: ignore

        def _sigint_handler(*args: Any) -> None:
            server.stop_event.set()

        signal.signal(signal.SIGINT, _sigint_handler)

        try:
            server.serve_forever()
        except SystemExit:
            server.stop_event.set()
            raise
Example #23
0
def launch_node(args: Namespace, trinity_config: TrinityConfig,
                endpoint: Endpoint) -> None:
    with trinity_config.process_id_file('networking'):

        NodeClass = trinity_config.get_app_config(Eth1AppConfig).node_class
        node = NodeClass(endpoint, trinity_config)
        loop = node.get_event_loop()

        endpoint.connect_no_wait(loop)
        # This is a second PluginManager instance governing plugins in a shared process.
        plugin_manager = setup_plugins(SharedProcessScope(endpoint),
                                       get_all_plugins())
        plugin_manager.prepare(args, trinity_config)

        asyncio.ensure_future(handle_networking_exit(node, plugin_manager,
                                                     endpoint),
                              loop=loop)
        asyncio.ensure_future(node.run(), loop=loop)
        loop.run_forever()
        loop.close()
Example #24
0
def test_chain_config_computed_properties_custom_xdg(tmpdir, xdg_trinity_root):
    alt_xdg_root = tmpdir.mkdir('trinity-custom')
    assert not is_under_path(alt_xdg_root, xdg_trinity_root)

    data_dir = get_data_dir_for_network_id(1, alt_xdg_root)
    chain_config = TrinityConfig(trinity_root_dir=alt_xdg_root, network_id=1)

    assert chain_config.network_id == 1
    assert chain_config.data_dir == data_dir
    assert chain_config.database_dir == data_dir / DATABASE_DIR_NAME / "full"
    assert chain_config.nodekey_path == get_nodekey_path(data_dir)
Example #25
0
def get_protocol(trinity_config: TrinityConfig) -> Type[ProtocolAPI]:
    # For now DiscoveryByTopicProtocol supports a single topic, so we use the latest
    # version of our supported protocols. Maybe this could be more generic?
    # TODO: This needs to support the beacon protocol when we have a way to
    # check the config, if trinity is being run as a beacon node.

    eth1_config = trinity_config.get_app_config(Eth1AppConfig)
    if eth1_config.database_mode is Eth1DbMode.LIGHT:
        return LESProtocolV2
    else:
        return ETHProtocol
Example #26
0
def _setup_standalone_component(
    component_type: Union[Type['TrioIsolatedComponent'],
                          Type['AsyncioIsolatedComponent']],
    app_identifier: str,
) -> Tuple[Union['TrioIsolatedComponent', 'AsyncioIsolatedComponent'], Tuple[
        str, ...]]:
    if app_identifier == APP_IDENTIFIER_ETH1:
        app_cfg: Type[BaseAppConfig] = Eth1AppConfig
    elif app_identifier == APP_IDENTIFIER_BEACON:
        app_cfg = BeaconAppConfig
    else:
        raise ValueError("Unknown app identifier: %s", app_identifier)

    # Require a root dir to be specified as we don't want to mess with the default one.
    for action in parser._actions:
        if action.dest == 'trinity_root_dir':
            action.required = True
            break

    component_type.configure_parser(parser, subparser)
    parser.add_argument(
        '--connect-to-endpoints',
        help=
        "A list of event bus IPC files for components we should connect to",
        nargs='+',
        default=tuple(),
    )
    args = parser.parse_args()
    # FIXME: Figure out a way to avoid having to set this.
    args.sync_mode = SYNC_FULL
    args.enable_metrics = False

    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s %(levelname)s: %(message)s',
                        datefmt='%H:%M:%S')
    if args.log_levels is not None:
        for name, level in args.log_levels.items():
            if name is None:
                name = ''
            get_logger(name).setLevel(level)

    trinity_config = TrinityConfig.from_parser_args(args, app_identifier,
                                                    (app_cfg, ))
    trinity_config.trinity_root_dir.mkdir(exist_ok=True)
    if not is_data_dir_initialized(trinity_config):
        initialize_data_dir(trinity_config)
    boot_info = BootInfo(
        args=args,
        trinity_config=trinity_config,
        min_log_level=None,
        logger_levels=None,
        profile=False,
    )
    return component_type(boot_info), args.connect_to_endpoints
Example #27
0
def trinity_boot(args: Namespace, trinity_config: TrinityConfig,
                 extra_kwargs: Dict[str, Any], plugin_manager: PluginManager,
                 listener: logging.handlers.QueueListener,
                 main_endpoint: TrinityMainEventBusEndpoint,
                 logger: logging.Logger) -> None:
    # start the listener thread to handle logs produced by other processes in
    # the local logger.
    listener.start()

    ensure_beacon_dirs(trinity_config.get_app_config(BeaconAppConfig))

    # First initialize the database process.
    database_server_process = ctx.Process(
        name="DB",
        target=run_database_process,
        args=(
            trinity_config,
            LevelDB,
        ),
        kwargs=extra_kwargs,
    )

    # start the processes
    database_server_process.start()
    logger.info("Started DB server process (pid=%d)",
                database_server_process.pid)

    try:
        wait_for_ipc(trinity_config.database_ipc_path)
    except TimeoutError as e:
        logger.error("Timeout waiting for database to start.  Exiting...")
        kill_process_gracefully(database_server_process, logger)
        ArgumentParser().error(message="Timed out waiting for database start")

    def kill_trinity_with_reason(reason: str) -> None:
        kill_trinity_gracefully(trinity_config,
                                logger, (),
                                plugin_manager,
                                main_endpoint,
                                reason=reason)

    main_endpoint.subscribe(ShutdownRequest,
                            lambda ev: kill_trinity_with_reason(ev.reason))

    plugin_manager.prepare(args, trinity_config, extra_kwargs)

    try:
        loop = asyncio.get_event_loop()
        loop.add_signal_handler(signal.SIGTERM,
                                lambda: kill_trinity_with_reason("SIGTERM"))
        loop.run_forever()
        loop.close()
    except KeyboardInterrupt:
        kill_trinity_with_reason("CTRL+C / Keyboard Interrupt")
Example #28
0
def test_sync_mode_effect_on_db_and_node_type(sync_mode, expected_full_db,
                                              expected_node_class):

    trinity_config = TrinityConfig(network_id=1)
    eth1_app_config = Eth1AppConfig(trinity_config, sync_mode)
    assert eth1_app_config.sync_mode == sync_mode
    assert eth1_app_config.node_class == expected_node_class
    if expected_full_db:
        assert eth1_app_config.database_mode is Eth1DbMode.FULL
    else:
        assert eth1_app_config.database_mode is Eth1DbMode.LIGHT
def test_trinity_config_app_identifier(xdg_trinity_root, app_identifier, expected_suffix):

    data_dir = get_local_data_dir('muffin', xdg_trinity_root)
    trinity_config = TrinityConfig(network_id=1, data_dir=data_dir, app_identifier=app_identifier)

    assert trinity_config.network_id == 1
    assert trinity_config.data_dir == data_dir
    assert trinity_config.logfile_path == data_dir / (LOG_DIR + expected_suffix) / LOG_FILE
    assert trinity_config.jsonrpc_ipc_path == data_dir / (IPC_DIR + expected_suffix) / JSONRPC_SOCKET_FILENAME  # noqa: E501
    assert trinity_config.database_ipc_path == data_dir / (IPC_DIR + expected_suffix) / DATABASE_SOCKET_FILENAME  # noqa: E501
    assert trinity_config.pid_dir == data_dir / (PID_DIR + expected_suffix)
    assert trinity_config.nodekey_path == get_nodekey_path(data_dir)
Example #30
0
def get_chain(trinity_config: TrinityConfig) -> ChainAPI:
    app_config = trinity_config.get_app_config(Eth1AppConfig)

    ensure_eth1_dirs(app_config)

    base_db = LevelDB(db_path=app_config.database_dir)
    chain_config = app_config.get_chain_config()
    chain = chain_config.full_chain_class(AtomicDB(base_db))

    initialize_database(chain_config, chain.chaindb, base_db)

    return chain