From fd98756c578292ce2b79a464100aa06133940622 Mon Sep 17 00:00:00 2001 From: Valentin Chaboche Date: Tue, 8 Nov 2022 14:17:25 +0100 Subject: [PATCH 1/3] Scoru,Proto: expose utility functions --- src/proto_alpha/lib_protocol/alpha_context.mli | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index aebebe920ef3..13a69ba6733a 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -3239,6 +3239,10 @@ module Sc_rollup : sig type history_proof + val equal_history_proof : history_proof -> history_proof -> bool + + val pp_history_proof : Format.formatter -> history_proof -> unit + module Hash : sig include S.HASH -- GitLab From a866b017ff59415d6c5b270a7fd4d2cf2d167bb7 Mon Sep 17 00:00:00 2001 From: Valentin Chaboche Date: Mon, 24 Oct 2022 16:14:38 +0200 Subject: [PATCH 2/3] Scoru,Test: extract full-history inboxes to helpers --- .../test/helpers/sc_rollup_helpers.ml | 99 +++++++++++++++++ .../test/pbt/test_refutation_game.ml | 105 +----------------- 2 files changed, 105 insertions(+), 99 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/helpers/sc_rollup_helpers.ml b/src/proto_alpha/lib_protocol/test/helpers/sc_rollup_helpers.ml index 6317349bacd3..d588feb4155a 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/sc_rollup_helpers.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/sc_rollup_helpers.ml @@ -423,3 +423,102 @@ let gen_message_reprs_for_levels_repr ~start_level ~max_level gen_message_repr = assert false in aux [] (max_level - start_level) + +module Tree_inbox = struct + open Sc_rollup.Inbox + module Store = Tezos_context_memory.Context + + module Tree = struct + include Store.Tree + + type tree = Store.tree + + type t = Store.t + + type key = string list + + type value = bytes + end + + type t = Store.t + + type tree = Tree.tree + + let commit_tree store key tree = + let open Lwt_syntax in + let* store = Store.add_tree store key tree in + let* (_ : Context_hash.t) = Store.commit ~time:Time.Protocol.epoch store in + return () + + let lookup_tree store hash = + let open Lwt_syntax in + let index = Store.index store in + let* _, tree = + Store.produce_tree_proof + index + (`Node (Hash.to_context_hash hash)) + (fun x -> Lwt.return (x, x)) + in + return (Some tree) + + type proof = Store.Proof.tree Store.Proof.t + + let verify_proof proof f = + Lwt.map Result.to_option (Store.verify_tree_proof proof f) + + let produce_proof store tree f = + let open Lwt_syntax in + let index = Store.index store in + let* proof = Store.produce_tree_proof index (`Node (Tree.hash tree)) f in + return (Some proof) + + let kinded_hash_to_inbox_hash = function + | `Value hash | `Node hash -> Hash.of_context_hash hash + + let proof_before proof = kinded_hash_to_inbox_hash proof.Store.Proof.before + + let proof_encoding = + Tezos_context_merkle_proof_encoding.Merkle_proof_encoding.V1.Tree32 + .tree_proof_encoding +end + +module Store_inbox = struct + include Sc_rollup.Inbox.Make_hashing_scheme (Tree_inbox) +end + +(* TODO: https://gitlab.com/tezos/tezos/-/issues/3529 + + Factor code for the unit test. + this and {!Store_inbox} is highly copy-pasted from + test/unit/test_sc_rollup_inbox. The main difference is: we use + [Alpha_context.Sc_rollup.Inbox] instead of [Sc_rollup_repr_inbox] in the + former. *) +let construct_inbox ~inbox ?origination_level ctxt levels_and_messages = + let open Lwt_syntax in + let open Store_inbox in + let history = Sc_rollup.Inbox.History.empty ~capacity:10000L in + let rec aux history inbox level_tree = function + | [] -> return (ctxt, level_tree, history, inbox) + | ((level, messages) : Raw_level.t * message list) :: rst -> + assert ( + match origination_level with + | Some origination_level -> Raw_level.(origination_level < level) + | None -> true) ; + let payloads = + List.map + (fun {input; _} -> + match input with + | Inbox_message {payload; _} -> payload + | Reveal _ -> (* We don't produce any reveals. *) assert false) + messages + in + let* res = + add_messages ctxt history inbox level payloads level_tree + >|= Environment.wrap_tzresult + in + let level_tree, history, inbox = + WithExceptions.Result.get_ok ~loc:__LOC__ res + in + aux history inbox (Some level_tree) rst + in + aux history inbox None levels_and_messages diff --git a/src/proto_alpha/lib_protocol/test/pbt/test_refutation_game.ml b/src/proto_alpha/lib_protocol/test/pbt/test_refutation_game.ml index 697a606fd7f7..aa62f034622e 100644 --- a/src/proto_alpha/lib_protocol/test/pbt/test_refutation_game.ml +++ b/src/proto_alpha/lib_protocol/test/pbt/test_refutation_game.ml @@ -51,9 +51,6 @@ let qcheck_make_lwt_res ?print ?count ~name ~gen f = ~gen (fun a -> Lwt_main.run (f a)) -(** Lift a computation using environment errors to use shell errors. *) -let lift k = Lwt.map Environment.wrap_tzresult k - let tick_to_int_exn ?(__LOC__ = __LOC__) t = WithExceptions.Option.get ~loc:__LOC__ (Tick.to_int t) @@ -787,68 +784,7 @@ end (** {2. ArithPVM utils} *) module ArithPVM = Arith_pvm - -module Tree_inbox = struct - open Inbox - module Store = Tezos_context_memory.Context - - module Tree = struct - include Store.Tree - - type tree = Store.tree - - type t = Store.t - - type key = string list - - type value = bytes - end - - type t = Store.t - - type tree = Tree.tree - - let commit_tree store key tree = - let open Lwt_syntax in - let* store = Store.add_tree store key tree in - let* (_ : Context_hash.t) = Store.commit ~time:Time.Protocol.epoch store in - return () - - let lookup_tree store hash = - let open Lwt_syntax in - let index = Store.index store in - let* _, tree = - Store.produce_tree_proof - index - (`Node (Hash.to_context_hash hash)) - (fun x -> Lwt.return (x, x)) - in - return (Some tree) - - type proof = Store.Proof.tree Store.Proof.t - - let verify_proof proof f = - Lwt.map Result.to_option (Store.verify_tree_proof proof f) - - let produce_proof store tree f = - let open Lwt_syntax in - let index = Store.index store in - let* proof = Store.produce_tree_proof index (`Node (Tree.hash tree)) f in - return (Some proof) - - let kinded_hash_to_inbox_hash = function - | `Value hash | `Node hash -> Hash.of_context_hash hash - - let proof_before proof = kinded_hash_to_inbox_hash proof.Store.Proof.before - - let proof_encoding = - Tezos_context_merkle_proof_encoding.Merkle_proof_encoding.V1.Tree32 - .tree_proof_encoding -end - -module Store_inbox = struct - include Inbox.Make_hashing_scheme (Tree_inbox) -end +module Store_inbox = Sc_rollup_helpers.Store_inbox module Arith_test_pvm = struct include ArithPVM @@ -1102,43 +1038,14 @@ module Player_client = struct @@ let+ index = Tezos_context_memory.Context.init id in Tezos_context_memory.Context.empty index - (* TODO: https://gitlab.com/tezos/tezos/-/issues/3529 - - Factor code for the unit test. - this and {!Store_inbox} is highly copy-pasted from - test/unit/test_sc_rollup_inbox. The main difference is: we use - [Alpha_context.Sc_rollup.Inbox] instead of [Sc_rollup_repr_inbox] in the - former. *) - let construct_inbox ~inbox ctxt levels_and_messages ~origination_level = - let open Lwt_syntax in - let open Store_inbox in - let history = Inbox.History.empty ~capacity:10000L in - let rec aux history inbox level_tree = function - | [] -> return (ctxt, level_tree, history, inbox) - | ((level, messages) : Raw_level.t * message list) :: rst -> - assert (Raw_level.(origination_level < level)) ; - let payloads = - List.map - (fun {input; _} -> - match input with - | Inbox_message {payload; _} -> payload - | Reveal _ -> (* We don't produce any reveals. *) assert false) - messages - in - let* res = - lift @@ add_messages ctxt history inbox level payloads level_tree - in - let level_tree, history, inbox = - WithExceptions.Result.get_ok ~loc:__LOC__ res - in - aux history inbox (Some level_tree) rst - in - aux history inbox None levels_and_messages - (** Construct an inbox based on [levels_and_messages] in the player context. *) let construct_inbox ~inbox ~origination_level ctxt levels_and_messages = Lwt_main.run - @@ construct_inbox ~inbox ~origination_level ctxt levels_and_messages + @@ Sc_rollup_helpers.construct_inbox + ~inbox + ~origination_level + ctxt + levels_and_messages (** Generate [our_states] for [levels_and_messages] based on the strategy. It needs [start_level] and [max_level] in case it will need to generate -- GitLab From 3d4f77997943207b795e68ce8fff3fed23ff78fc Mon Sep 17 00:00:00 2001 From: Valentin Chaboche Date: Mon, 24 Oct 2022 17:08:27 +0200 Subject: [PATCH 3/3] Scoru,Test: properly test the inclusion of SOL/EOL in the inbox --- .../integration/operations/test_sc_rollup.ml | 141 +++++++++++++++--- 1 file changed, 122 insertions(+), 19 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_sc_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_sc_rollup.ml index 35ad222bcecb..fefcf221c311 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_sc_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_sc_rollup.ml @@ -2016,36 +2016,139 @@ let test_refute_invalid_metadata () = in assert_refute_result ~game_status:expected_game_status incr +let node_proof_to_protocol_proof p = + let open Data_encoding.Binary in + let open Sc_rollup.Inbox in + let enc = serialized_proof_encoding in + let bytes = + Sc_rollup_helpers.Store_inbox.to_serialized_proof p |> to_bytes_exn enc + in + of_bytes_exn enc bytes |> of_serialized_proof + |> WithExceptions.Option.get ~loc:__LOC__ + +let full_history_inbox all_inbox_messages = + let open Lwt_syntax in + let open Sc_rollup_helpers in + (* Add the SOL/EOL to the list of inbox messages. *) + let all_inbox_messages = + List.map + (fun (inbox_level, inbox_messages) -> + (inbox_level, wrap_messages inbox_level inbox_messages)) + all_inbox_messages + in + (* Create a inbox adding the messages from [all_inbox_messages]. *) + let* index = Tezos_context_memory.Context.init "inbox" in + let ctxt = Tezos_context_memory.Context.empty index in + let* inbox = Store_inbox.empty ctxt Raw_level.root in + Sc_rollup_helpers.construct_inbox ~inbox ctxt all_inbox_messages + +let input_included ~snapshot ~full_history_inbox (l, n) = + let open Sc_rollup_helpers in + let ctxt, level_tree, history, inbox = full_history_inbox in + let* history, history_proof = + Store_inbox.form_history_proof ctxt history inbox level_tree + >|= Environment.wrap_tzresult + in + (* Create an inclusion proof of the inbox message at [(l, n)]. *) + let* proof, _ = + Store_inbox.produce_proof ctxt history history_proof (l, n) + >|= Environment.wrap_tzresult + in + let proof = node_proof_to_protocol_proof proof in + let+ inbox_message_verified = + Sc_rollup.Inbox.verify_proof (l, n) snapshot proof + >|= Environment.wrap_tzresult + in + Option.map + (fun inbox_message -> Sc_rollup.Inbox_message inbox_message) + inbox_message_verified + (** Test that the protocol adds a [SOL] and [EOL] for each Tezos level, even if no messages are added to the inbox. *) let test_sol_and_eol () = - let* block, account = context_init Context.T1 in - - (* SOL and EOL are added in the first inbox. *) - let* first_inbox = Context.Sc_rollup.inbox (B block) in - let messages_first_inbox = - Sc_rollup.Inbox.Internal_for_tests.inbox_message_counter first_inbox + let assert_input_included ~snapshot ~full_history_inbox (l, n) input = + let* input_verified = input_included ~snapshot ~full_history_inbox (l, n) in + Assert.equal + ~loc:__LOC__ + (Option.equal Sc_rollup.input_equal) + "Input found with the proof is different from input provided" + (fun ppf v -> + match v with + | None -> Format.pp_print_string ppf "None" + | Some v -> Sc_rollup.pp_input ppf v) + input_verified + input in - let* () = Assert.equal_int ~loc:__LOC__ 2 (Z.to_int messages_first_inbox) in - (* SOL and EOL are added when no messages are added. *) + (* Create the first block. *) + let* block, account = context_init Context.T1 in + + (* Bake a second block. *) let* block = Block.bake block in - let* second_inbox = Context.Sc_rollup.inbox (B block) in - let messages_second_inbox = - Sc_rollup.Inbox.Internal_for_tests.inbox_message_counter second_inbox - in - let* () = Assert.equal_int ~loc:__LOC__ 2 (Z.to_int messages_second_inbox) in - (* SOL and EOL are added when messages are added. *) + (* Bake a third block where a message is added. *) let* operation = Op.sc_rollup_add_messages (B block) account ["foo"] in let* block = Block.bake ~operation block in - let* third_inbox = Context.Sc_rollup.inbox (B block) in - let messages_third_inbox = - Sc_rollup.Inbox.Internal_for_tests.inbox_message_counter third_inbox + + (* Bake an extra block to archive all inbox messages for the snapshot. *) + let* block = Block.bake block in + let* inbox = Context.Sc_rollup.inbox (B block) in + let snapshot = Sc_rollup.Inbox.take_snapshot inbox in + + let level_zero = Raw_level.of_int32_exn 0l in + let level_one = Raw_level.of_int32_exn 1l in + let level_two = Raw_level.of_int32_exn 2l in + let*! ((ctxt, level_tree, history, inbox) as full_history_inbox) = + full_history_inbox [(level_zero, []); (level_one, []); (level_two, ["foo"])] in - let* () = Assert.equal_int ~loc:__LOC__ 3 (Z.to_int messages_third_inbox) in - return_unit + (* Assert SOL is at position 0. *) + let sol = Sc_rollup_helpers.make_sol ~inbox_level:level_two in + let* () = + assert_input_included + ~snapshot + ~full_history_inbox + (level_two, Z.zero) + (Some sol) + in + (* Assert EOL is at the end of inbox level. *) + let eol = + Sc_rollup_helpers.make_eol + ~inbox_level:level_two + ~message_counter:(Z.of_int 2) + in + let* () = + assert_input_included + ~snapshot + ~full_history_inbox + (level_two, Z.of_int 2) + (Some eol) + in + (* Assert EOL was the last message of the inbox level. *) + let* () = + assert_input_included + ~snapshot + ~full_history_inbox + (level_two, Z.of_int 3) + None + in + + (* Assert the computed inbox and protocol's inbox are equal. *) + let* _history, history_proof = + Sc_rollup_helpers.Store_inbox.form_history_proof + ctxt + history + inbox + level_tree + >|= Environment.wrap_tzresult + in + Assert.equal + ~loc:__LOC__ + Sc_rollup.Inbox.equal_history_proof + "Computed and protocol inboxes aren't equal" + Sc_rollup.Inbox.pp_history_proof + snapshot + history_proof (** With [Start_of_level] and [End_of_level] inbox messages in each inbox level, it's impossible to give a valid commitment with 0 ticks. *) -- GitLab