From e09bf73b53fcbb2a7e85bbe1a6f7fc1bd0b3a716 Mon Sep 17 00:00:00 2001 From: Dibassi Brahima Date: Mon, 28 Apr 2025 16:21:11 +0200 Subject: [PATCH 1/4] Tezlink/Node/RPC : Tezlink/Node/RPC : Move RPCs impl to improve readability and maintainability --- .../bin_node/lib_dev/tezlink_services_impl.ml | 64 +++++++++---------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/etherlink/bin_node/lib_dev/tezlink_services_impl.ml b/etherlink/bin_node/lib_dev/tezlink_services_impl.ml index 3a6e9ddf1fcf..15cef209ef9e 100644 --- a/etherlink/bin_node/lib_dev/tezlink_services_impl.ml +++ b/etherlink/bin_node/lib_dev/tezlink_services_impl.ml @@ -24,38 +24,6 @@ module Path = struct let counter contract = account contract ^ "/counter" end -let balance read chain c = - let `Main = chain in - - Durable_storage.inspect_durable_and_decode_default - ~default:Tezos_types.Tez.zero - read - (Path.balance c) - (Data_encoding.Binary.of_bytes_exn Tez.encoding) - -let manager_key read chain c = - (* TODO: #7831 !17664 - Support non-default chain and block parameters. *) - let `Main = chain in - - Durable_storage.inspect_durable_and_decode_opt - read - (Path.manager_key c) - (Data_encoding.Binary.of_bytes_exn Signature.V1.Public_key.encoding) - -let counter read chain c = - (* TODO: #7831 !17664 - Support non-default chain and block parameters. *) - let `Main = chain in - - Durable_storage.inspect_durable_and_decode_default - (* FIXME: #7960 - This default should be the global counter *) - ~default:Z.one - read - (Path.counter c) - (Data_encoding.Binary.of_bytes_exn Data_encoding.z) - module type Backend = sig include Durable_storage.READER @@ -118,11 +86,37 @@ module Make (Backend : Backend) : Tezlink_backend_sig.S = struct let* state = Backend.get_state ~block () in Backend.read state p - let balance chain block = balance (read ~block) chain + let balance chain block c = + let `Main = chain in + + Durable_storage.inspect_durable_and_decode_default + ~default:Tezos_types.Tez.zero + (read ~block) + (Path.balance c) + (Data_encoding.Binary.of_bytes_exn Tez.encoding) - let manager_key chain block = manager_key (read ~block) chain + let manager_key chain block c = + (* TODO: #7831 !17664 + Support non-default chain and block parameters. *) + let `Main = chain in + + Durable_storage.inspect_durable_and_decode_opt + (read ~block) + (Path.manager_key c) + (Data_encoding.Binary.of_bytes_exn Signature.V1.Public_key.encoding) + + let counter chain block c = + (* TODO: #7831 !17664 + Support non-default chain and block parameters. *) + let `Main = chain in - let counter chain block = counter (read ~block) chain + Durable_storage.inspect_durable_and_decode_default + (* FIXME: #7960 + This default should be the global counter *) + ~default:Z.one + (read ~block) + (Path.counter c) + (Data_encoding.Binary.of_bytes_exn Data_encoding.z) let header chain block = let open Lwt_result_syntax in -- GitLab From 0c24ecd615a065bced6354e65e37bc90bae20db5 Mon Sep 17 00:00:00 2001 From: Dibassi Brahima Date: Mon, 28 Apr 2025 12:13:36 +0200 Subject: [PATCH 2/4] Tezlink/Node/RPC : Refactor block parameter handling --- .../lib_dev/tezlink/tezlink_backend_sig.ml | 2 +- .../lib_dev/tezlink/tezos_services.ml | 2 +- .../bin_node/lib_dev/tezlink_services_impl.ml | 39 ++++++++++++------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/etherlink/bin_node/lib_dev/tezlink/tezlink_backend_sig.ml b/etherlink/bin_node/lib_dev/tezlink/tezlink_backend_sig.ml index 47f14032d39b..365783c840d7 100644 --- a/etherlink/bin_node/lib_dev/tezlink/tezlink_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/tezlink/tezlink_backend_sig.ml @@ -6,7 +6,7 @@ (*****************************************************************************) module type S = sig - type block_param = [`Head | `Level of int32] + type block_param = [`Head of int32 | `Level of int32] val current_level : [`Main] -> block_param -> offset:int32 -> Tezos_types.level tzresult Lwt.t diff --git a/etherlink/bin_node/lib_dev/tezlink/tezos_services.ml b/etherlink/bin_node/lib_dev/tezlink/tezos_services.ml index c1730c7f7d82..4f1dfed09bab 100644 --- a/etherlink/bin_node/lib_dev/tezlink/tezos_services.ml +++ b/etherlink/bin_node/lib_dev/tezlink/tezos_services.ml @@ -408,7 +408,7 @@ let check_block = let open Result_syntax in function | `Level l -> return (`Level l) - | `Head 0 -> return `Head + | `Head offset -> return (`Head (Int32.of_int offset)) | block -> tzfail (Unsupported_block_parameter diff --git a/etherlink/bin_node/lib_dev/tezlink_services_impl.ml b/etherlink/bin_node/lib_dev/tezlink_services_impl.ml index 15cef209ef9e..bb774933e68e 100644 --- a/etherlink/bin_node/lib_dev/tezlink_services_impl.ml +++ b/etherlink/bin_node/lib_dev/tezlink_services_impl.ml @@ -35,17 +35,34 @@ module type Backend = sig end module Make (Backend : Backend) : Tezlink_backend_sig.S = struct - type block_param = [`Head | `Level of int32] + type block_param = [`Head of int32 | `Level of int32] let shell_block_param_to_block_number = let open Lwt_result_syntax in + let compute_offset (Ethereum_types.Qty block_number) offset = + let result = Int32.sub (Z.to_int32 block_number) offset in + return (max 0l result) + in function - | `Head -> - let* (Qty current_block_number) = + | `Head offset -> + let* current_block_number = Backend.block_param_to_block_number (Block_parameter Latest) in - return current_block_number - | `Level l -> return (Z.of_int32 l) + compute_offset current_block_number offset + | `Level l -> return l + + let shell_block_param_to_eth_block_param = + let open Lwt_result_syntax in + function + | `Head 0l -> + return + @@ Ethereum_types.Block_parameter.Block_parameter + Ethereum_types.Block_parameter.Latest + | block -> + let* num = shell_block_param_to_block_number block in + return + @@ Ethereum_types.Block_parameter.Block_parameter + (Number (Ethereum_types.quantity_of_z (Z.of_int32 num))) let current_level chain block ~offset = let open Lwt_result_syntax in @@ -60,7 +77,7 @@ module Make (Backend : Backend) : Tezlink_backend_sig.S = struct let* block_number = shell_block_param_to_block_number block in let constants = Tezlink_constants.all_constants in - let level = Z.to_int32 (Z.add block_number (Z.of_int32 offset)) in + let level = Int32.add block_number offset in return Tezos_types. { @@ -76,13 +93,7 @@ module Make (Backend : Backend) : Tezlink_backend_sig.S = struct let read ~block p = let open Lwt_result_syntax in - let block = - match block with - | `Head -> Ethereum_types.Block_parameter.(Block_parameter Latest) - | `Level l -> - Ethereum_types.Block_parameter.( - Block_parameter (Number (Qty (Z.of_int32 l)))) - in + let* block = shell_block_param_to_eth_block_param block in let* state = Backend.get_state ~block () in Backend.read state p @@ -122,7 +133,7 @@ module Make (Backend : Backend) : Tezlink_backend_sig.S = struct let open Lwt_result_syntax in let `Main = chain in let* block_number = shell_block_param_to_block_number block in - Backend.tez_nth_block block_number + Backend.tez_nth_block (Z.of_int32 block_number) (* TODO: #7963 Support Observer Mode Here the catchup mechanism to fetch blueprints is not taken into account as -- GitLab From ff67447fbbd50dcc47876235a5826d9ab849e165 Mon Sep 17 00:00:00 2001 From: Dibassi Brahima Date: Mon, 28 Apr 2025 17:05:56 +0200 Subject: [PATCH 3/4] Tezlink/Node/RPC : Support `/chains/main/blocks/head~2/hash` --- .../bin_node/lib_dev/services_backend_sig.ml | 2 + .../lib_dev/tezlink/tezlink_backend_sig.ml | 3 + .../lib_dev/tezlink/tezos_services.ml | 70 +++++++++++++------ .../bin_node/lib_dev/tezlink_services_impl.ml | 9 +++ .../Alpha- Test the -describe endpoint.out | 4 ++ 5 files changed, 66 insertions(+), 22 deletions(-) diff --git a/etherlink/bin_node/lib_dev/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index ca8203d67c32..76e9a56c936c 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -197,6 +197,8 @@ module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct let block_param_to_block_number = Backend.block_param_to_block_number + let nth_block_hash = Block_storage.nth_block_hash + let tez_nth_block = Block_storage.tez_nth_block end) diff --git a/etherlink/bin_node/lib_dev/tezlink/tezlink_backend_sig.ml b/etherlink/bin_node/lib_dev/tezlink/tezlink_backend_sig.ml index 365783c840d7..7e9f2174dad9 100644 --- a/etherlink/bin_node/lib_dev/tezlink/tezlink_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/tezlink/tezlink_backend_sig.ml @@ -32,4 +32,7 @@ module type S = sig val bootstrapped : unit -> (Ethereum_types.block_hash * Time.Protocol.t) tzresult Lwt.t + + val block_hash : + [`Main] -> block_param -> Ethereum_types.block_hash option tzresult Lwt.t end diff --git a/etherlink/bin_node/lib_dev/tezlink/tezos_services.ml b/etherlink/bin_node/lib_dev/tezlink/tezos_services.ml index 4f1dfed09bab..7ea27c166814 100644 --- a/etherlink/bin_node/lib_dev/tezlink/tezos_services.ml +++ b/etherlink/bin_node/lib_dev/tezlink/tezos_services.ml @@ -69,11 +69,11 @@ module Protocol_types = struct else invalid_arg "Cycle_repr.of_int32_exn" end - let tezlink_to_tezos_chain_id_exn ~l2_chain_id _chain = + let tezlink_to_tezos_chain_id ~l2_chain_id _chain = let (L2_types.Chain_id l2_chain_id) = l2_chain_id in let bytes = Bytes.make 4 '\000' in l2_chain_id |> Z.to_int32 |> Bytes.set_int32_be bytes 0 ; - Chain_id.of_bytes_exn bytes + Chain_id.of_bytes bytes module Protocol_data = struct let get_mock_protocol_data = @@ -85,32 +85,35 @@ module Protocol_types = struct end let ethereum_to_tezos_block_hash hash = - hash |> Ethereum_types.block_hash_to_bytes |> Block_hash.of_string_exn + hash |> Ethereum_types.block_hash_to_bytes |> Block_hash.of_string module Block_header = struct let tezlink_block_to_shell_header (block : L2_types.Tezos_block.t) : - Block_header.shell_header = + Block_header.shell_header tzresult = + let open Result_syntax in let open Mock in - let predecessor = ethereum_to_tezos_block_hash block.parent_hash in - { - level = block.level; - proto_level; - predecessor; - timestamp = block.timestamp; - validation_passes; - operations_hash; - fitness; - context; - } + let* predecessor = ethereum_to_tezos_block_hash block.parent_hash in + return + Block_header. + { + level = block.level; + proto_level; + predecessor; + timestamp = block.timestamp; + validation_passes; + operations_hash; + fitness; + context; + } let tezlink_block_to_block_header ~l2_chain_id ((block : L2_types.Tezos_block.t), chain) : Block_services.block_header tzresult = let open Result_syntax in - let chain_id = tezlink_to_tezos_chain_id_exn ~l2_chain_id chain in + let* chain_id = tezlink_to_tezos_chain_id ~l2_chain_id chain in let* protocol_data = Protocol_data.get_mock_protocol_data in - let hash = ethereum_to_tezos_block_hash block.hash in - let shell = tezlink_block_to_shell_header block in + let* hash = ethereum_to_tezos_block_hash block.hash in + let* shell = tezlink_block_to_shell_header block in let block_header : Block_services.block_header = {chain_id; hash; shell; protocol_data} in @@ -185,6 +188,12 @@ let import_service s = Tezos_rpc.Service.subst0 s let register_with_conversion ~service ~impl ~convert_output dir = Tezos_rpc.Directory.register dir service (wrap convert_output impl) +let opt_register_with_conversion ~service ~impl ~convert_output dir = + Tezos_rpc.Directory.opt_register + dir + service + (wrap (Option.map_e convert_output) impl) + let register ~service ~impl dir = Tezos_rpc.Directory.register dir service impl type block = Tezos_shell_services.Block_services.block @@ -330,6 +339,16 @@ module Imported_services = struct Tezos_rpc.Service.t = import_service Constants_services.all + let hash : + ( [`GET], + tezlink_rpc_context, + tezlink_rpc_context, + unit, + unit, + Block_hash.t ) + Tezos_rpc.Service.t = + import_service Block_services.S.hash + let chain_id : ([`GET], chain, chain, unit, unit, Chain_id.t) Tezos_rpc.Service.t = import_service Tezos_shell_services.Chain_services.S.chain_id @@ -468,6 +487,13 @@ let register_block_services ~l2_chain_id ~convert_output: (Protocol_types.Block_header.tezlink_block_to_block_header ~l2_chain_id) + |> opt_register_with_conversion + ~service:Imported_services.hash + ~impl:(fun {block; chain} () () -> + let*? chain = check_chain chain in + let*? block = check_block block in + Backend.block_hash chain block) + ~convert_output:Protocol_types.ethereum_to_tezos_block_hash in Tezos_rpc.Directory.prefix block_directory_path @@ -485,8 +511,7 @@ let register_chain_services ~l2_chain_id ~impl:(fun chain () () -> Lwt_result_syntax.return (l2_chain_id, chain)) ~convert_output:(fun (l2_chain_id, chain) -> - Result_syntax.return - @@ Protocol_types.tezlink_to_tezos_chain_id_exn ~l2_chain_id chain) + Protocol_types.tezlink_to_tezos_chain_id ~l2_chain_id chain) |> Tezos_rpc.Directory.map (fun ((), chain) -> Lwt.return chain) in Tezos_rpc.Directory.merge @@ -503,8 +528,9 @@ let build_dir ~l2_chain_id backend = ~service:Imported_services.bootstrapped ~impl:(fun () () () -> Backend.bootstrapped ()) ~convert_output:(fun (input_hash, input_time) -> - Result_syntax.return - (Protocol_types.ethereum_to_tezos_block_hash input_hash, input_time)) + let open Result_syntax in + let* hash = Protocol_types.ethereum_to_tezos_block_hash input_hash in + return (hash, input_time)) |> register ~service:Imported_services.version ~impl:(fun () () () -> version ()) diff --git a/etherlink/bin_node/lib_dev/tezlink_services_impl.ml b/etherlink/bin_node/lib_dev/tezlink_services_impl.ml index bb774933e68e..cfb147d50a24 100644 --- a/etherlink/bin_node/lib_dev/tezlink_services_impl.ml +++ b/etherlink/bin_node/lib_dev/tezlink_services_impl.ml @@ -32,6 +32,8 @@ module type Backend = sig Ethereum_types.quantity tzresult Lwt.t val tez_nth_block : Z.t -> L2_types.Tezos_block.t tzresult Lwt.t + + val nth_block_hash : Z.t -> Ethereum_types.block_hash option tzresult Lwt.t end module Make (Backend : Backend) : Tezlink_backend_sig.S = struct @@ -145,4 +147,11 @@ module Make (Backend : Backend) : Tezlink_backend_sig.S = struct in let* block = Backend.tez_nth_block current_block_number in return (block.hash, block.timestamp) + + let block_hash chain block = + let open Lwt_result_syntax in + let `Main = chain in + let* number = shell_block_param_to_block_number block in + + Backend.nth_block_hash (Z.of_int32 number) end diff --git a/etherlink/tezt/tests/expected/evm_sequencer.ml/Alpha- Test the -describe endpoint.out b/etherlink/tezt/tests/expected/evm_sequencer.ml/Alpha- Test the -describe endpoint.out index 0a0f0047da2a..e66f5a090a2a 100644 --- a/etherlink/tezt/tests/expected/evm_sequencer.ml/Alpha- Test the -describe endpoint.out +++ b/etherlink/tezt/tests/expected/evm_sequencer.ml/Alpha- Test the -describe endpoint.out @@ -39,6 +39,8 @@ Available services: Access the counter of a contract, if any. - GET /tezlink/chains//blocks//context/contracts//manager_key Access the manager of an implicit contract. + - GET /tezlink/chains//blocks//hash + The block's hash, its unique identifier. - GET /tezlink/chains//blocks//header The whole block header. - GET /tezlink/chains//blocks//helpers/current_level @@ -110,6 +112,8 @@ Available services: Access the counter of a contract, if any. - GET /chains//blocks//context/contracts//manager_key Access the manager of an implicit contract. + - GET /chains//blocks//hash + The block's hash, its unique identifier. - GET /chains//blocks//header The whole block header. - GET /chains//blocks//helpers/current_level -- GitLab From 72f0f0ec8dba6456c08e28666d1f7e8d3f18b8a8 Mon Sep 17 00:00:00 2001 From: Dibassi Brahima Date: Mon, 5 May 2025 08:24:06 +0200 Subject: [PATCH 4/4] Tezlink/Tezt Add test for Tezlink hash RPC functionality --- etherlink/tezt/tests/evm_sequencer.ml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/etherlink/tezt/tests/evm_sequencer.ml b/etherlink/tezt/tests/evm_sequencer.ml index 238404ed3599..d3e5fd426812 100644 --- a/etherlink/tezt/tests/evm_sequencer.ml +++ b/etherlink/tezt/tests/evm_sequencer.ml @@ -530,6 +530,11 @@ let test_tezlink_current_level = in let* res = rpc_current_level "head" in let* () = check_current_level res 5 in + (* Check with block parameter *) + let* res = rpc_current_level "head~2" in + let* () = check_current_level res 3 in + let* res = rpc_current_level "head~2" ~offset:1 in + let* () = check_current_level res 4 in (* test negative offset *) let* res = rpc_current_level "head" ~offset:(-1) in Check.( @@ -1261,6 +1266,26 @@ let test_tezlink_produceBlock = ~error_msg:"Expected new block number to be %L, but got: %R" ; unit +let test_tezlink_hash_rpc = + register_tezlink_test ~title:"Test Tezlink hash rpc" ~tags:["rpc"; "hash"] + @@ fun {sequencer; _} _protocol -> + let path_head = "/tezlink/chains/main/blocks/head/hash" in + let rpc_hash () = + let* res = + Curl.get_raw ~args:["-v"] (Evm_node.endpoint sequencer ^ path_head) + |> Runnable.run + in + return @@ JSON.parse ~origin:"curl_hash" res + in + let* hash_old_head = rpc_hash () in + let*@ _ = produce_block sequencer in + let* hash_current_head = rpc_hash () in + Check.( + JSON.(hash_current_head |> as_string <> (hash_old_head |> as_string)) + string + ~error_msg:"Block hash should be different") ; + unit + module Protocol = struct include Protocol @@ -13631,6 +13656,7 @@ let () = test_tezlink_header [Alpha] ; test_tezlink_constants [Alpha] ; test_tezlink_produceBlock [Alpha] ; + test_tezlink_hash_rpc [Alpha] ; test_tezlink_chain_id [Alpha] ; test_tezlink_bootstrapped [Alpha] ; test_fa_deposit_can_be_claimed [Alpha] -- GitLab