From c963962b6d9bc0a9459f832ca796543c12b4fd68 Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Thu, 6 Feb 2025 00:43:23 +0100 Subject: [PATCH] EVM Node: Drop default rolling and store gc parameters in the store In this patch, we force users to explicitely set the desired retention period when they use the rolling mode, and we store this information in the store. This forces users to decide how much history they will keep, which will reduce the risk for us to introduce breaking changes by modifying the default configuration. This patch also remove the ability to switch from `rolling` to `archive`. This could be introduced later, but at first, it is probably less confusing to force a user to reimport an archive node instead. --- etherlink/bin_node/config/configuration.ml | 130 ++++++------------ etherlink/bin_node/config/configuration.mli | 14 +- etherlink/bin_node/lib_dev/evm_context.ml | 73 ++++------ etherlink/bin_node/lib_dev/evm_context.mli | 4 +- etherlink/bin_node/lib_dev/evm_store.ml | 13 +- etherlink/bin_node/main.ml | 54 +++----- etherlink/bin_node/migrations/018_rolling.sql | 4 + etherlink/script-inputs/evm_store_migrations | 1 + etherlink/tezt/lib/evm_node.ml | 7 +- .../EVM node- list events regression.out | 16 ++- .../EVM Node- describe config.out | 19 +-- .../evm_sequencer.ml/EVM Node- man.out | 2 +- etherlink/tezt/tests/gc.ml | 62 +++++---- 13 files changed, 169 insertions(+), 230 deletions(-) create mode 100644 etherlink/bin_node/migrations/018_rolling.sql diff --git a/etherlink/bin_node/config/configuration.ml b/etherlink/bin_node/config/configuration.ml index d767d8cd9c05..cd8d184e7736 100644 --- a/etherlink/bin_node/config/configuration.ml +++ b/etherlink/bin_node/config/configuration.ml @@ -44,7 +44,7 @@ type garbage_collector_parameters = { number_of_chunks : int; } -type history_mode = Archive | Rolling +type history_mode = Archive | Rolling of garbage_collector_parameters type rpc_server = Resto | Dream @@ -133,7 +133,6 @@ type t = { experimental_features : experimental_features; fee_history : fee_history; finalized_view : bool; - garbage_collector_parameters : garbage_collector_parameters; history_mode : history_mode option; } @@ -148,10 +147,25 @@ let default_enable_send_raw_transaction = true let default_history_mode = Archive -let retention ?(days = 14) () = +let gc_param_from_retention_period ~days = {split_frequency_in_seconds = 86_400; number_of_chunks = days} -let default_garbage_collector_parameters = retention () +let history_mode_of_string_opt str = + let open Option_syntax in + match String.split_on_char ':' str with + | ["archive"] -> return Archive + | ["rolling"; days] -> + let* days = int_of_string_opt days in + if days > 0 then return (Rolling (gc_param_from_retention_period ~days)) + else None + | _ -> None + +let string_of_history_mode = function + | Archive -> "archive" + | Rolling gc -> Format.sprintf "rolling:%d" gc.number_of_chunks + +let pp_history_mode fmt h = + Format.pp_print_string fmt @@ string_of_history_mode h (* This should be enough for messages we expect to receive in the ethereum JSONRPC protocol. *) @@ -717,68 +731,30 @@ let observer_encoding ?network () = bool default_rollup_node_tracking)) -let garbage_collector_parameters_encoding = - let open Data_encoding in - let int_days = - def - "days" - ~title:"number_of_days" - ~description:"Number of days of history to retain" - (ranged_int 0 ((1 lsl 30) - 1)) - in - conv - (function - | {split_frequency_in_seconds = 86_400; number_of_chunks} -> - number_of_chunks - | _ -> Stdlib.failwith "GC split frequency must one day") - (fun number_of_chunks -> - {split_frequency_in_seconds = 86_400; number_of_chunks}) - int_days - let rpc_server_encoding = let open Data_encoding in string_enum [("resto", Resto); ("dream", Dream)] -let history_mode_encoding = - let open Data_encoding in - string_enum [("archive", Archive); ("rolling", Rolling)] - -let pp_history_mode fmt h = - Format.pp_print_string fmt - @@ match h with Archive -> "archive" | Rolling -> "rolling" +let history_mode_schema = + Data_encoding.( + Json.schema @@ string_enum [("archive", ()); ("rolling:n", ())]) -let history_mode_and_gc_parameters_encoding = +let history_mode_encoding = let open Data_encoding in - union - [ - case - ~title:"archive" - (Tag 0) - (constant "archive") - (function Archive, _ -> Some () | _ -> None) - (fun () -> (Archive, default_garbage_collector_parameters)); - case - ~title:"rolling_default_gc" - (Tag 1) - (constant "rolling") - (function - | _ -> - (* This is a shortcut for rolling with default GC parameters, - never output it. *) - None) - (fun () -> (Rolling, default_garbage_collector_parameters)); - case - ~title:"rolling" - (Tag 2) - (obj2 - (req "mode" (constant "rolling")) - (req - "retention" - ~description:"How much history is retained for rolling nodes." - garbage_collector_parameters_encoding)) - (function Rolling, gc -> Some ((), gc) | _ -> None) - (fun ((), gc) -> (Rolling, gc)); - ] + def + "history_mode" + ~description: + "Compact notation for the history mode. Can either be `archive` and \ + `rolling:N` with `N` being the number of days to use as the retention \ + period" + @@ conv_with_guard + ~schema:history_mode_schema + string_of_history_mode + (fun str -> + match history_mode_of_string_opt str with + | None -> Error (Format.sprintf "%s is not a valid history mode" str) + | Some m -> Ok m) + string let monitor_websocket_heartbeat_encoding = let open Data_encoding in @@ -1165,7 +1141,6 @@ let encoding ?network data_dir : t Data_encoding.t = kernel_execution; finalized_view; history_mode; - garbage_collector_parameters; } -> ( (log_filter, sequencer, threshold_encryption_sequencer, observer), ( ( tx_pool_timeout_limit, @@ -1181,9 +1156,7 @@ let encoding ?network data_dir : t Data_encoding.t = public_rpc, private_rpc, finalized_view, - match history_mode with - | Some h -> Some (h, garbage_collector_parameters) - | None -> None ) ) )) + history_mode ) ) )) (fun ( (log_filter, sequencer, threshold_encryption_sequencer, observer), ( ( tx_pool_timeout_limit, tx_pool_addr_limit, @@ -1198,12 +1171,7 @@ let encoding ?network data_dir : t Data_encoding.t = public_rpc, private_rpc, finalized_view, - history_mode_and_gc ) ) ) -> - let history_mode, garbage_collector_parameters = - match history_mode_and_gc with - | None -> (None, default_garbage_collector_parameters) - | Some (h, gc) -> (Some h, gc) - in + history_mode ) ) ) -> { public_rpc; private_rpc; @@ -1223,7 +1191,6 @@ let encoding ?network data_dir : t Data_encoding.t = kernel_execution; finalized_view; history_mode; - garbage_collector_parameters; }) (merge_objs (obj4 @@ -1303,7 +1270,7 @@ let encoding ?network data_dir : t Data_encoding.t = (opt "history" ~description:"History mode of the EVM node" - history_mode_and_gc_parameters_encoding)))) + history_mode_encoding)))) let pp_print_json ~data_dir fmt config = let json = @@ -1486,8 +1453,7 @@ module Cli = struct ?log_filter_max_nb_logs ?log_filter_chunk_size ?max_blueprints_lag ?max_blueprints_ahead ?max_blueprints_catchup ?catchup_cooldown ?sequencer_sidecar_endpoint ?restricted_rpcs ?finalized_view - ?proxy_ignore_block_param ?dal_slots ?network ?history_mode - ?garbage_collector_parameters () = + ?proxy_ignore_block_param ?dal_slots ?network ?history_mode () = let public_rpc = default_rpc ?rpc_port @@ -1596,10 +1562,6 @@ module Cli = struct fee_history = default_fee_history; finalized_view = Option.value ~default:default_finalized_view finalized_view; - garbage_collector_parameters = - Option.value - garbage_collector_parameters - ~default:default_garbage_collector_parameters; history_mode; } @@ -1642,8 +1604,7 @@ module Cli = struct ?log_filter_max_nb_logs ?log_filter_chunk_size ?max_blueprints_lag ?max_blueprints_ahead ?max_blueprints_catchup ?catchup_cooldown ?sequencer_sidecar_endpoint ?restricted_rpcs ?finalized_view - ?proxy_ignore_block_param ?history_mode ?garbage_collector_parameters - ?dal_slots configuration = + ?proxy_ignore_block_param ?history_mode ?dal_slots configuration = let public_rpc = patch_rpc ?rpc_addr @@ -1901,10 +1862,6 @@ module Cli = struct experimental_features = configuration.experimental_features; fee_history = configuration.fee_history; finalized_view = finalized_view || configuration.finalized_view; - garbage_collector_parameters = - Option.value - garbage_collector_parameters - ~default:configuration.garbage_collector_parameters; history_mode = Option.either history_mode configuration.history_mode; } @@ -1918,8 +1875,7 @@ module Cli = struct ?max_blueprints_ahead ?max_blueprints_catchup ?catchup_cooldown ?log_filter_max_nb_blocks ?log_filter_max_nb_logs ?log_filter_chunk_size ?sequencer_sidecar_endpoint ?restricted_rpcs ?finalized_view - ?proxy_ignore_block_param ?dal_slots ?network ?history_mode - ?garbage_collector_parameters () = + ?proxy_ignore_block_param ?dal_slots ?network ?history_mode () = let open Lwt_result_syntax in let open Filename.Infix in (* Check if the data directory of the evm node is not the one of Octez @@ -1975,7 +1931,6 @@ module Cli = struct ?finalized_view ?proxy_ignore_block_param ?history_mode - ?garbage_collector_parameters ?dal_slots configuration in @@ -2019,7 +1974,6 @@ module Cli = struct ?dal_slots ?network ?history_mode - ?garbage_collector_parameters () in return config diff --git a/etherlink/bin_node/config/configuration.mli b/etherlink/bin_node/config/configuration.mli index f4019620ec09..dcfa19faabd1 100644 --- a/etherlink/bin_node/config/configuration.mli +++ b/etherlink/bin_node/config/configuration.mli @@ -66,7 +66,7 @@ type garbage_collector_parameters = { type history_mode = | Archive (** Keeps all blocks, operations and states. *) - | Rolling + | Rolling of garbage_collector_parameters (** Keep blocks, operations and states for a period defined by {!type-garbage_collector_parameters}. *) @@ -170,7 +170,6 @@ type t = { experimental_features : experimental_features; fee_history : fee_history; finalized_view : bool; - garbage_collector_parameters : garbage_collector_parameters; history_mode : history_mode option; } @@ -261,9 +260,13 @@ val observer_config_dft : val make_pattern_restricted_rpcs : string -> restricted_rpcs -(** [retention ?days ()] returns the GC parameters to retain [days] of history +val string_of_history_mode : history_mode -> string + +val history_mode_of_string_opt : string -> history_mode option + +(** [retention ~days] returns the GC parameters to retain [days] of history when provided or the default otherwise. *) -val retention : ?days:int -> unit -> garbage_collector_parameters +val gc_param_from_retention_period : days:int -> garbage_collector_parameters val default_history_mode : history_mode @@ -305,7 +308,6 @@ module Cli : sig ?dal_slots:int list -> ?network:supported_network -> ?history_mode:history_mode -> - ?garbage_collector_parameters:garbage_collector_parameters -> unit -> t @@ -343,7 +345,6 @@ module Cli : sig ?finalized_view:bool -> ?proxy_ignore_block_param:bool -> ?history_mode:history_mode -> - ?garbage_collector_parameters:garbage_collector_parameters -> ?dal_slots:int list -> t -> t @@ -385,7 +386,6 @@ module Cli : sig ?dal_slots:int list -> ?network:supported_network -> ?history_mode:history_mode -> - ?garbage_collector_parameters:garbage_collector_parameters -> unit -> t tzresult Lwt.t end diff --git a/etherlink/bin_node/lib_dev/evm_context.ml b/etherlink/bin_node/lib_dev/evm_context.ml index 99b11853ce40..fb0a6147b128 100644 --- a/etherlink/bin_node/lib_dev/evm_context.ml +++ b/etherlink/bin_node/lib_dev/evm_context.ml @@ -310,7 +310,7 @@ module State = struct let* history_mode = Evm_store.Metadata.get_history_mode conn in match history_mode with | Archive -> return_none - | Rolling -> + | Rolling gc_param -> let split = match ctxt.session.last_split_block with | None -> true @@ -324,18 +324,14 @@ module State = struct >= Int64.( add last_split_timestamp - (of_int - ctxt.configuration.garbage_collector_parameters - .split_frequency_in_seconds))) + (of_int gc_param.split_frequency_in_seconds))) in if split then ( Irmin_context.split ctxt.index ; let* () = Evm_store.Irmin_chunks.insert conn level timestamp in let*! () = Evm_context_events.gc_split level timestamp in let* number_of_chunks = Evm_store.Irmin_chunks.count conn in - let max_number_of_chunks = - ctxt.configuration.garbage_collector_parameters.number_of_chunks - in + let max_number_of_chunks = gc_param.number_of_chunks in let* () = if number_of_chunks > max_number_of_chunks then let* gc_level, _gc_timestamp = @@ -1144,51 +1140,42 @@ module State = struct *) return Tezos_crypto.Hashed.Smart_rollup_address.zero - let check_history_mode ?(switch = false) ~store_history_mode ~history_mode - conn = + let history_mode_switch_status h1 h2 = + let open Configuration in + match (h1, h2) with + | Archive, Archive -> `No_switch + | Rolling gc, Rolling gc' when gc.number_of_chunks = gc'.number_of_chunks -> + `No_switch + | Rolling _, Rolling _ | Archive, Rolling _ -> `Needs_switch + | Rolling _, Archive -> `Cannot_switch + + let check_history_mode ?(switch = false) ~store_history_mode ~history_mode () + = let open Lwt_result_syntax in - match store_history_mode with - | None -> ( - match history_mode with - | None -> return Configuration.default_history_mode - | Some h -> return h) - | Some store_history_mode -> ( - match (store_history_mode, history_mode) with - | Configuration.Archive, (None | Some Archive) - | Rolling, (None | Some Rolling) -> + match (store_history_mode, history_mode) with + | Some h, None -> return h + | None, None -> return Configuration.default_history_mode + | None, Some h -> return h + | Some store_history_mode, Some history_mode -> ( + match history_mode_switch_status store_history_mode history_mode with + | `No_switch -> if switch then Format.printf "History mode is already %a, not switching@." Configuration.pp_history_mode store_history_mode ; return store_history_mode - | Archive, Some Rolling when switch -> + | `Needs_switch when switch -> let*! () = Evm_context_events.switching_history_mode - ~from:Archive - ~to_:Rolling + ~from:store_history_mode + ~to_:history_mode in - return Configuration.Rolling - | Rolling, Some Archive when switch -> - (* Switching from rolling to archive is possible, however it does - not necessarily mean all information are stored, it will just - stop garbage collecting data. *) - let* () = Evm_store.Irmin_chunks.clear conn in - let* earliest = Evm_store.Context_hashes.find_earliest conn in - let earliest_level = Option.map fst earliest in - let* () = - unless (earliest_level = Some Ethereum_types.Qty.zero) (fun () -> - let*! () = - Evm_context_events.rolling_to_archive_incomplete_history - earliest_level - in - return_unit) - in - return Configuration.Archive - | _, Some history_mode -> + return history_mode + | _ -> tzfail (Incorrect_history_mode {store_history_mode; history_mode})) - let check_metadata ~store_metadata ~smart_rollup_address ~history_mode conn = + let check_metadata ~store_metadata ~smart_rollup_address ~history_mode () = let open Lwt_result_syntax in let* smart_rollup_address = check_smart_rollup_address @@ -1206,7 +1193,7 @@ module State = struct (fun (metadata : Evm_store.metadata) -> metadata.history_mode) store_metadata) ~history_mode - conn + () in return ({smart_rollup_address; history_mode} : Evm_store.metadata) @@ -1290,7 +1277,7 @@ module State = struct ~store_metadata ~smart_rollup_address ~history_mode:configuration.history_mode - conn + () in let* () = when_ (Option.is_none store_metadata) (fun () -> @@ -1325,7 +1312,7 @@ module State = struct let* last_split_block = match history_mode with - | Rolling -> Evm_store.Irmin_chunks.latest conn + | Rolling _ -> Evm_store.Irmin_chunks.latest conn | Archive -> return_none in diff --git a/etherlink/bin_node/lib_dev/evm_context.mli b/etherlink/bin_node/lib_dev/evm_context.mli index 43fbc79319da..903acdb636e6 100644 --- a/etherlink/bin_node/lib_dev/evm_context.mli +++ b/etherlink/bin_node/lib_dev/evm_context.mli @@ -140,7 +140,7 @@ val head_watcher : Ethereum_types.Subscription.output Lwt_watcher.input (** Watcher that gets notified each time a new receipt is produced. *) val receipt_watcher : Transaction_receipt.t Lwt_watcher.input -(** [check_history_mode ?switch ~store_history_mode ~history_mode conn] checks +(** [check_history_mode ?switch ~store_history_mode ~history_mode ()] checks that the history mode are compatible, and returns the history mode the node should run in, depending on its stored mode [store_history_mode], the one requested by the configuration [history_mode] and if it is allowed to @@ -149,5 +149,5 @@ val check_history_mode : ?switch:bool -> store_history_mode:Configuration.history_mode option -> history_mode:Configuration.history_mode option -> - Sqlite.conn -> + unit -> Configuration.history_mode tzresult Lwt.t diff --git a/etherlink/bin_node/lib_dev/evm_store.ml b/etherlink/bin_node/lib_dev/evm_store.ml index 41466161b9f9..ff7087df9909 100644 --- a/etherlink/bin_node/lib_dev/evm_store.ml +++ b/etherlink/bin_node/lib_dev/evm_store.ml @@ -161,12 +161,11 @@ module Q = struct let history_mode = custom - ~encode:(function - | Configuration.Archive -> Ok "archive" | Rolling -> Ok "rolling") - ~decode:(function - | "archive" -> Ok Archive - | "rolling" -> Ok Rolling - | s -> Error (Format.sprintf "Cannot decode %S" s)) + ~encode:(fun mode -> Ok (Configuration.string_of_history_mode mode)) + ~decode:(fun str -> + Option.to_result + ~none:(Format.sprintf "Cannot decode %S" str) + Configuration.(history_mode_of_string_opt str)) string let levels = @@ -235,7 +234,7 @@ module Q = struct You can review the result at [etherlink/tezt/tests/expected/evm_sequencer.ml/EVM Node- debug print store schemas.out]. *) - let version = 17 + let version = 18 let all : Evm_node_migrations.migration list = Evm_node_migrations.migrations version diff --git a/etherlink/bin_node/main.ml b/etherlink/bin_node/main.ml index b82cfe05c74f..a86d42ce275d 100644 --- a/etherlink/bin_node/main.ml +++ b/etherlink/bin_node/main.ml @@ -162,29 +162,19 @@ module Params = struct let history_param = Tezos_clic.parameter @@ fun () s -> let open Lwt_result_syntax in - match String.split_on_char ':' s with - | ["archive"] -> return Configuration.(Archive, retention ()) - | ["rolling"] -> return Configuration.(Rolling, retention ()) - | ["rolling"; n] -> ( - match int_of_string_opt n with - | Some days when days >= 0 -> - return Configuration.(Rolling, retention ~days ()) - | _ -> - failwith - "Invalid retention period %S for rolling history mode. Must be a \ - positive integer number of days." - n) - | _ -> + match Configuration.history_mode_of_string_opt s with + | Some mode -> return mode + | None -> failwith - "Invalid history mode. Must be either archive, rolling or rolling:n \ - where n is the number of days to retain history." + "Invalid history mode. Must be either archive, or rolling:n where n \ + is the number of days to retain history." let history next = Tezos_clic.param ~name:"history" ~desc: - "History mode, either archive, rolling or rolling:n where n is the \ - number of days of history to retain." + "History mode, either archive, or rolling:n where n is the number of \ + days of history to retain." history_param next end @@ -1701,7 +1691,7 @@ mode.|} evm_node_endpoint, threshold_encryption_bundler_endpoint, sequencer_sidecar_endpoint, - history, + history_mode, dont_track_rollup_node, wallet_dir, force, @@ -1719,11 +1709,6 @@ mode.|} Client_keys.Secret_key.parse_source_string wallet_ctxt str) sequencer_str in - let history_mode, garbage_collector_parameters = - match history with - | Some (hist_mode, gc_params) -> (Some hist_mode, Some gc_params) - | None -> (None, None) - in let* config = Cli.create_or_read_config ~data_dir @@ -1765,7 +1750,6 @@ mode.|} ~finalized_view ?network ?history_mode - ?garbage_collector_parameters () in let*! () = @@ -2434,7 +2418,15 @@ let snapshot_info_command = "@,History mode: %s@,First level: %a" (match history_mode with | Archive -> "Archive" - | Rolling -> "Rolling") + | Rolling gc -> + let hist_span = + Ptime.Span.of_int_s + (gc.split_frequency_in_seconds * gc.number_of_chunks) + in + Format.asprintf + "Rolling (with %a history)" + Ptime.Span.pp + hist_span) Evm_node_lib_dev_encoding.Ethereum_types.pp_quantity first_level in @@ -2462,7 +2454,7 @@ let switch_history_mode_command = ~desc:"Switch history mode of the node" (args1 data_dir_arg) (prefixes ["switch"; "history"; "to"] @@ Params.history @@ stop) - (fun data_dir (history_mode, garbage_collector_parameters) () -> + (fun data_dir history_mode () -> let open Lwt_result_syntax in let open Evm_node_lib_dev in let*! populated = Data_dir.populated ~data_dir in @@ -2476,13 +2468,7 @@ let switch_history_mode_command = let* store = Evm_store.init ~data_dir ~perm:`Read_write () in let* () = Evm_store.use store @@ fun conn -> - let* config = - Cli.create_or_read_config - ~data_dir - ~history_mode - ~garbage_collector_parameters - () - in + let* config = Cli.create_or_read_config ~data_dir ~history_mode () in let*! () = let open Tezos_base_unix.Internal_event_unix in let config = make_with_defaults ~verbosity:Warning () in @@ -2495,7 +2481,7 @@ let switch_history_mode_command = ~switch:true ~store_history_mode ~history_mode:config.history_mode - conn + () in let* () = Evm_store.Metadata.store_history_mode conn history_mode in let*! config_exists = diff --git a/etherlink/bin_node/migrations/018_rolling.sql b/etherlink/bin_node/migrations/018_rolling.sql new file mode 100644 index 000000000000..57d08e3a3d5b --- /dev/null +++ b/etherlink/bin_node/migrations/018_rolling.sql @@ -0,0 +1,4 @@ +-- rolling is no longer a valid value for history_mode +UPDATE metadata +SET value = 'rolling:14' +WHERE key = 'history_mode' AND value = 'rolling'; diff --git a/etherlink/script-inputs/evm_store_migrations b/etherlink/script-inputs/evm_store_migrations index a40c948d75ab..91615717019f 100644 --- a/etherlink/script-inputs/evm_store_migrations +++ b/etherlink/script-inputs/evm_store_migrations @@ -16,3 +16,4 @@ efd7da46af254996433066a6d2a6c692e60f7314130a5ba8ceee9e419e155118 etherlink/bin_ bd8fc14f18c1ca562e8b8e412a72bd36b071e28e84e8e8624b1f6581e70c144d etherlink/bin_node/migrations/015_irmin_chunks.sql 7c97ad4738c4c6672fd51e0357b5f4c4843ab1fb0a20e6925ca6a57879f339c6 etherlink/bin_node/migrations/016_history_mode.sql b223e97d75ca429e9130fcd37b3da7c8902b11c6177cec253949e25eeab32a8a etherlink/bin_node/migrations/017_legacy_mode.sql +a223d3797f36da6ea98e883cdb32734eaf5b1e20391c746adafbe46f146568aa etherlink/bin_node/migrations/018_rolling.sql diff --git a/etherlink/tezt/lib/evm_node.ml b/etherlink/tezt/lib/evm_node.ml index fe35a67fc0f3..2271fdf59982 100644 --- a/etherlink/tezt/lib/evm_node.ml +++ b/etherlink/tezt/lib/evm_node.ml @@ -1275,12 +1275,7 @@ let patch_config_gc ?history_mode json = json |> optional_json_put ~name:"history" history_mode (function | Archive -> `String "archive" - | Rolling retention -> - `O - [ - ("mode", `String "rolling"); - ("retention", `Float (float_of_int retention)); - ]) + | Rolling retention -> `String (Format.sprintf "rolling:%d" retention)) let init ?patch_config ?name ?runner ?mode ?data_dir ?rpc_addr ?rpc_port ?restricted_rpcs ?history_mode rollup_node = diff --git a/etherlink/tezt/tests/expected/evm_rollup.ml/EVM node- list events regression.out b/etherlink/tezt/tests/expected/evm_rollup.ml/EVM node- list events regression.out index 95903ed42052..27448ba47e26 100644 --- a/etherlink/tezt/tests/expected/evm_rollup.ml/EVM node- list events regression.out +++ b/etherlink/tezt/tests/expected/evm_rollup.ml/EVM node- list events regression.out @@ -507,8 +507,13 @@ evm_context_switch_history_mode: json format: { /* evm_context_switch_history_mode version 0 */ "evm_context_switch_history_mode.v0": - { "from": "rolling" | "archive", - "to_": "rolling" | "archive" } } + { "from": $history_mode, + "to_": $history_mode } } + $history_mode: + /* Compact notation for the history mode. Can either be `archive` and + `rolling:N` with `N` being the number of days to use as the + retention period */ + "archive" | "rolling:n" evm_context_rolling_to_archive_incomplete_history: description: switching history mode from Rolling to Archive, but be aware that history is incomplete, earliest level is {earliest_level} @@ -530,7 +535,12 @@ evm_context_start_history_mode: section: evm_node.dev.evm_context json format: { /* evm_context_start_history_mode version 0 */ - "evm_context_start_history_mode.v0": "rolling" | "archive" } + "evm_context_start_history_mode.v0": $history_mode } + $history_mode: + /* Compact notation for the history mode. Can either be `archive` and + `rolling:N` with `N` being the number of days to use as the + retention period */ + "archive" | "rolling:n" evm_context_get_block_failed: description: get block by number failed for level {level}{trace} diff --git a/etherlink/tezt/tests/expected/evm_sequencer.ml/EVM Node- describe config.out b/etherlink/tezt/tests/expected/evm_sequencer.ml/EVM Node- describe config.out index 8b24d3b7f5de..f39a80427c61 100644 --- a/etherlink/tezt/tests/expected/evm_sequencer.ml/EVM Node- describe config.out +++ b/etherlink/tezt/tests/expected/evm_sequencer.ml/EVM Node- describe config.out @@ -273,19 +273,12 @@ boolean /* When enabled, the node only expose blocks that are finalized, i.e., the `latest` block parameter becomes a synonym for `finalized`. */, - "history"?: - /* History mode of the EVM node */ - "archive" - || "rolling" - || { /* rolling */ - "mode": "rolling", - "retention": - $days - /* How much history is retained for rolling nodes. */ } } -$days: - /* number_of_days - Number of days of history to retain */ - integer ∈ [0, 2^30] + "history"?: $history_mode /* History mode of the EVM node */ } +$history_mode: + /* Compact notation for the history mode. Can either be `archive` and + `rolling:N` with `N` being the number of days to use as the retention + period */ + "archive" | "rolling:n" $int64: /* 64 bit integers Decimal representation of 64 bit integers */ diff --git a/etherlink/tezt/tests/expected/evm_sequencer.ml/EVM Node- man.out b/etherlink/tezt/tests/expected/evm_sequencer.ml/EVM Node- man.out index 9fd64b9d8f49..9a4bac497ee2 100644 --- a/etherlink/tezt/tests/expected/evm_sequencer.ml/EVM Node- man.out +++ b/etherlink/tezt/tests/expected/evm_sequencer.ml/EVM Node- man.out @@ -260,7 +260,7 @@ Miscellaneous commands: switch history to [--data-dir ] Switch history mode of the node - : History mode, either archive, rolling or rolling:n where n is the number of days of history to retain. + : History mode, either archive, or rolling:n where n is the number of days of history to retain. --data-dir : The path to the EVM node data directory chunk data [...] [--rollup-address ] [--as-blueprint] diff --git a/etherlink/tezt/tests/gc.ml b/etherlink/tezt/tests/gc.ml index 3aea754e14e7..353783de7049 100644 --- a/etherlink/tezt/tests/gc.ml +++ b/etherlink/tezt/tests/gc.ml @@ -20,7 +20,8 @@ open Rpc.Syntax -let register ?genesis_timestamp ?(retention_period = 5) ~title ~tags f = +let register ?genesis_timestamp ?(history_mode = Evm_node.Rolling 5) ~title + ~tags f = Test.register ~__FILE__ ~title @@ -39,7 +40,7 @@ let register ?genesis_timestamp ?(retention_period = 5) ~title ~tags f = let* sequencer = Helpers.init_sequencer_sandbox ?genesis_timestamp - ~history_mode:(Rolling retention_period) + ~history_mode ~patch_config () in @@ -52,7 +53,7 @@ let test_gc_boundaries () = let genesis_timestamp = Client.At genesis_time in register ~genesis_timestamp - ~retention_period:3 + ~history_mode:(Rolling 3) ~title:"GC boundaries" ~tags:["boundaries"; "earliest"] @@ fun sequencer -> @@ -124,49 +125,58 @@ let test_gc_boundaries () = let test_switch_history_mode () = let genesis_time = Client.Time.of_notation_exn "2020-01-01T00:00:00Z" in let genesis_timestamp = Client.At genesis_time in + let retention_period = 2 in + let get_timestamp i = + (* Move one day every block *) + Ptime.add_span genesis_time (days (i + 1)) + |> Option.get |> Client.Time.to_notation + in + let blocks_before_switch = 3 in register ~genesis_timestamp - ~retention_period:2 - ~title:"Switch history mode (rolling -> archive)" + ~title:"Switch history mode (archive -> rolling)" + ~history_mode:Archive ~tags:["history_mode"] @@ fun sequencer -> let* () = Evm_node.terminate sequencer in - let wait_for_rolling = - Evm_node.wait_for_start_history_mode ~history_mode:"rolling" sequencer + let wait_for_archive = + Evm_node.wait_for_start_history_mode ~history_mode:"archive" sequencer in - let* () = Evm_node.run sequencer and* _ = wait_for_rolling in - (* We want the evm-node to trigger at least one garbage collector to - have only partial history. *) - let wait_for_gc = Evm_node.wait_for_gc_finished sequencer in + let* () = Evm_node.run sequencer and* _ = wait_for_archive in let* _ = - fold 3 () (fun i () -> - let timestamp = - (* Move one day every block *) - Ptime.add_span genesis_time (days (i + 1)) - |> Option.get |> Client.Time.to_notation - in + fold blocks_before_switch () (fun i () -> + let timestamp = get_timestamp i in let* _ = Rpc.produce_block ~timestamp sequencer in unit) - and* _ = wait_for_gc in - let*@ earliest_block = Rpc.get_block_by_number ~block:"earliest" sequencer in - Check.((earliest_block.number > 0l) int32) - ~error_msg:"Garbage collector should have removed genesis block" ; + in (* Restart the node in archive mode. *) let* () = Evm_node.terminate sequencer in let* () = Evm_node.Config_file.update sequencer - (Evm_node.patch_config_gc ~history_mode:Archive) + (Evm_node.patch_config_gc ~history_mode:(Rolling retention_period)) in let process = Evm_node.spawn_run sequencer in let* () = Process.check_error ~msg:(rex "cannot be run with history mode") process in - let*! () = Evm_node.switch_history_mode sequencer Archive in - let wait_for_archive = - Evm_node.wait_for_start_history_mode ~history_mode:"archive" sequencer + let*! () = + Evm_node.switch_history_mode sequencer (Rolling retention_period) in - let* () = Evm_node.run sequencer and* _ = wait_for_archive in + let wait_for_rolling = + Evm_node.wait_for_start_history_mode + ~history_mode:(Format.sprintf "rolling:%d" retention_period) + sequencer + in + let* () = Evm_node.run sequencer and* _ = wait_for_rolling in + (* show that we indeed gc *) + let wait_for_gc = Evm_node.wait_for_gc_finished sequencer in + let* _ = + fold (retention_period + 1) () (fun i () -> + let timestamp = get_timestamp (blocks_before_switch + i + 1) in + let* _ = Rpc.produce_block ~timestamp sequencer in + unit) + and* _ = wait_for_gc in unit let () = -- GitLab