diff --git a/etherlink/bin_node/lib_dev/observer.ml b/etherlink/bin_node/lib_dev/observer.ml index 2179d9875cc4e48a624e689c91fb92811b72ecfb..89b8104d7398cdf4cc74b95e71e8f6e6b7890e57 100644 --- a/etherlink/bin_node/lib_dev/observer.ml +++ b/etherlink/bin_node/lib_dev/observer.ml @@ -190,7 +190,7 @@ let main ?network ?kernel_path ~data_dir ~(config : Configuration.t) ~no_sync let* enable_multichain = Evm_ro_context.read_enable_multichain_flag ro_ctxt in - let* (_chain_family : Ethereum_types.chain_family) = + let* chain_family = match (config.experimental_features.l2_chains, enable_multichain) with | None, false -> return EVM | None, true -> tzfail (Node_error.Mismatched_multichain `Kernel) @@ -205,12 +205,14 @@ let main ?network ?kernel_path ~data_dir ~(config : Configuration.t) ~no_sync ~evm_services: Evm_ro_context.(evm_services_methods ro_ctxt time_between_blocks) ~data_dir + ~rpc_server_family:(Rpc_types.Single_chain_node_rpc_server chain_family) Stateless config (observer_backend, smart_rollup_address) in let* finalizer_private_server = Rpc_server.start_private_server + ~rpc_server_family:(Rpc_types.Single_chain_node_rpc_server chain_family) config (observer_backend, smart_rollup_address) in diff --git a/etherlink/bin_node/lib_dev/proxy.ml b/etherlink/bin_node/lib_dev/proxy.ml index 9dc644612b5c72215b34953f129b2a269a561e68..7e884b6f1c3ec22d1460a966157ae8f56ac600ab 100644 --- a/etherlink/bin_node/lib_dev/proxy.ml +++ b/etherlink/bin_node/lib_dev/proxy.ml @@ -96,7 +96,7 @@ let main ~rollup_node_endpoint () in - let* (_chain_family : Ethereum_types.chain_family) = + let* chain_family = if finalized_view then if (* When finalized_view is set, it's too early to request the @@ -117,6 +117,7 @@ let main in let* server_finalizer = Rpc_server.start_public_server + ~rpc_server_family:(Rpc_types.Single_chain_node_rpc_server chain_family) validation_mode config ((module Rollup_node_rpc), smart_rollup_address) diff --git a/etherlink/bin_node/lib_dev/rpc.ml b/etherlink/bin_node/lib_dev/rpc.ml index 5fc57cd71c24ea8baf8ec5d509f9d2ffacaba8ab..e63f3db4cb0293b5b71b1ffa3f1f31afbce0689a 100644 --- a/etherlink/bin_node/lib_dev/rpc.ml +++ b/etherlink/bin_node/lib_dev/rpc.ml @@ -124,7 +124,7 @@ let main ~data_dir ~evm_node_endpoint ?evm_node_private_endpoint let* enable_multichain = Evm_ro_context.read_enable_multichain_flag ctxt in - let* (_chain_family : Ethereum_types.chain_family) = + let* chain_family = match (config.experimental_features.l2_chains, enable_multichain) with | None, false -> return Ethereum_types.EVM | None, true -> tzfail (Node_error.Mismatched_multichain `Kernel) @@ -140,6 +140,7 @@ let main ~data_dir ~evm_node_endpoint ?evm_node_private_endpoint ~evm_services: Evm_ro_context.(evm_services_methods ctxt time_between_blocks) ~data_dir + ~rpc_server_family:(Rpc_types.Single_chain_node_rpc_server chain_family) Stateless rpc_config (rpc_backend, ctxt.smart_rollup_address) diff --git a/etherlink/bin_node/lib_dev/rpc_encodings.ml b/etherlink/bin_node/lib_dev/rpc_encodings.ml index a466cfd95730423d9c539c3ff37452afd0ce1444..b50f9b8c8437d6c2013fc120b970d4b2a470d516 100644 --- a/etherlink/bin_node/lib_dev/rpc_encodings.ml +++ b/etherlink/bin_node/lib_dev/rpc_encodings.ml @@ -167,6 +167,16 @@ module type METHOD = sig type ('input, 'output) method_ += Method : (input, output) method_ end +(* A simple equality check for two (module METHOD) values by comparing the method_ field. *) +let equal_method (module M1 : METHOD) (module M2 : METHOD) = + M1.method_ = M2.method_ + +let get_diff (list1 : (module METHOD) list) (list2 : (module METHOD) list) : + (module METHOD) list = + List.filter + (fun m1 -> not (List.exists (fun m2 -> equal_method m1 m2) list2)) + list1 + let encoding_with_optional_extended_block_param encoding = Evm_node_lib_dev_encoding.Helpers.encoding_with_optional_last_param encoding @@ -979,7 +989,7 @@ type map_result = | Unknown | Disabled -let supported_methods : (module METHOD) list = +let evm_supported_methods : (module METHOD) list = [ (module Kernel_version); (module Kernel_root_hash); @@ -1029,7 +1039,7 @@ let supported_methods : (module METHOD) list = (module Trace_block); ] -let unsupported_methods : string list = +let evm_unsupported_methods : string list = [ (* net *) "net_listening"; @@ -1077,7 +1087,42 @@ let unsupported_methods : string list = "engine_newPayloadV4"; ] -let map_method_name ~restrict method_name = +let michelson_supported_methods = evm_supported_methods + +let multichain_sequencer_supported_methods : (module METHOD) list = + [ + (module Block_number); + (module Send_raw_transaction); + (* Private RPCs *) + (module Produce_block); + (module Inject_transaction); + (module Durable_state_value); + (module Durable_state_subkeys); + (module Replay_block); + ] + +let michelson_unsupported_methods = evm_unsupported_methods + +let multichain_sequencer_unsupported_methods = + let diff_methods = + get_diff evm_supported_methods multichain_sequencer_supported_methods + in + let diff_method_names = + List.map (fun (module M : METHOD) -> M.method_) diff_methods + in + evm_unsupported_methods @ diff_method_names + +let map_method_name ~rpc_server_family ~restrict method_name = + let supported_methods, unsupported_methods = + match rpc_server_family with + | Rpc_types.Multichain_sequencer_rpc_server -> + ( multichain_sequencer_supported_methods, + multichain_sequencer_unsupported_methods ) + | Rpc_types.Single_chain_node_rpc_server Ethereum_types.EVM -> + (evm_supported_methods, evm_unsupported_methods) + | Rpc_types.Single_chain_node_rpc_server Ethereum_types.Michelson -> + (michelson_supported_methods, michelson_unsupported_methods) + in let disabled = match restrict with | Configuration.Pattern {regex; _} -> Re.execp regex method_name diff --git a/etherlink/bin_node/lib_dev/rpc_encodings.mli b/etherlink/bin_node/lib_dev/rpc_encodings.mli index e3ccdf992c52eea698bb0dfd3dd4b003449f5c77..6ced8f7b8c7d1c6cccb822baae86710755d9e75a 100644 --- a/etherlink/bin_node/lib_dev/rpc_encodings.mli +++ b/etherlink/bin_node/lib_dev/rpc_encodings.mli @@ -359,7 +359,10 @@ type map_result = | Disabled val map_method_name : - restrict:Configuration.restricted_rpcs -> string -> map_result + rpc_server_family:Rpc_types.rpc_server_family -> + restrict:Configuration.restricted_rpcs -> + string -> + map_result type websocket_subscription = { id : Ethereum_types.Subscription.id; diff --git a/etherlink/bin_node/lib_dev/rpc_server.ml b/etherlink/bin_node/lib_dev/rpc_server.ml index f76c806dffd63994de29c573a262156af4dcecfe..ec84351b17674152df4b660ee45962b4aa2d63fa 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 : Rpc_types.rpc_server_family) + ?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 () @@ -152,7 +153,13 @@ let start_public_server ?delegate_health_check_to ?evm_services ?data_dir in let directory = - Services.directory ?delegate_health_check_to rpc validation config ctxt + Services.directory + ~rpc_server_family + ?delegate_health_check_to + rpc + validation + config + ctxt |> register_evm_services |> Evm_directory.register_metrics "/metrics" in @@ -166,12 +173,18 @@ let start_public_server ?delegate_health_check_to ?evm_services ?data_dir in return finalizer -let start_private_server ?(block_production = `Disabled) config ctxt = +let start_private_server ~(rpc_server_family : Rpc_types.rpc_server_family) + ?(block_production = `Disabled) config ctxt = let open Lwt_result_syntax in match config.Configuration.private_rpc with | Some private_rpc -> let directory = - Services.private_directory private_rpc ~block_production config ctxt + Services.private_directory + ~rpc_server_family + private_rpc + ~block_production + config + ctxt |> Evm_directory.register_metrics "/metrics" in let* finalizer = start_server private_rpc directory in diff --git a/etherlink/bin_node/lib_dev/rpc_server.mli b/etherlink/bin_node/lib_dev/rpc_server.mli index be05fd82cf5b6690e99ea4685861ff035879e5ae..4715b3af3b0d9270edeb9af319e4c509908ac233 100644 --- a/etherlink/bin_node/lib_dev/rpc_server.mli +++ b/etherlink/bin_node/lib_dev/rpc_server.mli @@ -29,6 +29,7 @@ type block_production = [`Single_node | `Disabled] sequencer setup, [`Disabled] means no block production method is available. *) val start_private_server : + rpc_server_family:Rpc_types.rpc_server_family -> ?block_production:block_production -> Configuration.t -> (module Services_backend_sig.S) * 'a -> @@ -43,6 +44,7 @@ val start_private_server : If [data_dir] is provided and the host provides the necessary binaries, performance metrics are enabled. *) val start_public_server : + rpc_server_family:Rpc_types.rpc_server_family -> ?delegate_health_check_to:Uri.t -> ?evm_services:evm_services_methods -> ?data_dir:string -> 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..c23dc1794e43b80a7d81d74403c2ecc744a25d62 --- /dev/null +++ b/etherlink/bin_node/lib_dev/rpc_types.ml @@ -0,0 +1,16 @@ +(*****************************************************************************) +(* *) +(* 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. *) + +type rpc_server_family = + | Multichain_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 c7b07d9b7e892203112cb740d96dcd3873e26134..bb06fbce68c44b59e172189682839c29037ed781 100644 --- a/etherlink/bin_node/lib_dev/sequencer.ml +++ b/etherlink/bin_node/lib_dev/sequencer.ml @@ -258,12 +258,18 @@ let main ~data_dir ?(genesis_timestamp = Misc.now ()) ~cctxt Evm_ro_context.( evm_services_methods ro_ctxt sequencer_config.time_between_blocks) ~data_dir + ~rpc_server_family: + (if enable_multichain then Rpc_types.Multichain_sequencer_rpc_server + else Rpc_types.Single_chain_node_rpc_server EVM) Full configuration (backend, smart_rollup_address_typed) in let* finalizer_private_server = Rpc_server.start_private_server + ~rpc_server_family: + (if enable_multichain then Rpc_types.Multichain_sequencer_rpc_server + else Rpc_types.Single_chain_node_rpc_server EVM) ~block_production:`Single_node configuration (backend, smart_rollup_address_typed) diff --git a/etherlink/bin_node/lib_dev/services.ml b/etherlink/bin_node/lib_dev/services.ml index 9b77ee040bccd58df9cce45f844134707a39222e..8a70686f898d4e9a0288b9cbec3b1aaead73554a 100644 --- a/etherlink/bin_node/lib_dev/services.ml +++ b/etherlink/bin_node/lib_dev/services.ml @@ -440,14 +440,17 @@ let process_trace_result trace = let msg = Format.asprintf "%a" pp_print_trace e in rpc_error (Rpc_errors.internal_error msg) -let dispatch_request (rpc : Configuration.rpc) - (validation : Validate.validation_mode) (config : Configuration.t) +let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) + (rpc : Configuration.rpc) (validation : Validate.validation_mode) + (config : Configuration.t) ((module Backend_rpc : Services_backend_sig.S), _) ({method_; parameters; id} : JSONRPC.request) : JSONRPC.response Lwt.t = let open Lwt_result_syntax in let open Ethereum_types in let*! value = - match map_method_name ~restrict:rpc.restricted_rpcs method_ with + match + map_method_name ~rpc_server_family ~restrict:rpc.restricted_rpcs method_ + with | Unknown -> Metrics.inc_rpc_method ~name:"unknown" ; Lwt.return_error (Rpc_errors.method_not_found method_) @@ -849,8 +852,8 @@ let dispatch_request (rpc : Configuration.rpc) in Lwt.return JSONRPC.{value; id} -let dispatch_private_request (rpc : Configuration.rpc) - (config : Configuration.t) +let dispatch_private_request (rpc_server_family : Rpc_types.rpc_server_family) + (rpc : Configuration.rpc) (config : Configuration.t) ((module Backend_rpc : Services_backend_sig.S), _) ~block_production ({method_; parameters; id} : JSONRPC.request) : JSONRPC.response Lwt.t = let open Lwt_syntax in @@ -867,7 +870,9 @@ let dispatch_private_request (rpc : Configuration.rpc) let* value = (* Private RPCs can only be accessed locally, they're not accessible to the end user. *) - match map_method_name ~restrict:rpc.restricted_rpcs method_ with + match + map_method_name ~rpc_server_family ~restrict:rpc.restricted_rpcs method_ + with | Unknown -> return (Error @@ -1022,10 +1027,15 @@ let empty_stream = let empty_sid = Ethereum_types.(Subscription.Id (Hex "")) -let dispatch_websocket (rpc : Configuration.rpc) validation config ctx - (input : JSONRPC.request) = +let dispatch_websocket (rpc_server_family : Rpc_types.rpc_server_family) + (rpc : Configuration.rpc) validation config ctx (input : JSONRPC.request) = let open Lwt_syntax in - match map_method_name ~restrict:rpc.restricted_rpcs input.method_ with + match + map_method_name + ~rpc_server_family + ~restrict:rpc.restricted_rpcs + input.method_ + with | Method (Subscribe.Method, module_) -> let sub_stream = ref empty_stream in let sid = ref empty_sid in @@ -1064,14 +1074,23 @@ let dispatch_websocket (rpc : Configuration.rpc) validation config ctx let+ value = build_with_input ~f module_ input.parameters in websocket_response_of_response JSONRPC.{value; id = input.id} | _ -> - let+ response = dispatch_request rpc validation config ctx input in + let+ response = + dispatch_request rpc_server_family rpc validation config ctx input + in websocket_response_of_response response -let dispatch_private_websocket ~block_production (rpc : Configuration.rpc) - config ctx (input : JSONRPC.request) = +let dispatch_private_websocket (rpc_server_family : Rpc_types.rpc_server_family) + ~block_production (rpc : Configuration.rpc) config ctx + (input : JSONRPC.request) = let open Lwt_syntax in let+ response = - dispatch_private_request ~block_production rpc config ctx input + dispatch_private_request + rpc_server_family + ~block_production + rpc + config + ctx + input in websocket_response_of_response response @@ -1080,24 +1099,25 @@ let generic_dispatch (rpc : Configuration.rpc) config ctx dir path Evm_directory.register0 dir (dispatch_batch_service ~path) (fun () input -> dispatch_handler rpc config ctx dispatch_request input |> Lwt_result.ok) -let dispatch_public (rpc : Configuration.rpc) validation config ctx dir = +let dispatch_public (rpc_server_family : Rpc_types.rpc_server_family) + (rpc : Configuration.rpc) validation config ctx dir = generic_dispatch rpc config ctx dir Path.root - (dispatch_request rpc validation) + (dispatch_request rpc_server_family rpc validation) -let dispatch_private (rpc : Configuration.rpc) ~block_production config ctx dir - = +let dispatch_private (rpc_server_family : Rpc_types.rpc_server_family) + (rpc : Configuration.rpc) ~block_production config ctx dir = generic_dispatch rpc config ctx dir Path.(add_suffix root "private") - (dispatch_private_request rpc ~block_production) + (dispatch_private_request rpc_server_family rpc ~block_production) let generic_websocket_dispatch (config : Configuration.t) ctx dir path dispatch_websocket = @@ -1111,51 +1131,55 @@ let generic_websocket_dispatch (config : Configuration.t) ctx dir path (dispatch_websocket config ctx) else dir -let dispatch_websocket_public (rpc : Configuration.rpc) validation config ctx - dir = +let dispatch_websocket_public (rpc_server_family : Rpc_types.rpc_server_family) + (rpc : Configuration.rpc) validation config ctx dir = generic_websocket_dispatch config ctx dir "/ws" - (dispatch_websocket rpc validation) + (dispatch_websocket rpc_server_family rpc validation) -let dispatch_websocket_private (rpc : Configuration.rpc) ~block_production - config ctx dir = +let dispatch_websocket_private (rpc_server_family : Rpc_types.rpc_server_family) + (rpc : Configuration.rpc) ~block_production config ctx dir = generic_websocket_dispatch config ctx dir "/private/ws" - (dispatch_private_websocket ~block_production rpc) + (dispatch_private_websocket rpc_server_family ~block_production rpc) -let directory ?delegate_health_check_to rpc validation config +let directory ~rpc_server_family ?delegate_health_check_to rpc validation config ((module Rollup_node_rpc : Services_backend_sig.S), smart_rollup_address) = Evm_directory.empty config.experimental_features.rpc_server |> version |> configuration config |> health_check ?delegate_to:delegate_health_check_to |> dispatch_public + rpc_server_family rpc validation config ((module Rollup_node_rpc : Services_backend_sig.S), smart_rollup_address) |> dispatch_websocket_public + rpc_server_family rpc validation config ((module Rollup_node_rpc : Services_backend_sig.S), smart_rollup_address) -let private_directory rpc config +let private_directory ~rpc_server_family rpc config ((module Rollup_node_rpc : Services_backend_sig.S), smart_rollup_address) ~block_production = Evm_directory.empty config.experimental_features.rpc_server |> version |> dispatch_private + rpc_server_family rpc config ((module Rollup_node_rpc : Services_backend_sig.S), smart_rollup_address) ~block_production |> dispatch_websocket_private + rpc_server_family rpc config ((module Rollup_node_rpc : Services_backend_sig.S), smart_rollup_address)