diff --git a/etherlink/bin_node/lib_dev/block_storage_setup.ml b/etherlink/bin_node/lib_dev/block_storage_setup.ml index 2d80798954ffedc73608dabe751c31e6d433945a..8ff71b919201833764dce4096ca5099ca3a3dd19 100644 --- a/etherlink/bin_node/lib_dev/block_storage_setup.ml +++ b/etherlink/bin_node/lib_dev/block_storage_setup.ml @@ -82,7 +82,11 @@ let enable ~keep_alive ?evm_node_endpoint store = if enable_fallback && key = tmp_world_state_path ^ "/transactions_receipts" then Lwt_preemptive.run_in_main @@ fun () -> - let* pred = Evm_state.current_block_height tree in + let* pred = + Evm_state.current_block_height + ~root:Durable_storage_path.etherlink_root + tree + in let n = Ethereum_types.Qty.next pred in let+ block = get_block_exn n in let s = Ethereum_types.hash_to_bytes block.receiptRoot in @@ -91,7 +95,11 @@ let enable ~keep_alive ?evm_node_endpoint store = enable_fallback && key = tmp_world_state_path ^ "/transactions_objects" then Lwt_preemptive.run_in_main @@ fun () -> - let* pred = Evm_state.current_block_height tree in + let* pred = + Evm_state.current_block_height + ~root:Durable_storage_path.etherlink_root + tree + in let n = Ethereum_types.Qty.next pred in let+ block = get_block_exn n in let s = Ethereum_types.hash_to_bytes block.transactionRoot in diff --git a/etherlink/bin_node/lib_dev/blueprints_follower.ml b/etherlink/bin_node/lib_dev/blueprints_follower.ml index 38d775ed83cc7a6d0adcb00ecc3bbb151249566e..637508c61df402725c5c2d6109cf19290df2ccb3 100644 --- a/etherlink/bin_node/lib_dev/blueprints_follower.ml +++ b/etherlink/bin_node/lib_dev/blueprints_follower.ml @@ -48,7 +48,11 @@ let local_head_too_old ?remote_head ~evm_node_endpoint return (Qty remote_head) | None | Some _ -> (* See {Note keep_alive} *) - Batch.call (module Block_number) ~keep_alive:true ~evm_node_endpoint () + Batch.call + (module Generic_block_number) + ~keep_alive:true + ~evm_node_endpoint + () in return ( is_too_old ~remote:remote_head_number ~next:next_blueprint_number, diff --git a/etherlink/bin_node/lib_dev/blueprints_publisher.ml b/etherlink/bin_node/lib_dev/blueprints_publisher.ml index a5eabc415649688688e9f972386f6fbc339890c5..0ca4d2c327555dd20d3ef9b1be3d7b6e11545361 100644 --- a/etherlink/bin_node/lib_dev/blueprints_publisher.ml +++ b/etherlink/bin_node/lib_dev/blueprints_publisher.ml @@ -224,7 +224,12 @@ module Worker = struct ~base:(rollup_node_endpoint self) durable_state_value ((), Block_id.Level rollup_block_lvl) - {key = Durable_storage_path.Block.current_number} + { + key = + Durable_storage_path.Block.current_number + (* TODO: Remove etherlink root *) + ~root:Durable_storage_path.etherlink_root; + } () in match finalized_current_number with diff --git a/etherlink/bin_node/lib_dev/durable_storage.ml b/etherlink/bin_node/lib_dev/durable_storage.ml index f00662d12a782dfbec82b211fe8f9d10b8df6612..ffdeba5e37f97946f504c22c8c27589067fa464d 100644 --- a/etherlink/bin_node/lib_dev/durable_storage.ml +++ b/etherlink/bin_node/lib_dev/durable_storage.ml @@ -106,14 +106,14 @@ let is_multichain_enabled read = let* bytes_opt = read Durable_storage_path.Feature_flags.multichain in return (Option.is_some bytes_opt) -let block_number read n = +let block_number ~root read n = let open Lwt_result_syntax in match n with (* This avoids an unecessary service call in case we ask a block's number with an already expected/known block number [n]. *) | Durable_storage_path.Block.Nth i -> return @@ Ethereum_types.Qty i | Durable_storage_path.Block.Current -> ( - let+ answer = read Durable_storage_path.Block.current_number in + let+ answer = read (Durable_storage_path.Block.current_number ~root) in match answer with | Some bytes -> Ethereum_types.Qty (Bytes.to_string bytes |> Z.of_bits) | None -> @@ -176,4 +176,9 @@ module Make (Reader : READER) = struct let open Lwt_result_syntax in let* read = read_with_state () in kernel_root_hash read + + let current_block_number ~root = + let open Lwt_result_syntax in + let* read = read_with_state () in + block_number ~root read Durable_storage_path.Block.Current end diff --git a/etherlink/bin_node/lib_dev/durable_storage_path.ml b/etherlink/bin_node/lib_dev/durable_storage_path.ml index f4515d622aaa5d1c62642c9b5678e3d4b4111d03..0169894b0d5a0352999809d171e322f30171eaf6 100644 --- a/etherlink/bin_node/lib_dev/durable_storage_path.ml +++ b/etherlink/bin_node/lib_dev/durable_storage_path.ml @@ -16,6 +16,12 @@ let reboot_counter = "/readonly/kernel/env/reboot_counter" let evm_node_flag = "/__evm_node" +module Tezlink = struct + let root = "/tezlink" +end + +let tezlink_root = Tezlink.root + module EVM = struct let root = "/evm" @@ -28,6 +34,13 @@ module World_state = struct let make s = EVM.make (root ^ s) end +let etherlink_root = World_state.make "" + +let root_of_chain_family chain_family = + match chain_family with + | L2_types.EVM -> etherlink_root + | L2_types.Michelson -> tezlink_root + let chain_id = EVM.make "/chain_id" let minimum_base_fee_per_gas = World_state.make "/fees/minimum_base_fee_per_gas" @@ -142,29 +155,30 @@ end module Block = struct type number = Current | Nth of Z.t - let blocks = World_state.make "/blocks" + let blocks ~root = root ^ "/blocks" let number = "/number" - let by_hash (Block_hash (Hex hash)) = blocks ^ "/" ^ hash + let by_hash ~root (Block_hash (Hex hash)) = blocks ~root ^ "/" ^ hash - let current_number = blocks ^ "/current" ^ number + let current_number ~root = blocks ~root ^ "/current" ^ number - let current_hash = blocks ^ "/current/hash" + let current_hash ~root = blocks ~root ^ "/current/hash" end module Indexes = struct - let indexes = World_state.make "/indexes" + let indexes ~root = root ^ "/indexes" let blocks = "/blocks" - let blocks = indexes ^ blocks + let blocks ~root = indexes ~root ^ blocks let number_to_string = function | Block.Current -> "current" | Nth i -> Z.to_string i - let block_by_number number = blocks ^ "/" ^ number_to_string number + let block_by_number ~root number = + blocks ~root ^ "/" ^ number_to_string number end module Transaction_receipt = struct diff --git a/etherlink/bin_node/lib_dev/durable_storage_path.mli b/etherlink/bin_node/lib_dev/durable_storage_path.mli index cbca43891b690e296584c2532c3f69b93613b6d9..b1660f21ee4f449125a57f628f42f7d7e951858a 100644 --- a/etherlink/bin_node/lib_dev/durable_storage_path.mli +++ b/etherlink/bin_node/lib_dev/durable_storage_path.mli @@ -12,6 +12,12 @@ open Ethereum_types type path = string +val tezlink_root : path + +val etherlink_root : path + +val root_of_chain_family : L2_types.chain_family -> path + val reboot_counter : string val evm_node_flag : path @@ -89,18 +95,18 @@ module Block : sig type number = Current | Nth of Z.t (** Path to the given block. *) - val by_hash : block_hash -> path + val by_hash : root:path -> block_hash -> path (** Path to the current block number. *) - val current_number : path + val current_number : root:path -> path (** Path to the current block hash. *) - val current_hash : path + val current_hash : root:path -> path end module Indexes : sig (** Make the path to the indexed block hash. *) - val block_by_number : Block.number -> path + val block_by_number : root:path -> Block.number -> path end module Transaction_receipt : sig diff --git a/etherlink/bin_node/lib_dev/etherlink_durable_storage.ml b/etherlink/bin_node/lib_dev/etherlink_durable_storage.ml index 0234210f52882f6dd3e3da92dc8a107d865cedb9..3fe0568ff13a500f3c7eccf2afa0c3dc286a6c8a 100644 --- a/etherlink/bin_node/lib_dev/etherlink_durable_storage.ml +++ b/etherlink/bin_node/lib_dev/etherlink_durable_storage.ml @@ -8,6 +8,8 @@ open Durable_storage open Ethereum_types +let root = Durable_storage_path.etherlink_root + let balance read address = inspect_durable_and_decode_default ~default:(Ethereum_types.Qty Z.zero) @@ -53,7 +55,7 @@ let code read address = decode) let current_block_number read = - Durable_storage.block_number read Durable_storage_path.Block.Current + Durable_storage.block_number ~root read Durable_storage_path.Block.Current let un_qty (Qty z) = z @@ -83,6 +85,7 @@ let transaction_receipt read ?block_hash tx_hash = inspect_durable_and_decode read (Durable_storage_path.Indexes.block_by_number + ~root (Nth (un_qty temp_receipt.blockNumber))) decode_block_hash in @@ -118,6 +121,7 @@ let transaction_object read tx_hash = inspect_durable_and_decode read (Durable_storage_path.Indexes.block_by_number + ~root (Nth (un_qty blockNumber))) decode_block_hash in @@ -154,11 +158,11 @@ let populate_tx_objects read ~full_transaction_object let blocks_by_number read ~full_transaction_object ~number = let open Lwt_result_syntax in - let* (Ethereum_types.Qty level) = block_number read number in + let* (Ethereum_types.Qty level) = block_number ~root read number in let* block_hash_opt = inspect_durable_and_decode_opt read - (Durable_storage_path.Indexes.block_by_number (Nth level)) + (Durable_storage_path.Indexes.block_by_number ~root (Nth level)) decode_block_hash in match block_hash_opt with @@ -167,7 +171,7 @@ let blocks_by_number read ~full_transaction_object ~number = let* block_opt = inspect_durable_and_decode_opt read - (Durable_storage_path.Block.by_hash block_hash) + (Durable_storage_path.Block.by_hash ~root block_hash) Ethereum_types.block_from_rlp in match block_opt with @@ -185,7 +189,7 @@ let block_by_hash read ~full_transaction_object block_hash = let* block_opt = inspect_durable_and_decode_opt read - (Durable_storage_path.Block.by_hash block_hash) + (Durable_storage_path.Block.by_hash ~root block_hash) Ethereum_types.block_from_rlp in match block_opt with diff --git a/etherlink/bin_node/lib_dev/evm_context.ml b/etherlink/bin_node/lib_dev/evm_context.ml index 5e7464ad1c340679e4c05c465e7e93c1f4f73ba8..56df800fca340d46d10b71199b9895e1ad765596 100644 --- a/etherlink/bin_node/lib_dev/evm_context.ml +++ b/etherlink/bin_node/lib_dev/evm_context.ml @@ -521,10 +521,15 @@ module State = struct if not ctxt.legacy_block_storage then Evm_store.Blocks.find_hash_of_number conn (Qty number) else + let chain_family = + Configuration.retrieve_chain_family + ~l2_chains:ctxt.configuration.experimental_features.l2_chains + in + let root = Durable_storage_path.root_of_chain_family chain_family in let*! bytes = Evm_state.inspect evm_state - (Durable_storage_path.Indexes.block_by_number (Nth number)) + (Durable_storage_path.Indexes.block_by_number ~root (Nth number)) in return (Option.map Ethereum_types.decode_block_hash bytes) in @@ -796,7 +801,9 @@ module State = struct | Eth block -> store_block_unsafe conn evm_state block | Tez block -> store_tez_block_unsafe conn block in - let*! evm_state = Evm_state.clear_block_storage block evm_state in + let*! evm_state = + Evm_state.clear_block_storage chain_family block evm_state + in return (evm_state, receipts) else let*! receipts = @@ -1699,10 +1706,18 @@ module State = struct if not ctxt.legacy_block_storage then Evm_store.Blocks.find_hash_of_number conn (Qty pred_number) else + let chain_family = + Configuration.retrieve_chain_family + ~l2_chains:ctxt.configuration.experimental_features.l2_chains + in + let root = + Durable_storage_path.root_of_chain_family chain_family + in let*! bytes = Evm_state.inspect ctxt.session.evm_state (Durable_storage_path.Indexes.block_by_number + ~root (Nth pred_number)) in return (Option.map Ethereum_types.decode_block_hash bytes) @@ -2040,8 +2055,10 @@ let init_context_from_rollup_node ~data_dir ~rollup_node_data_dir = let*! evm_state = Irmin_context.PVMState.get evm_node_context in return (evm_node_context, evm_state, final_l2_block.header.level) -let init_store_from_rollup_node ~data_dir ~evm_state ~irmin_context = +let init_store_from_rollup_node ~chain_family ~data_dir ~evm_state + ~irmin_context = let open Lwt_result_syntax in + let root = Durable_storage_path.root_of_chain_family chain_family in (* Tell the kernel that it is executed by an EVM node *) let*! evm_state = Evm_state.flag_local_exec evm_state in (* We remove the delayed inbox from the EVM state. Its contents will be @@ -2055,7 +2072,9 @@ let init_store_from_rollup_node ~data_dir ~evm_state ~irmin_context = (* Assert we can read the current blueprint number *) let* current_blueprint_number = let*! current_blueprint_number_opt = - Evm_state.inspect evm_state Durable_storage_path.Block.current_number + Evm_state.inspect + evm_state + (Durable_storage_path.Block.current_number ~root) in match current_blueprint_number_opt with | Some bytes -> return (Bytes.to_string bytes |> Z.of_bits) @@ -2065,7 +2084,9 @@ let init_store_from_rollup_node ~data_dir ~evm_state ~irmin_context = (* Assert we can read the current block hash *) let* () = let*! current_block_hash_opt = - Evm_state.inspect evm_state Durable_storage_path.Block.current_hash + Evm_state.inspect + evm_state + (Durable_storage_path.Block.current_hash ~root) in match current_block_hash_opt with | Some _bytes -> return_unit @@ -2132,7 +2153,17 @@ let init_from_rollup_node ~configuration ~omit_delayed_tx_events ~data_dir let* evm_events = get_evm_events_from_rollup_node_state ~omit_delayed_tx_events evm_state in - let* () = init_store_from_rollup_node ~data_dir ~evm_state ~irmin_context in + let chain_family = + Configuration.retrieve_chain_family + ~l2_chains:configuration.Configuration.experimental_features.l2_chains + in + let* () = + init_store_from_rollup_node + ~chain_family + ~data_dir + ~evm_state + ~irmin_context + in let* smart_rollup_address, _genesis_level = rollup_node_metadata ~rollup_node_data_dir in diff --git a/etherlink/bin_node/lib_dev/evm_ro_context.ml b/etherlink/bin_node/lib_dev/evm_ro_context.ml index d2643b75030ce2dc1a6d708965a6ed53a47d20c7..c4431fc8fc7675747b2a83dbc8f60e9ad3ecd96b 100644 --- a/etherlink/bin_node/lib_dev/evm_ro_context.ml +++ b/etherlink/bin_node/lib_dev/evm_ro_context.ml @@ -161,8 +161,9 @@ let get_irmin_hash_from_block_hash ~chain_family ctxt hash = (* we use the latest state to read the contents of the block *) let* latest_hash = find_latest_hash ctxt in let* evm_tree = get_evm_state ctxt latest_hash in + let root = Durable_storage_path.root_of_chain_family chain_family in let*! res = - Evm_state.inspect evm_tree Durable_storage_path.Block.(by_hash hash) + Evm_state.inspect evm_tree Durable_storage_path.Block.(by_hash ~root hash) in match res with | Some block_bytes -> @@ -357,9 +358,10 @@ struct Evm_store.use Ctxt.ctxt.store @@ fun conn -> Evm_store.L1_l2_finalized_levels.find conn ~l1_level - let block_param_to_block_number + let block_param_to_block_number ~chain_family (block_param : Ethereum_types.Block_parameter.extended) = let open Lwt_result_syntax in + let root = Durable_storage_path.root_of_chain_family chain_family in match block_param with | Block_parameter (Number n) -> return n | Block_parameter (Latest | Pending) when Ctxt.ctxt.finalized_view -> ( @@ -392,12 +394,14 @@ struct let* irmin_hash = find_irmin_hash Ctxt.ctxt block_param in let* evm_state = get_evm_state Ctxt.ctxt irmin_hash in let*! bytes = - Evm_state.inspect evm_state Durable_storage_path.(Block.by_hash hash) + Evm_state.inspect + evm_state + Durable_storage_path.(Block.by_hash ~root hash) in match bytes with | Some bytes -> - let block = Ethereum_types.block_from_rlp bytes in - return block.number + let block = L2_types.block_from_bytes ~chain_family bytes in + return (L2_types.block_number block) | None -> failwith "Missing block %a" Ethereum_types.pp_block_hash hash) end @@ -539,7 +543,7 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) module Tracer_etherlink = Tracer_sig.Make (Executor) (Etherlink_block_storage) (Tracer) - let block_param_to_block_number + let block_param_to_block_number ~chain_family (block_param : Ethereum_types.Block_parameter.extended) = let open Lwt_result_syntax in match block_param with @@ -550,7 +554,7 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) | Some number -> return number | None -> failwith "Missing block %a" Ethereum_types.pp_block_hash hash) - | param -> block_param_to_block_number param + | param -> block_param_to_block_number ~chain_family param module Tezlink_block_storage : Tezlink_block_storage_sig.S = struct let nth_block level = @@ -572,7 +576,8 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) (struct include Backend.Reader - let block_param_to_block_number = block_param_to_block_number + let block_param_to_block_number = + block_param_to_block_number ~chain_family:L2_types.Michelson end) (Tezlink_block_storage) end) diff --git a/etherlink/bin_node/lib_dev/evm_state.ml b/etherlink/bin_node/lib_dev/evm_state.ml index efa0232acc66a0aaca25cd5ee31307282b59e55c..e23fa9ef23df3d979635787077b77c07a00111c7 100644 --- a/etherlink/bin_node/lib_dev/evm_state.ml +++ b/etherlink/bin_node/lib_dev/evm_state.ml @@ -221,10 +221,10 @@ let kernel_version evm_state = let+ version = inspect evm_state Durable_storage_path.kernel_version in match version with Some v -> Bytes.unsafe_to_string v | None -> "(unknown)" -let current_block_height evm_state = +let current_block_height ~root evm_state = let open Lwt_syntax in let* current_block_number = - inspect evm_state Durable_storage_path.Block.current_number + inspect evm_state (Durable_storage_path.Block.current_number ~root) in match current_block_number with | None -> @@ -239,8 +239,9 @@ let current_block_height evm_state = let current_block_hash ~chain_family evm_state = let open Lwt_result_syntax in + let root = Durable_storage_path.root_of_chain_family chain_family in let*! current_hash = - inspect evm_state Durable_storage_path.Block.current_hash + inspect evm_state (Durable_storage_path.Block.current_hash ~root) in match current_hash with | Some h -> return (decode_block_hash h) @@ -325,12 +326,13 @@ let apply_blueprint ?wasm_pvm_fallback ?log_file ?profile ~data_dir ~chain_family ~config ~native_execution_policy evm_state (blueprint : Blueprint_types.payload) = let open Lwt_result_syntax in + let root = Durable_storage_path.root_of_chain_family chain_family in let exec_inputs = List.map (function `External payload -> `Input ("\001" ^ payload)) blueprint in - let*! (Qty before_height) = current_block_height evm_state in + let*! (Qty before_height) = current_block_height ~root evm_state in let* evm_state = execute ~native_execution:(native_execution_policy = Configuration.Always) @@ -344,9 +346,10 @@ let apply_blueprint ?wasm_pvm_fallback ?log_file ?profile ~data_dir exec_inputs in let* block_hash = current_block_hash ~chain_family evm_state in + let root = Durable_storage_path.root_of_chain_family chain_family in let* block = let*! bytes = - inspect evm_state (Durable_storage_path.Block.by_hash block_hash) + inspect evm_state (Durable_storage_path.Block.by_hash ~root block_hash) in return (Option.map (L2_types.block_from_bytes ~chain_family) bytes) in @@ -421,7 +424,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 chain_family block evm_state = let open Lwt_syntax in (* We have 2 path to clear related to block storage: 1. The predecessor block. @@ -431,13 +434,16 @@ 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 root = Durable_storage_path.root_of_chain_family chain_family 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 ~root block_parent + in delete ~kind:Value evm_state pred_block_path else return evm_state in @@ -451,6 +457,7 @@ let clear_block_storage block evm_state = if number >= to_keep then let index_path = Durable_storage_path.Indexes.block_by_number + ~root (Nth (Z.sub number to_keep)) in delete ~kind:Value evm_state index_path diff --git a/etherlink/bin_node/lib_dev/evm_state.mli b/etherlink/bin_node/lib_dev/evm_state.mli index dc95edf0a381caca7d909fe2713c02d3f06ff0df..6c0b2502b31ff8813b823ba6218878ffa4e0ad52 100644 --- a/etherlink/bin_node/lib_dev/evm_state.mli +++ b/etherlink/bin_node/lib_dev/evm_state.mli @@ -72,9 +72,10 @@ val execute_and_inspect : t -> bytes option list tzresult Lwt.t -(** [current_block_height evm_state] returns the height of the latest block - produced by the kernel. *) -val current_block_height : t -> Ethereum_types.quantity Lwt.t +(** [current_block_height ~root evm_state] returns the height of the latest + block produced by the kernel at [root]. *) +val current_block_height : + root:Durable_storage_path.path -> t -> Ethereum_types.quantity Lwt.t (** Same as {!current_block_height} for the block hash. *) val current_block_hash : @@ -135,10 +136,11 @@ val preload_kernel : t -> unit Lwt.t val get_delayed_inbox_item : t -> Ethereum_types.hash -> Evm_events.Delayed_transaction.t tzresult Lwt.t -(**[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 L2_types.block -> t -> t Lwt.t +(** [clear_block_storage chain_family 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 : + L2_types.chain_family -> '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/filter_helpers.ml b/etherlink/bin_node/lib_dev/filter_helpers.ml index b4d33609f2972aff8ad49419e87b43b908d190af..6dffbb19ba2407ad61783b4a1b886e26d01fec65 100644 --- a/etherlink/bin_node/lib_dev/filter_helpers.ml +++ b/etherlink/bin_node/lib_dev/filter_helpers.ml @@ -91,6 +91,7 @@ let validate_range log_filter_config | {from_block; to_block; _} -> let get_block_number block_param = Rollup_node_rpc.block_param_to_block_number + ~chain_family:L2_types.EVM (Block_parameter (Option.value ~default:Block_parameter.Latest block_param)) in diff --git a/etherlink/bin_node/lib_dev/rollup_node.ml b/etherlink/bin_node/lib_dev/rollup_node.ml index d4ec4c1962eeac28c212e6042e3aa7f6955298e4..ae520f300a72db12ca3db597b0d081938f3dda76 100644 --- a/etherlink/bin_node/lib_dev/rollup_node.ml +++ b/etherlink/bin_node/lib_dev/rollup_node.ml @@ -158,13 +158,14 @@ end) : Services_backend_sig.Backend = struct | _ -> failwith "Inconsistent simulation results" end - let block_param_to_block_number + let block_param_to_block_number ~chain_family (block_param : Ethereum_types.Block_parameter.extended) = let open Lwt_result_syntax in + let root = Durable_storage_path.root_of_chain_family chain_family in let read_from_block_parameter param = let* state = Reader.get_state ~block:(Block_parameter param) () in let* value = - Reader.read state Durable_storage_path.Block.current_number + Reader.read state (Durable_storage_path.Block.current_number ~root) in match value with | Some value -> @@ -176,12 +177,12 @@ end) : Services_backend_sig.Backend = struct | Block_hash {hash; _} -> ( let* state = Reader.get_state ~block:(Block_parameter Latest) () in let* value = - Reader.read state (Durable_storage_path.Block.by_hash hash) + Reader.read state (Durable_storage_path.Block.by_hash ~root hash) in match value with | Some value -> - let block = Ethereum_types.block_from_rlp value in - return block.number + let block = L2_types.block_from_bytes ~chain_family value in + return (L2_types.block_number block) | None -> failwith "Missing state for block %a" diff --git a/etherlink/bin_node/lib_dev/rpc_encodings.ml b/etherlink/bin_node/lib_dev/rpc_encodings.ml index 151805da56d2f880123dcb4a5c9f115d48351a74..6ffe10d318b3ef4b20abea84a5b347d542c0790f 100644 --- a/etherlink/bin_node/lib_dev/rpc_encodings.ml +++ b/etherlink/bin_node/lib_dev/rpc_encodings.ml @@ -217,6 +217,22 @@ module Kernel_root_hash = struct type ('input, 'output) method_ += Method : (input, output) method_ end +module Generic_block_number = struct + open Ethereum_types + + type input = unit + + type output = quantity + + let input_encoding = Data_encoding.unit + + let output_encoding = quantity_encoding + + let method_ = "tez_blockNumber" + + type ('input, 'output) method_ += Method : (input, output) method_ +end + module Network_id = struct type input = unit @@ -1025,11 +1041,17 @@ type map_result = let evm_supported_methods : (module METHOD) list = [ + (* Generic rpcs *) + (module Generic_block_number); (module Kernel_version); (module Kernel_root_hash); (module Network_id); (module Chain_id); (module Chain_family); + (module Durable_state_value); + (module Durable_state_subkeys); + (module Get_finalized_blocks_of_l1_level); + (* Etherlink rpcs *) (module Accounts); (module Get_balance); (module Get_storage_at); @@ -1060,8 +1082,6 @@ let evm_supported_methods : (module METHOD) list = (module Produce_block); (module Produce_proposal); (module Inject_transaction); - (module Durable_state_value); - (module Durable_state_subkeys); (module Eth_max_priority_fee_per_gas); (module Replay_block); (module Trace_transaction); @@ -1071,7 +1091,6 @@ let evm_supported_methods : (module METHOD) list = (module Subscribe); (module Unsubscribe); (module Trace_block); - (module Get_finalized_blocks_of_l1_level); ] let evm_unsupported_methods : string list = @@ -1126,7 +1145,7 @@ let michelson_supported_methods = evm_supported_methods let multichain_sequencer_supported_methods : (module METHOD) list = [ - (module Block_number); + (module Generic_block_number); (module Send_raw_transaction); (* Private RPCs *) (module Produce_block); diff --git a/etherlink/bin_node/lib_dev/rpc_encodings.mli b/etherlink/bin_node/lib_dev/rpc_encodings.mli index 362b8d60859a7d8e90391c37f1526800e4b3783b..ae6d35378e9bab5f68856d6f5f0a23810c3332c3 100644 --- a/etherlink/bin_node/lib_dev/rpc_encodings.mli +++ b/etherlink/bin_node/lib_dev/rpc_encodings.mli @@ -161,6 +161,9 @@ module Get_storage_at : * Ethereum_types.Block_parameter.extended and type output = Ethereum_types.hex +module Generic_block_number : + METHOD with type input = unit and type output = Ethereum_types.quantity + module Block_number : METHOD with type input = unit and type output = Ethereum_types.quantity diff --git a/etherlink/bin_node/lib_dev/services.ml b/etherlink/bin_node/lib_dev/services.ml index 6db4e109c1fdb42f04a3fd778718a416b3962c7d..3fd9c599ec62212d156d00739f0f3b0577c4427a 100644 --- a/etherlink/bin_node/lib_dev/services.ml +++ b/etherlink/bin_node/lib_dev/services.ml @@ -178,7 +178,9 @@ let get_block_by_number ~full_transaction_object block_param (module Rollup_node_rpc : Services_backend_sig.S) = let open Lwt_result_syntax in let* (Ethereum_types.Qty n) = - Rollup_node_rpc.block_param_to_block_number (Block_parameter block_param) + Rollup_node_rpc.block_param_to_block_number + ~chain_family:L2_types.EVM + (Block_parameter block_param) in Rollup_node_rpc.Etherlink_block_storage.nth_block ~full_transaction_object n @@ -186,7 +188,9 @@ let get_block_receipts block_param (module Rollup_node_rpc : Services_backend_sig.S) = let open Lwt_result_syntax in let* (Ethereum_types.Qty n) = - Rollup_node_rpc.block_param_to_block_number (Block_parameter block_param) + Rollup_node_rpc.block_param_to_block_number + ~chain_family:L2_types.EVM + (Block_parameter block_param) in Rollup_node_rpc.Etherlink_block_storage.block_receipts n @@ -545,6 +549,19 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) rpc_ok value in build_with_input ~f module_ parameters + | Generic_block_number.Method -> + let f (_ : unit option) = + let chain_family = + Configuration.retrieve_chain_family + ~l2_chains:config.experimental_features.l2_chains + in + let root = + Durable_storage_path.root_of_chain_family chain_family + in + let* block_number = Backend_rpc.current_block_number ~root in + rpc_ok block_number + in + build ~f module_ parameters | Block_number.Method -> let f (_ : unit option) = let* block_number = @@ -915,6 +932,7 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) let f ((block_param, config) : Tracer_types.block_input) = let* (Ethereum_types.Qty block_number) = Backend_rpc.block_param_to_block_number + ~chain_family:L2_types.EVM (Block_parameter block_param) in let*! traces = diff --git a/etherlink/bin_node/lib_dev/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index c6b181962b55f950b4ee807f4684a032fe75cb0a..7bf936c5e6d4635a3458ae34bc11e4a2f45a7acd 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -16,9 +16,15 @@ module type S = sig module Tracer_etherlink : Tracer_sig.S val block_param_to_block_number : + chain_family:L2_types.chain_family -> Ethereum_types.Block_parameter.extended -> Ethereum_types.quantity tzresult Lwt.t + (** [current_block_number ~root] returns the current block number of the L2 chain + prefixed by [root] (depending on the chain_family in the configuration) *) + val current_block_number : + root:string -> Ethereum_types.quantity tzresult Lwt.t + (** [chain_id ()] returns chain id defined by the rollup. *) val chain_id : unit -> L2_types.chain_id tzresult Lwt.t @@ -84,6 +90,7 @@ module type Backend = sig (** [block_param_to_block_number block_param] returns the block number of the block identified by [block_param]. *) val block_param_to_block_number : + chain_family:L2_types.chain_family -> Ethereum_types.Block_parameter.extended -> Ethereum_types.quantity tzresult Lwt.t @@ -129,7 +136,8 @@ module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct (struct include Backend.Reader - let block_param_to_block_number = Backend.block_param_to_block_number + let block_param_to_block_number = + Backend.block_param_to_block_number ~chain_family:L2_types.Michelson end) (Tezlink_block_storage) diff --git a/etherlink/bin_node/lib_dev/tezlink_durable_storage.ml b/etherlink/bin_node/lib_dev/tezlink_durable_storage.ml index 7b51ac27b6be908fe6de5b75c3671d47aba68a4e..af9fafc77176e7d513a7b129777a69bdeb0970d6 100644 --- a/etherlink/bin_node/lib_dev/tezlink_durable_storage.ml +++ b/etherlink/bin_node/lib_dev/tezlink_durable_storage.ml @@ -7,6 +7,8 @@ (*****************************************************************************) open Tezos_types +let root = Durable_storage_path.tezlink_root + module Path = struct (** [to_path encoding value] uses [encoding] to encode [value] in hexadecimal *) @@ -50,11 +52,13 @@ let counter read c = let nth_block read n = let open Lwt_result_syntax in let number = Durable_storage_path.Block.(Nth n) in - let* (Ethereum_types.Qty level) = Durable_storage.block_number read number in + let* (Ethereum_types.Qty level) = + Durable_storage.block_number ~root read number + in let* block_hash_opt = Durable_storage.inspect_durable_and_decode_opt read - (Durable_storage_path.Indexes.block_by_number (Nth level)) + (Durable_storage_path.Indexes.block_by_number ~root (Nth level)) Ethereum_types.decode_block_hash in match block_hash_opt with @@ -63,7 +67,7 @@ let nth_block read n = let* block_opt = Durable_storage.inspect_durable_and_decode_opt read - (Durable_storage_path.Block.by_hash block_hash) + (Durable_storage_path.Block.by_hash ~root block_hash) L2_types.Tezos_block.block_from_binary in match block_opt with @@ -76,7 +80,7 @@ let nth_block_hash read n = let number = Durable_storage_path.Block.(Nth n) in Durable_storage.inspect_durable_and_decode_opt read - (Durable_storage_path.Indexes.block_by_number number) + (Durable_storage_path.Indexes.block_by_number ~root number) Ethereum_types.decode_block_hash module Make_block_storage (Reader : Durable_storage.READER) : diff --git a/etherlink/kernel_latest/kernel/src/block.rs b/etherlink/kernel_latest/kernel/src/block.rs index e13383e64dbb0628f93ab5f392f6b4ce835b4962..078f480a3ef9860cb0892fd3cbd88bb2fd9c77a4 100644 --- a/etherlink/kernel_latest/kernel/src/block.rs +++ b/etherlink/kernel_latest/kernel/src/block.rs @@ -41,7 +41,7 @@ use tezos_evm_runtime::runtime::Runtime; use tezos_evm_runtime::safe_storage::SafeStorage; use tezos_smart_rollup::outbox::OutboxQueue; use tezos_smart_rollup::types::Timestamp; -use tezos_smart_rollup_host::path::Path; +use tezos_smart_rollup_host::path::{OwnedPath, Path}; pub const GENESIS_PARENT_HASH: H256 = H256([0xff; 32]); @@ -478,7 +478,10 @@ pub fn produce( let mut tick_counter = TickCounter::new(0u64); - let mut safe_host = SafeStorage { host }; + let mut safe_host = SafeStorage { + host, + world_state: OwnedPath::from(&chain_config.storage_root_path()), + }; let outbox_queue = OutboxQueue::new(&WITHDRAWAL_OUTBOX_QUEUE, u32::MAX)?; let precompiles = chain_config.precompiles_set(config.enable_fa_bridge); @@ -595,13 +598,10 @@ pub fn produce( mod tests { use super::*; use crate::block_storage; - use crate::block_storage::read_current_number; use crate::blueprint::Blueprint; use crate::blueprint_storage::store_inbox_blueprint; use crate::blueprint_storage::store_inbox_blueprint_by_number; - use crate::chains::{ - ChainFamily, EvmChainConfig, MichelsonChainConfig, TezTransactions, - }; + use crate::chains::{EvmChainConfig, MichelsonChainConfig, TezTransactions}; use crate::fees::DA_FEE_PER_BYTE; use crate::fees::MINIMUM_BASE_FEE_PER_GAS; use crate::storage::read_block_in_progress; @@ -629,6 +629,13 @@ mod tests { use tezos_evm_runtime::runtime::MockKernelHost; use tezos_evm_runtime::runtime::Runtime; use tezos_smart_rollup_encoding::timestamp::Timestamp; + use tezos_smart_rollup_host::path::concat; + use tezos_smart_rollup_host::path::RefPath; + + fn read_current_number(host: &impl Runtime) -> anyhow::Result { + Ok(crate::blueprint_storage::read_current_blueprint_header(host)?.number) + } + use tezos_smart_rollup_host::runtime::Runtime as SdkRuntime; fn blueprint(transactions: Vec) -> Blueprint { @@ -883,8 +890,15 @@ mod tests { .expect("The block production failed."); } - fn assert_current_block_reading_validity(host: &mut Host) { - match block_storage::read_current(host, &ChainFamily::Evm) { + fn assert_current_block_reading_validity( + host: &mut Host, + chain_config: &impl ChainConfigTrait, + ) { + match block_storage::read_current( + host, + &chain_config.storage_root_path(), + &chain_config.get_chain_family(), + ) { Ok(_) => (), Err(e) => { panic!("Block reading failed: {:?}\n", e) @@ -900,6 +914,16 @@ mod tests { let chain_config = dummy_tez_config(); let mut config = dummy_configuration(); + // We need to store something at the tezlink root path, + // otherwise the copy of the root done by the safe storage will fail + let path = concat( + &chain_config.storage_root_path(), + &RefPath::assert_from(b"/fee"), + ) + .expect("Path concatenation should have succeeded"); + host.store_write_all(&path, &[4; 32]) + .expect("Write in durable storage should have succeeded"); + store_blueprints::<_, MichelsonChainConfig>( &mut host, vec![ @@ -1213,11 +1237,13 @@ mod tests { fn test_read_storage_current_block_after_block_production_with_filled_queue() { let mut host = MockKernelHost::default(); + let chain_config = dummy_evm_config(EVMVersion::current_test_config()); + let mut evm_account_storage = init_account_storage().unwrap(); produce_block_with_several_valid_txs(&mut host, &mut evm_account_storage); - assert_current_block_reading_validity(&mut host); + assert_current_block_reading_validity(&mut host, &chain_config); } #[test] @@ -1282,8 +1308,11 @@ mod tests { ) .unwrap(); - let blocks_index = - block_storage::internal_for_tests::init_blocks_index().unwrap(); + let chain_config = dummy_evm_config(EVMVersion::current_test_config()); + let blocks_index = block_storage::internal_for_tests::init_blocks_index( + &chain_config.storage_root_path(), + ) + .unwrap(); store_blueprints::<_, EvmChainConfig>(&mut host, vec![blueprint(vec![])]); @@ -1299,7 +1328,7 @@ mod tests { store_block_fees(&mut host, &dummy_block_fees()).unwrap(); produce( &mut host, - &dummy_evm_config(EVMVersion::current_test_config()), + &chain_config, &mut dummy_configuration(), None, None, @@ -1308,12 +1337,15 @@ mod tests { let new_number_of_blocks_indexed = blocks_index.length(&host).unwrap(); - let current_block_hash = - block_storage::read_current(&mut host, &ChainFamily::Evm) - .unwrap() - .hash() - .as_bytes() - .to_vec(); + let current_block_hash = block_storage::read_current( + &mut host, + &chain_config.storage_root_path(), + &chain_config.get_chain_family(), + ) + .unwrap() + .hash() + .as_bytes() + .to_vec(); assert_eq!(number_of_blocks_indexed + 1, new_number_of_blocks_indexed); @@ -1496,8 +1528,8 @@ mod tests { } fn check_current_block_number(host: &mut Host, nb: usize) { - let current_nb = block_storage::read_current_number(host) - .expect("Should have manage to check block number"); + let current_nb = + read_current_number(host).expect("Should have manage to check block number"); assert_eq!(current_nb, U256::from(nb), "Incorrect block number"); } @@ -1505,13 +1537,14 @@ mod tests { fn test_first_blocks() { let mut host = MockKernelHost::default(); + let chain_config = dummy_evm_config(EVMVersion::current_test_config()); // first block should be 0 let blueprint = almost_empty_blueprint(); store_inbox_blueprint(&mut host, blueprint).expect("Should store a blueprint"); store_block_fees(&mut host, &dummy_block_fees()).unwrap(); produce( &mut host, - &dummy_evm_config(EVMVersion::current_test_config()), + &chain_config, &mut dummy_configuration(), None, None, @@ -1524,7 +1557,7 @@ mod tests { store_inbox_blueprint(&mut host, blueprint).expect("Should store a blueprint"); produce( &mut host, - &dummy_evm_config(EVMVersion::current_test_config()), + &chain_config, &mut dummy_configuration(), None, None, @@ -1537,7 +1570,7 @@ mod tests { store_inbox_blueprint(&mut host, blueprint).expect("Should store a blueprint"); produce( &mut host, - &dummy_evm_config(EVMVersion::current_test_config()), + &chain_config, &mut dummy_configuration(), None, None, @@ -1612,7 +1645,7 @@ mod tests { // sanity check: no current block assert!( - block_storage::read_current_number(&host).is_err(), + read_current_number(&host).is_err(), "Should not have found current block number" ); @@ -1661,7 +1694,7 @@ mod tests { // test no new block assert!( - block_storage::read_current_number(&host).is_err(), + read_current_number(&host).is_err(), "Should not have found current block number" ); @@ -1669,7 +1702,10 @@ mod tests { matches!(computation_result, ComputationResult::RebootNeeded); // The block is in progress, therefore it is in the safe storage. - let safe_host = SafeStorage { host: &mut host }; + let safe_host = SafeStorage { + host: &mut host, + world_state: OwnedPath::from(&chain_config.storage_root_path()), + }; let bip = read_block_in_progress(&safe_host) .expect("Should be able to read the block in progress") .expect("The reboot context should have a block in progress"); @@ -1702,7 +1738,7 @@ mod tests { // sanity check: no current block assert!( - block_storage::read_current_number(&host).is_err(), + read_current_number(&host).is_err(), "Should not have found current block number" ); //provision sender account @@ -1757,8 +1793,7 @@ mod tests { // test no new block assert_eq!( - block_storage::read_current_number(&host) - .expect("should have found a block number"), + read_current_number(&host).expect("should have found a block number"), U256::zero(), "There should have been one block registered" ); @@ -1767,7 +1802,10 @@ mod tests { matches!(computation_result, ComputationResult::RebootNeeded); // The block is in progress, therefore it is in the safe storage. - let safe_host = SafeStorage { host: &mut host }; + let safe_host = SafeStorage { + host: &mut host, + world_state: OwnedPath::from(&chain_config.storage_root_path()), + }; let bip = read_block_in_progress(&safe_host) .expect("Should be able to read the block in progress") .expect("The reboot context should have a block in progress"); diff --git a/etherlink/kernel_latest/kernel/src/block_in_progress.rs b/etherlink/kernel_latest/kernel/src/block_in_progress.rs index 44416d29203f9d5b4f18aab899ae4b228bd3dbc9..21552bef70648b5e2d9d51fb76b4ab7ca5c289c4 100644 --- a/etherlink/kernel_latest/kernel/src/block_in_progress.rs +++ b/etherlink/kernel_latest/kernel/src/block_in_progress.rs @@ -7,6 +7,7 @@ use crate::apply::{TransactionObjectInfo, TransactionReceiptInfo}; use crate::block_storage; +use crate::chains::ETHERLINK_SAFE_STORAGE_ROOT_PATH; use crate::error::Error; use crate::error::TransferError::CumulativeGasUsedOverflow; use crate::gas_price::base_fee_per_gas; @@ -481,7 +482,7 @@ impl EthBlockInProgress { base_fee_per_gas, ); let new_block = L2Block::Etherlink(Box::new(new_block)); - block_storage::store_current(host, &new_block) + block_storage::store_current(host, ÐERLINK_SAFE_STORAGE_ROOT_PATH, &new_block) .context("Failed to store the current block")?; Ok(new_block) } diff --git a/etherlink/kernel_latest/kernel/src/block_storage.rs b/etherlink/kernel_latest/kernel/src/block_storage.rs index 88f560398a8bb938da99d5a6c5723274b2777b61..1544192cb693641d141c97f804e84b73ce798988 100644 --- a/etherlink/kernel_latest/kernel/src/block_storage.rs +++ b/etherlink/kernel_latest/kernel/src/block_storage.rs @@ -9,9 +9,9 @@ use tezos_evm_logging::{ }; use tezos_evm_runtime::runtime::Runtime; use tezos_indexable_storage::IndexableStorage; -use tezos_smart_rollup_host::path::concat; use tezos_smart_rollup_host::path::OwnedPath; use tezos_smart_rollup_host::path::RefPath; +use tezos_smart_rollup_host::path::{concat, Path}; use tezos_storage::{read_h256_be, read_u256_le, write_h256_be, write_u256_le}; use crate::storage::EVM_TRANSACTIONS_OBJECTS; @@ -19,59 +19,92 @@ use crate::storage::EVM_TRANSACTIONS_RECEIPTS; use crate::{chains::ChainFamily, l2block::L2Block, migration::allow_path_not_found}; mod path { + use tezos_smart_rollup_host::path::Path; + use super::*; - pub const PATH: RefPath = RefPath::assert_from(b"/evm/world_state/blocks"); + const CURRENT_NUMBER: RefPath = RefPath::assert_from(b"/blocks/current/number"); + + pub fn current_number( + root: &impl Path, + ) -> Result { + concat(root, &CURRENT_NUMBER) + } + + const CURRENT_HASH: RefPath = RefPath::assert_from(b"/blocks/current/hash"); + + pub fn current_hash( + root: &impl Path, + ) -> Result { + concat(root, &CURRENT_HASH) + } - pub const CURRENT_NUMBER: RefPath = - RefPath::assert_from(b"/evm/world_state/blocks/current/number"); - pub const CURRENT_HASH: RefPath = - RefPath::assert_from(b"/evm/world_state/blocks/current/hash"); + pub fn blocks( + root: &impl Path, + ) -> Result { + concat(root, &RefPath::assert_from(b"/blocks")) + } - pub const INDEXES: RefPath = RefPath::assert_from(b"/evm/world_state/indexes/blocks"); + const INDEXES: RefPath = RefPath::assert_from(b"/indexes/blocks"); + + pub fn indexes( + root: &impl Path, + ) -> Result { + concat(root, &INDEXES) + } /// Path to the block in the storage. The path to the block is /// indexed by its hash. - pub fn path(hash: H256) -> anyhow::Result { + pub fn path(root: &impl Path, hash: H256) -> anyhow::Result { let hash = hex::encode(hash); let raw_hash_path: Vec = format!("/{}", &hash).into(); let hash_path = OwnedPath::try_from(raw_hash_path)?; - Ok(concat(&PATH, &hash_path)?) + Ok(concat(&blocks(root)?, &hash_path)?) } } -fn store_current_number(host: &mut impl Runtime, number: U256) -> anyhow::Result<()> { - Ok(write_u256_le(host, &path::CURRENT_NUMBER, number)?) +fn store_current_number( + host: &mut impl Runtime, + root: &impl Path, + number: U256, +) -> anyhow::Result<()> { + Ok(write_u256_le(host, &path::current_number(root)?, number)?) } -fn store_current_hash(host: &mut impl Runtime, hash: H256) -> anyhow::Result<()> { - write_h256_be(host, &path::CURRENT_HASH, hash) +fn store_current_hash( + host: &mut impl Runtime, + root: &impl Path, + hash: H256, +) -> anyhow::Result<()> { + write_h256_be(host, &path::current_hash(root)?, hash) } fn store_block( host: &mut impl Runtime, + root: &impl Path, block: &L2Block, index_block: bool, ) -> anyhow::Result<()> { if index_block { // Index the block, /evm/world_state/indexes/blocks/ points to // the block hash. - let index = IndexableStorage::new(&path::INDEXES)?; + let index = IndexableStorage::new_owned_path(path::indexes(root)?); index.push_value(host, block.hash().as_bytes())?; } - let path = path::path(block.hash())?; + let path = path::path(root, block.hash())?; let bytes = block.to_bytes(); Ok(host.store_write_all(&path, &bytes)?) } fn store_current_index_or_not( host: &mut impl Runtime, + root: &impl Path, block: &L2Block, index_block: bool, ) -> anyhow::Result<()> { - store_current_number(host, block.number())?; - store_current_hash(host, block.hash())?; - store_block(host, block, index_block)?; + store_current_number(host, root, block.number())?; + store_current_hash(host, root, block.hash())?; + store_block(host, root, block, index_block)?; log!( host, Info, @@ -84,28 +117,40 @@ fn store_current_index_or_not( Ok(()) } -pub fn store_current(host: &mut impl Runtime, block: &L2Block) -> anyhow::Result<()> { - store_current_index_or_not(host, block, true) +pub fn store_current( + host: &mut impl Runtime, + root: &impl Path, + block: &L2Block, +) -> anyhow::Result<()> { + store_current_index_or_not(host, root, block, true) } -pub fn restore_current(host: &mut impl Runtime, block: &L2Block) -> anyhow::Result<()> { - store_current_index_or_not(host, block, false) +pub fn restore_current( + host: &mut impl Runtime, + root: &impl Path, + block: &L2Block, +) -> anyhow::Result<()> { + store_current_index_or_not(host, root, block, false) } -pub fn read_current_number(host: &impl Runtime) -> anyhow::Result { - Ok(read_u256_le(host, &path::CURRENT_NUMBER)?) +pub fn read_current_number( + host: &impl Runtime, + root: &impl Path, +) -> anyhow::Result { + Ok(read_u256_le(host, &path::current_number(root)?)?) } -pub fn read_current_hash(host: &impl Runtime) -> anyhow::Result { - read_h256_be(host, &path::CURRENT_HASH) +pub fn read_current_hash(host: &impl Runtime, root: &impl Path) -> anyhow::Result { + read_h256_be(host, &path::current_hash(root)?) } pub fn read_current( host: &mut impl Runtime, + root: &impl Path, chain_family: &ChainFamily, ) -> anyhow::Result { - let hash = read_current_hash(host)?; - let block_path = path::path(hash)?; + let hash = read_current_hash(host, root)?; + let block_path = path::path(root, hash)?; let bytes = &host.store_read_all(&block_path)?; let block_from_bytes = L2Block::try_from_bytes(chain_family, bytes)?; Ok(block_from_bytes) @@ -113,14 +158,15 @@ pub fn read_current( pub fn garbage_collect_blocks( host: &mut impl Runtime, + root: &impl Path, chain_family: &ChainFamily, ) -> anyhow::Result<()> { log!(host, Debug, "Garbage collecting blocks."); - if let Ok(block) = read_current(host, chain_family) { + if let Ok(block) = read_current(host, root, chain_family) { // The kernel needs the current block to process the next one. Therefore // we garbage collect everything but the current block. - host.store_delete(&path::PATH)?; - restore_current(host, &block)?; + host.store_delete(&path::blocks(root)?)?; + restore_current(host, root, &block)?; // Clean all transactions, they are unused by the kernel. allow_path_not_found(host.store_delete(&EVM_TRANSACTIONS_OBJECTS))?; allow_path_not_found(host.store_delete(&EVM_TRANSACTIONS_RECEIPTS))?; @@ -132,14 +178,15 @@ pub fn garbage_collect_blocks( pub mod internal_for_tests { use super::*; - pub fn init_blocks_index() -> anyhow::Result { - Ok(IndexableStorage::new(&path::INDEXES)?) + pub fn init_blocks_index(root: &impl Path) -> anyhow::Result { + Ok(IndexableStorage::new_owned_path(path::indexes(root)?)) } pub fn store_current_number( host: &mut impl Runtime, + root: &impl Path, number: U256, ) -> anyhow::Result<()> { - super::store_current_number(host, number) + super::store_current_number(host, root, number) } } diff --git a/etherlink/kernel_latest/kernel/src/chains.rs b/etherlink/kernel_latest/kernel/src/chains.rs index 7182493d59d6288f462b087b87cdc417462d83b8..b143e55d0011d0f01c0cb02a4b5db8d789906025 100644 --- a/etherlink/kernel_latest/kernel/src/chains.rs +++ b/etherlink/kernel_latest/kernel/src/chains.rs @@ -32,6 +32,9 @@ use tezos_smart_rollup::{outbox::OutboxQueue, types::Timestamp}; use tezos_smart_rollup_host::path::{Path, RefPath}; use tezos_tezlink::block::TezBlock; +pub const ETHERLINK_SAFE_STORAGE_ROOT_PATH: RefPath = + RefPath::assert_from(b"/evm/world_state"); + pub const TEZLINK_SAFE_STORAGE_ROOT_PATH: RefPath = RefPath::assert_from(b"/tezlink"); #[derive(Clone, Copy, Debug)] @@ -178,6 +181,8 @@ pub trait ChainConfigTrait: Debug { fn get_chain_family(&self) -> ChainFamily; + fn storage_root_path(&self) -> RefPath; + fn fmt_with_family(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let chain_family = self.get_chain_family(); write!(f, "{{Chain family: {}, {:?}}}", chain_family, self) @@ -340,6 +345,10 @@ impl ChainConfigTrait for EvmChainConfig { ) -> PrecompileBTreeMap { precompile_set::(enable_fa_bridge) } + + fn storage_root_path(&self) -> RefPath { + ETHERLINK_SAFE_STORAGE_ROOT_PATH + } } impl EvmChainConfig { @@ -448,7 +457,8 @@ impl ChainConfigTrait for MichelsonChainConfig { let tezblock = TezBlock::new(number, timestamp, previous_hash); let new_block = L2Block::Tezlink(tezblock); - crate::block_storage::store_current(host, &new_block) + let root = self.storage_root_path(); + crate::block_storage::store_current(host, &root, &new_block) .context("Failed to store the current block")?; Ok(BlockComputationResult::Finished { included_delayed_transactions: vec![], @@ -470,6 +480,10 @@ impl ChainConfigTrait for MichelsonChainConfig { ) -> PrecompileBTreeMap { PrecompileBTreeMap::new() } + + fn storage_root_path(&self) -> RefPath { + TEZLINK_SAFE_STORAGE_ROOT_PATH + } } impl MichelsonChainConfig { diff --git a/etherlink/kernel_latest/kernel/src/inbox.rs b/etherlink/kernel_latest/kernel/src/inbox.rs index 13577392575f3c3f8434bc5628bbd5d32081fd76..f755123f15f8baa6c451f9660df9b2cb8bcd5598 100644 --- a/etherlink/kernel_latest/kernel/src/inbox.rs +++ b/etherlink/kernel_latest/kernel/src/inbox.rs @@ -39,6 +39,7 @@ use tezos_ethereum::tx_common::EthereumTransactionCommon; use tezos_evm_logging::{log, Level::*}; use tezos_evm_runtime::runtime::Runtime; use tezos_smart_rollup_encoding::public_key::PublicKey; +use tezos_smart_rollup_host::path::Path; #[derive(Debug, PartialEq)] pub struct ProxyInboxContent { @@ -377,6 +378,7 @@ pub fn handle_input( host: &mut impl Runtime, input: Input, inbox_content: &mut Mode::Inbox, + root: &impl Path, chain_family: &ChainFamily, garbage_collect_blocks: bool, ) -> anyhow::Result<()> { @@ -392,7 +394,7 @@ pub fn handle_input( clear_events(host)?; if garbage_collect_blocks { log!(host, Debug, "Garbage collection of old blocks"); - crate::block_storage::garbage_collect_blocks(host, chain_family)?; + crate::block_storage::garbage_collect_blocks(host, root, chain_family)?; } store_last_info_per_level_timestamp(host, info.info.predecessor_timestamp)?; store_l1_level(host, info.level)? @@ -466,6 +468,7 @@ fn read_and_dispatch_input< host, input, res, + &chain_configuration.storage_root_path(), &chain_configuration.get_chain_family(), garbage_collect_blocks, )?; diff --git a/etherlink/kernel_latest/kernel/src/lib.rs b/etherlink/kernel_latest/kernel/src/lib.rs index e168fd981efaff26017dd2ca2a2d6162c8b2c866..261e65a350bd56b75899970f1035111dde713f25 100644 --- a/etherlink/kernel_latest/kernel/src/lib.rs +++ b/etherlink/kernel_latest/kernel/src/lib.rs @@ -14,6 +14,7 @@ use crate::migration::storage_migration; use crate::stage_one::fetch_blueprints; use crate::storage::{read_sequencer_pool_address, PRIVATE_FLAG_PATH}; use anyhow::Context; +use chains::ETHERLINK_SAFE_STORAGE_ROOT_PATH; use delayed_inbox::DelayedInbox; use fallback_upgrade::fallback_backup_kernel; use inbox::StageOneStatus; @@ -29,7 +30,6 @@ use storage::{ use tezos_crypto_rs::hash::ContractKt1Hash; use tezos_evm_logging::{log, Level::*, Verbosity}; use tezos_evm_runtime::runtime::{KernelHost, Runtime}; -use tezos_evm_runtime::safe_storage::WORLD_STATE_PATH; use tezos_smart_rollup::entrypoint; use tezos_smart_rollup::michelson::MichelsonUnit; use tezos_smart_rollup::outbox::{ @@ -173,9 +173,14 @@ fn retrieve_base_fee_per_gas( host: &mut Host, minimum_base_fee_per_gas: U256, ) -> U256 { - use chains::ChainFamily; + use chains::{ChainConfigTrait, EvmChainConfig}; - match block_storage::read_current(host, &ChainFamily::Evm) { + let chain_config = EvmChainConfig::default(); + match block_storage::read_current( + host, + &chain_config.storage_root_path(), + &chain_config.get_chain_family(), + ) { Ok(current_block) => { let current_base_fee_per_gas = current_block.base_fee_per_gas(); if current_base_fee_per_gas < minimum_base_fee_per_gas { @@ -359,12 +364,16 @@ pub fn kernel_loop(host: &mut H let world_state_subkeys = host .host - .store_count_subkeys(&WORLD_STATE_PATH) + .store_count_subkeys(ÐERLINK_SAFE_STORAGE_ROOT_PATH) .expect("The kernel failed to read the number of /evm/world_state subkeys"); if world_state_subkeys == 0 { host.host - .store_write(&WORLD_STATE_PATH, "Un festival de GADT".as_bytes(), 0) + .store_write( + ÐERLINK_SAFE_STORAGE_ROOT_PATH, + "Un festival de GADT".as_bytes(), + 0, + ) .unwrap(); } diff --git a/etherlink/kernel_latest/kernel/src/migration.rs b/etherlink/kernel_latest/kernel/src/migration.rs index ffea81c17be1394b5b6f8df474b58aad7f8c121e..57237dfcf97304b9d4e241a022f409018a53df19 100644 --- a/etherlink/kernel_latest/kernel/src/migration.rs +++ b/etherlink/kernel_latest/kernel/src/migration.rs @@ -8,6 +8,7 @@ use crate::block_storage; use crate::blueprint_storage::{ blueprint_path, clear_all_blueprints, store_current_block_header, }; +use crate::chains::ETHERLINK_SAFE_STORAGE_ROOT_PATH; use crate::error::Error; use crate::error::StorageError; use crate::error::UpgradeProcessError; @@ -86,7 +87,8 @@ mod legacy { pub fn read_next_blueprint_number( host: &Host, ) -> anyhow::Result { - match block_storage::read_current_number(host) { + match block_storage::read_current_number(host, ÐERLINK_SAFE_STORAGE_ROOT_PATH) + { Err(err) => match err.downcast_ref() { Some(GenStorageError::Runtime(RuntimeError::PathNotFound)) => { Ok(U256::zero()) @@ -157,7 +159,10 @@ fn migrate_to( // // We need only the former. - let current_number = block_storage::read_current_number(host)?; + let current_number = block_storage::read_current_number( + host, + ÐERLINK_SAFE_STORAGE_ROOT_PATH, + )?; let to_clean = U256::min( current_number + 1, evm_execution::storage::blocks::BLOCKS_STORED.into(), @@ -273,7 +278,11 @@ fn migrate_to( } StorageVersion::V27 => { // Initialize the next_blueprint_info field - match block_storage::read_current(host, &crate::chains::ChainFamily::Evm) { + match block_storage::read_current( + host, + ÐERLINK_SAFE_STORAGE_ROOT_PATH, + &crate::chains::ChainFamily::Evm, + ) { Ok(block) => { store_current_block_header(host, &block.into())?; Ok(MigrationStatus::Done) diff --git a/etherlink/kernel_latest/kernel/src/simulation.rs b/etherlink/kernel_latest/kernel/src/simulation.rs index 0bfea78cb65172abdae295bc4f627c4854beed48..eb1bbccc488bb41db1b71b8243057e9e40774298 100644 --- a/etherlink/kernel_latest/kernel/src/simulation.rs +++ b/etherlink/kernel_latest/kernel/src/simulation.rs @@ -11,7 +11,7 @@ use std::borrow::Cow; use crate::block_storage; -use crate::chains::ChainFamily; +use crate::chains::{ChainFamily, ETHERLINK_SAFE_STORAGE_ROOT_PATH}; use crate::fees::simulation_add_gas_for_fees; use crate::l2block::L2Block; use crate::storage::{ @@ -399,7 +399,11 @@ impl Evaluation { } } - let constants = match block_storage::read_current(host, &ChainFamily::Evm) { + let constants = match block_storage::read_current( + host, + ÐERLINK_SAFE_STORAGE_ROOT_PATH, + &ChainFamily::Evm, + ) { Ok(L2Block::Etherlink(block)) => { // Timestamp is taken from the simulation caller if provided. // If the timestamp is missing, because of an older evm-node, diff --git a/etherlink/kernel_latest/kernel/src/stage_one.rs b/etherlink/kernel_latest/kernel/src/stage_one.rs index 983e2011fde0bdbfd9c0afa359f9ba3a63f41bf1..588f65499876bc1bd72704c10736b8c6c3c82455 100644 --- a/etherlink/kernel_latest/kernel/src/stage_one.rs +++ b/etherlink/kernel_latest/kernel/src/stage_one.rs @@ -636,6 +636,7 @@ mod tests { hex::decode(DUMMY_BLUEPRINT_CHUNK_NUMBER_10).unwrap(), )); let mut conf = dummy_sequencer_config(enable_dal, None); + let chain_config = test_evm_chain_config(); match read_proxy_inbox( &mut host, @@ -643,7 +644,7 @@ mod tests { &conf.tezos_contracts, false, false, - &test_evm_chain_config(), + &chain_config, ) .unwrap() { @@ -656,7 +657,8 @@ mod tests { }; // The dummy chunk in the inbox is registered at block 10 - store_current_number(&mut host, U256::from(9)).unwrap(); + store_current_number(&mut host, &chain_config.storage_root_path(), U256::from(9)) + .unwrap(); if read_next_blueprint(&mut host, &mut conf) .expect("Blueprint reading shouldn't fail") .0 diff --git a/etherlink/kernel_latest/runtime/src/safe_storage.rs b/etherlink/kernel_latest/runtime/src/safe_storage.rs index 3147795e3edfb58794bb56276d57e4fbd9a8549f..3dadd85848769598d9f05e7ef124a60feca2a3f2 100644 --- a/etherlink/kernel_latest/runtime/src/safe_storage.rs +++ b/etherlink/kernel_latest/runtime/src/safe_storage.rs @@ -19,7 +19,6 @@ use tezos_smart_rollup_host::{ }; pub const TMP_PATH: RefPath = RefPath::assert_from(b"/tmp"); -pub const WORLD_STATE_PATH: RefPath = RefPath::assert_from(b"/evm/world_state"); pub const TRACE_PATH: RefPath = RefPath::assert_from(b"/evm/trace"); pub fn safe_path(path: &T) -> Result { @@ -28,6 +27,7 @@ pub fn safe_path(path: &T) -> Result { pub struct SafeStorage { pub host: Runtime, + pub world_state: OwnedPath, } impl InternalRuntime for SafeStorage<&mut Host> { @@ -234,13 +234,13 @@ impl Verbosity for SafeStorage<&mut Host> { impl SafeStorage<&mut Host> { pub fn start(&mut self) -> Result<(), RuntimeError> { - let tmp_path = safe_path(&WORLD_STATE_PATH)?; - self.host.store_copy(&WORLD_STATE_PATH, &tmp_path) + let tmp_path = safe_path(&self.world_state)?; + self.host.store_copy(&self.world_state, &tmp_path) } pub fn promote(&mut self) -> Result<(), RuntimeError> { - let tmp_path = safe_path(&WORLD_STATE_PATH)?; - self.host.store_move(&tmp_path, &WORLD_STATE_PATH) + let tmp_path = safe_path(&self.world_state)?; + self.host.store_move(&tmp_path, &self.world_state) } // Only used in tracing mode, so that the trace doesn't polute the world diff --git a/etherlink/kernel_latest/tezos_execution/src/context.rs b/etherlink/kernel_latest/tezos_execution/src/context.rs index 60003315b0338f843079e25bc972132b08093ca6..f27e0aaeb2a494cefe0d837bc648a59d655b64a7 100644 --- a/etherlink/kernel_latest/tezos_execution/src/context.rs +++ b/etherlink/kernel_latest/tezos_execution/src/context.rs @@ -2,13 +2,10 @@ // // SPDX-License-Identifier: MIT -use tezos_smart_rollup_host::path::{OwnedPath, RefPath}; +use tezos_smart_rollup_host::path::{concat, OwnedPath, Path, PathError, RefPath}; // TODO: https://gitlab.com/tezos/tezos/-/issues/7867: add the missing paths -// This path should be the only one to refers to '/tezlink/context' -const CONTEXT_PATH: RefPath = RefPath::assert_from(b"/tezlink/context"); - // Instead of using directly the paths, we construct a Context object that holds the // path to the context and does the concatenations. // This will prevent '/tezlink/context' to appear at multiple place like '/evm/world_state' @@ -17,10 +14,17 @@ pub struct Context { } impl Context { - #[allow(dead_code)] + pub fn from(root: &impl Path) -> Result { + let context = RefPath::assert_from(b"/context"); + let path = concat(root, &context)?; + Ok(Self { path }) + } + + #[cfg(test)] pub fn init_context() -> Self { - Context { - path: CONTEXT_PATH.into(), + let path = RefPath::assert_from(b"/tezlink/context"); + Self { + path: OwnedPath::from(path), } } } @@ -30,25 +34,20 @@ pub mod contracts { use super::Context; - #[allow(dead_code)] const ROOT: RefPath = RefPath::assert_from(b"/contracts"); - #[allow(dead_code)] const INDEX: RefPath = RefPath::assert_from(b"/index"); - #[allow(dead_code)] const GLOBAL_COUNTER: RefPath = RefPath::assert_from(b"/global_counter"); pub fn root(context: &Context) -> Result { concat(&context.path, &ROOT) } - #[allow(dead_code)] pub fn index(context: &Context) -> Result { concat(&root(context)?, &INDEX) } - #[allow(dead_code)] pub fn global_counter(context: &Context) -> Result { concat(&root(context)?, &GLOBAL_COUNTER) } diff --git a/etherlink/tezt/tests/evm_rollup.ml b/etherlink/tezt/tests/evm_rollup.ml index 7bb198a86f0136bce7514112050ef3a26686d73c..3aab368bae7a15d84cfdd907e8e91d1eafbc2eab 100644 --- a/etherlink/tezt/tests/evm_rollup.ml +++ b/etherlink/tezt/tests/evm_rollup.ml @@ -6426,11 +6426,11 @@ let test_rpcs_can_be_disabled = register_both ~tags:["evm"; "rpc"; "restricted"] ~title:"RPCs can be restricted" - ~restricted_rpcs:"tez_*" + ~restricted_rpcs:"tez_kernel*" @@ fun ~protocol:_ ~evm_setup -> let* kernel_version = Rpc.tez_kernelVersion evm_setup.evm_node in (match kernel_version with - | Ok _ -> Test.fail "tez_* methods should be unsupported" + | Ok _ -> Test.fail "tez_kernel* methods should be unsupported" | Error err -> Check.( (err.message = "Method disabled") @@ -6438,7 +6438,7 @@ let test_rpcs_can_be_disabled = ~error_msg:"Disabled method should return %R, but returned %L")) ; let* kernel_root_hash = Rpc.tez_kernelRootHash evm_setup.evm_node in (match kernel_root_hash with - | Ok _ -> Test.fail "tez_* methods should be unsupported" + | Ok _ -> Test.fail "tez_kernel* methods should be unsupported" | Error err -> Check.( (err.message = "Method disabled")