diff --git a/manifest/main.ml b/manifest/main.ml index e0fd02bd9b0cd68738c8111ce89f9226164d2b9a..01e24057e41f3da778ee22c6ef5dc4b4135e1263 100644 --- a/manifest/main.ml +++ b/manifest/main.ml @@ -2,7 +2,7 @@ (* *) (* Open Source License *) (* Copyright (c) 2021-2022 Nomadic Labs *) -(* Copyright (c) 2022 Trili Tech *) +(* Copyright (c) 2022-2023 Trili Tech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -4926,6 +4926,7 @@ module Protocol = Protocol sc_rollup |> if_some |> open_; layer2_utils |> if_some |> open_; octez_layer2_store |> open_; + tree_encoding; data_encoding; irmin_pack; irmin_pack_unix; @@ -4933,6 +4934,7 @@ module Protocol = Protocol aches; aches_lwt; injector |> if_some |> open_; + octez_scoru_wasm; octez_scoru_wasm_fast; octez_crypto_dal |> if_ N.(number >= 016) |> open_; prometheus_app |> if_ N.(number >= 016); diff --git a/opam/octez-smart-rollup-node-PtMumbai.opam b/opam/octez-smart-rollup-node-PtMumbai.opam index f6bcf772f77eb8926dea70ab1aa1e0c10a946dc7..c8d14a4db1b8dc1df7509e11a654fec5e87dc31d 100644 --- a/opam/octez-smart-rollup-node-PtMumbai.opam +++ b/opam/octez-smart-rollup-node-PtMumbai.opam @@ -29,12 +29,14 @@ depends: [ "tezos-smart-rollup-016-PtMumbai" "tezos-layer2-utils-016-PtMumbai" "tezos-layer2-store" + "tezos-tree-encoding" "data-encoding" { >= "0.7.1" & < "1.0.0" } "irmin-pack" { >= "3.5.1" & < "3.6.0" } "irmin" { >= "3.5.1" & < "3.6.0" } "aches" { >= "1.0.0" } "aches-lwt" { >= "1.0.0" } "tezos-injector-016-PtMumbai" + "tezos-scoru-wasm" "tezos-scoru-wasm-fast" "tezos-crypto-dal" "prometheus-app" { >= "1.2" } diff --git a/opam/octez-smart-rollup-node-alpha.opam b/opam/octez-smart-rollup-node-alpha.opam index 1dfd5665940ac3c1aad0f35d8812a9e4188aaf49..42d842500f29f16220ad87a46235097a4ac6edb7 100644 --- a/opam/octez-smart-rollup-node-alpha.opam +++ b/opam/octez-smart-rollup-node-alpha.opam @@ -29,12 +29,14 @@ depends: [ "tezos-smart-rollup-alpha" "tezos-layer2-utils-alpha" "tezos-layer2-store" + "tezos-tree-encoding" "data-encoding" { >= "0.7.1" & < "1.0.0" } "irmin-pack" { >= "3.5.1" & < "3.6.0" } "irmin" { >= "3.5.1" & < "3.6.0" } "aches" { >= "1.0.0" } "aches-lwt" { >= "1.0.0" } "tezos-injector-alpha" + "tezos-scoru-wasm" "tezos-scoru-wasm-fast" "tezos-crypto-dal" "prometheus-app" { >= "1.2" } diff --git a/src/lib_scoru_wasm/durable.ml b/src/lib_scoru_wasm/durable.ml index 48927370a9a8117c6933ae4d585bfcce267b27ef..30f8a86e5876e1de828ca15edf5f67097b3d2845 100644 --- a/src/lib_scoru_wasm/durable.ml +++ b/src/lib_scoru_wasm/durable.ml @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 TriliTech *) +(* Copyright (c) 2022-2023 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -141,6 +141,11 @@ let copy_tree_exn tree ?(edit_readonly = false) from_key to_key = let count_subtrees tree key = T.length tree @@ key_contents key +let list tree key = + let open Lwt.Syntax in + let+ subtrees = T.list tree @@ key_contents key in + List.map (fun (name, _) -> if name == "@" then "" else name) subtrees + let delete ?(edit_readonly = false) tree key = if not edit_readonly then assert_key_writeable key ; T.remove tree @@ key_contents key diff --git a/src/lib_scoru_wasm/durable.mli b/src/lib_scoru_wasm/durable.mli index 822679362a186ecdb8485e2d196f6b44fe227a56..a90810c43c2d8ad6c26f9dac9cb3f65beae50ff4 100644 --- a/src/lib_scoru_wasm/durable.mli +++ b/src/lib_scoru_wasm/durable.mli @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 TriliTech *) +(* Copyright (c) 2022-2023 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -103,6 +103,9 @@ val copy_tree_exn : t -> ?edit_readonly:bool -> key -> key -> t Lwt.t *) val move_tree_exn : t -> key -> key -> t Lwt.t +(** [list durable key] returns the subkeys under [key]. *) +val list : t -> key -> string list Lwt.t + (** [count_subtrees durable key] returns the number of subtrees under [key]. *) val count_subtrees : t -> key -> int Lwt.t diff --git a/src/lib_scoru_wasm/wasm_pvm.ml b/src/lib_scoru_wasm/wasm_pvm.ml index 09f82fff28a456d8f91d00d393b3c3d7b2c77740..e7069351e42dea6c2cc942dbe1914689371ab3ef 100644 --- a/src/lib_scoru_wasm/wasm_pvm.ml +++ b/src/lib_scoru_wasm/wasm_pvm.ml @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 TriliTech *) +(* Copyright (c) 2022-2023 TriliTech *) (* Copyright (c) 2022 Marigold *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) @@ -109,6 +109,9 @@ let tick_state_encoding = let durable_buffers_encoding = Tezos_tree_encoding.(scope ["pvm"; "buffers"] Wasm_encoding.buffers_encoding) +let durable_storage_encoding = + Tezos_tree_encoding.(scope ["durable"] Durable.encoding) + let default_buffers validity_period message_limit () = Tezos_webassembly_interpreter.Eval. { @@ -194,7 +197,7 @@ let pvm_state_encoding = (value_option ["wasm"; "input"] Wasm_pvm_sig.input_info_encoding) (value ~default:Z.zero ["wasm"; "current_tick"] Data_encoding.n) (value_option ["wasm"; "reboot_counter"] Data_encoding.n) - (scope ["durable"] Durable.encoding) + durable_storage_encoding (option durable_buffers_encoding) (scope ["wasm"] tick_state_encoding) (value ~default:Z.zero ["pvm"; "last_top_level_call"] Data_encoding.n) diff --git a/src/lib_scoru_wasm/wasm_pvm.mli b/src/lib_scoru_wasm/wasm_pvm.mli index 203d16c188f878e46c0371c154598441bdfe6f2c..572d6d06dbcd8c4458751a41cea5695e007a0f8b 100644 --- a/src/lib_scoru_wasm/wasm_pvm.mli +++ b/src/lib_scoru_wasm/wasm_pvm.mli @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 TriliTech *) +(* Copyright (c) 2022-2023 TriliTech *) (* Copyright (c) 2022 Marigold *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) @@ -30,6 +30,8 @@ val pvm_state_encoding : val durable_buffers_encoding : Tezos_webassembly_interpreter.Eval.buffers Tezos_tree_encoding.t +val durable_storage_encoding : Durable.t Tezos_tree_encoding.t + module Make (T : Tezos_tree_encoding.TREE) : Wasm_pvm_sig.S with type tree = T.tree diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_directory_helpers.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_directory_helpers.ml new file mode 100644 index 0000000000000000000000000000000000000000..c60df3e8a355d1f91787b0ca71ed9902135e35c7 --- /dev/null +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_directory_helpers.ml @@ -0,0 +1,100 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +open Protocol + +(* Conveniences to construct RPC directory + against a subcontext of the Node_context *) + +module type PARAM = sig + include Sc_rollup_services.PREFIX + + type context + + val context_of_prefix : Node_context.rw -> prefix -> context tzresult Lwt.t +end + +module Make_directory (S : PARAM) = struct + open S + + let directory : context tzresult Tezos_rpc.Directory.t ref = + ref Tezos_rpc.Directory.empty + + let register service f = + directory := Tezos_rpc.Directory.register !directory service f + + let register0 service f = + let open Lwt_result_syntax in + register (Tezos_rpc.Service.subst0 service) @@ fun ctxt query input -> + let*? ctxt = ctxt in + f ctxt query input + + let register1 service f = + let open Lwt_result_syntax in + register (Tezos_rpc.Service.subst1 service) + @@ fun (ctxt, arg) query input -> + let*? ctxt = ctxt in + f ctxt arg query input + + let build_directory node_ctxt = + !directory + |> Tezos_rpc.Directory.map (fun prefix -> + context_of_prefix node_ctxt prefix) + |> Tezos_rpc.Directory.prefix prefix +end + +module Block_directory_helpers = struct + let get_head store = + let open Lwt_result_syntax in + let*! head = Node_context.last_processed_head_opt store in + match head with + | None -> failwith "No head" + | Some {header = {block_hash; _}; _} -> return block_hash + + let get_finalized node_ctxt = + let open Lwt_result_syntax in + let*! head = Node_context.get_finalized_head_opt node_ctxt in + match head with + | None -> failwith "No finalized head" + | Some {header = {block_hash; _}; _} -> return block_hash + + let get_last_cemented (node_ctxt : _ Node_context.t) = + let open Lwt_result_syntax in + protect @@ fun () -> + let* lcc_hash = + Node_context.hash_of_level + node_ctxt + (Alpha_context.Raw_level.to_int32 node_ctxt.lcc.level) + in + return lcc_hash + + let block_of_prefix node_ctxt block = + match block with + | `Head -> get_head node_ctxt + | `Hash b -> return b + | `Level l -> Node_context.hash_of_level node_ctxt l + | `Finalized -> get_finalized node_ctxt + | `Cemented -> get_last_cemented node_ctxt +end diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_directory_helpers.mli b/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_directory_helpers.mli new file mode 100644 index 0000000000000000000000000000000000000000..72f9952c4bbe88ef66dc81ccda5e9f071fb68fc1 --- /dev/null +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_directory_helpers.mli @@ -0,0 +1,71 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* Copyright (c) 2022-2023 TriliTech *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +open Tezos_rpc + +(** This module defines subcontext type of the subdirectory and + the way to project it from Node_context and a path prefix. *) +module type PARAM = sig + include Sc_rollup_services.PREFIX + + type context + + val context_of_prefix : Node_context.rw -> prefix -> context tzresult Lwt.t +end + +(** This module is a helper to register your endpoints and + build a resulting subdirectory eventually. *) +module Make_directory (S : PARAM) : sig + (** Register an endpoint with no parameters in the path. *) + val register0 : + ([< Resto.meth], 'prefix, 'prefix, 'query, 'input, 'output) Service.t -> + (S.context -> 'query -> 'input -> 'output tzresult Lwt.t) -> + unit + + (** Register an endpoint with a single parameter in the path. *) + val register1 : + ( [< Resto.meth], + 'prefix, + 'prefix * 'param1, + 'query, + 'input, + 'output ) + Service.t -> + (S.context -> 'param1 -> 'query -> 'input -> 'output tzresult Lwt.t) -> + unit + + (** Build directory with registered endpoints with respect to Node_context. *) + val build_directory : Node_context.rw -> unit Tezos_rpc.Directory.t +end + +(** This module is a helper to extract a block hash + from block reference and Node_context *) +module Block_directory_helpers : sig + val block_of_prefix : + Node_context.rw -> + [< `Cemented | `Finalized | `Hash of Block_hash.t | `Head | `Level of int32] -> + Block_hash.t tzresult Lwt.t +end diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_server.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_server.ml index 454e1e15d14e2d06c193668ff7b0863cfc5aafc5..15859eb7ce0a99bd9e3a236d4ae3a290544f4675 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_server.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_server.ml @@ -2,6 +2,7 @@ (* *) (* Open Source License *) (* Copyright (c) 2022 Nomadic Labs, *) +(* Copyright (c) 2022-2023 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -25,32 +26,9 @@ open Tezos_rpc_http open Tezos_rpc_http_server +open RPC_directory_helpers open Protocol -let get_head store = - let open Lwt_result_syntax in - let*! head = Node_context.last_processed_head_opt store in - match head with - | None -> failwith "No head" - | Some {header = {block_hash; _}; _} -> return block_hash - -let get_finalized node_ctxt = - let open Lwt_result_syntax in - let*! head = Node_context.get_finalized_head_opt node_ctxt in - match head with - | None -> failwith "No finalized head" - | Some {header = {block_hash; _}; _} -> return block_hash - -let get_last_cemented (node_ctxt : _ Node_context.t) = - let open Lwt_result_syntax in - protect @@ fun () -> - let* lcc_hash = - Node_context.hash_of_level - node_ctxt - (Alpha_context.Raw_level.to_int32 node_ctxt.lcc.level) - in - return lcc_hash - let get_head_hash_opt node_ctxt = let open Lwt_option_syntax in let+ {header = {block_hash; _}; _} = @@ -116,43 +94,6 @@ let get_dal_slot_page node_ctxt block slot_index slot_page = | None -> assert false | Some _contents -> return ("Slot page is available", contents_opt)) -module type PARAM = sig - include Sc_rollup_services.PREFIX - - type context - - val context_of_prefix : Node_context.rw -> prefix -> context tzresult Lwt.t -end - -module Make_directory (S : PARAM) = struct - open S - - let directory : context tzresult Tezos_rpc.Directory.t ref = - ref Tezos_rpc.Directory.empty - - let register service f = - directory := Tezos_rpc.Directory.register !directory service f - - let register0 service f = - let open Lwt_result_syntax in - register (Tezos_rpc.Service.subst0 service) @@ fun ctxt query input -> - let*? ctxt = ctxt in - f ctxt query input - - let register1 service f = - let open Lwt_result_syntax in - register (Tezos_rpc.Service.subst1 service) - @@ fun (ctxt, arg) query input -> - let*? ctxt = ctxt in - f ctxt arg query input - - let build_directory node_ctxt = - !directory - |> Tezos_rpc.Directory.map (fun prefix -> - context_of_prefix node_ctxt prefix) - |> Tezos_rpc.Directory.prefix prefix -end - module Global_directory = Make_directory (struct include Sc_rollup_services.Global @@ -186,14 +127,7 @@ module Block_directory = Make_directory (struct let context_of_prefix node_ctxt (((), block) : prefix) = let open Lwt_result_syntax in - let+ block = - match block with - | `Head -> get_head node_ctxt - | `Hash b -> return b - | `Level l -> Node_context.hash_of_level node_ctxt l - | `Finalized -> get_finalized node_ctxt - | `Cemented -> get_last_cemented node_ctxt - in + let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in (Node_context.readonly node_ctxt, block) end) @@ -204,14 +138,7 @@ module Outbox_directory = Make_directory (struct let context_of_prefix node_ctxt (((), block), level) = let open Lwt_result_syntax in - let+ block = - match block with - | `Head -> get_head node_ctxt - | `Hash b -> return b - | `Level l -> Node_context.hash_of_level node_ctxt l - | `Finalized -> get_finalized node_ctxt - | `Cemented -> get_last_cemented node_ctxt - in + let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in (Node_context.readonly node_ctxt, block, level) end) @@ -604,6 +531,7 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct Block_directory.build_directory; Proof_helpers_directory.build_directory; Outbox_directory.build_directory; + PVM.RPC.build_directory; ] let start node_ctxt configuration = diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/arith_pvm.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/arith_pvm.ml index ff72b3846ea0dcd0574a7f8ac6f91c68f1f4aee8..f7d3c2b78d3edb4dc91944c35491f06645d56b49 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/arith_pvm.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/arith_pvm.ml @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 TriliTech *) +(* Copyright (c) 2022-2023 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -52,6 +52,10 @@ module Impl : Pvm.S = struct module State = Context.PVMState + module RPC = struct + let build_directory _node_ctxt = Tezos_rpc.Directory.empty + end + let new_dissection = Game_helpers.default_new_dissection let string_of_status status = diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/dune b/src/proto_016_PtMumbai/bin_sc_rollup_node/dune index 6620cadda3c2183633de2e9ae6a4d8e239aecb6b..ab2242dd09a024ae96e28683743ede3dc2fa53c3 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/dune +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/dune @@ -29,6 +29,7 @@ tezos-smart-rollup-016-PtMumbai tezos-layer2-utils-016-PtMumbai tezos_layer2_store + tezos-tree-encoding data-encoding irmin-pack irmin-pack.unix @@ -36,6 +37,7 @@ aches aches-lwt tezos-injector-016-PtMumbai + tezos-scoru-wasm tezos-scoru-wasm-fast tezos-crypto-dal prometheus-app diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/pvm.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/pvm.ml index bb314669b17f7162ddf2dbfd443bb9acb68a5493..ca8e5769b9f6580abca572206ccdc6d881faeb68 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/pvm.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/pvm.ml @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 TriliTech *) +(* Copyright (c) 2022-2023 TriliTech *) (* Copyright (c) 2022 Nomadic Labs, *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) @@ -69,6 +69,11 @@ module type S = sig our_stop_chunk:Sc_rollup.Dissection_chunk.t -> Sc_rollup.Tick.t list + module RPC : sig + (** Build RPC directory of the PVM *) + val build_directory : Node_context.rw -> unit Environment.RPC_directory.t + end + (** State storage for this PVM. *) module State : sig (** [empty ()] is the empty state. *) diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/wasm_2_0_0_pvm.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/wasm_2_0_0_pvm.ml index a0e25f02ae434219f6f93af4d81c9bfb0b7644e0..9a7170774a955c00d4f75580ba043640b56514cc 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/wasm_2_0_0_pvm.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/wasm_2_0_0_pvm.ml @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 TriliTech *) +(* Copyright (c) 2022-2023 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -49,18 +49,57 @@ module type TreeS = with type key = string list and type value = bytes -module Make_backend (Tree : TreeS) = struct +module Make_wrapped_tree (Tree : TreeS) : + Tezos_tree_encoding.TREE with type tree = Tree.tree = struct type Tezos_lazy_containers.Lazy_map.tree += PVM_tree of Tree.tree - include Tezos_scoru_wasm_fast.Pvm.Make (struct - include Tree + include Tree - let select = function - | PVM_tree t -> t - | _ -> raise Tezos_tree_encoding.Incorrect_tree_type + let select = function + | PVM_tree t -> t + | _ -> raise Tezos_tree_encoding.Incorrect_tree_type - let wrap t = PVM_tree t - end) + let wrap t = PVM_tree t +end + +module Make_backend (Tree : TreeS) = + Tezos_scoru_wasm_fast.Pvm.Make (Make_wrapped_tree (Tree)) + +module Make_durable_state + (T : Tezos_tree_encoding.TREE with type tree = Context.tree) : + Wasm_2_0_0_rpc.Durable_state with type state = T.tree = struct + module Tree_encoding_runner = Tezos_tree_encoding.Runner.Make (T) + + type state = T.tree + + let decode_durable tree = + Tree_encoding_runner.decode + Tezos_scoru_wasm.Wasm_pvm.durable_storage_encoding + tree + + let value_length tree key_str = + let open Lwt_syntax in + let key = Tezos_scoru_wasm.Durable.key_of_string_exn key_str in + let* durable = decode_durable tree in + let+ res_opt = Tezos_scoru_wasm.Durable.find_value durable key in + Option.map Tezos_lazy_containers.Chunked_byte_vector.length res_opt + + let lookup tree key_str = + let open Lwt_syntax in + let key = Tezos_scoru_wasm.Durable.key_of_string_exn key_str in + let* durable = decode_durable tree in + let* res_opt = Tezos_scoru_wasm.Durable.find_value durable key in + match res_opt with + | None -> return_none + | Some v -> + let+ bts = Tezos_lazy_containers.Chunked_byte_vector.to_bytes v in + Some bts + + let list tree key_str = + let open Lwt_syntax in + let key = Tezos_scoru_wasm.Durable.key_of_string_exn key_str in + let* durable = decode_durable tree in + Tezos_scoru_wasm.Durable.list durable key end module Impl : Pvm.S = struct @@ -73,6 +112,9 @@ module Impl : Pvm.S = struct let new_dissection = Game_helpers.Wasm.new_dissection module State = Context.PVMState + module Durable_state = + Make_durable_state (Make_wrapped_tree (Wasm_2_0_0_proof_format.Tree)) + module RPC = Wasm_2_0_0_rpc.Make_RPC (Durable_state) let string_of_status : status -> string = function | Waiting_for_input_message -> "Waiting for input message" diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/wasm_2_0_0_rpc.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/wasm_2_0_0_rpc.ml new file mode 100644 index 0000000000000000000000000000000000000000..8f410c55049e08754e2d1c5b8ff3e3a16013bd0f --- /dev/null +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/wasm_2_0_0_rpc.ml @@ -0,0 +1,95 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* Copyright (c) 2023 Trili Tech *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +open RPC_directory_helpers + +(** Durable part of the storage of this PVM. *) +module type Durable_state = sig + type state + + (** [value_length state key] returns the length of data stored + for the [key] in the durable storage of the PVM state [state], if any. *) + val value_length : state -> string -> int64 option Lwt.t + + (** [lookup state key] returns the data stored + for the [key] in the durable storage of the PVM state [state], if any. *) + val lookup : state -> string -> bytes option Lwt.t + + (** [subtrees state key] returns subtrees + for the [key] in the durable storage of the PVM state [state]. + Empty list in case if path doesn't exist. *) + val list : state -> string -> string list Lwt.t +end + +module Make_RPC (Durable_state : Durable_state with type state = Context.tree) = +struct + module Block_directory = Make_directory (struct + include Sc_rollup_services.Global.Block + + type context = Node_context.ro * Block_hash.t + + let context_of_prefix node_ctxt (((), block) : prefix) = + let open Lwt_result_syntax in + let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in + (Node_context.readonly node_ctxt, block) + end) + + let get_state (node_ctxt : _ Node_context.t) block_hash = + let open Lwt_result_syntax in + let* ctxt = Node_context.checkout_context node_ctxt block_hash in + let*! state = Context.PVMState.find ctxt in + match state with None -> failwith "No state" | Some state -> return state + + let register () = + let open Protocol.Alpha_context.Sc_rollup in + ( Block_directory.register0 + (Sc_rollup_services.Global.Block.durable_state_value Kind.Wasm_2_0_0) + @@ fun (node_ctxt, block) {key} () -> + let open Lwt_result_syntax in + let* state = get_state node_ctxt block in + let*! value = Durable_state.lookup state key in + return value ) ; + + ( Block_directory.register0 + (Sc_rollup_services.Global.Block.durable_state_length Kind.Wasm_2_0_0) + @@ fun (node_ctxt, block) {key} () -> + let open Lwt_result_syntax in + let* state = get_state node_ctxt block in + let*! leng = Durable_state.value_length state key in + return leng ) ; + + Block_directory.register0 + (Sc_rollup_services.Global.Block.durable_state_subkeys Kind.Wasm_2_0_0) + @@ fun (node_ctxt, block) {key} () -> + let open Lwt_result_syntax in + let* state = get_state node_ctxt block in + let*! subkeys = Durable_state.list state key in + return subkeys + + let build_directory = + register () ; + Block_directory.build_directory +end diff --git a/src/proto_016_PtMumbai/lib_sc_rollup/sc_rollup_services.ml b/src/proto_016_PtMumbai/lib_sc_rollup/sc_rollup_services.ml index 609d325ff3dca18423b915e6ffdca54c9929a762..9bcbfa7c4eb3c2aba2c718ac24add20b39a4a88d 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup/sc_rollup_services.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup/sc_rollup_services.ml @@ -2,6 +2,7 @@ (* *) (* Open Source License *) (* Copyright (c) 2021 Nomadic Labs, *) +(* Copyright (c) 2023 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -501,6 +502,44 @@ module Global = struct ~output:Data_encoding.bytes (path / "state") + let durable_state_value (pvm_kind : Protocol.Alpha_context.Sc_rollup.Kind.t) + = + Tezos_rpc.Service.get_service + ~description: + "Retrieve value by key from PVM durable storage. PVM state is taken \ + with respect to the specified block level. Value returned in hex \ + format." + ~query:state_value_query + ~output:Data_encoding.(option bytes) + (path / "durable" + / Protocol.Alpha_context.Sc_rollup.Kind.to_string pvm_kind + / "value") + + let durable_state_length + (pvm_kind : Protocol.Alpha_context.Sc_rollup.Kind.t) = + Tezos_rpc.Service.get_service + ~description: + "Retrieve number of bytes in raw representation of value by key from \ + PVM durable storage. PVM state is taken with respect to the \ + specified block level." + ~query:state_value_query + ~output:Data_encoding.(option int64) + (path / "durable" + / Protocol.Alpha_context.Sc_rollup.Kind.to_string pvm_kind + / "length") + + let durable_state_subkeys + (pvm_kind : Protocol.Alpha_context.Sc_rollup.Kind.t) = + Tezos_rpc.Service.get_service + ~description: + "Retrieve subkeys of the specified key from PVM durable storage. PVM \ + state is taken with respect to the specified block level." + ~query:state_value_query + ~output:Data_encoding.(list string) + (path / "durable" + / Protocol.Alpha_context.Sc_rollup.Kind.to_string pvm_kind + / "subkeys") + let status = Tezos_rpc.Service.get_service ~description:"PVM status at block" diff --git a/src/proto_alpha/bin_sc_rollup_node/RPC_directory_helpers.ml b/src/proto_alpha/bin_sc_rollup_node/RPC_directory_helpers.ml new file mode 100644 index 0000000000000000000000000000000000000000..c60df3e8a355d1f91787b0ca71ed9902135e35c7 --- /dev/null +++ b/src/proto_alpha/bin_sc_rollup_node/RPC_directory_helpers.ml @@ -0,0 +1,100 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +open Protocol + +(* Conveniences to construct RPC directory + against a subcontext of the Node_context *) + +module type PARAM = sig + include Sc_rollup_services.PREFIX + + type context + + val context_of_prefix : Node_context.rw -> prefix -> context tzresult Lwt.t +end + +module Make_directory (S : PARAM) = struct + open S + + let directory : context tzresult Tezos_rpc.Directory.t ref = + ref Tezos_rpc.Directory.empty + + let register service f = + directory := Tezos_rpc.Directory.register !directory service f + + let register0 service f = + let open Lwt_result_syntax in + register (Tezos_rpc.Service.subst0 service) @@ fun ctxt query input -> + let*? ctxt = ctxt in + f ctxt query input + + let register1 service f = + let open Lwt_result_syntax in + register (Tezos_rpc.Service.subst1 service) + @@ fun (ctxt, arg) query input -> + let*? ctxt = ctxt in + f ctxt arg query input + + let build_directory node_ctxt = + !directory + |> Tezos_rpc.Directory.map (fun prefix -> + context_of_prefix node_ctxt prefix) + |> Tezos_rpc.Directory.prefix prefix +end + +module Block_directory_helpers = struct + let get_head store = + let open Lwt_result_syntax in + let*! head = Node_context.last_processed_head_opt store in + match head with + | None -> failwith "No head" + | Some {header = {block_hash; _}; _} -> return block_hash + + let get_finalized node_ctxt = + let open Lwt_result_syntax in + let*! head = Node_context.get_finalized_head_opt node_ctxt in + match head with + | None -> failwith "No finalized head" + | Some {header = {block_hash; _}; _} -> return block_hash + + let get_last_cemented (node_ctxt : _ Node_context.t) = + let open Lwt_result_syntax in + protect @@ fun () -> + let* lcc_hash = + Node_context.hash_of_level + node_ctxt + (Alpha_context.Raw_level.to_int32 node_ctxt.lcc.level) + in + return lcc_hash + + let block_of_prefix node_ctxt block = + match block with + | `Head -> get_head node_ctxt + | `Hash b -> return b + | `Level l -> Node_context.hash_of_level node_ctxt l + | `Finalized -> get_finalized node_ctxt + | `Cemented -> get_last_cemented node_ctxt +end diff --git a/src/proto_alpha/bin_sc_rollup_node/RPC_directory_helpers.mli b/src/proto_alpha/bin_sc_rollup_node/RPC_directory_helpers.mli new file mode 100644 index 0000000000000000000000000000000000000000..72f9952c4bbe88ef66dc81ccda5e9f071fb68fc1 --- /dev/null +++ b/src/proto_alpha/bin_sc_rollup_node/RPC_directory_helpers.mli @@ -0,0 +1,71 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* Copyright (c) 2022-2023 TriliTech *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +open Tezos_rpc + +(** This module defines subcontext type of the subdirectory and + the way to project it from Node_context and a path prefix. *) +module type PARAM = sig + include Sc_rollup_services.PREFIX + + type context + + val context_of_prefix : Node_context.rw -> prefix -> context tzresult Lwt.t +end + +(** This module is a helper to register your endpoints and + build a resulting subdirectory eventually. *) +module Make_directory (S : PARAM) : sig + (** Register an endpoint with no parameters in the path. *) + val register0 : + ([< Resto.meth], 'prefix, 'prefix, 'query, 'input, 'output) Service.t -> + (S.context -> 'query -> 'input -> 'output tzresult Lwt.t) -> + unit + + (** Register an endpoint with a single parameter in the path. *) + val register1 : + ( [< Resto.meth], + 'prefix, + 'prefix * 'param1, + 'query, + 'input, + 'output ) + Service.t -> + (S.context -> 'param1 -> 'query -> 'input -> 'output tzresult Lwt.t) -> + unit + + (** Build directory with registered endpoints with respect to Node_context. *) + val build_directory : Node_context.rw -> unit Tezos_rpc.Directory.t +end + +(** This module is a helper to extract a block hash + from block reference and Node_context *) +module Block_directory_helpers : sig + val block_of_prefix : + Node_context.rw -> + [< `Cemented | `Finalized | `Hash of Block_hash.t | `Head | `Level of int32] -> + Block_hash.t tzresult Lwt.t +end diff --git a/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml b/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml index 454e1e15d14e2d06c193668ff7b0863cfc5aafc5..15859eb7ce0a99bd9e3a236d4ae3a290544f4675 100644 --- a/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml +++ b/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml @@ -2,6 +2,7 @@ (* *) (* Open Source License *) (* Copyright (c) 2022 Nomadic Labs, *) +(* Copyright (c) 2022-2023 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -25,32 +26,9 @@ open Tezos_rpc_http open Tezos_rpc_http_server +open RPC_directory_helpers open Protocol -let get_head store = - let open Lwt_result_syntax in - let*! head = Node_context.last_processed_head_opt store in - match head with - | None -> failwith "No head" - | Some {header = {block_hash; _}; _} -> return block_hash - -let get_finalized node_ctxt = - let open Lwt_result_syntax in - let*! head = Node_context.get_finalized_head_opt node_ctxt in - match head with - | None -> failwith "No finalized head" - | Some {header = {block_hash; _}; _} -> return block_hash - -let get_last_cemented (node_ctxt : _ Node_context.t) = - let open Lwt_result_syntax in - protect @@ fun () -> - let* lcc_hash = - Node_context.hash_of_level - node_ctxt - (Alpha_context.Raw_level.to_int32 node_ctxt.lcc.level) - in - return lcc_hash - let get_head_hash_opt node_ctxt = let open Lwt_option_syntax in let+ {header = {block_hash; _}; _} = @@ -116,43 +94,6 @@ let get_dal_slot_page node_ctxt block slot_index slot_page = | None -> assert false | Some _contents -> return ("Slot page is available", contents_opt)) -module type PARAM = sig - include Sc_rollup_services.PREFIX - - type context - - val context_of_prefix : Node_context.rw -> prefix -> context tzresult Lwt.t -end - -module Make_directory (S : PARAM) = struct - open S - - let directory : context tzresult Tezos_rpc.Directory.t ref = - ref Tezos_rpc.Directory.empty - - let register service f = - directory := Tezos_rpc.Directory.register !directory service f - - let register0 service f = - let open Lwt_result_syntax in - register (Tezos_rpc.Service.subst0 service) @@ fun ctxt query input -> - let*? ctxt = ctxt in - f ctxt query input - - let register1 service f = - let open Lwt_result_syntax in - register (Tezos_rpc.Service.subst1 service) - @@ fun (ctxt, arg) query input -> - let*? ctxt = ctxt in - f ctxt arg query input - - let build_directory node_ctxt = - !directory - |> Tezos_rpc.Directory.map (fun prefix -> - context_of_prefix node_ctxt prefix) - |> Tezos_rpc.Directory.prefix prefix -end - module Global_directory = Make_directory (struct include Sc_rollup_services.Global @@ -186,14 +127,7 @@ module Block_directory = Make_directory (struct let context_of_prefix node_ctxt (((), block) : prefix) = let open Lwt_result_syntax in - let+ block = - match block with - | `Head -> get_head node_ctxt - | `Hash b -> return b - | `Level l -> Node_context.hash_of_level node_ctxt l - | `Finalized -> get_finalized node_ctxt - | `Cemented -> get_last_cemented node_ctxt - in + let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in (Node_context.readonly node_ctxt, block) end) @@ -204,14 +138,7 @@ module Outbox_directory = Make_directory (struct let context_of_prefix node_ctxt (((), block), level) = let open Lwt_result_syntax in - let+ block = - match block with - | `Head -> get_head node_ctxt - | `Hash b -> return b - | `Level l -> Node_context.hash_of_level node_ctxt l - | `Finalized -> get_finalized node_ctxt - | `Cemented -> get_last_cemented node_ctxt - in + let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in (Node_context.readonly node_ctxt, block, level) end) @@ -604,6 +531,7 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct Block_directory.build_directory; Proof_helpers_directory.build_directory; Outbox_directory.build_directory; + PVM.RPC.build_directory; ] let start node_ctxt configuration = diff --git a/src/proto_alpha/bin_sc_rollup_node/arith_pvm.ml b/src/proto_alpha/bin_sc_rollup_node/arith_pvm.ml index ff72b3846ea0dcd0574a7f8ac6f91c68f1f4aee8..f7d3c2b78d3edb4dc91944c35491f06645d56b49 100644 --- a/src/proto_alpha/bin_sc_rollup_node/arith_pvm.ml +++ b/src/proto_alpha/bin_sc_rollup_node/arith_pvm.ml @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 TriliTech *) +(* Copyright (c) 2022-2023 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -52,6 +52,10 @@ module Impl : Pvm.S = struct module State = Context.PVMState + module RPC = struct + let build_directory _node_ctxt = Tezos_rpc.Directory.empty + end + let new_dissection = Game_helpers.default_new_dissection let string_of_status status = diff --git a/src/proto_alpha/bin_sc_rollup_node/dune b/src/proto_alpha/bin_sc_rollup_node/dune index ae10da4f64f19173ecc80491cddff342d6bf0353..d311dd66eb4ccfd04a51f2a8d0b1e167ba6e175d 100644 --- a/src/proto_alpha/bin_sc_rollup_node/dune +++ b/src/proto_alpha/bin_sc_rollup_node/dune @@ -29,6 +29,7 @@ tezos-smart-rollup-alpha tezos-layer2-utils-alpha tezos_layer2_store + tezos-tree-encoding data-encoding irmin-pack irmin-pack.unix @@ -36,6 +37,7 @@ aches aches-lwt tezos-injector-alpha + tezos-scoru-wasm tezos-scoru-wasm-fast tezos-crypto-dal prometheus-app diff --git a/src/proto_alpha/bin_sc_rollup_node/pvm.ml b/src/proto_alpha/bin_sc_rollup_node/pvm.ml index bb314669b17f7162ddf2dbfd443bb9acb68a5493..ca8e5769b9f6580abca572206ccdc6d881faeb68 100644 --- a/src/proto_alpha/bin_sc_rollup_node/pvm.ml +++ b/src/proto_alpha/bin_sc_rollup_node/pvm.ml @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 TriliTech *) +(* Copyright (c) 2022-2023 TriliTech *) (* Copyright (c) 2022 Nomadic Labs, *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) @@ -69,6 +69,11 @@ module type S = sig our_stop_chunk:Sc_rollup.Dissection_chunk.t -> Sc_rollup.Tick.t list + module RPC : sig + (** Build RPC directory of the PVM *) + val build_directory : Node_context.rw -> unit Environment.RPC_directory.t + end + (** State storage for this PVM. *) module State : sig (** [empty ()] is the empty state. *) diff --git a/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_pvm.ml b/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_pvm.ml index a0e25f02ae434219f6f93af4d81c9bfb0b7644e0..9a7170774a955c00d4f75580ba043640b56514cc 100644 --- a/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_pvm.ml +++ b/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_pvm.ml @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 TriliTech *) +(* Copyright (c) 2022-2023 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -49,18 +49,57 @@ module type TreeS = with type key = string list and type value = bytes -module Make_backend (Tree : TreeS) = struct +module Make_wrapped_tree (Tree : TreeS) : + Tezos_tree_encoding.TREE with type tree = Tree.tree = struct type Tezos_lazy_containers.Lazy_map.tree += PVM_tree of Tree.tree - include Tezos_scoru_wasm_fast.Pvm.Make (struct - include Tree + include Tree - let select = function - | PVM_tree t -> t - | _ -> raise Tezos_tree_encoding.Incorrect_tree_type + let select = function + | PVM_tree t -> t + | _ -> raise Tezos_tree_encoding.Incorrect_tree_type - let wrap t = PVM_tree t - end) + let wrap t = PVM_tree t +end + +module Make_backend (Tree : TreeS) = + Tezos_scoru_wasm_fast.Pvm.Make (Make_wrapped_tree (Tree)) + +module Make_durable_state + (T : Tezos_tree_encoding.TREE with type tree = Context.tree) : + Wasm_2_0_0_rpc.Durable_state with type state = T.tree = struct + module Tree_encoding_runner = Tezos_tree_encoding.Runner.Make (T) + + type state = T.tree + + let decode_durable tree = + Tree_encoding_runner.decode + Tezos_scoru_wasm.Wasm_pvm.durable_storage_encoding + tree + + let value_length tree key_str = + let open Lwt_syntax in + let key = Tezos_scoru_wasm.Durable.key_of_string_exn key_str in + let* durable = decode_durable tree in + let+ res_opt = Tezos_scoru_wasm.Durable.find_value durable key in + Option.map Tezos_lazy_containers.Chunked_byte_vector.length res_opt + + let lookup tree key_str = + let open Lwt_syntax in + let key = Tezos_scoru_wasm.Durable.key_of_string_exn key_str in + let* durable = decode_durable tree in + let* res_opt = Tezos_scoru_wasm.Durable.find_value durable key in + match res_opt with + | None -> return_none + | Some v -> + let+ bts = Tezos_lazy_containers.Chunked_byte_vector.to_bytes v in + Some bts + + let list tree key_str = + let open Lwt_syntax in + let key = Tezos_scoru_wasm.Durable.key_of_string_exn key_str in + let* durable = decode_durable tree in + Tezos_scoru_wasm.Durable.list durable key end module Impl : Pvm.S = struct @@ -73,6 +112,9 @@ module Impl : Pvm.S = struct let new_dissection = Game_helpers.Wasm.new_dissection module State = Context.PVMState + module Durable_state = + Make_durable_state (Make_wrapped_tree (Wasm_2_0_0_proof_format.Tree)) + module RPC = Wasm_2_0_0_rpc.Make_RPC (Durable_state) let string_of_status : status -> string = function | Waiting_for_input_message -> "Waiting for input message" diff --git a/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_rpc.ml b/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_rpc.ml new file mode 100644 index 0000000000000000000000000000000000000000..8f410c55049e08754e2d1c5b8ff3e3a16013bd0f --- /dev/null +++ b/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_rpc.ml @@ -0,0 +1,95 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* Copyright (c) 2023 Trili Tech *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +open RPC_directory_helpers + +(** Durable part of the storage of this PVM. *) +module type Durable_state = sig + type state + + (** [value_length state key] returns the length of data stored + for the [key] in the durable storage of the PVM state [state], if any. *) + val value_length : state -> string -> int64 option Lwt.t + + (** [lookup state key] returns the data stored + for the [key] in the durable storage of the PVM state [state], if any. *) + val lookup : state -> string -> bytes option Lwt.t + + (** [subtrees state key] returns subtrees + for the [key] in the durable storage of the PVM state [state]. + Empty list in case if path doesn't exist. *) + val list : state -> string -> string list Lwt.t +end + +module Make_RPC (Durable_state : Durable_state with type state = Context.tree) = +struct + module Block_directory = Make_directory (struct + include Sc_rollup_services.Global.Block + + type context = Node_context.ro * Block_hash.t + + let context_of_prefix node_ctxt (((), block) : prefix) = + let open Lwt_result_syntax in + let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in + (Node_context.readonly node_ctxt, block) + end) + + let get_state (node_ctxt : _ Node_context.t) block_hash = + let open Lwt_result_syntax in + let* ctxt = Node_context.checkout_context node_ctxt block_hash in + let*! state = Context.PVMState.find ctxt in + match state with None -> failwith "No state" | Some state -> return state + + let register () = + let open Protocol.Alpha_context.Sc_rollup in + ( Block_directory.register0 + (Sc_rollup_services.Global.Block.durable_state_value Kind.Wasm_2_0_0) + @@ fun (node_ctxt, block) {key} () -> + let open Lwt_result_syntax in + let* state = get_state node_ctxt block in + let*! value = Durable_state.lookup state key in + return value ) ; + + ( Block_directory.register0 + (Sc_rollup_services.Global.Block.durable_state_length Kind.Wasm_2_0_0) + @@ fun (node_ctxt, block) {key} () -> + let open Lwt_result_syntax in + let* state = get_state node_ctxt block in + let*! leng = Durable_state.value_length state key in + return leng ) ; + + Block_directory.register0 + (Sc_rollup_services.Global.Block.durable_state_subkeys Kind.Wasm_2_0_0) + @@ fun (node_ctxt, block) {key} () -> + let open Lwt_result_syntax in + let* state = get_state node_ctxt block in + let*! subkeys = Durable_state.list state key in + return subkeys + + let build_directory = + register () ; + Block_directory.build_directory +end diff --git a/src/proto_alpha/lib_sc_rollup/sc_rollup_services.ml b/src/proto_alpha/lib_sc_rollup/sc_rollup_services.ml index c311d86ed731d8dc86c442986c07157bf3ef12df..de2c3a0e5e82e82566cdd7a3674b6a25739fdd07 100644 --- a/src/proto_alpha/lib_sc_rollup/sc_rollup_services.ml +++ b/src/proto_alpha/lib_sc_rollup/sc_rollup_services.ml @@ -2,6 +2,7 @@ (* *) (* Open Source License *) (* Copyright (c) 2021 Nomadic Labs, *) +(* Copyright (c) 2023 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -501,6 +502,44 @@ module Global = struct ~output:Data_encoding.bytes (path / "state") + let durable_state_value (pvm_kind : Protocol.Alpha_context.Sc_rollup.Kind.t) + = + Tezos_rpc.Service.get_service + ~description: + "Retrieve value by key from PVM durable storage. PVM state is taken \ + with respect to the specified block level. Value returned in hex \ + format." + ~query:state_value_query + ~output:Data_encoding.(option bytes) + (path / "durable" + / Protocol.Alpha_context.Sc_rollup.Kind.to_string pvm_kind + / "value") + + let durable_state_length + (pvm_kind : Protocol.Alpha_context.Sc_rollup.Kind.t) = + Tezos_rpc.Service.get_service + ~description: + "Retrieve number of bytes in raw representation of value by key from \ + PVM durable storage. PVM state is taken with respect to the \ + specified block level." + ~query:state_value_query + ~output:Data_encoding.(option int64) + (path / "durable" + / Protocol.Alpha_context.Sc_rollup.Kind.to_string pvm_kind + / "length") + + let durable_state_subkeys + (pvm_kind : Protocol.Alpha_context.Sc_rollup.Kind.t) = + Tezos_rpc.Service.get_service + ~description: + "Retrieve subkeys of the specified key from PVM durable storage. PVM \ + state is taken with respect to the specified block level." + ~query:state_value_query + ~output:Data_encoding.(list string) + (path / "durable" + / Protocol.Alpha_context.Sc_rollup.Kind.to_string pvm_kind + / "subkeys") + let status = Tezos_rpc.Service.get_service ~description:"PVM status at block" diff --git a/tezt/lib_tezos/sc_rollup_client.ml b/tezt/lib_tezos/sc_rollup_client.ml index 4a0db2e6e43c871a74e3fb12b7a1c12e33bf9bef..60e0c036630dcd179363548b7ee456120cf31b51 100644 --- a/tezt/lib_tezos/sc_rollup_client.ml +++ b/tezt/lib_tezos/sc_rollup_client.ml @@ -2,6 +2,7 @@ (* *) (* Open Source License *) (* Copyright (c) 2021 Nomadic Labs *) +(* Copyright (c) 2023 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -237,9 +238,53 @@ let rpc_get_rich ?hooks sc_client path parameters = @@ List.map (fun (k, v) -> Format.asprintf "%s=%s" k v) parameters in let uri = Client.string_of_path path ^ parameters in - let runnable = spawn_command ?hooks sc_client ["rpc"; "get"; uri] in - let* output = Process.check_and_read_stdout runnable.value in - return (JSON.parse ~origin:(Client.string_of_path path ^ " response") output) + spawn_command ?hooks sc_client ["rpc"; "get"; uri] + |> Runnable.map @@ fun output -> + JSON.parse ~origin:(Client.string_of_path path ^ " response") output + +type 'output_type durable_state_operation = + | Value : string option durable_state_operation + | Length : int64 option durable_state_operation + | Subkeys : string list durable_state_operation + +let string_of_durable_state_operation (type a) (x : a durable_state_operation) = + match x with Value -> "value" | Length -> "length" | Subkeys -> "subkeys" + +let inspect_durable_state_value : + type a. + ?hooks:Process.hooks -> + ?block:string -> + t -> + pvm_kind:string -> + operation:a durable_state_operation -> + key:string -> + a Runnable.process = + fun ?hooks ?(block = "head") sc_client ~pvm_kind ~operation ~key -> + let op = string_of_durable_state_operation operation in + let rpc_req () = + rpc_get_rich + ?hooks + sc_client + ["global"; "block"; block; "durable"; pvm_kind; op] + [("key", key)] + in + match operation with + | Value -> rpc_req () |> Runnable.map (fun json -> JSON.as_string_opt json) + | Length -> rpc_req () |> Runnable.map (fun json -> JSON.as_int64_opt json) + | Subkeys -> + rpc_req () + |> Runnable.map (fun json -> List.map JSON.as_string (JSON.as_list json)) + +(* match expected with + | Expected_success -> ( + let*! json = rpc_req () in + match operation with + | Value -> return (JSON.as_string json : a) + | Length -> return (JSON.as_int64 json : a) + | Subkeys -> return (List.map JSON.as_string (JSON.as_list json))) + | Expected_error msg -> + let*? process = rpc_req () in + Process.check_error ~msg process *) let ticks ?hooks ?(block = "head") sc_client = let res = rpc_get ?hooks sc_client ["global"; "block"; block; "ticks"] in diff --git a/tezt/lib_tezos/sc_rollup_client.mli b/tezt/lib_tezos/sc_rollup_client.mli index 31ec549fe8d99ba640a3b4f4a628e87a99d3f60c..c58d67a5e00fb9d2c1ac1cea9c199dc2a09299a5 100644 --- a/tezt/lib_tezos/sc_rollup_client.mli +++ b/tezt/lib_tezos/sc_rollup_client.mli @@ -2,6 +2,7 @@ (* *) (* Open Source License *) (* Copyright (c) 2021 Nomadic Labs *) +(* Copyright (c) 2023 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -82,7 +83,7 @@ val rpc_get_rich : t -> Client.path -> (string * string) list -> - JSON.t Lwt.t + JSON.t Runnable.process (** [total_ticks ?block client] gets the total number of ticks for the PVM. *) val total_ticks : @@ -111,6 +112,22 @@ val state_value : key:string -> bytes Runnable.process +type 'output_type durable_state_operation = + | Value : string option durable_state_operation + | Length : int64 option durable_state_operation + | Subkeys : string list durable_state_operation + +(** [inspect_durable_state_value ?block client key] gets the corresponding durable PVM state value + mapped to [key] for the [block] (default ["head"]). *) +val inspect_durable_state_value : + ?hooks:Process.hooks -> + ?block:string -> + t -> + pvm_kind:string -> + operation:'a durable_state_operation -> + key:string -> + 'a Runnable.process + (** [status ?block client] gets the corresponding PVM status for the [block] (default ["head"]). *) val status : diff --git a/tezt/tests/expected/sc_rollup.ml/Alpha- arith - RPC API should work and be stable.out b/tezt/tests/expected/sc_rollup.ml/Alpha- arith - RPC API should work and be stable.out index 1b3cd0c7969565346736e9d11bc969f5124f5f72..ae51f620dad67555f2fef97b1343c27db7da86b4 100644 --- a/tezt/tests/expected/sc_rollup.ml/Alpha- arith - RPC API should work and be stable.out +++ b/tezt/tests/expected/sc_rollup.ml/Alpha- arith - RPC API should work and be stable.out @@ -243,6 +243,16 @@ This sequence of operations was run: ./octez-smart-rollup-client-alpha rpc get /global/block/head/num_messages "5" +./octez-smart-rollup-client-alpha rpc get '/global/block/head/durable/wasm_2_0_0/value?key=/readonly/wasm_version' +Error + No service found at this URL + + +./octez-smart-rollup-client-alpha rpc get '/global/block/head/durable/arith/value?key=/readonly/wasm_version' +Error + No service found at this URL + + ./octez-smart-rollup-client-alpha rpc get /global/block/head/status "Waiting for input message" diff --git a/tezt/tests/expected/sc_rollup.ml/Alpha- wasm_2_0_0 - RPC API should work and be stable.out b/tezt/tests/expected/sc_rollup.ml/Alpha- wasm_2_0_0 - RPC API should work and be stable.out index 2634a5b2c83fe254defa4003c54a4b860604052f..29720e48380da546b544402ba3a0f7377c2f3330 100644 --- a/tezt/tests/expected/sc_rollup.ml/Alpha- wasm_2_0_0 - RPC API should work and be stable.out +++ b/tezt/tests/expected/sc_rollup.ml/Alpha- wasm_2_0_0 - RPC API should work and be stable.out @@ -243,6 +243,21 @@ This sequence of operations was run: ./octez-smart-rollup-client-alpha rpc get /global/block/head/num_messages "5" +./octez-smart-rollup-client-alpha rpc get '/global/block/head/durable/wasm_2_0_0/value?key=/kernel/boot.wasm' +"0061736d0100000001280760037f7f7f017f60027f7f017f60057f7f7f7f7f017f60017f0060017f017f60027f7f0060000002610311736d6172745f726f6c6c75705f636f72650a726561645f696e707574000011736d6172745f726f6c6c75705f636f72650c77726974655f6f7574707574000111736d6172745f726f6c6c75705f636f72650b73746f72655f77726974650002030504030405060503010001071402036d656d02000a6b65726e656c5f72756e00060aa401042a01027f41fa002f0100210120002f010021022001200247044041e4004112410041e400410010021a0b0b0800200041c4006b0b5001057f41fe002d0000210341fc002f0100210220002d0000210420002f0100210520011004210620042003460440200041016a200141016b10011a0520052002460440200041076a200610011a0b0b0b1d01017f41dc0141840241901c100021004184022000100541840210030b0b38050041e4000b122f6b65726e656c2f656e762f7265626f6f740041f8000b0200010041fa000b0200020041fc000b0200000041fe000b0101" + +./octez-smart-rollup-client-alpha rpc get '/global/block/head/durable/wasm_2_0_0/value?key=/kernel/boot.wasm2' +null + +./octez-smart-rollup-client-alpha rpc get '/global/block/head/durable/wasm_2_0_0/value?key=/readonly/wasm_version' +"322e302e30" + +./octez-smart-rollup-client-alpha rpc get '/global/block/head/durable/wasm_2_0_0/length?key=/readonly/wasm_version' +"5" + +./octez-smart-rollup-client-alpha rpc get '/global/block/head/durable/wasm_2_0_0/subkeys?key=/readonly/kernel' +[ "boot.wasm", "env" ] + ./octez-smart-rollup-client-alpha rpc get /global/block/head/status "Waiting for input message" diff --git a/tezt/tests/expected/sc_rollup.ml/Mumbai- arith - RPC API should work and be stable.out b/tezt/tests/expected/sc_rollup.ml/Mumbai- arith - RPC API should work and be stable.out index d232a5abf1cf7128b248210ef0263df6a5684fe4..32f483b6f774e4fa5bd25b08e59866c845e85ad7 100644 --- a/tezt/tests/expected/sc_rollup.ml/Mumbai- arith - RPC API should work and be stable.out +++ b/tezt/tests/expected/sc_rollup.ml/Mumbai- arith - RPC API should work and be stable.out @@ -243,6 +243,16 @@ This sequence of operations was run: ./octez-smart-rollup-client-PtMumbai rpc get /global/block/head/num_messages "5" +./octez-smart-rollup-client-PtMumbai rpc get '/global/block/head/durable/wasm_2_0_0/value?key=/readonly/wasm_version' +Error + No service found at this URL + + +./octez-smart-rollup-client-PtMumbai rpc get '/global/block/head/durable/arith/value?key=/readonly/wasm_version' +Error + No service found at this URL + + ./octez-smart-rollup-client-PtMumbai rpc get /global/block/head/status "Waiting for input message" diff --git a/tezt/tests/expected/sc_rollup.ml/Mumbai- wasm_2_0_0 - RPC API should work and be stable.out b/tezt/tests/expected/sc_rollup.ml/Mumbai- wasm_2_0_0 - RPC API should work and be stable.out index 983568b2964999237d9efa766221de8205a6da33..91e75042fca0a7ecc2d4c1673a79a05aca062044 100644 --- a/tezt/tests/expected/sc_rollup.ml/Mumbai- wasm_2_0_0 - RPC API should work and be stable.out +++ b/tezt/tests/expected/sc_rollup.ml/Mumbai- wasm_2_0_0 - RPC API should work and be stable.out @@ -243,6 +243,21 @@ This sequence of operations was run: ./octez-smart-rollup-client-PtMumbai rpc get /global/block/head/num_messages "5" +./octez-smart-rollup-client-PtMumbai rpc get '/global/block/head/durable/wasm_2_0_0/value?key=/kernel/boot.wasm' +"0061736d0100000001280760037f7f7f017f60027f7f017f60057f7f7f7f7f017f60017f0060017f017f60027f7f0060000002610311736d6172745f726f6c6c75705f636f72650a726561645f696e707574000011736d6172745f726f6c6c75705f636f72650c77726974655f6f7574707574000111736d6172745f726f6c6c75705f636f72650b73746f72655f77726974650002030504030405060503010001071402036d656d02000a6b65726e656c5f72756e00060aa401042a01027f41fa002f0100210120002f010021022001200247044041e4004112410041e400410010021a0b0b0800200041c4006b0b5001057f41fe002d0000210341fc002f0100210220002d0000210420002f0100210520011004210620042003460440200041016a200141016b10011a0520052002460440200041076a200610011a0b0b0b1d01017f41dc0141840241901c100021004184022000100541840210030b0b38050041e4000b122f6b65726e656c2f656e762f7265626f6f740041f8000b0200010041fa000b0200020041fc000b0200000041fe000b0101" + +./octez-smart-rollup-client-PtMumbai rpc get '/global/block/head/durable/wasm_2_0_0/value?key=/kernel/boot.wasm2' +null + +./octez-smart-rollup-client-PtMumbai rpc get '/global/block/head/durable/wasm_2_0_0/value?key=/readonly/wasm_version' +"322e302e30" + +./octez-smart-rollup-client-PtMumbai rpc get '/global/block/head/durable/wasm_2_0_0/length?key=/readonly/wasm_version' +"5" + +./octez-smart-rollup-client-PtMumbai rpc get '/global/block/head/durable/wasm_2_0_0/subkeys?key=/readonly/kernel' +[ "boot.wasm", "env" ] + ./octez-smart-rollup-client-PtMumbai rpc get /global/block/head/status "Waiting for input message" diff --git a/tezt/tests/sc_rollup.ml b/tezt/tests/sc_rollup.ml index b6cc0d5ed42d0a79445ceb54ee35c602c1acdac3..713aeda28253edd28cf8985dfab2ac8ecb324980 100644 --- a/tezt/tests/sc_rollup.ml +++ b/tezt/tests/sc_rollup.ml @@ -2,7 +2,7 @@ (* *) (* Open Source License *) (* Copyright (c) 2021-2022 Nomadic Labs *) -(* Copyright (c) 2022 TriliTech *) +(* Copyright (c) 2022-2023 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -3788,6 +3788,7 @@ let test_rpcs ~kind = } @@ fun _protocol sc_rollup_node sc_client sc_rollup node client -> let* () = Sc_rollup_node.run sc_rollup_node [] in + (* Smart rollup address endpoint test *) let*! sc_rollup_address = Sc_rollup_client.rpc_get ~hooks sc_client ["global"; "smart_rollup_address"] in @@ -3801,6 +3802,7 @@ let test_rpcs ~kind = in Check.((List.length hashes = n * batch_size) int) ~error_msg:"Injected %L messages but should have injected %R" ; + (* Head block hash endpoint test *) let level = Node.get_level node in let* _ = Sc_rollup_node.wait_for_level ~timeout:3.0 sc_rollup_node level in let* l1_block_hash = RPC.Client.call client @@ RPC.get_chain_block_hash () in @@ -3840,6 +3842,102 @@ let test_rpcs ~kind = let l2_num_messages = JSON.as_int l2_num_messages in Check.((l2_num_messages = batch_size) int) ~error_msg:"Number of messages of head is %L but should be %R" ; + + (* Durable value storage RPC tests *) + let* () = + match kind with + | "arith" -> + (* Make sure we neither have WASM nor Arith PVM endpoint in arith PVM *) + let*? process = + Sc_rollup_client.inspect_durable_state_value + ~hooks + sc_client + ~pvm_kind:"wasm_2_0_0" + ~operation:Sc_rollup_client.Value + ~key:"/readonly/wasm_version" + in + let* () = + Process.check_error + ~msg:(Base.rex "No service found at this URL") + process + in + + let*? process = + Sc_rollup_client.inspect_durable_state_value + ~hooks + sc_client + ~pvm_kind:"arith" + ~operation:Sc_rollup_client.Value + ~key:"/readonly/wasm_version" + in + Process.check_error + ~msg:(Base.rex "No service found at this URL") + process + | "wasm_2_0_0" -> + let*! wasm_boot_sector = + Sc_rollup_client.inspect_durable_state_value + ~hooks + sc_client + ~pvm_kind:kind + ~operation:Sc_rollup_client.Value + ~key:"/kernel/boot.wasm" + in + Check.( + (wasm_boot_sector = Some Constant.wasm_echo_kernel_boot_sector) + (option string)) + ~error_msg:"Encoded WASM kernel is %L but should be %R" ; + + let*! nonexisting_wasm_boot_sector = + Sc_rollup_client.inspect_durable_state_value + ~hooks + sc_client + ~pvm_kind:kind + ~operation:Sc_rollup_client.Value + ~key:"/kernel/boot.wasm2" + in + Check.((nonexisting_wasm_boot_sector = None) (option string)) + ~error_msg:"Encoded WASM kernel is %L but should be %R" ; + + let*! wasm_version_hex_opt = + Sc_rollup_client.inspect_durable_state_value + ~hooks + sc_client + ~pvm_kind:kind + ~operation:Sc_rollup_client.Value + ~key:"/readonly/wasm_version" + in + let wasm_version = + Option.map + (fun wasm_version_hex -> Hex.to_string (`Hex wasm_version_hex)) + wasm_version_hex_opt + in + Check.((wasm_version = Some "2.0.0") (option string)) + ~error_msg:"Decoded WASM version is %L but should be %R" ; + + let*! wasm_version_len = + Sc_rollup_client.inspect_durable_state_value + ~hooks + sc_client + ~pvm_kind:kind + ~operation:Sc_rollup_client.Length + ~key:"/readonly/wasm_version" + in + Check.((wasm_version_len = Some 5L) (option int64)) + ~error_msg:"WASM version value length is %L but should be %R" ; + + let*! kernel_subkeys = + Sc_rollup_client.inspect_durable_state_value + ~hooks + sc_client + ~pvm_kind:kind + ~operation:Sc_rollup_client.Subkeys + ~key:"/readonly/kernel" + in + Check.((kernel_subkeys = ["boot.wasm"; "env"]) (list string)) + ~error_msg:"The key's subkeys are %L but should be %R" ; + return () + | _ -> failwith "incorrect kind" + in let*! _status = Sc_rollup_client.rpc_get ~hooks