From 0a40476e2b5dbae28d72841d48e377e22317d46e Mon Sep 17 00:00:00 2001 From: arnaud Date: Fri, 14 Mar 2025 15:21:59 +0100 Subject: [PATCH 01/10] Etherlink/Kernel/Storage: Function to read the chain_family Introduce a root path pointing to where are stored the chain configurations --- etherlink/kernel_latest/kernel/src/chains.rs | 16 +++++++++++ etherlink/kernel_latest/kernel/src/storage.rs | 28 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/etherlink/kernel_latest/kernel/src/chains.rs b/etherlink/kernel_latest/kernel/src/chains.rs index d3bccff5a72f..bf97cba52237 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, diff --git a/etherlink/kernel_latest/kernel/src/storage.rs b/etherlink/kernel_latest/kernel/src/storage.rs index 417b6a9b70d8..ca86c5517d2e 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,23 @@ 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 + +#[allow(dead_code)] +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::*; -- GitLab From 14bd708b14a7e85bf98b432975cc196234c26eb8 Mon Sep 17 00:00:00 2001 From: arnaud Date: Tue, 18 Mar 2025 10:32:09 +0100 Subject: [PATCH 02/10] Etherlink/Kernel: Introducing a function to create a Michelson configuration --- etherlink/kernel_latest/kernel/src/chains.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/etherlink/kernel_latest/kernel/src/chains.rs b/etherlink/kernel_latest/kernel/src/chains.rs index bf97cba52237..911a973aaa90 100644 --- a/etherlink/kernel_latest/kernel/src/chains.rs +++ b/etherlink/kernel_latest/kernel/src/chains.rs @@ -77,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, -- GitLab From efbb71620936fd308966e9f9569a82e3c4beb003 Mon Sep 17 00:00:00 2001 From: arnaud Date: Fri, 14 Mar 2025 15:23:12 +0100 Subject: [PATCH 03/10] Etherlink/Kernel/Configuration: Fetch chain_configuration depending on the chain family found in the storage --- .../kernel_latest/kernel/src/configuration.rs | 31 +++++++++++++------ etherlink/kernel_latest/kernel/src/storage.rs | 1 - 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/etherlink/kernel_latest/kernel/src/configuration.rs b/etherlink/kernel_latest/kernel/src/configuration.rs index f2d0ac9192d6..1719fabf2237 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 ca86c5517d2e..726c6f5f0062 100644 --- a/etherlink/kernel_latest/kernel/src/storage.rs +++ b/etherlink/kernel_latest/kernel/src/storage.rs @@ -884,7 +884,6 @@ pub fn max_blueprint_lookahead_in_seconds(host: &impl Runtime) -> anyhow::Result // Storage functions related to a chain configuration -#[allow(dead_code)] pub fn read_chain_family( host: &impl Runtime, chain_id: U256, -- GitLab From 62dab9a61eff4f72bf73577c6f17b17ea2297cf7 Mon Sep 17 00:00:00 2001 From: arnaud Date: Tue, 11 Mar 2025 18:04:34 +0100 Subject: [PATCH 04/10] EVM/Node: Move function from ethereum_types to helpers to avoid circle dependency Some function extracted from ethereum_types could be useful for tezlink. To avoid duplicating those function, I extract them from the module and cut the helpers dependency. Maybe the keccak256 function could be moved in ethereum_types as this is the hash function specific to ethereum. --- etherlink/bin_node/lib_dev/durable_storage.ml | 6 ++--- .../lib_dev/encodings/ethereum_types.ml | 24 +++++-------------- .../lib_dev/encodings/ethereum_types.mli | 2 -- .../bin_node/lib_dev/encodings/helpers.ml | 19 +++++++++++---- .../lib_dev/encodings/tracer_types.ml | 4 ++-- etherlink/bin_node/lib_dev/ethbloom.ml | 4 ++-- etherlink/tezt/tests/evm_rollup.ml | 4 ++-- 7 files changed, 29 insertions(+), 34 deletions(-) diff --git a/etherlink/bin_node/lib_dev/durable_storage.ml b/etherlink/bin_node/lib_dev/durable_storage.ml index 122cfeaa2e38..75a5aff42ab1 100644 --- a/etherlink/bin_node/lib_dev/durable_storage.ml +++ b/etherlink/bin_node/lib_dev/durable_storage.ml @@ -280,20 +280,20 @@ 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 diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml index 76b4dc8c30ed..4f9cfc2134eb 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml @@ -105,26 +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 @@ -134,13 +122,13 @@ module Chain_id = struct let encoding = Data_encoding.conv - (fun (Chain_id c) -> z_to_hexa c) + (fun (Chain_id c) -> Helpers.z_to_hexa c) of_string_exn Data_encoding.string - let decode_le bytes = Chain_id (decode_z_le bytes) + let decode_le bytes = Chain_id (Helpers.decode_z_le bytes) - let decode_be bytes = Chain_id (decode_z_be bytes) + let decode_be bytes = Chain_id (Helpers.decode_z_be bytes) let compare (Chain_id c1) (Chain_id c2) = Z.compare c1 c2 @@ -298,9 +286,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 60f9810d3fa5..e2127c7f317b 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli @@ -126,8 +126,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 f15c0c01fcd7..ada56634223f 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/tracer_types.ml b/etherlink/bin_node/lib_dev/encodings/tracer_types.ml index 57ef9340c3f7..d050d17ac2e6 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/ethbloom.ml b/etherlink/bin_node/lib_dev/ethbloom.ml index 179bf5f77a29..32007b6bac9a 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/tezt/tests/evm_rollup.ml b/etherlink/tezt/tests/evm_rollup.ml index 1206b00b1553..383bdb3d376e 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 -- GitLab From 7d268b1f4d978434826ebef69608baf08216e869 Mon Sep 17 00:00:00 2001 From: arnaud Date: Tue, 11 Mar 2025 18:03:57 +0100 Subject: [PATCH 05/10] EVM/Tezlink/Node: Move Chain family and chain_id in a new module As chain_id and chain_family are notions common between Etherlink and Tezlink, it feels natural that it should not be in ethereum types. --- etherlink/bin_floodgate/craft.ml | 2 +- etherlink/bin_floodgate/floodgate_events.ml | 2 +- etherlink/bin_floodgate/floodgate_events.mli | 2 +- etherlink/bin_floodgate/network_info.ml | 2 +- etherlink/bin_floodgate/network_info.mli | 2 +- etherlink/bin_node/config/configuration.ml | 12 ++--- etherlink/bin_node/config/configuration.mli | 6 +-- etherlink/bin_node/lib_dev/durable_storage.ml | 4 +- .../bin_node/lib_dev/durable_storage_path.ml | 2 + .../bin_node/lib_dev/durable_storage_path.mli | 10 ++-- .../lib_dev/encodings/ethereum_types.ml | 40 ---------------- .../lib_dev/encodings/ethereum_types.mli | 37 -------------- .../bin_node/lib_dev/encodings/l2_types.ml | 48 +++++++++++++++++++ .../bin_node/lib_dev/encodings/l2_types.mli | 45 +++++++++++++++++ .../bin_node/lib_dev/encodings/transaction.ml | 1 + etherlink/bin_node/lib_dev/evm_ro_context.mli | 2 +- etherlink/bin_node/lib_dev/kernel_config.ml | 11 ++--- etherlink/bin_node/lib_dev/kernel_config.mli | 4 +- etherlink/bin_node/lib_dev/node_error.ml | 18 +++---- etherlink/bin_node/lib_dev/observer.ml | 1 + etherlink/bin_node/lib_dev/proxy.ml | 7 ++- etherlink/bin_node/lib_dev/rpc.ml | 7 ++- etherlink/bin_node/lib_dev/rpc_encodings.ml | 16 +++---- etherlink/bin_node/lib_dev/rpc_encodings.mli | 6 +-- etherlink/bin_node/lib_dev/rpc_types.ml | 2 +- .../bin_node/lib_dev/services_backend_sig.ml | 5 +- etherlink/bin_node/main.ml | 4 +- 27 files changed, 157 insertions(+), 141 deletions(-) create mode 100644 etherlink/bin_node/lib_dev/encodings/l2_types.ml create mode 100644 etherlink/bin_node/lib_dev/encodings/l2_types.mli diff --git a/etherlink/bin_floodgate/craft.ml b/etherlink/bin_floodgate/craft.ml index 3e8d366aafba..9127660868de 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 db563167e2a3..b3444eb41c66 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 ce4a59524673..0a4791f74690 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 728004ad16fa..dc23b9c265f3 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 87c921633fc2..eb332765ed13 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 eb1a95fa68df..03ca84194df8 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 7efaa1f09fab..bf0f7f62548f 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/durable_storage.ml b/etherlink/bin_node/lib_dev/durable_storage.ml index 75a5aff42ab1..233bf3a01ec5 100644 --- a/etherlink/bin_node/lib_dev/durable_storage.ml +++ b/etherlink/bin_node/lib_dev/durable_storage.ml @@ -274,7 +274,7 @@ 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 @@ -299,7 +299,7 @@ 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 0e20eb38124b..d61fee12a473 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 43d17fabefae..7c7d48b2c55c 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 4f9cfc2134eb..d8f07bd24600 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml @@ -113,46 +113,6 @@ let quantity_encoding = let pp_quantity fmt (Qty q) = Z.pp_print fmt q -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 block_hash = Block_hash of hex [@@ocaml.unboxed] let pp_block_hash fmt (Block_hash (Hex h)) = Format.pp_print_string fmt h diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli index e2127c7f317b..39a197cc9785 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] 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 000000000000..71854e28663b --- /dev/null +++ b/etherlink/bin_node/lib_dev/encodings/l2_types.ml @@ -0,0 +1,48 @@ +(*****************************************************************************) +(* *) +(* 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 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 000000000000..fbc3048cc258 --- /dev/null +++ b/etherlink/bin_node/lib_dev/encodings/l2_types.mli @@ -0,0 +1,45 @@ +(*****************************************************************************) +(* *) +(* 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 diff --git a/etherlink/bin_node/lib_dev/encodings/transaction.ml b/etherlink/bin_node/lib_dev/encodings/transaction.ml index c41a487fedc7..8d65400f40e2 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/evm_ro_context.mli b/etherlink/bin_node/lib_dev/evm_ro_context.mli index f491b0edd787..24cb4b555a67 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/kernel_config.ml b/etherlink/bin_node/lib_dev/kernel_config.ml index 7f39c99524dc..25e16c2e1783 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 2491ad6ff433..95bec428cf8c 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 b705d33ecc55..df539467e114 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 a4d3af1e9733..3b47da284002 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 ba9d22cf472c..3475c6414ab5 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/rpc.ml b/etherlink/bin_node/lib_dev/rpc.ml index 9afface54b18..49fd5c63f133 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 1bc10711646d..151805da56d2 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 f17ae54fbe27..362b8d60859a 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 c23dc1794e43..180c66db9a9e 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/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index af4ccaab4c27..3a1f4f63d6c7 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 diff --git a/etherlink/bin_node/main.ml b/etherlink/bin_node/main.ml index f7e1bd5b9e78..b1468ca8a97a 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 -- GitLab From 89c3ae11aa7a0ada581c5f93c46f0f197ccd0472 Mon Sep 17 00:00:00 2001 From: arnaud Date: Thu, 13 Mar 2025 14:44:50 +0100 Subject: [PATCH 06/10] EVM/Tezlink/Node: Copy function that will be common to etherlink and tezlink to make the evm node work To make the evm node work in tezlink mode (minimal features just produce block), we need to know the genesis parent hash, how to decode a block hash (maybe in the future this one could be remove), how to decode a block from rlp --- .../bin_node/lib_dev/encodings/l2_types.ml | 19 +++++++++++++++++++ .../bin_node/lib_dev/encodings/l2_types.mli | 12 ++++++++++++ 2 files changed, 31 insertions(+) diff --git a/etherlink/bin_node/lib_dev/encodings/l2_types.ml b/etherlink/bin_node/lib_dev/encodings/l2_types.ml index 71854e28663b..448e1b67ee14 100644 --- a/etherlink/bin_node/lib_dev/encodings/l2_types.ml +++ b/etherlink/bin_node/lib_dev/encodings/l2_types.ml @@ -46,3 +46,22 @@ module Chain_family = struct let pp fmt cf = Format.fprintf fmt "%s" (to_string cf) end + +type 'a block = Eth of 'a Ethereum_types.block + +let decode_block_hash ~chain_family bytes = + match chain_family with + | EVM -> Ethereum_types.decode_block_hash bytes + | Michelson -> raise (Invalid_argument "TODO tezos") + +let genesis_parent_hash ~chain_family = + match chain_family with + | EVM -> Ethereum_types.genesis_parent_hash + | Michelson -> raise (Invalid_argument "TODO tezos") + +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 -> raise (Invalid_argument "TODO tezos") diff --git a/etherlink/bin_node/lib_dev/encodings/l2_types.mli b/etherlink/bin_node/lib_dev/encodings/l2_types.mli index fbc3048cc258..773c7fb975fd 100644 --- a/etherlink/bin_node/lib_dev/encodings/l2_types.mli +++ b/etherlink/bin_node/lib_dev/encodings/l2_types.mli @@ -43,3 +43,15 @@ module Chain_family : sig val pp : Format.formatter -> chain_family -> unit end + +type 'a block = Eth of 'a Ethereum_types.block + +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 -- GitLab From f81be2d5f225c11b214fc1430da029737bdae295 Mon Sep 17 00:00:00 2001 From: arnaud Date: Thu, 13 Mar 2025 14:47:56 +0100 Subject: [PATCH 07/10] EVM/Tezlink/Node: Replace every call to genesis_parent_hash by the one in l2_types For now forcing it to Etherlink to not change the behavior of the evm_node --- etherlink/bin_node/lib_dev/evm_context.ml | 2 +- etherlink/bin_node/lib_dev/evm_state.ml | 2 +- etherlink/bin_node/lib_dev/sequencer.ml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/etherlink/bin_node/lib_dev/evm_context.ml b/etherlink/bin_node/lib_dev/evm_context.ml index 4825ffb0568c..d73bfe6e62d5 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 = diff --git a/etherlink/bin_node/lib_dev/evm_state.ml b/etherlink/bin_node/lib_dev/evm_state.ml index 0c71fc631e62..2949be64aca3 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 diff --git a/etherlink/bin_node/lib_dev/sequencer.ml b/etherlink/bin_node/lib_dev/sequencer.ml index 2b348cefbdda..482e5f0d1dfe 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 -- GitLab From 58e51b7cdb5cdb8b63b2317f39a095b8ba7fef68 Mon Sep 17 00:00:00 2001 From: arnaud Date: Thu, 13 Mar 2025 17:24:40 +0100 Subject: [PATCH 08/10] EVM/Tezlink/Node: Use block function in L2_types instead of matching on ethereum Previous commit matched on Eth block to limit the diff, this one remove this and start to use L2_types function for notions that are common between Etherlink and Tezlink (block number and block_hash). Still keep some match for notion that are too specific to ethereum (it's not impossible that the solution is to just duplicate the function one for Etherlink and another one for Tezlink) --- .../bin_node/lib_dev/blueprint_events.ml | 1 + .../bin_node/lib_dev/blueprint_events.mli | 2 +- .../bin_node/lib_dev/encodings/l2_types.ml | 14 +++ .../bin_node/lib_dev/encodings/l2_types.mli | 6 ++ etherlink/bin_node/lib_dev/evm_context.ml | 87 ++++++++++++------- etherlink/bin_node/lib_dev/evm_ro_context.ml | 4 +- etherlink/bin_node/lib_dev/evm_state.ml | 14 +-- etherlink/bin_node/lib_dev/evm_state.mli | 5 +- etherlink/bin_node/lib_dev/replay.ml | 2 +- .../bin_node/lib_dev/services_backend_sig.ml | 2 +- 10 files changed, 90 insertions(+), 47 deletions(-) diff --git a/etherlink/bin_node/lib_dev/blueprint_events.ml b/etherlink/bin_node/lib_dev/blueprint_events.ml index 99dac6f0ffe9..2fc2ebc79a2d 100644 --- a/etherlink/bin_node/lib_dev/blueprint_events.ml +++ b/etherlink/bin_node/lib_dev/blueprint_events.ml @@ -165,6 +165,7 @@ let blueprint_injection_failed level trace = let blueprint_applied block process_time = let open Ethereum_types in + let block = match block with L2_types.Eth block -> block in let count_txs = function | TxHash l -> List.length l | TxFull l -> List.length l diff --git a/etherlink/bin_node/lib_dev/blueprint_events.mli b/etherlink/bin_node/lib_dev/blueprint_events.mli index 79343b727710..a33fccc37eab 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/encodings/l2_types.ml b/etherlink/bin_node/lib_dev/encodings/l2_types.ml index 448e1b67ee14..e0d76ac74bcd 100644 --- a/etherlink/bin_node/lib_dev/encodings/l2_types.ml +++ b/etherlink/bin_node/lib_dev/encodings/l2_types.ml @@ -49,6 +49,20 @@ end type 'a block = Eth of 'a Ethereum_types.block +let block_hash block = match block with Eth block -> block.hash + +let block_number block = match block with Eth 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 + let decode_block_hash ~chain_family bytes = match chain_family with | EVM -> Ethereum_types.decode_block_hash bytes diff --git a/etherlink/bin_node/lib_dev/encodings/l2_types.mli b/etherlink/bin_node/lib_dev/encodings/l2_types.mli index 773c7fb975fd..10525ded1c90 100644 --- a/etherlink/bin_node/lib_dev/encodings/l2_types.mli +++ b/etherlink/bin_node/lib_dev/encodings/l2_types.mli @@ -46,6 +46,12 @@ end type 'a block = Eth of 'a Ethereum_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 decode_block_hash : chain_family:chain_family -> bytes -> Ethereum_types.block_hash diff --git a/etherlink/bin_node/lib_dev/evm_context.ml b/etherlink/bin_node/lib_dev/evm_context.ml index d73bfe6e62d5..1dd605c59293 100644 --- a/etherlink/bin_node/lib_dev/evm_context.ml +++ b/etherlink/bin_node/lib_dev/evm_context.ml @@ -605,7 +605,7 @@ module State = struct return_true | None -> return_false - let store_block_unsafe conn evm_state block = + let store_block_unsafe conn evm_state (L2_types.Eth block) = let open Lwt_result_syntax in (* Store the block itself. *) let* () = Evm_store.Blocks.store conn block in @@ -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,27 +732,32 @@ 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 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 = @@ -760,9 +767,11 @@ module State = struct 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 in return (evm_state, receipts) in @@ -794,12 +803,17 @@ 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 ; + (match block with + | Eth block -> + Lwt_watcher.notify + head_watcher + (Ethereum_types.Subscription.NewHeads block)) ; Option.iter (fun (split_level, split_timestamp) -> ctxt.session.last_split_block <- Some (split_level, split_timestamp)) @@ -856,7 +870,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 +890,13 @@ 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) in let*! () = @@ -1738,10 +1757,12 @@ 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) 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 2fd30406fea2..7259149cd5d2 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_state.ml b/etherlink/bin_node/lib_dev/evm_state.ml index 2949be64aca3..80614126e757 100644 --- a/etherlink/bin_node/lib_dev/evm_state.ml +++ b/etherlink/bin_node/lib_dev/evm_state.ml @@ -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 = @@ -388,7 +390,7 @@ let get_delayed_inbox_item evm_state hash = return res | _ -> failwith "invalid delayed inbox item" -let clear_block_storage block evm_state = +let clear_block_storage (L2_types.Eth block) evm_state = let open Lwt_syntax in (* We have 2 path to clear related to block storage: 1. The predecessor block. diff --git a/etherlink/bin_node/lib_dev/evm_state.mli b/etherlink/bin_node/lib_dev/evm_state.mli index 2c538d8ff467..48e3c21b463a 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/replay.ml b/etherlink/bin_node/lib_dev/replay.ml index 9d4b7ee4407c..937c828f72dc 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/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index 3a1f4f63d6c7..44a3414d8415 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -187,7 +187,7 @@ 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_failure -> failwith "Could not replay the block" let smart_rollup_address = Backend.smart_rollup_address -- GitLab From 9eef257ff16099ddaf0cefa039da55d45d7179d5 Mon Sep 17 00:00:00 2001 From: arnaud Date: Thu, 13 Mar 2025 18:19:28 +0100 Subject: [PATCH 09/10] Tezlink/Node: Introduce tezos_types module that is the equivalent of ethereum_types but for tezlink --- .../bin_node/lib_dev/encodings/tezos_types.ml | 42 +++++++++++++++++++ .../lib_dev/encodings/tezos_types.mli | 19 +++++++++ 2 files changed, 61 insertions(+) create mode 100644 etherlink/bin_node/lib_dev/encodings/tezos_types.ml create mode 100644 etherlink/bin_node/lib_dev/encodings/tezos_types.mli 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 000000000000..6c5403e5e2fc --- /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 000000000000..25a0c2f62add --- /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 -- GitLab From 29d86607ccddfcb703172d678acebf427b38f9e2 Mon Sep 17 00:00:00 2001 From: arnaud Date: Thu, 13 Mar 2025 17:56:57 +0100 Subject: [PATCH 10/10] EVM/Tezlink/Node: Add Tezos block in l2 types and implement common function Add a case tezos block to the type block in l2_types so that we can really introduce tezos block in the evm_node. --- .../bin_node/lib_dev/blueprint_events.ml | 37 ++++++++++++------- .../bin_node/lib_dev/encodings/l2_types.ml | 20 +++++++--- .../bin_node/lib_dev/encodings/l2_types.mli | 4 +- etherlink/bin_node/lib_dev/evm_context.ml | 24 ++++++++++-- etherlink/bin_node/lib_dev/evm_state.ml | 8 ++-- .../bin_node/lib_dev/services_backend_sig.ml | 2 + 6 files changed, 69 insertions(+), 26 deletions(-) diff --git a/etherlink/bin_node/lib_dev/blueprint_events.ml b/etherlink/bin_node/lib_dev/blueprint_events.ml index 2fc2ebc79a2d..ba5b234e5dd2 100644 --- a/etherlink/bin_node/lib_dev/blueprint_events.ml +++ b/etherlink/bin_node/lib_dev/blueprint_events.ml @@ -165,19 +165,30 @@ let blueprint_injection_failed level trace = let blueprint_applied block process_time = let open Ethereum_types in - let block = match block with L2_types.Eth block -> block 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/encodings/l2_types.ml b/etherlink/bin_node/lib_dev/encodings/l2_types.ml index e0d76ac74bcd..d4fac8bf6a6b 100644 --- a/etherlink/bin_node/lib_dev/encodings/l2_types.ml +++ b/etherlink/bin_node/lib_dev/encodings/l2_types.ml @@ -47,11 +47,13 @@ module Chain_family = struct let pp fmt cf = Format.fprintf fmt "%s" (to_string cf) end -type 'a block = Eth of 'a Ethereum_types.block +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 +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 +let block_number block = + match block with Eth block -> block.number | Tez block -> block.number let block_number_of_transactions block = match block with @@ -62,20 +64,26 @@ let block_number_of_transactions block = | 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 -> raise (Invalid_argument "TODO tezos") + | Michelson -> Tezos_types.decode_block_hash bytes let genesis_parent_hash ~chain_family = match chain_family with | EVM -> Ethereum_types.genesis_parent_hash - | Michelson -> raise (Invalid_argument "TODO tezos") + | 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 -> raise (Invalid_argument "TODO tezos") + | 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 index 10525ded1c90..c2d664f097ce 100644 --- a/etherlink/bin_node/lib_dev/encodings/l2_types.mli +++ b/etherlink/bin_node/lib_dev/encodings/l2_types.mli @@ -44,7 +44,7 @@ module Chain_family : sig val pp : Format.formatter -> chain_family -> unit end -type 'a block = Eth of 'a Ethereum_types.block +type 'a block = Eth of 'a Ethereum_types.block | Tez of Tezos_types.block val block_hash : 'a block -> Ethereum_types.block_hash @@ -52,6 +52,8 @@ 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 diff --git a/etherlink/bin_node/lib_dev/evm_context.ml b/etherlink/bin_node/lib_dev/evm_context.ml index 1dd605c59293..360722d9b463 100644 --- a/etherlink/bin_node/lib_dev/evm_context.ml +++ b/etherlink/bin_node/lib_dev/evm_context.ml @@ -605,7 +605,7 @@ module State = struct return_true | None -> return_false - let store_block_unsafe conn evm_state (L2_types.Eth block) = + let store_block_unsafe conn evm_state block = let open Lwt_result_syntax in (* Store the block itself. *) let* () = Evm_store.Blocks.store conn block in @@ -753,6 +753,9 @@ module State = struct baseFeePerGas |> Ethereum_types.Qty.to_z |> Metrics.set_gas_price) block.baseFeePerGas + | Tez _ -> + (* TODO: https://gitlab.com/tezos/tezos/-/issues/7866 *) + () in let* () = Evm_store.Blueprints.store @@ -762,7 +765,13 @@ module State = struct 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 @@ -772,6 +781,9 @@ module State = struct 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 @@ -809,11 +821,15 @@ module State = struct ctxt.session.context <- context ; ctxt.session.next_blueprint_number <- Qty (Z.succ level) ; 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)) ; + (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)) @@ -897,6 +913,7 @@ module State = struct Transaction_object.reconstruct_block payload block in return (L2_types.Eth current_block) + | Tez block -> return (L2_types.Tez block) in let*! () = @@ -1763,6 +1780,7 @@ module Handlers = struct | 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_state.ml b/etherlink/bin_node/lib_dev/evm_state.ml index 80614126e757..f9dd9175e61c 100644 --- a/etherlink/bin_node/lib_dev/evm_state.ml +++ b/etherlink/bin_node/lib_dev/evm_state.ml @@ -390,7 +390,7 @@ let get_delayed_inbox_item evm_state hash = return res | _ -> failwith "invalid delayed inbox item" -let clear_block_storage (L2_types.Eth block) evm_state = +let clear_block_storage block evm_state = let open Lwt_syntax in (* We have 2 path to clear related to block storage: 1. The predecessor block. @@ -400,11 +400,13 @@ let clear_block_storage (L2_types.Eth 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/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index 44a3414d8415..65857150f69a 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -188,6 +188,8 @@ module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct in match result with | 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 -- GitLab