diff --git a/manifest/main.ml b/manifest/main.ml index 66fe6814cfdfc86991e493889b2dfe4807de98ae..f73d8b1c975a84408edcec724e92fc663fe6f754 100644 --- a/manifest/main.ml +++ b/manifest/main.ml @@ -3662,6 +3662,7 @@ end = struct alcotest_lwt; octez_stdlib |> if_ N.(number >= 013) |> open_; octez_crypto_dal |> if_ N.(number >= 016) |> open_; + octez_scoru_wasm; ] ~dune: Dune. diff --git a/opam/tezos-protocol-014-PtKathma-tests.opam b/opam/tezos-protocol-014-PtKathma-tests.opam index 8fb0acd86afe485146bc85e4f48fd04199f69166..c01c61d3ef37c6a54a0897152162c33065c2b6f1 100644 --- a/opam/tezos-protocol-014-PtKathma-tests.opam +++ b/opam/tezos-protocol-014-PtKathma-tests.opam @@ -28,6 +28,7 @@ depends: [ "tezos-protocol-environment" {with-test} "tezos-stdlib-unix" {with-test} "tezos-stdlib" {with-test} + "tezos-scoru-wasm" {with-test} "tezt" {with-test} "tezt-tezos" {with-test} ] diff --git a/opam/tezos-protocol-015-PtLimaPt-tests.opam b/opam/tezos-protocol-015-PtLimaPt-tests.opam index da3ce07382dff3aaad2e8c58715e8e8409378fb1..8454dcbc1ecc2efdd505833bf4cde0eccbeba6a8 100644 --- a/opam/tezos-protocol-015-PtLimaPt-tests.opam +++ b/opam/tezos-protocol-015-PtLimaPt-tests.opam @@ -29,6 +29,7 @@ depends: [ "tezos-protocol-environment" {with-test} "tezos-stdlib-unix" {with-test} "tezos-stdlib" {with-test} + "tezos-scoru-wasm" {with-test} "tezt-tezos" {with-test} ] build: [ diff --git a/opam/tezos-protocol-alpha-tests.opam b/opam/tezos-protocol-alpha-tests.opam index 0b2d0e29dcbedb95068f3565d557c917062530c5..f92f66d77d145862aa1a99cd5306578e6fc6c32b 100644 --- a/opam/tezos-protocol-alpha-tests.opam +++ b/opam/tezos-protocol-alpha-tests.opam @@ -31,6 +31,7 @@ depends: [ "tezos-protocol-environment" {with-test} "tezos-stdlib-unix" {with-test} "tezos-stdlib" {with-test} + "tezos-scoru-wasm" {with-test} "tezt-tezos" {with-test} ] build: [ diff --git a/src/lib_protocol_environment/environment_V8.ml b/src/lib_protocol_environment/environment_V8.ml index 9102916ead49afb8149d08a6ca205641db8cb8ff..ab364121bfa6f8fc2594158db62328716c10e707 100644 --- a/src/lib_protocol_environment/environment_V8.ml +++ b/src/lib_protocol_environment/environment_V8.ml @@ -1062,6 +1062,7 @@ struct type reveal = Tezos_scoru_wasm.Wasm_pvm_state.reveal = | Reveal_raw_data of input_hash + | Reveal_metadata type input_request = Tezos_scoru_wasm.Wasm_pvm_state.input_request = | No_input_required diff --git a/src/lib_protocol_environment/sigs/v8.ml b/src/lib_protocol_environment/sigs/v8.ml index b22d772383c902770b19cc121e4cdc844afc249a..88224440817f3ae87c3d21bd163859a31e280871 100644 --- a/src/lib_protocol_environment/sigs/v8.ml +++ b/src/lib_protocol_environment/sigs/v8.ml @@ -11769,7 +11769,7 @@ type input_hash val input_hash_to_string : input_hash -> string -type reveal = Reveal_raw_data of input_hash +type reveal = Reveal_raw_data of input_hash | Reveal_metadata type input_request = | No_input_required 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 6a460f5db68b60e7f4a4f422a7c579f290ed8548..942c6ba615e5c21f044e81d7581ab4fd99186343 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 @@ -31,7 +31,7 @@ type input_hash val input_hash_to_string : input_hash -> string -type reveal = Reveal_raw_data of input_hash +type reveal = Reveal_raw_data of input_hash | Reveal_metadata type input_request = | No_input_required diff --git a/src/lib_scoru_wasm/host_funcs.ml b/src/lib_scoru_wasm/host_funcs.ml index 22f8853cba5dddc07554a62707bb19e7a4749a25..d77b21833281f1fd9d6c4a2a4ec1bf22ba1de8cf 100644 --- a/src/lib_scoru_wasm/host_funcs.ml +++ b/src/lib_scoru_wasm/host_funcs.ml @@ -622,17 +622,12 @@ let store_read = (durable, [Values.(Num (I32 len))]) | _ -> 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_name = "tezos_reveal_preimage" let reveal_preimage_type = - let input_types = reveal_args Types.[NumType I32Type] |> Vector.of_list in + let input_types = + Types.[NumType I32Type; NumType I32Type; NumType I32Type] |> Vector.of_list + in let output_types = Types.[NumType I32Type] |> Vector.of_list in Types.FuncType (input_types, output_types) @@ -648,6 +643,26 @@ let reveal_preimage_parse_args memories args = let reveal_preimage = Host_funcs.Reveal_func reveal_preimage_parse_args +let reveal_metadata_name = "tezos_reveal_metadata" + +let reveal_metadata_type = + let input_types = Types.[NumType I32Type] |> Vector.of_list in + let output_types = Types.[NumType I32Type] |> Vector.of_list in + Types.FuncType (input_types, output_types) + +(* The rollup address is a 20-byte hash. The origination level is + a 4-byte (32bit) integer. *) +let metadata_size = Int32.add 20l 4l + +let reveal_metadata_parse_args _memories args = + match args with + | Values.[Num (I32 base)] -> + Lwt.return + (Reveal.Reveal_metadata, Host_funcs.{base; max_bytes = metadata_size}) + | _ -> raise Bad_input + +let reveal_metadata = Host_funcs.Reveal_func reveal_metadata_parse_args + let store_write_name = "tezos_write_read" let store_write_type = @@ -717,6 +732,8 @@ let lookup_opt name = (ExternFunc (HostFunc (store_value_size_type, store_value_size_name))) | "reveal_preimage" -> Some (ExternFunc (HostFunc (reveal_preimage_type, reveal_preimage_name))) + | "reveal_metadata" -> + Some (ExternFunc (HostFunc (reveal_metadata_type, reveal_metadata_name))) | "store_read" -> Some (ExternFunc (HostFunc (store_read_type, store_read_name))) | "store_write" -> @@ -743,11 +760,14 @@ let register_host_funcs registry = (store_move_name, store_move); (store_value_size_name, store_value_size); (reveal_preimage_name, reveal_preimage); + (reveal_metadata_name, reveal_metadata); (store_read_name, store_read); (store_write_name, store_write); ] module Internal_for_tests = struct + let metadata_size = Int32.to_int metadata_size + let write_output = Func.HostFunc (write_output_type, write_output_name) let read_input = Func.HostFunc (read_input_type, read_input_name) diff --git a/src/lib_scoru_wasm/host_funcs.mli b/src/lib_scoru_wasm/host_funcs.mli index f1f76db3e1418c7f10542769fd8ded5edbf3a19f..8431770c9c9fb151889843b861b0aa2445ddfb2e 100644 --- a/src/lib_scoru_wasm/host_funcs.mli +++ b/src/lib_scoru_wasm/host_funcs.mli @@ -183,6 +183,9 @@ module Aux : sig end module Internal_for_tests : sig + (** The number of bytes used to store the metadata of a rollup in memory *) + val metadata_size : int + val write_output : Tezos_webassembly_interpreter.Instance.func_inst val read_input : Tezos_webassembly_interpreter.Instance.func_inst diff --git a/src/lib_scoru_wasm/test/ast_printer.ml b/src/lib_scoru_wasm/test/ast_printer.ml index b0e56e8562572f486d8aac518c0307720a2a9b5b..235f23b3a987ca071633ed83a2edabef07d3dc46 100644 --- a/src/lib_scoru_wasm/test/ast_printer.ml +++ b/src/lib_scoru_wasm/test/ast_printer.ml @@ -430,6 +430,7 @@ let pp_reveal out = function out "Reveal_raw_data (%s)" (Reveal.input_hash_to_string hash) + | Reveal_metadata -> Format.fprintf out "Reveal_metadata" let pp_invoke_step_kont out = function | Eval.Inv_start {func; code = vs, es} -> diff --git a/src/lib_scoru_wasm/test/test_reveal.ml b/src/lib_scoru_wasm/test/test_reveal.ml index 9e075edd02b0fac4e9c93ce2d2e66a6b6492063d..9864dc5e79b9be770890e2214f41b815b97f7a97 100644 --- a/src/lib_scoru_wasm/test/test_reveal.ml +++ b/src/lib_scoru_wasm/test/test_reveal.ml @@ -36,7 +36,7 @@ open Tezos_webassembly_interpreter open Tezos_scoru_wasm open Wasm_utils -let module_ hash_addr preimage_addr max_bytes = +let reveal_preimage_module hash_addr preimage_addr max_bytes = Format.sprintf {| (module @@ -54,11 +54,44 @@ let module_ hash_addr preimage_addr max_bytes = preimage_addr max_bytes +let reveal_metadata_module metadata_addr = + Format.sprintf + {| + (module + (import "rollup_safe_core" "reveal_metadata" + (func $reveal_metadata (param i32) (result i32)) + ) + (memory 1) + (export "mem" (memory 0)) + (func (export "kernel_next") + (call $reveal_metadata (i32.const %ld)) + ) + ) + |} + metadata_addr + +let reveal_returned_size tree = + let open Lwt_syntax in + let* tick_state = Wasm.Internal_for_tests.get_tick_state tree in + match tick_state with + | Eval + Tezos_webassembly_interpreter.Eval. + { + step_kont = + SK_Next (_, _, LS_Craft_frame (_, Inv_stop {code = vs, _; _})); + _; + } -> ( + let* hd = Tezos_lazy_containers.Lazy_vector.Int32Vector.get 0l vs in + match hd with + | Num (I32 size) -> return size + | _ -> Stdlib.failwith "Incorrect stack") + | _ -> Stdlib.failwith "The tick after reveal_step is not consistent" + 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 modl = reveal_preimage_module hash_addr preimage_addr max_bytes in let*! state = initial_tree modl in let*! state_snapshotted = eval_until_input_requested state in let*! state_with_dummy_input = @@ -69,9 +102,8 @@ let test_reveal_preimage_gen preimage max_bytes = let*! info = Wasm.get_info state in let* () = let open Wasm_pvm_state in - match info.input_request with - | No_input_required | Input_required -> assert false - | Reveal_required (Reveal_raw_data hash) -> + match info.Wasm_pvm_state.input_request with + | Wasm_pvm_state.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 *) @@ -80,6 +112,7 @@ let test_reveal_preimage_gen preimage max_bytes = in assert (hash = zero_hash) ; return_unit + | No_input_required | Input_required | Reveal_required _ -> assert false in let*! state = Wasm.reveal_step (Bytes.of_string preimage) state in let*! info = Wasm.get_info state in @@ -91,24 +124,9 @@ let test_reveal_preimage_gen preimage max_bytes = 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_stop {code = vs, _; _})); - _; - } -> ( - let*! hd = Tezos_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*! returned_size = reveal_returned_size state in (* Let's check the preimage in memory. *) let*! module_instance = Wasm.Internal_for_tests.get_module_instance_exn state @@ -143,6 +161,56 @@ let test_reveal_preimage_above_max () = let max_bytes = 50l in test_reveal_preimage_gen preimage max_bytes +let test_reveal_metadata () = + let open Lwt_result_syntax in + let metadata_addr = 200l in + let modl = reveal_metadata_module metadata_addr in + let*! state = initial_tree modl in + let*! state_snapshotted = eval_until_input_requested state in + let*! state_with_dummy_input = + set_input_step "dummy_input" 0 state_snapshotted + in + (* Let’s go *) + let*! state = eval_until_input_requested state_with_dummy_input in + let*! info = Wasm.get_info state in + let* () = + match info.Wasm_pvm_state.input_request with + | Wasm_pvm_state.Reveal_required Reveal_metadata -> return_unit + | No_input_required | Input_required | Reveal_required _ -> assert false + in + (* These are dummy metadata since we do not have access to the + metadata definition in this compilation unit. *) + let metadata = + Bytes.init + Tezos_scoru_wasm.Host_funcs.Internal_for_tests.metadata_size + Char.chr + in + let*! state = Wasm.reveal_step metadata state in + let*! info = Wasm.get_info state in + let* () = + match info.Wasm_pvm_state.input_request with + | Wasm_pvm_state.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 + (* The revelation step should contain the number of bytes effectively wrote in + memory for the preimage. *) + let*! returned_size = reveal_returned_size state 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 + assert ( + Int32.to_int returned_size + = Tezos_scoru_wasm.Host_funcs.Internal_for_tests.metadata_size) ; + let*! preimage_in_memory = + Memory.load_bytes memory metadata_addr (Int32.to_int returned_size) + in + assert (preimage_in_memory = Bytes.to_string metadata) ; + return_unit + let tests = [ tztest @@ -153,4 +221,5 @@ let tests = "Test reveal_preimage with preimage length above max_bytes" `Quick test_reveal_preimage_above_max; + tztest "Test reveal_metadata" `Quick test_reveal_metadata; ] diff --git a/src/lib_scoru_wasm/wasm_encoding.ml b/src/lib_scoru_wasm/wasm_encoding.ml index d84b609033b869ed8fa86c5f71800fcbd0e949d3..1bcd78b0fb0a4203c85a645529812bc8039bd827 100644 --- a/src/lib_scoru_wasm/wasm_encoding.ml +++ b/src/lib_scoru_wasm/wasm_encoding.ml @@ -1000,8 +1000,13 @@ let reveal_encoding = case "Reveal_raw_data" input_hash_encoding - (function Reveal.Reveal_raw_data hash -> Some hash) + (function Reveal.Reveal_raw_data hash -> Some hash | _ -> None) (fun hash -> Reveal_raw_data hash); + case + "Reveal_metadata" + (value [] Data_encoding.unit) + (function Reveal.Reveal_metadata -> Some () | _ -> None) + (fun () -> Reveal_metadata); ] let invoke_step_kont_encoding = diff --git a/src/lib_scoru_wasm/wasm_pvm_state.ml b/src/lib_scoru_wasm/wasm_pvm_state.ml index d494d25fbe483d40e129f238fd6b5eeac7bfc5dc..f20b9d8baa135c9f860bc628d62802971c71bacd 100644 --- a/src/lib_scoru_wasm/wasm_pvm_state.ml +++ b/src/lib_scoru_wasm/wasm_pvm_state.ml @@ -45,6 +45,7 @@ let input_hash_to_string = type reveal = Tezos_webassembly_interpreter.Reveal.reveal = | Reveal_raw_data of Tezos_webassembly_interpreter.Reveal.input_hash + | Reveal_metadata (** Represents the state of input requests. *) type input_request = diff --git a/src/lib_webassembly/exec/reveal.ml b/src/lib_webassembly/exec/reveal.ml index 29e928ba5967468ad51bb160e9108a43514c696c..995a96c58180bb27c9bec345935be6aeb7396123 100644 --- a/src/lib_webassembly/exec/reveal.ml +++ b/src/lib_webassembly/exec/reveal.ml @@ -7,4 +7,4 @@ let input_hash_from_string_exn str = let input_hash_to_string hash = hash -type reveal = Reveal_raw_data of input_hash +type reveal = Reveal_raw_data of input_hash | Reveal_metadata diff --git a/src/lib_webassembly/exec/reveal.mli b/src/lib_webassembly/exec/reveal.mli index 4009079b5ab855c3778cf73cab6d7e84b9bbc71d..ffa1002a8f248efef48c94a04eff81387f807fc6 100644 --- a/src/lib_webassembly/exec/reveal.mli +++ b/src/lib_webassembly/exec/reveal.mli @@ -7,4 +7,4 @@ 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 +type reveal = Reveal_raw_data of input_hash | Reveal_metadata diff --git a/src/proto_014_PtKathma/lib_protocol/test/unit/dune b/src/proto_014_PtKathma/lib_protocol/test/unit/dune index 6ad9182be73b12e8940dd3484547163fef99defb..4f92db0c6328c3544b86c4d21d684eefbd9dea28 100644 --- a/src/proto_014_PtKathma/lib_protocol/test/unit/dune +++ b/src/proto_014_PtKathma/lib_protocol/test/unit/dune @@ -15,7 +15,8 @@ tezos-protocol-014-PtKathma tezos-014-PtKathma-test-helpers alcotest-lwt - tezos-stdlib) + tezos-stdlib + tezos-scoru-wasm) (flags (:standard) -open Tezos_base.TzPervasives diff --git a/src/proto_015_PtLimaPt/lib_protocol/test/unit/dune b/src/proto_015_PtLimaPt/lib_protocol/test/unit/dune index b2903e0c97ba52089feb34d07526eee5c06251a5..ff801623ee1fa08a56c0ce09b5ea22ab5e5a12ad 100644 --- a/src/proto_015_PtLimaPt/lib_protocol/test/unit/dune +++ b/src/proto_015_PtLimaPt/lib_protocol/test/unit/dune @@ -15,7 +15,8 @@ tezos-protocol-015-PtLimaPt tezos-015-PtLimaPt-test-helpers alcotest-lwt - tezos-stdlib) + tezos-stdlib + tezos-scoru-wasm) (flags (:standard) -open Tezos_base.TzPervasives diff --git a/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml b/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml index f6f9a3e79dc9ef4f6607fefc1707aa9e1206ea0b..e2ab200a4aed423fd0a94009153a8820c31486e9 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml @@ -248,6 +248,8 @@ module V2_0_0 = struct (* In case of an invalid hash, the rollup is blocked. Any commitment will be invalid. *) Waiting_for_reveal (Reveal_raw_data Input_hash.zero)) + | Reveal_required Wasm_2_0_0.Reveal_metadata -> + Waiting_for_reveal Reveal_metadata let get_last_message_read : _ Monad.t = let open Monad.Syntax in @@ -283,10 +285,10 @@ module V2_0_0 = struct return [] let set_input_state input = + let open Monad.Syntax in match input with | PS.Inbox_message input -> let open PS in - let open Monad.Syntax in let {inbox_level; message_counter; payload} = input in let* s = get in let* s = @@ -301,18 +303,18 @@ module V2_0_0 = struct in set s | 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 - | PS.Reveal (PS.Metadata _) -> - (* TODO: https://gitlab.com/tezos/tezos/-/issues/3890 - - The WASM PVM does not produce [Needs_metadata] input - requests. Thus, no [set_input_state] should transmit a - [Metadata]. - *) - assert false + | PS.Reveal (PS.Metadata metadata) -> + let metadata_bytes = + Data_encoding.Binary.to_bytes_exn + Sc_rollup_metadata_repr.encoding + metadata + in + let* s = get in + let* s = lift (WASM_machine.reveal_step metadata_bytes s) in + set s let set_input input = state_of @@ set_input_state input diff --git a/src/proto_alpha/lib_protocol/test/unit/dune b/src/proto_alpha/lib_protocol/test/unit/dune index 7fabcf75d5e7548659e09da594a43aa14f734190..cc9f541a60600a32f4f52b49131223e52e28e6f1 100644 --- a/src/proto_alpha/lib_protocol/test/unit/dune +++ b/src/proto_alpha/lib_protocol/test/unit/dune @@ -16,7 +16,8 @@ tezos-alpha-test-helpers alcotest-lwt tezos-stdlib - tezos-crypto-dal) + tezos-crypto-dal + tezos-scoru-wasm) (flags (:standard) -open Tezos_base.TzPervasives diff --git a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_wasm.ml b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_wasm.ml index 0630ecc37e0d0992c82ef31d14909f6d6804d9ee..7fc39d919daa7c6dc86ba53d2da4f2104023ae63 100644 --- a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_wasm.ml +++ b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_wasm.ml @@ -34,9 +34,9 @@ *) open Protocol -open Alpha_context let test_initial_state_hash_wasm_pvm () = + let open Alpha_context in let open Lwt_result_syntax in let context = Tezos_context_memory.make_empty_context () in let*! state = Sc_rollup_helpers.Wasm_pvm.initial_state context in @@ -72,6 +72,19 @@ let test_incomplete_kernel_chunk_limit () = | None -> return_unit | Some _ -> failwith "encoding of a floppy with a chunk too large should fail" +let test_metadata_size () = + let address = Sc_rollup_repr.Address.of_bytes_exn (Bytes.make 20 '\000') in + let metadata = + Sc_rollup_metadata_repr.{address; origination_level = Raw_level_repr.root} + in + let bytes = + Data_encoding.Binary.to_bytes_exn Sc_rollup_metadata_repr.encoding metadata + in + assert ( + Bytes.length bytes + = Tezos_scoru_wasm.Host_funcs.Internal_for_tests.metadata_size) ; + Lwt_result_syntax.return_unit + let tests = [ Tztest.tztest @@ -82,4 +95,5 @@ let tests = "encoding of a floppy with a chunk too large should fail" `Quick test_incomplete_kernel_chunk_limit; + Tztest.tztest "size of a rollup metadata" `Quick test_metadata_size; ]