From f5a5a564ad1c14379f18394f93e08ecc93b4730f Mon Sep 17 00:00:00 2001 From: Corneliu Hoffman Date: Mon, 26 Sep 2022 11:20:59 +0100 Subject: [PATCH 1/4] SCORU/WASM: move host function implemented- no test --- src/lib_scoru_wasm/host_funcs.ml | 46 +++++++++++++++++++++++++++++++ src/lib_scoru_wasm/host_funcs.mli | 2 ++ 2 files changed, 48 insertions(+) diff --git a/src/lib_scoru_wasm/host_funcs.ml b/src/lib_scoru_wasm/host_funcs.ml index a4bf310aed92..c2a5e711581c 100644 --- a/src/lib_scoru_wasm/host_funcs.ml +++ b/src/lib_scoru_wasm/host_funcs.ml @@ -348,6 +348,47 @@ let store_copy = to_key_length | _ -> raise Bad_input) +let store_move_name = "tezos_store_move" + +let store_move_type = + let input_types = + Types.[NumType I32Type; NumType I32Type; NumType I32Type; NumType I32Type] + |> Vector.of_list + in + let output_types = Vector.of_list [] in + Types.FuncType (input_types, output_types) + +let store_move = + Host_funcs.Host_func + (fun _input_buffer _output_buffer durable memories inputs -> + let open Lwt.Syntax in + match inputs with + | [ + Values.(Num (I32 from_key_offset)); + Values.(Num (I32 from_key_length)); + Values.(Num (I32 to_key_offset)); + Values.(Num (I32 to_key_length)); + ] -> + let from_key_length = Int32.to_int from_key_length in + let to_key_length = Int32.to_int to_key_length in + if from_key_length > Durable.max_key_length then + raise (Key_too_large from_key_length) ; + if to_key_length > Durable.max_key_length then + raise (Key_too_large to_key_length) ; + let* memory = retrieve_memory memories in + let* from_key = + Memory.load_bytes memory from_key_offset from_key_length + in + let* to_key = Memory.load_bytes memory to_key_offset to_key_length in + let tree = Durable.of_storage_exn durable in + let from_key = Durable.key_of_string_exn from_key in + let to_key = Durable.key_of_string_exn to_key in + let* move_tree = Durable.find_tree_exn tree from_key in + let* tree = Durable.add_tree tree to_key move_tree in + let+ tree = Durable.delete tree from_key in + (Durable.to_storage tree, []) + | _ -> raise Bad_input) + let lookup_opt name = match name with | "read_input" -> @@ -363,6 +404,8 @@ let lookup_opt name = Some (ExternFunc (HostFunc (store_delete_type, store_delete_name))) | "store_copy" -> Some (ExternFunc (HostFunc (store_copy_type, store_copy_name))) + | "store_move" -> + Some (ExternFunc (HostFunc (store_move_type, store_move_name))) | _ -> None let lookup name = @@ -381,6 +424,7 @@ let register_host_funcs registry = (store_list_size_name, store_list_size); (store_delete_name, store_delete); (store_copy_name, store_copy); + (store_move_name, store_move); ] module Internal_for_tests = struct @@ -398,6 +442,8 @@ module Internal_for_tests = struct let store_copy = Func.HostFunc (store_copy_type, store_copy_name) + let store_move = Func.HostFunc (store_move_type, store_move_name) + let store_list_size = Func.HostFunc (store_list_size_type, store_list_size_name) end diff --git a/src/lib_scoru_wasm/host_funcs.mli b/src/lib_scoru_wasm/host_funcs.mli index b5eec35e9679..5f0cd5031bc9 100644 --- a/src/lib_scoru_wasm/host_funcs.mli +++ b/src/lib_scoru_wasm/host_funcs.mli @@ -109,5 +109,7 @@ module Internal_for_tests : sig val store_copy : Tezos_webassembly_interpreter.Instance.func_inst + val store_move : Tezos_webassembly_interpreter.Instance.func_inst + val store_list_size : Tezos_webassembly_interpreter.Instance.func_inst end -- GitLab From aa49f240428561d2541288caede80be051693863 Mon Sep 17 00:00:00 2001 From: Corneliu Hoffman Date: Mon, 26 Sep 2022 12:48:29 +0100 Subject: [PATCH 2/4] SCORU/WASM: added test --- src/lib_scoru_wasm/host_funcs.ml | 65 ++++++++------ .../test/test_durable_storage.ml | 90 +++++++++++++++++++ 2 files changed, 126 insertions(+), 29 deletions(-) diff --git a/src/lib_scoru_wasm/host_funcs.ml b/src/lib_scoru_wasm/host_funcs.ml index c2a5e711581c..dd6b5f64206d 100644 --- a/src/lib_scoru_wasm/host_funcs.ml +++ b/src/lib_scoru_wasm/host_funcs.ml @@ -258,21 +258,23 @@ let store_delete_type = let output_types = Vector.of_list [] in Types.FuncType (input_types, output_types) +let store_delete_aux durable memories key_offset key_length = + let open Lwt.Syntax in + let key_length = Int32.to_int key_length in + if key_length > Durable.max_key_length then raise (Key_too_large key_length) ; + let* memory = retrieve_memory memories in + let* key = Memory.load_bytes memory key_offset key_length in + let tree = Durable.of_storage_exn durable in + let key = Durable.key_of_string_exn key in + let+ tree = Durable.delete tree key in + (Durable.to_storage tree, []) + let store_delete = Host_funcs.Host_func (fun _input_buffer _output_buffer durable memories inputs -> - let open Lwt.Syntax in match inputs with | [Values.(Num (I32 key_offset)); Values.(Num (I32 key_length))] -> - let key_length = Int32.to_int key_length in - if key_length > Durable.max_key_length then - raise (Key_too_large key_length) ; - let* memory = retrieve_memory memories in - let* key = Memory.load_bytes memory key_offset key_length in - let tree = Durable.of_storage_exn durable in - let key = Durable.key_of_string_exn key in - let+ tree = Durable.delete tree key in - (Durable.to_storage tree, []) + store_delete_aux durable memories key_offset key_length | _ -> raise Bad_input) let store_list_size_name = "tezos_store_list_size" @@ -358,10 +360,26 @@ let store_move_type = let output_types = Vector.of_list [] in Types.FuncType (input_types, output_types) +let store_move_aux durable memories from_key_offset from_key_length + to_key_offset to_key_length = + let open Lwt.Syntax in + let* durable, _ = + store_copy_aux + durable + memories + from_key_offset + from_key_length + to_key_offset + to_key_length + in + let+ durable, _ = + store_delete_aux durable memories from_key_offset from_key_length + in + (durable, []) + let store_move = Host_funcs.Host_func (fun _input_buffer _output_buffer durable memories inputs -> - let open Lwt.Syntax in match inputs with | [ Values.(Num (I32 from_key_offset)); @@ -369,24 +387,13 @@ let store_move = Values.(Num (I32 to_key_offset)); Values.(Num (I32 to_key_length)); ] -> - let from_key_length = Int32.to_int from_key_length in - let to_key_length = Int32.to_int to_key_length in - if from_key_length > Durable.max_key_length then - raise (Key_too_large from_key_length) ; - if to_key_length > Durable.max_key_length then - raise (Key_too_large to_key_length) ; - let* memory = retrieve_memory memories in - let* from_key = - Memory.load_bytes memory from_key_offset from_key_length - in - let* to_key = Memory.load_bytes memory to_key_offset to_key_length in - let tree = Durable.of_storage_exn durable in - let from_key = Durable.key_of_string_exn from_key in - let to_key = Durable.key_of_string_exn to_key in - let* move_tree = Durable.find_tree_exn tree from_key in - let* tree = Durable.add_tree tree to_key move_tree in - let+ tree = Durable.delete tree from_key in - (Durable.to_storage tree, []) + store_move_aux + durable + memories + from_key_offset + from_key_length + to_key_offset + to_key_length | _ -> raise Bad_input) let lookup_opt name = diff --git a/src/lib_scoru_wasm/test/test_durable_storage.ml b/src/lib_scoru_wasm/test/test_durable_storage.ml index b0abc4f1b14e..78b32ffe6cf4 100644 --- a/src/lib_scoru_wasm/test/test_durable_storage.ml +++ b/src/lib_scoru_wasm/test/test_durable_storage.ml @@ -388,6 +388,95 @@ let test_store_copy () = let* () = equal_chunks old_value_from_key new_value_from_key in Lwt.return_ok () +let test_store_move () = + let open Lwt_syntax in + let* tree = empty_tree () in + let value () = Chunked_byte_vector.of_string "a very long value" in + (* + Store the following tree: + /durable/a/short/path/_ = "..." + /durable/a/short/path/one/_ = "..." + /durable/a/long/path/_ = "..." + + We expect that deleting "/a/short/path" is leaves only "/durable/a/long/path". + *) + let _key = "/a/short/path" in + let key_steps = ["a"; "short"; "path"] in + let* tree = + Tree_encoding_runner.encode + (Tree_encoding.scope + ("durable" :: List.append key_steps ["_"]) + Tree_encoding.chunked_byte_vector) + (value ()) + tree + in + let* tree = + Tree_encoding_runner.encode + (Tree_encoding.scope + ("durable" :: List.append key_steps ["one"; "_"]) + Tree_encoding.chunked_byte_vector) + (value ()) + tree + in + let* tree = + Tree_encoding_runner.encode + (Tree_encoding.scope + ["durable"; "a"; "long"; "path"; "_"] + Tree_encoding.chunked_byte_vector) + (value ()) + tree + in + let* durable = wrap_as_durable_storage tree in + let module_inst = Tezos_webassembly_interpreter.Instance.empty_module_inst in + let memory = Memory.alloc (MemoryType Types.{min = 20l; max = Some 3600l}) in + let from_key = "/a/short/path/one" in + let to_key = "/a/long/path/one" in + let durable_st = Durable.of_storage_exn durable in + + let* from_tree = + Durable.find_value_exn durable_st @@ Durable.key_of_string_exn from_key + in + let from_offset = 20l in + let to_offset = 40l in + let _ = Memory.store_bytes memory from_offset from_key in + let _ = Memory.store_bytes memory to_offset to_key in + let memories = Lazy_vector.Int32Vector.cons memory module_inst.memories in + let module_inst = {module_inst with memories} in + let host_funcs_registry = Tezos_webassembly_interpreter.Host_funcs.empty () in + Host_funcs.register_host_funcs host_funcs_registry ; + let module_reg = Instance.ModuleMap.create () in + let module_key = Instance.Module_key "test" in + Instance.update_module_ref module_reg module_key module_inst ; + let values = + Values. + [ + Num (I32 from_offset); + Num (I32 (Int32.of_int @@ String.length from_key)); + Num (I32 to_offset); + Num (I32 (Int32.of_int @@ String.length to_key)); + ] + in + let* durable, result = + Eval.invoke + ~module_reg + ~caller:module_key + ~durable + host_funcs_registry + Host_funcs.Internal_for_tests.store_move + values + in + assert (result = []) ; + let durable = Durable.of_storage_exn durable in + let* empty_from_tree_opt = + Durable.find_value durable @@ Durable.key_of_string_exn from_key + in + let* to_tree = + Durable.find_value_exn durable @@ Durable.key_of_string_exn to_key + in + assert (empty_from_tree_opt = None) ; + let* () = equal_chunks from_tree to_tree in + Lwt.return_ok () + (* Test invalid key encodings are rejected. *) let test_durable_invalid_keys () = let open Lwt.Syntax in @@ -421,6 +510,7 @@ let tests = tztest "store_list_size counts subtrees" `Quick test_store_list_size; tztest "store_delete removes subtree" `Quick test_store_delete; tztest "store_copy" `Quick test_store_copy; + tztest "store_move" `Quick test_store_move; tztest "Durable: find value" `Quick test_durable_find_value; tztest "Durable: count subtrees" `Quick test_durable_count_subtrees; tztest "Durable: invalid keys" `Quick test_durable_invalid_keys; -- GitLab From 334dba2097ec901df8b34eb1f8f52068b868d2c4 Mon Sep 17 00:00:00 2001 From: Corneliu Hoffman Date: Wed, 28 Sep 2022 17:24:27 +0100 Subject: [PATCH 3/4] SCORU/WASM: moved the move_tree function to Durable --- src/lib_scoru_wasm/durable.ml | 5 +++++ src/lib_scoru_wasm/durable.mli | 6 +++++- src/lib_scoru_wasm/host_funcs.ml | 18 ++++++++++++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/lib_scoru_wasm/durable.ml b/src/lib_scoru_wasm/durable.ml index d429f7f12312..04ff4b27d0c8 100644 --- a/src/lib_scoru_wasm/durable.ml +++ b/src/lib_scoru_wasm/durable.ml @@ -116,6 +116,11 @@ let count_subtrees tree key = let delete tree key = T.remove tree key +let move_tree_exn tree from_key to_key = + let open Lwt.Syntax in + let* tree = copy_tree_exn tree from_key to_key in + delete tree from_key + let hash_exn tree key = let open Lwt.Syntax in let+ opt = T.find_tree tree (to_value_key key) in diff --git a/src/lib_scoru_wasm/durable.mli b/src/lib_scoru_wasm/durable.mli index c746aac29948..3d3a4d049453 100644 --- a/src/lib_scoru_wasm/durable.mli +++ b/src/lib_scoru_wasm/durable.mli @@ -68,9 +68,13 @@ val find_value : t -> key -> Lazy_containers.Chunked_byte_vector.t option Lwt.t val find_value_exn : t -> key -> Lazy_containers.Chunked_byte_vector.t Lwt.t (** [copy_tree_exn tree from_key to_key] produces a new tree in which a copy of - the entire subtree at from_key is copied at to_key.*) + the entire subtree at from_key is copied to to_key.*) val copy_tree_exn : t -> key -> key -> t Lwt.t +(** [move_tree_exn tree from_key to_key] produces a new tree in which + the entire subtree at from_key is moved to to_key.*) +val move_tree_exn : t -> key -> key -> t 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/host_funcs.ml b/src/lib_scoru_wasm/host_funcs.ml index dd6b5f64206d..e85d91cd97e6 100644 --- a/src/lib_scoru_wasm/host_funcs.ml +++ b/src/lib_scoru_wasm/host_funcs.ml @@ -372,10 +372,20 @@ let store_move_aux durable memories from_key_offset from_key_length to_key_offset to_key_length in - let+ durable, _ = - store_delete_aux durable memories from_key_offset from_key_length - in - (durable, []) + let from_key_length = Int32.to_int from_key_length in + let to_key_length = Int32.to_int to_key_length in + if from_key_length > Durable.max_key_length then + raise (Key_too_large from_key_length) ; + if to_key_length > Durable.max_key_length then + raise (Key_too_large to_key_length) ; + let* memory = retrieve_memory memories in + let* from_key = Memory.load_bytes memory from_key_offset from_key_length in + let* to_key = Memory.load_bytes memory to_key_offset to_key_length in + let tree = Durable.of_storage_exn durable in + let from_key = Durable.key_of_string_exn from_key in + let to_key = Durable.key_of_string_exn to_key in + let+ tree = Durable.movep_tree_exn tree from_key to_key in + (Durable.to_storage tree, []) let store_move = Host_funcs.Host_func -- GitLab From fc754b3e0e5f8bfb22bdbd576de28a827e7f6d85 Mon Sep 17 00:00:00 2001 From: Corneliu Hoffman Date: Wed, 28 Sep 2022 17:39:21 +0100 Subject: [PATCH 4/4] SCORU/WASM: improved the test --- src/lib_scoru_wasm/host_funcs.ml | 11 +-- .../test/test_durable_storage.ml | 76 +++++++------------ 2 files changed, 30 insertions(+), 57 deletions(-) diff --git a/src/lib_scoru_wasm/host_funcs.ml b/src/lib_scoru_wasm/host_funcs.ml index e85d91cd97e6..be112a384ec6 100644 --- a/src/lib_scoru_wasm/host_funcs.ml +++ b/src/lib_scoru_wasm/host_funcs.ml @@ -363,15 +363,6 @@ let store_move_type = let store_move_aux durable memories from_key_offset from_key_length to_key_offset to_key_length = let open Lwt.Syntax in - let* durable, _ = - store_copy_aux - durable - memories - from_key_offset - from_key_length - to_key_offset - to_key_length - in let from_key_length = Int32.to_int from_key_length in let to_key_length = Int32.to_int to_key_length in if from_key_length > Durable.max_key_length then @@ -384,7 +375,7 @@ let store_move_aux durable memories from_key_offset from_key_length let tree = Durable.of_storage_exn durable in let from_key = Durable.key_of_string_exn from_key in let to_key = Durable.key_of_string_exn to_key in - let+ tree = Durable.movep_tree_exn tree from_key to_key in + let+ tree = Durable.move_tree_exn tree from_key to_key in (Durable.to_storage tree, []) let store_move = diff --git a/src/lib_scoru_wasm/test/test_durable_storage.ml b/src/lib_scoru_wasm/test/test_durable_storage.ml index 78b32ffe6cf4..b641045d7e16 100644 --- a/src/lib_scoru_wasm/test/test_durable_storage.ml +++ b/src/lib_scoru_wasm/test/test_durable_storage.ml @@ -390,70 +390,48 @@ let test_store_copy () = let test_store_move () = let open Lwt_syntax in - let* tree = empty_tree () in - let value () = Chunked_byte_vector.of_string "a very long value" in (* Store the following tree: /durable/a/short/path/_ = "..." - /durable/a/short/path/one/_ = "..." /durable/a/long/path/_ = "..." + /durable/a/long/path/one/_ = "..." - We expect that deleting "/a/short/path" is leaves only "/durable/a/long/path". + We expect that moving "/a/short/path" to "a/long/path" is leaves only + "/durable/a/long/path". *) - let _key = "/a/short/path" in - let key_steps = ["a"; "short"; "path"] in - let* tree = - Tree_encoding_runner.encode - (Tree_encoding.scope - ("durable" :: List.append key_steps ["_"]) - Tree_encoding.chunked_byte_vector) - (value ()) - tree - in - let* tree = - Tree_encoding_runner.encode - (Tree_encoding.scope - ("durable" :: List.append key_steps ["one"; "_"]) - Tree_encoding.chunked_byte_vector) - (value ()) - tree + let* durable = + make_durable + [ + ("a/short/path", "a very long value"); + ("a/long/path", "a very long value"); + ("a/long/path/one", "a very long value"); + ] in - let* tree = - Tree_encoding_runner.encode - (Tree_encoding.scope - ["durable"; "a"; "long"; "path"; "_"] - Tree_encoding.chunked_byte_vector) - (value ()) - tree - in - let* durable = wrap_as_durable_storage tree in - let module_inst = Tezos_webassembly_interpreter.Instance.empty_module_inst in - let memory = Memory.alloc (MemoryType Types.{min = 20l; max = Some 3600l}) in - let from_key = "/a/short/path/one" in - let to_key = "/a/long/path/one" in + let from_key = "/a/short/path" in + let to_key = "/a/long/path" in + let bad_key = "/a/long/path/one" in let durable_st = Durable.of_storage_exn durable in let* from_tree = Durable.find_value_exn durable_st @@ Durable.key_of_string_exn from_key in - let from_offset = 20l in - let to_offset = 40l in - let _ = Memory.store_bytes memory from_offset from_key in - let _ = Memory.store_bytes memory to_offset to_key in - let memories = Lazy_vector.Int32Vector.cons memory module_inst.memories in - let module_inst = {module_inst with memories} in - let host_funcs_registry = Tezos_webassembly_interpreter.Host_funcs.empty () in - Host_funcs.register_host_funcs host_funcs_registry ; - let module_reg = Instance.ModuleMap.create () in - let module_key = Instance.Module_key "test" in - Instance.update_module_ref module_reg module_key module_inst ; + let src = 20l in + let module_reg, module_key, host_funcs_registry = + make_module_inst [from_key; to_key; bad_key] src + in + + let from_offset = src in + let from_length = Int32.of_int @@ String.length from_key in + Printf.printf "fl= %li" from_length ; + let to_offset = Int32.(add from_offset from_length) in + let to_length = Int32.of_int @@ String.length to_key in let values = Values. [ Num (I32 from_offset); - Num (I32 (Int32.of_int @@ String.length from_key)); + Num (I32 from_length); Num (I32 to_offset); - Num (I32 (Int32.of_int @@ String.length to_key)); + Num (I32 to_length); ] in let* durable, result = @@ -473,7 +451,11 @@ let test_store_move () = let* to_tree = Durable.find_value_exn durable @@ Durable.key_of_string_exn to_key in + let* empty_bad_key_tree_opt = + Durable.find_value durable @@ Durable.key_of_string_exn bad_key + in assert (empty_from_tree_opt = None) ; + assert (empty_bad_key_tree_opt = None) ; let* () = equal_chunks from_tree to_tree in Lwt.return_ok () -- GitLab