From ca829f0a460693fe54313cab4347eff434438f7b Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Thu, 8 Sep 2022 11:03:34 +0200 Subject: [PATCH 1/3] WASM: Meta admin instructions --- src/lib_scoru_wasm/test/ast_generators.ml | 58 ++++ src/lib_scoru_wasm/test/ast_printer.ml | 69 ++++ src/lib_scoru_wasm/wasm_encoding.ml | 85 +++++ src/lib_webassembly/exec/eval.ml | 317 +++++++++++------- src/lib_webassembly/exec/eval.mli | 6 + .../test/integration/test_sc_rollup_wasm.ml | 2 +- 6 files changed, 411 insertions(+), 126 deletions(-) diff --git a/src/lib_scoru_wasm/test/ast_generators.ml b/src/lib_scoru_wasm/test/ast_generators.ml index bddd5fec7575..52118898ddfe 100644 --- a/src/lib_scoru_wasm/test/ast_generators.ml +++ b/src/lib_scoru_wasm/test/ast_generators.ml @@ -552,6 +552,58 @@ let rec admin_instr'_gen ~module_reg = let+ values = small_vector_gen value_gen in Breaking (index, values) in + let table_init_meta_gen = + let* idx = int32 in + let* value = ref_gen in + let* d = int32 in + let* s = int32 in + let* n = int32 in + let* x = var_gen in + let+ y = var_gen in + Table_init_meta (idx, value, d, s, n, x, y) + in + let table_fill_meta_gen = + let* idx = int32 in + let* i = int32 in + let* n = int32 in + let* r = ref_gen in + let+ x = var_gen in + Table_fill_meta (idx, i, n, r, x) + in + let table_copy_meta_gen = + let* idx = int32 in + let* d = int32 in + let* s = int32 in + let* n = int32 in + let* x = var_gen in + let* y = var_gen in + let+ case = bool in + Table_copy_meta (idx, d, s, n, x, y, case) + in + let memory_init_meta_gen = + let* idx = int32 in + let* d = int32 in + let* b = int32 in + let* n = int32 in + let* s = int32 in + let+ x = var_gen in + Memory_init_meta (idx, d, b, n, s, x) + in + let memory_fill_meta_gen = + let* idx = int32 in + let* i = int32 in + let* k = num_gen in + let+ n = int32 in + Memory_fill_meta (idx, i, k.it, n) + in + let memory_copy_meta_instr = + let* idx = int32 in + let* d = int32 in + let* s = int32 in + let* n = int32 in + let+ case = bool in + Memory_copy_meta (idx, d, s, n, case) + in oneof [ from_block_gen; @@ -561,6 +613,12 @@ let rec admin_instr'_gen ~module_reg = trapping_gen; returning_gen; breaking_gen; + table_init_meta_gen; + table_fill_meta_gen; + table_copy_meta_gen; + memory_init_meta_gen; + memory_fill_meta_gen; + memory_copy_meta_instr; ] and admin_instr_gen ~module_reg = diff --git a/src/lib_scoru_wasm/test/ast_printer.ml b/src/lib_scoru_wasm/test/ast_printer.ml index 9b304133b6cc..b0562c2b7d3d 100644 --- a/src/lib_scoru_wasm/test/ast_printer.ml +++ b/src/lib_scoru_wasm/test/ast_printer.ml @@ -284,6 +284,75 @@ let rec pp_admin_instr' out instr = index (pp_vector Values.pp_value) values + | Table_init_meta (idx, value, d, s, n, x, y) -> + Format.fprintf + out + "@[Table_init_meta (%ld, %a, %ld, %ld, %ld, %a, %a)@]" + idx + Values.pp_ref_ + value + d + s + n + Ast.pp_var + x + Ast.pp_var + y + | Table_fill_meta (idx, i, n, r, x) -> + Format.fprintf + out + "@[Table_fill_meta (%ld, %ld, %ld, %a, %a)@]" + idx + i + n + Values.pp_ref_ + r + Ast.pp_var + x + | Table_copy_meta (idx, d, s, n, x, y, case) -> + Format.fprintf + out + "@[Table_copy_meta (%ld, %ld, %ld, %ld, %a, %a, %a)@]" + idx + d + s + n + Ast.pp_var + x + Ast.pp_var + y + Format.pp_print_bool + case + | Memory_init_meta (idx, d, b, n, s, x) -> + Format.fprintf + out + "@[Memory_init_meta (%ld, %ld, %ld, %ld, %ld, %a)@]" + idx + d + b + n + s + Ast.pp_var + x + | Memory_fill_meta (idx, i, k, n) -> + Format.fprintf + out + "@[Memory_fill_meta (%ld, %ld, %a, %ld)@]" + idx + i + Values.pp_num + k + n + | Memory_copy_meta (idx, d, s, n, case) -> + Format.fprintf + out + "@[Memory_copy_meta (%ld, %ld, %ld, %ld, %a)@]" + idx + d + s + n + Format.pp_print_bool + case and pp_admin_instr out instr = pp_admin_instr' out instr.Source.it diff --git a/src/lib_scoru_wasm/wasm_encoding.ml b/src/lib_scoru_wasm/wasm_encoding.ml index d46908071c80..dc7bd6c17ae4 100644 --- a/src/lib_scoru_wasm/wasm_encoding.ml +++ b/src/lib_scoru_wasm/wasm_encoding.ml @@ -778,6 +778,91 @@ let rec admin_instr'_encoding () = (function | Breaking (index, values) -> Some (index, values) | _ -> None) (fun (index, values) -> Breaking (index, values)); + case + "Table_init_meta" + (tup7 + ~flatten:false + (value [] Data_encoding.int32) + value_ref_encoding + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Interpreter_encodings.Ast.var_encoding) + (value [] Interpreter_encodings.Ast.var_encoding)) + (function + | Table_init_meta (idx, value, d, s, n, x, y) -> + Some (idx, value, d, s, n, x, y) + | _ -> None) + (fun (idx, value, d, s, n, x, y) -> + Table_init_meta (idx, value, d, s, n, x, y)); + case + "Table_fill_meta" + (tup5 + ~flatten:false + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + value_ref_encoding + (value [] Interpreter_encodings.Ast.var_encoding)) + (function + | Table_fill_meta (idx, i, n, r, x) -> Some (idx, i, n, r, x) + | _ -> None) + (fun (idx, i, n, r, x) -> Table_fill_meta (idx, i, n, r, x)); + case + "Table_copy_meta" + (tup7 + ~flatten:false + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Interpreter_encodings.Ast.var_encoding) + (value [] Interpreter_encodings.Ast.var_encoding) + (value [] Data_encoding.bool)) + (function + | Table_copy_meta (idx, d, s, n, x, y, case) -> + Some (idx, d, s, n, x, y, case) + | _ -> None) + (fun (idx, d, s, n, x, y, case) -> + Table_copy_meta (idx, d, s, n, x, y, case)); + case + "Memory_init_meta" + (tup6 + ~flatten:false + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Interpreter_encodings.Ast.var_encoding)) + (function + | Memory_init_meta (idx, d, b, n, s, x) -> Some (idx, d, b, n, s, x) + | _ -> None) + (fun (idx, d, b, n, s, x) -> Memory_init_meta (idx, d, b, n, s, x)); + case + "Memory_fill_meta" + (tup4 + ~flatten:false + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Interpreter_encodings.Values.num_encoding) + (value [] Data_encoding.int32)) + (function + | Memory_fill_meta (idx, i, k, n) -> Some (idx, i, k, n) | _ -> None) + (fun (idx, i, k, n) -> Memory_fill_meta (idx, i, k, n)); + case + "Memory_copy_meta" + (tup5 + ~flatten:false + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Data_encoding.int32) + (value [] Data_encoding.bool)) + (function + | Memory_copy_meta (idx, d, s, n, case) -> Some (idx, d, s, n, case) + | _ -> None) + (fun (idx, d, s, n, case) -> Memory_copy_meta (idx, d, s, n, case)); ] and admin_instr_encoding () = diff --git a/src/lib_webassembly/exec/eval.ml b/src/lib_webassembly/exec/eval.ml index 65ee0a79c573..ef79175ec021 100644 --- a/src/lib_webassembly/exec/eval.ml +++ b/src/lib_webassembly/exec/eval.ml @@ -146,6 +146,156 @@ and admin_instr' = | Trapping of string | Returning of value Vector.t | Breaking of int32 * value Vector.t + | Table_init_meta of int32 * ref_ * int32 * int32 * int32 * var * var + | Table_fill_meta of int32 * int32 * int32 * ref_ * var + | Table_copy_meta of int32 * int32 * int32 * int32 * var * var * bool + | Memory_init_meta of int32 * int32 * int32 * int32 * int32 * var + | Memory_fill_meta of int32 * int32 * Values.num * int32 + | Memory_copy_meta of int32 * int32 * int32 * int32 * bool + +let table_init_meta_instr idx value d s n x y at = + let instrs = + [ + Plain (Const (I32 d @@ at)); + Refer value; + Plain (TableSet x); + Plain (Const (I32 (I32.add d 1l) @@ at)); + Plain (Const (I32 (I32.add s 1l) @@ at)); + Plain (Const (I32 (I32.sub n 1l) @@ at)); + Plain (TableInit (x, y)); + ] + in + match List.nth_opt instrs (Int32.to_int idx) with + | Some instr -> + ( instr @@ at, + if List.length instrs <= Int32.to_int idx + 1 then None + else Some (Table_init_meta (Int32.succ idx, value, d, s, n, x, y) @@ at) + ) + | None -> raise (Invalid_argument "table_fill_meta_instr") + +let table_fill_meta_instr idx i n r x at = + let instrs = + [ + Plain (Const (I32 i @@ at)); + Refer r; + Plain (TableSet x); + Plain (Const (I32 (I32.add i 1l) @@ at)); + Refer r; + Plain (Const (I32 (I32.sub n 1l) @@ at)); + Plain (TableFill x); + ] + in + match List.nth_opt instrs (Int32.to_int idx) with + | Some instr -> + ( instr @@ at, + if List.length instrs <= Int32.to_int idx + 1 then None + else Some (Table_fill_meta (Int32.succ idx, i, n, r, x) @@ at) ) + | None -> raise (Invalid_argument "table_fill_meta_instr") + +let table_copy_meta_instr idx d s n x y case at = + let instrs = + if case then + [ + Plain (Const (I32 d @@ at)); + Plain (Const (I32 s @@ at)); + Plain (TableGet y); + Plain (TableSet x); + Plain (Const (I32 (I32.add d 1l) @@ at)); + Plain (Const (I32 (I32.add s 1l) @@ at)); + Plain (Const (I32 (I32.sub n 1l) @@ at)); + Plain (TableCopy (x, y)); + ] + else + [ + Plain (Const (I32 (I32.add d 1l) @@ at)); + Plain (Const (I32 (I32.add s 1l) @@ at)); + Plain (Const (I32 (I32.sub n 1l) @@ at)); + Plain (TableCopy (x, y)); + Plain (Const (I32 d @@ at)); + Plain (Const (I32 s @@ at)); + Plain (TableGet y); + Plain (TableSet x); + ] + in + match List.nth_opt instrs (Int32.to_int idx) with + | Some instr -> + ( instr @@ at, + if List.length instrs <= Int32.to_int idx + 1 then None + else Some (Table_copy_meta (Int32.succ idx, d, s, n, x, y, case) @@ at) + ) + | None -> raise (Invalid_argument "table_copy_meta_instr") + +let memory_init_meta_instr idx d b n s x at = + let instrs = + [ + Plain (Const (I32 d @@ at)); + Plain (Const (I32 b @@ at)); + Plain (Store {ty = I32Type; align = 0; offset = 0l; pack = Some Pack8}); + Plain (Const (I32 (I32.add d 1l) @@ at)); + Plain (Const (I32 (I32.add s 1l) @@ at)); + Plain (Const (I32 (I32.sub n 1l) @@ at)); + Plain (MemoryInit x); + ] + in + match List.nth_opt instrs (Int32.to_int idx) with + | Some instr -> + ( instr @@ at, + if List.length instrs <= Int32.to_int idx + 1 then None + else Some (Memory_init_meta (Int32.succ idx, d, b, n, s, x) @@ at) ) + | None -> raise (Invalid_argument "memory_init_meta_instr") + +let memory_fill_meta_instr idx i k n at = + let instrs = + [ + Plain (Const (I32 i @@ at)); + Plain (Const (k @@ at)); + Plain (Store {ty = I32Type; align = 0; offset = 0l; pack = Some Pack8}); + Plain (Const (I32 (I32.add i 1l) @@ at)); + Plain (Const (k @@ at)); + Plain (Const (I32 (I32.sub n 1l) @@ at)); + Plain MemoryFill; + ] + in + match List.nth_opt instrs (Int32.to_int idx) with + | Some instr -> + ( instr @@ at, + if List.length instrs <= Int32.to_int idx + 1 then None + else Some (Memory_fill_meta (Int32.succ idx, i, k, n) @@ at) ) + | None -> raise (Invalid_argument "memory_init_meta_instr") + +let memory_copy_meta_instr idx d s n case at = + let instrs = + if case then + [ + Plain (Const (I32 d @@ at)); + Plain (Const (I32 s @@ at)); + Plain + (Load {ty = I32Type; align = 0; offset = 0l; pack = Some (Pack8, ZX)}); + Plain (Store {ty = I32Type; align = 0; offset = 0l; pack = Some Pack8}); + Plain (Const (I32 (I32.add d 1l) @@ at)); + Plain (Const (I32 (I32.add s 1l) @@ at)); + Plain (Const (I32 (I32.sub n 1l) @@ at)); + Plain MemoryCopy; + ] + else + [ + Plain (Const (I32 (I32.add d 1l) @@ at)); + Plain (Const (I32 (I32.add s 1l) @@ at)); + Plain (Const (I32 (I32.sub n 1l) @@ at)); + Plain MemoryCopy; + Plain (Const (I32 d @@ at)); + Plain (Const (I32 s @@ at)); + Plain + (Load {ty = I32Type; align = 0; offset = 0l; pack = Some (Pack8, ZX)}); + Plain (Store {ty = I32Type; align = 0; offset = 0l; pack = Some Pack8}); + ] + in + match List.nth_opt instrs (Int32.to_int idx) with + | Some instr -> + ( instr @@ at, + if List.length instrs <= Int32.to_int idx + 1 then None + else Some (Memory_copy_meta (Int32.succ idx, d, s, n, case) @@ at) ) + | None -> raise (Invalid_argument "memory_copy_meta_instr") type code = value Vector.t * admin_instr Vector.t @@ -692,19 +842,7 @@ let step_instr module_reg label vs at e' es_rst stack : 'a label_kont Lwt.t = else if n = 0l then label_kont_with_code vs' [] else let _ = assert (I32.lt_u i 0xffff_ffffl) in - label_kont_with_code - vs' - (List.map - (Source.at at) - [ - Plain (Const (I32 i @@ at)); - Refer r; - Plain (TableSet x); - Plain (Const (I32 (I32.add i 1l) @@ at)); - Refer r; - Plain (Const (I32 (I32.sub n 1l) @@ at)); - Plain (TableFill x); - ]) + label_kont_with_code vs' [Table_fill_meta (0l, i, n, r, x) @@ at] | TableCopy (x, y) -> (* Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' *) let* n, vs = vector_pop_map vs num_i32 at in @@ -717,32 +855,9 @@ let step_instr module_reg label vs at e' es_rst stack : 'a label_kont Lwt.t = (if oob_d || oob_s then [Trapping (table_error at Table.Bounds) @@ at] else if n = 0l then [] else if I32.le_u d s then - List.map - (Source.at at) - [ - Plain (Const (I32 d @@ at)); - Plain (Const (I32 s @@ at)); - Plain (TableGet y); - Plain (TableSet x); - Plain (Const (I32 (I32.add d 1l) @@ at)); - Plain (Const (I32 (I32.add s 1l) @@ at)); - Plain (Const (I32 (I32.sub n 1l) @@ at)); - Plain (TableCopy (x, y)); - ] - else - (* d > s *) - List.map - (Source.at at) - [ - Plain (Const (I32 (I32.add d 1l) @@ at)); - Plain (Const (I32 (I32.add s 1l) @@ at)); - Plain (Const (I32 (I32.sub n 1l) @@ at)); - Plain (TableCopy (x, y)); - Plain (Const (I32 d @@ at)); - Plain (Const (I32 s @@ at)); - Plain (TableGet y); - Plain (TableSet x); - ]) + [Table_copy_meta (0l, d, s, n, x, y, true) @@ at] + else (* d > s *) + [Table_copy_meta (0l, d, s, n, x, y, false) @@ at]) | TableInit (x, y) -> (* Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' *) let* n, vs = vector_pop_map vs num_i32 at in @@ -761,21 +876,7 @@ let step_instr module_reg label vs at e' es_rst stack : 'a label_kont Lwt.t = let+ value = Instance.Vector.get s !seg in label_kont_with_code vs' - (List.map - (Source.at at) - [ - Plain (Const (I32 d @@ at)); - (* Note, the [Instance.Vector.get] is logarithmic in the number of - contained elements in [seg]. However, in a scenario where the PVM - runs, only the element that will be looked up is in the map - making the look up cheap. *) - Refer value; - Plain (TableSet x); - Plain (Const (I32 (I32.add d 1l) @@ at)); - Plain (Const (I32 (I32.add s 1l) @@ at)); - Plain (Const (I32 (I32.sub n 1l) @@ at)); - Plain (TableInit (x, y)); - ]) + [Table_init_meta (0l, value, d, s, n, x, y) @@ at] | ElemDrop x -> let* inst = resolve_module_ref module_reg frame.inst in let+ seg = elem inst x in @@ -937,19 +1038,7 @@ let step_instr module_reg label vs at e' es_rst stack : 'a label_kont Lwt.t = vs' (if oob then [Trapping (memory_error at Memory.Bounds) @@ at] else if n = 0l then [] - else - List.map - (Source.at at) - [ - Plain (Const (I32 i @@ at)); - Plain (Const (k @@ at)); - Plain - (Store {ty = I32Type; align = 0; offset = 0l; pack = Some Pack8}); - Plain (Const (I32 (I32.add i 1l) @@ at)); - Plain (Const (k @@ at)); - Plain (Const (I32 (I32.sub n 1l) @@ at)); - Plain MemoryFill; - ]) + else [Memory_fill_meta (0l, i, k, n) @@ at]) | MemoryCopy -> (* Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' *) let* n, vs = vector_pop_map vs num_i32 at in @@ -961,49 +1050,9 @@ let step_instr module_reg label vs at e' es_rst stack : 'a label_kont Lwt.t = vs' (if oob_s || oob_d then [Trapping (memory_error at Memory.Bounds) @@ at] else if n = 0l then [] - else if I32.le_u d s then - List.map - (Source.at at) - [ - Plain (Const (I32 d @@ at)); - Plain (Const (I32 s @@ at)); - Plain - (Load - { - ty = I32Type; - align = 0; - offset = 0l; - pack = Some (Pack8, ZX); - }); - Plain - (Store {ty = I32Type; align = 0; offset = 0l; pack = Some Pack8}); - Plain (Const (I32 (I32.add d 1l) @@ at)); - Plain (Const (I32 (I32.add s 1l) @@ at)); - Plain (Const (I32 (I32.sub n 1l) @@ at)); - Plain MemoryCopy; - ] - else - (* d > s *) - List.map - (Source.at at) - [ - Plain (Const (I32 (I32.add d 1l) @@ at)); - Plain (Const (I32 (I32.add s 1l) @@ at)); - Plain (Const (I32 (I32.sub n 1l) @@ at)); - Plain MemoryCopy; - Plain (Const (I32 d @@ at)); - Plain (Const (I32 s @@ at)); - Plain - (Load - { - ty = I32Type; - align = 0; - offset = 0l; - pack = Some (Pack8, ZX); - }); - Plain - (Store {ty = I32Type; align = 0; offset = 0l; pack = Some Pack8}); - ]) + else if I32.le_u d s then [Memory_copy_meta (0l, d, s, n, true) @@ at] + else (* d > s *) + [Memory_copy_meta (0l, d, s, n, false) @@ at]) | MemoryInit x -> (* Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' *) let* n, vs = vector_pop_map vs num_i32 at in @@ -1022,21 +1071,7 @@ let step_instr module_reg label vs at e' es_rst stack : 'a label_kont Lwt.t = let* seg = Ast.get_data !seg inst.allocations.datas in let+ b = Chunked_byte_vector.load_byte seg (Int64.of_int32 s) in let b = Int32.of_int b in - label_kont_with_code - vs' - (List.map - (Source.at at) - [ - Plain (Const (I32 d @@ at)); - Plain (Const (I32 b @@ at)); - Plain - (Store - {ty = I32Type; align = 0; offset = 0l; pack = Some Pack8}); - Plain (Const (I32 (I32.add d 1l) @@ at)); - Plain (Const (I32 (I32.add s 1l) @@ at)); - Plain (Const (I32 (I32.sub n 1l) @@ at)); - Plain (MemoryInit x); - ]) + label_kont_with_code vs' [Memory_init_meta (0l, d, b, n, s, x) @@ at] | DataDrop x -> let* inst = resolve_module_ref module_reg frame.inst in let+ seg = data inst x in @@ -1237,6 +1272,18 @@ let step_instr module_reg label vs at e' es_rst stack : 'a label_kont Lwt.t = with exn -> label_kont_with_code vs' [Trapping (numeric_error at exn) @@ at]) +(* This function is used to implement the logic of the “meta” + instruction for memory and memory manipulation. *) +let push_admin_instr label es vs instr next stack = + LS_Modify_top + (Label_stack + ( { + label with + label_code = + (vs, Vector.prepend_list (instr :: Option.to_list next) es); + }, + stack )) + let label_step : Durable_storage.t -> module_reg -> @@ -1327,6 +1374,26 @@ let label_step : (LS_Craft_frame ( Label_stack (label, stack), Inv_start {func; code = (vs, es)} )) + | Table_init_meta (idx, value, d, s, n, x, y) -> + let instr, next = + table_init_meta_instr idx value d s n x y e.at + in + Lwt.return (push_admin_instr label es vs instr next stack) + | Table_fill_meta (idx, i, n, r, x) -> + let instr, next = table_fill_meta_instr idx i n r x e.at in + Lwt.return (push_admin_instr label es vs instr next stack) + | Table_copy_meta (idx, d, s, n, y, x, case) -> + let instr, next = table_copy_meta_instr idx d s n y x case e.at in + Lwt.return (push_admin_instr label es vs instr next stack) + | Memory_init_meta (idx, d, b, n, s, x) -> + let instr, next = memory_init_meta_instr idx d b n s x e.at in + Lwt.return (push_admin_instr label es vs instr next stack) + | Memory_fill_meta (idx, i, k, n) -> + let instr, next = memory_fill_meta_instr idx i k n e.at in + Lwt.return (push_admin_instr label es vs instr next stack) + | Memory_copy_meta (idx, d, s, n, case) -> + let instr, next = memory_copy_meta_instr idx d s n case e.at in + Lwt.return (push_admin_instr label es vs instr next stack) in (durable, kont) else if Vector.num_elements stack = 0l then diff --git a/src/lib_webassembly/exec/eval.mli b/src/lib_webassembly/exec/eval.mli index 473c9ffde0c3..ac3d200f8fa6 100644 --- a/src/lib_webassembly/exec/eval.mli +++ b/src/lib_webassembly/exec/eval.mli @@ -48,6 +48,12 @@ and admin_instr' = | Trapping of string | Returning of value Vector.t | Breaking of int32 * value Vector.t + | Table_init_meta of int32 * ref_ * int32 * int32 * int32 * Ast.var * Ast.var + | Table_fill_meta of int32 * int32 * int32 * ref_ * Ast.var + | Table_copy_meta of int32 * int32 * int32 * int32 * Ast.var * Ast.var * bool + | Memory_init_meta of int32 * int32 * int32 * int32 * int32 * Ast.var + | Memory_fill_meta of int32 * int32 * Values.num * int32 + | Memory_copy_meta of int32 * int32 * int32 * int32 * bool type code = value Vector.t * admin_instr Vector.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 7bcb0f61f788..d2662cb46e56 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 @@ -124,7 +124,7 @@ module Prover = Alpha_context.Sc_rollup.Wasm_2_0_0PVM.Make (WASM_P) pass. It should be updated to [16 * 1024] once the small ticks milestone is completed. *) -let proof_size_limit = 21_550 +let proof_size_limit = 21_542 let check_proof_size ~loc context input_opt s = let open Lwt_result_syntax in -- GitLab From d0af297e58b4d4a9f337ccab366e15bd494d1881 Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Mon, 12 Sep 2022 22:02:56 +0200 Subject: [PATCH 2/3] Lazy_containers: Shrink the chunks to reduce the size of the proofs From 4,096 up to 512. In certain circumstances, we have to read more than one page, which could take a toll on proof size. With this, most of the proof we are able to observe are lesser than 8KBytes. --- src/lib_lazy_containers/chunked_byte_vector.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib_lazy_containers/chunked_byte_vector.ml b/src/lib_lazy_containers/chunked_byte_vector.ml index 873a7e67e29d..f7cc56c7968d 100644 --- a/src/lib_lazy_containers/chunked_byte_vector.ml +++ b/src/lib_lazy_containers/chunked_byte_vector.ml @@ -52,9 +52,10 @@ module Chunk = struct type t = (int, int8_unsigned_elt, c_layout) Array1.t (** Number of bits in an address for the chunk offset *) - let offset_bits = 12 + let offset_bits = 9 - (** Size of a chunk in bytes - with 12 bits of address space the chunk is 4KiB *) + (** Size of a chunk in bytes - with 9 bits of address space the + chunk is 512 bytes *) let size = Int64.shift_left 1L offset_bits (** Get the chunk index for an address. *) @@ -221,9 +222,8 @@ let to_bytes vector = (* The last chunk (at `length - 1`) is not necessarily of size [Chunk.size], i.e. if the length of the chunked_byte_vector is not a multiple of [Chunk.size]. *) - if index >= Int64.pred chunks_number then - Int64.rem vector.length Chunk.size - else Chunk.size + let r = Int64.rem vector.length Chunk.size in + if index >= Int64.pred chunks_number && r <> 0L then r else Chunk.size in for offset = 0 to Int64.to_int rem - 1 do let address = -- GitLab From fc3b1ecdd3df1d912477481f18e8e4ed00bba78e Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Mon, 12 Sep 2022 22:05:04 +0200 Subject: [PATCH 3/3] Lazy_containers: Do not store default chunks when calling 'grow' This was a source of unboundness. --- src/lib_lazy_containers/chunked_byte_vector.ml | 10 +++++----- .../test/chunked_byte_vector_tests.ml | 9 +-------- .../test/integration/test_sc_rollup_wasm.ml | 9 ++------- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/lib_lazy_containers/chunked_byte_vector.ml b/src/lib_lazy_containers/chunked_byte_vector.ml index f7cc56c7968d..9e86469feb94 100644 --- a/src/lib_lazy_containers/chunked_byte_vector.ml +++ b/src/lib_lazy_containers/chunked_byte_vector.ml @@ -119,10 +119,7 @@ let grow vector size_delta = error in case of absent value (which is the case when growing the chunked byte vector requires to allocate new chunks). *) - Vector.grow - ~default:(fun () -> Chunk.alloc ()) - chunk_count_delta - vector.chunks ; + Vector.grow chunk_count_delta vector.chunks ; vector.length <- new_size) let allocate length = @@ -133,7 +130,10 @@ let allocate length = let length vector = vector.length let get_chunk index {chunks; _} = - Lwt.catch (fun () -> Vector.get index chunks) reraise + Lwt.catch + (fun () -> Vector.get index chunks) + (function + | Lazy_vector.Bounds as exn -> reraise exn | _ -> def_get_chunk ()) let set_chunk index chunk {chunks; _} = try Vector.set index chunk chunks with exn -> reraise exn diff --git a/src/lib_lazy_containers/test/chunked_byte_vector_tests.ml b/src/lib_lazy_containers/test/chunked_byte_vector_tests.ml index 737f6e13b80e..9c81cf621d20 100644 --- a/src/lib_lazy_containers/test/chunked_byte_vector_tests.ml +++ b/src/lib_lazy_containers/test/chunked_byte_vector_tests.ml @@ -94,14 +94,7 @@ let can_write_after_grow = chunk of [vector], that was filled in the process. *) let init_size = Int64.(sub chunk_size 100L) in let vector = - create - ~get_chunk:(function - | 0L -> - Lwt.return - (Chunked_byte_vector.Chunk.of_bytes - @@ Bytes.make (Int64.to_int chunk_size) 'a') - | _otherwise -> assert false) - init_size + of_string (String.make (Int64.to_int chunk_size - 100) 'a') in let* v = load_byte vector 0L in assert (v = Char.code 'a') ; 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 d2662cb46e56..9192eddef123 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 @@ -118,13 +118,8 @@ module Prover = Alpha_context.Sc_rollup.Wasm_2_0_0PVM.Make (WASM_P) If #2198 is addressed, and a constant is added to the protocol to limit the maximum size of a valid SCORU proof, then the value here - should reflect that. - - The size set here is the minimum size that makes the current tests - pass. It should be updated to [16 * 1024] once the small ticks - milestone is completed. -*) -let proof_size_limit = 21_542 + should reflect that. *) +let proof_size_limit = 16 * 1024 let check_proof_size ~loc context input_opt s = let open Lwt_result_syntax in -- GitLab