From a5aab78b02dcd65c92796cf9344a447825b24c9c Mon Sep 17 00:00:00 2001 From: Sylvain Ribstein Date: Thu, 30 Mar 2023 13:00:45 +0200 Subject: [PATCH 1/2] soru/tezt: create refutation helper --- tezt/tests/sc_rollup.ml | 147 ++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 65 deletions(-) diff --git a/tezt/tests/sc_rollup.ml b/tezt/tests/sc_rollup.ml index 276b15fe4daa..cd5cc3ca5e8f 100644 --- a/tezt/tests/sc_rollup.ml +++ b/tezt/tests/sc_rollup.ml @@ -3397,12 +3397,13 @@ let test_forking_scenario ~kind ~variant scenario = let cement_commitments client sc_rollup ?fail = Lwt_list.iter_s (fun hash -> cement_commitment client ~sc_rollup ~hash ?fail) -let timeout ?expect_failure ~sc_rollup ~staker1 ~staker2 client = +let timeout ?expect_failure ~sc_rollup ~staker1 ~staker2 ?(src = staker1) client + = let*! () = Client.Sc_rollup.timeout ~hooks ~dst:sc_rollup - ~src:Constant.bootstrap1.alias + ~src ~staker1 ~staker2 client @@ -3410,6 +3411,47 @@ let timeout ?expect_failure ~sc_rollup ~staker1 ~staker2 client = in Client.bake_for_and_wait client +let start_refute client ~source ~opponent ~sc_rollup ~player_commitment_hash + ~opponent_commitment_hash = + let module M = Operation.Manager in + let refutation = M.Start {player_commitment_hash; opponent_commitment_hash} in + bake_operation_via_rpc ~__LOC__ client + @@ M.make ~source + @@ M.sc_rollup_refute ~sc_rollup ~opponent ~refutation () + +(** [move_refute_with_unique_state_hash + ?number_of_sections_in_dissection client ~source ~opponent + ~sc_rollup ~state_hash] submits a dissection refutation + operation. The dissection is always composed of the same + state_hash and should only be used for test. *) +let move_refute_with_unique_state_hash ?number_of_sections_in_dissection client + ~source ~opponent ~sc_rollup ~state_hash = + let module M = Operation.Manager in + let* number_of_sections_in_dissection = + match number_of_sections_in_dissection with + | Some n -> return n + | None -> + let* {number_of_sections_in_dissection; _} = + get_sc_rollup_constants client + in + return number_of_sections_in_dissection + in + (* Construct a valid dissection with valid initial hash of size + [sc_rollup.number_of_sections_in_dissection]. The state hash + given is the state hash of the parent commitment of the refuted + one and the one used for all tick. *) + let rec aux i acc = + if i = number_of_sections_in_dissection - 1 then + List.rev (M.{state_hash = None; tick = i} :: acc) + else aux (i + 1) (M.{state_hash = Some state_hash; tick = i} :: acc) + in + let refutation = + M.Move {choice_tick = 0; refutation_step = Dissection (aux 0 [])} + in + bake_operation_via_rpc ~__LOC__ client + @@ M.make ~source + @@ M.sc_rollup_refute ~sc_rollup ~opponent ~refutation () + (** Given a commitment tree constructed by {test_forking_scenario}, this function: - tests different (failing and non-failing) cementation of commitments and checks the returned error for each situation (in case of failure); @@ -3448,18 +3490,14 @@ let test_no_cementation_if_parent_not_lcc_or_if_disputed_commit = loses the dispute, and the branch c32 --- c321 dies. *) (* [operator1] starts a dispute. *) - let module M = Operation.Manager in let* () = - let refutation = - M.Start {player_commitment_hash = c32; opponent_commitment_hash = c31} - in - bake_operation_via_rpc ~__LOC__ client - @@ M.make ~source:operator2 - @@ M.sc_rollup_refute - ~sc_rollup - ~opponent:operator1.public_key_hash - ~refutation - () + start_refute + client + ~source:operator2 + ~opponent:operator1.public_key_hash + ~sc_rollup + ~player_commitment_hash:c32 + ~opponent_commitment_hash:c31 in (* [operator1] will not play and will be timeout-ed. *) let timeout_period = constants.timeout_period_in_blocks in @@ -3489,9 +3527,6 @@ let test_valid_dispute_dissection = let* constants = get_sc_rollup_constants client in let challenge_window = constants.challenge_window_in_blocks in let commitment_period = constants.commitment_period_in_blocks in - let number_of_sections_in_dissection = - constants.number_of_sections_in_dissection - in let* () = (* Be able to cement both c1 and c2 *) repeat (challenge_window + commitment_period) (fun () -> @@ -3503,37 +3538,28 @@ let test_valid_dispute_dissection = let source = operator2 in let opponent = operator1.public_key_hash in let* () = - let refutation = - M.Start {player_commitment_hash = c32; opponent_commitment_hash = c31} - in - bake_operation_via_rpc ~__LOC__ client - @@ M.make ~source - @@ M.sc_rollup_refute ~sc_rollup ~opponent ~refutation () + start_refute + client + ~source + ~opponent + ~sc_rollup + ~player_commitment_hash:c32 + ~opponent_commitment_hash:c31 in - (* Construct a valid dissection with valid initial hash of size - [sc_rollup.number_of_sections_in_dissection]. The state hash below is - the hash of the state computed after submitting the first commitment c1 - (which is also equal to states's hashes of subsequent commitments, as we - didn't add any message in inboxes). If this hash needs to be recomputed, - run this test with --verbose and grep for 'compressed_state' in the - produced logs. *) + (* If this hash needs to be recomputed, run this test with --verbose + and grep for 'compressed_state' in the produced logs. *) let state_hash = "srs11Z9V76SGd97kGmDQXV8tEF67C48GMy77RuaHdF1kWLk6UTmMfj" in - let rec aux i acc = - if i = number_of_sections_in_dissection - 1 then - List.rev ({M.state_hash = None; tick = i} :: acc) - else aux (i + 1) ({M.state_hash = Some state_hash; tick = i} :: acc) - in (* Inject a valid dissection move *) - let refutation = - M.Move {choice_tick = 0; refutation_step = Dissection (aux 0 [])} - in - let* () = - bake_operation_via_rpc ~__LOC__ client - @@ M.make ~source - @@ M.sc_rollup_refute ~sc_rollup ~opponent ~refutation () + move_refute_with_unique_state_hash + client + ~source + ~opponent + ~sc_rollup + ~state_hash in + (* We cannot cement neither c31, nor c32 because refutation game hasn't ended. *) cement [c31; c32] ~fail:"Attempted to cement a disputed commitment" @@ -3573,16 +3599,13 @@ let test_timeout = let module M = Operation.Manager in (* [operator2] starts a dispute, but won't be playing then. *) let* () = - let refutation = - M.Start {player_commitment_hash = c32; opponent_commitment_hash = c31} - in - bake_operation_via_rpc ~__LOC__ client - @@ M.make ~source:operator2 - @@ M.sc_rollup_refute - ~sc_rollup - ~opponent:operator1.public_key_hash - ~refutation - () + start_refute + client + ~source:operator2 + ~opponent:operator1.public_key_hash + ~sc_rollup + ~player_commitment_hash:c32 + ~opponent_commitment_hash:c31 in (* Get exactly to the block where we are able to timeout. *) let* () = @@ -3816,20 +3839,13 @@ let test_refutation_reward_and_punishment ~kind = let module M = Operation.Manager in (* [operator1] starts a dispute, but will never play. *) let* () = - let refutation = - M.Start - { - player_commitment_hash = operator1_commitment; - opponent_commitment_hash = operator2_commitment; - } - in - bake_operation_via_rpc ~__LOC__ client - @@ M.make ~source:operator1 - @@ M.sc_rollup_refute - ~sc_rollup - ~opponent:operator2.public_key_hash - ~refutation - () + start_refute + client + ~source:operator1 + ~opponent:operator2.public_key_hash + ~sc_rollup + ~player_commitment_hash:operator1_commitment + ~opponent_commitment_hash:operator2_commitment in (* Get exactly to the block where we are able to timeout. *) let* () = @@ -3840,6 +3856,7 @@ let test_refutation_reward_and_punishment ~kind = ~sc_rollup ~staker1:operator2.public_key_hash ~staker2:operator1.public_key_hash + ~src:Constant.bootstrap1.alias client in -- GitLab From 218bc68712dbc06082e2608109ae8ee5739e2ff6 Mon Sep 17 00:00:00 2001 From: Sylvain Ribstein Date: Thu, 30 Mar 2023 13:18:51 +0200 Subject: [PATCH 2/2] soru/tezt: refutation game can still be played after migration --- tezt/lib_tezos/sc_rollup_helpers.ml | 20 ++++ tezt/lib_tezos/sc_rollup_helpers.mli | 6 ++ tezt/tests/sc_rollup.ml | 146 ++++++++++++++++++++++++++- 3 files changed, 171 insertions(+), 1 deletion(-) diff --git a/tezt/lib_tezos/sc_rollup_helpers.ml b/tezt/lib_tezos/sc_rollup_helpers.ml index 134663bb3cc3..bc9a83478d05 100644 --- a/tezt/lib_tezos/sc_rollup_helpers.ml +++ b/tezt/lib_tezos/sc_rollup_helpers.ml @@ -150,3 +150,23 @@ let last_cemented_commitment_hash_with_level ~sc_rollup client = let hash = JSON.(json |-> "hash" |> as_string) in let level = JSON.(json |-> "level" |> as_int) in return (hash, level) + +let genesis_commitment ~sc_rollup tezos_client = + let* genesis_info = + RPC.Client.call ~hooks tezos_client + @@ RPC.get_chain_block_context_smart_rollups_smart_rollup_genesis_info + sc_rollup + in + let genesis_commitment_hash = + JSON.(genesis_info |-> "commitment_hash" |> as_string) + in + let* json = + RPC.Client.call ~hooks tezos_client + @@ RPC.get_chain_block_context_smart_rollups_smart_rollup_commitment + ~sc_rollup + ~hash:genesis_commitment_hash + () + in + match Sc_rollup_client.commitment_from_json json with + | None -> failwith "genesis commitment have been removed" + | Some commitment -> return commitment diff --git a/tezt/lib_tezos/sc_rollup_helpers.mli b/tezt/lib_tezos/sc_rollup_helpers.mli index b28242199b74..ee3061a34ae2 100644 --- a/tezt/lib_tezos/sc_rollup_helpers.mli +++ b/tezt/lib_tezos/sc_rollup_helpers.mli @@ -84,3 +84,9 @@ val default_boot_sector_of : kind:string -> string val last_cemented_commitment_hash_with_level : sc_rollup:string -> Client.t -> (string * int) Lwt.t + +(** [genesis_commitment ~sc_rollup client] returns the genesis + commitment, fails if this commitment have been cleaned from the + context. *) +val genesis_commitment : + sc_rollup:string -> Client.t -> Sc_rollup_client.commitment Lwt.t diff --git a/tezt/tests/sc_rollup.ml b/tezt/tests/sc_rollup.ml index cd5cc3ca5e8f..7fc763398c6d 100644 --- a/tezt/tests/sc_rollup.ml +++ b/tezt/tests/sc_rollup.ml @@ -4803,6 +4803,148 @@ let test_migration_recover ~kind ~migrate_from ~migrate_to = ~description () +(* Test to refute a commitment pre-migration. *) +let test_migration_refute ~kind ~migrate_from ~migrate_to = + let tags = ["refutation"] + and description = "Refuting a pre-migration commitment." + and scenario_prior tezos_client ~sc_rollup = + let* commitment1, hash1 = + bake_period_then_publish_commitment + ~sc_rollup + ~number_of_ticks:1 + ~src:Constant.bootstrap1.public_key_hash + tezos_client + in + let* _commitment2, hash2 = + forge_and_publish_commitment + ~inbox_level:commitment1.inbox_level + ~predecessor:commitment1.predecessor + ~sc_rollup + ~number_of_ticks:2 + ~src:Constant.bootstrap2.public_key_hash + tezos_client + in + return (hash1, hash2) + and scenario_after tezos_client ~sc_rollup + (player_commitment_hash, opponent_commitment_hash) = + let* {timeout_period_in_blocks = timeout_period; _} = + get_sc_rollup_constants tezos_client + in + let* () = + start_refute + tezos_client + ~sc_rollup + ~source:Constant.bootstrap1 + ~opponent:Constant.bootstrap2.public_key_hash + ~player_commitment_hash + ~opponent_commitment_hash + in + let* Sc_rollup_client.{compressed_state = state_hash; _} = + Sc_rollup_helpers.genesis_commitment ~sc_rollup tezos_client + in + let* () = + move_refute_with_unique_state_hash + ~number_of_sections_in_dissection:3 + tezos_client + ~source:Constant.bootstrap1 + ~opponent:Constant.bootstrap2.public_key_hash + ~sc_rollup + ~state_hash + in + let* () = + repeat (timeout_period + 1) (fun () -> + Client.bake_for_and_wait tezos_client) + in + let* () = + timeout + ~sc_rollup + ~staker1:Constant.bootstrap1.public_key_hash + ~staker2:Constant.bootstrap2.public_key_hash + tezos_client + in + unit + in + test_l1_migration_scenario + ~kind + ~migrate_from + ~migrate_to + ~scenario_prior + ~scenario_after + ~tags + ~description + () + +(* Test to refute a commitment pre-migration. *) +let test_cont_refute_pre_migration ~kind ~migrate_from ~migrate_to = + let tags = ["refutation"] + and description = + "Refuting a commitment pre-migration when the game started pre-migration." + and scenario_prior tezos_client ~sc_rollup = + let* commitment1, player_commitment_hash = + bake_period_then_publish_commitment + ~sc_rollup + ~number_of_ticks:1 + ~src:Constant.bootstrap1.public_key_hash + tezos_client + in + let* _commitment2, opponent_commitment_hash = + forge_and_publish_commitment + ~inbox_level:commitment1.inbox_level + ~predecessor:commitment1.predecessor + ~sc_rollup + ~number_of_ticks:2 + ~src:Constant.bootstrap2.public_key_hash + tezos_client + in + let* () = + start_refute + tezos_client + ~sc_rollup + ~source:Constant.bootstrap1 + ~opponent:Constant.bootstrap2.public_key_hash + ~player_commitment_hash + ~opponent_commitment_hash + in + unit + and scenario_after tezos_client ~sc_rollup () = + let* {timeout_period_in_blocks = timeout_period; _} = + get_sc_rollup_constants tezos_client + in + let* Sc_rollup_client.{compressed_state = state_hash; _} = + Sc_rollup_helpers.genesis_commitment ~sc_rollup tezos_client + in + let* () = + move_refute_with_unique_state_hash + ~number_of_sections_in_dissection:3 + tezos_client + ~source:Constant.bootstrap1 + ~opponent:Constant.bootstrap2.public_key_hash + ~sc_rollup + ~state_hash + in + let* () = + repeat (timeout_period + 1) (fun () -> + Client.bake_for_and_wait tezos_client) + in + let* () = + timeout + ~sc_rollup + ~staker1:Constant.bootstrap1.public_key_hash + ~staker2:Constant.bootstrap2.public_key_hash + tezos_client + in + unit + in + test_l1_migration_scenario + ~kind + ~migrate_from + ~migrate_to + ~scenario_prior + ~scenario_after + ~tags + ~description + () + let test_injector_auto_discard = test_full_scenario { @@ -5033,7 +5175,9 @@ let register_migration ~kind ~migrate_from ~migrate_to = test_migration_inbox ~kind ~migrate_from ~migrate_to ; test_migration_ticket_inbox ~kind ~migrate_from ~migrate_to ; test_migration_cement ~kind ~migrate_from ~migrate_to ; - test_migration_recover ~kind ~migrate_from ~migrate_to + test_migration_recover ~kind ~migrate_from ~migrate_to ; + test_migration_refute ~kind ~migrate_from ~migrate_to ; + test_cont_refute_pre_migration ~kind ~migrate_from ~migrate_to let register_migration ~migrate_from ~migrate_to = register_migration ~kind:"arith" ~migrate_from ~migrate_to ; -- GitLab