From c411fd8d90dea7485b79505495c2853999cf5d6b Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Cornilleau Date: Tue, 25 Nov 2025 20:17:01 +0100 Subject: [PATCH 1/4] TezosX/L2Node: read kernel runtime feature flags --- etherlink/bin_node/lib_dev/durable_storage.ml | 13 +++++++++++++ etherlink/bin_node/lib_dev/services_backend_sig.ml | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/etherlink/bin_node/lib_dev/durable_storage.ml b/etherlink/bin_node/lib_dev/durable_storage.ml index ffdeba5e37f9..a4e165ca7b47 100644 --- a/etherlink/bin_node/lib_dev/durable_storage.ml +++ b/etherlink/bin_node/lib_dev/durable_storage.ml @@ -121,6 +121,14 @@ let block_number ~root read n = @@ Invalid_block_structure "Unexpected [None] value for [current_number]'s [answer]") +let list_runtimes read = + let open Lwt_result_syntax in + let check_runtime r = + let* bytes_opt = read (Tezosx.feature_flag r) in + if Option.is_some bytes_opt then return @@ Some r else return None + in + List.filter_map_ep check_runtime Tezosx.known_runtimes + module Make (Reader : READER) = struct let read_with_state ?block () = let open Lwt_result_syntax in @@ -181,4 +189,9 @@ module Make (Reader : READER) = struct let open Lwt_result_syntax in let* read = read_with_state () in block_number ~root read Durable_storage_path.Block.Current + + let list_runtimes () = + let open Lwt_result_syntax in + let* read = read_with_state () in + list_runtimes read end diff --git a/etherlink/bin_node/lib_dev/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index 80c1ee04d263..af41d351b91c 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -79,6 +79,10 @@ module type S = sig val l2_levels_of_l1_level : int32 -> Evm_store.L1_l2_finalized_levels.t option tzresult Lwt.t + + (** [list_runtimes ()] returns the list of runtimes activated in the kernel, + according to the feature flags set in durable storage. *) + val list_runtimes : unit -> Tezosx.runtime list tzresult Lwt.t end module type Backend = sig -- GitLab From a15281467e707214d6ef6aff0fb350780c2f9cc1 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Cornilleau Date: Wed, 26 Nov 2025 15:33:48 +0100 Subject: [PATCH 2/4] TezosX/L2Node: runtime event --- etherlink/bin_node/lib_dev/rpc_server.ml | 5 ++++- etherlink/bin_node/lib_dev/tezosx.ml | 5 +++++ etherlink/bin_node/lib_dev/tezosx.mli | 2 ++ etherlink/bin_node/lib_dev/tezosx_events.ml | 20 ++++++++++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 etherlink/bin_node/lib_dev/tezosx_events.ml diff --git a/etherlink/bin_node/lib_dev/rpc_server.ml b/etherlink/bin_node/lib_dev/rpc_server.ml index 511b716e7ef6..67f1e86e5360 100644 --- a/etherlink/bin_node/lib_dev/rpc_server.ml +++ b/etherlink/bin_node/lib_dev/rpc_server.ml @@ -167,9 +167,9 @@ let start_public_server (type f) ~(mode : f Mode.t) in let*? () = Rpc_types.check_rpc_server_config rpc_server_family config in let* register_tezos_services = + let (module Backend : Services_backend_sig.S), _ = ctxt in match rpc_server_family with | Rpc_types.Single_chain_node_rpc_server Michelson -> - let (module Backend : Services_backend_sig.S), _ = ctxt in let* l2_chain_id = match l2_chain_id with | Some l2_chain_id -> return l2_chain_id @@ -227,6 +227,9 @@ let start_public_server (type f) ~(mode : f Mode.t) in return hash) | Single_chain_node_rpc_server EVM | Multichain_sequencer_rpc_server -> + let* runtimes = Backend.list_runtimes () in + let*! _ = List.map_p Tezosx_events.runtime_activated runtimes in + return @@ Evm_directory.empty config.experimental_features.rpc_server in (* If spawn_rpc is defined, use it as intermediate *) diff --git a/etherlink/bin_node/lib_dev/tezosx.ml b/etherlink/bin_node/lib_dev/tezosx.ml index ade13d79901d..8b1be962e88e 100644 --- a/etherlink/bin_node/lib_dev/tezosx.ml +++ b/etherlink/bin_node/lib_dev/tezosx.ml @@ -18,3 +18,8 @@ let pp_runtime fmt runtime = Format.pp_print_string fmt (string_of_runtime runtime) let feature_flag = function Tezos -> "/evm/feature_flags/enable_tezos_runtime" + +let runtime_encoding : runtime Data_encoding.t = + let open Data_encoding in + (* FIXME: use string_enum instead once we have more than one runtime *) + conv (fun _ -> ()) (fun () -> Tezos) (constant "tezos") diff --git a/etherlink/bin_node/lib_dev/tezosx.mli b/etherlink/bin_node/lib_dev/tezosx.mli index 02c3982e1747..a477a9c0d79a 100644 --- a/etherlink/bin_node/lib_dev/tezosx.mli +++ b/etherlink/bin_node/lib_dev/tezosx.mli @@ -9,6 +9,8 @@ runtime in Tezos X. *) type runtime = Tezos +val runtime_encoding : runtime Data_encoding.t + val runtime_of_string_opt : string -> runtime option val string_of_runtime : runtime -> string diff --git a/etherlink/bin_node/lib_dev/tezosx_events.ml b/etherlink/bin_node/lib_dev/tezosx_events.ml new file mode 100644 index 000000000000..3159799818bb --- /dev/null +++ b/etherlink/bin_node/lib_dev/tezosx_events.ml @@ -0,0 +1,20 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* SPDX-FileCopyrightText: 2025 Nomadic Labs *) +(* *) +(*****************************************************************************) + +include Internal_event.Simple + +let section = Events.section @ ["tezosx"] + +let runtime_activated = + declare_1 + ~section + ~name:"runtime_activated" + ~msg:"the runtime {runtime} is activated" + ~level:Notice + ("runtime", Tezosx.runtime_encoding) + +let runtime_activated runtime = emit runtime_activated runtime -- GitLab From 9f8b4fce3f2c3274e0bc609f10d7efec67129af3 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Cornilleau Date: Mon, 1 Dec 2025 11:00:02 +0100 Subject: [PATCH 3/4] TezosX/L2Node: tezos runtime backend --- .../bin_node/lib_dev/services_backend_sig.ml | 3 ++ etherlink/bin_node/lib_dev/tezos_backend.ml | 45 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 etherlink/bin_node/lib_dev/tezos_backend.ml diff --git a/etherlink/bin_node/lib_dev/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index af41d351b91c..21a56b58b655 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -9,6 +9,8 @@ module type S = sig module Etherlink_block_storage : Block_storage_sig.S + module Tezos : Tezlink_backend_sig.S + module Tezlink : Tezlink_backend_sig.S module Etherlink : Etherlink_backend_sig.S @@ -138,6 +140,7 @@ module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct module Tezlink_block_storage = Tezlink_durable_storage.Make_block_storage (Backend.Reader) module SimulatorBackend = Backend.SimulatorBackend + module Tezos = Tezos_backend.Make (Backend.SimulatorBackend) module Tezlink = Tezlink_services_impl.Make diff --git a/etherlink/bin_node/lib_dev/tezos_backend.ml b/etherlink/bin_node/lib_dev/tezos_backend.ml new file mode 100644 index 000000000000..5a04f18e748a --- /dev/null +++ b/etherlink/bin_node/lib_dev/tezos_backend.ml @@ -0,0 +1,45 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* SPDX-FileCopyrightText: 2025 Nomadic Labs *) +(* *) +(*****************************************************************************) + +module Make (Backend : Simulator.SimulationBackend) : Tezlink_backend_sig.S = +struct + type block_param = + [ `Head of int32 + | `Level of int32 + | `Hash of Ethereum_types.block_hash * int32 ] + + let constants _chain (_block : block_param) = + failwith "Not Implemented Yet (%s)" __LOC__ + + let current_level _ _ ~offset:_ = failwith "Not Implemented Yet (%s)" __LOC__ + + let balance _chain _block _c = failwith "Not Implemented Yet (%s)" __LOC__ + + let bootstrap_accounts () = failwith "Not Implemented Yet (%s)" __LOC__ + + let get_storage _chain _block _c = failwith "Not Implemented Yet (%s)" __LOC__ + + let get_code _chain _block _c = failwith "Not Implemented Yet (%s)" __LOC__ + + let get_script _chain _block _c = failwith "Not Implemented Yet (%s)" __LOC__ + + let manager_key _chain _block _c = failwith "Not Implemented Yet (%s)" __LOC__ + + let counter _chain _block _c = failwith "Not Implemented Yet (%s)" __LOC__ + + let block _chain _block = failwith "Not Implemented Yet (%s)" __LOC__ + + let monitor_heads _chain _query = + Stdlib.failwith (Format.sprintf "Not Implemented Yet (%s)" __LOC__) + + let bootstrapped () = failwith "Not Implemented Yet (%s)" __LOC__ + + let block_hash _chain _block = failwith "Not Implemented Yet (%s)" __LOC__ + + let simulate_operation ~chain_id:_ ~skip_signature:_ _op _hash _block = + failwith "Not Implemented Yet (%s)" __LOC__ +end -- GitLab From b3597743712d7348ce3b96f055d3fcfc21b00f71 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Cornilleau Date: Thu, 27 Nov 2025 17:47:26 +0100 Subject: [PATCH 4/4] TezosX/L2Node: register Tezos RPC if Tezos runtime active --- etherlink/bin_node/lib_dev/rpc_server.ml | 46 +++++++++++++++---- etherlink/bin_node/lib_dev/tezosx_events.ml | 11 +++++ etherlink/bin_node/lib_dev/tezosx_rpc.ml | 16 +++++++ etherlink/bin_node/lib_dev/tezosx_rpc.mli | 13 ++++++ .../EVM node- list events regression.out | 16 +++++++ 5 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 etherlink/bin_node/lib_dev/tezosx_rpc.ml create mode 100644 etherlink/bin_node/lib_dev/tezosx_rpc.mli diff --git a/etherlink/bin_node/lib_dev/rpc_server.ml b/etherlink/bin_node/lib_dev/rpc_server.ml index 67f1e86e5360..0b1981200e7b 100644 --- a/etherlink/bin_node/lib_dev/rpc_server.ml +++ b/etherlink/bin_node/lib_dev/rpc_server.ml @@ -170,11 +170,6 @@ let start_public_server (type f) ~(mode : f Mode.t) let (module Backend : Services_backend_sig.S), _ = ctxt in match rpc_server_family with | Rpc_types.Single_chain_node_rpc_server Michelson -> - let* l2_chain_id = - match l2_chain_id with - | Some l2_chain_id -> return l2_chain_id - | None -> Backend.chain_id () - in let add_transaction ~next_nonce transaction_object ~raw_op = match mode with | Observer (Michelson_tx_container (module Tx_container)) @@ -192,6 +187,11 @@ let start_public_server (type f) ~(mode : f Mode.t) ~op:transaction_object ~raw_op in + let* l2_chain_id = + match l2_chain_id with + | Some l2_chain_id -> return l2_chain_id + | None -> Backend.chain_id () + in return @@ Evm_directory.init_from_resto_directory @@ Tezlink_directory.register_tezlink_services ~l2_chain_id @@ -226,11 +226,39 @@ let start_public_server (type f) ~(mode : f Mode.t) | Error s -> failwith "%s" s in return hash) - | Single_chain_node_rpc_server EVM | Multichain_sequencer_rpc_server -> - let* runtimes = Backend.list_runtimes () in - let*! _ = List.map_p Tezosx_events.runtime_activated runtimes in + | Single_chain_node_rpc_server EVM | Multichain_sequencer_rpc_server -> ( + let*! runtimes = Backend.list_runtimes () in + match runtimes with + | Ok [] -> + return + @@ Evm_directory.empty config.experimental_features.rpc_server + | Ok runtimes -> + let*! _ = List.map_p Tezosx_events.runtime_activated runtimes in + let* l2_chain_id = + match l2_chain_id with + | Some l2_chain_id -> return l2_chain_id + | None -> Backend.chain_id () + in + let* () = + (* we use Resto for some runtimes, so we can _only_ use resto. *) + if config.experimental_features.rpc_server = Dream then + failwith "Dream RPC server is not supported for TezosX" + else return_unit + in + return @@ Evm_directory.init_from_resto_directory + @@ List.fold_left + (Tezosx_rpc.add_rpc_directory (module Backend) ~l2_chain_id) + Tezos_rpc.Directory.empty + runtimes + | Error e -> + (* FIXME: added during TezosX POC - return @@ Evm_directory.empty config.experimental_features.rpc_server + This branch is taken by the observer on some tests. It's not + clear if it's a pb in the test setup or a pb with the observer. + To be explored when the POC is a bit more advanced. *) + let*! () = Tezosx_events.list_runtime_failed e in + return + @@ Evm_directory.empty config.experimental_features.rpc_server) in (* If spawn_rpc is defined, use it as intermediate *) let rpc = diff --git a/etherlink/bin_node/lib_dev/tezosx_events.ml b/etherlink/bin_node/lib_dev/tezosx_events.ml index 3159799818bb..0b378b8aab2f 100644 --- a/etherlink/bin_node/lib_dev/tezosx_events.ml +++ b/etherlink/bin_node/lib_dev/tezosx_events.ml @@ -17,4 +17,15 @@ let runtime_activated = ~level:Notice ("runtime", Tezosx.runtime_encoding) +let fail = + declare_1 + ~section + ~name:"list_runtime_failed" + ~msg:"runtime flags read failed with error {error}" + ~level:Warning + ~pp1:Error_monad.pp_print_trace + ("error", Events.trace_encoding) + let runtime_activated runtime = emit runtime_activated runtime + +let list_runtime_failed err = emit fail err diff --git a/etherlink/bin_node/lib_dev/tezosx_rpc.ml b/etherlink/bin_node/lib_dev/tezosx_rpc.ml new file mode 100644 index 000000000000..774923c0dc8c --- /dev/null +++ b/etherlink/bin_node/lib_dev/tezosx_rpc.ml @@ -0,0 +1,16 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* SPDX-FileCopyrightText: 2025 Nomadic Labs *) +(* *) +(*****************************************************************************) + +let add_rpc_directory (module Backend : Services_backend_sig.S) ~l2_chain_id dir + = function + | Tezosx.Tezos -> + Tezos_rpc.Directory.merge + (Tezlink_directory.register_tezlink_services + ~l2_chain_id + (module Backend.Tezos) + ~add_operation:(fun _ -> failwith "TODO: can't inject operation")) + dir diff --git a/etherlink/bin_node/lib_dev/tezosx_rpc.mli b/etherlink/bin_node/lib_dev/tezosx_rpc.mli new file mode 100644 index 000000000000..16285dcb52b1 --- /dev/null +++ b/etherlink/bin_node/lib_dev/tezosx_rpc.mli @@ -0,0 +1,13 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* SPDX-FileCopyrightText: 2025 Nomadic Labs *) +(* *) +(*****************************************************************************) + +val add_rpc_directory : + (module Services_backend_sig.S) -> + l2_chain_id:L2_types.chain_id -> + unit Tezos_rpc.Directory.t -> + Tezosx.runtime -> + unit Tezos_rpc.Directory.t diff --git a/etherlink/tezt/tests/expected/evm_rollup.ml/EVM node- list events regression.out b/etherlink/tezt/tests/expected/evm_rollup.ml/EVM node- list events regression.out index e72eb3a17729..308be3ce499c 100644 --- a/etherlink/tezt/tests/expected/evm_rollup.ml/EVM node- list events regression.out +++ b/etherlink/tezt/tests/expected/evm_rollup.ml/EVM node- list events regression.out @@ -1377,6 +1377,14 @@ kernel_log_notice: contain invalid byte sequences. */ string || { "invalid_utf8_string": [ integer ∈ [0, 255] ... ] } +list_runtime_failed: + description: runtime flags read failed with error {error} + level: warning + section: evm_node.dev.tezosx + json format: + { /* list_runtime_failed version 0 */ + "list_runtime_failed.v0": any } + migrations_from_the_future: description: store has {applied} migrations applied but the EVM node is only aware of {known} level: error @@ -1904,6 +1912,14 @@ rpc_server_error: contain invalid byte sequences. */ string || { "invalid_utf8_string": [ integer ∈ [0, 255] ... ] } +runtime_activated: + description: the runtime {runtime} is activated + level: notice + section: evm_node.dev.tezosx + json format: + { /* runtime_activated version 0 */ + "runtime_activated.v0": "tezos" } + sandbox_started: description: starting sandbox mode at level {level} level: notice -- GitLab