From 5bc873495d23ccd6ca70281b3a191daf018a1650 Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Thu, 22 Sep 2022 13:46:59 +0200 Subject: [PATCH 1/5] =?UTF-8?q?WASM:=20Implement=20the=20=E2=80=9Creveal?= =?UTF-8?q?=20tick=E2=80=9D=20host=20function=20in=20the=20PVM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../environment_V6.ml | 3 +- .../environment_V7.ml | 23 ++- .../environment_V7.mli | 3 - .../environment_V8.ml | 13 ++ .../environment_V8.mli | 2 + src/lib_protocol_environment/sigs/v8.ml | 13 +- .../sigs/v8/wasm_2_0_0.mli | 13 +- src/lib_scoru_wasm/gather_floppies.ml | 2 + src/lib_scoru_wasm/host_funcs.ml | 19 ++ src/lib_scoru_wasm/test/ast_generators.ml | 17 ++ src/lib_scoru_wasm/test/ast_printer.ml | 28 +++ src/lib_scoru_wasm/test/test_get_set.ml | 38 +--- src/lib_scoru_wasm/test/wasm_utils.ml | 1 + src/lib_scoru_wasm/wasm_encoding.ml | 47 +++++ src/lib_scoru_wasm/wasm_pvm.ml | 85 +++++--- src/lib_scoru_wasm/wasm_pvm_sig.ml | 16 ++ src/lib_webassembly/exec/eval.ml | 189 ++++++++++++++---- src/lib_webassembly/exec/eval.mli | 16 ++ src/lib_webassembly/exec/reveal.ml | 10 + src/lib_webassembly/exec/reveal.mli | 10 + src/lib_webassembly/runtime/host_funcs.ml | 4 +- src/lib_webassembly/runtime/host_funcs.mli | 4 +- .../bin_sc_rollup_node/wasm_2_0_0_pvm.ml | 18 ++ .../bin_sc_rollup_node/wasm_2_0_0_pvm.ml | 5 + .../lib_protocol/alpha_context.mli | 5 +- .../lib_protocol/sc_rollup_wasm.ml | 35 +++- .../lib_protocol/sc_rollup_wasm.mli | 5 +- .../test/integration/test_sc_rollup_wasm.ml | 2 +- 28 files changed, 500 insertions(+), 126 deletions(-) create mode 100644 src/lib_webassembly/exec/reveal.ml create mode 100644 src/lib_webassembly/exec/reveal.mli diff --git a/src/lib_protocol_environment/environment_V6.ml b/src/lib_protocol_environment/environment_V6.ml index 57b2e7996054..5fe72f6e8866 100644 --- a/src/lib_protocol_environment/environment_V6.ml +++ b/src/lib_protocol_environment/environment_V6.ml @@ -1112,7 +1112,8 @@ struct input_request = (match input_request with | No_input_required -> No_input_required - | Input_required -> Input_required); + | Input_required -> Input_required + | Reveal_required _ -> No_input_required); } end end diff --git a/src/lib_protocol_environment/environment_V7.ml b/src/lib_protocol_environment/environment_V7.ml index 2909cd7a8892..a48a54aee522 100644 --- a/src/lib_protocol_environment/environment_V7.ml +++ b/src/lib_protocol_environment/environment_V7.ml @@ -106,9 +106,6 @@ module type T = sig Tezos_base.Bounded.Non_negative_int32.t and type Wasm_2_0_0.input = Tezos_scoru_wasm.Wasm_pvm_sig.input_info and type Wasm_2_0_0.output = Tezos_scoru_wasm.Wasm_pvm_sig.output_info - and type Wasm_2_0_0.input_request = - Tezos_scoru_wasm.Wasm_pvm_sig.input_request - and type Wasm_2_0_0.info = Tezos_scoru_wasm.Wasm_pvm_sig.info type error += Ecoproto_error of Error_monad.error @@ -1051,11 +1048,9 @@ struct message_index : Z.t; } - type input_request = Tezos_scoru_wasm.Wasm_pvm_sig.input_request = - | No_input_required - | Input_required + type input_request = No_input_required | Input_required - type info = Tezos_scoru_wasm.Wasm_pvm_sig.info = { + type info = { current_tick : Z.t; last_input_read : input option; input_request : input_request; @@ -1083,7 +1078,19 @@ struct let get_output output (tree : Tree.tree) = Wasm.get_output output tree - let get_info (tree : Tree.tree) = Wasm.get_info tree + let get_info (tree : Tree.tree) = + let open Lwt_syntax in + let+ {current_tick; last_input_read; input_request} = + Wasm.get_info tree + in + { + current_tick; + last_input_read; + input_request = + (match input_request with + | Reveal_required _ | No_input_required -> No_input_required + | Input_required -> Input_required); + } end end diff --git a/src/lib_protocol_environment/environment_V7.mli b/src/lib_protocol_environment/environment_V7.mli index ae4cbf141664..0ce2fc9c4d7c 100644 --- a/src/lib_protocol_environment/environment_V7.mli +++ b/src/lib_protocol_environment/environment_V7.mli @@ -106,9 +106,6 @@ module type T = sig Tezos_base.Bounded.Non_negative_int32.t and type Wasm_2_0_0.input = Tezos_scoru_wasm.Wasm_pvm_sig.input_info and type Wasm_2_0_0.output = Tezos_scoru_wasm.Wasm_pvm_sig.output_info - and type Wasm_2_0_0.input_request = - Tezos_scoru_wasm.Wasm_pvm_sig.input_request - and type Wasm_2_0_0.info = Tezos_scoru_wasm.Wasm_pvm_sig.info (** An [Ecoproto_error e] is a shell error that carry a protocol error. diff --git a/src/lib_protocol_environment/environment_V8.ml b/src/lib_protocol_environment/environment_V8.ml index 790a60592bf9..4a83785c4e47 100644 --- a/src/lib_protocol_environment/environment_V8.ml +++ b/src/lib_protocol_environment/environment_V8.ml @@ -106,6 +106,8 @@ module type T = sig Tezos_base.Bounded.Non_negative_int32.t and type Wasm_2_0_0.input = Tezos_scoru_wasm.Wasm_pvm_sig.input_info and type Wasm_2_0_0.output = Tezos_scoru_wasm.Wasm_pvm_sig.output_info + and type Wasm_2_0_0.input_hash = Tezos_scoru_wasm.Wasm_pvm_sig.input_hash + and type Wasm_2_0_0.reveal = Tezos_scoru_wasm.Wasm_pvm_sig.reveal and type Wasm_2_0_0.input_request = Tezos_scoru_wasm.Wasm_pvm_sig.input_request and type Wasm_2_0_0.info = Tezos_scoru_wasm.Wasm_pvm_sig.info @@ -1051,9 +1053,18 @@ struct message_index : Z.t; } + type input_hash = Tezos_scoru_wasm.Wasm_pvm_sig.input_hash + + let input_hash_to_string = + Tezos_scoru_wasm.Wasm_pvm_sig.input_hash_to_string + + type reveal = Tezos_scoru_wasm.Wasm_pvm_sig.reveal = + | Reveal_raw_data of input_hash + type input_request = Tezos_scoru_wasm.Wasm_pvm_sig.input_request = | No_input_required | Input_required + | Reveal_required of reveal type info = Tezos_scoru_wasm.Wasm_pvm_sig.info = { current_tick : Z.t; @@ -1081,6 +1092,8 @@ struct let set_input_step input payload (tree : Tree.tree) = Wasm.set_input_step input payload tree + let reveal_step = Wasm.reveal_step + let get_output output (tree : Tree.tree) = Wasm.get_output output tree let get_info (tree : Tree.tree) = Wasm.get_info tree diff --git a/src/lib_protocol_environment/environment_V8.mli b/src/lib_protocol_environment/environment_V8.mli index 1bd5467e8504..ea70f763dc3a 100644 --- a/src/lib_protocol_environment/environment_V8.mli +++ b/src/lib_protocol_environment/environment_V8.mli @@ -106,6 +106,8 @@ module type T = sig Tezos_base.Bounded.Non_negative_int32.t and type Wasm_2_0_0.input = Tezos_scoru_wasm.Wasm_pvm_sig.input_info and type Wasm_2_0_0.output = Tezos_scoru_wasm.Wasm_pvm_sig.output_info + and type Wasm_2_0_0.input_hash = Tezos_scoru_wasm.Wasm_pvm_sig.input_hash + and type Wasm_2_0_0.reveal = Tezos_scoru_wasm.Wasm_pvm_sig.reveal and type Wasm_2_0_0.input_request = Tezos_scoru_wasm.Wasm_pvm_sig.input_request and type Wasm_2_0_0.info = Tezos_scoru_wasm.Wasm_pvm_sig.info diff --git a/src/lib_protocol_environment/sigs/v8.ml b/src/lib_protocol_environment/sigs/v8.ml index 41f8050b641d..3e57aa36653b 100644 --- a/src/lib_protocol_environment/sigs/v8.ml +++ b/src/lib_protocol_environment/sigs/v8.ml @@ -11765,7 +11765,16 @@ type input = {inbox_level : Bounded.Non_negative_int32.t; message_counter : Z.t} type output = {outbox_level : Bounded.Non_negative_int32.t; message_index : Z.t} -type input_request = No_input_required | Input_required +type input_hash + +val input_hash_to_string : input_hash -> string + +type reveal = Reveal_raw_data of input_hash + +type input_request = + | No_input_required + | Input_required + | Reveal_required of reveal type info = { current_tick : Z.t; @@ -11779,6 +11788,8 @@ module Make val set_input_step : input -> string -> Tree.tree -> Tree.tree Lwt.t + val reveal_step : bytes -> Tree.tree -> Tree.tree Lwt.t + val get_output : output -> Tree.tree -> string Lwt.t val get_info : Tree.tree -> info Lwt.t diff --git a/src/lib_protocol_environment/sigs/v8/wasm_2_0_0.mli b/src/lib_protocol_environment/sigs/v8/wasm_2_0_0.mli index aa17a2bb4f6a..f163b28c8d6b 100644 --- a/src/lib_protocol_environment/sigs/v8/wasm_2_0_0.mli +++ b/src/lib_protocol_environment/sigs/v8/wasm_2_0_0.mli @@ -27,7 +27,16 @@ type input = {inbox_level : Bounded.Non_negative_int32.t; message_counter : Z.t} type output = {outbox_level : Bounded.Non_negative_int32.t; message_index : Z.t} -type input_request = No_input_required | Input_required +type input_hash + +val input_hash_to_string : input_hash -> string + +type reveal = Reveal_raw_data of input_hash + +type input_request = + | No_input_required + | Input_required + | Reveal_required of reveal type info = { current_tick : Z.t; @@ -41,6 +50,8 @@ module Make val set_input_step : input -> string -> Tree.tree -> Tree.tree Lwt.t + val reveal_step : bytes -> Tree.tree -> Tree.tree Lwt.t + val get_output : output -> Tree.tree -> string Lwt.t val get_info : Tree.tree -> info Lwt.t diff --git a/src/lib_scoru_wasm/gather_floppies.ml b/src/lib_scoru_wasm/gather_floppies.ml index 0459d8538d42..7f6a4b0c96e4 100644 --- a/src/lib_scoru_wasm/gather_floppies.ml +++ b/src/lib_scoru_wasm/gather_floppies.ml @@ -369,6 +369,8 @@ module Make Tree_encoding_runner.encode state_merklizer state tree | Not_gathering_floppies -> Wasm.set_input_step input message tree) + let reveal_step = Wasm.reveal_step + let get_output = Wasm.get_output let get_info tree = diff --git a/src/lib_scoru_wasm/host_funcs.ml b/src/lib_scoru_wasm/host_funcs.ml index be112a384ec6..e2ba31121091 100644 --- a/src/lib_scoru_wasm/host_funcs.ml +++ b/src/lib_scoru_wasm/host_funcs.ml @@ -397,6 +397,22 @@ let store_move = to_key_length | _ -> raise Bad_input) +(** [reveal_args args] compute the list of arguments type of a host + functions resulting in a reveal tick. [args] is the list of types + specific to a given host functions, and [reveal_args] appends two + int32 which specify the output buffer (base, and length) where the + result of the function is to be stored. *) +let reveal_args args = args @ Types.[NumType I32Type; NumType I32Type] + +let reveal_preimage_name = "reveal_preimage" + +let reveal_preimage_type = + let input_types = reveal_args Types.[NumType I32Type] |> Vector.of_list in + let output_types = Types.[NumType I32Type] |> Vector.of_list in + Types.FuncType (input_types, output_types) + +let reveal_preimage = Host_funcs.Reveal_tick Preimage + let lookup_opt name = match name with | "read_input" -> @@ -414,6 +430,8 @@ let lookup_opt name = Some (ExternFunc (HostFunc (store_copy_type, store_copy_name))) | "store_move" -> Some (ExternFunc (HostFunc (store_move_type, store_move_name))) + | "reveal_preimage" -> + Some (ExternFunc (HostFunc (reveal_preimage_type, reveal_preimage_name))) | _ -> None let lookup name = @@ -433,6 +451,7 @@ let register_host_funcs registry = (store_delete_name, store_delete); (store_copy_name, store_copy); (store_move_name, store_move); + (reveal_preimage_name, reveal_preimage); ] module Internal_for_tests = struct diff --git a/src/lib_scoru_wasm/test/ast_generators.ml b/src/lib_scoru_wasm/test/ast_generators.ml index e3556749664f..c00478785740 100644 --- a/src/lib_scoru_wasm/test/ast_generators.ml +++ b/src/lib_scoru_wasm/test/ast_generators.ml @@ -762,6 +762,22 @@ let inv_concat_gen ~module_reg = let+ concat_kont = concat_kont_gen value_gen in Eval.Inv_concat {arity; vs; instructions; inst; func; concat_kont} +let inv_reveal_tick ~module_reg = + let* hash = Reveal.input_hash_from_string_exn <$> string_size (pure 32) in + let* base_destination = Int32.of_int <$> small_nat in + let* max_bytes = Int32.of_int <$> small_nat in + let* vs = small_vector_gen value_gen in + let* es = small_vector_gen (admin_instr_gen ~module_reg) in + let+ revealed_bytes = option int32 in + Eval.Inv_reveal_tick + { + reveal = Reveal_raw_data hash; + base_destination; + max_bytes; + code = (vs, es); + revealed_bytes; + } + 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 @@ -775,6 +791,7 @@ let invoke_step_gen ~module_reg = inv_prepare_locals_gen ~module_reg; inv_prepare_args_gen ~module_reg; inv_concat_gen ~module_reg; + inv_reveal_tick ~module_reg; inv_stop_gen ~module_reg; ] diff --git a/src/lib_scoru_wasm/test/ast_printer.ml b/src/lib_scoru_wasm/test/ast_printer.ml index 3a643eba3222..54950c5c5aa5 100644 --- a/src/lib_scoru_wasm/test/ast_printer.ml +++ b/src/lib_scoru_wasm/test/ast_printer.ml @@ -423,6 +423,13 @@ let pp_concat_kont pp out Eval.{lv; rv; res; offset} = res offset +let pp_reveal out = function + | Reveal.Reveal_raw_data hash -> + Format.fprintf + out + "Reveal_raw_data (%s)" + (Reveal.input_hash_to_string hash) + let pp_invoke_step_kont out = function | Eval.Inv_start {func; code = vs, es} -> Format.fprintf @@ -505,6 +512,27 @@ let pp_invoke_step_kont out = function func (pp_concat_kont Values.pp_value) concat_kont + | Inv_reveal_tick + {reveal; base_destination; max_bytes; code = vs, es; revealed_bytes} -> + Format.fprintf + out + "@[Inv_reveal_tick {instructions = %a;@;\ + values = %a;@;\ + reveal = %a;@;\ + revealed_bytes = %a;@;\ + base_destination = %ld;@;\ + max_bytes = %ld;@;\ + }@]" + (pp_vector pp_admin_instr) + es + (pp_vector Values.pp_value) + vs + pp_reveal + reveal + (pp_opt pp_int32) + revealed_bytes + base_destination + max_bytes | Inv_stop {code = vs, es; fresh_frame} -> Format.fprintf out diff --git a/src/lib_scoru_wasm/test/test_get_set.ml b/src/lib_scoru_wasm/test/test_get_set.ml index 9caf35c762ec..c1aae1bbbe51 100644 --- a/src/lib_scoru_wasm/test/test_get_set.ml +++ b/src/lib_scoru_wasm/test/test_get_set.ml @@ -67,18 +67,8 @@ let current_tick_encoding = (* Replicates the encoder in [Wasm_pvm]. Used here for artificially encode input info in the tree. *) -let input_request_encoding = - Tree_encoding.conv - (function - | true -> Wasm_pvm_sig.Input_required - | false -> Wasm_pvm_sig.No_input_required) - (function - | Wasm_pvm_sig.Input_required -> true - | Wasm_pvm_sig.No_input_required -> false) - (Tree_encoding.value - ~default:false - ["input"; "consuming"] - Data_encoding.bool) +let input_requested_encoding = + Tree_encoding.value ~default:false ["input"; "consuming"] Data_encoding.bool let floppy_encoding = Tree_encoding.value @@ -122,12 +112,7 @@ let initialise_tree () = Gather_floppies.Not_gathering_floppies tree in - let* tree = - Tree_encoding_runner.encode - input_request_encoding - Wasm_pvm_sig.Input_required - tree - in + let* tree = Tree_encoding_runner.encode input_requested_encoding true tree in Tree_encoding_runner.encode buffers_encoding (Tezos_webassembly_interpreter.Eval.buffers ()) @@ -216,18 +201,7 @@ let test_set_input () = let open Lwt_syntax in let* tree = initialise_tree () in let* tree = add_input_info tree ~inbox_level:5 ~message_counter:10 in - let* tree = - Tree_encoding_runner.encode - input_request_encoding - Wasm_pvm_sig.No_input_required - tree - in - let* tree = - Tree_encoding_runner.encode - input_request_encoding - Wasm_pvm_sig.Input_required - tree - in + let* tree = Tree_encoding_runner.encode input_requested_encoding true tree in let host_funcs = Tezos_webassembly_interpreter.Host_funcs.empty () in let module_reg = Tezos_webassembly_interpreter.Instance.ModuleMap.create () in let tick_state = @@ -248,7 +222,7 @@ let test_set_input () = in let* result_input = Tree_encoding_runner.decode inp_encoding tree in let* waiting_for_input = - Tree_encoding_runner.decode input_request_encoding tree + Tree_encoding_runner.decode input_requested_encoding tree in let* current_tick = Tree_encoding_runner.decode current_tick_encoding tree in let expected_info = @@ -265,7 +239,7 @@ let test_set_input () = let* actual_info = Wasm.get_info tree in assert (actual_info = expected_info) ; assert (current_tick = Z.one) ; - assert (waiting_for_input = Wasm_pvm_sig.No_input_required) ; + assert (waiting_for_input = false) ; assert (result_input = "hello") ; Lwt_result_syntax.return_unit diff --git a/src/lib_scoru_wasm/test/wasm_utils.ml b/src/lib_scoru_wasm/test/wasm_utils.ml index 0f83d6bc2822..0ff572c67071 100644 --- a/src/lib_scoru_wasm/test/wasm_utils.ml +++ b/src/lib_scoru_wasm/test/wasm_utils.ml @@ -79,6 +79,7 @@ let rec eval_until_input_requested ?(max_steps = Int64.max_int) tree = let* tree = Wasm.compute_step_many ~max_steps tree in eval_until_input_requested tree | Input_required -> return tree + | Reveal_required _ -> return tree let rec eval_until_init tree = let open Lwt_syntax in diff --git a/src/lib_scoru_wasm/wasm_encoding.ml b/src/lib_scoru_wasm/wasm_encoding.ml index 93ab6c845816..122c1ea9dc07 100644 --- a/src/lib_scoru_wasm/wasm_encoding.ml +++ b/src/lib_scoru_wasm/wasm_encoding.ml @@ -987,6 +987,23 @@ let packed_frame_stack_encoding = (scope ["frame"] frame_encoding) (scope ["label_kont"] packed_label_kont_encoding)) +let input_hash_encoding = + conv + Reveal.input_hash_from_string_exn + Reveal.input_hash_to_string + (value [] (Data_encoding.Fixed.string 32)) + +let reveal_encoding = + tagged_union + string_tag + [ + case + "Reveal_raw_data" + input_hash_encoding + (function Reveal.Reveal_raw_data hash -> Some hash) + (fun hash -> Reveal_raw_data hash); + ] + let invoke_step_kont_encoding = tagged_union string_tag @@ -1069,6 +1086,36 @@ let invoke_step_kont_encoding = | _ -> None) (fun (arity, vs, instructions, inst, func, concat_kont) -> Inv_concat {arity; vs; instructions; inst; func; concat_kont}); + case + "Inv_reveal_tick" + (tup6 + ~flatten:true + (scope ["reveal"] reveal_encoding) + (value ["base_destination"] Data_encoding.int32) + (value ["max_bytes"] Data_encoding.int32) + (lazy_vector_encoding "values" value_encoding) + (lazy_vector_encoding "instructions" admin_instr_encoding) + (option (value ["revealed_bytes"] Data_encoding.int32))) + (function + | Eval.Inv_reveal_tick + { + reveal; + base_destination; + max_bytes; + code = vs, es; + revealed_bytes; + } -> + Some (reveal, base_destination, max_bytes, vs, es, revealed_bytes) + | _ -> None) + (fun (reveal, base_destination, max_bytes, vs, es, revealed_bytes) -> + Inv_reveal_tick + { + reveal; + base_destination; + max_bytes; + code = (vs, es); + revealed_bytes; + }); case "Inv_stop" (tup3 diff --git a/src/lib_scoru_wasm/wasm_pvm.ml b/src/lib_scoru_wasm/wasm_pvm.ml index fd3dccf89213..ca8826d1affc 100644 --- a/src/lib_scoru_wasm/wasm_pvm.ml +++ b/src/lib_scoru_wasm/wasm_pvm.ml @@ -66,8 +66,7 @@ type pvm_state = { buffers : Wasm.Eval.buffers; (** Input and outut buffers used by the PVM host functions. *) tick_state : tick_state; (** The current tick state. *) - input_request : Wasm_pvm_sig.input_request; - (** Signals whether or not the PVM needs input. *) + input_requested : bool; (** Signals whether or not the PVM needs input. *) last_top_level_call : Z.t; (** Last tick corresponding to a top-level call. *) max_nb_ticks : Z.t; (** Number of ticks between top level call. *) @@ -155,15 +154,8 @@ struct (fun () -> Snapshot); ] - let input_request_encoding = - Tree_encoding.conv - (function - | true -> Wasm_pvm_sig.Input_required - | false -> Wasm_pvm_sig.No_input_required) - (function - | Wasm_pvm_sig.Input_required -> true - | Wasm_pvm_sig.No_input_required -> false) - (Tree_encoding.value ~default:false [] Data_encoding.bool) + let input_requested_encoding = + Tree_encoding.value ~default:false [] Data_encoding.bool let durable_buffers_encoding = Tree_encoding.(scope ["pvm"; "buffers"] Wasm_encoding.buffers_encoding) @@ -176,7 +168,7 @@ struct durable, buffers, tick_state, - input_request, + input_requested, last_top_level_call, max_nb_ticks ) -> { @@ -190,7 +182,7 @@ struct ~default:Tezos_webassembly_interpreter.Eval.buffers buffers; tick_state; - input_request; + input_requested; last_top_level_call; max_nb_ticks; }) @@ -200,7 +192,7 @@ struct durable; buffers; tick_state; - input_request; + input_requested; last_top_level_call; max_nb_ticks; } -> @@ -209,7 +201,7 @@ struct durable, Some buffers, tick_state, - input_request, + input_requested, last_top_level_call, max_nb_ticks )) (tup8 @@ -219,7 +211,7 @@ struct (scope ["durable"] Durable.encoding) (option durable_buffers_encoding) (scope ["wasm"] tick_state_encoding) - (scope ["input"; "consuming"] input_request_encoding) + (scope ["input"; "consuming"] input_requested_encoding) (value ~default:Z.zero ["pvm"; "last_top_level_call"] @@ -389,9 +381,9 @@ struct in Lwt.catch (fun () -> unsafe_next_tick_state pvm_state) to_stuck - let next_input_request = function - | Restarting | Failing -> Wasm_pvm_sig.Input_required - | Starting | Running -> Wasm_pvm_sig.No_input_required + let next_input_requested = function + | Restarting | Failing -> true + | Starting | Running -> false let next_last_top_level_call {current_tick; last_top_level_call; _} = function @@ -402,14 +394,14 @@ struct let open Lwt_syntax in (* Calculate the next tick state. *) let* durable, tick_state, status = next_tick_state pvm_state in - let input_request = next_input_request status in + let input_requested = next_input_requested status in let current_tick = Z.succ pvm_state.current_tick in let last_top_level_call = next_last_top_level_call pvm_state status in let pvm_state = { pvm_state with tick_state; - input_request; + input_requested; durable; current_tick; last_top_level_call; @@ -422,8 +414,11 @@ struct assert (max_steps > 0L) ; let should_continue pvm_state = - match (pvm_state.input_request, pvm_state.tick_state) with - | Wasm_pvm_sig.Input_required, _ -> false + match (pvm_state.input_requested, pvm_state.tick_state) with + | true, _ -> false + | _, Eval config -> + Option.is_none + (Tezos_webassembly_interpreter.Eval.is_reveal_tick config) | _, Stuck _ -> false | _ -> true in @@ -475,12 +470,27 @@ struct let get_info tree = let open Lwt_syntax in - let* {current_tick; last_input_info; input_request; _} = + let* {current_tick; last_input_info; input_requested; tick_state; _} = Tree_encoding_runner.decode pvm_state_encoding tree in - Lwt.return - Wasm_pvm_sig. - {current_tick; last_input_read = last_input_info; input_request} + let input_request = + if input_requested then Wasm_pvm_sig.Input_required + else No_input_required + in + let+ input_request = + match tick_state with + | Eval config -> + let maybe_reveal = + Tezos_webassembly_interpreter.Eval.is_reveal_tick config + in + Lwt.return + (match maybe_reveal with + | Some reveal -> Wasm_pvm_sig.Reveal_required reveal + | None -> input_request) + | _ -> Lwt.return input_request + in + Wasm_pvm_sig. + {current_tick; last_input_read = last_input_info; input_request} let set_input_step input_info message tree = let open Lwt_syntax in @@ -548,12 +558,31 @@ struct pvm_state with tick_state; current_tick = Z.succ pvm_state.current_tick; - input_request = Wasm_pvm_sig.No_input_required; + input_requested = false; } in (* Encode the new pvm-state in the tree. *) Tree_encoding_runner.encode pvm_state_encoding pvm_state tree + let reveal_step payload tree = + let open Lwt_syntax in + let open Tezos_webassembly_interpreter in + let* pvm_state = Tree_encoding_runner.decode pvm_state_encoding tree in + let* pvm_state = + match pvm_state.tick_state with + | Eval config -> + let+ config = Eval.reveal_step config.module_reg payload config in + { + pvm_state with + current_tick = Z.succ pvm_state.current_tick; + tick_state = Eval config; + } + | _ -> + (* TODO: Proper error handling *) + assert false + in + Tree_encoding_runner.encode pvm_state_encoding pvm_state tree + module Internal_for_tests = struct let get_tick_state tree = let open Lwt_syntax in diff --git a/src/lib_scoru_wasm/wasm_pvm_sig.ml b/src/lib_scoru_wasm/wasm_pvm_sig.ml index 2a054ed041bc..34c1c13740e3 100644 --- a/src/lib_scoru_wasm/wasm_pvm_sig.ml +++ b/src/lib_scoru_wasm/wasm_pvm_sig.ml @@ -37,10 +37,19 @@ type output_info = { message_index : Z.t; (** The index of the message in the outbox. *) } +type input_hash = Tezos_webassembly_interpreter.Reveal.input_hash + +let input_hash_to_string = + Tezos_webassembly_interpreter.Reveal.input_hash_to_string + +type reveal = Tezos_webassembly_interpreter.Reveal.reveal = + | Reveal_raw_data of Tezos_webassembly_interpreter.Reveal.input_hash + (** Represents the state of input requests. *) type input_request = | No_input_required (** The VM does not expect any input. *) | Input_required (** The VM needs input in order to progress. *) + | Reveal_required of reveal (** Represents the state of the VM. *) type info = { @@ -90,6 +99,13 @@ module type S = sig the function raises an exception if the VM is not expecting input. *) val set_input_step : input_info -> string -> tree -> tree Lwt.t + (** [reveal_step reveal_data tree] loads the [reveal_data] in the + memory of module of the currently executed function. + + If the VM does not expect any reveal data, this function raises + an exception. *) + val reveal_step : bytes -> tree -> tree Lwt.t + (** [get_output output state] returns the payload associated with the given output. The result is meant to be deserialized using [Sc_rollup_PVM_sem.output_encoding]. If the output is missing, this diff --git a/src/lib_webassembly/exec/eval.ml b/src/lib_webassembly/exec/eval.ml index 4553d4119700..5a91cf001fcd 100644 --- a/src/lib_webassembly/exec/eval.ml +++ b/src/lib_webassembly/exec/eval.ml @@ -350,8 +350,33 @@ type invoke_step_kont = func : func; concat_kont : value concat_kont; } + | Inv_reveal_tick of { + reveal : Reveal.reveal; + base_destination : int32; + max_bytes : int32; + code : code; + revealed_bytes : int32 option; + } | Inv_stop of {code : code; fresh_frame : ongoing frame_stack option} +let vector_pop_map v f at = + if 1l <= Vector.num_elements v then + let+ hd, v = Vector.pop v in + match f hd with + | Some r -> (r, v) + | None -> Crash.error at "missing or ill-typed operand on stack" + else Crash.error at "missing or ill-typed operand on stack" + +let num = function Num n -> Some n | _ -> None + +let num_i32 = function Num (I32 i) -> Some i | _ -> None + +let ref_ = function Ref r -> Some r | _ -> None + +let vec = function Vec v -> Some v | _ -> None + +let vec_v128 = function Vec (V128 v) -> Some v | _ -> None + type label_step_kont = | LS_Start : ongoing label_kont -> label_step_kont | LS_Craft_frame of ongoing label_kont * invoke_step_kont @@ -494,25 +519,62 @@ let invoke_step ~init ?(durable = Durable_storage.empty) c buffers frame at = | Func.HostFunc (_, global_name) -> Lwt.catch (fun () -> - let (Host_funcs.Host_func f) = - Host_funcs.lookup ~global_name c.host_funcs - in - let* inst = resolve_module_ref c.module_reg frame.inst in - let* args = Vector.to_list args in - let available_memories = - if not init then Host_funcs.Available_memories inst.memories - else Host_funcs.No_memories_during_init - in - let+ durable, res = - f - buffers.input - buffers.output - durable - available_memories - (List.rev args) - in - let vs' = Vector.prepend_list res vs' in - (durable, Inv_stop {code = (vs', es); fresh_frame = None})) + let host_func = Host_funcs.lookup ~global_name c.host_funcs in + match host_func with + | Host_func f -> + let* inst = resolve_module_ref c.module_reg frame.inst in + let* args = Vector.to_list args in + let available_memories = + if not init then Host_funcs.Available_memories inst.memories + else Host_funcs.No_memories_during_init + in + let+ durable, res = + f + buffers.input + buffers.output + durable + available_memories + (List.rev args) + in + let vs' = Vector.prepend_list res vs' in + (durable, Inv_stop {code = (vs', es); fresh_frame = None}) + | Reveal_tick kind -> + (* Reminder: the arguments are put on a stack, and must be + read in reverse order from the function definition. *) + let* max_bytes, args = + vector_pop_map args num_i32 no_region + in + let* base_destination, args = + vector_pop_map args num_i32 no_region + in + let* args, reveal = + match kind with + | Preimage -> + let* offset, args = + vector_pop_map args num_i32 no_region + in + let* inst = + resolve_module_ref c.module_reg frame.inst + in + let* mem = memory inst (0l @@ no_region) in + let+ hash = Memory.load_bytes mem offset 32 in + ( args, + Reveal.( + Reveal_raw_data (input_hash_from_string_exn hash)) + ) + in + (* TODO: Proper error handling. *) + assert (Vector.num_elements args = 0l) ; + Lwt.return + ( durable, + Inv_reveal_tick + { + reveal; + max_bytes; + base_destination; + code = (vs', es); + revealed_bytes = None; + } )) (function Crash (_, msg) -> Crash.error at msg | exn -> raise exn)) | Inv_prepare_locals { @@ -592,6 +654,14 @@ let invoke_step ~init ?(durable = Durable_storage.empty) c buffers frame at = }; }; } ) + | Inv_reveal_tick {revealed_bytes = None; _} -> + (* This is a reveal tick, not an evaluation tick. The PVM should + prevent this execution path. *) + assert false + | Inv_reveal_tick {revealed_bytes = Some revealed_bytes; code; _} -> + let vs, es = code in + let vs = Vector.cons (Num (I32 revealed_bytes)) vs in + Lwt.return (durable, Inv_stop {code = (vs, es); fresh_frame = None}) | Inv_concat tick -> let+ concat_kont = concat_step tick.concat_kont in (durable, Inv_concat {tick with concat_kont}) @@ -636,24 +706,6 @@ let elem_oob module_reg frame x i n = (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) (Int64.of_int32 (Instance.Vector.num_elements !elem)) -let vector_pop_map v f at = - if 1l <= Vector.num_elements v then - let+ hd, v = Vector.pop v in - match f hd with - | Some r -> (r, v) - | None -> Crash.error at "missing or ill-typed operand on stack" - else Crash.error at "missing or ill-typed operand on stack" - -let num = function Num n -> Some n | _ -> None - -let num_i32 = function Num (I32 i) -> Some i | _ -> None - -let ref_ = function Ref r -> Some r | _ -> None - -let vec = function Vec v -> Some v | _ -> None - -let vec_v128 = function Vec (V128 v) -> Some v | _ -> None - (** [step_instr module_reg label vs at e es stack] returns the new state of the label stack [label, stack] for a given [frame], by executing the WASM instruction [e] on top of the admin instr @@ -1505,6 +1557,69 @@ let rec eval durable module_reg (c : config) buffers : let* durable, c = step ~init:false ~durable c buffers in eval durable module_reg c buffers +let is_reveal_tick = function + | { + step_kont = + SK_Next + ( _, + _, + LS_Craft_frame + (_, Inv_reveal_tick {reveal; revealed_bytes = None; _}) ); + _; + } -> + Some reveal + | _ -> None + +let reveal module_reg base_destination max_bytes frame payload = + let open Lwt.Syntax in + Lwt.catch + (fun () -> + let* inst = resolve_module_ref module_reg frame.inst in + let+ mem = memory inst (0l @@ no_region) in + let payload_size = Bytes.length payload in + let revealed_bytes = min payload_size (Int32.to_int max_bytes) in + let payload = Bytes.sub payload 0 revealed_bytes in + let _ = + Memory.store_bytes mem base_destination (Bytes.to_string payload) + in + Int32.of_int revealed_bytes) + (fun _exn -> + (* TODO: error handling *) + assert false) + +let reveal_step module_reg payload = + let open Lwt.Syntax in + function + | { + step_kont = + SK_Next + ( frame, + top, + LS_Craft_frame + (label, Inv_reveal_tick ({revealed_bytes = None; _} as inv)) ); + _; + } as config -> + let+ bytes_count = + reveal + module_reg + inv.base_destination + inv.max_bytes + frame.frame_specs + payload + in + { + config with + step_kont = + SK_Next + ( frame, + top, + LS_Craft_frame + ( label, + Inv_reveal_tick {inv with revealed_bytes = Some bytes_count} + ) ); + } + | _ -> assert false (* TODO: error handling *) + (* Functions & Constants *) let invoke ~module_reg ~caller ?(input = Input_buffer.alloc ()) diff --git a/src/lib_webassembly/exec/eval.mli b/src/lib_webassembly/exec/eval.mli index 97bc4ec87234..a3deac997f60 100644 --- a/src/lib_webassembly/exec/eval.mli +++ b/src/lib_webassembly/exec/eval.mli @@ -106,6 +106,13 @@ type invoke_step_kont = func : Ast.func; concat_kont : value concat_kont; } + | Inv_reveal_tick of { + reveal : Reveal.reveal; + base_destination : int32; + max_bytes : int32; + code : code; + revealed_bytes : int32 option; + } | Inv_stop of {code : code; fresh_frame : ongoing frame_stack option} type label_step_kont = @@ -256,6 +263,15 @@ val step : buffers -> (Durable_storage.t * config) Lwt.t +val is_reveal_tick : config -> Reveal.reveal option + +(** [reveal_step module_reg payload config] loads [payload] in the + memory of the module whose function is being evaluated with [config]. + + This function can only be used when [is_reveal_tick] returns + something ({i i.e.}, not [None]). *) +val reveal_step : module_reg -> bytes -> config -> config Lwt.t + val config : Host_funcs.registry -> ?frame_arity:int32 (* The number of values returned by the computation *) -> diff --git a/src/lib_webassembly/exec/reveal.ml b/src/lib_webassembly/exec/reveal.ml new file mode 100644 index 000000000000..29e928ba5967 --- /dev/null +++ b/src/lib_webassembly/exec/reveal.ml @@ -0,0 +1,10 @@ +exception Invalid_input_hash + +type input_hash = string + +let input_hash_from_string_exn str = + if String.length str = 32 then str else raise Invalid_input_hash + +let input_hash_to_string hash = hash + +type reveal = Reveal_raw_data of input_hash diff --git a/src/lib_webassembly/exec/reveal.mli b/src/lib_webassembly/exec/reveal.mli new file mode 100644 index 000000000000..4009079b5ab8 --- /dev/null +++ b/src/lib_webassembly/exec/reveal.mli @@ -0,0 +1,10 @@ +exception Invalid_input_hash + +type input_hash + +(** @raise Invalid_input_hash *) +val input_hash_from_string_exn : string -> input_hash + +val input_hash_to_string : input_hash -> string + +type reveal = Reveal_raw_data of input_hash diff --git a/src/lib_webassembly/runtime/host_funcs.ml b/src/lib_webassembly/runtime/host_funcs.ml index 496bb3eb793a..9627916e5622 100644 --- a/src/lib_webassembly/runtime/host_funcs.ml +++ b/src/lib_webassembly/runtime/host_funcs.ml @@ -2,6 +2,8 @@ type available_memories = | No_memories_during_init | Available_memories of Instance.memory_inst Instance.Vector.t +type reveal_tick_kind = Preimage + type host_func = | Host_func of (Input_buffer.t -> @@ -10,7 +12,7 @@ type host_func = available_memories -> Values.value list -> (Durable_storage.t * Values.value list) Lwt.t) -[@@ocaml.unboxed] + | Reveal_tick of reveal_tick_kind module Registry = Map.Make (String) diff --git a/src/lib_webassembly/runtime/host_funcs.mli b/src/lib_webassembly/runtime/host_funcs.mli index fb0c44804495..65f6106238a6 100644 --- a/src/lib_webassembly/runtime/host_funcs.mli +++ b/src/lib_webassembly/runtime/host_funcs.mli @@ -3,6 +3,8 @@ type available_memories = | No_memories_during_init | Available_memories of Instance.memory_inst Instance.Vector.t +type reveal_tick_kind = Preimage + (** The type of a Host function implementation *) type host_func = | Host_func of @@ -12,7 +14,7 @@ type host_func = available_memories -> Values.value list -> (Durable_storage.t * Values.value list) Lwt.t) -[@@ocaml.unboxed] + | Reveal_tick of reveal_tick_kind (** A (mutable) host function registry *) type registry diff --git a/src/proto_015_PtLimaPt/bin_sc_rollup_node/wasm_2_0_0_pvm.ml b/src/proto_015_PtLimaPt/bin_sc_rollup_node/wasm_2_0_0_pvm.ml index 74f0ac3018ca..f341e57e1ea6 100644 --- a/src/proto_015_PtLimaPt/bin_sc_rollup_node/wasm_2_0_0_pvm.ml +++ b/src/proto_015_PtLimaPt/bin_sc_rollup_node/wasm_2_0_0_pvm.ml @@ -61,6 +61,24 @@ module Make_backend (Tree : TreeS) = struct let wrap t = PVM_tree t end) + + (* We need to deal with the introduction of new constructors post V7 + freeze. *) + let get_info tree = + let open Lwt_syntax in + let+ Tezos_scoru_wasm.Wasm_pvm_sig. + {current_tick; last_input_read; input_request} = + get_info tree + in + Environment.Wasm_2_0_0. + { + current_tick; + last_input_read; + input_request = + (match input_request with + | Reveal_required _ | No_input_required -> No_input_required + | Input_required -> Input_required); + } end module Impl : Pvm.S = struct 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 74f0ac3018ca..8b11b6e7a3be 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 @@ -69,6 +69,11 @@ module Impl : Pvm.S = struct let string_of_status : status -> string = function | Waiting_for_input_message -> "Waiting for input message" + | Waiting_for_reveal (Sc_rollup.Reveal_raw_data hash) -> + Format.asprintf + "Waiting for preimage reveal %a" + Sc_rollup.Input_hash.pp + hash | Computing -> "Computing" end diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index ee7879723dfa..13b3d6a08151 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -3395,7 +3395,10 @@ module Sc_rollup : sig val get_tick : state -> Tick.t Lwt.t - type status = Computing | Waiting_for_input_message + type status = + | Computing + | Waiting_for_input_message + | Waiting_for_reveal of reveal val get_status : state -> status Lwt.t diff --git a/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml b/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml index acb3d0a5b758..2054eade58fa 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml @@ -93,7 +93,10 @@ module V2_0_0 = struct val get_tick : state -> Sc_rollup_tick_repr.t Lwt.t (** PVM status *) - type status = Computing | Waiting_for_input_message + type status = + | Computing + | Waiting_for_input_message + | Waiting_for_reveal of Sc_rollup_PVM_sig.reveal (** [get_status state] gives you the current execution status for the PVM. *) val get_status : state -> status Lwt.t @@ -133,7 +136,10 @@ module V2_0_0 = struct type tree = Tree.tree - type status = Computing | Waiting_for_input_message + type status = + | Computing + | Waiting_for_input_message + | Waiting_for_reveal of Sc_rollup_PVM_sig.reveal module State = struct type state = tree @@ -224,6 +230,7 @@ module V2_0_0 = struct let get_status : status Monad.t = let open Monad.Syntax in + let open Sc_rollup_PVM_sig in let* s = get in let* info = lift (WASM_machine.get_info s) in return @@ -231,6 +238,16 @@ module V2_0_0 = struct match info.input_request with | No_input_required -> Computing | Input_required -> Waiting_for_input_message + | Reveal_required (Wasm_2_0_0.Reveal_raw_data hash) -> ( + match + Input_hash.of_bytes_opt + (Bytes.of_string (Wasm_2_0_0.input_hash_to_string hash)) + with + | Some hash -> Waiting_for_reveal (Reveal_raw_data hash) + | None -> + (* In case of an invalid hash, the rollup is + blocked. Any commitment will be invalid. *) + Waiting_for_reveal (Reveal_raw_data Input_hash.zero)) let get_last_message_read : _ Monad.t = let open Monad.Syntax in @@ -254,6 +271,7 @@ module V2_0_0 = struct | Some (level, n) -> return (PS.First_after (level, n)) | None -> return PS.Initial) | Computing -> return PS.No_input_required + | Waiting_for_reveal reveal -> return (PS.Needs_reveal reveal) let is_input_state = result_of is_input_state @@ -282,14 +300,11 @@ module V2_0_0 = struct s) in set s - | PS.Reveal _ -> - (* TODO: https://gitlab.com/tezos/tezos/-/issues/3754 - - The WASM PVM does not produce [Needs_reveal] input - requests. Thus, no [set_input_state] should transmit a - [Reveal_revelation]. - *) - assert false + | PS.Reveal (PS.Raw_data data) -> + let open Monad.Syntax in + let* s = get in + let* s = lift (WASM_machine.reveal_step (Bytes.of_string data) s) in + set s let set_input input = state_of @@ set_input_state input diff --git a/src/proto_alpha/lib_protocol/sc_rollup_wasm.mli b/src/proto_alpha/lib_protocol/sc_rollup_wasm.mli index c33f80431f68..20268f7c386b 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_wasm.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_wasm.mli @@ -53,7 +53,10 @@ module V2_0_0 : sig val get_tick : state -> Sc_rollup_tick_repr.t Lwt.t (** PVM status *) - type status = Computing | Waiting_for_input_message + type status = + | Computing + | Waiting_for_input_message + | Waiting_for_reveal of Sc_rollup_PVM_sig.reveal (** [get_status state] gives you the current execution status for the PVM. *) val get_status : state -> status Lwt.t diff --git a/src/proto_alpha/lib_protocol/test/integration/test_sc_rollup_wasm.ml b/src/proto_alpha/lib_protocol/test/integration/test_sc_rollup_wasm.ml index cdf4309b4d08..22fd3c35d6be 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_sc_rollup_wasm.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_sc_rollup_wasm.ml @@ -413,7 +413,7 @@ let rec eval_until_set_input context s = | Computing -> let* s = checked_eval ~loc:__LOC__ context s in eval_until_set_input context s - | Waiting_for_input_message -> return s + | Waiting_for_reveal _ | Waiting_for_input_message -> return s let should_boot_computation_kernel () = let open Lwt_result_syntax in -- GitLab From 4254700fb3a3159aba5dc9cbb8a8239e0d18c20b Mon Sep 17 00:00:00 2001 From: Pierrick Couderc Date: Fri, 23 Sep 2022 14:00:10 +0200 Subject: [PATCH 2/5] WASM: Handle Reveal tick errors --- .../test/test_wasm_pvm_encodings.ml | 28 +++++++++++++ src/lib_scoru_wasm/wasm_pvm.ml | 36 ++++++++++++---- src/lib_scoru_wasm/wasm_pvm_errors.ml | 25 ++++++++++- src/lib_webassembly/exec/eval.ml | 42 ++++++++++++++----- src/lib_webassembly/exec/eval.mli | 25 ++++++++++- 5 files changed, 136 insertions(+), 20 deletions(-) diff --git a/src/lib_scoru_wasm/test/test_wasm_pvm_encodings.ml b/src/lib_scoru_wasm/test/test_wasm_pvm_encodings.ml index 48a0aa31de23..8b1653901e16 100644 --- a/src/lib_scoru_wasm/test/test_wasm_pvm_encodings.ml +++ b/src/lib_scoru_wasm/test/test_wasm_pvm_encodings.ml @@ -58,6 +58,24 @@ let init_state_gen = let open QCheck2.Gen in oneofl [Eval.Init_step; Map_step; Map_concat_step; Join_step; Section_step] +let eval_state_gen = + let open QCheck2.Gen in + let+ msg = string in + Eval.Invoke_step msg + +let reveal_error_gen = + let open QCheck2.Gen in + let reveal_step = return Eval.Reveal_step in + let reveal_hash_decoding = + let+ raw = string in + Eval.Reveal_hash_decoding raw + in + let reveal_payload_decoding = + let+ raw = string in + Eval.Reveal_payload_decoding raw + in + oneof [reveal_step; reveal_hash_decoding; reveal_payload_decoding] + let exn_gen = let open QCheck2.Gen in let open Lazy_containers in @@ -83,6 +101,14 @@ let exn_gen = let+ state = init_state_gen in Eval.Init_step_error state in + let eval_step_error = + let+ state = eval_state_gen in + Eval.Evaluation_step_error state + in + let reveal_error = + let+ err = reveal_error_gen in + Eval.Reveal_error err + in let invalid = let+ msg = string in Valid.Invalid (Source.no_region, msg) @@ -116,6 +142,8 @@ let exn_gen = encode_error; decode_step_error; init_step_error; + eval_step_error; + reveal_error; return Lazy_map.UnexpectedAccess; return Lazy_vector.Bounds; return Lazy_vector.SizeOverflow; diff --git a/src/lib_scoru_wasm/wasm_pvm.ml b/src/lib_scoru_wasm/wasm_pvm.ml index ca8826d1affc..a40917abddc5 100644 --- a/src/lib_scoru_wasm/wasm_pvm.ml +++ b/src/lib_scoru_wasm/wasm_pvm.ml @@ -569,17 +569,39 @@ struct let open Tezos_webassembly_interpreter in let* pvm_state = Tree_encoding_runner.decode pvm_state_encoding tree in let* pvm_state = - match pvm_state.tick_state with - | Eval config -> - let+ config = Eval.reveal_step config.module_reg payload config in + let return tick_state = + Lwt.return { pvm_state with current_tick = Z.succ pvm_state.current_tick; - tick_state = Eval config; + tick_state; } - | _ -> - (* TODO: Proper error handling *) - assert false + in + match pvm_state.tick_state with + | Eval config -> + let* config = Eval.reveal_step config.module_reg payload config in + return (Eval config) + | Decode _ -> + return + (Stuck + (Wasm_pvm_errors.invalid_state + "No reveal expected during decoding")) + | Link _ -> + return + (Stuck + (Wasm_pvm_errors.invalid_state + "No reveal expected during link")) + | Init _ -> + return + (Stuck + (Wasm_pvm_errors.invalid_state + "No reveal expected during initialization")) + | Snapshot -> + return + (Stuck + (Wasm_pvm_errors.invalid_state + "No reveal expected during snapshotting")) + | Stuck _ -> return pvm_state.tick_state in Tree_encoding_runner.encode pvm_state_encoding pvm_state tree diff --git a/src/lib_scoru_wasm/wasm_pvm_errors.ml b/src/lib_scoru_wasm/wasm_pvm_errors.ml index 4ea06c4ad601..6900d4fcc02d 100644 --- a/src/lib_scoru_wasm/wasm_pvm_errors.ml +++ b/src/lib_scoru_wasm/wasm_pvm_errors.ml @@ -65,14 +65,14 @@ let decode_state_to_string_raw = function let decode_state_to_string exn = decode_state_to_string_raw exn |> truncate_message -let eval_state_to_string_raw = function +let init_state_to_string_raw = function | Eval.Init_step -> "Init_step" | Map_step -> "Map_step" | Map_concat_step -> "Map_concat_step" | Join_step -> "Join_step" | Section_step -> "Section_step" -let eval_state_to_string exn = eval_state_to_string_raw exn |> truncate_message +let init_state_to_string exn = init_state_to_string_raw exn |> truncate_message let durable_exn_explanation_raw = function | Durable.Invalid_key path -> Some ("Invalid_key: " ^ path) @@ -84,6 +84,21 @@ let durable_exn_explanation_raw = function let durable_exn_explanation exn = durable_exn_explanation_raw exn |> Option.map truncate_message +let eval_state_to_string_raw = function + | Eval.Invoke_step msg -> "Invoke_step: " ^ msg + +let eval_state_to_string exn = eval_state_to_string_raw exn |> truncate_message + +let reveal_error_to_string_raw = function + | Eval.Reveal_step -> "Reveal_step" + | Reveal_hash_decoding msg -> + Format.sprintf "Unknown error during hash decoding: %s" msg + | Reveal_payload_decoding msg -> + Format.sprintf "Unknown error during payload decoding: %s" msg + +let reveal_error_to_string exn = + reveal_error_to_string_raw exn |> truncate_message + let extract_interpreter_error exn = let open Lazy_containers in let raw_exception = Printexc.to_string exn |> truncate_message in @@ -113,8 +128,14 @@ let extract_interpreter_error exn = `Interpreter {raw_exception; explanation = Some (decode_state_to_string state)} | Eval.Init_step_error state -> + `Interpreter + {raw_exception; explanation = Some (init_state_to_string state)} + | Eval.Evaluation_step_error state -> `Interpreter {raw_exception; explanation = Some (eval_state_to_string state)} + | Eval.Reveal_error state -> + `Interpreter + {raw_exception; explanation = Some (reveal_error_to_string state)} | Eval.Missing_memory_0_export -> `Interpreter { diff --git a/src/lib_webassembly/exec/eval.ml b/src/lib_webassembly/exec/eval.ml index 5a91cf001fcd..233690d87fae 100644 --- a/src/lib_webassembly/exec/eval.ml +++ b/src/lib_webassembly/exec/eval.ml @@ -104,6 +104,10 @@ type init_state = exception Init_step_error of init_state +type eval_state = Invoke_step of string + +exception Evaluation_step_error of eval_state + let table_error at = function | Table.Bounds -> "out of bounds table access" | Table.SizeOverflow -> "table size overflow" @@ -495,7 +499,8 @@ let vmtake n vs = match n with Some n -> Vector.split vs n |> fst | None -> vs let invoke_step ~init ?(durable = Durable_storage.empty) c buffers frame at = function - | Inv_stop _ -> assert false + | Inv_stop _ -> + raise (Evaluation_step_error (Invoke_step "Inv_stop cannot reduce")) | Inv_start {func; code = vs, es} -> ( let (FuncType (ins, out)) = func_type_of func in let n1, n2 = @@ -563,8 +568,12 @@ let invoke_step ~init ?(durable = Durable_storage.empty) c buffers frame at = Reveal_raw_data (input_hash_from_string_exn hash)) ) in - (* TODO: Proper error handling. *) - assert (Vector.num_elements args = 0l) ; + if Vector.num_elements args <> 0l then + raise + (Evaluation_step_error + (Invoke_step + "The number of passed arguments to \ + \"reveal_preimage\" is inconsistent")) ; Lwt.return ( durable, Inv_reveal_tick @@ -657,7 +666,9 @@ let invoke_step ~init ?(durable = Durable_storage.empty) c buffers frame at = | Inv_reveal_tick {revealed_bytes = None; _} -> (* This is a reveal tick, not an evaluation tick. The PVM should prevent this execution path. *) - assert false + raise + (Evaluation_step_error + (Invoke_step "The reveal tick cannot be evaluated as is")) | Inv_reveal_tick {revealed_bytes = Some revealed_bytes; code; _} -> let vs, es = code in let vs = Vector.cons (Num (I32 revealed_bytes)) vs in @@ -1557,6 +1568,13 @@ let rec eval durable module_reg (c : config) buffers : let* durable, c = step ~init:false ~durable c buffers in eval durable module_reg c buffers +type reveal_error = + | Reveal_step + | Reveal_hash_decoding of string + | Reveal_payload_decoding of string + +exception Reveal_error of reveal_error + let is_reveal_tick = function | { step_kont = @@ -1575,17 +1593,21 @@ let reveal module_reg base_destination max_bytes frame payload = Lwt.catch (fun () -> let* inst = resolve_module_ref module_reg frame.inst in - let+ mem = memory inst (0l @@ no_region) in + let* mem = memory inst (0l @@ no_region) in let payload_size = Bytes.length payload in let revealed_bytes = min payload_size (Int32.to_int max_bytes) in let payload = Bytes.sub payload 0 revealed_bytes in - let _ = + let+ () = Memory.store_bytes mem base_destination (Bytes.to_string payload) in Int32.of_int revealed_bytes) - (fun _exn -> - (* TODO: error handling *) - assert false) + (function + | ( Memory.Bounds (* Memory.store_bytes *) + | Lazy_map.UnexpectedAccess (* resolve_module_ref *) ) as exn -> + raise exn + | exn -> + let raw_exn = Printexc.to_string exn in + raise (Reveal_error (Reveal_payload_decoding raw_exn))) let reveal_step module_reg payload = let open Lwt.Syntax in @@ -1618,7 +1640,7 @@ let reveal_step module_reg payload = Inv_reveal_tick {inv with revealed_bytes = Some bytes_count} ) ); } - | _ -> assert false (* TODO: error handling *) + | _ -> raise (Reveal_error Reveal_step) (* Functions & Constants *) diff --git a/src/lib_webassembly/exec/eval.mli b/src/lib_webassembly/exec/eval.mli index a3deac997f60..f151ed983c1d 100644 --- a/src/lib_webassembly/exec/eval.mli +++ b/src/lib_webassembly/exec/eval.mli @@ -36,6 +36,14 @@ type init_state = initialization. *) exception Init_step_error of init_state +(** Possible erroneous states of the small-step evaluation, used for error + reporting. *) +type eval_state = Invoke_step of string + +(** Exception raised on irreducible states of the small step + evaluation. *) +exception Evaluation_step_error of eval_state + type frame = {inst : module_key; mutable locals : value Vector.t} type admin_instr = admin_instr' Source.phrase @@ -263,13 +271,28 @@ val step : buffers -> (Durable_storage.t * config) Lwt.t +(* Possible errors raised during the reveal ticks handling. *) +type reveal_error = + | Reveal_step + | Reveal_hash_decoding of string + | Reveal_payload_decoding of string + +(* Exception encapuslating errors during reveal ticks handling. *) +exception Reveal_error of reveal_error + +(** [is_reveal_tick config] returns [Some hash] if the evalutation is + in a state expecting the payload of a given hash, and returns [None] + otherwise. *) val is_reveal_tick : config -> Reveal.reveal option (** [reveal_step module_reg payload config] loads [payload] in the memory of the module whose function is being evaluated with [config]. This function can only be used when [is_reveal_tick] returns - something ({i i.e.}, not [None]). *) + something ({i i.e.}, not [None]). + + @raise Reveal_error +*) val reveal_step : module_reg -> bytes -> config -> config Lwt.t val config : -- GitLab From e5c63688f0f49807ace251dfb52da885a0355e76 Mon Sep 17 00:00:00 2001 From: Pierrick Couderc Date: Mon, 26 Sep 2022 09:27:20 +0200 Subject: [PATCH 3/5] WASM/Test: test reveal tick --- src/lib_scoru_wasm/test/test_reveal.ml | 151 +++++++++++++++++++++ src/lib_scoru_wasm/test/test_scoru_wasm.ml | 1 + src/lib_scoru_wasm/wasm_pvm.ml | 8 ++ src/lib_scoru_wasm/wasm_pvm_sig.ml | 3 + 4 files changed, 163 insertions(+) create mode 100644 src/lib_scoru_wasm/test/test_reveal.ml diff --git a/src/lib_scoru_wasm/test/test_reveal.ml b/src/lib_scoru_wasm/test/test_reveal.ml new file mode 100644 index 000000000000..572192b57237 --- /dev/null +++ b/src/lib_scoru_wasm/test/test_reveal.ml @@ -0,0 +1,151 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 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: Lib_scoru_wasm reveal + Invocation: dune exec src/lib_scoru_wasm/test/test_scoru_wasm.exe \ + -- test "Reveal" + Subject: Reveal tests for the tezos-scoru-wasm library +*) + +open Tztest +open Tezos_webassembly_interpreter +open Tezos_scoru_wasm +open Wasm_utils + +let module_ hash_addr preimage_addr max_bytes = + Format.sprintf + {| + (module + (import "rollup_safe_core" "reveal_preimage" + (func $reveal_preimage (param i32 i32 i32) (result i32)) + ) + (memory 1) + (export "mem" (memory 0)) + (func (export "kernel_next") + (call $reveal_preimage (i32.const %ld) (i32.const %ld) (i32.const %ld)) + ) + ) + |} + hash_addr + preimage_addr + max_bytes + +let test_reveal_preimage_gen preimage max_bytes = + let open Lwt_result_syntax in + let hash_addr = 120l in + let preimage_addr = 200l in + let modl = module_ hash_addr preimage_addr max_bytes in + let*! state = initial_tree modl in + (* Let’s go *) + let*! state = eval_until_input_requested state in + let*! info = Wasm.get_info state in + let* () = + match info.Wasm_pvm_sig.input_request with + | Wasm_pvm_sig.No_input_required | Input_required -> assert false + | Reveal_required (Reveal_raw_data hash) -> + (* The PVM has reached a point where it’s asking for some + preimage. Since the memory is left blank, we are looking + for the zero hash *) + let zero_hash = + Reveal.input_hash_from_string_exn (String.make 32 '\000') + in + assert (hash = zero_hash) ; + return_unit + in + let*! state = Wasm.reveal_step (Bytes.of_string preimage) state in + let*! info = Wasm.get_info state in + let* () = + match info.Wasm_pvm_sig.input_request with + | Wasm_pvm_sig.No_input_required -> return_unit + | Input_required -> + failwith "should be running, but expect input from the L1" + | Reveal_required _ -> failwith "should be running, but expect reveal tick" + in + let*! tick_state = Wasm.Internal_for_tests.get_tick_state state in + (* The revelation step should contain the number of bytes effectively wrote in + memory for the preimage. *) + let* returned_size = + match tick_state with + | Eval + Tezos_webassembly_interpreter.Eval. + { + step_kont = + SK_Next + ( _, + _, + LS_Craft_frame + (_, Inv_reveal_tick {revealed_bytes = Some size; _}) ); + _; + } -> + return size + | _ -> failwith "The tick after reveal_step is not consistent" + in + (* Let's check the preimage in memory. *) + let*! module_instance = + Wasm.Internal_for_tests.get_module_instance_exn state + in + let*! memory = Instance.Vector.get 0l module_instance.memories in + let expected_length = min (String.length preimage) (Int32.to_int max_bytes) in + assert (returned_size = Int32.of_int expected_length) ; + let*! preimage_in_memory = + Memory.load_bytes memory preimage_addr expected_length + in + assert ( + preimage_in_memory = String.sub preimage 0 (Int32.to_int returned_size)) ; + return_unit + +(* Test the best conditions for the preimage reveal: its size is below the + maximum bytes for the preimage, it will be . *) +let test_reveal_preimage_classic () = + let preimage = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse \ + elementum nec ex sed porttitor." + (* 100 bytes *) + in + let max_bytes = 200l in + test_reveal_preimage_gen preimage max_bytes + +let test_reveal_preimage_above_max () = + let preimage = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse \ + elementum nec ex sed porttitor." + (* 100 bytes *) + in + let max_bytes = 50l in + test_reveal_preimage_gen preimage max_bytes + +let tests = + [ + tztest + "Test reveal_preimage with preimage length below max_bytes" + `Quick + test_reveal_preimage_classic; + tztest + "Test reveal_preimage with preimage length above max_bytes" + `Quick + test_reveal_preimage_above_max; + ] diff --git a/src/lib_scoru_wasm/test/test_scoru_wasm.ml b/src/lib_scoru_wasm/test/test_scoru_wasm.ml index 42affad445f1..ac721436e3c8 100644 --- a/src/lib_scoru_wasm/test/test_scoru_wasm.ml +++ b/src/lib_scoru_wasm/test/test_scoru_wasm.ml @@ -46,5 +46,6 @@ let () = ("Module Initialisation", Test_init.tests); ("Max nb of ticks", Test_fixed_nb_ticks.tests); ("Hash correspondence", Test_hash_consistency.tests); + ("Reveal", Test_reveal.tests); ] |> Lwt_main.run diff --git a/src/lib_scoru_wasm/wasm_pvm.ml b/src/lib_scoru_wasm/wasm_pvm.ml index a40917abddc5..95792306857f 100644 --- a/src/lib_scoru_wasm/wasm_pvm.ml +++ b/src/lib_scoru_wasm/wasm_pvm.ml @@ -611,6 +611,14 @@ struct let+ pvm_state = Tree_encoding_runner.decode pvm_state_encoding tree in pvm_state.tick_state + let get_module_instance_exn tree = + let open Lwt_syntax in + let* pvm_state = Tree_encoding_runner.decode pvm_state_encoding tree in + match pvm_state.tick_state with + | Eval config -> + Wasm.Instance.ModuleMap.get wasm_main_module_name config.module_reg + | _ -> raise (Invalid_argument "get_module_instance") + let is_stuck tree = let open Lwt.Syntax in let* pvm = Tree_encoding_runner.decode pvm_state_encoding tree in diff --git a/src/lib_scoru_wasm/wasm_pvm_sig.ml b/src/lib_scoru_wasm/wasm_pvm_sig.ml index 34c1c13740e3..c9b29b7b604b 100644 --- a/src/lib_scoru_wasm/wasm_pvm_sig.ml +++ b/src/lib_scoru_wasm/wasm_pvm_sig.ml @@ -68,6 +68,9 @@ module type Internal_for_tests = sig val get_tick_state : tree -> tick_state Lwt.t + val get_module_instance_exn : + tree -> Tezos_webassembly_interpreter.Instance.module_inst Lwt.t + val is_stuck : tree -> Wasm_pvm_errors.t option Lwt.t val set_max_nb_ticks : Z.t -> tree -> tree Lwt.t -- GitLab From 839d66d03d0864ac3a89d12f0cc474c279e7efaa Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Tue, 27 Sep 2022 13:25:01 +0200 Subject: [PATCH 4/5] WASM: Proposal for an alternative take on Reveal functions --- src/lib_scoru_wasm/host_funcs.ml | 12 +++++- src/lib_webassembly/exec/eval.ml | 50 +++++----------------- src/lib_webassembly/runtime/host_funcs.ml | 9 +++- src/lib_webassembly/runtime/host_funcs.mli | 9 +++- 4 files changed, 36 insertions(+), 44 deletions(-) diff --git a/src/lib_scoru_wasm/host_funcs.ml b/src/lib_scoru_wasm/host_funcs.ml index e2ba31121091..c0a8d5f8e6ba 100644 --- a/src/lib_scoru_wasm/host_funcs.ml +++ b/src/lib_scoru_wasm/host_funcs.ml @@ -411,7 +411,17 @@ let reveal_preimage_type = let output_types = Types.[NumType I32Type] |> Vector.of_list in Types.FuncType (input_types, output_types) -let reveal_preimage = Host_funcs.Reveal_tick Preimage +let reveal_preimage_parse_args memories args = + let open Lwt_syntax in + match args with + | Values.[Num (I32 hash_addr); Num (I32 base); Num (I32 max_bytes)] -> + let* memory = retrieve_memory memories in + let+ hash = Memory.load_bytes memory hash_addr 32 in + ( Reveal.(Reveal_raw_data (input_hash_from_string_exn hash)), + Host_funcs.{base; max_bytes} ) + | _ -> raise Bad_input + +let reveal_preimage = Host_funcs.Reveal_func reveal_preimage_parse_args let lookup_opt name = match name with diff --git a/src/lib_webassembly/exec/eval.ml b/src/lib_webassembly/exec/eval.ml index 233690d87fae..6694a4044add 100644 --- a/src/lib_webassembly/exec/eval.ml +++ b/src/lib_webassembly/exec/eval.ml @@ -525,62 +525,34 @@ let invoke_step ~init ?(durable = Durable_storage.empty) c buffers frame at = Lwt.catch (fun () -> let host_func = Host_funcs.lookup ~global_name c.host_funcs in + let* args = Vector.to_list args in + let args = List.rev args in + let* inst = resolve_module_ref c.module_reg frame.inst in + let available_memories = + if not init then Host_funcs.Available_memories inst.memories + else Host_funcs.No_memories_during_init + in match host_func with | Host_func f -> - let* inst = resolve_module_ref c.module_reg frame.inst in - let* args = Vector.to_list args in - let available_memories = - if not init then Host_funcs.Available_memories inst.memories - else Host_funcs.No_memories_during_init - in let+ durable, res = f buffers.input buffers.output durable available_memories - (List.rev args) + args in let vs' = Vector.prepend_list res vs' in (durable, Inv_stop {code = (vs', es); fresh_frame = None}) - | Reveal_tick kind -> - (* Reminder: the arguments are put on a stack, and must be - read in reverse order from the function definition. *) - let* max_bytes, args = - vector_pop_map args num_i32 no_region - in - let* base_destination, args = - vector_pop_map args num_i32 no_region - in - let* args, reveal = - match kind with - | Preimage -> - let* offset, args = - vector_pop_map args num_i32 no_region - in - let* inst = - resolve_module_ref c.module_reg frame.inst - in - let* mem = memory inst (0l @@ no_region) in - let+ hash = Memory.load_bytes mem offset 32 in - ( args, - Reveal.( - Reveal_raw_data (input_hash_from_string_exn hash)) - ) - in - if Vector.num_elements args <> 0l then - raise - (Evaluation_step_error - (Invoke_step - "The number of passed arguments to \ - \"reveal_preimage\" is inconsistent")) ; + | Reveal_func f -> + let* reveal, {base; max_bytes} = f available_memories args in Lwt.return ( durable, Inv_reveal_tick { reveal; max_bytes; - base_destination; + base_destination = base; code = (vs', es); revealed_bytes = None; } )) diff --git a/src/lib_webassembly/runtime/host_funcs.ml b/src/lib_webassembly/runtime/host_funcs.ml index 9627916e5622..2456ebae0bf9 100644 --- a/src/lib_webassembly/runtime/host_funcs.ml +++ b/src/lib_webassembly/runtime/host_funcs.ml @@ -2,7 +2,12 @@ type available_memories = | No_memories_during_init | Available_memories of Instance.memory_inst Instance.Vector.t -type reveal_tick_kind = Preimage +type reveal_destination = {base : int32; max_bytes : int32} + +type reveal_func = + available_memories -> + Values.value list -> + (Reveal.reveal * reveal_destination) Lwt.t type host_func = | Host_func of @@ -12,7 +17,7 @@ type host_func = available_memories -> Values.value list -> (Durable_storage.t * Values.value list) Lwt.t) - | Reveal_tick of reveal_tick_kind + | 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 65f6106238a6..046c63a3a44c 100644 --- a/src/lib_webassembly/runtime/host_funcs.mli +++ b/src/lib_webassembly/runtime/host_funcs.mli @@ -3,7 +3,12 @@ type available_memories = | No_memories_during_init | Available_memories of Instance.memory_inst Instance.Vector.t -type reveal_tick_kind = Preimage +type reveal_destination = {base : int32; max_bytes : int32} + +type reveal_func = + available_memories -> + Values.value list -> + (Reveal.reveal * reveal_destination) Lwt.t (** The type of a Host function implementation *) type host_func = @@ -14,7 +19,7 @@ type host_func = available_memories -> Values.value list -> (Durable_storage.t * Values.value list) Lwt.t) - | Reveal_tick of reveal_tick_kind + | Reveal_func of reveal_func (** A (mutable) host function registry *) type registry -- GitLab From c55c8579a8c1bc5dec45064a5826c60b4f8cd6c5 Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Wed, 28 Sep 2022 13:41:13 +0200 Subject: [PATCH 5/5] WASM: Save one tick for the reveal functions --- src/lib_scoru_wasm/test/ast_generators.ml | 4 +--- src/lib_scoru_wasm/test/ast_printer.ml | 6 +---- src/lib_scoru_wasm/test/test_reveal.ml | 13 +++++------ src/lib_scoru_wasm/wasm_encoding.ml | 26 +++++----------------- src/lib_webassembly/exec/eval.ml | 27 +++++------------------ src/lib_webassembly/exec/eval.mli | 1 - 6 files changed, 20 insertions(+), 57 deletions(-) diff --git a/src/lib_scoru_wasm/test/ast_generators.ml b/src/lib_scoru_wasm/test/ast_generators.ml index c00478785740..8c583ad177e8 100644 --- a/src/lib_scoru_wasm/test/ast_generators.ml +++ b/src/lib_scoru_wasm/test/ast_generators.ml @@ -767,15 +767,13 @@ let inv_reveal_tick ~module_reg = let* base_destination = Int32.of_int <$> small_nat in let* max_bytes = Int32.of_int <$> small_nat in let* vs = small_vector_gen value_gen in - let* es = small_vector_gen (admin_instr_gen ~module_reg) in - let+ revealed_bytes = option int32 in + let+ es = small_vector_gen (admin_instr_gen ~module_reg) in Eval.Inv_reveal_tick { reveal = Reveal_raw_data hash; base_destination; max_bytes; code = (vs, es); - revealed_bytes; } let inv_stop_gen ~module_reg = diff --git a/src/lib_scoru_wasm/test/ast_printer.ml b/src/lib_scoru_wasm/test/ast_printer.ml index 54950c5c5aa5..5334da8b8876 100644 --- a/src/lib_scoru_wasm/test/ast_printer.ml +++ b/src/lib_scoru_wasm/test/ast_printer.ml @@ -512,14 +512,12 @@ let pp_invoke_step_kont out = function func (pp_concat_kont Values.pp_value) concat_kont - | Inv_reveal_tick - {reveal; base_destination; max_bytes; code = vs, es; revealed_bytes} -> + | Inv_reveal_tick {reveal; base_destination; max_bytes; code = vs, es} -> Format.fprintf out "@[Inv_reveal_tick {instructions = %a;@;\ values = %a;@;\ reveal = %a;@;\ - revealed_bytes = %a;@;\ base_destination = %ld;@;\ max_bytes = %ld;@;\ }@]" @@ -529,8 +527,6 @@ let pp_invoke_step_kont out = function vs pp_reveal reveal - (pp_opt pp_int32) - revealed_bytes base_destination max_bytes | Inv_stop {code = vs, es; fresh_frame} -> diff --git a/src/lib_scoru_wasm/test/test_reveal.ml b/src/lib_scoru_wasm/test/test_reveal.ml index 572192b57237..d24816bd9b28 100644 --- a/src/lib_scoru_wasm/test/test_reveal.ml +++ b/src/lib_scoru_wasm/test/test_reveal.ml @@ -94,14 +94,13 @@ let test_reveal_preimage_gen preimage max_bytes = Tezos_webassembly_interpreter.Eval. { step_kont = - SK_Next - ( _, - _, - LS_Craft_frame - (_, Inv_reveal_tick {revealed_bytes = Some size; _}) ); + SK_Next (_, _, LS_Craft_frame (_, Inv_stop {code = vs, _; _})); _; - } -> - return size + } -> ( + let*! hd = Lazy_containers.Lazy_vector.Int32Vector.get 0l vs in + match hd with + | Num (I32 size) -> return size + | _ -> failwith "Incorrect stack") | _ -> failwith "The tick after reveal_step is not consistent" in (* Let's check the preimage in memory. *) diff --git a/src/lib_scoru_wasm/wasm_encoding.ml b/src/lib_scoru_wasm/wasm_encoding.ml index 122c1ea9dc07..6e8aa05d8dbc 100644 --- a/src/lib_scoru_wasm/wasm_encoding.ml +++ b/src/lib_scoru_wasm/wasm_encoding.ml @@ -1088,34 +1088,20 @@ let invoke_step_kont_encoding = Inv_concat {arity; vs; instructions; inst; func; concat_kont}); case "Inv_reveal_tick" - (tup6 + (tup5 ~flatten:true (scope ["reveal"] reveal_encoding) (value ["base_destination"] Data_encoding.int32) (value ["max_bytes"] Data_encoding.int32) (lazy_vector_encoding "values" value_encoding) - (lazy_vector_encoding "instructions" admin_instr_encoding) - (option (value ["revealed_bytes"] Data_encoding.int32))) + (lazy_vector_encoding "instructions" admin_instr_encoding)) (function | Eval.Inv_reveal_tick - { - reveal; - base_destination; - max_bytes; - code = vs, es; - revealed_bytes; - } -> - Some (reveal, base_destination, max_bytes, vs, es, revealed_bytes) + {reveal; base_destination; max_bytes; code = vs, es} -> + Some (reveal, base_destination, max_bytes, vs, es) | _ -> None) - (fun (reveal, base_destination, max_bytes, vs, es, revealed_bytes) -> - Inv_reveal_tick - { - reveal; - base_destination; - max_bytes; - code = (vs, es); - revealed_bytes; - }); + (fun (reveal, base_destination, max_bytes, vs, es) -> + Inv_reveal_tick {reveal; base_destination; max_bytes; code = (vs, es)}); case "Inv_stop" (tup3 diff --git a/src/lib_webassembly/exec/eval.ml b/src/lib_webassembly/exec/eval.ml index 6694a4044add..337d8fcb4bf6 100644 --- a/src/lib_webassembly/exec/eval.ml +++ b/src/lib_webassembly/exec/eval.ml @@ -359,7 +359,6 @@ type invoke_step_kont = base_destination : int32; max_bytes : int32; code : code; - revealed_bytes : int32 option; } | Inv_stop of {code : code; fresh_frame : ongoing frame_stack option} @@ -554,7 +553,6 @@ let invoke_step ~init ?(durable = Durable_storage.empty) c buffers frame at = max_bytes; base_destination = base; code = (vs', es); - revealed_bytes = None; } )) (function Crash (_, msg) -> Crash.error at msg | exn -> raise exn)) | Inv_prepare_locals @@ -635,16 +633,12 @@ let invoke_step ~init ?(durable = Durable_storage.empty) c buffers frame at = }; }; } ) - | Inv_reveal_tick {revealed_bytes = None; _} -> + | Inv_reveal_tick _ -> (* This is a reveal tick, not an evaluation tick. The PVM should prevent this execution path. *) raise (Evaluation_step_error (Invoke_step "The reveal tick cannot be evaluated as is")) - | Inv_reveal_tick {revealed_bytes = Some revealed_bytes; code; _} -> - let vs, es = code in - let vs = Vector.cons (Num (I32 revealed_bytes)) vs in - Lwt.return (durable, Inv_stop {code = (vs, es); fresh_frame = None}) | Inv_concat tick -> let+ concat_kont = concat_step tick.concat_kont in (durable, Inv_concat {tick with concat_kont}) @@ -1549,12 +1543,7 @@ exception Reveal_error of reveal_error let is_reveal_tick = function | { - step_kont = - SK_Next - ( _, - _, - LS_Craft_frame - (_, Inv_reveal_tick {reveal; revealed_bytes = None; _}) ); + step_kont = SK_Next (_, _, LS_Craft_frame (_, Inv_reveal_tick {reveal; _})); _; } -> Some reveal @@ -1586,11 +1575,7 @@ let reveal_step module_reg payload = function | { step_kont = - SK_Next - ( frame, - top, - LS_Craft_frame - (label, Inv_reveal_tick ({revealed_bytes = None; _} as inv)) ); + SK_Next (frame, top, LS_Craft_frame (label, Inv_reveal_tick inv)); _; } as config -> let+ bytes_count = @@ -1601,6 +1586,8 @@ let reveal_step module_reg payload = frame.frame_specs payload in + let vs, es = inv.code in + let vs = Vector.cons (Num (I32 bytes_count)) vs in { config with step_kont = @@ -1608,9 +1595,7 @@ let reveal_step module_reg payload = ( frame, top, LS_Craft_frame - ( label, - Inv_reveal_tick {inv with revealed_bytes = Some bytes_count} - ) ); + (label, Inv_stop {code = (vs, es); fresh_frame = None}) ); } | _ -> raise (Reveal_error Reveal_step) diff --git a/src/lib_webassembly/exec/eval.mli b/src/lib_webassembly/exec/eval.mli index f151ed983c1d..82537c535b2d 100644 --- a/src/lib_webassembly/exec/eval.mli +++ b/src/lib_webassembly/exec/eval.mli @@ -119,7 +119,6 @@ type invoke_step_kont = base_destination : int32; max_bytes : int32; code : code; - revealed_bytes : int32 option; } | Inv_stop of {code : code; fresh_frame : ongoing frame_stack option} -- GitLab