diff --git a/etherlink/bin_evm_node/config/configuration.ml b/etherlink/bin_evm_node/config/configuration.ml index b4cef7a87921855081c2f423a6d00a9907d83791..69f98de4d9e6ff96059a60ce2c2f270b3db22f41 100644 --- a/etherlink/bin_evm_node/config/configuration.ml +++ b/etherlink/bin_evm_node/config/configuration.ml @@ -15,12 +15,15 @@ type proxy = {rollup_node_endpoint : Uri.t} type time_between_blocks = Nothing | Time_between_blocks of float +(** TODO https://gitlab.com/tezos/tezos/-/issues/6811 + We need to properly handle the secrets in the node. *) type sequencer = { rollup_node_endpoint : Uri.t; kernel : string; preimages : string; time_between_blocks : time_between_blocks; private_rpc_port : int; + sequencer : Signature.secret_key; } type 'a t = { @@ -45,30 +48,25 @@ let default_rpc_addr = "127.0.0.1" let default_rpc_port = 8545 -let default_private_rpc_port = 8546 +let default_devmode = false + +let default_cors_origins = [] -let default default_mode = - { - rpc_addr = default_rpc_addr; - rpc_port = default_rpc_port; - devmode = false; - cors_origins = []; - cors_headers = []; - verbose = false; - log_filter = default_filter_config; - mode = default_mode; - } +let default_cors_headers = [] + +let default_verbose = false let default_proxy = {rollup_node_endpoint = Uri.empty} -let default_sequencer = - { - kernel = "sequencer.wasm"; - preimages = "_evm_installer_preimages"; - rollup_node_endpoint = Uri.empty; - time_between_blocks = Time_between_blocks 5.; - private_rpc_port = default_private_rpc_port; - } +let default_kernel = "sequencer.wasm" + +let default_preimages = "_evm_installer_preimages" + +let default_rollup_node_endpoint = Uri.empty + +let default_time_between_blocks = Time_between_blocks 5. + +let default_private_rpc_port = 8546 let log_filter_config_encoding : log_filter_config Data_encoding.t = let open Data_encoding in @@ -111,44 +109,49 @@ let encoding_sequencer = rollup_node_endpoint; time_between_blocks; private_rpc_port; + sequencer; } -> ( kernel, preimages, Uri.to_string rollup_node_endpoint, time_between_blocks, - private_rpc_port )) + private_rpc_port, + sequencer )) (fun ( kernel, preimages, rollup_node_endpoint, time_between_blocks, - private_rpc_port ) -> + private_rpc_port, + sequencer ) -> { kernel; preimages; rollup_node_endpoint = Uri.of_string rollup_node_endpoint; time_between_blocks; private_rpc_port; + sequencer; }) - (obj5 - (dft "kernel" string default_sequencer.kernel) - (dft "preimages" string default_sequencer.preimages) + (obj6 + (dft "kernel" string default_kernel) + (dft "preimages" string default_preimages) (dft "rollup_node_endpoint" string - (Uri.to_string default_proxy.rollup_node_endpoint)) + (Uri.to_string default_rollup_node_endpoint)) (dft "time_between_blocks" encoding_time_between_blocks - default_sequencer.time_between_blocks) + default_time_between_blocks) (dft "private-rpc-port" ~description:"RPC port for private server" uint16 - default_private_rpc_port)) + default_private_rpc_port) + (req "sequencer" Signature.Secret_key.encoding)) -let encoding ~default_mode mode_encoding = +let encoding : type a. a Data_encoding.t -> a t Data_encoding.t = + fun mode_encoding -> let open Data_encoding in - let default = default default_mode in conv (fun { rpc_addr; @@ -189,12 +192,12 @@ let encoding ~default_mode mode_encoding = ((obj8 (dft "rpc-addr" ~description:"RPC address" string default_rpc_addr) (dft "rpc-port" ~description:"RPC port" uint16 default_rpc_port) - (dft "devmode" bool default.devmode) - (dft "cors_origins" (list string) default.cors_origins) - (dft "cors_headers" (list string) default.cors_headers) - (dft "verbose" bool default.verbose) + (dft "devmode" bool default_devmode) + (dft "cors_origins" (list string) default_cors_origins) + (dft "cors_headers" (list string) default_cors_headers) + (dft "verbose" bool default_verbose) (dft "log_filter" log_filter_config_encoding default_filter_config)) - (dft "mode" mode_encoding default_mode)) + (req "mode" mode_encoding)) let save ~force ~data_dir encoding config = let open Lwt_result_syntax in @@ -210,11 +213,11 @@ let save ~force ~data_dir encoding config = Lwt_utils_unix.Json.write_file config_file json let save_proxy ~force ~data_dir config = - let encoding = encoding ~default_mode:default_proxy encoding_proxy in + let encoding = encoding encoding_proxy in save ~force ~data_dir encoding config let save_sequencer ~force ~data_dir config = - let encoding = encoding ~default_mode:default_sequencer encoding_sequencer in + let encoding = encoding encoding_sequencer in save ~force ~data_dir encoding config let load ~data_dir encoding = @@ -224,23 +227,22 @@ let load ~data_dir encoding = config let load_proxy ~data_dir = - let encoding = encoding ~default_mode:default_proxy encoding_proxy in + let encoding = encoding encoding_proxy in load ~data_dir encoding let load_sequencer ~data_dir = - let encoding = encoding ~default_mode:default_sequencer encoding_sequencer in + let encoding = encoding encoding_sequencer in load ~data_dir encoding module Cli = struct let create ~devmode ?rpc_addr ?rpc_port ?cors_origins ?cors_headers ?log_filter ~verbose ~mode () = - let default = default mode in { - rpc_addr = Option.value ~default:default.rpc_addr rpc_addr; - rpc_port = Option.value ~default:default.rpc_port rpc_port; + rpc_addr = Option.value ~default:default_rpc_addr rpc_addr; + rpc_port = Option.value ~default:default_rpc_port rpc_port; devmode; - cors_origins = Option.value ~default:default.cors_origins cors_origins; - cors_headers = Option.value ~default:default.cors_headers cors_headers; + cors_origins = Option.value ~default:default_cors_origins cors_origins; + cors_headers = Option.value ~default:default_cors_headers cors_headers; verbose; log_filter = Option.value ~default:default_filter_config log_filter; mode; @@ -260,23 +262,20 @@ module Cli = struct let create_sequencer ?private_rpc_port ~devmode ?rpc_addr ?rpc_port ?cors_origins ?cors_headers ?log_filter ~verbose ?rollup_node_endpoint - ?kernel ?preimages ?time_between_blocks = + ?kernel ?preimages ?time_between_blocks ~sequencer = let mode = { rollup_node_endpoint = Option.value - ~default:default_sequencer.rollup_node_endpoint + ~default:default_rollup_node_endpoint rollup_node_endpoint; - kernel = Option.value ~default:default_sequencer.kernel kernel; - preimages = Option.value ~default:default_sequencer.preimages preimages; + kernel = Option.value ~default:default_kernel kernel; + preimages = Option.value ~default:default_preimages preimages; time_between_blocks = - Option.value - ~default:default_sequencer.time_between_blocks - time_between_blocks; + Option.value ~default:default_time_between_blocks time_between_blocks; private_rpc_port = - Option.value - ~default:default_sequencer.private_rpc_port - private_rpc_port; + Option.value ~default:default_private_rpc_port private_rpc_port; + sequencer; } in create @@ -326,7 +325,7 @@ module Cli = struct let patch_sequencer_configuration_from_args ?private_rpc_port ~devmode ?rpc_addr ?rpc_port ?cors_origins ?cors_headers ?log_filter ~verbose ?rollup_node_endpoint ?kernel ?preimages ?time_between_blocks - configuration = + configuration ~sequencer = let mode = { rollup_node_endpoint = @@ -340,9 +339,8 @@ module Cli = struct ~default:configuration.mode.time_between_blocks time_between_blocks; private_rpc_port = - Option.value - ~default:default_sequencer.private_rpc_port - private_rpc_port; + Option.value ~default:default_private_rpc_port private_rpc_port; + sequencer; } in patch_configuration_from_args @@ -427,7 +425,8 @@ module Cli = struct let create_or_read_sequencer_config ~data_dir ~devmode ?rpc_addr ?rpc_port ?private_rpc_port ?cors_origins ?cors_headers ?log_filter ~verbose - ?rollup_node_endpoint ?kernel ?preimages ?time_between_blocks () = + ?rollup_node_endpoint ?kernel ?preimages ?time_between_blocks ~sequencer + () = create_or_read_config ~data_dir ~devmode @@ -444,12 +443,14 @@ module Cli = struct ?rollup_node_endpoint ?kernel ?preimages - ?time_between_blocks) + ?time_between_blocks + ~sequencer) ~create: (create_sequencer ?rollup_node_endpoint ?kernel ?preimages - ?time_between_blocks) + ?time_between_blocks + ~sequencer) () end diff --git a/etherlink/bin_evm_node/config/configuration.mli b/etherlink/bin_evm_node/config/configuration.mli index 19b7e7c22e0cf8efee042c564e4bbb69785f9e4c..caff31c355a2cfdda7cdd90a1960e5bbc111b617 100644 --- a/etherlink/bin_evm_node/config/configuration.mli +++ b/etherlink/bin_evm_node/config/configuration.mli @@ -32,6 +32,8 @@ type sequencer = { preimages : string; (** Path to the preimages directory. *) time_between_blocks : time_between_blocks; (** See {!time_between_blocks}. *) private_rpc_port : int; (** Port for internal RPC services *) + sequencer : Signature.secret_key; + (** The secret key used to sign the blueprints. *) } type 'a t = { @@ -93,6 +95,7 @@ module Cli : sig ?kernel:string -> ?preimages:string -> ?time_between_blocks:time_between_blocks -> + sequencer:Signature.secret_key -> unit -> sequencer t @@ -123,6 +126,7 @@ module Cli : sig ?kernel:string -> ?preimages:string -> ?time_between_blocks:time_between_blocks -> + sequencer:Signature.secret_key -> unit -> sequencer t tzresult Lwt.t end diff --git a/etherlink/bin_evm_node/evm_node.ml b/etherlink/bin_evm_node/evm_node.ml index ee912902a5f47d2dcc8b78dc2de8edecf1b19e64..e8426cc23abf0b8df5f4778489668891f9912da6 100644 --- a/etherlink/bin_evm_node/evm_node.ml +++ b/etherlink/bin_evm_node/evm_node.ml @@ -302,6 +302,10 @@ module Params = struct let rollup_node_endpoint = Tezos_clic.parameter (fun _ uri -> Lwt.return_ok (Uri.of_string uri)) + let secret_key : (Signature.secret_key, unit) Tezos_clic.parameter = + Tezos_clic.parameter (fun _ sk -> + Lwt.return_ok (Signature.Secret_key.of_b58check_exn sk)) + let string_list = Tezos_clic.parameter (fun _ s -> let list = String.split ',' s in @@ -373,14 +377,6 @@ let data_dir_arg = ~default Params.string -let rollup_node_endpoint_param = - Tezos_clic.param - ~name:"rollup-node-endpoint" - ~desc: - "The smart rollup node endpoint address (as ADDR:PORT) the node will \ - communicate with." - Params.rollup_node_endpoint - let rollup_address_arg = let open Lwt_result_syntax in let open Tezos_clic in @@ -454,7 +450,13 @@ let proxy_command = verbose_arg keep_alive_arg) (prefixes ["run"; "proxy"; "with"; "endpoint"] - @@ rollup_node_endpoint_param @@ stop) + @@ param + ~name:"rollup-node-endpoint" + ~desc: + "The smart rollup node endpoint address (as ADDR:PORT) the node \ + will communicate with." + Params.rollup_node_endpoint + @@ stop) (fun ( data_dir, devmode, rpc_addr, @@ -561,7 +563,19 @@ let sequencer_command = preimages_arg time_between_blocks_arg) (prefixes ["run"; "sequencer"; "with"; "endpoint"] - @@ rollup_node_endpoint_param @@ stop) + @@ param + ~name:"rollup-node-endpoint" + ~desc: + "The smart rollup node endpoint address (as ADDR:PORT) the node \ + will communicate with." + Params.rollup_node_endpoint + @@ prefixes ["signing"; "with"] + @@ param + ~name:"secret-key" + ~desc: + "The tezos secret key used to sign the blueprints published to L1" + Params.secret_key + @@ stop) (fun ( data_dir, rpc_addr, rpc_port, @@ -573,6 +587,7 @@ let sequencer_command = preimages, time_between_blocks ) rollup_node_endpoint + sequencer () -> let*! () = Tezos_base_unix.Internal_event_unix.init () in let*! () = Internal_event.Simple.emit Event.event_starting "sequencer" in @@ -590,6 +605,7 @@ let sequencer_command = ?kernel ?preimages ?time_between_blocks + ~sequencer () in let* () = Configuration.save_sequencer ~force:true ~data_dir config in @@ -607,12 +623,18 @@ let sequencer_command = let* ctxt = if loaded then return ctxt else - Sequencer_state.init ~rollup_node_endpoint ~smart_rollup_address ctxt + Sequencer_state.init + ~secret_key:sequencer + ~rollup_node_endpoint + ~smart_rollup_address + ctxt in let module Sequencer = Sequencer.Make (struct let ctxt = ctxt let rollup_node_endpoint = rollup_node_endpoint + + let secret_key = sequencer end) in (* Ignore the smart rollup address for now. *) let* () = diff --git a/etherlink/bin_evm_node/lib_dev/sequencer.ml b/etherlink/bin_evm_node/lib_dev/sequencer.ml index 41bde1bdbda185591e9ab12e73cf2b5213888160..60b2f132f122c25369ebd980ad940675a259a9d4 100644 --- a/etherlink/bin_evm_node/lib_dev/sequencer.ml +++ b/etherlink/bin_evm_node/lib_dev/sequencer.ml @@ -9,6 +9,8 @@ module MakeBackend (Ctxt : sig val ctxt : Sequencer_context.t val rollup_node_endpoint : Uri.t + + val secret_key : Signature.secret_key end) : Services_backend_sig.Backend = struct module READER = struct let read path = @@ -38,6 +40,7 @@ end) : Services_backend_sig.Backend = struct let (Ethereum_types.(Qty next) as number) = ctxt.next_blueprint_number in let inputs = Sequencer_blueprint.create + ~secret_key:Ctxt.secret_key ~timestamp ~smart_rollup_address ~transactions:messages @@ -74,5 +77,7 @@ module Make (Ctxt : sig val ctxt : Sequencer_context.t val rollup_node_endpoint : Uri.t + + val secret_key : Signature.secret_key end) = Services_backend_sig.Make (MakeBackend (Ctxt)) diff --git a/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.ml b/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.ml index 7088b7fd82d24b2f89fdedcba2b056cbccbba585..8d0f6538ca9af78bd80478f6ad2cf8861fd89758 100644 --- a/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.ml +++ b/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.ml @@ -18,6 +18,9 @@ let chunk_index_size = 2 let blueprint_tag_size = 1 +(* ED25519 *) +let signature_size = 64 + (* Tags added by RLP encoding for the sequencer blueprint. The sequencer blueprint follows the format: [ chunk, <- max size around 4kb, requires tag of 3 bytes @@ -35,7 +38,7 @@ let max_chunk_size = (* max_input_size already considers the external tag *) max_input_size - framing_protocol_tag_size - smart_rollup_address_size - blueprint_tag_size - blueprint_number_size - nb_chunks_size - - chunk_index_size - rlp_tags_size + - chunk_index_size - rlp_tags_size - signature_size let make_blueprint_chunks ~timestamp ~transactions = let open Rlp in @@ -70,17 +73,29 @@ let encode_u16_le i = Bytes.set_uint16_le bytes 0 i ; bytes -let create ~timestamp ~smart_rollup_address ~number ~transactions = +let create ~secret_key ~timestamp ~smart_rollup_address ~number ~transactions = let open Rlp in let number = Value (encode_u256_le number) in let chunks = make_blueprint_chunks ~timestamp ~transactions in - let nb_chunks = Rlp.Value (encode_u16_le @@ List.length chunks) in + let nb_chunks = Value (encode_u16_le @@ List.length chunks) in let message_from_chunk chunk_index chunk = - let chunk_index = Rlp.Value (encode_u16_le chunk_index) in + let chunk_index = Value (encode_u16_le chunk_index) in + let value = Value (Bytes.of_string chunk) in + + (* Takes the blueprints fields and sign them. *) + let rlp_unsigned_blueprint = + List [value; number; nb_chunks; chunk_index] |> encode + in + let signature = + Signature.(sign secret_key rlp_unsigned_blueprint |> to_bytes) + in + + (* Encode the blueprints fields and its signature. *) let rlp_sequencer_blueprint = - List [Value (Bytes.of_string chunk); number; nb_chunks; chunk_index] + List [value; number; nb_chunks; chunk_index; Value signature] |> encode |> Bytes.to_string in + `External ("\000" (* Framed protocol *) ^ smart_rollup_address ^ "\003" diff --git a/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.mli b/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.mli index e3f0cf49cc37ea59e4b657d90c286c1c9a8f4f70..520e4b7277ab8dc40dc59494586c93dec9a07c67 100644 --- a/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.mli +++ b/etherlink/bin_evm_node/lib_dev/sequencer_blueprint.mli @@ -5,12 +5,13 @@ (* *) (*****************************************************************************) -(** [create ~timestamp ~smart_rollup_address ~number ~transactions] +(** [create ~secret_key ~timestamp ~smart_rollup_address ~number ~transactions] creates a sequencer blueprint at [timestamp] with a given [number] - containing [transactions]. Returns valid payload of external - messages inputs to put in the inbox. + containing [transactions], signed with [secret_key]. Returns + valid list of external messages inputs to put in the inbox. *) val create : + secret_key:Signature.secret_key -> timestamp:Time.Protocol.t -> smart_rollup_address:string -> number:Ethereum_types.quantity -> diff --git a/etherlink/bin_evm_node/lib_dev/sequencer_state.ml b/etherlink/bin_evm_node/lib_dev/sequencer_state.ml index 8131af386d7c3b650ae6c4fbdacf2be64596c24f..bc988904f0d8856f7fd11cd21dcaa645f2f2ead7 100644 --- a/etherlink/bin_evm_node/lib_dev/sequencer_state.ml +++ b/etherlink/bin_evm_node/lib_dev/sequencer_state.ml @@ -29,7 +29,7 @@ let execute ?(commit = false) ctxt inbox = in return (ctxt, evm_state) -let init ~smart_rollup_address ~rollup_node_endpoint ctxt = +let init ~secret_key ~smart_rollup_address ~rollup_node_endpoint ctxt = let open Lwt_result_syntax in let* evm_state = Wasm.start @@ -43,6 +43,7 @@ let init ~smart_rollup_address ~rollup_node_endpoint ctxt = (* Create the first empty block. *) let inputs = Sequencer_blueprint.create + ~secret_key ~timestamp:(Helpers.now ()) ~smart_rollup_address ~transactions:[] diff --git a/etherlink/bin_evm_node/lib_dev/sequencer_state.mli b/etherlink/bin_evm_node/lib_dev/sequencer_state.mli index ff90ce82425fecd737538d5808fbab3ffc16735f..e77d58a8e9747bf0cc4a134238d3201f9a70ba2f 100644 --- a/etherlink/bin_evm_node/lib_dev/sequencer_state.mli +++ b/etherlink/bin_evm_node/lib_dev/sequencer_state.mli @@ -14,10 +14,11 @@ val execute : [< `Input of string] list -> (Sequencer_context.t * Sequencer_context.evm_state) tzresult Lwt.t -(** [init ~smart_rollup_address ~rollup_node_endpoint ctxt] +(** [init ~secret_key ~smart_rollup_address ~rollup_node_endpoint ctxt] initializes the local state in [ctxt], produces and publishes the genesis block. *) val init : + secret_key:Signature.secret_key -> smart_rollup_address:string -> rollup_node_endpoint:Uri.t -> Sequencer_context.t -> diff --git a/etherlink/kernel_evm/kernel/src/blueprint_storage.rs b/etherlink/kernel_evm/kernel/src/blueprint_storage.rs index f4533ce10a3443023a565aa049143d243d693b76..58f0aee04a71911f5891070797ebcc99f334dd06 100644 --- a/etherlink/kernel_evm/kernel/src/blueprint_storage.rs +++ b/etherlink/kernel_evm/kernel/src/blueprint_storage.rs @@ -159,11 +159,11 @@ pub fn store_sequencer_blueprint( host: &mut Host, blueprint: SequencerBlueprint, ) -> Result<(), Error> { - let blueprint_path = blueprint_path(blueprint.number)?; - store_blueprint_nb_chunks(host, &blueprint_path, blueprint.nb_chunks)?; + let blueprint_path = blueprint_path(blueprint.blueprint.number)?; + store_blueprint_nb_chunks(host, &blueprint_path, blueprint.blueprint.nb_chunks)?; let blueprint_chunk_path = - blueprint_chunk_path(&blueprint_path, blueprint.chunk_index)?; - let store_blueprint = StoreBlueprint::SequencerChunk(blueprint.chunk); + blueprint_chunk_path(&blueprint_path, blueprint.blueprint.chunk_index)?; + let store_blueprint = StoreBlueprint::SequencerChunk(blueprint.blueprint.chunk); store_rlp(&store_blueprint, host, &blueprint_chunk_path) } diff --git a/etherlink/kernel_evm/kernel/src/inbox.rs b/etherlink/kernel_evm/kernel/src/inbox.rs index c5801765030481bdc4b0fbf5a9302c21bc9c9a93..039b692b8a3e23fba7edfa5fb7f0efecb31ea79e 100644 --- a/etherlink/kernel_evm/kernel/src/inbox.rs +++ b/etherlink/kernel_evm/kernel/src/inbox.rs @@ -24,6 +24,7 @@ use tezos_ethereum::transaction::{TransactionHash, TRANSACTION_HASH_SIZE}; use tezos_ethereum::tx_common::EthereumTransactionCommon; use tezos_evm_logging::{log, Level::*}; use tezos_smart_rollup_core::PREIMAGE_HASH_SIZE; +use tezos_smart_rollup_encoding::public_key::PublicKey; use tezos_smart_rollup_host::runtime::Runtime; #[derive(Debug, PartialEq, Clone)] @@ -182,6 +183,7 @@ pub fn read_input( admin: &Option, inbox_is_empty: &mut bool, delayed_bridge: &Option, + sequencer: &Option, ) -> Result { let input = host.read_input()?; @@ -195,6 +197,7 @@ pub fn read_input( ticketer, admin, delayed_bridge, + sequencer, )) } None => Ok(InputResult::NoInput), @@ -286,6 +289,7 @@ pub fn read_inbox( ticketer: Option, admin: Option, delayed_bridge: Option, + sequencer: Option, ) -> Result, anyhow::Error> { let mut res = InboxContent { kernel_upgrade: None, @@ -305,6 +309,7 @@ pub fn read_inbox( &admin, &mut inbox_is_empty, &delayed_bridge, + &sequencer, )? { InputResult::NoInput => { if inbox_is_empty { @@ -489,9 +494,10 @@ mod tests { host.add_external(Bytes::from(input_to_bytes(SMART_ROLLUP_ADDRESS, input))); - let inbox_content = read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None) - .unwrap() - .unwrap(); + let inbox_content = + read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None, None) + .unwrap() + .unwrap(); let expected_transactions = vec![Transaction { tx_hash, content: Ethereum(tx), @@ -513,9 +519,10 @@ mod tests { host.add_external(Bytes::from(input_to_bytes(SMART_ROLLUP_ADDRESS, input))) } - let inbox_content = read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None) - .unwrap() - .unwrap(); + let inbox_content = + read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None, None) + .unwrap() + .unwrap(); let expected_transactions = vec![Transaction { tx_hash, content: Ethereum(tx), @@ -553,9 +560,10 @@ mod tests { let transfer_metadata = TransferMetadata::new(sender.clone(), source); host.add_transfer(payload, &transfer_metadata); - let inbox_content = read_inbox(&mut host, [0; 20], None, Some(sender), None) - .unwrap() - .unwrap(); + let inbox_content = + read_inbox(&mut host, [0; 20], None, Some(sender), None, None) + .unwrap() + .unwrap(); let expected_upgrade = Some(KernelUpgrade { preimage_hash }); assert_eq!(inbox_content.kernel_upgrade, expected_upgrade); } @@ -589,7 +597,7 @@ mod tests { ))); let _inbox_content = - read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None).unwrap(); + read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None, None).unwrap(); let num_chunks = chunked_transaction_num_chunks(&mut host, &tx_hash) .expect("The number of chunks should exist"); @@ -632,7 +640,7 @@ mod tests { host.add_external(Bytes::from(input_to_bytes(SMART_ROLLUP_ADDRESS, chunk))); let _inbox_content = - read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None).unwrap(); + read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None, None).unwrap(); // The out of bounds chunk should not exist. let chunked_transaction_path = chunked_transaction_path(&tx_hash).unwrap(); @@ -664,7 +672,7 @@ mod tests { host.add_external(Bytes::from(input_to_bytes(SMART_ROLLUP_ADDRESS, chunk))); let _inbox_content = - read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None).unwrap(); + read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None, None).unwrap(); // The unknown chunk should not exist. let chunked_transaction_path = chunked_transaction_path(&tx_hash).unwrap(); @@ -711,9 +719,10 @@ mod tests { host.add_external(Bytes::from(input_to_bytes(SMART_ROLLUP_ADDRESS, chunk0))); - let inbox_content = read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None) - .unwrap() - .unwrap(); + let inbox_content = + read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None, None) + .unwrap() + .unwrap(); assert_eq!( inbox_content, InboxContent { @@ -727,9 +736,10 @@ mod tests { for input in inputs { host.add_external(Bytes::from(input_to_bytes(SMART_ROLLUP_ADDRESS, input))) } - let inbox_content = read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None) - .unwrap() - .unwrap(); + let inbox_content = + read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None, None) + .unwrap() + .unwrap(); let expected_transactions = vec![Transaction { tx_hash, @@ -782,9 +792,10 @@ mod tests { host.add_external(framed); - let inbox_content = read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None) - .unwrap() - .unwrap(); + let inbox_content = + read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None, None) + .unwrap() + .unwrap(); let expected_transactions = vec![Transaction { tx_hash, content: Ethereum(tx), @@ -801,12 +812,12 @@ mod tests { // in the inbox, we mock it by adding a single input. host.add_external(Bytes::from(vec![])); let inbox_content = - read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None).unwrap(); + read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None, None).unwrap(); assert!(inbox_content.is_some()); // Reading again the inbox returns no inbox content at all. let inbox_content = - read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None).unwrap(); + read_inbox(&mut host, SMART_ROLLUP_ADDRESS, None, None, None, None).unwrap(); assert!(inbox_content.is_none()); } } diff --git a/etherlink/kernel_evm/kernel/src/lib.rs b/etherlink/kernel_evm/kernel/src/lib.rs index e068501d3e33d6767ba7a8f4ccbe0c653142872f..6203b66866cebb4e3caa2dc5f8630ee9f526d6c8 100644 --- a/etherlink/kernel_evm/kernel/src/lib.rs +++ b/etherlink/kernel_evm/kernel/src/lib.rs @@ -21,11 +21,11 @@ use evm_execution::Config; use migration::MigrationStatus; use primitive_types::U256; use storage::{ - is_sequencer, read_admin, read_base_fee_per_gas, read_chain_id, - read_delayed_transaction_bridge, read_kernel_version, - read_last_info_per_level_timestamp, read_last_info_per_level_timestamp_stats, - read_ticketer, store_base_fee_per_gas, store_chain_id, store_kernel_version, - store_storage_version, STORAGE_VERSION, STORAGE_VERSION_PATH, + read_admin, read_base_fee_per_gas, read_chain_id, read_delayed_transaction_bridge, + read_kernel_version, read_last_info_per_level_timestamp, + read_last_info_per_level_timestamp_stats, read_ticketer, sequencer, + store_base_fee_per_gas, store_chain_id, store_kernel_version, store_storage_version, + STORAGE_VERSION, STORAGE_VERSION_PATH, }; use tezos_crypto_rs::hash::ContractKt1Hash; use tezos_evm_logging::{log, Level::*}; @@ -104,6 +104,7 @@ pub fn stage_one( ticketer, admin ); + log!(host, Info, "Configuration: {}", configuration); fetch(host, smart_rollup_address, ticketer, admin, configuration) } @@ -211,22 +212,26 @@ fn retrieve_base_fee_per_gas(host: &mut Host) -> Result(host: &mut Host) -> anyhow::Result { - let is_sequencer = is_sequencer(host)?; - if is_sequencer { - let delayed_bridge = read_delayed_transaction_bridge(host) - // The sequencer must declare a delayed transaction bridge. This - // default value is only to facilitate the testing. - .unwrap_or_else(|| { - ContractKt1Hash::from_base58_check("KT18amZmM5W7qDWVt2pH6uj7sCEd3kbzLrHT") + let sequencer = sequencer(host)?; + match sequencer { + Some(sequencer) => { + let delayed_bridge = read_delayed_transaction_bridge(host) + // The sequencer must declare a delayed transaction bridge. This + // default value is only to facilitate the testing. + .unwrap_or_else(|| { + ContractKt1Hash::from_base58_check( + "KT18amZmM5W7qDWVt2pH6uj7sCEd3kbzLrHT", + ) .unwrap() - }); - let delayed_inbox = Box::new(DelayedInbox::new(host)?); - Ok(Configuration::Sequencer { - delayed_bridge, - delayed_inbox, - }) - } else { - Ok(Configuration::Proxy) + }); + let delayed_inbox = Box::new(DelayedInbox::new(host)?); + Ok(Configuration::Sequencer { + delayed_bridge, + delayed_inbox, + sequencer, + }) + } + None => Ok(Configuration::Proxy), } } diff --git a/etherlink/kernel_evm/kernel/src/parsing.rs b/etherlink/kernel_evm/kernel/src/parsing.rs index 88beeee96ade64aa3e4d454d029da0002af4c5cc..65c7d6a865c54ec6105d1139bb73ca963af281a5 100644 --- a/etherlink/kernel_evm/kernel/src/parsing.rs +++ b/etherlink/kernel_evm/kernel/src/parsing.rs @@ -7,11 +7,12 @@ use crate::{ inbox::{Deposit, KernelUpgrade, Transaction, TransactionContent}, - sequencer_blueprint::SequencerBlueprint, + sequencer_blueprint::{SequencerBlueprint, UnsignedSequencerBlueprint}, }; use primitive_types::{H160, U256}; +use rlp::Encodable; use sha3::{Digest, Keccak256}; -use tezos_crypto_rs::hash::ContractKt1Hash; +use tezos_crypto_rs::{hash::ContractKt1Hash, PublicKeySignatureVerifier}; use tezos_ethereum::{ rlp_helpers::FromRlpBytes, transaction::{TransactionHash, TRANSACTION_HASH_SIZE}, @@ -26,6 +27,7 @@ use tezos_smart_rollup_encoding::{ ExternalMessageFrame, InboxMessage, InfoPerLevel, InternalInboxMessage, Transfer, }, michelson::{ticket::FA2_1Ticket, MichelsonBytes, MichelsonOr, MichelsonPair}, + public_key::PublicKey, }; use tezos_smart_rollup_host::input::Message; use tezos_smart_rollup_host::runtime::Runtime; @@ -201,10 +203,26 @@ impl InputResult { } } - fn parse_sequencer_blueprint_input(bytes: &[u8]) -> Self { + fn parse_sequencer_blueprint_input(sequencer: &PublicKey, bytes: &[u8]) -> Self { + // Parse the sequencer blueprint let seq_blueprint: SequencerBlueprint = parsable!(FromRlpBytes::from_rlp_bytes(bytes).ok()); - InputResult::Input(Input::SequencerBlueprint(seq_blueprint)) + + // Creates and encodes the unsigned blueprint: + let unsigned_seq_blueprint: UnsignedSequencerBlueprint = (&seq_blueprint).into(); + let bytes = unsigned_seq_blueprint.rlp_bytes().to_vec(); + // The sequencer signs the hash of the blueprint. + let msg = tezos_crypto_rs::blake2b::digest_256(&bytes).unwrap(); + + let correctly_signed = sequencer + .verify_signature(&seq_blueprint.signature, &msg) + .unwrap_or(false); + + if correctly_signed { + InputResult::Input(Input::SequencerBlueprint(seq_blueprint)) + } else { + InputResult::Unparsable + } } /// Parses transactions that come from the delayed inbox. @@ -230,9 +248,13 @@ impl InputResult { /// Parses an external message /// - /// External message structure : - /// EXTERNAL_TAG 1B / FRAMING_PROTOCOL_TARGETTED 21B / MESSAGE_TAG 1B / DATA - fn parse_external(input: &[u8], smart_rollup_address: &[u8]) -> Self { + // External message structure : + // EXTERNAL_TAG 1B / FRAMING_PROTOCOL_TARGETTED 21B / MESSAGE_TAG 1B / DATA + fn parse_external( + input: &[u8], + smart_rollup_address: &[u8], + sequencer: &Option, + ) -> Self { // Compatibility with framing protocol for external messages let remaining = match ExternalMessageFrame::parse(input) { Ok(ExternalMessageFrame::Targetted { address, contents }) @@ -248,7 +270,12 @@ impl InputResult { SIMPLE_TRANSACTION_TAG => Self::parse_simple_transaction(remaining), NEW_CHUNKED_TRANSACTION_TAG => Self::parse_new_chunked_transaction(remaining), TRANSACTION_CHUNK_TAG => Self::parse_transaction_chunk(remaining), - SEQUENCER_BLUEPRINT_TAG => Self::parse_sequencer_blueprint_input(remaining), + SEQUENCER_BLUEPRINT_TAG if sequencer.is_some() => { + Self::parse_sequencer_blueprint_input( + sequencer.as_ref().unwrap(), + remaining, + ) + } _ => InputResult::Unparsable, } } @@ -370,6 +397,7 @@ impl InputResult { ticketer: &Option, admin: &Option, delayed_bridge: &Option, + sequencer: &Option, ) -> Self { let bytes = Message::as_ref(&input); let (input_tag, remaining) = parsable!(bytes.split_first()); @@ -380,7 +408,7 @@ impl InputResult { match InboxMessage::::parse(bytes) { Ok((_remaing, message)) => match message { InboxMessage::External(message) => { - Self::parse_external(message, &smart_rollup_address) + Self::parse_external(message, &smart_rollup_address, sequencer) } InboxMessage::Internal(message) => Self::parse_internal( host, @@ -416,6 +444,7 @@ mod tests { ZERO_SMART_ROLLUP_ADDRESS, &None, &None, + &None, &None ), InputResult::Unparsable diff --git a/etherlink/kernel_evm/kernel/src/sequencer_blueprint.rs b/etherlink/kernel_evm/kernel/src/sequencer_blueprint.rs index 0b0a8355d66059d74709040ddd2e3acd66979835..12ac3fbd6f363eedfa80c088a0382e9aa34f9434 100644 --- a/etherlink/kernel_evm/kernel/src/sequencer_blueprint.rs +++ b/etherlink/kernel_evm/kernel/src/sequencer_blueprint.rs @@ -4,19 +4,32 @@ use primitive_types::U256; use rlp::{Decodable, DecoderError, Encodable}; +use tezos_crypto_rs::hash::Signature; use tezos_ethereum::rlp_helpers::{ self, append_u16_le, append_u256_le, decode_field_u16_le, decode_field_u256_le, }; #[derive(PartialEq, Debug, Clone)] -pub struct SequencerBlueprint { +pub struct UnsignedSequencerBlueprint { pub chunk: Vec, pub number: U256, pub nb_chunks: u16, pub chunk_index: u16, } -impl Encodable for SequencerBlueprint { +#[derive(PartialEq, Debug, Clone)] +pub struct SequencerBlueprint { + pub blueprint: UnsignedSequencerBlueprint, + pub signature: Signature, +} + +impl From<&SequencerBlueprint> for UnsignedSequencerBlueprint { + fn from(val: &SequencerBlueprint) -> UnsignedSequencerBlueprint { + val.blueprint.clone() + } +} + +impl Encodable for UnsignedSequencerBlueprint { fn rlp_append(&self, stream: &mut rlp::RlpStream) { stream.begin_list(4); stream.append(&self.chunk); @@ -26,12 +39,23 @@ impl Encodable for SequencerBlueprint { } } +impl Encodable for SequencerBlueprint { + fn rlp_append(&self, stream: &mut rlp::RlpStream) { + stream.begin_list(5); + stream.append(&self.blueprint.chunk); + append_u256_le(stream, &self.blueprint.number); + append_u16_le(stream, &self.blueprint.nb_chunks); + append_u16_le(stream, &self.blueprint.chunk_index); + stream.append(&self.signature.0); + } +} + impl Decodable for SequencerBlueprint { fn decode(decoder: &rlp::Rlp) -> Result { if !decoder.is_list() { return Err(DecoderError::RlpExpectedToBeList); } - if decoder.item_count()? != 4 { + if decoder.item_count()? != 5 { return Err(DecoderError::RlpIncorrectListLen); } let mut it = decoder.iter(); @@ -40,23 +64,32 @@ impl Decodable for SequencerBlueprint { let nb_chunks = decode_field_u16_le(&rlp_helpers::next(&mut it)?, "nb_chunks")?; let chunk_index = decode_field_u16_le(&rlp_helpers::next(&mut it)?, "chunk_index")?; - Ok(Self { + let bytes: Vec = + rlp_helpers::decode_field(&rlp_helpers::next(&mut it)?, "signature")?; + let signature = Signature::try_from(bytes.as_slice()) + .map_err(|_| DecoderError::Custom("Invalid signature encoding"))?; + let blueprint = UnsignedSequencerBlueprint { chunk, number, nb_chunks, chunk_index, + }; + Ok(Self { + blueprint, + signature, }) } } #[cfg(test)] mod tests { - use super::SequencerBlueprint; + use super::{SequencerBlueprint, UnsignedSequencerBlueprint}; use crate::blueprint::Blueprint; use crate::inbox::Transaction; use crate::inbox::TransactionContent::Ethereum; use primitive_types::{H160, U256}; use rlp::Encodable; + use tezos_crypto_rs::hash::Signature; use tezos_ethereum::rlp_helpers::FromRlpBytes; use tezos_ethereum::{ transaction::TRANSACTION_HASH_SIZE, tx_common::EthereumTransactionCommon, @@ -106,11 +139,18 @@ mod tests { transactions, }; let chunk = rlp::Encodable::rlp_bytes(&blueprint); + let signature = Signature::from_base58_check( + "sigdGBG68q2vskMuac4AzyNb1xCJTfuU8MiMbQtmZLUCYydYrtTd5Lessn1EFLTDJzjXoYxRasZxXbx6tHnirbEJtikcMHt3" + ).expect("signature decoding should work"); + SequencerBlueprint { - chunk: chunk.into(), - number: U256::from(42), - nb_chunks: 1u16, - chunk_index: 0u16, + blueprint: UnsignedSequencerBlueprint { + chunk: chunk.into(), + number: U256::from(42), + nb_chunks: 1u16, + chunk_index: 0u16, + }, + signature, } } diff --git a/etherlink/kernel_evm/kernel/src/stage_one.rs b/etherlink/kernel_evm/kernel/src/stage_one.rs index bc5206e2f480f938c8e70b57d10205c91def181e..eb3f78c4f5f7b798c667f7ec5fa33e7e65f3e324 100644 --- a/etherlink/kernel_evm/kernel/src/stage_one.rs +++ b/etherlink/kernel_evm/kernel/src/stage_one.rs @@ -12,6 +12,7 @@ use crate::storage::store_kernel_upgrade; use anyhow::Ok; use tezos_crypto_rs::hash::ContractKt1Hash; use tezos_evm_logging::{log, Level::*}; +use tezos_smart_rollup_encoding::public_key::PublicKey; use tezos_smart_rollup_host::metadata::RAW_ROLLUP_ADDRESS_SIZE; use tezos_smart_rollup_host::runtime::Runtime; @@ -21,9 +22,27 @@ pub enum Configuration { Sequencer { delayed_bridge: ContractKt1Hash, delayed_inbox: Box, + sequencer: PublicKey, }, } +impl std::fmt::Display for Configuration { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Configuration::Proxy => write!(f, "Proxy"), + Configuration::Sequencer { + delayed_bridge, + delayed_inbox: _, // Ignoring delayed_inbox + sequencer, + } => write!( + f, + "Sequencer {{ delayed_bridge: {:?}, sequencer: {:?} }}", + delayed_bridge, sequencer + ), + } + } +} + pub fn fetch_inbox_blueprints( host: &mut Host, smart_rollup_address: [u8; RAW_ROLLUP_ADDRESS_SIZE], @@ -34,7 +53,7 @@ pub fn fetch_inbox_blueprints( kernel_upgrade, transactions, sequencer_blueprints: _, - }) = read_inbox(host, smart_rollup_address, ticketer, admin, None)? + }) = read_inbox(host, smart_rollup_address, ticketer, admin, None, None)? { let timestamp = current_timestamp(host); let blueprint = Blueprint { @@ -58,6 +77,7 @@ fn fetch_sequencer_blueprints( admin: Option, delayed_bridge: ContractKt1Hash, delayed_inbox: &mut DelayedInbox, + sequencer: PublicKey, ) -> Result<(), anyhow::Error> { if let Some(InboxContent { kernel_upgrade, @@ -69,6 +89,7 @@ fn fetch_sequencer_blueprints( ticketer, admin, Some(delayed_bridge), + Some(sequencer), )? { // Store the transactions in the delayed inbox. for transaction in transactions { @@ -81,8 +102,8 @@ fn fetch_sequencer_blueprints( host, Debug, "Storing chunk {} of sequencer blueprint number {}", - seq_blueprint.chunk_index, - seq_blueprint.number + seq_blueprint.blueprint.chunk_index, + seq_blueprint.blueprint.number ); store_sequencer_blueprint(host, seq_blueprint)? } @@ -105,6 +126,7 @@ pub fn fetch( Configuration::Sequencer { delayed_bridge, delayed_inbox, + sequencer, } => fetch_sequencer_blueprints( host, smart_rollup_address, @@ -112,6 +134,7 @@ pub fn fetch( admin, delayed_bridge.clone(), delayed_inbox, + sequencer.clone(), ), Configuration::Proxy => { fetch_inbox_blueprints(host, smart_rollup_address, ticketer, admin) diff --git a/etherlink/kernel_evm/kernel/src/storage.rs b/etherlink/kernel_evm/kernel/src/storage.rs index b333904ea3c53381ebb937fd833ea13ee1a53d43..97ee31cfc7fbacfcab9fa37ed951ad95dfe5335e 100644 --- a/etherlink/kernel_evm/kernel/src/storage.rs +++ b/etherlink/kernel_evm/kernel/src/storage.rs @@ -12,6 +12,7 @@ use evm_execution::account_storage::EthereumAccount; use tezos_crypto_rs::hash::{ContractKt1Hash, HashTrait}; use tezos_evm_logging::{log, Level::*}; use tezos_smart_rollup_core::MAX_FILE_CHUNK_SIZE; +use tezos_smart_rollup_encoding::public_key::PublicKey; use tezos_smart_rollup_encoding::timestamp::Timestamp; use tezos_smart_rollup_host::path::*; use tezos_smart_rollup_host::runtime::{Runtime, ValueType}; @@ -90,7 +91,8 @@ pub const WORD_SIZE: usize = 32usize; const KERNEL_UPGRADE: RefPath = RefPath::assert_from(b"/kernel_upgrade"); -// Path to the flag denoting whether the kernel is in sequencer mode or not. +// Path to the tz1 administrating the sequencer. If there is nothing +// at this path, the kernel is in proxy mode. const SEQUENCER: RefPath = RefPath::assert_from(b"/sequencer"); pub fn store_read_slice( @@ -832,8 +834,15 @@ pub fn delete_kernel_upgrade(host: &mut Host) -> anyhow::Result<( .context("Failed to delete kernel upgrade") } -pub fn is_sequencer(host: &Host) -> Result { - Ok(host.store_has(&SEQUENCER)?.is_some()) +pub fn sequencer(host: &Host) -> anyhow::Result> { + if host.store_has(&SEQUENCER)?.is_some() { + let bytes = host.store_read_all(&SEQUENCER)?; + let Ok(tz1_b58) = String::from_utf8(bytes) else { return Ok(None) }; + let Ok(tz1) = PublicKey::from_b58check(&tz1_b58) else { return Ok(None)}; + Ok(Some(tz1)) + } else { + Ok(None) + } } #[cfg(test)] diff --git a/tezt/lib_ethereum/configuration.ml b/tezt/lib_ethereum/configuration.ml index 7d7cdef571affe87f8d51ad8c9d3f2ad909f9c73..182b53a899fff45ef13be4d3fa80d25e43368211 100644 --- a/tezt/lib_ethereum/configuration.ml +++ b/tezt/lib_ethereum/configuration.ml @@ -7,8 +7,8 @@ let default_bootstrap_account_balance = Wei.of_eth_int 9999 -let make_config ?bootstrap_accounts ?ticketer ?administrator - ?(sequencer = false) ?delayed_bridge () = +let make_config ?bootstrap_accounts ?ticketer ?administrator ?sequencer + ?delayed_bridge () = let open Sc_rollup_helpers.Installer_kernel_config in let ticketer = Option.fold @@ -44,9 +44,13 @@ let make_config ?bootstrap_accounts ?ticketer ?administrator administrator in let sequencer = - if sequencer then [Set {value = "00"; to_ = Durable_storage_path.sequencer}] - else [] + match sequencer with + | Some secret_key -> + let value = Hex.(of_string secret_key |> show) in + [Set {value; to_ = Durable_storage_path.sequencer}] + | None -> [] in + let delayed_bridge = Option.fold ~some:(fun delayed_bridge -> diff --git a/tezt/lib_ethereum/configuration.mli b/tezt/lib_ethereum/configuration.mli index 70171437d303743950cec094372e4033864f50b1..f553e0da20b66219d764c16bb95cac3f17f3fac6 100644 --- a/tezt/lib_ethereum/configuration.mli +++ b/tezt/lib_ethereum/configuration.mli @@ -15,7 +15,7 @@ val make_config : ?bootstrap_accounts:Eth_account.t array -> ?ticketer:string -> ?administrator:string -> - ?sequencer:bool -> + ?sequencer:string -> ?delayed_bridge:string -> unit -> [> `Config of Sc_rollup_helpers.Installer_kernel_config.instr list] option diff --git a/tezt/lib_tezos/evm_node.ml b/tezt/lib_tezos/evm_node.ml index 9e863bbca2016928ba1019eff72ca38a0ce91688..d69d277fc2b4ae28f9d0287d405fb05787f22e53 100644 --- a/tezt/lib_tezos/evm_node.ml +++ b/tezt/lib_tezos/evm_node.ml @@ -33,6 +33,7 @@ type mode = preimage_dir : string; private_rpc_port : int; time_between_blocks : time_between_blocks option; + sequencer : string; } | Proxy of {devmode : bool} @@ -149,13 +150,18 @@ let run_args evm_node = evm_node.persistent_state.rollup_node_endpoint; ] @ Cli_arg.optional_switch "devmode" devmode - | Sequencer {kernel; preimage_dir; private_rpc_port; time_between_blocks} -> + | Sequencer + {kernel; preimage_dir; private_rpc_port; time_between_blocks; sequencer} + -> [ "run"; "sequencer"; "with"; "endpoint"; evm_node.persistent_state.rollup_node_endpoint; + "signing"; + "with"; + sequencer; "--kernel"; kernel; "--preimage-dir"; diff --git a/tezt/lib_tezos/evm_node.mli b/tezt/lib_tezos/evm_node.mli index 2811dd0d698d7c8bd212b9aca73028fe8a30e880..2d51d816dbc9cb35241eff35b9a6a7dab8ce6aa7 100644 --- a/tezt/lib_tezos/evm_node.mli +++ b/tezt/lib_tezos/evm_node.mli @@ -44,6 +44,7 @@ type mode = time_between_blocks : time_between_blocks option; (** See {!time_between_blocks}, if the value is not provided, the sequencer uses it default value. *) + sequencer : string; (** Secret key used to sign the blueprints. *) } | Proxy of {devmode : bool (** --devmode flag. *)} diff --git a/tezt/tests/evm_rollup.ml b/tezt/tests/evm_rollup.ml index ea0dba135ae4ed3bb647feea7bde8f8266773de0..a3cac6a9f767fe74aeb6e61ceea9dca12190de8d 100644 --- a/tezt/tests/evm_rollup.ml +++ b/tezt/tests/evm_rollup.ml @@ -255,6 +255,7 @@ type kernel_installee = {base_installee : string; installee : string} type setup_mode = | Setup_sequencer of { time_between_blocks : Evm_node.time_between_blocks option; + sequencer : Account.key; } | Setup_proxy of {devmode : bool} @@ -283,13 +284,15 @@ let setup_evm_kernel ?config ?kernel_installee else None in let sequencer = - match setup_mode with Setup_proxy _ -> false | Setup_sequencer _ -> true + match setup_mode with + | Setup_proxy _ -> None + | Setup_sequencer {sequencer; _} -> Some sequencer.public_key in Configuration.make_config ~bootstrap_accounts ?ticketer ?administrator - ~sequencer + ?sequencer () in let config = @@ -309,18 +312,16 @@ let setup_evm_kernel ?config ?kernel_installee ~default_operator:rollup_operator_key in (* Start a rollup node *) + let preimages_dir = + Filename.concat (Sc_rollup_node.data_dir sc_rollup_node) "wasm_2_0_0" + in let* {output; _} = let base_installee, installee = match kernel_installee with | Some {base_installee; installee} -> (base_installee, installee) | None -> ("./", "evm_kernel") in - prepare_installer_kernel - ~base_installee - ~preimages_dir: - (Filename.concat (Sc_rollup_node.data_dir sc_rollup_node) "wasm_2_0_0") - ?config - installee + prepare_installer_kernel ~base_installee ~preimages_dir ?config installee in let* sc_rollup_address = originate_sc_rollup @@ -340,16 +341,14 @@ let setup_evm_kernel ?config ?kernel_installee let* mode = match setup_mode with | Setup_proxy {devmode} -> return (Evm_node.Proxy {devmode}) - | Setup_sequencer {time_between_blocks} -> - let preimages_dir = Temp.dir "preimages" in - let* {output; _} = - prepare_installer_kernel - ~base_installee:"./" - ~preimages_dir - ?config - "evm_kernel" - in + | Setup_sequencer {time_between_blocks; sequencer} -> let private_rpc_port = Port.fresh () in + let sequencer = + match sequencer.secret_key with + | Unencrypted sk -> sk + | Encrypted _ -> + Test.fail "Provide an unencrypted key for the sequencer" + in return (Evm_node.Sequencer { @@ -357,6 +356,7 @@ let setup_evm_kernel ?config ?kernel_installee preimage_dir = preimages_dir; private_rpc_port; time_between_blocks; + sequencer; }) in let* evm_node = @@ -482,7 +482,9 @@ let register_both ~title ~tags ?uses ?admin ?commitment_period ?challenge_window ~past_genesis in register ~setup_mode:(Setup_proxy {devmode = true}) ; - register ~setup_mode:(Setup_sequencer {time_between_blocks}) + register + ~setup_mode: + (Setup_sequencer {time_between_blocks; sequencer = Constant.bootstrap1}) type contract = {label : string; abi : string; bin : string} diff --git a/tezt/tests/evm_sequencer.ml b/tezt/tests/evm_sequencer.ml index c16ede45c645acf0f5946c4a4697a530b464bc8b..14025ba87deff15f5a4993b851814b35783a8a86 100644 --- a/tezt/tests/evm_sequencer.ml +++ b/tezt/tests/evm_sequencer.ml @@ -72,7 +72,8 @@ let setup_l1_contracts client = return {delayed_transaction_bridge; exchanger; bridge} let setup_sequencer ?time_between_blocks - ?(bootstrap_accounts = Eth_account.bootstrap_accounts) protocol = + ?(bootstrap_accounts = Eth_account.bootstrap_accounts) + ?(sequencer = Constant.bootstrap1) protocol = let* node, client = setup_l1 protocol in let* l1_contracts = setup_l1_contracts client in let sc_rollup_node = @@ -86,7 +87,7 @@ let setup_sequencer ?time_between_blocks let config = Configuration.make_config ~bootstrap_accounts - ~sequencer:true + ~sequencer:sequencer.public_key ~delayed_bridge:l1_contracts.delayed_transaction_bridge ~ticketer:l1_contracts.exchanger () @@ -110,12 +111,18 @@ let setup_sequencer ?time_between_blocks in let private_rpc_port = Port.fresh () in let mode = + let sequencer = + match sequencer.secret_key with + | Unencrypted sk -> sk + | Encrypted _ -> Test.fail "Provide an unencrypted key for the sequencer" + in Evm_node.Sequencer { kernel = output; preimage_dir = preimages_dir; private_rpc_port; time_between_blocks; + sequencer; } in let* evm_node =