diff --git a/src/proto_alpha/lib_client/mockup.ml b/src/proto_alpha/lib_client/mockup.ml index 0225f8cccc7bb1513945a8f190de9c0a426e170c..16734e86ee5495d3ded3f8788106d17998f5d5b5 100644 --- a/src/proto_alpha/lib_client/mockup.ml +++ b/src/proto_alpha/lib_client/mockup.ml @@ -63,6 +63,7 @@ module Protocol_constants_overrides = struct max_lookahead_in_blocks : int32 option; max_active_outbox_levels : int32 option; max_outbox_messages_per_level : int option; + number_of_sections_in_dissection : int option; } type t = { @@ -196,7 +197,8 @@ module Protocol_constants_overrides = struct c.commitment_period_in_blocks, c.max_lookahead_in_blocks, c.max_active_outbox_levels, - c.max_outbox_messages_per_level )) + c.max_outbox_messages_per_level, + c.number_of_sections_in_dissection )) (fun ( sc_rollup_enable, sc_rollup_origination_size, sc_rollup_challenge_window_in_blocks, @@ -205,7 +207,8 @@ module Protocol_constants_overrides = struct sc_rollup_commitment_period_in_blocks, sc_rollup_max_lookahead_in_blocks, sc_rollup_max_active_outbox_levels, - sc_rollup_max_outbox_messages_per_level ) -> + sc_rollup_max_outbox_messages_per_level, + sc_rollup_number_of_sections_in_dissection ) -> { enable = sc_rollup_enable; origination_size = sc_rollup_origination_size; @@ -217,8 +220,10 @@ module Protocol_constants_overrides = struct max_active_outbox_levels = sc_rollup_max_active_outbox_levels; max_outbox_messages_per_level = sc_rollup_max_outbox_messages_per_level; + number_of_sections_in_dissection = + sc_rollup_number_of_sections_in_dissection; }) - (obj9 + (obj10 (opt "sc_rollup_enable" bool) (opt "sc_rollup_origination_size" int31) (opt "sc_rollup_challenge_window_in_blocks" int31) @@ -227,7 +232,8 @@ module Protocol_constants_overrides = struct (opt "sc_rollup_commitment_period_in_blocks" int31) (opt "sc_rollup_max_lookahead_in_blocks" int32) (opt "sc_rollup_max_active_outbox_levels" int32) - (opt "sc_rollup_max_outbox_messages_per_level" int31)) + (opt "sc_rollup_max_outbox_messages_per_level" int31) + (opt "sc_rollup_number_of_sections_in_dissection" uint8)) let encoding = let open Data_encoding in @@ -508,6 +514,8 @@ module Protocol_constants_overrides = struct Some parametric.sc_rollup.max_active_outbox_levels; max_outbox_messages_per_level = Some parametric.sc_rollup.max_outbox_messages_per_level; + number_of_sections_in_dissection = + Some parametric.sc_rollup.number_of_sections_in_dissection; }; dal = Some parametric.dal; tx_rollup = @@ -595,6 +603,7 @@ module Protocol_constants_overrides = struct max_lookahead_in_blocks = None; max_active_outbox_levels = None; max_outbox_messages_per_level = None; + number_of_sections_in_dissection = None; }; dal = None; tx_rollup = @@ -1086,6 +1095,10 @@ module Protocol_constants_overrides = struct Option.value ~default:c.sc_rollup.max_outbox_messages_per_level o.sc_rollup.max_outbox_messages_per_level; + number_of_sections_in_dissection = + Option.value + ~default:c.sc_rollup.number_of_sections_in_dissection + o.sc_rollup.number_of_sections_in_dissection; }; dal = Option.value ~default:c.dal o.dal; tx_rollup = diff --git a/src/proto_alpha/lib_parameters/default_parameters.ml b/src/proto_alpha/lib_parameters/default_parameters.ml index c05954b0d9ac50a609e372016d5007d5fcf1aba9..256cea8a1ac759d347d9eff484de6f7f0bc4b1aa 100644 --- a/src/proto_alpha/lib_parameters/default_parameters.ml +++ b/src/proto_alpha/lib_parameters/default_parameters.ml @@ -211,6 +211,7 @@ let constants_mainnet = max_lookahead_in_blocks = 30_000l; max_active_outbox_levels = sc_rollup_max_active_outbox_levels; max_outbox_messages_per_level = sc_rollup_max_outbox_messages_per_level; + number_of_sections_in_dissection = 32; }; } diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 01c3d3225d8faeca0bf13ff5d95f0b7848510029..ec0a6a33a99216c02dcf15e01b82cba13e8f7f03 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -808,6 +808,7 @@ module Constants : sig max_lookahead_in_blocks : int32; max_active_outbox_levels : int32; max_outbox_messages_per_level : int; + number_of_sections_in_dissection : int; } type t = { @@ -992,6 +993,8 @@ module Constants : sig val sc_rollup_max_outbox_messages_per_level : context -> int + val sc_rollup_number_of_sections_in_dissection : context -> int + (** All constants: fixed and parametric *) type t = private {fixed : fixed; parametric : Parametric.t} @@ -3309,6 +3312,7 @@ module Sc_rollup : sig level : Raw_level.t; pvm_name : string; dissection : dissection_chunk list; + default_number_of_sections : int; } val pp : Format.formatter -> t -> unit @@ -3354,17 +3358,21 @@ module Sc_rollup : sig child:Commitment.t -> refuter:Staker.t -> defender:Staker.t -> + default_number_of_sections:int -> t - val check_dissection : - State_hash.t option -> - Tick.t -> - State_hash.t option -> - Tick.t -> - dissection_chunk list -> - (unit, reason) result Lwt.t - val play : t -> refutation -> (outcome, t) Either.t Lwt.t + + module Internal_for_tests : sig + val check_dissection : + default_number_of_sections:int -> + State_hash.t option -> + Tick.t -> + State_hash.t option -> + Tick.t -> + dissection_chunk list -> + (unit, reason) result Lwt.t + end end module Stake_storage : sig diff --git a/src/proto_alpha/lib_protocol/constants_parametric_repr.ml b/src/proto_alpha/lib_protocol/constants_parametric_repr.ml index 6d8678201e3360606d60e3617a389ba2248b0feb..ff05aeeed3cf8b5c6c4c728411a5f3275eb1e3fe 100644 --- a/src/proto_alpha/lib_protocol/constants_parametric_repr.ml +++ b/src/proto_alpha/lib_protocol/constants_parametric_repr.ml @@ -104,6 +104,7 @@ type sc_rollup = { max_lookahead_in_blocks : int32; max_active_outbox_levels : int32; max_outbox_messages_per_level : int; + number_of_sections_in_dissection : int; } type t = { @@ -235,7 +236,8 @@ let sc_rollup_encoding = c.commitment_period_in_blocks, c.max_lookahead_in_blocks, c.max_active_outbox_levels, - c.max_outbox_messages_per_level )) + c.max_outbox_messages_per_level, + c.number_of_sections_in_dissection )) (fun ( sc_rollup_enable, sc_rollup_origination_size, sc_rollup_challenge_window_in_blocks, @@ -244,7 +246,8 @@ let sc_rollup_encoding = sc_rollup_commitment_period_in_blocks, sc_rollup_max_lookahead_in_blocks, sc_rollup_max_active_outbox_levels, - sc_rollup_max_outbox_messages_per_level ) -> + sc_rollup_max_outbox_messages_per_level, + sc_rollup_number_of_sections_in_dissection ) -> { enable = sc_rollup_enable; origination_size = sc_rollup_origination_size; @@ -255,8 +258,10 @@ let sc_rollup_encoding = max_lookahead_in_blocks = sc_rollup_max_lookahead_in_blocks; max_active_outbox_levels = sc_rollup_max_active_outbox_levels; max_outbox_messages_per_level = sc_rollup_max_outbox_messages_per_level; + number_of_sections_in_dissection = + sc_rollup_number_of_sections_in_dissection; }) - (obj9 + (obj10 (req "sc_rollup_enable" bool) (req "sc_rollup_origination_size" int31) (req "sc_rollup_challenge_window_in_blocks" int31) @@ -265,7 +270,8 @@ let sc_rollup_encoding = (req "sc_rollup_commitment_period_in_blocks" int31) (req "sc_rollup_max_lookahead_in_blocks" int32) (req "sc_rollup_max_active_outbox_levels" int32) - (req "sc_rollup_max_outbox_messages_per_level" int31)) + (req "sc_rollup_max_outbox_messages_per_level" int31) + (req "sc_rollup_number_of_sections_in_dissection" uint8)) let encoding = let open Data_encoding in diff --git a/src/proto_alpha/lib_protocol/constants_parametric_repr.mli b/src/proto_alpha/lib_protocol/constants_parametric_repr.mli index 41a652bc63cbde746bccb75b0d0a30b603c5d082..94acc0c7c5c39fb08d60248bf8d23925f71f05e3 100644 --- a/src/proto_alpha/lib_protocol/constants_parametric_repr.mli +++ b/src/proto_alpha/lib_protocol/constants_parametric_repr.mli @@ -100,6 +100,8 @@ type sc_rollup = { if it has an associated record of applied messages. *) max_active_outbox_levels : int32; max_outbox_messages_per_level : int; + (* The default number of required sections in a dissection *) + number_of_sections_in_dissection : int; } type t = { diff --git a/src/proto_alpha/lib_protocol/constants_storage.ml b/src/proto_alpha/lib_protocol/constants_storage.ml index aa92d0c80ba946add3121eca9d7a80426a49088c..f4eb9bb669326e021581999479f26c5b780cee02 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.ml +++ b/src/proto_alpha/lib_protocol/constants_storage.ml @@ -262,6 +262,10 @@ let sc_rollup_max_outbox_messages_per_level c = let sc_rollup = Raw_context.sc_rollup c in sc_rollup.max_outbox_messages_per_level +let sc_rollup_number_of_sections_in_dissection c = + let sc_rollup = Raw_context.sc_rollup c in + sc_rollup.number_of_sections_in_dissection + let dal_number_of_slots c = let constants = Raw_context.constants c in constants.dal.number_of_slots diff --git a/src/proto_alpha/lib_protocol/constants_storage.mli b/src/proto_alpha/lib_protocol/constants_storage.mli index f3aff29231fce1dad979506e40ee4bb97668005a..6a92a6560a185d722e74f1eea6b974ab8a3591b1 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.mli +++ b/src/proto_alpha/lib_protocol/constants_storage.mli @@ -153,6 +153,8 @@ val sc_rollup_max_active_outbox_levels : Raw_context.t -> int32 val sc_rollup_max_outbox_messages_per_level : Raw_context.t -> int +val sc_rollup_number_of_sections_in_dissection : Raw_context.t -> int + val dal_number_of_slots : Raw_context.t -> int val dal_enable : Raw_context.t -> bool diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index cccfaf3cdd306ba84d2f323ef9af9d9f6e240199..798cb716ffca98e63c2e41b3e7d62f38481ad5c7 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -999,6 +999,8 @@ let prepare_first_block ~level ~timestamp ctxt = WARNING: changing this value impacts the storage cost charged for applying messages from the outbox. *) max_outbox_messages_per_level = 100; + (* The default number of required sections in a dissection *) + number_of_sections_in_dissection = 32; }; } in diff --git a/src/proto_alpha/lib_protocol/sc_rollup_game_repr.ml b/src/proto_alpha/lib_protocol/sc_rollup_game_repr.ml index 982e4832e571d573c1941f51c3e0a4946de5fe5c..b7406bae36c4cc96aa68324b0f99e97647632d7b 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_game_repr.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_game_repr.ml @@ -40,6 +40,7 @@ module V1 = struct level : Raw_level_repr.t; pvm_name : string; dissection : dissection_chunk list; + default_number_of_sections : int; } let player_encoding = @@ -78,6 +79,7 @@ module V1 = struct level = level1; pvm_name = pvm_name1; dissection = dissection1; + default_number_of_sections = default_number_of_sections1; } { turn = turn2; @@ -85,8 +87,10 @@ module V1 = struct level = level2; pvm_name = pvm_name2; dissection = dissection2; + default_number_of_sections = default_number_of_sections2; } = player_equal turn1 turn2 + && Compare.Int.equal default_number_of_sections1 default_number_of_sections2 && Sc_rollup_inbox_repr.equal_history_proof inbox_snapshot1 inbox_snapshot2 && Raw_level_repr.equal level1 level2 && String.equal pvm_name1 pvm_name2 @@ -111,16 +115,41 @@ module V1 = struct let encoding = let open Data_encoding in conv - (fun {turn; inbox_snapshot; level; pvm_name; dissection} -> - (turn, inbox_snapshot, level, pvm_name, dissection)) - (fun (turn, inbox_snapshot, level, pvm_name, dissection) -> - {turn; inbox_snapshot; level; pvm_name; dissection}) - (obj5 + (fun { + turn; + inbox_snapshot; + level; + pvm_name; + dissection; + default_number_of_sections; + } -> + ( turn, + inbox_snapshot, + level, + pvm_name, + dissection, + default_number_of_sections )) + (fun ( turn, + inbox_snapshot, + level, + pvm_name, + dissection, + default_number_of_sections ) -> + { + turn; + inbox_snapshot; + level; + pvm_name; + dissection; + default_number_of_sections; + }) + (obj6 (req "turn" player_encoding) (req "inbox_snapshot" Sc_rollup_inbox_repr.history_proof_encoding) (req "level" Raw_level_repr.encoding) (req "pvm_name" string) - (req "dissection" dissection_encoding)) + (req "dissection" dissection_encoding) + (req "default_number_of_sections" uint8)) let pp_dissection ppf d = Format.pp_print_list @@ -227,7 +256,8 @@ end let make_chunk state_hash tick = {state_hash; tick} let initial inbox ~pvm_name ~(parent : Sc_rollup_commitment_repr.t) - ~(child : Sc_rollup_commitment_repr.t) ~refuter ~defender = + ~(child : Sc_rollup_commitment_repr.t) ~refuter ~defender + ~default_number_of_sections = let ({alice; _} : Index.t) = Index.make refuter defender in let alice_to_play = Staker.equal alice refuter in let open Sc_rollup_tick_repr in @@ -249,6 +279,7 @@ let initial inbox ~pvm_name ~(parent : Sc_rollup_commitment_repr.t) make_chunk (Some child.compressed_state) tick; make_chunk None (next tick); ]); + default_number_of_sections; } type step = @@ -421,16 +452,18 @@ let check pred reason = let open Lwt_result_syntax in if pred then return () else invalid_move reason -let check_dissection start start_tick stop stop_tick dissection = +let check_dissection ~default_number_of_sections start start_tick stop stop_tick + dissection = let open Lwt_result_syntax in let len = Z.of_int @@ List.length dissection in let dist = Sc_rollup_tick_repr.distance start_tick stop_tick in let should_be_equal_to what = Format.asprintf "The number of sections must be equal to %a" Z.pp_print what in + let num_sections = Z.of_int @@ default_number_of_sections in let* () = - if Z.(geq dist (of_int 32)) then - check Z.(equal len (of_int 32)) (should_be_equal_to (Z.of_int 32)) + if Z.geq dist num_sections then + check Z.(equal len num_sections) (should_be_equal_to num_sections) else if Z.(gt dist one) then check Z.(equal len (succ dist)) (should_be_equal_to Z.(succ dist)) else @@ -545,7 +578,15 @@ let play game refutation = in match refutation.step with | Dissection states -> - let* () = check_dissection start start_tick stop stop_tick states in + let* () = + check_dissection + ~default_number_of_sections:game.default_number_of_sections + start + start_tick + stop + stop_tick + states + in return (Either.Right { @@ -554,6 +595,7 @@ let play game refutation = level = game.level; pvm_name = game.pvm_name; dissection = states; + default_number_of_sections = game.default_number_of_sections; }) | Proof proof -> let* () = @@ -576,3 +618,9 @@ let play game refutation = match result with | Ok x -> Lwt.return x | Error reason -> Lwt.return @@ Either.Left {loser = game.turn; reason} + +module Internal_for_tests = struct + let find_choice = find_choice + + let check_dissection = check_dissection +end diff --git a/src/proto_alpha/lib_protocol/sc_rollup_game_repr.mli b/src/proto_alpha/lib_protocol/sc_rollup_game_repr.mli index d5f73ed9c99fa43bf7eab9cfaa615fa6de0b8a61..8162d73d9870e7e552799a325694dcfd5bcc494e 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_game_repr.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_game_repr.mli @@ -160,6 +160,10 @@ module V1 : sig player will specify, in the next move, a tick count that indicates the last of these states that she agrees with. + - [default_number_of_sections] is the number of sections a bisection should + contain in the more general case where we still have sufficiently many + disputed ticks. + Invariants: ----------- - [dissection] must contain at least 2 values (normally it will be 32 @@ -175,6 +179,7 @@ module V1 : sig level : Raw_level_repr.t; pvm_name : string; dissection : dissection_chunk list; + default_number_of_sections : int; } (** [equal g1 g2] returns [true] iff [g1] is equal to [g2]. *) @@ -250,6 +255,7 @@ val initial : child:Sc_rollup_commitment_repr.t -> refuter:Staker.t -> defender:Staker.t -> + default_number_of_sections:int -> t (** A [step] in the game is either a new dissection (if there are @@ -300,25 +306,34 @@ val pp_outcome : Format.formatter -> outcome -> unit val outcome_encoding : outcome Data_encoding.t -(** Checks that the tick count chosen by the current move is one of +(** Applies the move [refutation] to the game. Checks the move is + valid and returns an [Invalid_move] outcome if not. + + In the case of the game continuing, this swaps the current + player and updates the [dissection]. In the case of a [Proof] + being provided this returns an [outcome]. *) +val play : t -> refutation -> (outcome, t) Either.t Lwt.t + +module Internal_for_tests : sig + (** Checks that the tick count chosen by the current move is one of the ones in the current dissection. Returns a tuple containing the current dissection interval (including the two states) between this tick and the next. *) -val find_choice : - t -> - Sc_rollup_tick_repr.t -> - ( Sc_rollup_repr.State_hash.t option - * Sc_rollup_tick_repr.t - * Sc_rollup_repr.State_hash.t option - * Sc_rollup_tick_repr.t, - reason ) - result - Lwt.t - -(** We check firstly that [dissection] is the correct length. It must be - 32 values long, unless the distance between [start_tick] and - [stop_tick] is too small to make this possible, in which case it - should be as long as possible. (If the distance is one we fail + val find_choice : + t -> + Sc_rollup_tick_repr.t -> + ( Sc_rollup_repr.State_hash.t option + * Sc_rollup_tick_repr.t + * Sc_rollup_repr.State_hash.t option + * Sc_rollup_tick_repr.t, + reason ) + result + Lwt.t + + (** We check firstly that [dissection] is the correct length. It must be + [default_number_of_sections] values long, unless the distance between + [start_tick] and [stop_tick] is too small to make this possible, in which + case it should be as long as possible. (If the distance is one we fail immediately as there is no possible legal dissection). Then we check that [dissection] starts at the correct tick and state, @@ -332,18 +347,12 @@ val find_choice : (which are necessary to prevent a 'linear-time game' attack) will mean that sometimes the honest play is a dissection with multiple [None] states. *) -val check_dissection : - Sc_rollup_repr.State_hash.t option -> - Sc_rollup_tick_repr.t -> - Sc_rollup_repr.State_hash.t option -> - Sc_rollup_tick_repr.t -> - dissection_chunk list -> - (unit, reason) result Lwt.t - -(** Applies the move [refutation] to the game. Checks the move is - valid and returns an [Invalid_move] outcome if not. - - In the case of the game continuing, this swaps the current - player and updates the [dissection]. In the case of a [Proof] - being provided this returns an [outcome]. *) -val play : t -> refutation -> (outcome, t) Either.t Lwt.t + val check_dissection : + default_number_of_sections:int -> + Sc_rollup_repr.State_hash.t option -> + Sc_rollup_tick_repr.t -> + Sc_rollup_repr.State_hash.t option -> + Sc_rollup_tick_repr.t -> + dissection_chunk list -> + (unit, reason) result Lwt.t +end diff --git a/src/proto_alpha/lib_protocol/sc_rollup_refutation_storage.ml b/src/proto_alpha/lib_protocol/sc_rollup_refutation_storage.ml index 1ea94c5e376d1bacfff4beed2b5ca6a177f94c6b..9f9e4570e5755d91636ac8e71b5f6dfcbe376b89 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_refutation_storage.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_refutation_storage.ml @@ -227,6 +227,10 @@ let init_game ctxt rollup ~refuter ~defender = in let* ctxt, inbox = Store.Inbox.get ctxt rollup in let* kind = Store.PVM_kind.get ctxt rollup in + let default_number_of_sections = + Constants_storage.sc_rollup_number_of_sections_in_dissection ctxt + in + let game = Sc_rollup_game_repr.initial (Sc_rollup_inbox_repr.take_snapshot inbox) @@ -235,6 +239,7 @@ let init_game ctxt rollup ~refuter ~defender = ~child:child_info ~refuter ~defender + ~default_number_of_sections in let* ctxt, _ = Store.Game.init (ctxt, rollup) stakers game in let* ctxt, _ = 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 f96dd2e1b94c5165073f5cac1c7f6de93bb5aba6..86cdb5fd563e19da5f6b397a26bb6f8b7dbccb44 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 @@ -97,13 +97,29 @@ let tick_of_int_exn n = let tick_to_int_exn t = match Tick.to_int t with None -> assert false | Some n -> n +(* Default number of sections in a dissection *) +let gen_num_sections = + let open Tezos_protocol_alpha_parameters.Default_parameters in + let testnet = constants_test.sc_rollup.number_of_sections_in_dissection in + let mainnet = constants_mainnet.sc_rollup.number_of_sections_in_dissection in + let sandbox = constants_sandbox.sc_rollup.number_of_sections_in_dissection in + QCheck2.Gen.( + frequency + [ + (5, pure mainnet); + (4, pure testnet); + (2, pure sandbox); + (1, int_range 4 100); + ]) + let mk_dissection_chunk (state_hash, tick) = Game.{state_hash; tick} -let random_dissection start_at start_hash stop_at stop_hash = +let random_dissection ~default_number_of_sections start_at start_hash stop_at + stop_hash = let start_int = tick_to_int_exn start_at in let stop_int = tick_to_int_exn stop_at in let dist = stop_int - start_int in - let branch = min (dist + 1) 32 in + let branch = min (dist + 1) default_number_of_sections in let size = (dist + 1) / (branch - 1) in if dist = 1 then return None @@ -530,17 +546,19 @@ module Strategies (PVM : TestPVM with type hash = State_hash.t) = struct loop from_state from_tick (** [dissection_of_section start_tick start_state stop_tick] creates - a dissection with at most [32] pieces that are (roughly) equal + a dissection with at most {!default_number_of_sections} pieces + that are (roughly) equal spaced and whose states are computed by running the eval function until the correct tick. Note that the last piece can be as much - as 31 ticks longer than the others. *) - let dissection_of_section start_tick start_state stop_tick = + as {!default_number_of_sections} - 1 ticks longer than the others. *) + let dissection_of_section ~default_number_of_sections start_tick start_state + stop_tick = let start_int = tick_to_int_exn start_tick in let stop_int = tick_to_int_exn stop_tick in let dist = stop_int - start_int in if dist = 1 then return None else - let branch = min (dist + 1) 32 in + let branch = min (dist + 1) default_number_of_sections in let size = (dist + 1) / (branch - 1) in let tick_list = Result.to_option @@ -588,7 +606,7 @@ module Strategies (PVM : TestPVM with type hash = State_hash.t) = struct | Game.Bob -> if alice_is_refuter then Refuter_wins else Defender_wins | Game.Alice -> if alice_is_refuter then Defender_wins else Refuter_wins - let run ~inbox ~refuter_client ~defender_client = + let run ~default_number_of_sections ~inbox ~refuter_client ~defender_client = let refuter, (_ : public_key), (_ : Signature.secret_key) = Signature.generate_key () in @@ -608,7 +626,14 @@ module Strategies (PVM : TestPVM with type hash = State_hash.t) = struct get_comm Commitment.Hash.zero 0l 3l number_of_ticks initial_hash in let initial_game = - Game.initial inbox ~pvm_name:PVM.name ~parent ~child ~refuter ~defender + Game.initial + inbox + ~pvm_name:PVM.name + ~parent + ~child + ~refuter + ~defender + ~default_number_of_sections in let* outcome = let rec loop game refuter_move = @@ -630,8 +655,9 @@ module Strategies (PVM : TestPVM with type hash = State_hash.t) = struct in return outcome - let random_tick ?(from = 0) () = - Option.value ~default:Tick.initial (Tick.of_int (from + Random.int 31)) + let random_tick ?(from = 0) ~into () = + return + @@ Option.value ~default:Tick.initial (Tick.of_int (from + Random.int into)) (** checks that the stop state of a section conflicts with the one computed by the @@ -658,7 +684,7 @@ module Strategies (PVM : TestPVM with type hash = State_hash.t) = struct the given modified states. If the length is longer it creates a random decision and outputs a Refine decision with this dissection.*) - let random_decision d = + let random_decision ~default_number_of_sections d = let number_of_somes = List.length (List.filter (fun {Game.state_hash; _} -> Option.is_some state_hash) d) @@ -676,7 +702,12 @@ module Strategies (PVM : TestPVM with type hash = State_hash.t) = struct in let stop_hash = Some (random_hash ()) in let* random_dissection = - random_dissection start start_hash stop stop_hash + random_dissection + ~default_number_of_sections + start + start_hash + stop + stop_hash in match random_dissection with @@ -730,9 +761,8 @@ module Strategies (PVM : TestPVM with type hash = State_hash.t) = struct many pieces and returns a move with a Refine type conflict_resolution_step. *) - let next_move dissection = + let next_move ~default_number_of_sections dissection = let* conflict = find_conflict dissection in - match conflict with | Some ((_, start_tick), (_, next_tick)) -> let* start_state, (_ : Tick.t) = @@ -741,7 +771,12 @@ module Strategies (PVM : TestPVM with type hash = State_hash.t) = struct let* next_dissection = match start_state with | None -> return None - | Some s -> dissection_of_section start_tick s next_tick + | Some s -> + dissection_of_section + ~default_number_of_sections + start_tick + s + next_tick in let* stop_state, (_ : Tick.t) = match start_state with @@ -792,7 +827,11 @@ module Strategies (PVM : TestPVM with type hash = State_hash.t) = struct let next_move (game : Game.t) = let dissection = game.dissection in - let* mv = next_move dissection in + let* mv = + next_move + ~default_number_of_sections:game.default_number_of_sections + dissection + in match mv with Some move -> return (Some move) | None -> return None in {initial; next_move} @@ -801,24 +840,40 @@ module Strategies (PVM : TestPVM with type hash = State_hash.t) = struct MachineDirected it uses the above constructions. If the strategy is random then it uses a random section for the initial commitments and the random decision for the next move. *) - let player_from_strategy = function + let player_from_strategy ~default_number_of_sections = function | Random -> let initial = let random_state = PVM.Utils.default_state in let* stop_hash = PVM.state_hash random_state in - let random_tick = random_tick ~from:1 () in + let* random_tick = + random_tick ~from:1 ~into:(default_number_of_sections - 1) () + in return (Some (random_tick, stop_hash)) in - {initial; next_move = (fun game -> random_decision game.dissection)} + { + initial; + next_move = + (fun game -> + random_decision + ~default_number_of_sections:game.default_number_of_sections + game.dissection); + } | MachineDirected -> machine_directed (** [test_strategies defender_strategy refuter_strategy expectation inbox] runs a game based oin the two given strategies and checks that the resulting outcome fits the expectations. *) - let test_strategies defender_strategy refuter_strategy expectation inbox = - let defender_client = player_from_strategy defender_strategy in - let refuter_client = player_from_strategy refuter_strategy in - let* outcome = run ~inbox ~defender_client ~refuter_client in + let test_strategies ~default_number_of_sections defender_strategy + refuter_strategy expectation inbox = + let defender_client = + player_from_strategy ~default_number_of_sections defender_strategy + in + let refuter_client = + player_from_strategy ~default_number_of_sections refuter_strategy + in + let* outcome = + run ~default_number_of_sections ~inbox ~defender_client ~refuter_client + in return (expectation outcome) (** the possible expectation functions *) @@ -830,31 +885,50 @@ module Strategies (PVM : TestPVM with type hash = State_hash.t) = struct end (** The following are the possible combinations of strategies. *) -let perfect_perfect (module P : TestPVM) inbox = +let perfect_perfect (module P : TestPVM) inbox ~default_number_of_sections = let module R = Strategies (P) in - R.test_strategies MachineDirected MachineDirected R.defender_wins inbox - -let random_random (module P : TestPVM) inbox = + R.test_strategies + ~default_number_of_sections + MachineDirected + MachineDirected + R.defender_wins + inbox + +let random_random (module P : TestPVM) inbox ~default_number_of_sections = let module S = Strategies (P) in - S.test_strategies Random Random S.all_win inbox + S.test_strategies ~default_number_of_sections Random Random S.all_win inbox -let random_perfect (module P : TestPVM) inbox = +let random_perfect (module P : TestPVM) inbox ~default_number_of_sections = let module S = Strategies (P) in - S.test_strategies Random MachineDirected S.refuter_wins inbox - -let perfect_random (module P : TestPVM) inbox = + S.test_strategies + Random + MachineDirected + S.refuter_wins + inbox + ~default_number_of_sections + +let perfect_random (module P : TestPVM) inbox ~default_number_of_sections = let module S = Strategies (P) in - S.test_strategies MachineDirected Random S.defender_wins inbox + S.test_strategies + MachineDirected + Random + S.defender_wins + inbox + ~default_number_of_sections (** This assembles a test from a RandomPVM and a function that chooses the type of strategies. *) let testing_randomPVM - (f : (module TestPVM) -> Inbox.history_proof -> bool Lwt.t) name = + (f : + (module TestPVM) -> + Inbox.history_proof -> + default_number_of_sections:int -> + bool Lwt.t) name = let open QCheck2 in Test.make ~name - Gen.(list_size small_int (int_range 0 100)) - (fun initial_prog -> + Gen.(pair (list_size small_int (int_range 0 100)) gen_num_sections) + (fun (initial_prog, default_number_of_sections) -> assume (initial_prog <> []) ; let rollup = Address.hash_string [""] in let level = Raw_level.root in @@ -866,14 +940,22 @@ let testing_randomPVM (module MakeRandomPVM (struct let initial_prog = initial_prog end)) - snapshot) + snapshot + ~default_number_of_sections) (** This assembles a test from a CountingPVM and a function that chooses the type of strategies *) -let testing_countPVM (f : (module TestPVM) -> Inbox.history_proof -> bool Lwt.t) - name = +let testing_countPVM + (f : + (module TestPVM) -> + Inbox.history_proof -> + default_number_of_sections:int -> + bool Lwt.t) name = let open QCheck2 in - Test.make ~name Gen.small_int (fun target -> + Test.make + ~name + Gen.(pair small_int gen_num_sections) + (fun (target, default_number_of_sections) -> assume (target > 200) ; let rollup = Address.hash_string [""] in let level = Raw_level.root in @@ -885,15 +967,20 @@ let testing_countPVM (f : (module TestPVM) -> Inbox.history_proof -> bool Lwt.t) (module MakeCountingPVM (struct let target = target end)) - snapshot) - -let testing_arith (f : (module TestPVM) -> Inbox.history_proof -> bool Lwt.t) - name = + snapshot + ~default_number_of_sections) + +let testing_arith + (f : + (module TestPVM) -> + Inbox.history_proof -> + default_number_of_sections:int -> + bool Lwt.t) name = let open QCheck2 in Test.make ~name - Gen.(pair gen_list small_int) - (fun (inputs, evals) -> + Gen.(triple gen_list small_int gen_num_sections) + (fun (inputs, evals, default_number_of_sections) -> assume (evals > 1 && evals < List.length inputs - 1) ; let rollup = Address.hash_string [""] in let level = Raw_level.root in @@ -907,9 +994,11 @@ let testing_arith (f : (module TestPVM) -> Inbox.history_proof -> bool Lwt.t) let evals = evals end)) - snapshot) + snapshot + ~default_number_of_sections) -let test_random_dissection (module P : TestPVM) start_at length = +let test_random_dissection (module P : TestPVM) start_at length + ~default_number_of_sections = let open P in let module S = Strategies (P) in let section_start_state = Utils.default_state in @@ -926,7 +1015,11 @@ let test_random_dissection (module P : TestPVM) start_at length = match Tick.of_int start_at with None -> assert false | Some x -> x in let* option_dissection = - S.dissection_of_section section_start_at section_start_state section_stop_at + S.dissection_of_section + ~default_number_of_sections + section_start_at + section_start_state + section_stop_at in let dissection = match option_dissection with @@ -936,7 +1029,8 @@ let test_random_dissection (module P : TestPVM) start_at length = let* start = state_hash section_start_state in let stop_hash = Some (aux start) in let* check = - Game.check_dissection + Game.Internal_for_tests.check_dissection + ~default_number_of_sections (Some start) section_start_at stop_hash @@ -950,24 +1044,39 @@ let testDissection = [ Test.make ~name:"randomVPN" - Gen.(triple (list_size small_int (int_range 0 100)) small_int small_int) - (fun (initial_prog, start_at, length) -> + Gen.( + quad + (list_size small_int (int_range 0 100)) + small_int + small_int + gen_num_sections) + (fun (initial_prog, start_at, length, default_number_of_sections) -> assume (start_at >= 0 && length > 1 && List.length initial_prog > start_at + length) ; let module P = MakeRandomPVM (struct let initial_prog = initial_prog end) in - Lwt_main.run @@ test_random_dissection (module P) start_at length); + Lwt_main.run + @@ test_random_dissection + (module P) + start_at + length + ~default_number_of_sections); Test.make ~name:"count" - Gen.(triple small_int small_int small_int) - (fun (target, start_at, length) -> + Gen.(quad small_int small_int small_int gen_num_sections) + (fun (target, start_at, length, default_number_of_sections) -> assume (start_at >= 0 && length > 1) ; let module P = MakeCountingPVM (struct let target = target end) in - Lwt_main.run @@ test_random_dissection (module P) start_at length); + Lwt_main.run + @@ test_random_dissection + (module P) + start_at + length + ~default_number_of_sections); ] let testRandomDissection = @@ -975,8 +1084,8 @@ let testRandomDissection = [ Test.make ~name:"randomdissection" - Gen.(pair small_int small_int) - (fun (start_int, length) -> + Gen.(triple small_int small_int gen_num_sections) + (fun (start_int, length, default_number_of_sections) -> assume (start_int > 0 && length >= 10) ; let testing_lwt = let start_at = tick_of_int_exn start_int in @@ -985,7 +1094,12 @@ let testRandomDissection = let stop_hash = Some (random_hash ()) in let* dissection_opt = - random_dissection start_at start_hash stop_at stop_hash + random_dissection + ~default_number_of_sections + start_at + start_hash + stop_at + stop_hash in let dissection = match dissection_opt with None -> assert false | Some d -> d @@ -996,7 +1110,8 @@ let testRandomDissection = in let new_hash = aux stop_hash in let* check = - Game.check_dissection + Game.Internal_for_tests.check_dissection + ~default_number_of_sections (Some start_hash) start_at new_hash diff --git a/src/proto_alpha/lib_protocol/test/pbt/test_sc_rollup_encoding.ml b/src/proto_alpha/lib_protocol/test/pbt/test_sc_rollup_encoding.ml index ccb0e9eb9fad7d7d7b2d63f98cc8ba78a8100529..c6c648385f6476e860e55e3dd93d4611d488e41e 100644 --- a/src/proto_alpha/lib_protocol/test/pbt/test_sc_rollup_encoding.ml +++ b/src/proto_alpha/lib_protocol/test/pbt/test_sc_rollup_encoding.ml @@ -156,12 +156,22 @@ let gen_game = let* inbox_snapshot = gen_inbox_history_proof rollup level in let* pvm_name = gen_pvm_name in let* dissection = gen_dissection in + let* default_number_of_sections = int_range 4 100 in let dissection = List.map (fun (state_hash, tick) -> Sc_rollup_game_repr.{state_hash; tick}) dissection in - return Sc_rollup_game_repr.{turn; inbox_snapshot; level; pvm_name; dissection} + return + Sc_rollup_game_repr. + { + turn; + inbox_snapshot; + level; + pvm_name; + dissection; + default_number_of_sections (* should be greater than 3 *); + } let gen_conflict = let open Gen in diff --git a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_game.ml b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_game.ml index 94e9c511abd50b115827761e63db13c6f1beec96..33d0bb332de491d0c0a259c7645ce0a318a18c48 100644 --- a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_game.ml +++ b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_game.ml @@ -69,7 +69,7 @@ let hash_int n = hash_string (Format.sprintf "%d" n) let mk_dissection_chunk (state_hash, tick) = G.{state_hash; tick} -let init_dissection ?(size = 32) ?init_tick start_hash = +let init_dissection ~size ?init_tick start_hash = let default_init_tick i = let hash = if i = size - 1 then None @@ -85,11 +85,11 @@ let init_dissection ?(size = 32) ?init_tick start_hash = in Stdlib.List.init size init_tick -let init_refutation ?size ?init_tick start_hash = +let init_refutation ~size ?init_tick start_hash = G. { choice = Sc_rollup_tick_repr.initial; - step = Dissection (init_dissection ?size ?init_tick start_hash); + step = Dissection (init_dissection ~size ?init_tick start_hash); } let two_stakers_in_conflict () = @@ -163,7 +163,10 @@ let test_poorly_distributed_dissection () = let* ctxt = T.lift @@ R.start_game ctxt rollup ~player:refuter ~opponent:defender in - let move = init_refutation ~init_tick start_hash in + let size = + Constants_storage.sc_rollup_number_of_sections_in_dissection ctxt + in + let move = init_refutation ~size ~init_tick start_hash in let* outcome, _ctxt = T.lift @@ R.game_move ctxt rollup ~player:refuter ~opponent:defender move in @@ -176,13 +179,17 @@ let test_poorly_distributed_dissection () = let test_single_valid_game_move () = let* ctxt, rollup, refuter, defender = two_stakers_in_conflict () in let start_hash = hash_string "foo" in + let size = + Constants_storage.sc_rollup_number_of_sections_in_dissection ctxt + in + let tick_per_state = 10_000 / size in let dissection = - Stdlib.List.init 32 (fun i -> + Stdlib.List.init size (fun i -> mk_dissection_chunk @@ if i = 0 then (Some start_hash, tick_of_int_exn 0) - else if i = 31 then (None, tick_of_int_exn 10000) - else (Some (hash_int i), tick_of_int_exn (i * 200))) + else if i = size - 1 then (None, tick_of_int_exn 10000) + else (Some (hash_int i), tick_of_int_exn (i * tick_per_state))) in let* ctxt = T.lift @@ R.start_game ctxt rollup ~player:refuter ~opponent:defender @@ -230,7 +237,10 @@ let staker_injectivity_gen ~refuter2_plays = let hash2 = hash_string "bar" in let hash3 = hash_string "xyz" in let hash4 = hash_string "abc" in - let refutation = init_refutation hash1 in + let size = + Constants_storage.sc_rollup_number_of_sections_in_dissection ctxt + in + let refutation = init_refutation ~size hash1 in let commit1 = Commitment_repr. { diff --git a/tests_python/tests_alpha/test_mockup.py b/tests_python/tests_alpha/test_mockup.py index d8b03e378c103aa7501f09a130fd16f0ac84709b..fd5451420b53d5cec9d34e9570435506e937c8e2 100644 --- a/tests_python/tests_alpha/test_mockup.py +++ b/tests_python/tests_alpha/test_mockup.py @@ -689,6 +689,7 @@ def _test_create_mockup_init_show_roundtrip( "sc_rollup_max_lookahead_in_blocks": 30_000, "sc_rollup_max_active_outbox_levels": 20_160, "sc_rollup_max_outbox_messages_per_level": 100, + "sc_rollup_number_of_sections_in_dissection": 32, } ), ], diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol.out index 4de1c9ba32ad83bf125de16742dcf54f6ad7fe17..00036eba103f2b60d25663021d55aa3fed821f4f 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol.out @@ -55,7 +55,8 @@ "sc_rollup_commitment_period_in_blocks": 30, "sc_rollup_max_lookahead_in_blocks": 30000, "sc_rollup_max_active_outbox_levels": 20160, - "sc_rollup_max_outbox_messages_per_level": 100 } + "sc_rollup_max_outbox_messages_per_level": 100, + "sc_rollup_number_of_sections_in_dissection": 32 } ./tezos-client rpc get /chains/main/blocks/head/helpers/baking_rights [ { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode light) RPC regression tests- misc_protocol.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode light) RPC regression tests- misc_protocol.out index 550580f4db2884589e17548189c5cb8c9233e2c8..8bc086405acc1b705d647e85e99d6bee3d6408de 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode light) RPC regression tests- misc_protocol.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode light) RPC regression tests- misc_protocol.out @@ -55,7 +55,8 @@ "sc_rollup_commitment_period_in_blocks": 30, "sc_rollup_max_lookahead_in_blocks": 30000, "sc_rollup_max_active_outbox_levels": 20160, - "sc_rollup_max_outbox_messages_per_level": 100 } + "sc_rollup_max_outbox_messages_per_level": 100, + "sc_rollup_number_of_sections_in_dissection": 32 } protocol of light mode unspecified, using the node's protocol: ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im ./tezos-client --mode light rpc get /chains/main/blocks/head/helpers/baking_rights diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- misc_protocol.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- misc_protocol.out index de3836004240abda6419adcfc6dfe1db47687547..2db71be7263c5cd63c2cb3c4f6baeea409a6a8a1 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- misc_protocol.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- misc_protocol.out @@ -55,7 +55,8 @@ "sc_rollup_commitment_period_in_blocks": 30, "sc_rollup_max_lookahead_in_blocks": 30000, "sc_rollup_max_active_outbox_levels": 20160, - "sc_rollup_max_outbox_messages_per_level": 100 } + "sc_rollup_max_outbox_messages_per_level": 100, + "sc_rollup_number_of_sections_in_dissection": 32 } protocol of proxy unspecified, using the node's protocol: ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im ./tezos-client --mode proxy rpc get /chains/main/blocks/head/helpers/baking_rights diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_data_dir) RPC regression tests- misc_protocol.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_data_dir) RPC regression tests- misc_protocol.out index f19b21573f7a69b24255abd8de8ef12016ebf116..29f76dad638c780f6ee1dfa216bdc439580ed5cc 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_data_dir) RPC regression tests- misc_protocol.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_data_dir) RPC regression tests- misc_protocol.out @@ -55,7 +55,8 @@ "sc_rollup_commitment_period_in_blocks": 30, "sc_rollup_max_lookahead_in_blocks": 30000, "sc_rollup_max_active_outbox_levels": 20160, - "sc_rollup_max_outbox_messages_per_level": 100 } + "sc_rollup_max_outbox_messages_per_level": 100, + "sc_rollup_number_of_sections_in_dissection": 32 } ./tezos-client rpc get /chains/main/blocks/head/helpers/baking_rights [ { "level": 3, "delegate": "[PUBLIC_KEY_HASH]", diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_rpc) RPC regression tests- misc_protocol.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_rpc) RPC regression tests- misc_protocol.out index f19b21573f7a69b24255abd8de8ef12016ebf116..29f76dad638c780f6ee1dfa216bdc439580ed5cc 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_rpc) RPC regression tests- misc_protocol.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_rpc) RPC regression tests- misc_protocol.out @@ -55,7 +55,8 @@ "sc_rollup_commitment_period_in_blocks": 30, "sc_rollup_max_lookahead_in_blocks": 30000, "sc_rollup_max_active_outbox_levels": 20160, - "sc_rollup_max_outbox_messages_per_level": 100 } + "sc_rollup_max_outbox_messages_per_level": 100, + "sc_rollup_number_of_sections_in_dissection": 32 } ./tezos-client rpc get /chains/main/blocks/head/helpers/baking_rights [ { "level": 3, "delegate": "[PUBLIC_KEY_HASH]", diff --git a/tezt/tests/expected/sc_rollup.ml/Alpha- observing the correct handling of commitments in the rollup node (no_comm.out b/tezt/tests/expected/sc_rollup.ml/Alpha- observing the correct handling of commitments in the rollup node (no_comm.out index 14cb7219f274f4fe42d111363e4fe5aa6b2e1395..5d6a8a4a98f3050ba2da762eb915e109b34f662d 100644 --- a/tezt/tests/expected/sc_rollup.ml/Alpha- observing the correct handling of commitments in the rollup node (no_comm.out +++ b/tezt/tests/expected/sc_rollup.ml/Alpha- observing the correct handling of commitments in the rollup node (no_comm.out @@ -109,7 +109,8 @@ This sequence of operations was run: "sc_rollup_commitment_period_in_blocks": 30, "sc_rollup_max_lookahead_in_blocks": 30000, "sc_rollup_max_active_outbox_levels": 20160, - "sc_rollup_max_outbox_messages_per_level": 100 } + "sc_rollup_max_outbox_messages_per_level": 100, + "sc_rollup_number_of_sections_in_dissection": 32 } ./tezos-client --wait none recover bond of '[PUBLIC_KEY_HASH]' for sc rollup '[SC_ROLLUP_HASH]' --fee 1 Node is bootstrapped. @@ -211,7 +212,8 @@ This sequence of operations was run: "sc_rollup_commitment_period_in_blocks": 30, "sc_rollup_max_lookahead_in_blocks": 30000, "sc_rollup_max_active_outbox_levels": 20160, - "sc_rollup_max_outbox_messages_per_level": 100 } + "sc_rollup_max_outbox_messages_per_level": 100, + "sc_rollup_number_of_sections_in_dissection": 32 } ./tezos-client --wait none recover bond of '[PUBLIC_KEY_HASH]' for sc rollup '[SC_ROLLUP_HASH]' --fee 1 Node is bootstrapped.