diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml index 2c94c29651559920f8360ad4d38bd3efa1244ea8..59c6e92034e17a627b3c03cdaeb899a3d1e59d67 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml @@ -141,6 +141,8 @@ module Chain_id = struct let decode_le bytes = Chain_id (decode_z_le bytes) let decode_be bytes = Chain_id (decode_z_be bytes) + + let compare (Chain_id c1) (Chain_id c2) = Z.compare c1 c2 end type chain_family = EVM | Michelson diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli index 8e827dd75322f2a3dcb3e079d657dbdcd225cd20..99cf72f1d6df5eb66b281622186fc3a7a01d7fc3 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli @@ -68,6 +68,8 @@ module Chain_id : sig val decode_le : bytes -> chain_id val decode_be : bytes -> chain_id + + val compare : chain_id -> chain_id -> int end type chain_family = EVM | Michelson diff --git a/etherlink/bin_node/lib_dev/kernel_config.ml b/etherlink/bin_node/lib_dev/kernel_config.ml index 6edeb50cb087cc3b710690f15a33b4fb634850a2..195aff7dd4aa2f4c335c0a3924be574f4b563eb2 100644 --- a/etherlink/bin_node/lib_dev/kernel_config.ml +++ b/etherlink/bin_node/lib_dev/kernel_config.ml @@ -37,6 +37,40 @@ let le_int64_bytes i = Bytes.set_int64_le b 0 (Int64.of_string i) ; String.of_bytes b +module ChainSet = Set.Make (struct + type t = Ethereum_types.chain_id + + let compare = Ethereum_types.Chain_id.compare +end) + +let all_duplicate_chain_ids ~l2_chain_ids = + let rec aux_same answer seen = function + | [] -> answer + | chain_id :: tl when ChainSet.mem chain_id seen -> + aux_same (ChainSet.add chain_id answer) seen tl + | chain_id :: tl -> aux_same answer (ChainSet.add chain_id seen) tl + in + aux_same ChainSet.empty ChainSet.empty l2_chain_ids + +(* This code comes from etherlink/bin_node/config/configuration.ml *) +let warn = + Format.kasprintf @@ fun s -> + let reset = Pretty_printing.add_ansi_marking Format.err_formatter in + Format.eprintf "@{[Warning] %s@}@." s ; + reset () + +let check_for_duplicate ~l2_chain_ids = + let duplicate_chain_ids = all_duplicate_chain_ids ~l2_chain_ids in + if not (ChainSet.is_empty duplicate_chain_ids) then + warn + "The following chain ids have been provided more than once: %a. Chain \ + IDs must be unique." + (Format.pp_print_list + ~pp_sep:(fun ppf () -> Format.fprintf ppf ", ") + (fun ppf chain_id -> + Format.fprintf ppf "%s" (Ethereum_types.Chain_id.to_string chain_id))) + (ChainSet.elements duplicate_chain_ids) + (* When splitting the path given in argument, their should be empty string at the start/end of the list *) @@ -114,14 +148,15 @@ let make_l2 ~boostrap_balance ?bootstrap_accounts ?minimum_base_fee_per_gas in Installer_config.to_file (config_instrs @ world_state_instrs) ~output -let make ~mainnet_compat ~boostrap_balance ?bootstrap_accounts ?kernel_root_hash - ?chain_id ?sequencer ?delayed_bridge ?ticketer ?admin ?sequencer_governance - ?kernel_governance ?kernel_security_governance ?minimum_base_fee_per_gas - ?da_fee_per_byte ?delayed_inbox_timeout ?delayed_inbox_min_levels - ?sequencer_pool_address ?maximum_allowed_ticks ?maximum_gas_per_transaction - ?max_blueprint_lookahead_in_seconds ?remove_whitelist ?enable_fa_bridge - ?enable_dal ?dal_slots ?enable_fast_withdrawal ?enable_multichain - ?set_account_code ?max_delayed_inbox_blueprint_length ~output () = +let make ~mainnet_compat ~boostrap_balance ?l2_chain_ids ?bootstrap_accounts + ?kernel_root_hash ?chain_id ?sequencer ?delayed_bridge ?ticketer ?admin + ?sequencer_governance ?kernel_governance ?kernel_security_governance + ?minimum_base_fee_per_gas ?da_fee_per_byte ?delayed_inbox_timeout + ?delayed_inbox_min_levels ?sequencer_pool_address ?maximum_allowed_ticks + ?maximum_gas_per_transaction ?max_blueprint_lookahead_in_seconds + ?remove_whitelist ?enable_fa_bridge ?enable_dal ?dal_slots + ?enable_fast_withdrawal ?enable_multichain ?set_account_code + ?max_delayed_inbox_blueprint_length ~output () = let bootstrap_accounts = match bootstrap_accounts with | None -> [] @@ -155,6 +190,24 @@ let make ~mainnet_compat ~boostrap_balance ?bootstrap_accounts ?kernel_root_hash |> Seq.map (fun s -> Char.chr (int_of_string s)) |> String.of_seq in + let chain_ids_instr = + match l2_chain_ids with + | None -> [] + | Some l2_chain_ids -> + let open Rlp in + check_for_duplicate ~l2_chain_ids ; + let chain_ids = + List.map + (fun chain_id -> + let chain_id = Ethereum_types.Chain_id.to_string chain_id in + Value (Bytes.of_string chain_id)) + l2_chain_ids + in + let encoded_chain_ids = + Rlp.encode (List chain_ids) |> Bytes.to_string + in + make_instr (Some ("chain_ids", encoded_chain_ids)) + in let instrs = (if mainnet_compat then make_instr ticketer else @@ -198,5 +251,6 @@ let make ~mainnet_compat ~boostrap_balance ?bootstrap_accounts ?kernel_root_hash @ make_instr ~convert:(fun s -> Ethereum_types.u16_to_bytes (int_of_string s)) max_delayed_inbox_blueprint_length + @ chain_ids_instr in Installer_config.to_file instrs ~output diff --git a/etherlink/bin_node/lib_dev/kernel_config.mli b/etherlink/bin_node/lib_dev/kernel_config.mli index 49684d5484245bcc4049de6274d29178b0c4b9bd..dc0d17e676a2bfc571af60903fd653ae050a8148 100644 --- a/etherlink/bin_node/lib_dev/kernel_config.mli +++ b/etherlink/bin_node/lib_dev/kernel_config.mli @@ -12,6 +12,7 @@ val make : mainnet_compat:bool -> boostrap_balance:Ethereum_types.NonceMap.key -> + ?l2_chain_ids:Ethereum_types.chain_id list -> ?bootstrap_accounts:string list -> ?kernel_root_hash:string * string -> ?chain_id:string * string -> diff --git a/etherlink/bin_node/main.ml b/etherlink/bin_node/main.ml index dd8bf2c97b884502954b8dcb64cb500b2a9a925d..c08f02254c4a8a749df4c4a92544996492d9eb43 100644 --- a/etherlink/bin_node/main.ml +++ b/etherlink/bin_node/main.ml @@ -1877,6 +1877,15 @@ let make_l2_kernel_config_command = ~output ()) +let l2_chain_ids_arg = + let open Evm_node_lib_dev_encoding in + Tezos_clic.multiple_arg + ~long:"l2-chain-id" + ~doc:"specify one of the chain ids in the kernel, can be used several times" + ~placeholder:"1" + @@ Tezos_clic.parameter (fun _ chain_id -> + Lwt.return_ok @@ Ethereum_types.Chain_id.of_string_exn chain_id) + let make_kernel_config_command = let open Tezos_clic in let open Lwt_result_syntax in @@ -1924,8 +1933,9 @@ let make_kernel_config_command = (config_key_flag ~name:"enable_fa_bridge") (config_key_flag ~name:"enable_dal") (config_key_arg ~name:"dal_slots" ~placeholder:"0,1,4,6,...")) - (args3 + (args4 (config_key_flag ~name:"enable_multichain") + l2_chain_ids_arg (config_key_arg ~name:"max_delayed_inbox_blueprint_length" ~placeholder:"1000") @@ -1962,12 +1972,14 @@ let make_kernel_config_command = enable_dal, dal_slots ), ( enable_multichain, + l2_chain_ids, max_delayed_inbox_blueprint_length, enable_fast_withdrawal ) ) output () -> Evm_node_lib_dev.Kernel_config.make ~mainnet_compat + ?l2_chain_ids ?kernel_root_hash ?chain_id ?sequencer diff --git a/etherlink/tezt/lib/evm_node.ml b/etherlink/tezt/lib/evm_node.ml index 3a1b9a7a3f94fdb02ff67782f98bff554f66ba46..e6ab1f36731770f8baf6bc9ceee0473816c5ec66 100644 --- a/etherlink/tezt/lib/evm_node.ml +++ b/etherlink/tezt/lib/evm_node.ml @@ -1629,14 +1629,14 @@ let wait_termination (evm_node : t) = let ten_years_in_seconds = 3600 * 24 * 365 * 10 |> Int64.of_int -let make_kernel_installer_config ?max_delayed_inbox_blueprint_length - ?(mainnet_compat = false) ?(remove_whitelist = false) ?kernel_root_hash - ?chain_id ?bootstrap_balance ?bootstrap_accounts ?sequencer ?delayed_bridge - ?ticketer ?administrator ?sequencer_governance ?kernel_governance - ?kernel_security_governance ?minimum_base_fee_per_gas - ?(da_fee_per_byte = Wei.zero) ?delayed_inbox_timeout - ?delayed_inbox_min_levels ?sequencer_pool_address ?maximum_allowed_ticks - ?maximum_gas_per_transaction +let make_kernel_installer_config ?(l2_chain_ids = []) + ?max_delayed_inbox_blueprint_length ?(mainnet_compat = false) + ?(remove_whitelist = false) ?kernel_root_hash ?chain_id ?bootstrap_balance + ?bootstrap_accounts ?sequencer ?delayed_bridge ?ticketer ?administrator + ?sequencer_governance ?kernel_governance ?kernel_security_governance + ?minimum_base_fee_per_gas ?(da_fee_per_byte = Wei.zero) + ?delayed_inbox_timeout ?delayed_inbox_min_levels ?sequencer_pool_address + ?maximum_allowed_ticks ?maximum_gas_per_transaction ?(max_blueprint_lookahead_in_seconds = ten_years_in_seconds) ?(set_account_code = []) ?(enable_fa_bridge = false) ?(enable_dal = false) ?dal_slots ?(enable_fast_withdrawal = false) ?(enable_multichain = false) @@ -1648,6 +1648,12 @@ let make_kernel_installer_config ?max_delayed_inbox_blueprint_length ["--set-code"; Format.sprintf "%s,%s" address code]) set_account_code in + let l2_chain_ids = + List.flatten + @@ List.map + (fun l2_chain_id -> ["--l2-chain-id"; string_of_int l2_chain_id]) + l2_chain_ids + in let cmd = ["make"; "kernel"; "installer"; "config"; output] @ Cli_arg.optional_arg @@ -1658,6 +1664,7 @@ let make_kernel_installer_config ?max_delayed_inbox_blueprint_length @ Cli_arg.optional_switch "remove-whitelist" remove_whitelist @ Cli_arg.optional_arg "kernel-root-hash" Fun.id kernel_root_hash @ Cli_arg.optional_arg "chain-id" string_of_int chain_id + @ l2_chain_ids @ Cli_arg.optional_arg "sequencer" Fun.id sequencer @ Cli_arg.optional_arg "delayed-bridge" Fun.id delayed_bridge @ Cli_arg.optional_arg "ticketer" Fun.id ticketer diff --git a/etherlink/tezt/lib/evm_node.mli b/etherlink/tezt/lib/evm_node.mli index 9fbd528bdd7d7add77990589590be89d9551e731..44b710238a57ad3e9b5f7de0da475367b3251562 100644 --- a/etherlink/tezt/lib/evm_node.mli +++ b/etherlink/tezt/lib/evm_node.mli @@ -604,6 +604,7 @@ val make_l2_kernel_installer_config : (** [make_kernel_installer_config ~output ()] create the config needed for the evm kernel used by the installer *) val make_kernel_installer_config : + ?l2_chain_ids:int list -> ?max_delayed_inbox_blueprint_length:int -> ?mainnet_compat:bool -> ?remove_whitelist:bool -> diff --git a/etherlink/tezt/tests/evm_sequencer.ml b/etherlink/tezt/tests/evm_sequencer.ml index a0122b01114c6181030ce3178037580d68d1743d..2c891607d5d789fe3bd69906c898b3397e514b8b 100644 --- a/etherlink/tezt/tests/evm_sequencer.ml +++ b/etherlink/tezt/tests/evm_sequencer.ml @@ -372,10 +372,12 @@ let test_make_l2_kernel_installer_config chain_family = let* node, client = setup_l1 protocol in (* Random chain id, let's not take one that could have been set by default (1, 42, 1337) *) - let chain_id = 2988 in + let chain_id_1 = 2988 in + let chain_id_2 = 4571 in - (* Configuration files for an l2 chain and for the rollup *) - let l2_config = Temp.file "l2-chain-config.yaml" in + (* Configuration files for the two l2 chains and for the rollup *) + let l2_config_1 = Temp.file "l2-chain-1-config.yaml" in + let l2_config_2 = Temp.file "l2-chain-2-config.yaml" in let rollup_config = Temp.file "rollup-chain-config.yaml" in (* Argument for the l2 chain, a bootstrap account and a new world_state_path *) @@ -383,17 +385,26 @@ let test_make_l2_kernel_installer_config chain_family = let address = Eth_account.bootstrap_accounts.(0).address in let*! () = Evm_node.make_l2_kernel_installer_config - ~chain_id + ~chain_id:chain_id_1 ~chain_family ~world_state_path ~bootstrap_accounts:[address] - ~output:l2_config + ~output:l2_config_1 + () + in + let*! () = + Evm_node.make_l2_kernel_installer_config + ~chain_id:chain_id_2 + ~chain_family + ~bootstrap_accounts:[address] + ~output:l2_config_2 () in let*! () = Evm_node.make_kernel_installer_config (* No need for a real sequencer governance *) ~sequencer_governance:"KT1" + ~l2_chain_ids:[chain_id_1; chain_id_2] ~output:rollup_config () in @@ -413,7 +424,7 @@ let test_make_l2_kernel_installer_config chain_family = prepare_installer_kernel_with_multiple_setup_file ~output:(Temp.file "kernel.hex") ~preimages_dir - ~configs:[rollup_config; l2_config] + ~configs:[rollup_config; l2_config_1; l2_config_2] (Uses.path kernel) in let* sc_rollup_address = @@ -455,7 +466,12 @@ let test_make_l2_kernel_installer_config chain_family = in (* Verify the chain_family is properly set *) - let*@ family_value = Rpc.get_chain_family sequencer chain_id in + let*@ family_value = Rpc.get_chain_family sequencer chain_id_1 in + Check.((family_value = chain_family) string) + ~error_msg:"Expected chain_family to be %R, got %L" ; + + (* Verify the chain_family is properly set *) + let*@ family_value = Rpc.get_chain_family sequencer chain_id_2 in Check.((family_value = chain_family) string) ~error_msg:"Expected chain_family to be %R, got %L" ; @@ -465,15 +481,51 @@ let test_make_l2_kernel_installer_config chain_family = let address_balance = world_state_path ^ "eth_accounts/" ^ address_in_durable ^ "/balance" in - let*@ rpc = Rpc.state_value sequencer address_balance in - match rpc with - | None -> + let*@ rpc_balance = Rpc.state_value sequencer address_balance in + let* _balance = + match rpc_balance with + | None -> + Test.fail + ~__LOC__ + "There should be a value at %s setup by the \ + make_l2_kernel_installer_config" + address_balance + | Some balance -> return balance + in + let chain_ids = "/evm/chain_ids" in + let*@ rpc_chain_ids = Rpc.state_value sequencer chain_ids in + let* chain_ids = + match rpc_chain_ids with + | None -> + Test.fail + ~__LOC__ + "There should be a value at %s setup by the \ + make_kernel_installer_config" + chain_ids + | Some chain_ids -> return chain_ids + in + let chain_ids_bytes = Hex.to_bytes (`Hex chain_ids) in + + match Evm_node_lib_dev_encoding.Rlp.decode chain_ids_bytes with + | Ok + Evm_node_lib_dev_encoding.Rlp.( + List [Value rlp_chain_id_1; Value rlp_chain_id_2]) -> + let str_chain_1 = Bytes.to_string rlp_chain_id_1 in + Check.(string_of_int chain_id_1 = str_chain_1) + Check.string + ~error_msg: + "Unexpected chain id from durable storage, expected: %L, got %R." ; + let str_chain_2 = Bytes.to_string rlp_chain_id_2 in + Check.(string_of_int chain_id_2 = str_chain_2) + Check.string + ~error_msg: + "Unexpected chain id from durable storage, expected: %L, got %R." ; + return () + | _ -> Test.fail ~__LOC__ - "There should be a value at %s setup by the \ - make_l2_kernel_installer_config" - address_balance - | Some _bootstrap_value -> return () + "Unexpected value decoded at path %s in durable storage" + chain_ids (* The test uses a very specific setup, so it doesn't use general helpers. *) let test_observer_reset = 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 807149a4b3c7c3bb3f0ccfa39bb20fee3e82fc38..b3b2bca0103101b304d142304e656fd8c1ec57e0 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 @@ -478,7 +478,7 @@ Miscellaneous commands: [--bootstrap-account <0x...>] [--set-code <0x...,0x....>] [--enable-fa-bridge] [--enable-dal] [--dal-slots <0,1,4,6,...>] - [--enable-multichain] + [--enable-multichain] [--l2-chain-id <1>] [--max-delayed-inbox-blueprint-length <1000>] [--enable-fast-withdrawal] Transforms the JSON list of instructions to a RLP list @@ -509,6 +509,7 @@ Miscellaneous commands: --enable-dal: enable flag enable_dal in the installer config --dal-slots <0,1,4,6,...>: value for dal_slots in the installer config --enable-multichain: enable flag enable_multichain in the installer config + --l2-chain-id <1>: specify one of the chain ids in the kernel, can be used several times --max-delayed-inbox-blueprint-length <1000>: value for max_delayed_inbox_blueprint_length in the installer config --enable-fast-withdrawal: enable flag enable_fast_withdrawal in the installer config