diff --git a/etherlink/bin_floodgate/craft.ml b/etherlink/bin_floodgate/craft.ml index 3e8d366aafba003bb44af1ff8c3b6eb597e85193..9127660868defb02f5255db117f7c8ed0d4ccbe4 100644 --- a/etherlink/bin_floodgate/craft.ml +++ b/etherlink/bin_floodgate/craft.ml @@ -34,7 +34,7 @@ let prepare_and_forge_tx ?to_ ?data ~gas_limit ~base_fee_per_gas ~chain_id let transfer ?nonce ?to_ ?data ~value ~gas_limit ~infos ~from () = let nonce = Option.value nonce ~default:from.Account.nonce |> Z.to_int in - let (Ethereum_types.Chain_id chain_id) = infos.Network_info.chain_id in + let (L2_types.Chain_id chain_id) = infos.Network_info.chain_id in let txn = prepare_and_forge_tx ?to_ diff --git a/etherlink/bin_floodgate/floodgate_events.ml b/etherlink/bin_floodgate/floodgate_events.ml index db563167e2a33d6ab7fa2c3d24a0298b32a27df7..b3444eb41c66ec48562e3e69e75f6921f4adbea5 100644 --- a/etherlink/bin_floodgate/floodgate_events.ml +++ b/etherlink/bin_floodgate/floodgate_events.ml @@ -28,7 +28,7 @@ let is_ready = {base_fee_per_gas})" ~level:Notice ~pp2:pp_eth - ("chain_id", Ethereum_types.Chain_id.encoding) + ("chain_id", L2_types.Chain_id.encoding) ("base_fee_per_gas", Data_encoding.n) let tx_queue_is_ready = diff --git a/etherlink/bin_floodgate/floodgate_events.mli b/etherlink/bin_floodgate/floodgate_events.mli index ce4a59524673439a825ae99bf225fd45f76dbd74..0a4791f74690436afe7ed00f401993a339c39eab 100644 --- a/etherlink/bin_floodgate/floodgate_events.mli +++ b/etherlink/bin_floodgate/floodgate_events.mli @@ -8,7 +8,7 @@ (** [is_ready chain_id base_fee_per_gas] advertises that Floodgate has started and is ready to spam. *) -val is_ready : Ethereum_types.chain_id -> Z.t -> unit Lwt.t +val is_ready : L2_types.chain_id -> Z.t -> unit Lwt.t (** [tx_queue_is_ready ()] advertises that the [Tx_queue] is ready to receive transactions. *) diff --git a/etherlink/bin_floodgate/network_info.ml b/etherlink/bin_floodgate/network_info.ml index 728004ad16fa654e48bba6446b280204c825b20c..dc23b9c265f3c87c56c41f9db7a02b81970ae88e 100644 --- a/etherlink/bin_floodgate/network_info.ml +++ b/etherlink/bin_floodgate/network_info.ml @@ -6,7 +6,7 @@ (* *) (*****************************************************************************) -type t = {chain_id : Ethereum_types.chain_id; base_fee_per_gas : Z.t} +type t = {chain_id : L2_types.chain_id; base_fee_per_gas : Z.t} let get_chain_id ~evm_node_endpoint = let open Lwt_result_syntax in diff --git a/etherlink/bin_floodgate/network_info.mli b/etherlink/bin_floodgate/network_info.mli index 87c921633fc234e1fe61208da490d194ff495503..eb332765ed13b43fa85f8fbff685eb8139324236 100644 --- a/etherlink/bin_floodgate/network_info.mli +++ b/etherlink/bin_floodgate/network_info.mli @@ -6,7 +6,7 @@ (* *) (*****************************************************************************) -type t = {chain_id : Ethereum_types.chain_id; base_fee_per_gas : Z.t} +type t = {chain_id : L2_types.chain_id; base_fee_per_gas : Z.t} val fetch : rpc_endpoint:Uri.t -> base_fee_factor:float -> t tzresult Lwt.t diff --git a/etherlink/bin_node/config/configuration.ml b/etherlink/bin_node/config/configuration.ml index eb1a95fa68df49780c127e1a5742393d00cd1f45..03ca84194df85016d1a3c7f925df87a10c3f6ea8 100644 --- a/etherlink/bin_node/config/configuration.ml +++ b/etherlink/bin_node/config/configuration.ml @@ -61,17 +61,17 @@ type rpc_server = Resto | Dream type monitor_websocket_heartbeat = {ping_interval : float; ping_timeout : float} let chain_id network = - Ethereum_types.Chain_id + L2_types.Chain_id (Z.of_int (match network with Mainnet -> 0xa729 | Testnet -> 0x1f47b)) -let chain_id_encoding : Ethereum_types.chain_id Data_encoding.t = - let open Ethereum_types in +let chain_id_encoding : L2_types.chain_id Data_encoding.t = + let open L2_types in let open Data_encoding in conv (fun (Chain_id z) -> z) (fun z -> Chain_id z) z type l2_chain = { - chain_id : Ethereum_types.chain_id; - chain_family : Ethereum_types.chain_family; + chain_id : L2_types.chain_id; + chain_family : L2_types.chain_family; } type tx_queue = { @@ -901,7 +901,7 @@ let opt_monitor_websocket_heartbeat_encoding = ] let l2_chain_encoding : l2_chain Data_encoding.t = - let open Ethereum_types in + let open L2_types in let open Data_encoding in conv (fun {chain_id; chain_family} -> (chain_id, chain_family)) diff --git a/etherlink/bin_node/config/configuration.mli b/etherlink/bin_node/config/configuration.mli index 7efaa1f09fab23d8d6b23ea51a689d7d59d2c238..bf0f7f62548f2f92f96e1ad483a06cbc3858deba 100644 --- a/etherlink/bin_node/config/configuration.mli +++ b/etherlink/bin_node/config/configuration.mli @@ -86,11 +86,11 @@ type rpc_server = (** Parameters for monitoring websocket connection heartbeats. *) type monitor_websocket_heartbeat = {ping_interval : float; ping_timeout : float} -val chain_id : supported_network -> Ethereum_types.chain_id +val chain_id : supported_network -> L2_types.chain_id type l2_chain = { - chain_id : Ethereum_types.chain_id; - chain_family : Ethereum_types.chain_family; + chain_id : L2_types.chain_id; + chain_family : L2_types.chain_family; } type tx_queue = { diff --git a/etherlink/bin_node/lib_dev/blueprint_events.ml b/etherlink/bin_node/lib_dev/blueprint_events.ml index 99dac6f0ffe97a91cf8f85ccd831b349efa16a95..ba5b234e5dd2ac2c104ca92a43b178e5f6d9467d 100644 --- a/etherlink/bin_node/lib_dev/blueprint_events.ml +++ b/etherlink/bin_node/lib_dev/blueprint_events.ml @@ -165,18 +165,30 @@ let blueprint_injection_failed level trace = let blueprint_applied block process_time = let open Ethereum_types in - let count_txs = function - | TxHash l -> List.length l - | TxFull l -> List.length l - in - emit - blueprint_application - ( Qty.to_z block.number, - block.timestamp |> Qty.to_z |> Z.to_int64 |> Time.Protocol.of_seconds, - count_txs block.transactions, - Qty.to_z block.gasUsed, - block.hash, - process_time ) + match block with + | L2_types.Eth block -> + let count_txs = function + | TxHash l -> List.length l + | TxFull l -> List.length l + in + emit + blueprint_application + ( Qty.to_z block.number, + block.timestamp |> Qty.to_z |> Z.to_int64 |> Time.Protocol.of_seconds, + count_txs block.transactions, + Qty.to_z block.gasUsed, + block.hash, + process_time ) + | Tez block -> + (* TODO: https://gitlab.com/tezos/tezos/-/issues/7866 *) + emit + blueprint_application + ( Qty.to_z block.number, + block.timestamp |> Qty.to_z |> Z.to_int64 |> Time.Protocol.of_seconds, + 0, + Z.zero, + block.hash, + process_time ) let invalid_blueprint_produced level = emit invalid_blueprint_produced level diff --git a/etherlink/bin_node/lib_dev/blueprint_events.mli b/etherlink/bin_node/lib_dev/blueprint_events.mli index 79343b727710538702785649dfbf9ffd927fc522..a33fccc37eab7592303dd3a8cd81beeeb6cd0724 100644 --- a/etherlink/bin_node/lib_dev/blueprint_events.mli +++ b/etherlink/bin_node/lib_dev/blueprint_events.mli @@ -21,7 +21,7 @@ val publisher_shutdown : unit -> unit Lwt.t leading to [block] has been applied in [duration] time onto the local state. *) val blueprint_applied : - 'transaction_object Ethereum_types.block -> Time.System.Span.t -> unit Lwt.t + 'transaction_object L2_types.block -> Time.System.Span.t -> unit Lwt.t (** [blueprint_injected level] advertizes that a blueprint for level [level] has been forwarded to a rollup node *) diff --git a/etherlink/bin_node/lib_dev/durable_storage.ml b/etherlink/bin_node/lib_dev/durable_storage.ml index 122cfeaa2e3852ed21dfac9a54c03a70b78cc1cc..233bf3a01ec518a239d41e2794d6abae4bf7bed6 100644 --- a/etherlink/bin_node/lib_dev/durable_storage.ml +++ b/etherlink/bin_node/lib_dev/durable_storage.ml @@ -274,32 +274,32 @@ let chain_id read = inspect_durable_and_decode read Durable_storage_path.chain_id - Chain_id.decode_le + L2_types.Chain_id.decode_le let l2_minimum_base_fee_per_gas read chain_id = inspect_durable_and_decode read (Durable_storage_path.Chain_configuration.minimum_base_fee_per_gas chain_id) - Ethereum_types.decode_z_le + Helpers.decode_z_le let l2_da_fee_per_byte read chain_id = inspect_durable_and_decode read (Durable_storage_path.Chain_configuration.da_fee_per_byte chain_id) - Ethereum_types.decode_z_le + Helpers.decode_z_le let l2_maximum_gas_per_transaction read chain_id = inspect_durable_and_decode read (Durable_storage_path.Chain_configuration.maximum_gas_per_transaction chain_id) - Ethereum_types.decode_z_le + Helpers.decode_z_le let chain_family read chain_id = inspect_durable_and_decode read (Durable_storage_path.Chain_configuration.chain_family chain_id) - (fun x -> Ethereum_types.Chain_family.of_string_exn (Bytes.to_string x)) + (fun x -> L2_types.Chain_family.of_string_exn (Bytes.to_string x)) let world_state read chain_id = inspect_durable_and_decode diff --git a/etherlink/bin_node/lib_dev/durable_storage_path.ml b/etherlink/bin_node/lib_dev/durable_storage_path.ml index 0e20eb38124b983b3bdf3066dbdf3bc592827d28..d61fee12a473f06771c5bb2a8cbe24926e23d3e2 100644 --- a/etherlink/bin_node/lib_dev/durable_storage_path.ml +++ b/etherlink/bin_node/lib_dev/durable_storage_path.ml @@ -227,6 +227,8 @@ module Trace = struct end module Chain_configuration = struct + open L2_types + let root chain_id = EVM.make "/chain_configurations/" ^ Chain_id.to_string chain_id diff --git a/etherlink/bin_node/lib_dev/durable_storage_path.mli b/etherlink/bin_node/lib_dev/durable_storage_path.mli index 43d17fabefae1966de13613482df7ba251756821..7c7d48b2c55c17878776fac093b84f0d24706691 100644 --- a/etherlink/bin_node/lib_dev/durable_storage_path.mli +++ b/etherlink/bin_node/lib_dev/durable_storage_path.mli @@ -162,15 +162,15 @@ module Trace : sig end module Chain_configuration : sig - val minimum_base_fee_per_gas : Ethereum_types.chain_id -> path + val minimum_base_fee_per_gas : L2_types.chain_id -> path - val da_fee_per_byte : Ethereum_types.chain_id -> path + val da_fee_per_byte : L2_types.chain_id -> path - val maximum_gas_per_transaction : Ethereum_types.chain_id -> path + val maximum_gas_per_transaction : L2_types.chain_id -> path - val chain_family : Ethereum_types.chain_id -> path + val chain_family : L2_types.chain_id -> path - val world_state : Ethereum_types.chain_id -> path + val world_state : L2_types.chain_id -> path end module Feature_flags : sig diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml index 76b4dc8c30edfca5b14ea5047ff6626b539fac39..d8f07bd246007aed0bffde2121bc2cdf8cbbdcae 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml @@ -105,66 +105,14 @@ end let quantity_of_z z = Qty z -let z_to_hexa = Z.format "#x" - let quantity_encoding = Data_encoding.conv - (fun (Qty q) -> z_to_hexa q) + (fun (Qty q) -> Helpers.z_to_hexa q) (fun q -> Qty (Z.of_string q)) Data_encoding.string let pp_quantity fmt (Qty q) = Z.pp_print fmt q -let decode_z_le bytes = Bytes.to_string bytes |> Z.of_bits - -let decode_z_be bytes = - Bytes.fold_left - (fun acc c -> - let open Z in - add (of_int (Char.code c)) (shift_left acc 8)) - Z.zero - bytes - -type chain_id = Chain_id of Z.t [@@ocaml.unboxed] - -module Chain_id = struct - let of_string_exn s = Chain_id (Z.of_string s) - - let to_string (Chain_id s) = Z.to_string s - - let encoding = - Data_encoding.conv - (fun (Chain_id c) -> z_to_hexa c) - of_string_exn - Data_encoding.string - - 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 - - let pp fmt (Chain_id cid) = - Format.fprintf fmt "Chain_id (%s)" (Z.to_string cid) -end - -type chain_family = EVM | Michelson - -module Chain_family = struct - let to_string = function EVM -> "EVM" | Michelson -> "Michelson" - - let of_string_exn s = - match String.lowercase_ascii s with - | "evm" -> EVM - | "michelson" -> Michelson - | _ -> invalid_arg "Chain_family.of_string" - - let encoding = - Data_encoding.string_enum [("EVM", EVM); ("Michelson", Michelson)] - - let pp fmt cf = Format.fprintf fmt "%s" (to_string cf) -end - type block_hash = Block_hash of hex [@@ocaml.unboxed] let pp_block_hash fmt (Block_hash (Hex h)) = Format.pp_print_string fmt h @@ -298,9 +246,9 @@ let decode_address bytes = Address (decode_hex bytes) let encode_address (Address address) = encode_hex address -let decode_number_le bytes = decode_z_le bytes |> quantity_of_z +let decode_number_le bytes = Helpers.decode_z_le bytes |> quantity_of_z -let decode_number_be bytes = decode_z_be bytes |> quantity_of_z +let decode_number_be bytes = Helpers.decode_z_be bytes |> quantity_of_z let decode_hash bytes = Hash (decode_hex bytes) diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli index 60f9810d3fa57cfce3d86e2b292df3dcc44aaf9d..39a197cc9785588261d84eca0d69446215d77957 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli @@ -53,43 +53,6 @@ val hex_of_utf8 : string -> hex (** [hex_of_bytes] transforms the [bytes] to hexadecimal. *) val hex_of_bytes : bytes -> hex -type chain_id = Chain_id of Z.t [@@unboxed] - -module Chain_id : sig - val encoding : chain_id Data_encoding.t - - (** [of_string_exn hex] transforms a string to a chain id. - It raises an exception if the string is not an number - (base 10, hexa, binary, octal ...) *) - val of_string_exn : string -> chain_id - - val to_string : chain_id -> string - - val decode_le : bytes -> chain_id - - val decode_be : bytes -> chain_id - - val compare : chain_id -> chain_id -> int - - val pp : Format.formatter -> chain_id -> unit -end - -type chain_family = EVM | Michelson - -module Chain_family : sig - val encoding : chain_family Data_encoding.t - - (** [of_string_exn s] returns the chain family corresponding to the string [s]. - The comparison is case-insensitive, so ["Evm"], ["evm"], ["EVM"], etc. are all valid. - @raise Invalid_argument if [s] does not correspond to a recognized chain family. - *) - val of_string_exn : string -> chain_family - - val to_string : chain_family -> string - - val pp : Format.formatter -> chain_family -> unit -end - (** Ethereum block hash (32 bytes) *) type block_hash = Block_hash of hex [@@unboxed] @@ -126,8 +89,6 @@ val quantity_encoding : quantity Data_encoding.t val pp_quantity : Format.formatter -> quantity -> unit -val decode_z_le : bytes -> Z.t - val quantity_of_z : Z.t -> quantity val decode_number_le : bytes -> quantity diff --git a/etherlink/bin_node/lib_dev/encodings/helpers.ml b/etherlink/bin_node/lib_dev/encodings/helpers.ml index f15c0c01fcd7889448193a6a168a4b7e123b320c..ada56634223f837df2a4d9df6665517f95d344a0 100644 --- a/etherlink/bin_node/lib_dev/encodings/helpers.ml +++ b/etherlink/bin_node/lib_dev/encodings/helpers.ml @@ -5,11 +5,8 @@ (* Copyright (c) 2024 Functori *) (* *) (*****************************************************************************) - -open Ethereum_types - -let keccak256 (Hex s) = - let bytes = Hex.to_bytes_exn (`Hex s) in +let keccak256 s = + let bytes = Hex.to_bytes_exn s in Tezos_crypto.Hacl.Hash.Keccak_256.digest bytes let encode_i32_le i = @@ -37,6 +34,18 @@ let encoding_with_optional_last_param encoding second_param_encoding (fun t -> (t, default_second_param)); ] +let z_to_hexa = Z.format "#x" + +let decode_z_le bytes = Bytes.to_string bytes |> Z.of_bits + +let decode_z_be bytes = + Bytes.fold_left + (fun acc c -> + let open Z in + add (of_int (Char.code c)) (shift_left acc 8)) + Z.zero + bytes + (* A variation of List.fold_left where the function f returns an option. If f returns None, the fold stops and returns None. If f returns Some, the fold continues with the updated accumulator. diff --git a/etherlink/bin_node/lib_dev/encodings/l2_types.ml b/etherlink/bin_node/lib_dev/encodings/l2_types.ml new file mode 100644 index 0000000000000000000000000000000000000000..d4fac8bf6a6b0de4de4a97554f44432a9389ce77 --- /dev/null +++ b/etherlink/bin_node/lib_dev/encodings/l2_types.ml @@ -0,0 +1,89 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs *) +(* Copyright (c) 2023 Marigold *) +(* Copyright (c) 2024-2025 Functori *) +(* *) +(*****************************************************************************) + +type chain_id = Chain_id of Z.t [@@ocaml.unboxed] + +module Chain_id = struct + let of_string_exn s = Chain_id (Z.of_string s) + + let to_string (Chain_id s) = Z.to_string s + + let encoding = + Data_encoding.conv + (fun (Chain_id c) -> Helpers.z_to_hexa c) + of_string_exn + Data_encoding.string + + let decode_le bytes = Chain_id (Helpers.decode_z_le bytes) + + let decode_be bytes = Chain_id (Helpers.decode_z_be bytes) + + let compare (Chain_id c1) (Chain_id c2) = Z.compare c1 c2 + + let pp fmt (Chain_id cid) = + Format.fprintf fmt "Chain_id (%s)" (Z.to_string cid) +end + +type chain_family = EVM | Michelson + +module Chain_family = struct + let to_string = function EVM -> "EVM" | Michelson -> "Michelson" + + let of_string_exn s = + match String.lowercase_ascii s with + | "evm" -> EVM + | "michelson" -> Michelson + | _ -> invalid_arg "Chain_family.of_string" + + let encoding = + Data_encoding.string_enum [("EVM", EVM); ("Michelson", Michelson)] + + let pp fmt cf = Format.fprintf fmt "%s" (to_string cf) +end + +type 'a block = Eth of 'a Ethereum_types.block | Tez of Tezos_types.block + +let block_hash block = + match block with Eth block -> block.hash | Tez block -> block.hash + +let block_number block = + match block with Eth block -> block.number | Tez block -> block.number + +let block_number_of_transactions block = + match block with + | Eth block -> + let number_of_transactions = + match block.transactions with + | TxHash l -> List.length l + | TxFull l -> List.length l + in + number_of_transactions + | Tez _ -> 0 + +let block_parent block = + match block with Eth block -> block.parent | Tez block -> block.parent_hash + +let decode_block_hash ~chain_family bytes = + match chain_family with + | EVM -> Ethereum_types.decode_block_hash bytes + | Michelson -> Tezos_types.decode_block_hash bytes + +let genesis_parent_hash ~chain_family = + match chain_family with + | EVM -> Ethereum_types.genesis_parent_hash + | Michelson -> Tezos_types.genesis_parent_hash + +let block_from_bytes ~chain_family bytes = + match chain_family with + | EVM -> + let eth_block = Ethereum_types.block_from_rlp bytes in + Eth eth_block + | Michelson -> + let tez_block = Tezos_types.block_from_binary bytes in + Tez tez_block diff --git a/etherlink/bin_node/lib_dev/encodings/l2_types.mli b/etherlink/bin_node/lib_dev/encodings/l2_types.mli new file mode 100644 index 0000000000000000000000000000000000000000..c2d664f097ce3437a41a03e519e923cc4a5e73ce --- /dev/null +++ b/etherlink/bin_node/lib_dev/encodings/l2_types.mli @@ -0,0 +1,65 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs *) +(* Copyright (c) 2023 Marigold *) +(* Copyright (c) 2024-2025 Functori *) +(* *) +(*****************************************************************************) + +type chain_id = Chain_id of Z.t [@@unboxed] + +module Chain_id : sig + val encoding : chain_id Data_encoding.t + + (** [of_string_exn hex] transforms a string to a chain id. + It raises an exception if the string is not an number + (base 10, hexa, binary, octal ...) *) + val of_string_exn : string -> chain_id + + val to_string : chain_id -> string + + val decode_le : bytes -> chain_id + + val decode_be : bytes -> chain_id + + val compare : chain_id -> chain_id -> int + + val pp : Format.formatter -> chain_id -> unit +end + +type chain_family = EVM | Michelson + +module Chain_family : sig + val encoding : chain_family Data_encoding.t + + (** [of_string_exn s] returns the chain family corresponding to the string [s]. + The comparison is case-insensitive, so ["Evm"], ["evm"], ["EVM"], etc. are all valid. + @raise Invalid_argument if [s] does not correspond to a recognized chain family. + *) + val of_string_exn : string -> chain_family + + val to_string : chain_family -> string + + val pp : Format.formatter -> chain_family -> unit +end + +type 'a block = Eth of 'a Ethereum_types.block | Tez of Tezos_types.block + +val block_hash : 'a block -> Ethereum_types.block_hash + +val block_number : 'a block -> Ethereum_types.quantity + +val block_number_of_transactions : 'a block -> int + +val block_parent : 'a block -> Ethereum_types.block_hash + +val decode_block_hash : + chain_family:chain_family -> bytes -> Ethereum_types.block_hash + +val genesis_parent_hash : chain_family:chain_family -> Ethereum_types.block_hash + +val block_from_bytes : + chain_family:chain_family -> + bytes -> + Ethereum_types.legacy_transaction_object block diff --git a/etherlink/bin_node/lib_dev/encodings/tezos_types.ml b/etherlink/bin_node/lib_dev/encodings/tezos_types.ml new file mode 100644 index 0000000000000000000000000000000000000000..6c5403e5e2fc38c4145a4b827bec807e92026809 --- /dev/null +++ b/etherlink/bin_node/lib_dev/encodings/tezos_types.ml @@ -0,0 +1,42 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Functori *) +(* *) +(*****************************************************************************) + +(* WIP: Minimal Block Tezos (should be equal to shell_block header) *) +type block = { + number : Ethereum_types.quantity; + hash : Ethereum_types.block_hash; + timestamp : Ethereum_types.quantity; + parent_hash : Ethereum_types.block_hash; +} + +let decode_block_hash = Ethereum_types.decode_block_hash + +let genesis_parent_hash = + (* This Hex comes from this b58 hash 'BLockGenesisGenesisGenesisGenesisGenesis1db77eJNeJ9' *) + (* That is the ghostnet genesis hash according to 'devtools/get_contracts/config.ml' *) + Ethereum_types.Block_hash + (Hex "8fcf233671b6a04fcf679d2a381c2544ea6c1ea29ba6157776ed8423e7c02934") + +(* This function may be replaced in the future by an already existing function *) +(* When Tezos block will be complete *) +let block_from_binary bytes = + if Bytes.length bytes = 44 then ( + let number = Bytes.make 4 '\000' in + Bytes.blit bytes 0 number 0 4 ; + let number = Ethereum_types.Qty (Helpers.decode_z_be number) in + let previous_hash = Bytes.make 32 '\000' in + Bytes.blit bytes 4 previous_hash 0 32 ; + let parent = Ethereum_types.decode_block_hash previous_hash in + let timestamp = Bytes.make 8 '\000' in + Bytes.blit bytes 36 timestamp 0 8 ; + let timestamp = Ethereum_types.Qty (Helpers.decode_z_le timestamp) in + let block_hash = Block_hash.hash_bytes [bytes] in + let hash = + Ethereum_types.decode_block_hash (Block_hash.to_bytes block_hash) + in + {number; hash; timestamp; parent_hash = parent}) + else raise (Invalid_argument "Expected a string of length 44") diff --git a/etherlink/bin_node/lib_dev/encodings/tezos_types.mli b/etherlink/bin_node/lib_dev/encodings/tezos_types.mli new file mode 100644 index 0000000000000000000000000000000000000000..25a0c2f62add9fa5a2af99a3cea20f09ab7c42f7 --- /dev/null +++ b/etherlink/bin_node/lib_dev/encodings/tezos_types.mli @@ -0,0 +1,19 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Functori *) +(* *) +(*****************************************************************************) + +type block = { + number : Ethereum_types.quantity; + hash : Ethereum_types.block_hash; + timestamp : Ethereum_types.quantity; + parent_hash : Ethereum_types.block_hash; +} + +val decode_block_hash : bytes -> Ethereum_types.block_hash + +val genesis_parent_hash : Ethereum_types.block_hash + +val block_from_binary : bytes -> block diff --git a/etherlink/bin_node/lib_dev/encodings/tracer_types.ml b/etherlink/bin_node/lib_dev/encodings/tracer_types.ml index 57ef9340c3f7521de67892485f28ec5925ea8295..d050d17ac2e6df3195708b69c9e6873a863bb9e7 100644 --- a/etherlink/bin_node/lib_dev/encodings/tracer_types.ml +++ b/etherlink/bin_node/lib_dev/encodings/tracer_types.ml @@ -950,8 +950,8 @@ module CallTracer = struct } let solidity_revert_selector = - let error = Ethereum_types.hex_of_utf8 "Error(string)" in - let selector = Helpers.keccak256 error in + let (Hex error) = Ethereum_types.hex_of_utf8 "Error(string)" in + let selector = Helpers.keccak256 (`Hex error) in Bytes.sub selector 0 4 let logs_encoding = diff --git a/etherlink/bin_node/lib_dev/encodings/transaction.ml b/etherlink/bin_node/lib_dev/encodings/transaction.ml index c41a487fedc7472d3a67ba8db0fb1d57159db29d..8d65400f40e208d9a07677427b4cd71c33336fad 100644 --- a/etherlink/bin_node/lib_dev/encodings/transaction.ml +++ b/etherlink/bin_node/lib_dev/encodings/transaction.ml @@ -7,6 +7,7 @@ (*****************************************************************************) open Ethereum_types +open L2_types type transaction_type = Legacy | Eip2930 | Eip1559 diff --git a/etherlink/bin_node/lib_dev/ethbloom.ml b/etherlink/bin_node/lib_dev/ethbloom.ml index 179bf5f77a29bbf52ba45e4fe8a2ced42c143824..32007b6bac9a9987593c706d30aee472bf939337 100644 --- a/etherlink/bin_node/lib_dev/ethbloom.ml +++ b/etherlink/bin_node/lib_dev/ethbloom.ml @@ -21,8 +21,8 @@ module Bits = struct original_byte land (1 lsl (7 - Int.rem position 8)) != 0 end -let positions input = - let hash = Helpers.keccak256 input in +let positions (Ethereum_types.Hex input) = + let hash = Helpers.keccak256 (`Hex input) in let pos_for_idx idx = let hash_bytes = Bytes.sub hash idx 2 in let bit_to_set = Int.logand (Bytes.get_uint16_be hash_bytes 0) 0x07FF in diff --git a/etherlink/bin_node/lib_dev/evm_context.ml b/etherlink/bin_node/lib_dev/evm_context.ml index 4825ffb0568c8a536b655b5a294787577a07d2ce..360722d9b463d55d08b09eb8cfe321d4e281ded9 100644 --- a/etherlink/bin_node/lib_dev/evm_context.ml +++ b/etherlink/bin_node/lib_dev/evm_context.ml @@ -270,7 +270,7 @@ module State = struct ( store, context, Ethereum_types.Qty Z.zero, - Ethereum_types.genesis_parent_hash, + L2_types.genesis_parent_hash ~chain_family:EVM, Created ) let commit store (context : Irmin_context.rw) evm_state number = @@ -689,25 +689,27 @@ module State = struct match try_apply with | Apply_success {evm_state; block} -> + let block_number = L2_types.block_number block in + let block_hash = L2_types.block_hash block in let* () = if is_sequencer ctxt then return_unit else let* finalized_hash = - Evm_store.Pending_confirmations.find_with_level conn block.number + Evm_store.Pending_confirmations.find_with_level conn block_number in match finalized_hash with | None -> return_unit | Some expected_block_hash -> - if expected_block_hash = block.hash then + if expected_block_hash = block_hash then Evm_store.Pending_confirmations.delete_with_level conn - block.number + block_number else - let Ethereum_types.(Qty number) = block.number in + let Ethereum_types.(Qty number) = block_number in let*! () = Evm_events_follower_events.diverged - (number, expected_block_hash, block.hash) + (number, expected_block_hash, block_hash) in (* If the observer cannot reset to finalized level it must exit. *) @@ -716,7 +718,7 @@ module State = struct { level = number; expected_block_hash; - found_block_hash = Some block.hash; + found_block_hash = Some block_hash; must_exit = true; } in @@ -730,39 +732,58 @@ module State = struct { level = number; expected_block_hash; - found_block_hash = Some block.hash; + found_block_hash = Some block_hash; must_exit = false; }) in - - let number_of_transactions = - match block.transactions with - | TxHash l -> List.length l - | TxFull l -> List.length l + (* Set metrics for the block *) + let () = + match block with + | Eth block -> + let number_of_transactions = + match block.transactions with + | TxHash l -> List.length l + | TxFull l -> List.length l + in + Metrics.set_block + ~time_processed:!time_processed + ~transactions:number_of_transactions ; + Option.iter + (fun baseFeePerGas -> + baseFeePerGas |> Ethereum_types.Qty.to_z + |> Metrics.set_gas_price) + block.baseFeePerGas + | Tez _ -> + (* TODO: https://gitlab.com/tezos/tezos/-/issues/7866 *) + () in - Metrics.set_block - ~time_processed:!time_processed - ~transactions:number_of_transactions ; - Option.iter - (fun baseFeePerGas -> - baseFeePerGas |> Ethereum_types.Qty.to_z |> Metrics.set_gas_price) - block.baseFeePerGas ; let* () = Evm_store.Blueprints.store conn - {number = block.number; timestamp; payload} + {number = block_number; timestamp; payload} in let* evm_state, receipts = if not ctxt.legacy_block_storage then - let* receipts = store_block_unsafe conn evm_state block in + let* receipts = + match block with + | Eth block -> store_block_unsafe conn evm_state block + | Tez _ -> + (* TODO: https://gitlab.com/tezos/tezos/-/issues/7866 *) + Lwt_result.return [] + in let*! evm_state = Evm_state.clear_block_storage block evm_state in return (evm_state, receipts) else let*! receipts = - Durable_storage.block_receipts_of_block - (read_from_state evm_state) - block + match block with + | Eth block -> + Durable_storage.block_receipts_of_block + (read_from_state evm_state) + block + | Tez _ -> + (* TODO: https://gitlab.com/tezos/tezos/-/issues/7866 *) + Lwt.return [] in return (evm_state, receipts) in @@ -794,12 +815,21 @@ module State = struct let on_new_head ?split_info ctxt ~applied_upgrade evm_state context block blueprint_with_events = let open Lwt_syntax in + let block_hash = L2_types.block_hash block in let (Qty level) = ctxt.session.next_blueprint_number in ctxt.session.evm_state <- evm_state ; ctxt.session.context <- context ; ctxt.session.next_blueprint_number <- Qty (Z.succ level) ; - ctxt.session.current_block_hash <- Ethereum_types.(block.hash) ; - Lwt_watcher.notify head_watcher (Ethereum_types.Subscription.NewHeads block) ; + ctxt.session.current_block_hash <- block_hash ; + (* TODO: https://gitlab.com/tezos/tezos/-/issues/7865 *) + (match block with + | Eth block -> + Lwt_watcher.notify + head_watcher + (Ethereum_types.Subscription.NewHeads block) + | Tez _ -> + (* TODO: https://gitlab.com/tezos/tezos/-/issues/7866 *) + ()) ; Option.iter (fun (split_level, split_timestamp) -> ctxt.session.last_split_block <- Some (split_level, split_timestamp)) @@ -856,7 +886,7 @@ module State = struct return_unit let rec apply_blueprint ?(events = []) ctxt conn timestamp payload - delayed_transactions = + delayed_transactions : 'a L2_types.block tzresult Lwt.t = let open Lwt_result_syntax in Misc.with_timing_f_e Blueprint_events.blueprint_applied @@ fun () -> let* evm_state, context, current_block, applied_kernel_upgrade, split_info = @@ -876,8 +906,14 @@ module State = struct | _ -> None in - let*? current_block = - Transaction_object.reconstruct_block payload current_block + let* current_block = + match current_block with + | Eth block -> + let*? current_block = + Transaction_object.reconstruct_block payload block + in + return (L2_types.Eth current_block) + | Tez block -> return (L2_types.Tez block) in let*! () = @@ -1738,10 +1774,13 @@ module Handlers = struct delayed_transactions in let tx_hashes = - match block.transactions with - | TxHash tx_hashes -> List.to_seq tx_hashes - | TxFull tx_objects -> - List.to_seq tx_objects |> Seq.map Transaction_object.hash + match block with + | Eth block -> ( + match block.transactions with + | TxHash tx_hashes -> List.to_seq tx_hashes + | TxFull tx_objects -> + List.to_seq tx_objects |> Seq.map Transaction_object.hash) + | Tez _ -> Seq.empty in return tx_hashes | Last_known_L1_level -> ( diff --git a/etherlink/bin_node/lib_dev/evm_ro_context.ml b/etherlink/bin_node/lib_dev/evm_ro_context.ml index 2fd30406fea229544a45febdafd18d10edea49a5..7259149cd5d2805ce6aa23dfc23e4f3aaf4606a4 100644 --- a/etherlink/bin_node/lib_dev/evm_ro_context.ml +++ b/etherlink/bin_node/lib_dev/evm_ro_context.ml @@ -166,8 +166,8 @@ let get_irmin_hash_from_block_hash ctxt hash = in match res with | Some block_bytes -> - let block = Ethereum_types.block_from_rlp block_bytes in - get_irmin_hash_from_number ctxt block.number + let block = L2_types.block_from_bytes ~chain_family:EVM block_bytes in + get_irmin_hash_from_number ctxt (L2_types.block_number block) | None -> failwith "Unknown block %a" Ethereum_types.pp_block_hash hash let find_irmin_hash ctxt (block : Ethereum_types.Block_parameter.extended) = diff --git a/etherlink/bin_node/lib_dev/evm_ro_context.mli b/etherlink/bin_node/lib_dev/evm_ro_context.mli index f491b0edd7877adad39cd8b64e80c4018af8c9ed..24cb4b555a6767ae53f1c2e600f1a5dff96d4f90 100644 --- a/etherlink/bin_node/lib_dev/evm_ro_context.mli +++ b/etherlink/bin_node/lib_dev/evm_ro_context.mli @@ -36,7 +36,7 @@ val load : (** [read_chain_family chain_id] returns the chain_family associated to the chain_id passed on parameter. *) val read_chain_family : - t -> Ethereum_types.chain_id -> Ethereum_types.chain_family tzresult Lwt.t + t -> L2_types.chain_id -> L2_types.chain_family tzresult Lwt.t (** [read_enable_multichain_flag] reads the value of the `enable_multichain` feature_flag that enables multichain and tezos compatibility on the l2_node. *) diff --git a/etherlink/bin_node/lib_dev/evm_state.ml b/etherlink/bin_node/lib_dev/evm_state.ml index 0c71fc631e62a196eebdb2968470f3143f886bcc..f9dd9175e61c65552e701a5071a4b2267f025c1d 100644 --- a/etherlink/bin_node/lib_dev/evm_state.ml +++ b/etherlink/bin_node/lib_dev/evm_state.ml @@ -231,7 +231,7 @@ let current_block_hash evm_state = in match current_hash with | Some h -> return (decode_block_hash h) - | None -> return genesis_parent_hash + | None -> return (L2_types.genesis_parent_hash ~chain_family:EVM) (* The Fast Execution engine relies on Lwt_preemptive to execute Wasmer in dedicated worker threads (`Lwt_preemptive.detach`), while pushing to lwt @@ -304,7 +304,7 @@ let execute_and_inspect ?wasm_pvm_fallback ~data_dir ?wasm_entrypoint ~config type apply_result = | Apply_success of { evm_state : t; - block : Ethereum_types.legacy_transaction_object Ethereum_types.block; + block : Ethereum_types.legacy_transaction_object L2_types.block; } | Apply_failure @@ -334,12 +334,14 @@ let apply_blueprint ?wasm_pvm_fallback ?log_file ?profile ~data_dir ~config let*! bytes = inspect evm_state (Durable_storage_path.Block.by_hash block_hash) in - return (Option.map Ethereum_types.block_from_rlp bytes) + return (Option.map (L2_types.block_from_bytes ~chain_family:EVM) bytes) in match block with - | Some ({number = Qty after_height; _} as block) - when Z.(equal (succ before_height) after_height) -> - return (Apply_success {evm_state; block}) + | Some block -> + let (Qty after_height) = L2_types.block_number block in + if Z.(equal (succ before_height) after_height) then + return (Apply_success {evm_state; block}) + else return Apply_failure | _ -> return Apply_failure let delete ~kind evm_state path = @@ -398,11 +400,13 @@ let clear_block_storage block evm_state = necessary to produce the next block. Block production starts by reading the head to retrieve information such as parent block hash. *) - let (Qty number) = block.number in + let block_parent = L2_types.block_parent block in + let block_number = L2_types.block_number block in + let (Qty number) = block_number in (* Handles case (1.). *) let* evm_state = if number > Z.zero then - let pred_block_path = Durable_storage_path.Block.by_hash block.parent in + let pred_block_path = Durable_storage_path.Block.by_hash block_parent in delete ~kind:Value evm_state pred_block_path else return evm_state in diff --git a/etherlink/bin_node/lib_dev/evm_state.mli b/etherlink/bin_node/lib_dev/evm_state.mli index 2c538d8ff467cbe6c578bc15915ffeb71d1f833a..48e3c21b463a7b1dc820824f5f4fd5c3e3c27293 100644 --- a/etherlink/bin_node/lib_dev/evm_state.mli +++ b/etherlink/bin_node/lib_dev/evm_state.mli @@ -82,7 +82,7 @@ val current_block_hash : t -> Ethereum_types.block_hash tzresult Lwt.t type apply_result = | Apply_success of { evm_state : t; - block : Ethereum_types.legacy_transaction_object Ethereum_types.block; + block : Ethereum_types.legacy_transaction_object L2_types.block; } | Apply_failure @@ -134,8 +134,7 @@ val get_delayed_inbox_item : (**[clear_block_storage block state] removes the parent of [block], and all durable storage information stored for [block], if this function is called they need to be store elsewhere, mainly it consists in transactions. *) -val clear_block_storage : - 'transaction_object Ethereum_types.block -> t -> t Lwt.t +val clear_block_storage : 'transaction_object L2_types.block -> t -> t Lwt.t (** [storage_version tree] returns the current storage version set by the kernel. This storage version is used by the EVM node to determine whether a diff --git a/etherlink/bin_node/lib_dev/kernel_config.ml b/etherlink/bin_node/lib_dev/kernel_config.ml index 7f39c99524dce691c908f7fd98a22eb9f2ea6ae2..25e16c2e178350e475206fbc707b00499a8fcb35 100644 --- a/etherlink/bin_node/lib_dev/kernel_config.ml +++ b/etherlink/bin_node/lib_dev/kernel_config.ml @@ -40,9 +40,9 @@ let le_int64_bytes i = String.of_bytes b module ChainSet = Set.Make (struct - type t = Ethereum_types.chain_id + type t = L2_types.chain_id - let compare = Ethereum_types.Chain_id.compare + let compare = L2_types.Chain_id.compare end) let all_duplicate_chain_ids ~l2_chain_ids = @@ -70,7 +70,7 @@ let check_for_duplicate ~l2_chain_ids = (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))) + Format.fprintf ppf "%s" (L2_types.Chain_id.to_string chain_id))) (ChainSet.elements duplicate_chain_ids) (* When splitting the path given in argument, @@ -136,8 +136,7 @@ let make_l2 ~boostrap_balance ?bootstrap_accounts ?minimum_base_fee_per_gas @ make_l2_config_instr ~l2_chain_id (Some - ( "chain_family", - l2_chain_family |> Ethereum_types.Chain_family.to_string )) + ("chain_family", l2_chain_family |> L2_types.Chain_family.to_string)) @ make_l2_config_instr ~l2_chain_id world_state_path in let world_state_instrs = @@ -204,7 +203,7 @@ let make ~mainnet_compat ~boostrap_balance ?l2_chain_ids ?bootstrap_accounts let chain_ids = List.map (fun chain_id -> - let chain_id = Ethereum_types.Chain_id.to_string chain_id in + let chain_id = L2_types.Chain_id.to_string chain_id in Value (Bytes.of_string chain_id)) l2_chain_ids in diff --git a/etherlink/bin_node/lib_dev/kernel_config.mli b/etherlink/bin_node/lib_dev/kernel_config.mli index 2491ad6ff433a089e4541e50f24080ca1dd3c5f8..95bec428cf8c1574bbd5a386e1cac73e818a55f5 100644 --- a/etherlink/bin_node/lib_dev/kernel_config.mli +++ b/etherlink/bin_node/lib_dev/kernel_config.mli @@ -14,7 +14,7 @@ type evm_version = Shanghai | Cancun val make : mainnet_compat:bool -> boostrap_balance:Ethereum_types.NonceMap.key -> - ?l2_chain_ids:Ethereum_types.chain_id list -> + ?l2_chain_ids:L2_types.chain_id list -> ?bootstrap_accounts:Ethereum_types.address list -> ?kernel_root_hash:string * string -> ?chain_id:string * string -> @@ -60,7 +60,7 @@ val make_l2 : ?set_account_code:(string * string) list -> ?world_state_path:string * string -> l2_chain_id:string -> - l2_chain_family:Ethereum_types.chain_family -> + l2_chain_family:L2_types.chain_family -> output:string -> unit -> unit tzresult Lwt.t diff --git a/etherlink/bin_node/lib_dev/node_error.ml b/etherlink/bin_node/lib_dev/node_error.ml index b705d33ecc55528a133fa68ad3166faff86284b4..df539467e114179d55e46889bfd16bf8d9a0f39d 100644 --- a/etherlink/bin_node/lib_dev/node_error.ml +++ b/etherlink/bin_node/lib_dev/node_error.ml @@ -34,9 +34,9 @@ type error += | Proxy_finalize_with_multichain of error_source | Singlechain_node_multichain_kernel | Mismatched_chain_family of { - chain_id : Ethereum_types.chain_id; - node_family : Ethereum_types.chain_family; - kernel_family : Ethereum_types.chain_family; + chain_id : L2_types.chain_id; + node_family : L2_types.chain_family; + kernel_family : L2_types.chain_family; } | Dream_rpc_tezlink @@ -162,17 +162,17 @@ let () = ppf "The node was configured with the %a chain family for chain %a but the \ rollup expects the %a chain family for this chain." - Ethereum_types.Chain_id.pp + L2_types.Chain_id.pp chain_id - Ethereum_types.Chain_family.pp + L2_types.Chain_family.pp node_family - Ethereum_types.Chain_family.pp + L2_types.Chain_family.pp kernel_family) Data_encoding.( obj3 - (req "chain_id" Ethereum_types.Chain_id.encoding) - (req "node_family" Ethereum_types.Chain_family.encoding) - (req "kernel_family" Ethereum_types.Chain_family.encoding)) + (req "chain_id" L2_types.Chain_id.encoding) + (req "node_family" L2_types.Chain_family.encoding) + (req "kernel_family" L2_types.Chain_family.encoding)) (function | Mismatched_chain_family {chain_id; node_family; kernel_family} -> Some (chain_id, node_family, kernel_family) diff --git a/etherlink/bin_node/lib_dev/observer.ml b/etherlink/bin_node/lib_dev/observer.ml index a4d3af1e973384894854dc878a4403b1128b7378..3b47da28400283986415d4b4d700c46adcdbf952 100644 --- a/etherlink/bin_node/lib_dev/observer.ml +++ b/etherlink/bin_node/lib_dev/observer.ml @@ -7,6 +7,7 @@ (*****************************************************************************) open Ethereum_types +open L2_types let confirm_txs config confirmed_txs = let open Lwt_result_syntax in diff --git a/etherlink/bin_node/lib_dev/proxy.ml b/etherlink/bin_node/lib_dev/proxy.ml index ba9d22cf472c7c294987a6e8cd4b40a2dae666ba..3475c6414ab5db296ce6234b6c36b6373066de24 100644 --- a/etherlink/bin_node/lib_dev/proxy.ml +++ b/etherlink/bin_node/lib_dev/proxy.ml @@ -121,7 +121,6 @@ let main () in let* chain_family = - let open Ethereum_types in if finalized_view then if (* When finalized_view is set, it's too early to request the @@ -130,15 +129,15 @@ let main then (* The finalized view of the proxy mode and the multichain feature are not compatible. *) tzfail (Node_error.Proxy_finalize_with_multichain `Node) - else return EVM + else return L2_types.EVM else let* enable_multichain = Rollup_node_rpc.is_multichain_enabled () in match (config.experimental_features.l2_chains, enable_multichain) with - | None, false -> return EVM + | None, false -> return L2_types.EVM | None, true -> tzfail Node_error.Singlechain_node_multichain_kernel | Some [_], false -> let*! () = Events.multichain_node_singlechain_kernel () in - return EVM + return L2_types.EVM | Some [l2_chain], true -> let* chain_family = Rollup_node_rpc.chain_family l2_chain.chain_id in if l2_chain.chain_family = chain_family then return chain_family diff --git a/etherlink/bin_node/lib_dev/replay.ml b/etherlink/bin_node/lib_dev/replay.ml index 9d4b7ee4407ca37a4883ae523c818d591b067332..937c828f72dcf31b5c9ac1dba0eb645b3932c431 100644 --- a/etherlink/bin_node/lib_dev/replay.ml +++ b/etherlink/bin_node/lib_dev/replay.ml @@ -64,7 +64,7 @@ let main ?profile ?kernel ?kernel_verbosity ~data_dir config number = Ethereum_types.pp_quantity number Ethereum_types.pp_block_hash - block.hash ; + (L2_types.block_hash block) ; return_unit | Apply_failure -> failwith "Could not replay blueprint %a" Ethereum_types.pp_quantity number diff --git a/etherlink/bin_node/lib_dev/rpc.ml b/etherlink/bin_node/lib_dev/rpc.ml index 9afface54b1802eafff61d75b7538794c4d75c0d..49fd5c63f133463770f7f307b1d3b15a0d32e743 100644 --- a/etherlink/bin_node/lib_dev/rpc.ml +++ b/etherlink/bin_node/lib_dev/rpc.ml @@ -190,13 +190,12 @@ let main ~data_dir ~evm_node_endpoint ?evm_node_private_endpoint let* enable_multichain = Evm_ro_context.read_enable_multichain_flag ctxt in let* chain_family = - let open Ethereum_types in match (config.experimental_features.l2_chains, enable_multichain) with - | None, false -> return EVM + | None, false -> return L2_types.EVM | None, true -> tzfail Node_error.Singlechain_node_multichain_kernel | Some [_], false -> let*! () = Events.multichain_node_singlechain_kernel () in - return EVM + return L2_types.EVM | Some [l2_chain], true -> let* chain_family = Evm_ro_context.read_chain_family ctxt l2_chain.chain_id @@ -221,7 +220,7 @@ let main ~data_dir ~evm_node_endpoint ?evm_node_private_endpoint ~data_dir ~rpc_server_family:(Rpc_types.Single_chain_node_rpc_server chain_family) ?tezlink_services: - (if chain_family = Michelson then + (if chain_family = L2_types.Michelson then Some Tezlink_services_impl.( michelson_services_methods rpc_backend Tezlink_constants.mainnet) diff --git a/etherlink/bin_node/lib_dev/rpc_encodings.ml b/etherlink/bin_node/lib_dev/rpc_encodings.ml index 1bc10711646d7b3773c8b50a612ed252225b60ee..151805da56d2f880123dcb4a5c9f115d48351a74 100644 --- a/etherlink/bin_node/lib_dev/rpc_encodings.ml +++ b/etherlink/bin_node/lib_dev/rpc_encodings.ml @@ -234,11 +234,11 @@ end module Chain_id = struct type input = unit - type output = Ethereum_types.chain_id + type output = L2_types.chain_id let input_encoding = Data_encoding.unit - let output_encoding = Ethereum_types.Chain_id.encoding + let output_encoding = L2_types.Chain_id.encoding let method_ = "eth_chainId" @@ -246,13 +246,13 @@ module Chain_id = struct end module Chain_family = struct - type input = Ethereum_types.chain_id + type input = L2_types.chain_id - type output = Ethereum_types.chain_family + type output = L2_types.chain_family - let input_encoding = Data_encoding.tup1 Ethereum_types.Chain_id.encoding + let input_encoding = Data_encoding.tup1 L2_types.Chain_id.encoding - let output_encoding = Ethereum_types.Chain_family.encoding + let output_encoding = L2_types.Chain_family.encoding let method_ = "tez_chainFamily" @@ -1153,9 +1153,9 @@ let map_method_name ~rpc_server_family ~restrict method_name = | Rpc_types.Multichain_sequencer_rpc_server -> ( multichain_sequencer_supported_methods, multichain_sequencer_unsupported_methods ) - | Rpc_types.Single_chain_node_rpc_server Ethereum_types.EVM -> + | Rpc_types.Single_chain_node_rpc_server L2_types.EVM -> (evm_supported_methods, evm_unsupported_methods) - | Rpc_types.Single_chain_node_rpc_server Ethereum_types.Michelson -> + | Rpc_types.Single_chain_node_rpc_server L2_types.Michelson -> (michelson_supported_methods, michelson_unsupported_methods) in let disabled = diff --git a/etherlink/bin_node/lib_dev/rpc_encodings.mli b/etherlink/bin_node/lib_dev/rpc_encodings.mli index f17ae54fbe27c58f7ac149636baa8c10851e7cf1..362b8d60859a7d8e90391c37f1526800e4b3783b 100644 --- a/etherlink/bin_node/lib_dev/rpc_encodings.mli +++ b/etherlink/bin_node/lib_dev/rpc_encodings.mli @@ -137,12 +137,12 @@ module Kernel_root_hash : module Network_id : METHOD with type input = unit and type output = string module Chain_id : - METHOD with type input = unit and type output = Ethereum_types.chain_id + METHOD with type input = unit and type output = L2_types.chain_id module Chain_family : METHOD - with type input = Ethereum_types.chain_id - and type output = Ethereum_types.chain_family + with type input = L2_types.chain_id + and type output = L2_types.chain_family module Accounts : METHOD with type input = unit and type output = Ethereum_types.address list diff --git a/etherlink/bin_node/lib_dev/rpc_types.ml b/etherlink/bin_node/lib_dev/rpc_types.ml index c23dc1794e43b80a7d81d74403c2ecc744a25d62..180c66db9a9e482dfa61dcbf6cf15e7c09b8e9db 100644 --- a/etherlink/bin_node/lib_dev/rpc_types.ml +++ b/etherlink/bin_node/lib_dev/rpc_types.ml @@ -13,4 +13,4 @@ type rpc_server_family = | Multichain_sequencer_rpc_server - | Single_chain_node_rpc_server of Ethereum_types.chain_family + | Single_chain_node_rpc_server of L2_types.chain_family diff --git a/etherlink/bin_node/lib_dev/sequencer.ml b/etherlink/bin_node/lib_dev/sequencer.ml index 2b348cefbdda658a9eee35062a62155d4ae2a3af..482e5f0d1dfe6adba220beb09566ec72d5fd8bf1 100644 --- a/etherlink/bin_node/lib_dev/sequencer.ml +++ b/etherlink/bin_node/lib_dev/sequencer.ml @@ -179,7 +179,7 @@ let main ~data_dir ?(genesis_timestamp = Misc.now ()) ~cctxt ~transactions:[] ~delayed_transactions:[] ~number:Ethereum_types.(Qty Z.zero) - ~parent_hash:Ethereum_types.genesis_parent_hash + ~parent_hash:(L2_types.genesis_parent_hash ~chain_family:EVM) in let genesis_payload = Sequencer_blueprint.create_inbox_payload diff --git a/etherlink/bin_node/lib_dev/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index af4ccaab4c27807a704dda290d08cdbda02fd16b..65857150f69ae595cd0bde17d2289061cb539776 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -76,11 +76,10 @@ module type S = sig Ethereum_types.quantity tzresult Lwt.t (** [chain_id ()] returns chain id defined by the rollup. *) - val chain_id : unit -> Ethereum_types.chain_id tzresult Lwt.t + val chain_id : unit -> L2_types.chain_id tzresult Lwt.t (** [chain_family chain_id] returns chain family defined for the chain with id chain_id. *) - val chain_family : - Ethereum_types.chain_id -> Ethereum_types.chain_family tzresult Lwt.t + val chain_family : L2_types.chain_id -> L2_types.chain_family tzresult Lwt.t (** [base_fee_per_gas ()] returns base fee defined by the rollup. *) val base_fee_per_gas : unit -> Ethereum_types.quantity tzresult Lwt.t @@ -188,7 +187,9 @@ module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct Executor.replay ~log_file:"replay_rpc" ~profile:false number in match result with - | Apply_success {block; _} -> return block + | Apply_success {block = Eth block; _} -> return block + | Apply_success {block = Tez _; _} -> + failwith "Could not replay a tezlink block" | Apply_failure -> failwith "Could not replay the block" let smart_rollup_address = Backend.smart_rollup_address diff --git a/etherlink/bin_node/main.ml b/etherlink/bin_node/main.ml index f7e1bd5b9e78db4618ac6794c517788e316ad03e..b1468ca8a97ae987e8ef0bdf228d9d4044a35ec3 100644 --- a/etherlink/bin_node/main.ml +++ b/etherlink/bin_node/main.ml @@ -1855,7 +1855,7 @@ let evm_version_arg = let make_l2_kernel_config_command = let open Tezos_clic in let open Lwt_result_syntax in - let open Evm_node_lib_dev_encoding.Ethereum_types in + let open Evm_node_lib_dev_encoding.L2_types in command ~group:Groups.kernel ~desc: @@ -1938,7 +1938,7 @@ let l2_chain_ids_arg = ~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) + Lwt.return_ok @@ L2_types.Chain_id.of_string_exn chain_id) let make_kernel_config_command = let open Tezos_clic in diff --git a/etherlink/kernel_latest/kernel/src/chains.rs b/etherlink/kernel_latest/kernel/src/chains.rs index d3bccff5a72f26deb90873cc9136acf10636e5b9..911a973aaa90aeb6bf38bf18b01106447c183eca 100644 --- a/etherlink/kernel_latest/kernel/src/chains.rs +++ b/etherlink/kernel_latest/kernel/src/chains.rs @@ -16,6 +16,22 @@ pub enum ChainFamily { Michelson, } +impl Default for ChainFamily { + fn default() -> Self { + Self::Evm + } +} + +impl From for ChainFamily { + fn from(value: String) -> Self { + match value.as_str() { + "Michelson" => Self::Michelson, + "Evm" => Self::Evm, + _ => Self::default(), + } + } +} + pub struct EvmChainConfig { pub chain_id: U256, pub limits: EvmLimits, @@ -61,6 +77,10 @@ impl ChainConfig { ChainConfig::Evm(EvmChainConfig::create_config(chain_id, limits, evm_config)) } + pub fn new_michelson_config(chain_id: U256) -> Self { + ChainConfig::Michelson(MichelsonChainConfig::create_config(chain_id)) + } + pub fn get_chain_family(&self) -> ChainFamily { match self { ChainConfig::Evm(_) => ChainFamily::Evm, diff --git a/etherlink/kernel_latest/kernel/src/configuration.rs b/etherlink/kernel_latest/kernel/src/configuration.rs index f2d0ac9192d66ced8bf81521920d6c4bd185d90e..1719fabf22375fb3b758e79a07d0826e6efc7622 100644 --- a/etherlink/kernel_latest/kernel/src/configuration.rs +++ b/etherlink/kernel_latest/kernel/src/configuration.rs @@ -5,15 +5,15 @@ use crate::{ blueprint_storage::DEFAULT_MAX_BLUEPRINT_LOOKAHEAD_IN_SECONDS, - chains::{ChainConfig, EvmLimits}, + chains::{ChainConfig, ChainFamily, EvmLimits}, delayed_inbox::DelayedInbox, retrieve_minimum_base_fee_per_gas, storage::{ dal_slots, enable_dal, evm_node_flag, is_enable_fa_bridge, - max_blueprint_lookahead_in_seconds, read_admin, read_delayed_transaction_bridge, - read_kernel_governance, read_kernel_security_governance, - read_maximum_allowed_ticks, read_or_set_maximum_gas_per_transaction, - read_sequencer_governance, sequencer, + max_blueprint_lookahead_in_seconds, read_admin, read_chain_family, + read_delayed_transaction_bridge, read_kernel_governance, + read_kernel_security_governance, read_maximum_allowed_ticks, + read_or_set_maximum_gas_per_transaction, read_sequencer_governance, sequencer, }, tick_model::constants::{MAXIMUM_GAS_LIMIT, MAX_ALLOWED_TICKS}, }; @@ -193,6 +193,22 @@ fn fetch_dal_configuration(host: &mut Host) -> Option( + host: &mut Host, + chain_id: U256, +) -> ChainConfig { + // if the info is not in durable storage, we must not fail, but treat it as EVM + let chain_family = read_chain_family(host, chain_id).unwrap_or_default(); + match chain_family { + ChainFamily::Michelson => ChainConfig::new_michelson_config(chain_id), + ChainFamily::Evm => { + let evm_limits = fetch_evm_limits(host); + let evm_configuration = fetch_evm_configuration(host); + ChainConfig::new_evm_config(chain_id, evm_limits, evm_configuration) + } + } +} + pub fn fetch_configuration( host: &mut Host, chain_id: U256, @@ -200,14 +216,11 @@ pub fn fetch_configuration( let tezos_contracts = fetch_tezos_contracts(host); let maximum_allowed_ticks = read_maximum_allowed_ticks(host).unwrap_or(MAX_ALLOWED_TICKS); - let evm_limits = fetch_evm_limits(host); let sequencer = sequencer(host).unwrap_or_default(); let enable_fa_bridge = is_enable_fa_bridge(host).unwrap_or_default(); - let evm_configuration = fetch_evm_configuration(host); let dal: Option = fetch_dal_configuration(host); let evm_node_flag = evm_node_flag(host).unwrap_or(false); - let chain_config = - ChainConfig::new_evm_config(chain_id, evm_limits, evm_configuration); + let chain_config = fetch_chain_configuration(host, chain_id); match sequencer { Some(sequencer) => { let delayed_bridge = read_delayed_transaction_bridge(host) diff --git a/etherlink/kernel_latest/kernel/src/storage.rs b/etherlink/kernel_latest/kernel/src/storage.rs index 417b6a9b70d800061c18829614ffed7289610221..726c6f5f006267d284317418ea4d39b78252fc0c 100644 --- a/etherlink/kernel_latest/kernel/src/storage.rs +++ b/etherlink/kernel_latest/kernel/src/storage.rs @@ -6,6 +6,7 @@ // SPDX-License-Identifier: MIT use crate::block_in_progress::EthBlockInProgress; +use crate::chains::ChainFamily; use crate::event::Event; use crate::simulation::SimulationResult; use crate::tick_model::constants::MAXIMUM_GAS_LIMIT; @@ -118,6 +119,10 @@ const EVM_CHAIN_ID: RefPath = RefPath::assert_from(b"/evm/chain_id"); pub const ENABLE_MULTICHAIN: RefPath = RefPath::assert_from(b"/evm/feature_flags/enable_multichain"); +// Root for chain configurations. Informations about a chain are available by appending its chain ID. +pub const CHAIN_CONFIGURATIONS: RefPath = + RefPath::assert_from(b"/evm/chain_configurations"); + const EVM_MINIMUM_BASE_FEE_PER_GAS: RefPath = RefPath::assert_from(b"/evm/world_state/fees/minimum_base_fee_per_gas"); const EVM_DA_FEE: RefPath = @@ -191,6 +196,12 @@ pub fn object_path(object_hash: &TransactionHash) -> Result { concat(&EVM_TRANSACTIONS_OBJECTS, &object_path).map_err(Error::from) } +pub fn chain_config_path(chain_id: &U256) -> Result { + let raw_chain_id_path: Vec = format!("/{}", chain_id).into(); + let chain_id_path = OwnedPath::try_from(raw_chain_id_path)?; + concat(&CHAIN_CONFIGURATIONS, &chain_id_path).map_err(Error::from) +} + pub fn store_simulation_result( host: &mut Host, result: SimulationResult, @@ -871,6 +882,22 @@ pub fn max_blueprint_lookahead_in_seconds(host: &impl Runtime) -> anyhow::Result Ok(i64::from_le_bytes(bytes)) } +// Storage functions related to a chain configuration + +pub fn read_chain_family( + host: &impl Runtime, + chain_id: U256, +) -> anyhow::Result { + let chain_configurations_path = chain_config_path(&chain_id)?; + let chain_family_path = RefPath::assert_from(b"/chain_family"); + let path = concat(&chain_configurations_path, &chain_family_path)?; + let bytes = host + .store_read_all(&path) + .context(format!("Cannot read chain family for chain {}", chain_id))?; + let chain_family = String::from_utf8(bytes)?; + Ok(chain_family.into()) +} + #[cfg(test)] mod internal_for_tests { use super::*; diff --git a/etherlink/tezt/tests/evm_rollup.ml b/etherlink/tezt/tests/evm_rollup.ml index 1206b00b15537c38094e22db5d59b8235019db4a..383bdb3d376e7b845b50ac27367b81c9b3b97311 100644 --- a/etherlink/tezt/tests/evm_rollup.ml +++ b/etherlink/tezt/tests/evm_rollup.ml @@ -1614,7 +1614,7 @@ let ensure_current_block_header_integrity evm_setup = List [Value hash; Value receipts_root; Value transactions_root]; ]; ]) -> - ( Z.to_int32 @@ Ethereum_types.decode_z_le number, + ( Z.to_int32 @@ Helpers.decode_z_le number, timestamp, Hex.of_bytes hash, Hex.of_bytes receipts_root, @@ -1646,7 +1646,7 @@ let ensure_current_block_header_integrity evm_setup = Check.string ~error_msg:"Bad block header hash, expected %R got %L." ; Check.( - Z.to_int64 @@ Ethereum_types.decode_z_le timestamp + Z.to_int64 @@ Helpers.decode_z_le timestamp = Tezos_base.Time.Protocol.to_seconds block.timestamp) ~__LOC__ Check.int64