diff --git a/CHANGES.rst b/CHANGES.rst index cdc84d1873c798574a2e193effd2b8f763119efb..daf7fcd84dbb332b233a60a4ca762d56f9023129 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -204,6 +204,9 @@ Smart Rollup WASM Debugger the debugger via the option ``--installer-config`` and will initialize the storage with this configuration. (MR :gl:`!9641`) +- The argument ``--kernel`` accepts hexadecimal files (suffixed by ``.hex``), it + is consired as an hexadecimal ``.wasm`` file. (MR :gl:`!11094`) + Data Availability Committee (DAC) --------------------------------- diff --git a/etherlink/bin_evm_node/evm_node.ml b/etherlink/bin_evm_node/evm_node.ml index 8eaaa1b08c7e9f9459a0d5fb1bc8a3c71394676e..5d9584f8920fd55753b38c1843d2fcba6f4c94bd 100644 --- a/etherlink/bin_evm_node/evm_node.ml +++ b/etherlink/bin_evm_node/evm_node.ml @@ -244,15 +244,15 @@ let data_parameter = let kernel_arg = Tezos_clic.arg ~long:"kernel" + ~placeholder:"evm_installer.wasm" ~doc:"Path to the EVM kernel" - ~placeholder:"_evm_installer_preimages" Params.string let preimages_arg = Tezos_clic.arg ~long:"preimage-dir" ~doc:"Path to the preimages directory" - ~placeholder:"evm_installer.wasm" + ~placeholder:"_evm_installer_preimages" Params.string let proxy_command = @@ -305,8 +305,13 @@ let proxy_command = in return_unit else - let* rollup_config = rollup_node_config_dev ~rollup_node_endpoint in - let* () = Evm_node_lib_dev.Tx_pool.start rollup_config in + let* ((backend_rpc, smart_rollup_address) as rollup_config) = + rollup_node_config_dev ~rollup_node_endpoint + in + let* () = + Evm_node_lib_dev.Tx_pool.start + {rollup_node = backend_rpc; smart_rollup_address; mode = Proxy} + in let* directory = dev_directory config rollup_config in let* server = start config ~directory in let (_ : Lwt_exit.clean_up_callback_id) = @@ -362,19 +367,35 @@ let sequencer_command = in let* () = Configuration.save_sequencer ~force:true ~data_dir config in let open Evm_node_lib_dev in + let* smart_rollup_address = + Rollup_node_services.smart_rollup_address rollup_node_endpoint + in let* ctxt, loaded = Sequencer_context.init ~data_dir ~kernel:config.mode.kernel ~preimages:config.mode.preimages + ~smart_rollup_address + in + let* ctxt = + if loaded then return ctxt + else Sequencer_state.init ~smart_rollup_address ctxt in - let* ctxt = if loaded then return ctxt else Sequencer_state.init ctxt in let module Sequencer = Sequencer.Make (struct let ctxt = ctxt end) in (* Ignore the smart rollup address for now. *) - let* () = Tx_pool.start ((module Sequencer), "") in - let* directory = dev_directory config ((module Sequencer), "") in + let* () = + Tx_pool.start + { + rollup_node = (module Sequencer); + smart_rollup_address; + mode = Sequencer {time_between_blocks = 5.}; + } + in + let* directory = + dev_directory config ((module Sequencer), smart_rollup_address) + in let* server = start config ~directory in let (_ : Lwt_exit.clean_up_callback_id) = install_finalizer_dev server in let wait, _resolve = Lwt.wait () in diff --git a/etherlink/bin_evm_node/lib_dev/publisher.ml b/etherlink/bin_evm_node/lib_dev/publisher.ml index b2301fa4537e19e3f0ca1cafff1feec24c2f89ef..3332bda5ea813b5c8c664047e7546768daab47ad 100644 --- a/etherlink/bin_evm_node/lib_dev/publisher.ml +++ b/etherlink/bin_evm_node/lib_dev/publisher.ml @@ -15,7 +15,8 @@ module type TxEncoder = sig end module type Publisher = sig - val publish_messages : messages:string list -> unit tzresult Lwt.t + val publish_messages : + smart_rollup_address:string -> messages:string list -> unit tzresult Lwt.t end module Make (TxEncoder : TxEncoder) (Publisher : Publisher) = struct @@ -33,6 +34,8 @@ module Make (TxEncoder : TxEncoder) (Publisher : Publisher) = struct ([], []) transactions in - let* () = Publisher.publish_messages ~messages:to_publish in + let* () = + Publisher.publish_messages ~smart_rollup_address ~messages:to_publish + in return (List.rev rev_tx_hashes) end diff --git a/etherlink/bin_evm_node/lib_dev/rollup_node.ml b/etherlink/bin_evm_node/lib_dev/rollup_node.ml index f945a8f2595559d1de9aceb2388bf5aa9c1fb9ac..8a326a150be7b3d496d0796ef77deb7434f08809 100644 --- a/etherlink/bin_evm_node/lib_dev/rollup_node.ml +++ b/etherlink/bin_evm_node/lib_dev/rollup_node.ml @@ -43,7 +43,7 @@ end) : Services_backend_sig.Backend = struct end module Publisher = struct - let publish_messages ~messages = + let publish_messages ~smart_rollup_address:_ ~messages = let open Lwt_result_syntax in (* The injection's service returns a notion of L2 message hash (defined by the rollup node) used to track the message's injection in the batcher. diff --git a/etherlink/bin_evm_node/lib_dev/sequencer.ml b/etherlink/bin_evm_node/lib_dev/sequencer.ml index 5500f337145c38a5b3bb72aa75405f42d25c1c8d..9c108c0cda6b7654d2910c2e102f1e804e0e48b6 100644 --- a/etherlink/bin_evm_node/lib_dev/sequencer.ml +++ b/etherlink/bin_evm_node/lib_dev/sequencer.ml @@ -29,10 +29,12 @@ end) : Services_backend_sig.Backend = struct end module Publisher = struct - let publish_messages ~messages = + let publish_messages ~smart_rollup_address ~messages = let open Lwt_result_syntax in (* Create the blueprint with the messages. *) - let inputs = Sequencer_blueprint.create ~transactions:messages in + let inputs = + Sequencer_blueprint.create ~smart_rollup_address ~transactions:messages + in (* Execute the blueprint. *) let* ctxt = Sequencer_context.sync Ctxt.ctxt in let* _ctxt = Sequencer_state.execute ~commit:true ctxt inputs in diff --git a/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.ml b/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.ml index b18f80b73c4520a9403984914e68138ce0220d7f..0103ec77aa1745e91c2468f7bdd20b6709fca1bd 100644 --- a/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.ml +++ b/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.ml @@ -12,7 +12,7 @@ let now_bytes () = Time.Protocol.to_seconds timestamp |> Z.of_int64 |> Z.to_bits |> Bytes.of_string -let create ~transactions = +let create ~smart_rollup_address ~transactions = let timestamp = Rlp.Value (now_bytes ()) in let messages = Rlp.List @@ -23,5 +23,11 @@ let create ~transactions = let rlp_blueprint = Rlp.List [messages; timestamp] |> Rlp.encode |> Bytes.to_string in - (* External message tag. *) - ["\001" ^ rlp_blueprint] + + [ + "\001" (* External message *) ^ "\000" + (* Framed protocol *) ^ smart_rollup_address + ^ "\003" + ^ (* Blueprint *) + rlp_blueprint; + ] diff --git a/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.mli b/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.mli index b6852a4f03a3caedffb79d1b209b33a1e50f3c83..5635611d53aa366a3e12dc8c6afc302eb14db8d2 100644 --- a/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.mli +++ b/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.mli @@ -5,6 +5,8 @@ (* *) (*****************************************************************************) -(** [create transactions] creates a sequencer blueprint containing - [transactions]. Returns the inputs to put in the inbox. *) -val create : transactions:string list -> string list +(** [create ~smart_rollup_address ~transactions] creates a sequencer + blueprint containing [transactions]. Returns the inputs to put in + the inbox. *) +val create : + smart_rollup_address:string -> transactions:string list -> string list diff --git a/etherlink/bin_evm_node/lib_dev/sequencer_context.ml b/etherlink/bin_evm_node/lib_dev/sequencer_context.ml index d504a1dfa2c61ca870a81aa5d17fe65d69ffc8ad..43f9581f4a67c7537514d1692bcb94c7547085ce 100644 --- a/etherlink/bin_evm_node/lib_dev/sequencer_context.ml +++ b/etherlink/bin_evm_node/lib_dev/sequencer_context.ml @@ -20,6 +20,7 @@ type t = { evm_state : evm_state; kernel : string; preimages : string; + smart_rollup_address : Tezos_crypto.Hashed.Smart_rollup_address.t; } (** The EVM/PVM local state used by the sequencer. *) @@ -65,11 +66,24 @@ let load_checkpoint ~data_dir index = let evm_state = Context.Tree.empty store in return (store, evm_state, false) -let init ~data_dir ~kernel ~preimages = +let init ~data_dir ~kernel ~preimages ~smart_rollup_address = let open Lwt_result_syntax in let*! index = Context.init (store_path ~data_dir) in let* store, evm_state, loaded = load_checkpoint ~data_dir index in - return ({index; store; data_dir; evm_state; kernel; preimages}, loaded) + let smart_rollup_address = + Tezos_crypto.Hashed.Smart_rollup_address.of_string_exn smart_rollup_address + in + return + ( { + index; + store; + data_dir; + evm_state; + kernel; + preimages; + smart_rollup_address; + }, + loaded ) let commit ctxt evm_state = let open Lwt_result_syntax in diff --git a/etherlink/bin_evm_node/lib_dev/sequencer_context.mli b/etherlink/bin_evm_node/lib_dev/sequencer_context.mli index d1508afdf1020f151068292495997bbaaa2d24c8..4289f1f75faceaaa2ca660dee2439ef357ea367f 100644 --- a/etherlink/bin_evm_node/lib_dev/sequencer_context.mli +++ b/etherlink/bin_evm_node/lib_dev/sequencer_context.mli @@ -20,11 +20,12 @@ type t = { evm_state : evm_state; (** EVM local state of the sequencer. *) kernel : string; (** Path to the kernel to execute. *) preimages : string; (** Path to the preimages directory. *) + smart_rollup_address : Tezos_crypto.Hashed.Smart_rollup_address.t; } -(** [init ~data_dir ~kernel ~preimages] creates a context where it - initializes the {!type-index}, and use a checkpoint mechanism to load - the latest {!type-store} if any. +(** [init ~data_dir ~kernel ~preimages ~smart_rollup_address] creates + a context where it initializes the {!type-index}, and use a + checkpoint mechanism to load the latest {!type-store} if any. Also returns a boolean denoting whether the context was initialized or not. *) @@ -32,6 +33,7 @@ val init : data_dir:string -> kernel:string -> preimages:string -> + smart_rollup_address:string -> (t * bool) tzresult Lwt.t (** [commit ctxt evm_state] updates the [evm_state] in [ctxt], commits diff --git a/etherlink/bin_evm_node/lib_dev/sequencer_state.ml b/etherlink/bin_evm_node/lib_dev/sequencer_state.ml index 5e52f47da053f4e6db31971bea5d81b5dfbe596b..1bd58da474552d03b954e3f5e4fc7199819e4c19 100644 --- a/etherlink/bin_evm_node/lib_dev/sequencer_state.ml +++ b/etherlink/bin_evm_node/lib_dev/sequencer_state.ml @@ -17,6 +17,7 @@ let execute ?(commit = false) ctxt inbox = Config.config ~preimage_directory:ctxt.Sequencer_context.preimages ~kernel_debug:true + ~destination:ctxt.Sequencer_context.smart_rollup_address () in let* pvm_state, _, _, _ = @@ -24,18 +25,19 @@ let execute ?(commit = false) ctxt inbox = in if commit then Sequencer_context.commit ctxt pvm_state else return ctxt -let init ctxt = +let init ~smart_rollup_address ctxt = let open Lwt_result_syntax in let* evm_state = Wasm.start ~tree:ctxt.Sequencer_context.evm_state Tezos_scoru_wasm.Wasm_pvm_state.V3 - true ctxt.kernel in let ctxt = {ctxt with evm_state} in (* Create the first empty block. *) - let inputs = Sequencer_blueprint.create ~transactions:[] in + let inputs = + Sequencer_blueprint.create ~smart_rollup_address ~transactions:[] + in execute ~commit:true ctxt inputs let inspect evm_state key = diff --git a/etherlink/bin_evm_node/lib_dev/sequencer_state.mli b/etherlink/bin_evm_node/lib_dev/sequencer_state.mli index 19443b2c8a928b4afe424947f1cd97b76790c9cb..87ac577c6de4eeb02366d09acbbaa9d656110702 100644 --- a/etherlink/bin_evm_node/lib_dev/sequencer_state.mli +++ b/etherlink/bin_evm_node/lib_dev/sequencer_state.mli @@ -13,8 +13,12 @@ val execute : string list -> Sequencer_context.t tzresult Lwt.t -(** [init ctxt] initializes the local state in [ctxt], bakes the genesis block. *) -val init : Sequencer_context.t -> Sequencer_context.t tzresult Lwt.t +(** [init ~smart_rollup_address ctxt] initializes the local state in + [ctxt], bakes the genesis block. *) +val init : + smart_rollup_address:string -> + Sequencer_context.t -> + Sequencer_context.t tzresult Lwt.t (** [inspect evm_state key] inspects [key] in [evm_state]. *) val inspect : Sequencer_context.evm_state -> string -> bytes option Lwt.t diff --git a/etherlink/bin_evm_node/lib_dev/tx_pool.ml b/etherlink/bin_evm_node/lib_dev/tx_pool.ml index 917baac887b0f91c9a1cdf37af3fa363c127579a..7e4d2dd1e3f2e57c63cef8890d964fe7c402e13f 100644 --- a/etherlink/bin_evm_node/lib_dev/tx_pool.ml +++ b/etherlink/bin_evm_node/lib_dev/tx_pool.ml @@ -104,15 +104,24 @@ module Pool = struct aux current_nonce user_transactions |> Ethereum_types.quantity_of_z end +type mode = Proxy | Sequencer of {time_between_blocks : float} + +type parameters = { + rollup_node : (module Services_backend_sig.S); + smart_rollup_address : string; + mode : mode; +} + module Types = struct type state = { rollup_node : (module Services_backend_sig.S); smart_rollup_address : string; mutable level : Ethereum_types.block_height; mutable pool : Pool.t; + mode : mode; } - type parameters = (module Services_backend_sig.S) * string + type nonrec parameters = parameters end module Name = struct @@ -133,7 +142,7 @@ module Request = struct | Add_transaction : string -> ((Ethereum_types.hash, string) result, tztrace) t - | New_l2_head : Ethereum_types.block_height -> (unit, tztrace) t + | Inject_transactions : Ethereum_types.block_height -> (unit, tztrace) t type view = View : _ t -> view @@ -154,12 +163,12 @@ module Request = struct (fun ((), messages) -> View (Add_transaction messages)); case (Tag 1) - ~title:"New_l2_head" + ~title:"Inject_transactions" (obj2 (req "request" (constant "new_l2_head")) (req "block_height" Ethereum_types.block_height_encoding)) - (function View (New_l2_head b) -> Some ((), b) | _ -> None) - (fun ((), b) -> View (New_l2_head b)); + (function View (Inject_transactions b) -> Some ((), b) | _ -> None) + (fun ((), b) -> View (Inject_transactions b)); ] let pp ppf (View r) = @@ -169,7 +178,7 @@ module Request = struct ppf "Add [%s] tx to tx-pool" (Hex.of_string transaction |> Hex.show) - | New_l2_head block_height -> + | Inject_transactions block_height -> let (Ethereum_types.Block_height block_height) = block_height in Format.fprintf ppf "New L2 head: %s" (Z.to_string block_height) end @@ -205,12 +214,9 @@ let on_transaction state tx_raw = state.pool <- pool ; return (Ok hash) -let on_head state block_height = +let inject_transactions ~smart_rollup_address rollup_node pool = let open Lwt_result_syntax in - let open Types in - let {rollup_node = (module Rollup_node); smart_rollup_address; pool; _} = - state - in + let (module Rollup_node : Services_backend_sig.S) = rollup_node in (* Get all the addresses in the tx-pool. *) let addresses = Pool.addresses pool in (* Get the nonce related to each address. *) @@ -278,6 +284,13 @@ let on_head state block_height = "[tx-pool] Transaction %s sent to the rollup.\n%!" (Ethereum_types.hash_to_string hash)) hashes) ; + return pool + +let on_head state block_height = + let open Lwt_result_syntax in + let open Types in + let {rollup_node; smart_rollup_address; pool; _} = state in + let* pool = inject_transactions ~smart_rollup_address rollup_node pool in (* update the pool *) state.level <- block_height ; state.pool <- pool ; @@ -295,12 +308,13 @@ module Handlers = struct match request with | Request.Add_transaction raw_tx -> protect @@ fun () -> on_transaction state raw_tx - | Request.New_l2_head block_height -> + | Request.Inject_transactions block_height -> protect @@ fun () -> on_head state block_height type launch_error = error trace - let on_launch _w () (rollup_node, smart_rollup_address) = + let on_launch _w () + ({rollup_node; smart_rollup_address; mode} : Types.parameters) = let state = Types. { @@ -308,6 +322,7 @@ module Handlers = struct smart_rollup_address; level = Block_height Z.zero; pool = Pool.empty; + mode; } in Lwt_result_syntax.return state @@ -352,12 +367,14 @@ TODO: https://gitlab.com/tezos/tezos/-/issues/6079 listen to the node instead of pulling the level each 5s *) let rec subscribe_l2_block worker = - let open Lwt_result_syntax in - let*! () = Lwt_unix.sleep 5.0 in + let open Lwt_syntax in + let* () = Lwt_unix.sleep 5.0 in let state = Worker.state worker in - let Types.{rollup_node = (module Rollup_node_rpc); _} = state in + let (Types.{rollup_node = (module Rollup_node_rpc); _} : Types.state) = + state + in (* Get the current eth level.*) - let*! res = Rollup_node_rpc.current_block_number () in + let* res = Rollup_node_rpc.current_block_number () in match res with | Error _ -> (* Kind of retry strategy *) @@ -366,25 +383,41 @@ let rec subscribe_l2_block worker = subscribe_l2_block worker | Ok block_number -> if state.level != block_number then - let*! _pushed = - Worker.Queue.push_request worker (Request.New_l2_head block_number) + let* _pushed = + Worker.Queue.push_request + worker + (Request.Inject_transactions block_number) in subscribe_l2_block worker else subscribe_l2_block worker -let start - ((module Rollup_node_rpc : Services_backend_sig.S), smart_rollup_address) = - let open Lwt_result_syntax in - let+ worker = - Worker.launch - table - () - ((module Rollup_node_rpc), smart_rollup_address) - (module Handlers) +let rec sequencer_produce_block ~time_between_blocks worker = + let open Lwt_syntax in + let* () = Lwt_unix.sleep time_between_blocks in + let state = Worker.state worker in + let (Types.{rollup_node = (module Rollup_node_rpc); _} : Types.state) = + state + in + let* _pushed = + Worker.Queue.push_request + worker + (* The sequencer mode does not rely on the state.level, therefore we do not + care about the value we push. Also, note that this is state.level will + be completely removed when we stream L2 blocks. *) + (Request.Inject_transactions (Ethereum_types.Block_height Z.zero)) in + sequencer_produce_block ~time_between_blocks worker + +let start ({mode; _} as parameters) = + let open Lwt_result_syntax in + let+ worker = Worker.launch table () parameters (module Handlers) in let () = Lwt.dont_wait - (fun () -> subscribe_l2_block worker) + (fun () -> + match mode with + | Proxy -> subscribe_l2_block worker + | Sequencer {time_between_blocks} -> + sequencer_produce_block ~time_between_blocks worker) (fun _ -> (* TODO: https://gitlab.com/tezos/tezos/-/issues/6569*) Format.printf "[tx-pool] Pool has been stopped.\n%!") diff --git a/etherlink/bin_evm_node/lib_dev/tx_pool.mli b/etherlink/bin_evm_node/lib_dev/tx_pool.mli index d21ba5f3602b7eafe3884b47f0460d815a13f439..ec8cceb889988b9171bbf489b77991fa03c7927b 100644 --- a/etherlink/bin_evm_node/lib_dev/tx_pool.mli +++ b/etherlink/bin_evm_node/lib_dev/tx_pool.mli @@ -5,9 +5,19 @@ (* *) (*****************************************************************************) -(** [start config] starts the tx-pool. The [config] represents the - Rollup_node rpc module and the address of the smart rollup. *) -val start : (module Services_backend_sig.S) * string -> unit tzresult Lwt.t +(* TODO: https://gitlab.com/tezos/tezos/-/issues/6672 + It should be created by the configuration, or at least using values of + the configuration. *) +type mode = Proxy | Sequencer of {time_between_blocks : float} + +type parameters = { + rollup_node : (module Services_backend_sig.S); (** The backend RPC module. *) + smart_rollup_address : string; (** The address of the smart rollup. *) + mode : mode; (** The mode of the node. *) +} + +(** [start parameters] starts the tx-pool *) +val start : parameters -> unit tzresult Lwt.t (** [shutdown ()] stops the tx-pool, waiting for the ongoing request to be processed. *) diff --git a/manifest/main.ml b/manifest/main.ml index 007fba324afc5c53a265889f090452de10cb6766..e04bed4b14ca91f90d642d784c457d27f9ffba91 100644 --- a/manifest/main.ml +++ b/manifest/main.ml @@ -2680,6 +2680,7 @@ let tezt_ethereum = tezt_lib |> open_ |> open_ ~m:"Base"; tezt_performance_regression |> open_; octez_crypto; + tezt_tezos |> open_; ] ~release_status:Unreleased diff --git a/src/bin_testnet_scenarios/evm_rollup.ml b/src/bin_testnet_scenarios/evm_rollup.ml index bf404292373e068207192f32143fbc7fbd2e88ff..fa11001111a68c7405e0164a6f1802237bfd4b4e 100644 --- a/src/bin_testnet_scenarios/evm_rollup.ml +++ b/src/bin_testnet_scenarios/evm_rollup.ml @@ -132,7 +132,9 @@ let setup_evm_infra ~config ~operator ?runner ?preexisting_rollup (* EVM Kernel installation level. *) let* current_level = Node.get_level node in let* _ = Sc_rollup_node.wait_for_level rollup_node current_level in - let* evm_node = Evm_node.init ~devmode:true ?runner rollup_node in + let* evm_node = + Evm_node.init ~devmode:true ?runner (Sc_rollup_node.endpoint rollup_node) + in Log.info "Node API is available at %s." (Evm_node.endpoint evm_node) ; return (rollup_address, rollup_node, evm_node) diff --git a/src/lib_wasm_debugger/wasm_debugger.ml b/src/lib_wasm_debugger/wasm_debugger.ml index 136be971a83476ec1a500009523410bee8efb786..46663521fb7366ae7846ccd4fed29941f0cca8e5 100644 --- a/src/lib_wasm_debugger/wasm_debugger.ml +++ b/src/lib_wasm_debugger/wasm_debugger.ml @@ -106,10 +106,27 @@ module Make (Wasm : Wasm_utils_intf.S) = struct let*! tree = Wasm.eval_until_input_requested tree in return tree - let start ?installer_config ?tree version binary file = + let start ?installer_config ?tree version file = let open Lwt_result_syntax in let module_name = Filename.(file |> basename |> chop_extension) in - let*! buffer = Repl_helpers.read_file file in + let* buffer, binary = + if Filename.(check_suffix file ".hex") then + let*! content = Repl_helpers.read_file file in + let*? content = + match Hex.to_string (`Hex content) with + | Some content -> Ok content + | None -> error_with "%S is not a valid hexadecimal file" file + in + return (content, true) + else + let*! content = Repl_helpers.read_file file in + let*? binary = + if Filename.check_suffix file ".wasm" then Ok true + else if Filename.check_suffix file ".wast" then Ok false + else error_with "Kernels should have .wasm or .wast file extension" + in + return (content, binary) + in handle_module ?installer_config ?tree version binary module_name buffer (* REPL main loop: reads an input, does something out of it, then loops. *) @@ -338,11 +355,6 @@ module Make (Wasm : Wasm_utils_intf.S) = struct | Some wasm_file -> Ok wasm_file | None -> error_with "A kernel file must be provided" in - let*? binary = - if Filename.check_suffix wasm_file ".wasm" then Ok true - else if Filename.check_suffix wasm_file ".wast" then Ok false - else error_with "Kernels should have .wasm or .wast file extension" - in let parse_json_config content = match Data_encoding.Json.from_string content with | Ok json -> ( @@ -366,7 +378,7 @@ module Make (Wasm : Wasm_utils_intf.S) = struct | `Json, content -> parse_json_config content) installer_config in - let* tree = start ?installer_config version binary wasm_file in + let* tree = start ?installer_config version wasm_file in let* inboxes = match inputs with | Some inputs -> Messages.parse_inboxes inputs config diff --git a/tezt/lib_ethereum/configuration.ml b/tezt/lib_ethereum/configuration.ml new file mode 100644 index 0000000000000000000000000000000000000000..396644d3f921ec576f1a4d4d0359369c189b7684 --- /dev/null +++ b/tezt/lib_ethereum/configuration.ml @@ -0,0 +1,52 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs *) +(* *) +(*****************************************************************************) + +let default_bootstrap_account_balance = Wei.of_eth_int 9999 + +let make_config ?bootstrap_accounts ?ticketer ?administrator + ?(sequencer = false) () = + let open Sc_rollup_helpers.Installer_kernel_config in + let ticketer = + Option.fold + ~some:(fun ticketer -> + let value = Hex.(of_string ticketer |> show) in + let to_ = Durable_storage_path.ticketer in + [Set {value; to_}]) + ~none:[] + ticketer + in + let bootstrap_accounts = + Option.fold + ~some: + (Array.fold_left + (fun acc Eth_account.{address; _} -> + let value = + Wei.(to_le_bytes default_bootstrap_account_balance) + |> Hex.of_bytes |> Hex.show + in + let to_ = Durable_storage_path.balance address in + Set {value; to_} :: acc) + []) + ~none:[] + bootstrap_accounts + in + let administrator = + Option.fold + ~some:(fun administrator -> + let to_ = Durable_storage_path.admin in + let value = Hex.(of_string administrator |> show) in + [Set {value; to_}]) + ~none:[] + administrator + in + let sequencer = + if sequencer then [Set {value = "00"; to_ = Durable_storage_path.sequencer}] + else [] + in + match ticketer @ bootstrap_accounts @ administrator @ sequencer with + | [] -> None + | res -> Some (`Config res) diff --git a/tezt/lib_ethereum/configuration.mli b/tezt/lib_ethereum/configuration.mli new file mode 100644 index 0000000000000000000000000000000000000000..9f8608e769fa80d692f70f9357321eea6a9c6f47 --- /dev/null +++ b/tezt/lib_ethereum/configuration.mli @@ -0,0 +1,20 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs *) +(* *) +(*****************************************************************************) + +(** Default balance given to bootstrap account. *) +val default_bootstrap_account_balance : Wei.t + +(** [make_config ?bootstrap_accounts ?ticketer ?administrator + ?sequencer ()] creates an installer configuration compatible with + the EVM kernel. *) +val make_config : + ?bootstrap_accounts:Eth_account.t array -> + ?ticketer:string -> + ?administrator:string -> + ?sequencer:bool -> + unit -> + [> `Config of Sc_rollup_helpers.Installer_kernel_config.instr list] option diff --git a/tezt/lib_ethereum/dune b/tezt/lib_ethereum/dune index 671c6e21ce92908ba0a67f0fb9a3dc72339da324..14d7d7996718c14c988ad3b6dbee042561cfd71f 100644 --- a/tezt/lib_ethereum/dune +++ b/tezt/lib_ethereum/dune @@ -7,9 +7,11 @@ (libraries tezt tezt-tezos.tezt-performance-regression - octez-libs.crypto) + octez-libs.crypto + tezt-tezos) (flags (:standard) -open Tezt -open Tezt.Base - -open Tezt_tezos_tezt_performance_regression)) + -open Tezt_tezos_tezt_performance_regression + -open Tezt_tezos)) diff --git a/tezt/lib_ethereum/durable_storage_path.ml b/tezt/lib_ethereum/durable_storage_path.ml index 52b85db71645f0681961528faf6e0cea1ba5e884..5687e3cd83a94648c659fa0bd8533c0dd98815d0 100644 --- a/tezt/lib_ethereum/durable_storage_path.ml +++ b/tezt/lib_ethereum/durable_storage_path.ml @@ -48,4 +48,6 @@ let admin = evm "/admin" let ticketer = evm "/ticketer" +let sequencer = evm "/sequencer" + let kernel_boot_wasm = kernel "/boot.wasm" diff --git a/tezt/lib_ethereum/durable_storage_path.mli b/tezt/lib_ethereum/durable_storage_path.mli index 7096b642e4cbb6e4df56a675bbb13362df34749e..9a9c4a5322a0236f5a00940497f729dcf5f58efb 100644 --- a/tezt/lib_ethereum/durable_storage_path.mli +++ b/tezt/lib_ethereum/durable_storage_path.mli @@ -50,5 +50,8 @@ val admin : path (** [ticketer] is the path to the ticketer contract. *) val ticketer : path +(** [sequencer] is the path to the sequencer flag. *) +val sequencer : path + (** [kernel_boot_wasm] is the path to the kernel `boot.wasm`. *) val kernel_boot_wasm : path diff --git a/tezt/lib_ethereum/rpc.ml b/tezt/lib_ethereum/rpc.ml new file mode 100644 index 0000000000000000000000000000000000000000..d224d5d44c2fca260ecb106a3c2f9c546e3e8469 --- /dev/null +++ b/tezt/lib_ethereum/rpc.ml @@ -0,0 +1,14 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs *) +(* *) +(*****************************************************************************) + +let block_number evm_node = + let* json = + Evm_node.call_evm_rpc + evm_node + {method_ = "eth_blockNumber"; parameters = `A []} + in + return JSON.(json |-> "result" |> as_string |> Int32.of_string) diff --git a/tezt/lib_ethereum/rpc.mli b/tezt/lib_ethereum/rpc.mli new file mode 100644 index 0000000000000000000000000000000000000000..cdca83025f580d6ef0cc2d2b4ed85dfc9cf44f93 --- /dev/null +++ b/tezt/lib_ethereum/rpc.mli @@ -0,0 +1,9 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs *) +(* *) +(*****************************************************************************) + +(** [block_number evm_node] calls [eth_blockNumber]. *) +val block_number : Evm_node.t -> int32 Lwt.t diff --git a/tezt/lib_tezos/evm_node.ml b/tezt/lib_tezos/evm_node.ml index 0a8325a5adb852f9f149adf5cf6268e843f2e654..68d8d4afca3232248ec659fc05327c259fe46a3b 100644 --- a/tezt/lib_tezos/evm_node.ml +++ b/tezt/lib_tezos/evm_node.ml @@ -25,15 +25,18 @@ (* *) (*****************************************************************************) +type mode = Sequencer of {kernel : string; preimage_dir : string} | Proxy + module Parameters = struct type persistent_state = { arguments : string list; mutable pending_ready : unit option Lwt.u list; + mode : mode; data_dir : string; devmode : bool; rpc_addr : string; rpc_port : int; - rollup_node : Sc_rollup_node.t; + rollup_node_endpoint : string; runner : Runner.t option; } @@ -92,7 +95,8 @@ let wait_for_ready evm_node = resolver :: evm_node.persistent_state.pending_ready ; check_event evm_node event_ready_name promise -let create ?runner ?data_dir ~devmode ?rpc_addr ?rpc_port rollup_node = +let create ?runner ?(mode = Proxy) ?data_dir ~devmode ?rpc_addr ?rpc_port + rollup_node_endpoint = let arguments, rpc_addr, rpc_port = connection_arguments ~devmode ?rpc_addr ?rpc_port () in @@ -107,35 +111,53 @@ let create ?runner ?data_dir ~devmode ?rpc_addr ?rpc_port rollup_node = { arguments; pending_ready = []; + mode; data_dir; devmode; rpc_addr; rpc_port; - rollup_node; + rollup_node_endpoint; runner; } in on_event evm_node (handle_event evm_node) ; evm_node -let create ?runner ?data_dir ?(devmode = false) ?rpc_addr ?rpc_port rollup_node - = - create ?runner ?data_dir ~devmode ?rpc_addr ?rpc_port rollup_node - -let rollup_node_endpoint evm_node = - Sc_rollup_node.endpoint evm_node.persistent_state.rollup_node +let create ?runner ?mode ?data_dir ?(devmode = false) ?rpc_addr ?rpc_port + rollup_node = + create ?mode ?runner ?data_dir ~devmode ?rpc_addr ?rpc_port rollup_node let data_dir evm_node = ["--data-dir"; evm_node.persistent_state.data_dir] -let run evm_node = - let* () = - run - evm_node - {ready = false} - (["run"; "proxy"; "with"; "endpoint"] - @ [rollup_node_endpoint evm_node] - @ data_dir evm_node @ evm_node.persistent_state.arguments) +let run_args evm_node = + let shared_args = data_dir evm_node @ evm_node.persistent_state.arguments in + let mode_args = + match evm_node.persistent_state.mode with + | Proxy -> + [ + "run"; + "proxy"; + "with"; + "endpoint"; + evm_node.persistent_state.rollup_node_endpoint; + ] + | Sequencer {kernel; preimage_dir} -> + [ + "run"; + "sequencer"; + "with"; + "endpoint"; + evm_node.persistent_state.rollup_node_endpoint; + "--kernel"; + kernel; + "--preimage-dir"; + preimage_dir; + ] in + mode_args @ shared_args + +let run evm_node = + let* () = run evm_node {ready = false} (run_args evm_node) in let* () = wait_for_ready evm_node in unit @@ -145,13 +167,7 @@ let spawn_command evm_node args = (Uses.path Constant.octez_evm_node) @@ args -let spawn_run evm_node = - spawn_command - evm_node - (["run"; "proxy"; "with"; "endpoint"] - @ data_dir evm_node - @ [rollup_node_endpoint evm_node] - @ evm_node.persistent_state.arguments) +let spawn_run evm_node = spawn_command evm_node (run_args evm_node) let endpoint (evm_node : t) = Format.sprintf @@ -159,9 +175,10 @@ let endpoint (evm_node : t) = evm_node.persistent_state.rpc_addr evm_node.persistent_state.rpc_port -let init ?runner ?data_dir ?(devmode = false) ?rpc_addr ?rpc_port rollup_node = +let init ?runner ?mode ?data_dir ?(devmode = false) ?rpc_addr ?rpc_port + rollup_node = let evm_node = - create ?runner ?data_dir ~devmode ?rpc_addr ?rpc_port rollup_node + create ?runner ?mode ?data_dir ~devmode ?rpc_addr ?rpc_port rollup_node in let* () = run evm_node in return evm_node diff --git a/tezt/lib_tezos/evm_node.mli b/tezt/lib_tezos/evm_node.mli index 6eff38698ce2e3e915061aeba23b12e25e843fd2..9d05f3319880a71f694d4e0bea69f74a37241717 100644 --- a/tezt/lib_tezos/evm_node.mli +++ b/tezt/lib_tezos/evm_node.mli @@ -28,8 +28,17 @@ (** EVM node server state. *) type t -(** [create ?runner ?data_dir ?devmode ?rpc_addr ?rpc_port - rollup_node] creates an EVM node server. +(** EVM node mode. *) +type mode = + | Sequencer of { + kernel : string; (** Path to the kernel used by the sequencer. *) + preimage_dir : string; + (** Path to the directory with the associated preimages. *) + } + | Proxy + +(** [create ?runner ?mode ?data_dir ?devmode ?rpc_addr ?rpc_port + rollup_node_endpoint] creates an EVM node server. The server listens to requests at address [rpc_addr] and the port [rpc_port]. [rpc_addr] defaults to ["127.0.0.1"] and a fresh port is @@ -39,36 +48,45 @@ type t set it to the one on production set [devmode] to [false] (or omit the parameter). The server communicates with a rollup-node and sets its endpoint via - [rollup_node]. + [rollup_node_endpoint]. + + [mode] defaults to [Proxy]. *) val create : ?runner:Runner.t -> + ?mode:mode -> ?data_dir:string -> ?devmode:bool -> ?rpc_addr:string -> ?rpc_port:int -> - Sc_rollup_node.t -> + string -> t (** [run evm_node] launches the EVM node server with the arguments given during {!create}. *) val run : t -> unit Lwt.t -(** [init ?runner ?data_dir ?devmode ?rpc_addr ?rpc_port rollup_node] - creates an EVM node server with {!create} and runs it with - {!run}. *) +(** [init ?runner ?mode ?data_dir ?devmode ?rpc_addr ?rpc_port + rollup_node_endpoint] creates an EVM node server with {!create} + and runs it with {!run}. *) val init : ?runner:Runner.t -> + ?mode:mode -> ?data_dir:string -> ?devmode:bool -> ?rpc_addr:string -> ?rpc_port:int -> - Sc_rollup_node.t -> + string -> t Lwt.t (** [spawn_run evm_node] same as {!run} but spawns a process. *) val spawn_run : t -> Process.t +(** Send SIGTERM and wait for the process to terminate. + + Default [timeout] is 30 seconds, after which SIGKILL is sent. *) +val terminate : ?timeout:float -> t -> unit Lwt.t + (** [endpoint evm_node] returns the endpoint to communicate with the [evm_node]. *) val endpoint : t -> string diff --git a/tezt/tests/evm_rollup.ml b/tezt/tests/evm_rollup.ml index b7d35490eb5b75ac3ad6296b138a26eabcf06f5c..719a47457346b498d1a34bab09e8769eb9d0927a 100644 --- a/tezt/tests/evm_rollup.ml +++ b/tezt/tests/evm_rollup.ml @@ -263,47 +263,6 @@ let setup_l1_contracts ~admin client = return {exchanger; bridge; admin} -let default_bootstrap_account_balance = Wei.of_eth_int 9999 - -let make_config ?bootstrap_accounts ?ticketer ?administrator () = - let open Sc_rollup_helpers.Installer_kernel_config in - let ticketer = - Option.fold - ~some:(fun ticketer -> - let value = Hex.(of_string ticketer |> show) in - let to_ = Durable_storage_path.ticketer in - [Set {value; to_}]) - ~none:[] - ticketer - in - let bootstrap_accounts = - Option.fold - ~some: - (Array.fold_left - (fun acc Eth_account.{address; _} -> - let value = - Wei.(to_le_bytes default_bootstrap_account_balance) - |> Hex.of_bytes |> Hex.show - in - let to_ = Durable_storage_path.balance address in - Set {value; to_} :: acc) - []) - ~none:[] - bootstrap_accounts - in - let administrator = - Option.fold - ~some:(fun administrator -> - let to_ = Durable_storage_path.admin in - let value = Hex.(of_string administrator |> show) in - [Set {value; to_}]) - ~none:[] - administrator - in - match ticketer @ bootstrap_accounts @ administrator with - | [] -> None - | res -> Some (`Config res) - type kernel_installee = {base_installee : string; installee : string} let setup_evm_kernel ?config ?kernel_installee @@ -330,7 +289,7 @@ let setup_evm_kernel ?config ?kernel_installee Option.map (fun {admin; _} -> admin) l1_contracts else None in - make_config ~bootstrap_accounts ?ticketer ?administrator () + Configuration.make_config ~bootstrap_accounts ?ticketer ?administrator () in let config = match (config, base_config) with @@ -378,7 +337,9 @@ let setup_evm_kernel ?config ?kernel_installee let* () = Client.bake_for_and_wait client in let* level = Node.get_level node in let* _ = Sc_rollup_node.wait_for_level ~timeout:30. sc_rollup_node level in - let* evm_node = Evm_node.init ~devmode:true sc_rollup_node in + let* evm_node = + Evm_node.init ~devmode:true (Sc_rollup_node.endpoint sc_rollup_node) + in let endpoint = Evm_node.endpoint evm_node in return { @@ -527,7 +488,7 @@ let test_evm_node_connection = ~base_dir:(Client.base_dir tezos_client) ~default_operator:Constant.bootstrap1.alias in - let evm_node = Evm_node.create sc_rollup_node in + let evm_node = Evm_node.create (Sc_rollup_node.endpoint sc_rollup_node) in (* Tries to start the EVM node server without a listening rollup node. *) let process = Evm_node.spawn_run evm_node in let* () = Process.check ~expect_failure:true process in @@ -593,7 +554,7 @@ let test_rpc_getBalance = ~account:Eth_account.bootstrap_accounts.(0).address ~endpoint:evm_node_endpoint in - Check.((balance = default_bootstrap_account_balance) Wei.typ) + Check.((balance = Configuration.default_bootstrap_account_balance) Wei.typ) ~error_msg: (sf "Expected balance of %s should be %%R, but got %%L" @@ -1336,7 +1297,7 @@ let transfer ?data protocol = } = make_transfer ?data - ~value:Wei.(default_bootstrap_account_balance - one) + ~value:Wei.(Configuration.default_bootstrap_account_balance - one) ~sender ~receiver full_evm_setup @@ -1455,14 +1416,7 @@ let test_simulate = let* {evm_node; sc_rollup_node; _} = setup_past_genesis ~admin:None protocol in - let* json = - Evm_node.call_evm_rpc - evm_node - {method_ = "eth_blockNumber"; parameters = `A []} - in - let block_number = - JSON.(json |-> "result" |> as_string |> int_of_string) - in + let* block_number = Rpc.block_number evm_node in let* simulation_result = Sc_rollup_node.RPC.call sc_rollup_node @@ Sc_rollup_rpc.post_global_block_simulate @@ -1475,7 +1429,9 @@ let test_simulate = | [insight] -> Option.map Helpers.hex_string_to_int insight | _ -> None in - Check.((simulated_block_number = Some (block_number + 1)) (option int)) + Check.( + (simulated_block_number = Some (Int32.to_int block_number + 1)) + (option int)) ~error_msg:"The simulation should advance one L2 block" ; unit) @@ -1636,13 +1592,7 @@ let test_inject_100_transactions = ~error_msg:"Expected %R transactions in the latest block, got %L") ; let* _level = next_evm_level ~sc_rollup_node ~node ~client in - let* latest_evm_level = - Evm_node.( - call_evm_rpc evm_node {method_ = "eth_blockNumber"; parameters = `A []}) - in - let latest_evm_level = - latest_evm_level |> Evm_node.extract_result |> JSON.as_int32 - in + let* latest_evm_level = Rpc.block_number evm_node in (* At each loop, the kernel reads the previous block. Until the patch, the kernel failed to read the previous block if there was more than 64 hash, this test ensures it works by assessing new blocks are produced. *) @@ -2603,7 +2553,11 @@ let gen_kernel_migration_test ?config ?(admin = Constant.bootstrap5) protocol in (* Load the EVM rollup's storage and sanity check results. *) - let* evm_node = Evm_node.init ~devmode:false evm_setup.sc_rollup_node in + let* evm_node = + Evm_node.init + ~devmode:false + (Sc_rollup_node.endpoint evm_setup.sc_rollup_node) + in let endpoint = Evm_node.endpoint evm_node in let* sanity_check = scenario_prior ~evm_setup:{evm_setup with evm_node; endpoint} @@ -2642,7 +2596,7 @@ let test_kernel_migration = let scenario_prior ~evm_setup = let* transfer_result = make_transfer - ~value:Wei.(default_bootstrap_account_balance - one) + ~value:Wei.(Configuration.default_bootstrap_account_balance - one) ~sender ~receiver evm_setup @@ -2754,7 +2708,7 @@ let test_deposit_dailynet = smart_rollup_node_extra_args in - let* evm_node = Evm_node.init sc_rollup_node in + let* evm_node = Evm_node.init (Sc_rollup_node.endpoint sc_rollup_node) in let endpoint = Evm_node.endpoint evm_node in (* Deposit tokens to the EVM rollup. *) diff --git a/tezt/tests/evm_sequencer.ml b/tezt/tests/evm_sequencer.ml new file mode 100644 index 0000000000000000000000000000000000000000..9c7288c5833db9f3ecb034b0e5db99c5fd219d10 --- /dev/null +++ b/tezt/tests/evm_sequencer.ml @@ -0,0 +1,72 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs *) +(* *) +(*****************************************************************************) + +open Sc_rollup_helpers + +let setup_sequencer ?(bootstrap_accounts = Eth_account.bootstrap_accounts) + protocol = + let* node, client = setup_l1 protocol in + let sc_rollup_node = + Sc_rollup_node.create Observer node ~base_dir:(Client.base_dir client) + in + let preimages_dir = Sc_rollup_node.data_dir sc_rollup_node // "wasm_2_0_0" in + let config = + Configuration.make_config ~bootstrap_accounts ~sequencer:true () + in + let* {output; _} = + prepare_installer_kernel + ~base_installee:"./" + ~preimages_dir + ?config + "evm_kernel" + in + let* sc_rollup_address = + originate_sc_rollup + ~kind:"wasm_2_0_0" + ~boot_sector:("file:" ^ output) + ~parameters_ty:"unit" + client + in + let* () = + Sc_rollup_node.run sc_rollup_node sc_rollup_address ["--log-kernel-debug"] + in + let mode = + Evm_node.Sequencer {kernel = output; preimage_dir = preimages_dir} + in + Evm_node.init ~mode ~devmode:false (Sc_rollup_node.endpoint sc_rollup_node) + +let test_persistent_state = + Protocol.register_test + ~__FILE__ + ~tags:["evm"; "sequencer"] + ~title:"Sequencer state is persistent across runs" + @@ fun protocol -> + let* evm_node = setup_sequencer protocol in + (* Sleep to let the sequencer produce some blocks. *) + let* () = Lwt_unix.sleep 20. in + (* Ask for the current block. *) + let* block_number = Rpc.block_number evm_node in + Check.is_true + ~__LOC__ + (block_number > 0l) + ~error_msg:"The sequencer should have produced a block" ; + (* Terminate the sequencer. *) + let* () = Evm_node.terminate evm_node in + (* Restart it. *) + let* () = Evm_node.run evm_node in + (* Assert the block number is at least [block_number]. Asserting + that the block number is exactly the same as {!block_number} can + be flaky if a block is produced between the restart and the + RPC. *) + let* new_block_number = Rpc.block_number evm_node in + Check.is_true + ~__LOC__ + (new_block_number >= block_number) + ~error_msg:"The sequencer should have produced a block" ; + unit + +let register ~protocols = test_persistent_state protocols diff --git a/tezt/tests/evm_sequencer.mli b/tezt/tests/evm_sequencer.mli new file mode 100644 index 0000000000000000000000000000000000000000..dfd5caa382eb1ae418e7640412691de89a3d32fc --- /dev/null +++ b/tezt/tests/evm_sequencer.mli @@ -0,0 +1,16 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs *) +(* *) +(*****************************************************************************) + +(* Testing + ------- + Component: Etherlink: sequencer + Requirement: make -f kernels.mk build + npm install eth-cli + Invocation: dune exec tezt/tests/main.exe -- --file evm_sequencer.ml +*) + +val register : protocols:Protocol.t list -> unit diff --git a/tezt/tests/main.ml b/tezt/tests/main.ml index ab67c6ebf5d267018db9b94bdd18979dd966ec98..2da7b89e2c9a944bb40f9123d08e7c0d40687aaa 100644 --- a/tezt/tests/main.ml +++ b/tezt/tests/main.ml @@ -224,6 +224,7 @@ let register_protocol_tests_that_use_supports_correctly () = let register_protocol_specific_because_regression_tests () = Dal.register ~protocols:[Alpha] ; Evm_rollup.register ~protocols:[Alpha] ; + Evm_sequencer.register ~protocols:[Alpha] ; (* This can be safely removed after Nairobi is frozen *) Timelock_disabled.register ~protocols:[Nairobi]