diff --git a/etherlink/bin_node/lib_dev/durable_storage.ml b/etherlink/bin_node/lib_dev/durable_storage.ml index 0409574ae0be616fb7d364d7629986f058b0daa6..484ecc53212dc044ce04410e053dd0cb834862a2 100644 --- a/etherlink/bin_node/lib_dev/durable_storage.ml +++ b/etherlink/bin_node/lib_dev/durable_storage.ml @@ -334,6 +334,22 @@ let kernel_root_hash read = Durable_storage_path.kernel_root_hash Bytes.to_string +let enable_multichain read = + let open Lwt_result_syntax in + let bytes_to_bool (b : bytes) : bool = + if Bytes.length b <> 1 then + invalid_arg + "Expected a single byte representing the multichain feature flag" + else Bytes.get b 0 <> '\x00' + in + let* res_opt = + inspect_durable_and_decode_opt + read + Durable_storage_path.Feature_flags.multichain + bytes_to_bool + in + match res_opt with Some res -> return res | None -> return false + let storage_at read address (Qty pos) = let open Lwt_result_syntax in let pad32left0 s = @@ -420,6 +436,11 @@ module Make (Reader : READER) = struct let* read = read_with_state () in chain_id read + let enable_multichain () = + let open Lwt_result_syntax in + let* read = read_with_state () in + enable_multichain read + let l2_minimum_base_fee_per_gas chain_id = let open Lwt_result_syntax in let* read = read_with_state () in diff --git a/etherlink/bin_node/lib_dev/durable_storage_path.ml b/etherlink/bin_node/lib_dev/durable_storage_path.ml index f3cbe1d47375e99bfb7fbdfc38fa6e6a100e6e3d..3d4e89b3c8645975e36148b3505f10014ee1be2b 100644 --- a/etherlink/bin_node/lib_dev/durable_storage_path.ml +++ b/etherlink/bin_node/lib_dev/durable_storage_path.ml @@ -242,3 +242,13 @@ module Chain_configuration = struct let world_state chain_id = root chain_id ^ "/world_state" end + +module Feature_flags = struct + let root = EVM.make "/feature_flags" + + let dal = root ^ "/enable_dal" + + let fa_bridge = root ^ "/enable_fa_bridge" + + let multichain = root ^ "/enable_multichain" +end diff --git a/etherlink/bin_node/lib_dev/durable_storage_path.mli b/etherlink/bin_node/lib_dev/durable_storage_path.mli index 70efeb8735cf3c5f11741be6a3e5a64eebfe2fda..0656130875368a9e071d6a12d905745293f715f5 100644 --- a/etherlink/bin_node/lib_dev/durable_storage_path.mli +++ b/etherlink/bin_node/lib_dev/durable_storage_path.mli @@ -172,3 +172,11 @@ module Chain_configuration : sig val world_state : Ethereum_types.chain_id -> path end + +module Feature_flags : sig + val dal : path + + val fa_bridge : path + + val multichain : path +end diff --git a/etherlink/bin_node/lib_dev/evm_ro_context.ml b/etherlink/bin_node/lib_dev/evm_ro_context.ml index 5c27c2fcdf65fd60dd117619785968a271a007ea..4ed1e8e334827f7ca99de2e789c3022d9e97622c 100644 --- a/etherlink/bin_node/lib_dev/evm_ro_context.ml +++ b/etherlink/bin_node/lib_dev/evm_ro_context.ml @@ -29,6 +29,20 @@ let read state path = let*! res = Evm_state.inspect state path in return res +let read_chain_family ctxt chain_id = + let open Lwt_result_syntax in + let* _, hash = Evm_store.(use ctxt.store Context_hashes.get_latest) in + let* evm_state = get_evm_state ctxt hash in + let* chain_family = Durable_storage.chain_family (read evm_state) chain_id in + return chain_family + +let read_enable_multichain ctxt = + let open Lwt_result_syntax in + let* _, hash = Evm_store.(use ctxt.store Context_hashes.get_latest) in + let* evm_state = get_evm_state ctxt hash in + let* enable_multichain = Durable_storage.enable_multichain (read evm_state) in + return enable_multichain + let network_sanity_check ~network ctxt = let open Lwt_result_syntax in let expected_smart_rollup_address = Constants.rollup_address network in diff --git a/etherlink/bin_node/lib_dev/evm_ro_context.mli b/etherlink/bin_node/lib_dev/evm_ro_context.mli index e99ce9a08b7d4a9aa3fc63cb5321363934c34862..a0071ff3787b37badb7ec0746bc76047eb088223 100644 --- a/etherlink/bin_node/lib_dev/evm_ro_context.mli +++ b/etherlink/bin_node/lib_dev/evm_ro_context.mli @@ -33,6 +33,11 @@ val load : Configuration.t -> t tzresult Lwt.t +val read_chain_family : + t -> Ethereum_types.chain_id -> Ethereum_types.chain_family tzresult Lwt.t + +val read_enable_multichain : t -> bool tzresult Lwt.t + (** [preload_known_kernels ctxt] uses [ctxt] to preload every kernel known to the node in the Fast Execution kernel cache. *) val preload_known_kernels : t -> unit tzresult Lwt.t diff --git a/etherlink/bin_node/lib_dev/observer.ml b/etherlink/bin_node/lib_dev/observer.ml index aabe9e19725171df8c9e066040ca22f9b1f985ae..57b4f00b470621c362320e8b92a7dfc23a492528 100644 --- a/etherlink/bin_node/lib_dev/observer.ml +++ b/etherlink/bin_node/lib_dev/observer.ml @@ -237,8 +237,22 @@ let main ?network ?kernel_path ~data_dir ~(config : Configuration.t) ~no_sync ~tx_pool_size_info:Tx_pool.size_info ~smart_rollup_address ; + let* chain_family = + match config.experimental_features.l2_chains with + | None -> return EVM + | Some [l2_chain] -> + let* family = + Evm_ro_context.read_chain_family ro_ctxt l2_chain.chain_id + in + return family + | _ -> failwith "Too many L2 chains for observer" + in + + let* enable_multichain = Evm_ro_context.read_enable_multichain ro_ctxt in + let* finalizer_public_server = Rpc_server.start_public_server + ~_chain_family:chain_family ~evm_services: Evm_ro_context.(evm_services_methods ro_ctxt time_between_blocks) ~data_dir diff --git a/etherlink/bin_node/lib_dev/proxy.ml b/etherlink/bin_node/lib_dev/proxy.ml index 3cf1cb90221e840b983a826033eea72bafd9663c..cdf8e09a27add66f1073cb0899a3721eb0fe09ab 100644 --- a/etherlink/bin_node/lib_dev/proxy.ml +++ b/etherlink/bin_node/lib_dev/proxy.ml @@ -96,6 +96,16 @@ let main ~rollup_node_endpoint () in + let* _chain_family = + match config.experimental_features.l2_chains with + | None -> return Ethereum_types.EVM + | Some [l2_chain] -> + let* family = Rollup_node_rpc.chain_family l2_chain.chain_id in + return family + | _ -> failwith "Too many L2 chains for proxy" + in + let* _enable_multichain = Rollup_node_rpc.enable_multichain () in + let* server_finalizer = Rpc_server.start_public_server validation_mode diff --git a/etherlink/bin_node/lib_dev/rpc.ml b/etherlink/bin_node/lib_dev/rpc.ml index 36b9c8ef95c0c66ae0987a8bbdb0bb808e5dec3f..5d5fddfeb28aa396b0b376d5ee5bf69f648b20e6 100644 --- a/etherlink/bin_node/lib_dev/rpc.ml +++ b/etherlink/bin_node/lib_dev/rpc.ml @@ -122,6 +122,17 @@ let main ~data_dir ~evm_node_endpoint ?evm_node_private_endpoint } in + let* _chain_family = + match config.experimental_features.l2_chains with + | None -> return Ethereum_types.EVM + | Some [l2_chain] -> + let* family = Evm_ro_context.read_chain_family ctxt l2_chain.chain_id in + return family (* This ensures the result is an option inside Lwt *) + | _ -> failwith "Too many L2 chains for rpc" + in + + let* _enable_multichain = Evm_ro_context.read_enable_multichain ctxt in + let* server_public_finalizer = Rpc_server.start_public_server ~delegate_health_check_to:evm_node_endpoint diff --git a/etherlink/bin_node/lib_dev/rpc_server.ml b/etherlink/bin_node/lib_dev/rpc_server.ml index f76c806dffd63994de29c573a262156af4dcecfe..379ce945628dbd826942096401b9d597a15aa598 100644 --- a/etherlink/bin_node/lib_dev/rpc_server.ml +++ b/etherlink/bin_node/lib_dev/rpc_server.ml @@ -124,8 +124,9 @@ let monitor_performances ~data_dir = in Lwt.dont_wait aux (Fun.const ()) -let start_public_server ?delegate_health_check_to ?evm_services ?data_dir - validation (config : Configuration.t) ctxt = +let start_public_server ~_rpc_server_family ~_enable_multichain + ?delegate_health_check_to ?evm_services ?data_dir validation + (config : Configuration.t) ctxt = let open Lwt_result_syntax in let*! can_start_performance_metrics = Octez_performance_metrics.supports_performance_metrics () diff --git a/etherlink/bin_node/lib_dev/rpc_types.ml b/etherlink/bin_node/lib_dev/rpc_types.ml new file mode 100644 index 0000000000000000000000000000000000000000..d9abf37df45bc29057452c6206ca986403e3f657 --- /dev/null +++ b/etherlink/bin_node/lib_dev/rpc_types.ml @@ -0,0 +1,21 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Nomadic Labs *) +(* *) +(*****************************************************************************) + +(* The set of supported RPCs depends on the mode. + For the sequencer, only very few JSON RPCs need to be supported. + For the observer, proxy, and RPC modes, we assume that a single + chain is followed even when the multichain feature is activated + and the set of supported RPCs depends on the chain family. *) + +(* The set of supported RPCs depends on the mode. + For the sequencer, only very few JSON RPCs need to be supported. + For the observer, proxy, and RPC modes, we assume that a single + chain is followed even when the multichain feature is activated + and the set of supported RPCs depends on the chain family. *) +type rpc_server_family = + | Sequencer_rpc_server + | Single_chain_node_rpc_server of Ethereum_types.chain_family diff --git a/etherlink/bin_node/lib_dev/sequencer.ml b/etherlink/bin_node/lib_dev/sequencer.ml index 62da7d22ea27ba7554bea009d9cdcffab62f7b59..92d05991db1242632b026b0174aa13fefbcaf84f 100644 --- a/etherlink/bin_node/lib_dev/sequencer.ml +++ b/etherlink/bin_node/lib_dev/sequencer.ml @@ -189,6 +189,7 @@ let main ~data_dir ?(genesis_timestamp = Misc.now ()) ~cctxt in return_unit in + let* _enable_multichain = Evm_ro_context.read_enable_multichain ro_ctxt in let* finalizer_public_server = Rpc_server.start_public_server ~evm_services: diff --git a/etherlink/bin_node/lib_dev/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index a69faca1e48bf29419c059b26aa4df4788b59589..e24c60d5b9e059ed751de9c129863d2bbd1c6a87 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -99,6 +99,11 @@ module type S = sig or the zero address. *) val coinbase : unit -> Ethereum_types.address tzresult Lwt.t + (** enable_multichain () returns the value of the enable_multichain + this method targets proxy nodes that do not have direct access + to the durable storage. *) + val enable_multichain : unit -> bool tzresult Lwt.t + include Tracer_sig.S end