From 4e0867cb62e496e66fc26567e65ad5032c6d7efa Mon Sep 17 00:00:00 2001 From: Sylvain Ribstein Date: Mon, 2 Jan 2023 15:12:45 +0100 Subject: [PATCH 1/2] test/scoru/helper: default pred info based on inbox_level --- .../test/helpers/sc_rollup_helpers.ml | 32 ++++++++++++------- .../integration/operations/test_sc_rollup.ml | 8 ++--- 2 files changed, 22 insertions(+), 18 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 39d60e035022..84b23f48c6a6 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 @@ -368,23 +368,31 @@ let make_inputs predecessor_timestamp predecessor messages inbox_level = in [sol; info_per_level] @ external_inputs @ [eol] +let predecessor_timestamp_and_hash_from_level level = + let level_int64 = Int64.of_int32 @@ Raw_level.to_int32 level in + let predecessor_timestamp = Time.Protocol.of_seconds level_int64 in + let hash = Block_hash.hash_string [Int64.to_string level_int64] in + (predecessor_timestamp, hash) + (** Wrap messages, predecessor_timestamp and predecessor of a level into a [payloads_per_level] .*) -let wrap_messages ?(predecessor_timestamp = Timestamp.of_seconds 0L) - ?(predecessor = Block_hash.zero) level messages : payloads_per_level = +let wrap_messages level + ?(pred_info = predecessor_timestamp_and_hash_from_level level) messages : + payloads_per_level = + let predecessor_timestamp, predecessor = pred_info in let payloads = List.map make_external_inbox_message messages in let inputs = make_inputs predecessor_timestamp predecessor messages level in {payloads; predecessor_timestamp; predecessor; messages; level; inputs} -(** An empty inbox level is a SOL,info_per_level and EOL. *) -let make_empty_level ?predecessor_timestamp ?predecessor inbox_level = - wrap_messages ?predecessor_timestamp ?predecessor inbox_level [] +(** An empty inbox level is a SOL,IPL and EOL. *) +let make_empty_level ?pred_info inbox_level = + wrap_messages ?pred_info inbox_level [] -let gen_messages inbox_level gen_message = +let gen_messages ?pred_info inbox_level gen_message = let open QCheck2.Gen in let* input = gen_message in let* inputs = small_list gen_message in - return (wrap_messages inbox_level (input :: inputs)) + return (wrap_messages ?pred_info inbox_level (input :: inputs)) let gen_payloads_for_levels ~start_level ~max_level gen_message = let open QCheck2.Gen in @@ -472,7 +480,7 @@ let pp_message_repr fmt {input_repr; message_repr} = | `Message msg -> msg | `EOL -> "EOL") -(** An empty inbox level is a SOL and EOL. *) +(** An empty inbox level is a SOL,IPL and EOL. *) let make_empty_level_repr inbox_level = let sol = {input_repr = make_sol_repr ~inbox_level; message_repr = `SOL} in let eol = @@ -777,14 +785,14 @@ module Protocol_inbox = struct in aux inbox payloads_per_levels - let add_new_level inbox messages = + let add_new_level ?pred_info inbox messages = let next_level = Raw_level.succ @@ Sc_rollup.Inbox.inbox_level inbox in - let messages_per_level = wrap_messages next_level messages in + let messages_per_level = wrap_messages ?pred_info next_level messages in fill_inbox inbox [messages_per_level] - let add_new_empty_level inbox = + let add_new_empty_level ?pred_info inbox = let next_level = Raw_level.succ @@ Sc_rollup.Inbox.inbox_level inbox in - let empty_level = [make_empty_level next_level] in + let empty_level = [make_empty_level ?pred_info next_level] in fill_inbox inbox empty_level let construct_inbox ?inbox_creation_level ?genesis_predecessor_timestamp 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 97b385e8ce86..39243556fad2 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 @@ -2599,12 +2599,8 @@ let full_history_inbox (genesis_predecessor_timestamp, genesis_predecessor) let open Sc_rollup_helpers in let payloads_per_levels = List.map - (fun ((predecessor_timestamp, predecessor), level, external_messages) -> - wrap_messages - ~predecessor_timestamp - ~predecessor - level - external_messages) + (fun (pred_info, level, external_messages) -> + wrap_messages ~pred_info level external_messages) all_external_messages in Sc_rollup_helpers.Node_inbox.construct_inbox -- GitLab From d6ab5ff271c2b2877a2eb563629f4baa6faca8d3 Mon Sep 17 00:00:00 2001 From: Sylvain Ribstein Date: Mon, 2 Jan 2023 15:13:37 +0100 Subject: [PATCH 2/2] test/scoru: add test for inbox --- .../lib_protocol/alpha_context.mli | 10 +- .../lib_protocol/sc_rollup_inbox_repr.ml | 6 + .../lib_protocol/sc_rollup_inbox_repr.mli | 4 + .../test/helpers/sc_rollup_helpers.ml | 24 ++ .../test/unit/test_sc_rollup_inbox.ml | 399 ++++++++++++++++-- 5 files changed, 400 insertions(+), 43 deletions(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 9b9920262e33..ec95f9c2752e 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -3267,7 +3267,7 @@ module Sc_rollup : sig type t = Internal of internal_inbox_message | External of string - type serialized + type serialized = private string val encoding : t Data_encoding.t @@ -3291,6 +3291,8 @@ module Sc_rollup : sig val encoding : t Data_encoding.t + val pp : Format.formatter -> t -> unit + val equal : t -> t -> bool val hash : t -> Hash.t @@ -3321,6 +3323,8 @@ module Sc_rollup : sig type proof = private t list + val pp_proof : Format.formatter -> proof -> unit + val proof_encoding : proof Data_encoding.t val produce_proof : @@ -3522,6 +3526,10 @@ module Sc_rollup : sig } val level_proof_of_history_proof : history_proof -> level_proof + + val expose_proof : proof -> inclusion_proof * payloads_proof + + val make_proof : inclusion_proof -> payloads_proof -> proof end val add_external_messages : context -> string list -> context tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.ml b/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.ml index 2cfc1ebdb97a..f6e4a6a4f9bd 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.ml @@ -864,6 +864,12 @@ module Internal_for_tests = struct } let level_proof_of_history_proof = Skip_list.content + + let expose_proof {inclusion_proof; message_proof} = + (inclusion_proof, message_proof) + + let make_proof inclusion_proof message_proof = + {inclusion_proof; message_proof} end type inbox = t diff --git a/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.mli b/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.mli index 61352d5406bf..789a10b7988b 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.mli @@ -402,6 +402,10 @@ module Internal_for_tests : sig } val level_proof_of_history_proof : history_proof -> level_proof + + val expose_proof : proof -> inclusion_proof * payloads_proof + + val make_proof : inclusion_proof -> payloads_proof -> proof end type inbox = t 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 84b23f48c6a6..3f7a802b304f 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 @@ -632,6 +632,12 @@ let origination_op ?force_reveal ?counter ?fee ?gas_limit ?storage_limit ~parameters_ty:(Script.lazy_expr @@ Expr.from_string parameters_ty) ~origination_proof +let latest_level_proof inbox = + Sc_rollup.Inbox.Internal_for_tests.level_proof_of_history_proof + @@ Sc_rollup.Inbox.old_levels_messages inbox + +let latest_level_proof_hash inbox = (latest_level_proof inbox).hash + module Node_inbox = struct type t = { inbox : Sc_rollup.Inbox.t; @@ -720,6 +726,24 @@ module Node_inbox = struct inbox_snapshot (level, message_counter) + let produce_and_expose_proof node_inbox node_inbox_snapshot + (level, message_counter) = + let open Lwt_result_syntax in + let* proof, input = + produce_proof node_inbox node_inbox_snapshot (level, message_counter) + in + let exposed_proof = Sc_rollup.Inbox.Internal_for_tests.expose_proof proof in + return (exposed_proof, input) + + let produce_payloads_proof {payloads_histories; _} + (head_cell_hash : Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t) + message_counter = + Lwt.map Environment.wrap_tzresult + @@ Sc_rollup.Inbox.Internal_for_tests.produce_payloads_proof + (get_payloads_history payloads_histories) + head_cell_hash + ~index:message_counter + let produce_inclusion_proof {history; _} inbox_snapshot level = Lwt.map Environment.wrap_tzresult @@ Sc_rollup.Inbox.Internal_for_tests.produce_inclusion_proof diff --git a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_inbox.ml b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_inbox.ml index 3bdf0b5e5e5c..98ba277b0fd4 100644 --- a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_inbox.ml +++ b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_inbox.ml @@ -31,6 +31,7 @@ Subject: These unit tests check the off-line inbox implementation for smart contract rollups *) + open Protocol let opt_get ~__LOC__ = WithExceptions.Option.get ~loc:__LOC__ @@ -105,6 +106,10 @@ let assert_merkelized_payload_proof_error ~__LOC__ expected_msg result = expected_msg = msg | _ -> false) +let verify_merkelized_payload_proof_fails ~__LOC__ expected_msg proof = + assert_merkelized_payload_proof_error ~__LOC__ expected_msg + @@ Merkelized_payload_hashes.verify_proof proof + let assert_equal_history_proof ~__LOC__ found expected = Assert.equal ~loc:__LOC__ @@ -121,6 +126,18 @@ let assert_inbox_proof_error ~__LOC__ expected_msg result = expected_msg = msg | _ -> false) +let verify_payloads_proof_fails ~__LOC__ expected_msg proof head_cell_hash + message_counter = + assert_inbox_proof_error ~__LOC__ expected_msg + @@ Inbox.Internal_for_tests.verify_payloads_proof + proof + head_cell_hash + message_counter + +let verify_inclusion_proof_fails ~__LOC__ expected_msg proof snapshot = + assert_inbox_proof_error ~__LOC__ expected_msg + @@ Inbox.Internal_for_tests.verify_inclusion_proof proof snapshot + let gen_payload_size = QCheck2.Gen.(1 -- 10) let gen_payload_string = @@ -239,6 +256,8 @@ let construct_merkelized_payload_hashes payloads = let history = Merkelized_payload_hashes.History.empty ~capacity:1000L in fill_merkelized_payload history payloads +(** The merkelized payload hashes history is correctly filled with all + values. *) let test_merkelized_payload_hashes_history payloads = let open Lwt_result_syntax in let nb_payloads = List.length payloads in @@ -272,6 +291,7 @@ let test_merkelized_payload_hashes_history payloads = expected_payload_hash) payloads +(** Produce a merkelized payload hashes proof and verify it's valid. *) let test_merkelized_payload_hashes_proof (payloads, index) = let open Lwt_result_syntax in let* history, merkelized_payload = @@ -312,6 +332,11 @@ let test_merkelized_payload_hashes_proof (payloads, index) = in return_unit +(** Verifying an empty merkelized payload hashes proof fails *) +let test_empty_merkelized_payload_hashes_proof_fails () = + verify_merkelized_payload_proof_fails ~__LOC__ "proof is empty" + @@ Merkelized_payload_hashes.Internal_for_tests.make_proof [] + (* Test multiple cases of invalid proof. This test is more about testing the skip list than testing merkelized payload. But it was easier to test with a skip-list with hashes as pointer. *) @@ -390,8 +415,7 @@ let test_invalid_merkelized_payload_hashes_proof_fails (payloads, index) = make_proof @@ prefix @ suffix in let assert_fails ~__LOC__ proof = - let res = Merkelized_payload_hashes.verify_proof proof in - assert_merkelized_payload_proof_error ~__LOC__ "invalid proof" res + verify_merkelized_payload_proof_fails ~__LOC__ "invalid proof" proof in let* () = assert_fails ~__LOC__ proof_with_missing_cell in let* () = assert_fails ~__LOC__ proof_with_invalid_cell_in_path in @@ -401,6 +425,7 @@ let test_invalid_merkelized_payload_hashes_proof_fails (payloads, index) = let* () = assert_fails ~__LOC__ proof_with_extra_step in return_unit +(** A node produces an inbox inclusion proof and the protocol verify it. *) let test_inclusion_proof_production (payloads_for_levels, level) = let open Lwt_result_wrap_syntax in let*? node_inbox, proto_inbox = @@ -424,6 +449,8 @@ let test_inclusion_proof_production (payloads_for_levels, level) = verified_old_levels_messages node_old_level_messages +(** A node produces an inclusion proof and the protocol fails to verify it + against the snapshot of the next (empty) level. *) let test_inclusion_proof_verification (payloads_for_levels, level) = let open Lwt_result_wrap_syntax in let*? node_inbox, proto_inbox = @@ -439,11 +466,246 @@ let test_inclusion_proof_verification (payloads_for_levels, level) = (* This snapshot is not the same one as node_inbox_snapshot because we added an empty level. *) let proto_inbox_snapshot = Inbox.take_snapshot proto_inbox in - let result = - Inbox.Internal_for_tests.verify_inclusion_proof proof proto_inbox_snapshot + verify_inclusion_proof_fails + ~__LOC__ + "invalid inclusion proof" + proof + proto_inbox_snapshot + +(** The protocol fails to verify an empty inclusion proof. *) +let test_empty_inclusion_proof_fails payloads = + let open Lwt_result_syntax in + let*? proto_inbox = + Protocol_inbox.construct_inbox + ~inbox_creation_level:Raw_level.root + [payloads] + in + let proto_inbox_snapshot = Inbox.take_snapshot proto_inbox in + verify_inclusion_proof_fails + ~__LOC__ + "inclusion proof is empty" + [] + proto_inbox_snapshot + +(** A node produces an inbox payloads proof and the protocol verify it. *) +let test_payloads_proof_production + ((payloads : payloads_per_level), message_counter) = + let open Lwt_result_syntax in + let payloads_for_levels = [payloads] in + let exp_message = + first_after payloads_for_levels payloads.level message_counter |> function + | Some {payload; _} -> Some payload + | None -> None + in + let*? node_inbox, proto_inbox = + construct_node_and_protocol_inbox + ~inbox_creation_level:Raw_level.root + payloads_for_levels + in + let node_head_cell_hash = latest_level_proof_hash node_inbox.inbox in + (* Produce a payloads proof using the {!Node_inbox}. *) + let* ({payload = proof_input; _} as proof) = + Node_inbox.produce_payloads_proof + node_inbox + node_head_cell_hash + message_counter + in + (* Verify the produced proof using the {!Protocol_inbox}. *) + let proto_head_cell_hash = latest_level_proof_hash proto_inbox in + let*? verified_input = + Environment.wrap_tzresult + @@ Inbox.Internal_for_tests.verify_payloads_proof + proof + proto_head_cell_hash + message_counter + in + let* () = assert_equal_payload_option ~__LOC__ proof_input verified_input in + assert_equal_payload_option ~__LOC__ exp_message verified_input + +(** A node produces a payloads proof and the protocol fails to verify it + against the snapshot of the next (empty) level. *) +let test_payloads_proof_invalid_inbox_snapshot (payloads, message_counter) = + let open Lwt_result_syntax in + let*? node_inbox, proto_inbox = + construct_node_and_protocol_inbox + ~inbox_creation_level:Raw_level.root + [payloads] + in + let* proof = + let node_head_cell_hash = latest_level_proof_hash node_inbox.inbox in + Node_inbox.produce_payloads_proof + node_inbox + node_head_cell_hash + message_counter + in + let*? proto_inbox = Protocol_inbox.add_new_level proto_inbox [] in + (* As we added one level in the [proto_inbox], it is one level further than + the [node_inbox]. The proof will not match the history. *) + let head_cell_hash = latest_level_proof_hash proto_inbox in + verify_payloads_proof_fails + ~__LOC__ + "message_proof does not match history" + proof + head_cell_hash + message_counter + +(** Fail to verify a payloads proof with an input when none is expected. *) +let test_payloads_proof_no_payload_expected (payloads : payloads_per_level) = + let open Lwt_result_syntax in + let message_counter = Z.of_int (List.length payloads.inputs) in + let*? node_inbox, proto_inbox = + construct_node_and_protocol_inbox + ~inbox_creation_level:Raw_level.root + [payloads] + in + let* proof = + let node_head_cell_hash = latest_level_proof_hash node_inbox.inbox in + Node_inbox.produce_payloads_proof + node_inbox + node_head_cell_hash + message_counter + in + let invalid_proof = + let payload = Some (make_internal_inbox_message Start_of_level) in + Inbox.Internal_for_tests.{proof with payload} + in + let head_cell_hash = latest_level_proof_hash proto_inbox in + verify_payloads_proof_fails + ~__LOC__ + "Payload provided but none expected" + invalid_proof + head_cell_hash + message_counter + +(** Fail to verify a payloads proof with no input when one is expected. *) +let test_payloads_proof_payload_expected payloads = + let open Lwt_result_syntax in + let message_counter = Z.zero in + let*? node_inbox, proto_inbox = + construct_node_and_protocol_inbox + ~inbox_creation_level:Raw_level.root + [payloads] + in + let* proof = + let node_head_cell_hash = latest_level_proof_hash node_inbox.inbox in + Sc_rollup_helpers.Node_inbox.produce_payloads_proof + node_inbox + node_head_cell_hash + message_counter + in + let invalid_proof = Inbox.Internal_for_tests.{proof with payload = None} in + let head_cell_hash = latest_level_proof_hash proto_inbox in + verify_payloads_proof_fails + ~__LOC__ + "Expected a payload but none provided in the proof" + invalid_proof + head_cell_hash + message_counter + +(** Fail to verify a payloads proof about another index. *) +let test_payloads_proof_incorrect_proof payloads = + let open Lwt_result_syntax in + let*? node_inbox, proto_inbox = + construct_node_and_protocol_inbox + ~inbox_creation_level:Raw_level.root + [payloads] + in + let* proof = + let node_head_cell_hash = latest_level_proof_hash node_inbox.inbox in + Node_inbox.produce_payloads_proof node_inbox node_head_cell_hash Z.zero + in + let proof = Inbox.Internal_for_tests.{proof with payload = None} in + let head_cell_hash = latest_level_proof_hash proto_inbox in + let invalid_message_counter = Z.of_int (List.length payloads.inputs) in + verify_payloads_proof_fails + ~__LOC__ + "Provided proof is about a unexpected payload" + proof + head_cell_hash + invalid_message_counter + +(** Fail to verify a payloads proof about another payload. *) +let test_payloads_proof_incorrect_payload payloads = + let open Lwt_result_syntax in + let message_counter = Z.zero in + let*? node_inbox, proto_inbox = + construct_node_and_protocol_inbox + ~inbox_creation_level:Raw_level.root + [payloads] + in + let* proof = + let node_head_cell_hash = latest_level_proof_hash node_inbox.inbox in + Node_inbox.produce_payloads_proof + node_inbox + node_head_cell_hash + message_counter + in + let invalid_proof = + let payload = Some (make_internal_inbox_message End_of_level) in + Inbox.Internal_for_tests.{proof with payload} + in + let head_cell_hash = latest_level_proof_hash proto_inbox in + verify_payloads_proof_fails + ~__LOC__ + "the payload provided does not match the payload's hash found in the \ + message proof" + invalid_proof + head_cell_hash + message_counter + +(** Fail to verify a valid payloads proof for an invalid message counter. *) +let test_payloads_proof_incorrect_index payloads = + let open Lwt_result_syntax in + let message_counter = Z.zero in + let*? node_inbox, proto_inbox = + construct_node_and_protocol_inbox + ~inbox_creation_level:Raw_level.root + [payloads] + in + let* proof = + let node_head_cell_hash = latest_level_proof_hash node_inbox.inbox in + Node_inbox.produce_payloads_proof + node_inbox + node_head_cell_hash + message_counter + in + let head_cell_hash = latest_level_proof_hash proto_inbox in + let invalid_message_counter = Z.succ message_counter in + verify_payloads_proof_fails + ~__LOC__ + "found index in message_proof is incorrect" + proof + head_cell_hash + invalid_message_counter + +(** Fail to verify a payloads proof with an out of bound index. *) +let test_payloads_proof_out_of_bound_index payloads = + let open Lwt_result_syntax in + let message_counter = Z.zero in + let*? node_inbox, proto_inbox = + construct_node_and_protocol_inbox + ~inbox_creation_level:Raw_level.root + [payloads] + in + let* proof = + let node_head_cell_hash = latest_level_proof_hash node_inbox.inbox in + Node_inbox.produce_payloads_proof + node_inbox + node_head_cell_hash + message_counter + in + let head_cell_hash = latest_level_proof_hash proto_inbox in + let invalid_message_counter = + Z.of_int @@ succ (List.length payloads.inputs) in - assert_inbox_proof_error ~__LOC__ "invalid inclusion proof" result + verify_payloads_proof_fails + ~__LOC__ + "Provided message counter is out of the valid range [0 -- (max_index + 1)]" + proof + head_cell_hash + invalid_message_counter +(** Produce an inbox proof and verify it. *) let test_inbox_proof_production (payloads_for_levels, level, message_counter) = let open Lwt_result_wrap_syntax in let exp_message = first_after payloads_for_levels level message_counter in @@ -472,53 +734,57 @@ let test_inbox_proof_production (payloads_for_levels, level, message_counter) = in assert_inbox_message ~__LOC__ exp_message input_in_proof -let test_inbox_proof_verification (payloads_for_levels, level, message_counter) - = +(** This test first produces two valid inbox proofs [proof1] and + [proof2] for two different levels [l1; l2], and message counters + [i1; i2]. Then combine the two proofs to create two invalid ones + [{proof1.inclusion_proof; proof2.payloads_prof}] and + [{proof2.inclusion_proof; proof1.payloads_prof}]. Both fail with + all combinations of levels [l1, l2] and messages counter [i1, + i2]. *) +let test_invalid_inbox_proof_fails + (payloads_for_levels, level, message_counter, level', message_counter') = + QCheck2.assume + ((not (Raw_level.equal level level')) + && not (Z.equal message_counter message_counter')) ; let open Lwt_result_wrap_syntax in let*? node_inbox, proto_inbox = construct_node_and_protocol_inbox ~inbox_creation_level:Raw_level.root payloads_for_levels in - let node_inbox_snapshot = Inbox.old_levels_messages node_inbox.inbox in - let* proof, _input = - Node_inbox.produce_proof - node_inbox - node_inbox_snapshot - (level, message_counter) - in + let node_inbox_snapshot = Inbox.take_snapshot node_inbox.inbox in let proto_inbox_snapshot = Inbox.take_snapshot proto_inbox in - (* The proto and node inboxes are synchronized, we make sure the verification - refuses the invalid message index. *) - let invalid_message_counter = - if Z.(equal message_counter zero) then Z.succ message_counter - else Z.pred message_counter - in - let* () = - let result = - Inbox.verify_proof - (level, invalid_message_counter) - proto_inbox_snapshot - proof + assert (node_inbox_snapshot = proto_inbox_snapshot) ; + let* invalid_proof = + let* (inclusion_proof, _message_proof), _input = + Node_inbox.produce_and_expose_proof + node_inbox + node_inbox_snapshot + (level, message_counter) in - assert_inbox_proof_error - ~__LOC__ - "found index in message_proof is incorrect" - result - in - - (* We move the inbox one level forward so the inbox's inclusion proof fails. *) - let*? proto_inbox = Protocol_inbox.add_new_level proto_inbox [] in - let proto_inbox_snapshot = Inbox.take_snapshot proto_inbox in - let* () = - let result = - Inbox.verify_proof (level, message_counter) proto_inbox_snapshot proof + let* (_inclusion_proof', message_proof'), _input = + Node_inbox.produce_and_expose_proof + node_inbox + node_inbox_snapshot + (level', message_counter') in - assert_inbox_proof_error ~__LOC__ "invalid inclusion proof" result + return @@ Inbox.Internal_for_tests.make_proof inclusion_proof message_proof' in - + let assert_fails ~__LOC__ (level, message_counter) = + assert_inbox_proof_error ~__LOC__ "message_proof does not match history" + @@ Inbox.verify_proof + (level, message_counter) + proto_inbox_snapshot + invalid_proof + in + let* () = assert_fails ~__LOC__ (level, message_counter) in + let* () = assert_fails ~__LOC__ (level', message_counter) in + let* () = assert_fails ~__LOC__ (level, message_counter') in + let* () = assert_fails ~__LOC__ (level', message_counter') in return_unit +(** Verify that the inbox history is correctly filled by calling + {!Inbox.add_all_messages}. *) let test_messages_are_correctly_added_in_history {predecessor_timestamp; predecessor; messages; _} = let open Lwt_result_syntax in @@ -580,6 +846,10 @@ let merkelized_payload_hashes_tests = ~name:"Produce a merkelized payload hashes proof and verify its validity." (gen_payloads_and_index ()) test_merkelized_payload_hashes_proof; + Tztest.tztest + "Empty merkelized payload hashes proof fails." + `Quick + test_empty_merkelized_payload_hashes_proof_fails; Tztest.tztest_qcheck2 ~count:1000 ~name:"Invalid merkelized payload hashes proof fails." @@ -603,6 +873,51 @@ let inbox_tests = ~name:"negative test of inclusion proof." (gen_payloads_for_levels_and_level ()) test_inclusion_proof_verification; + Tztest.tztest_qcheck2 + ~count:1000 + ~name:"verify empty inclusion proof fails." + (gen_payloads_and_level ()) + test_empty_inclusion_proof_fails; + Tztest.tztest_qcheck2 + ~count:1000 + ~name:"produce payloads proof and verifies it." + (gen_payloads_and_level_and_index ()) + test_payloads_proof_production; + Tztest.tztest_qcheck2 + ~count:1000 + ~name:"test to verify a proof not using the correct current level proof." + (gen_payloads_and_level_and_index ()) + test_payloads_proof_invalid_inbox_snapshot; + Tztest.tztest_qcheck2 + ~count:1000 + ~name:"test to verify a proof without the payload." + (gen_payloads_and_level ()) + test_payloads_proof_no_payload_expected; + Tztest.tztest_qcheck2 + ~count:1000 + ~name:"test to verify a proof with payload when none is expected." + (gen_payloads_and_level ()) + test_payloads_proof_payload_expected; + Tztest.tztest_qcheck2 + ~count:1000 + ~name:"test to verify a proof with a proof for another payload." + (gen_payloads_and_level ()) + test_payloads_proof_incorrect_proof; + Tztest.tztest_qcheck2 + ~count:1000 + ~name:"test to verify a proof with another payload." + (gen_payloads_and_level ()) + test_payloads_proof_incorrect_payload; + Tztest.tztest_qcheck2 + ~count:1000 + ~name:"test to verify a proof with a payload with an incorrect index." + (gen_payloads_and_level ()) + test_payloads_proof_incorrect_index; + Tztest.tztest_qcheck2 + ~count:1000 + ~name:"test to verify a proof with an out of bound index." + (gen_payloads_and_level ()) + test_payloads_proof_out_of_bound_index; Tztest.tztest_qcheck2 ~count:1000 ~name:"produce inbox proof and verifies it." @@ -611,8 +926,8 @@ let inbox_tests = Tztest.tztest_qcheck2 ~count:1000 ~name:"negative test of inbox proof." - (gen_payloads_for_levels_and_level_and_index ()) - test_inbox_proof_verification; + (gen_payloads_for_levels_and_two_levels_and_two_indexes ()) + test_invalid_inbox_proof_fails; Tztest.tztest_qcheck2 ~count:1000 ~name:"messages are correctly added in payloads history" -- GitLab