diff --git a/etherlink/bin_node/lib_dev/kernel_download.ml b/etherlink/bin_node/lib_dev/kernel_download.ml index d5bf6806283df5220d69785605be973e26a7aa29..09ef181bce2173f8e4deddb00e316b8977e966d2 100644 --- a/etherlink/bin_node/lib_dev/kernel_download.ml +++ b/etherlink/bin_node/lib_dev/kernel_download.ml @@ -5,6 +5,28 @@ (* *) (*****************************************************************************) +module Reveal_hash = Tezos_raw_protocol_alpha.Sc_rollup_reveal_hash + +type error += Invalid_preimage_for_hash of Hex.t * string + +let () = + register_error_kind + `Permanent + ~id:"evm_node_dev_invalid_preimage" + ~title:"Preimage has not the expected hash" + ~description: + "The EVM node could not apply a blueprint on top of its local EVM state." + ~pp:(fun ppf (hash, _preimage) -> + Format.fprintf + ppf + "The preimage received for %s doesn't return the same hash" + hash) + Data_encoding.(obj2 (req "expected_hash" string) (req "preimage" string)) + (function + | Invalid_preimage_for_hash (`Hex hash, preimage) -> Some (hash, preimage) + | _ -> None) + (fun (hash, preimage) -> Invalid_preimage_for_hash (`Hex hash, preimage)) + type preimages = Contents of bytes | Hashes of string list let preimages_encoding = @@ -21,29 +43,58 @@ let preimages_encoding = case ~title:"hashes" (Tag 1) - (list Tezos_raw_protocol_alpha.Sc_rollup_reveal_hash.encoding) + (list Reveal_hash.encoding) (function Hashes _hashes -> assert false | _ -> None) - (fun hashes -> - Hashes - (List.map - Tezos_raw_protocol_alpha.Sc_rollup_reveal_hash.to_hex - hashes)); + (fun hashes -> Hashes (List.map Reveal_hash.to_hex hashes)); ]) -let download ~preimages_endpoint ~preimages ~(root_hash : Hex.t) = +let check_preimage (`Hex hash) preimage = + let computed_hash = + Reveal_hash.hash_string ~scheme:Reveal_hash.Blake2B [preimage] + |> Reveal_hash.to_hex + in + hash = computed_hash + +let delete_preimage preimages (`Hex hash) = + Lwt_unix.unlink (Filename.concat preimages hash) + +let rec reveal_and_check ~preimages_endpoint ~preimages ~num_download_retries + hash = + let open Lwt_result_syntax in + let*! preimage = + Commands.reveal_preimage + ~preimages_endpoint + ~preimages + 0 + (* Retrying makes sense only when the preimage is fed through stdin, this + wouldn't make sense in our case. *) + hash + in + if not (check_preimage hash preimage) then + if num_download_retries <= 0 then + tzfail (Invalid_preimage_for_hash (hash, preimage)) + else + let*! () = delete_preimage preimages hash in + reveal_and_check + ~preimages_endpoint + ~preimages + ~num_download_retries:(pred num_download_retries) + hash + else return preimage + +let download ~preimages_endpoint ~preimages ~(root_hash : Hex.t) + ?(num_download_retries = 1) () = let open Lwt_result_syntax in - (* value found in `commands.ml`, should we make it configurable? *) - let num_retries = 3 in let rec go retrieved_hashes = let open Lwt_result_syntax in match retrieved_hashes with | [] -> return_unit | hash :: hashes -> ( - let*! preimage = - Commands.reveal_preimage + let* preimage = + reveal_and_check ~preimages_endpoint ~preimages - num_retries + ~num_download_retries hash in match diff --git a/etherlink/bin_node/lib_dev/kernel_download.mli b/etherlink/bin_node/lib_dev/kernel_download.mli index edd213d7e8c7b06f7418706e7105faee824798b8..c18741c41b3e98d1c337f0567e8b37e9b3561eab 100644 --- a/etherlink/bin_node/lib_dev/kernel_download.mli +++ b/etherlink/bin_node/lib_dev/kernel_download.mli @@ -9,4 +9,6 @@ val download : preimages_endpoint:Uri.t -> preimages:string -> root_hash:Hex.t -> + ?num_download_retries:int -> + unit -> unit tzresult Lwt.t diff --git a/etherlink/bin_node/main.ml b/etherlink/bin_node/main.ml index 13639653e689baa2d8bd6fa763463e92538b1781..a74feb99ec1b87b016344f95dfef3b980d7b501e 100644 --- a/etherlink/bin_node/main.ml +++ b/etherlink/bin_node/main.ml @@ -579,6 +579,16 @@ let dal_slots_arg = s |> String.split ',' |> List.map int_of_string |> Lwt_result_syntax.return)) +let num_download_retries = + Tezos_clic.arg + ~doc: + "Number of times a revealed preimage can be redownloaded in case the it \ + doesn't pass the sanity check. It can be useful if the download is \ + corrupted for some reason." + ~long:"retry" + ~placeholder:"1" + Params.int + let common_config_args = Tezos_clic.args18 data_dir_arg @@ -2168,7 +2178,11 @@ let preemptive_kernel_download_command = let open Tezos_clic in command ~desc:"Transforms the JSON list of instructions to a RLP list" - (args3 data_dir_arg preimages_arg preimages_endpoint_arg) + (args4 + data_dir_arg + preimages_arg + preimages_endpoint_arg + num_download_retries) (prefixes ["download"; "kernel"; "with"; "root"; "hash"] @@ param ~name:"root hash" @@ -2176,7 +2190,9 @@ let preemptive_kernel_download_command = (Tezos_clic.parameter (fun _ str -> Lwt_result_syntax.return @@ `Hex str)) @@ stop) - (fun (data_dir, preimages, preimages_endpoint) root_hash () -> + (fun (data_dir, preimages, preimages_endpoint, num_download_retries) + root_hash + () -> let open Lwt_result_syntax in let* configuration = Cli.create_or_read_config @@ -2199,9 +2215,11 @@ let preemptive_kernel_download_command = in let*! () = Lwt_utils_unix.create_dir preimages in Evm_node_lib_dev.Kernel_download.download + ~root_hash ~preimages ~preimages_endpoint - ~root_hash) + ?num_download_retries + ()) let debug_print_store_schemas_command = let open Tezos_clic in 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 3418aaaefb5517d00ac2c9e8fa914d9e79a10de2..bea7e759a2e8db9a0717370d703d1adae3be1557 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 @@ -477,12 +477,13 @@ Miscellaneous commands: download kernel with root hash [--data-dir ] [--preimages-dir <_evm_installer_preimages>] - [--preimages-endpoint ] + [--preimages-endpoint ] [--retry <1>] Transforms the JSON list of instructions to a RLP list : root hash of the kernel to download --data-dir : The path to the EVM node data directory --preimages-dir <_evm_installer_preimages>: Path to the preimages directory --preimages-endpoint : The address of a service which provides pre-images for the rollup. Missing pre-images will be downloaded remotely if they are not already present on disk. + --retry <1>: Number of times a revealed preimage can be redownloaded in case the it doesn't pass the sanity check. It can be useful if the download is corrupted for some reason. debug print store schemas Print SQL statements describing the tables created in the store