From 98ec7923d5a5fe37a5c1d6a85380200daa722128 Mon Sep 17 00:00:00 2001 From: Pierrick Couderc Date: Mon, 2 Jan 2023 15:35:51 +0100 Subject: [PATCH 1/4] WASM: tickify host functions --- src/lib_scoru_wasm/host_funcs.ml | 28 +++++++------ .../test/helpers/ast_generators.ml | 5 ++- .../test/helpers/ast_printer.ml | 6 ++- src/lib_scoru_wasm/wasm_encoding.ml | 12 +++--- src/lib_webassembly/exec/eval.ml | 40 +++++++++++++++---- src/lib_webassembly/exec/eval.mli | 6 ++- src/lib_webassembly/host/spectest.ml | 2 +- src/lib_webassembly/runtime/host_funcs.ml | 4 +- src/lib_webassembly/runtime/host_funcs.mli | 4 +- 9 files changed, 75 insertions(+), 32 deletions(-) diff --git a/src/lib_scoru_wasm/host_funcs.ml b/src/lib_scoru_wasm/host_funcs.ml index d601e99a6676..da11f0899ff7 100644 --- a/src/lib_scoru_wasm/host_funcs.ml +++ b/src/lib_scoru_wasm/host_funcs.ml @@ -595,6 +595,8 @@ module Aux = struct include Make (Memory_access_interpreter) end +let default_ticks = Z.zero + let value i = Values.(Num (I32 i)) let read_input_type = @@ -620,7 +622,7 @@ let read_input = let* x = Aux.read_input ~input_buffer ~memory ~info_addr ~dst ~max_bytes in - Lwt.return (durable, [value x]) + Lwt.return (durable, [value x], default_ticks) | _ -> raise Bad_input) let write_output_name = "tezos_write_output" @@ -640,7 +642,7 @@ let write_output = | [Values.(Num (I32 src)); Values.(Num (I32 num_bytes))] -> let* memory = retrieve_memory memories in let* x = Aux.write_output ~output_buffer ~memory ~src ~num_bytes in - Lwt.return (durable, [value x]) + Lwt.return (durable, [value x], default_ticks) | _ -> raise Bad_input) let write_debug_name = "tezos_write_debug" @@ -666,7 +668,7 @@ let write_debug ~implem = match inputs with | [Values.(Num (I32 src)); Values.(Num (I32 num_bytes))] -> let+ () = run ~memory ~src ~num_bytes in - (durable, []) + (durable, [], default_ticks) | _ -> raise Bad_input) let store_has_name = "tezos_store_has" @@ -692,7 +694,7 @@ let store_has = ~key_offset ~key_length in - (durable, [value r]) + (durable, [value r], default_ticks) | _ -> raise Bad_input) let store_delete_name = "tezos_store_delete" @@ -718,7 +720,7 @@ let store_delete = ~key_offset ~key_length in - (Durable.to_storage durable, [value code]) + (Durable.to_storage durable, [value code], default_ticks) | _ -> raise Bad_input) let store_value_size_name = "tezos_store_value_size" @@ -746,7 +748,7 @@ let store_value_size = ~key_offset ~key_length in - (durable, [value res]) + (durable, [value res], default_ticks) | _ -> raise Bad_input) let store_list_size_name = "tezos_store_list_size" @@ -773,7 +775,9 @@ let store_list_size = ~key_offset ~key_length in - (Durable.to_storage durable, [Values.(Num (I64 result))]) + ( Durable.to_storage durable, + [Values.(Num (I64 result))], + default_ticks ) | _ -> raise Bad_input) let store_get_nth_key_name = "tezos_store_get_nth_key_list" @@ -817,7 +821,7 @@ let store_get_nth_key = ~dst ~max_size in - (durable, [value result]) + (durable, [value result], default_ticks) | _ -> raise Bad_input) let store_copy_name = "tezos_store_copy" @@ -853,7 +857,7 @@ let store_copy = ~to_key_offset ~to_key_length in - (Durable.to_storage durable, [value code]) + (Durable.to_storage durable, [value code], default_ticks) | _ -> raise Bad_input) let store_move_name = "tezos_store_move" @@ -889,7 +893,7 @@ let store_move = ~to_key_offset ~to_key_length in - (Durable.to_storage durable, [value code]) + (Durable.to_storage durable, [value code], default_ticks) | _ -> raise Bad_input) let store_read_name = "tezos_store_read" @@ -932,7 +936,7 @@ let store_read = ~dest ~max_bytes in - (durable, [value len]) + (durable, [value len], default_ticks) | _ -> raise Bad_input) let reveal_preimage_name = "tezos_reveal_preimage" @@ -1025,7 +1029,7 @@ let store_write = ~src ~num_bytes in - (Durable.to_storage durable, [value code]) + (Durable.to_storage durable, [value code], default_ticks) | _ -> raise Bad_input) let lookup_opt name = diff --git a/src/lib_scoru_wasm/test/helpers/ast_generators.ml b/src/lib_scoru_wasm/test/helpers/ast_generators.ml index 3db6d50b49ef..41b079630a07 100644 --- a/src/lib_scoru_wasm/test/helpers/ast_generators.ml +++ b/src/lib_scoru_wasm/test/helpers/ast_generators.ml @@ -788,8 +788,9 @@ let inv_reveal_tick ~module_reg = let inv_stop_gen ~module_reg = let* vs = small_vector_gen value_gen in let* es = small_vector_gen (admin_instr_gen ~module_reg) in - let+ fresh_frame = option (ongoing_frame_stack_gen ~module_reg) in - Eval.Inv_stop {code = (vs, es); fresh_frame} + let* fresh_frame = option (ongoing_frame_stack_gen ~module_reg) in + let+ remaining_ticks = map Z.of_int small_nat in + Eval.Inv_stop {code = (vs, es); fresh_frame; remaining_ticks} let invoke_step_gen ~module_reg = oneof diff --git a/src/lib_scoru_wasm/test/helpers/ast_printer.ml b/src/lib_scoru_wasm/test/helpers/ast_printer.ml index 7a8491f60589..a06a02dc2986 100644 --- a/src/lib_scoru_wasm/test/helpers/ast_printer.ml +++ b/src/lib_scoru_wasm/test/helpers/ast_printer.ml @@ -531,18 +531,20 @@ let pp_invoke_step_kont out = function reveal base_destination max_bytes - | Inv_stop {code = vs, es; fresh_frame} -> + | Inv_stop {code = vs, es; fresh_frame; remaining_ticks} -> Format.fprintf out "%@[Inv_stop {values = %a;@;\ instructions = %a;@;\ - fresh_frame = %a}@]" + fresh_frame = %a;@;\ + remaining_ticks = %s}@]" (pp_vector Values.pp_value) vs (pp_vector pp_admin_instr) es (pp_opt pp_frame_stack) fresh_frame + (Z.to_string remaining_ticks) let pp_label_step_kont out = function | Eval.LS_Start label_kont -> diff --git a/src/lib_scoru_wasm/wasm_encoding.ml b/src/lib_scoru_wasm/wasm_encoding.ml index d862bec135ac..b59e81951909 100644 --- a/src/lib_scoru_wasm/wasm_encoding.ml +++ b/src/lib_scoru_wasm/wasm_encoding.ml @@ -1091,16 +1091,18 @@ let invoke_step_kont_encoding = Inv_reveal_tick {reveal; base_destination; max_bytes; code = (vs, es)}); case "Inv_stop" - (tup3 + (tup4 ~flatten:true (scope ["values"] values_encoding) (lazy_vector_encoding "instructions" admin_instr_encoding) - (scope ["fresh_frame"] (option ongoing_frame_stack_encoding))) + (scope ["fresh_frame"] (option ongoing_frame_stack_encoding)) + (value ["remaining_ticks"] Data_encoding.z)) (function - | Eval.Inv_stop {code = vs, es; fresh_frame} -> - Some (vs, es, fresh_frame) + | Eval.Inv_stop {code = vs, es; fresh_frame; remaining_ticks} -> + Some (vs, es, fresh_frame, remaining_ticks) | _ -> None) - (fun (vs, es, fresh_frame) -> Inv_stop {code = (vs, es); fresh_frame}); + (fun (vs, es, fresh_frame, remaining_ticks) -> + Inv_stop {code = (vs, es); fresh_frame; remaining_ticks}); ] let label_step_kont_encoding = diff --git a/src/lib_webassembly/exec/eval.ml b/src/lib_webassembly/exec/eval.ml index fdc1cf5d8209..d9b90865113e 100644 --- a/src/lib_webassembly/exec/eval.ml +++ b/src/lib_webassembly/exec/eval.ml @@ -363,7 +363,11 @@ type invoke_step_kont = max_bytes : int32; code : code; } - | Inv_stop of {code : code; fresh_frame : ongoing frame_stack option} + | Inv_stop of { + code : code; + fresh_frame : ongoing frame_stack option; + remaining_ticks : Z.t; + } let vector_pop_map v f at = if 1l <= Vector.num_elements v then @@ -506,8 +510,12 @@ let vmtake n vs = match n with Some n -> Vector.split vs n |> fst | None -> vs let invoke_step ~init ?(durable = Durable_storage.empty) (module_reg : module_reg) c buffers frame at = function - | Inv_stop _ -> + | Inv_stop {remaining_ticks; _} when remaining_ticks <= Z.zero -> raise (Evaluation_step_error (Invoke_step "Inv_stop cannot reduce")) + | Inv_stop stop -> + Lwt.return + ( durable, + Inv_stop {stop with remaining_ticks = Z.pred stop.remaining_ticks} ) | Inv_start {func; code = vs, es} -> ( let (FuncType (ins, out)) = func_type_of func in let n1, n2 = @@ -541,7 +549,7 @@ let invoke_step ~init ?(durable = Durable_storage.empty) in match host_func with | Host_func f -> - let+ durable, res = + let+ durable, res, remaining_ticks = f buffers.input buffers.output @@ -550,7 +558,9 @@ let invoke_step ~init ?(durable = Durable_storage.empty) args in let vs' = Vector.prepend_list res vs' in - (durable, Inv_stop {code = (vs', es); fresh_frame = None}) + ( durable, + Inv_stop + {code = (vs', es); fresh_frame = None; remaining_ticks} ) | Reveal_func f -> ( let* result = f available_memories args in match result with @@ -569,7 +579,12 @@ let invoke_step ~init ?(durable = Durable_storage.empty) let vs' = Vector.prepend_list [err_code] vs' in Lwt.return ( durable, - Inv_stop {code = (vs', es); fresh_frame = None} ))) + Inv_stop + { + code = (vs', es); + fresh_frame = None; + remaining_ticks = Z.zero; + } ))) (function Crash (_, msg) -> Crash.error at msg | exn -> raise exn)) | Inv_prepare_locals { @@ -648,6 +663,7 @@ let invoke_step ~init ?(durable = Durable_storage.empty) (From_block (f.it.body, 0l) @@ f.at) ); }; }; + remaining_ticks = Z.zero; } ) | Inv_reveal_tick _ -> (* This is a reveal tick, not an evaluation tick. The PVM should @@ -1451,7 +1467,9 @@ let label_step : | LS_Consolidate_top (label', tick, es', stack) -> let+ tick = concat_step tick in (durable, LS_Consolidate_top (label', tick, es', stack)) - | LS_Craft_frame (Label_stack (label, stack), Inv_stop {code; fresh_frame}) -> + | LS_Craft_frame + (Label_stack (label, stack), Inv_stop {code; fresh_frame; remaining_ticks}) + when remaining_ticks <= Z.zero -> let label_kont = Label_stack ({label with label_code = code}, stack) in Lwt.return ( durable, @@ -1589,6 +1607,8 @@ let reveal_step reveal module_reg payload = in let vs, es = inv.code in let vs = Vector.cons (Num (I32 bytes_count)) vs in + (* This value should be benchmarked *) + let ticks_to_consume = Z.zero in { config with step_kont = @@ -1596,7 +1616,13 @@ let reveal_step reveal module_reg payload = ( frame, top, LS_Craft_frame - (label, Inv_stop {code = (vs, es); fresh_frame = None}) ); + ( label, + Inv_stop + { + code = (vs, es); + fresh_frame = None; + remaining_ticks = ticks_to_consume; + } ) ); } | _ -> raise (Reveal_error Reveal_step) diff --git a/src/lib_webassembly/exec/eval.mli b/src/lib_webassembly/exec/eval.mli index 4340024a3821..743fb626358b 100644 --- a/src/lib_webassembly/exec/eval.mli +++ b/src/lib_webassembly/exec/eval.mli @@ -123,7 +123,11 @@ type invoke_step_kont = max_bytes : int32; code : code; } - | Inv_stop of {code : code; fresh_frame : ongoing frame_stack option} + | Inv_stop of { + code : code; + fresh_frame : ongoing frame_stack option; + remaining_ticks : Z.t; + } type label_step_kont = | LS_Start : ongoing label_kont -> label_step_kont diff --git a/src/lib_webassembly/host/spectest.ml b/src/lib_webassembly/host/spectest.ml index 91cd6586996e..3ef148343028 100644 --- a/src/lib_webassembly/host/spectest.ml +++ b/src/lib_webassembly/host/spectest.ml @@ -37,7 +37,7 @@ let print = (fun _i _o d _m vs -> List.iter print_value vs ; flush_all () ; - Lwt.return (d, [])) + Lwt.return (d, [], Z.zero)) let register_host_funcs registry = Host_funcs.register ~global_name:"spectest_print" print registry ; diff --git a/src/lib_webassembly/runtime/host_funcs.ml b/src/lib_webassembly/runtime/host_funcs.ml index 1275513ffe3e..a0ead3daaa3d 100644 --- a/src/lib_webassembly/runtime/host_funcs.ml +++ b/src/lib_webassembly/runtime/host_funcs.ml @@ -6,6 +6,8 @@ type reveal = Reveal_raw_data of string | Reveal_metadata type reveal_destination = {base : int32; max_bytes : int32} +type ticks = Z.t + type reveal_func = available_memories -> Values.value list -> @@ -18,7 +20,7 @@ type host_func = Durable_storage.t -> available_memories -> Values.value list -> - (Durable_storage.t * Values.value list) Lwt.t) + (Durable_storage.t * Values.value list * ticks) Lwt.t) | Reveal_func of reveal_func module Registry = Map.Make (String) diff --git a/src/lib_webassembly/runtime/host_funcs.mli b/src/lib_webassembly/runtime/host_funcs.mli index 296be6205998..77cf7fe125a6 100644 --- a/src/lib_webassembly/runtime/host_funcs.mli +++ b/src/lib_webassembly/runtime/host_funcs.mli @@ -7,6 +7,8 @@ type reveal_destination = {base : int32; max_bytes : int32} type reveal = Reveal_raw_data of string | Reveal_metadata +type ticks = Z.t + type reveal_func = available_memories -> Values.value list -> @@ -20,7 +22,7 @@ type host_func = Durable_storage.t -> available_memories -> Values.value list -> - (Durable_storage.t * Values.value list) Lwt.t) + (Durable_storage.t * Values.value list * ticks) Lwt.t) | Reveal_func of reveal_func (** A (mutable) host function registry *) -- GitLab From ad46943576981a1e825f0d5c8e6979086dc6de39 Mon Sep 17 00:00:00 2001 From: Pierrick Couderc Date: Wed, 4 Jan 2023 10:07:35 +0100 Subject: [PATCH 2/4] WASM/Test: move `eval_to_result` from repl in the test helpers --- src/bin_wasm_debugger/commands.ml | 46 +--------------- src/lib_scoru_wasm/test/helpers/wasm_utils.ml | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 45 deletions(-) diff --git a/src/bin_wasm_debugger/commands.ml b/src/bin_wasm_debugger/commands.ml index 4aa258feeddc..e9acf941bf62 100644 --- a/src/bin_wasm_debugger/commands.ml +++ b/src/bin_wasm_debugger/commands.ml @@ -111,51 +111,7 @@ let compute_step tree = (** [eval_to_result tree] tries to evaluates the PVM until the next `SK_Result` or `SK_Trap`, and stops in case of reveal tick or input tick. It has the property that the memory hasn't been flushed yet and can be inspected. *) -let eval_to_result tree = - let open Lwt_syntax in - let open Wasm_pvm_state in - let should_compute pvm_state = - let+ input_request_val = Wasm_vm.get_info pvm_state in - match (input_request_val.input_request, pvm_state.tick_state) with - | Input_required, _ -> false - | ( No_input_required, - Eval - { - config = - { - step_kont = - Tezos_webassembly_interpreter.Eval.( - SK_Result _ | SK_Trapped _); - _; - }; - _; - } ) -> - false - | Reveal_required _, _ | No_input_required, _ -> true - in - (* Since `compute_step_many_until` is not exported by the PVM but only the VM, - we decode and re-encode by hand. *) - trap_exn (fun () -> - let* pvm_state = - Test_encodings_util.Tree_encoding_runner.decode - Tezos_scoru_wasm.Wasm_pvm.pvm_state_encoding - tree - in - let* pvm_state, ticks = - Tezos_scoru_wasm.Wasm_vm.compute_step_many_until - ~reveal_builtins - ~write_debug - ~max_steps:Int64.max_int - should_compute - pvm_state - in - let+ tree = - Test_encodings_util.Tree_encoding_runner.encode - Tezos_scoru_wasm.Wasm_pvm.pvm_state_encoding - pvm_state - tree - in - (tree, ticks)) +let eval_to_result tree = trap_exn (fun () -> eval_to_result tree) (* [eval_kernel_run tree] evals up to the end of the current `kernel_run` (or starts a new one if already at snapshot point). *) diff --git a/src/lib_scoru_wasm/test/helpers/wasm_utils.ml b/src/lib_scoru_wasm/test/helpers/wasm_utils.ml index e0809b75e835..6ef4353f335d 100644 --- a/src/lib_scoru_wasm/test/helpers/wasm_utils.ml +++ b/src/lib_scoru_wasm/test/helpers/wasm_utils.ml @@ -240,6 +240,59 @@ let rec eval_until_init tree = let* tree = Wasm.compute_step tree in eval_until_init tree +(* [eval_until_cond should_conpute tree] is exactly `compute_step_many_until`, + it can fail if [should_compute] doesn't stop on input ticks. *) +let eval_to_cond ?write_debug ?reveal_builtins should_compute tree = + let open Lwt_syntax in + (* Since `compute_step_many_until` is not exported by the PVM but only the VM, + we decode and re-encode by hand. *) + let* pvm_state = + Test_encodings_util.Tree_encoding_runner.decode + Tezos_scoru_wasm.Wasm_pvm.pvm_state_encoding + tree + in + let* pvm_state, ticks = + Tezos_scoru_wasm.Wasm_vm.compute_step_many_until + ?reveal_builtins + ?write_debug + ~max_steps:(Z.to_int64 pvm_state.max_nb_ticks) + should_compute + pvm_state + in + let+ tree = + Test_encodings_util.Tree_encoding_runner.encode + Tezos_scoru_wasm.Wasm_pvm.pvm_state_encoding + pvm_state + tree + in + (tree, ticks) + +(** [eval_to_result tree] tries to evaluates the PVM until the next `SK_Result` + or `SK_Trap`, and stops in case of reveal tick or input tick. It has the + property that the memory hasn't been flushed yet and can be inspected. *) +let eval_to_result ?write_debug ?reveal_builtins tree = + let open Lwt_syntax in + let should_compute pvm_state = + let+ input_request_val = Wasm_vm.get_info pvm_state in + match (input_request_val.input_request, pvm_state.tick_state) with + | Reveal_required _, _ | Input_required, _ -> false + | ( No_input_required, + Eval + { + config = + { + step_kont = + Tezos_webassembly_interpreter.Eval.( + SK_Result _ | SK_Trapped _); + _; + }; + _; + } ) -> + false + | No_input_required, _ -> true + in + eval_to_cond ?write_debug ?reveal_builtins should_compute tree + let set_input_step message message_counter tree = let input_info = Wasm_pvm_state. -- GitLab From 7c10200d652bc5322bcd09332fbe0977aa01f208 Mon Sep 17 00:00:00 2001 From: Pierrick Couderc Date: Mon, 2 Jan 2023 17:08:50 +0100 Subject: [PATCH 3/4] WASM/PVM: test tickification of host function --- .../test/test_host_functions_ticks.ml | 113 ++++++++++++++++++ src/lib_scoru_wasm/test/test_scoru_wasm.ml | 1 + 2 files changed, 114 insertions(+) create mode 100644 src/lib_scoru_wasm/test/test_host_functions_ticks.ml diff --git a/src/lib_scoru_wasm/test/test_host_functions_ticks.ml b/src/lib_scoru_wasm/test/test_host_functions_ticks.ml new file mode 100644 index 000000000000..0c8fbb12dda9 --- /dev/null +++ b/src/lib_scoru_wasm/test/test_host_functions_ticks.ml @@ -0,0 +1,113 @@ +(*****************************************************************************) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Test + Invocation: dune exec src/lib_scoru_wasm/test/test_scoru_wasm.exe \ + -- test "^Host functions ticks$" + Subject: Tickification of host functions tests for the \ + tezos-scoru-wasm library +*) + +open Tztest +open Tezos_scoru_wasm +open Wasm_utils + +(* This function return a function to modifiy `write_debug` in the registry, and + a function to revert the change. Due to how the registry works right now (a + mutable global), this in necessary otherwise the next tests might fail. *) +let register_new_write_debug added_ticks = + let open Lwt_syntax in + let name = + match Host_funcs.Internal_for_tests.write_debug with + | Tezos_webassembly_interpreter.Func.HostFunc (_, name) -> name + | _ -> Stdlib.failwith "write_debug is not an host function" + in + let current_write_debug = + Tezos_webassembly_interpreter.Host_funcs.lookup + ~global_name:name + Host_funcs.all + in + let alternative_write_debug = + match current_write_debug with + | Tezos_webassembly_interpreter.Host_funcs.Host_func f -> + let write_debug input output durable mem args = + let* durable, res, ticks = f input output durable mem args in + return (durable, res, Z.add ticks (Z.of_int added_ticks)) + in + Tezos_webassembly_interpreter.Host_funcs.Host_func write_debug + | Reveal_func _ -> Stdlib.failwith "write_debug is not a reveal function" + in + let register impl () = + Tezos_webassembly_interpreter.Host_funcs.register + ~global_name:name + impl + Host_funcs.all + in + (register alternative_write_debug, register current_write_debug) + +let test_tickified_host_function () = + let open Lwt_syntax in + let run_until_result () = + let module_ = + {| +(module + (import "smart_rollup_core" "write_debug" + (func $write_debug (param i32 i32))) + ;; Durable keys + (data (i32.const 100) "hello") + (memory 1) + (export "mem" (memory 0)) + (func (export "kernel_run") + (local $hello_address i32) + (local $hello_length i32) + + (local.set $hello_address (i32.const 100)) + (local.set $hello_length (i32.const 5)) + + (call $write_debug (local.get $hello_address) (local.get $hello_length)) + (nop) + ) + ) +|} + in + let* tree = initial_tree ~from_binary:false module_ in + (* Feeding it with one input *) + let* tree = set_empty_inbox_step 0l tree in + (* running until waiting for input *) + let* _tree, elapsed_ticks = eval_to_result tree in + return elapsed_ticks + in + let* elapsed_tick_before = run_until_result () in + let update_registry, revert_registry = register_new_write_debug 100 in + update_registry () ; + let* elapsed_tick_with_alt_write_debug = run_until_result () in + assert (Int64.add elapsed_tick_before 100L = elapsed_tick_with_alt_write_debug) ; + revert_registry () ; + return_ok_unit + +let tests = + [tztest "Test tickified host function" `Quick test_tickified_host_function] diff --git a/src/lib_scoru_wasm/test/test_scoru_wasm.ml b/src/lib_scoru_wasm/test/test_scoru_wasm.ml index eebb0e65997b..25e9c41dfecb 100644 --- a/src/lib_scoru_wasm/test/test_scoru_wasm.ml +++ b/src/lib_scoru_wasm/test/test_scoru_wasm.ml @@ -49,5 +49,6 @@ let () = ("Hash correspondence", Test_hash_consistency.tests); ("Reveal", Test_reveal.tests); ("Debug", Test_debug.tests); + ("Host functions ticks", Test_host_functions_ticks.tests); ] |> Lwt_main.run -- GitLab From e172c9ae22b1c10548b06abede4d175b24a06e63 Mon Sep 17 00:00:00 2001 From: Pierrick Couderc Date: Thu, 5 Jan 2023 16:20:48 +0100 Subject: [PATCH 4/4] WASM: Add model placeholders --- src/lib_scoru_wasm/host_funcs.ml | 85 +++++++++++++++++++++++++++----- src/lib_webassembly/exec/eval.ml | 4 +- 2 files changed, 75 insertions(+), 14 deletions(-) diff --git a/src/lib_scoru_wasm/host_funcs.ml b/src/lib_scoru_wasm/host_funcs.ml index da11f0899ff7..3ec2cecf355b 100644 --- a/src/lib_scoru_wasm/host_funcs.ml +++ b/src/lib_scoru_wasm/host_funcs.ml @@ -608,6 +608,11 @@ let read_input_type = let read_input_name = "tezos_read_input" +(* TODO: https://gitlab.com/tezos/tezos/-/issues/4531 + Define a tick consumption model. +*) +let read_input_ticks _size = default_ticks + let read_input = Host_funcs.Host_func (fun input_buffer _output_buffer durable memories inputs -> @@ -619,10 +624,10 @@ let read_input = Values.(Num (I32 max_bytes)); ] -> let* memory = retrieve_memory memories in - let* x = + let* read_bytes = Aux.read_input ~input_buffer ~memory ~info_addr ~dst ~max_bytes in - Lwt.return (durable, [value x], default_ticks) + Lwt.return (durable, [value read_bytes], read_input_ticks read_bytes) | _ -> raise Bad_input) let write_output_name = "tezos_write_output" @@ -634,6 +639,11 @@ let write_output_type = let output_types = Types.[NumType I32Type] |> Vector.of_list in Types.FuncType (input_types, output_types) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/4531 + Define a tick consumption model. +*) +let write_output_ticks _size = default_ticks + let write_output = Host_funcs.Host_func (fun _input_buffer output_buffer durable memories inputs -> @@ -641,8 +651,10 @@ let write_output = match inputs with | [Values.(Num (I32 src)); Values.(Num (I32 num_bytes))] -> let* memory = retrieve_memory memories in - let* x = Aux.write_output ~output_buffer ~memory ~src ~num_bytes in - Lwt.return (durable, [value x], default_ticks) + let* read_bytes = + Aux.write_output ~output_buffer ~memory ~src ~num_bytes + in + Lwt.return (durable, [value read_bytes], write_output_ticks read_bytes) | _ -> raise Bad_input) let write_debug_name = "tezos_write_debug" @@ -668,6 +680,8 @@ let write_debug ~implem = match inputs with | [Values.(Num (I32 src)); Values.(Num (I32 num_bytes))] -> let+ () = run ~memory ~src ~num_bytes in + (* Write_debug is considered a no-op, it shouldn't take more than the + default ticks. *) (durable, [], default_ticks) | _ -> raise Bad_input) @@ -680,6 +694,11 @@ let store_has_type = let output_types = Types.[NumType I32Type] |> Vector.of_list in Types.FuncType (input_types, output_types) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/4531 + Define a tick consumption model. +*) +let store_has_ticks _size = default_ticks + let store_has = Host_funcs.Host_func (fun _input_buffer _output_buffer durable memories inputs -> @@ -694,7 +713,7 @@ let store_has = ~key_offset ~key_length in - (durable, [value r], default_ticks) + (durable, [value r], store_has_ticks 0l) | _ -> raise Bad_input) let store_delete_name = "tezos_store_delete" @@ -706,6 +725,11 @@ let store_delete_type = let output_types = Vector.of_list [Types.NumType I32Type] in Types.FuncType (input_types, output_types) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/4531 + Define a tick consumption model. +*) +let store_delete_ticks _size = default_ticks + let store_delete = Host_funcs.Host_func (fun _input_buffer _output_buffer durable memories inputs -> @@ -720,7 +744,7 @@ let store_delete = ~key_offset ~key_length in - (Durable.to_storage durable, [value code], default_ticks) + (Durable.to_storage durable, [value code], store_delete_ticks 0l) | _ -> raise Bad_input) let store_value_size_name = "tezos_store_value_size" @@ -733,6 +757,11 @@ let store_value_size_type = let output_types = Vector.of_list Types.[NumType I32Type] in Types.FuncType (input_types, output_types) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/4531 + Define a tick consumption model. +*) +let store_value_size_ticks _size = default_ticks + let store_value_size = let open Lwt_syntax in let open Values in @@ -748,7 +777,7 @@ let store_value_size = ~key_offset ~key_length in - (durable, [value res], default_ticks) + (durable, [value res], store_value_size_ticks 0l) | _ -> raise Bad_input) let store_list_size_name = "tezos_store_list_size" @@ -761,6 +790,11 @@ let store_list_size_type = let output_types = Types.[NumType I64Type] |> Vector.of_list in Types.FuncType (input_types, output_types) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/4531 + Define a tick consumption model. +*) +let store_list_size_ticks _size = default_ticks + let store_list_size = Host_funcs.Host_func (fun _input_buffer _output_buffer durable memories inputs -> @@ -777,7 +811,7 @@ let store_list_size = in ( Durable.to_storage durable, [Values.(Num (I64 result))], - default_ticks ) + store_list_size_ticks 0l ) | _ -> raise Bad_input) let store_get_nth_key_name = "tezos_store_get_nth_key_list" @@ -797,6 +831,11 @@ let store_get_nth_key_type = let output_types = Types.[NumType I32Type] |> Vector.of_list in Types.FuncType (input_types, output_types) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/4531 + Define a tick consumption model. +*) +let store_get_nth_key_ticks _size = default_ticks + let store_get_nth_key = Host_funcs.Host_func (fun _input_buffer _output_buffer durable memories inputs -> @@ -821,7 +860,7 @@ let store_get_nth_key = ~dst ~max_size in - (durable, [value result], default_ticks) + (durable, [value result], store_get_nth_key_ticks 0l) | _ -> raise Bad_input) let store_copy_name = "tezos_store_copy" @@ -835,6 +874,11 @@ let store_copy_type = let output_types = Vector.of_list Types.[NumType I32Type] in Types.FuncType (input_types, output_types) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/4531 + Define a tick consumption model. +*) +let store_copy_ticks _size = default_ticks + let store_copy = Host_funcs.Host_func (fun _input_buffer _output_buffer durable memories inputs -> @@ -857,7 +901,7 @@ let store_copy = ~to_key_offset ~to_key_length in - (Durable.to_storage durable, [value code], default_ticks) + (Durable.to_storage durable, [value code], store_copy_ticks 0l) | _ -> raise Bad_input) let store_move_name = "tezos_store_move" @@ -871,6 +915,11 @@ let store_move_type = let output_types = Vector.of_list Types.[NumType I32Type] in Types.FuncType (input_types, output_types) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/4531 + Define a tick consumption model. +*) +let store_move_ticks _size = default_ticks + let store_move = Host_funcs.Host_func (fun _input_buffer _output_buffer durable memories inputs -> @@ -893,7 +942,7 @@ let store_move = ~to_key_offset ~to_key_length in - (Durable.to_storage durable, [value code], default_ticks) + (Durable.to_storage durable, [value code], store_move_ticks 0l) | _ -> raise Bad_input) let store_read_name = "tezos_store_read" @@ -913,6 +962,11 @@ let store_read_type = let output_types = Vector.of_list Types.[NumType I32Type] in Types.FuncType (input_types, output_types) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/4531 + Define a tick consumption model. +*) +let store_read_ticks _size = default_ticks + let store_read = Host_funcs.Host_func (fun _input_buffer _output_buffer durable memories inputs -> @@ -936,7 +990,7 @@ let store_read = ~dest ~max_bytes in - (durable, [value len], default_ticks) + (durable, [value len], store_read_ticks 0l) | _ -> raise Bad_input) let reveal_preimage_name = "tezos_reveal_preimage" @@ -1005,6 +1059,11 @@ let store_write_type = let output_types = Vector.of_list Types.[NumType I32Type] in Types.FuncType (input_types, output_types) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/4531 + Define a tick consumption model. +*) +let store_write_ticks _size = default_ticks + let store_write = Host_funcs.Host_func (fun _input_buffer _output_buffer durable memories inputs -> @@ -1029,7 +1088,7 @@ let store_write = ~src ~num_bytes in - (Durable.to_storage durable, [value code], default_ticks) + (Durable.to_storage durable, [value code], store_write_ticks 0l) | _ -> raise Bad_input) let lookup_opt name = diff --git a/src/lib_webassembly/exec/eval.ml b/src/lib_webassembly/exec/eval.ml index d9b90865113e..d87ce7305716 100644 --- a/src/lib_webassembly/exec/eval.ml +++ b/src/lib_webassembly/exec/eval.ml @@ -1607,7 +1607,9 @@ let reveal_step reveal module_reg payload = in let vs, es = inv.code in let vs = Vector.cons (Num (I32 bytes_count)) vs in - (* This value should be benchmarked *) + (* TODO: https://gitlab.com/tezos/tezos/-/issues/4531 + Define a tick consumption model. + *) let ticks_to_consume = Z.zero in { config with -- GitLab