From e4bf859fbdddf4778b958685ba192964f36f78e0 Mon Sep 17 00:00:00 2001 From: arnaud Date: Thu, 15 May 2025 11:39:13 +0200 Subject: [PATCH 1/6] L2/node: Introduce Etherlink_durable_storage that holds Etherlink specific functions Durable storage modules keeps generic functions or functions that can be useful for both Etherlink and Tezlink --- etherlink/bin_node/lib_dev/block_producer.ml | 10 +- etherlink/bin_node/lib_dev/durable_storage.ml | 458 +----------------- .../lib_dev/etherlink_durable_storage.ml | 424 ++++++++++++++++ etherlink/bin_node/lib_dev/evm_context.ml | 6 +- .../bin_node/lib_dev/services_backend_sig.ml | 7 +- etherlink/bin_node/lib_dev/simulator.ml | 5 +- etherlink/bin_node/lib_dev/validate.ml | 5 +- etherlink/bin_node/test/test_wasm_runtime.ml | 2 +- 8 files changed, 468 insertions(+), 449 deletions(-) create mode 100644 etherlink/bin_node/lib_dev/etherlink_durable_storage.ml diff --git a/etherlink/bin_node/lib_dev/block_producer.ml b/etherlink/bin_node/lib_dev/block_producer.ml index 5643bfa0e2e2..96b547163923 100644 --- a/etherlink/bin_node/lib_dev/block_producer.ml +++ b/etherlink/bin_node/lib_dev/block_producer.ml @@ -231,19 +231,19 @@ let pop_valid_tx ~chain_family ~initial_validation_state | EVM -> let read = Evm_state.read head_info.evm_state in - let* base_fee_per_gas = Durable_storage.base_fee_per_gas read in + let* base_fee_per_gas = Etherlink_durable_storage.base_fee_per_gas read in let* maximum_gas_limit = - Durable_storage.maximum_gas_per_transaction read + Etherlink_durable_storage.maximum_gas_per_transaction read in - let* da_fee_per_byte = Durable_storage.da_fee_per_byte read in + let* da_fee_per_byte = Etherlink_durable_storage.da_fee_per_byte read in let config = Validate. { base_fee_per_gas; maximum_gas_limit; da_fee_per_byte; - next_nonce = (fun addr -> Durable_storage.nonce read addr); - balance = (fun addr -> Durable_storage.balance read addr); + next_nonce = (fun addr -> Etherlink_durable_storage.nonce read addr); + balance = (fun addr -> Etherlink_durable_storage.balance read addr); } in let initial_validation_state = diff --git a/etherlink/bin_node/lib_dev/durable_storage.ml b/etherlink/bin_node/lib_dev/durable_storage.ml index d5444f92544f..f00662d12a78 100644 --- a/etherlink/bin_node/lib_dev/durable_storage.ml +++ b/etherlink/bin_node/lib_dev/durable_storage.ml @@ -5,7 +5,7 @@ (* *) (*****************************************************************************) -open Ethereum_types +exception Invalid_block_structure of string module type READER = sig type state @@ -39,260 +39,6 @@ let inspect_durable_and_decode read path decode = | Some res -> return res | None -> failwith "No value found under %s" path -let balance read address = - inspect_durable_and_decode_default - ~default:(Ethereum_types.Qty Z.zero) - read - (Durable_storage_path.Accounts.balance address) - decode_number_le - -let nonce read address = - inspect_durable_and_decode_opt - read - (Durable_storage_path.Accounts.nonce address) - decode_number_le - -let code read address = - let open Lwt_result_syntax in - let default = Ethereum_types.Hex "" in - let decode bytes = - bytes |> Hex.of_bytes |> Hex.show |> Ethereum_types.hex_of_string - in - let* answer = - inspect_durable_and_decode_opt - read - (Durable_storage_path.Accounts.code address) - decode - in - match answer with - | Some code -> return code - | None -> ( - let* hash_opt = - inspect_durable_and_decode_opt - read - (Durable_storage_path.Accounts.code_hash address) - (fun bytes -> - Hex.of_bytes bytes |> Hex.show |> Ethereum_types.hash_of_string) - in - match hash_opt with - | None -> return default - | Some hash -> - inspect_durable_and_decode_default - ~default - read - (Durable_storage_path.Code.code hash) - decode) - -exception Invalid_block_structure of string - -let block_number 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 - match answer with - | Some bytes -> Ethereum_types.Qty (Bytes.to_string bytes |> Z.of_bits) - | None -> - raise - @@ Invalid_block_structure - "Unexpected [None] value for [current_number]'s [answer]") - -let current_block_number read = - block_number read Durable_storage_path.Block.Current - -let un_qty (Qty z) = z - -let mock_block_hash = Block_hash (Hex (String.make 64 'a')) - -let transaction_receipt read ?block_hash tx_hash = - let open Lwt_result_syntax in - (* We use a mock block hash to decode the rest of the receipt, - so that we can get the number to query for the actual block - hash (only if the block hash isn't already available). *) - let block = Option.value block_hash ~default:mock_block_hash in - let* opt_receipt = - inspect_durable_and_decode_opt - read - (Durable_storage_path.Transaction_receipt.receipt tx_hash) - (Transaction_receipt.of_rlp_bytes block) - in - match block_hash with - | Some _ -> - (* Correct receipt *) - return opt_receipt - | None -> ( - (* Need to replace with correct block hash *) - match opt_receipt with - | Some temp_receipt -> - let+ blockHash = - inspect_durable_and_decode - read - (Durable_storage_path.Indexes.block_by_number - (Nth (un_qty temp_receipt.blockNumber))) - decode_block_hash - in - let logs = - List.map - (fun (log : transaction_log) -> - {log with blockHash = Some blockHash}) - temp_receipt.logs - in - Some {temp_receipt with blockHash; logs} - | None -> return_none) - -let transaction_object read tx_hash = - let open Lwt_result_syntax in - (* We use a mock block hash to decode the rest of the receipt, - so that we can get the number to query for the actual block - hash. *) - let mock_block_hash = Block_hash (Hex (String.make 64 'a')) in - let* opt_object = - inspect_durable_and_decode_opt - read - (Durable_storage_path.Transaction_object.object_ tx_hash) - (Ethereum_types.legacy_transaction_object_from_rlp (Some mock_block_hash)) - in - match opt_object with - | Some temp_object -> - let*? (blockNumber : quantity) = - match temp_object.blockNumber with - | None -> error_with "Unexpected null blockNumber in valid object" - | Some n -> Ok n - in - let+ blockHash = - inspect_durable_and_decode - read - (Durable_storage_path.Indexes.block_by_number - (Nth (un_qty blockNumber))) - decode_block_hash - in - Some {temp_object with blockHash = Some blockHash} - | None -> return_none - -let transaction_object_with_block_hash read block_hash tx_hash = - inspect_durable_and_decode_opt - read - (Durable_storage_path.Transaction_object.object_ tx_hash) - (Ethereum_types.legacy_transaction_object_from_rlp block_hash) - -let full_transactions read block_hash transactions = - let open Lwt_result_syntax in - match transactions with - | TxHash hashes -> - let+ objects = - List.filter_map_es - (transaction_object_with_block_hash read block_hash) - hashes - in - TxFull objects - | TxFull l -> return (TxFull l) - -let populate_tx_objects read ~full_transaction_object - (block : legacy_transaction_object block) = - let open Lwt_result_syntax in - if full_transaction_object then - let* transactions = - full_transactions read (Some block.hash) block.transactions - in - return {block with transactions} - else return block - -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* block_hash_opt = - inspect_durable_and_decode_opt - read - (Durable_storage_path.Indexes.block_by_number (Nth level)) - decode_block_hash - in - match block_hash_opt with - | None -> failwith "Block %a not found" Z.pp_print level - | Some block_hash -> ( - let* block_opt = - inspect_durable_and_decode_opt - read - (Durable_storage_path.Block.by_hash block_hash) - Ethereum_types.block_from_rlp - in - match block_opt with - | None -> raise @@ Invalid_block_structure "Couldn't decode bytes" - | Some block -> populate_tx_objects read ~full_transaction_object block) - -let nth_block read ~full_transaction_object n = - blocks_by_number - read - ~full_transaction_object - ~number:Durable_storage_path.Block.(Nth n) - -let tez_nth_block read n = - let open Lwt_result_syntax in - let number = Durable_storage_path.Block.(Nth n) in - let* (Ethereum_types.Qty level) = block_number read number in - let* block_hash_opt = - inspect_durable_and_decode_opt - read - (Durable_storage_path.Indexes.block_by_number (Nth level)) - decode_block_hash - in - match block_hash_opt with - | None -> failwith "Block %a not found" Z.pp_print level - | Some block_hash -> ( - let* block_opt = - inspect_durable_and_decode_opt - read - (Durable_storage_path.Block.by_hash block_hash) - L2_types.Tezos_block.block_from_binary - in - match block_opt with - | None -> raise @@ Invalid_block_structure "Couldn't decode bytes" - | Some block -> return block) - -let nth_block_hash read n = - let number = Durable_storage_path.Block.(Nth n) in - inspect_durable_and_decode_opt - read - (Durable_storage_path.Indexes.block_by_number number) - decode_block_hash - -let block_by_hash read ~full_transaction_object block_hash = - let open Lwt_result_syntax in - let* block_opt = - inspect_durable_and_decode_opt - read - (Durable_storage_path.Block.by_hash block_hash) - Ethereum_types.block_from_rlp - in - match block_opt with - | None -> raise @@ Invalid_block_structure "Couldn't decode bytes" - | Some block -> populate_tx_objects read ~full_transaction_object block - -let block_receipts_of_block read block = - let get_receipt_from_hash tx_hash = - Lwt.map - (function Ok receipt -> receipt | _ -> None) - (transaction_receipt read ~block_hash:block.hash tx_hash) - in - let tx_hashes : hash list = - match block.transactions with - | TxHash tx_hashes -> tx_hashes - | TxFull tx_objects -> - (* This case should never happen, because there is no ways - to ask for full objects when requestion block receipts. *) - List.map (fun (obj : legacy_transaction_object) -> obj.hash) tx_objects - in - Lwt_list.filter_map_s get_receipt_from_hash tx_hashes - -let block_receipts read n = - let number = Durable_storage_path.Block.(Nth n) in - let open Lwt_result_syntax in - let* block = blocks_by_number read ~full_transaction_object:false ~number in - let*! receipts = block_receipts_of_block read block in - Lwt.return_ok receipts - let chain_id read = inspect_durable_and_decode read @@ -330,35 +76,18 @@ let world_state read chain_id = (Durable_storage_path.Chain_configuration.world_state chain_id) Bytes.to_string -let base_fee_per_gas read = - let open Lwt_result_syntax in - let* block = - blocks_by_number - read - ~full_transaction_object:false - ~number:Durable_storage_path.Block.Current - in - match block.baseFeePerGas with - | Some base_fee_per_gas -> return base_fee_per_gas - | None -> - Error_monad.failwith - "Attempted to get the base fee per gas from a block which does not \ - have one." - -let backlog read = - let open Lwt_result_syntax in - let+ read_result = read Durable_storage_path.backlog in - match read_result with - | Some backlog_bytes -> - Z.of_int64_unsigned - Data_encoding.(Binary.of_bytes_exn Little_endian.int64 backlog_bytes) - | None -> Z.zero - -let minimum_base_fee_per_gas read = +let sequencer read = inspect_durable_and_decode read - Durable_storage_path.minimum_base_fee_per_gas - Helpers.decode_z_le + Durable_storage_path.sequencer_key + (fun bytes -> Signature.Public_key.of_b58check_exn (String.of_bytes bytes)) + +let storage_version read = + inspect_durable_and_decode_default + ~default:0 + read + Durable_storage_path.storage_version + (fun bytes -> Helpers.decode_z_le bytes |> Z.to_int) let kernel_version read = inspect_durable_and_decode @@ -377,87 +106,27 @@ let is_multichain_enabled read = let* bytes_opt = read Durable_storage_path.Feature_flags.multichain in return (Option.is_some bytes_opt) -let storage_at read address (Qty pos) = +let block_number read n = let open Lwt_result_syntax in - let pad32left0 s = - let open Ethereum_types in - (* Strip 0x *) - let (Hex s) = hex_of_string s in - let len = String.length s in - (* This is a Hex string of 32 bytes, therefore the length is 64 *) - String.make (64 - len) '0' ^ s - in - let index = Z.format "#x" pos |> pad32left0 in - let+ answer = read (Durable_storage_path.Accounts.storage address index) in - match answer with - | Some bytes -> - Bytes.to_string bytes |> Hex.of_string |> Hex.show - |> Ethereum_types.hex_of_string - | None -> Ethereum_types.Hex (pad32left0 "0") - -let coinbase read = - inspect_durable_and_decode_default - ~default: - (Address - (Ethereum_types.hex_of_string - "0x0000000000000000000000000000000000000000")) - read - Durable_storage_path.sequencer_pool_address - (fun bytes -> - Address (Hex.of_bytes bytes |> Hex.show |> Ethereum_types.hex_of_string)) - -let storage_version read = - inspect_durable_and_decode_default - ~default:0 - read - Durable_storage_path.storage_version - (fun bytes -> decode_number_le bytes |> un_qty |> Z.to_int) - -let maximum_gas_per_transaction read = - (* In future iterations of the kernel, the default value will be - written to the storage. This default value will no longer need to - be declared here. *) - inspect_durable_and_decode_default - ~default:(Qty (Z.of_string "30_000_000")) - read - Durable_storage_path.maximum_gas_per_transaction - decode_number_le - -let da_fee_per_byte read = - inspect_durable_and_decode - read - Durable_storage_path.da_fee_per_byte - decode_number_le - -let sequencer read = - inspect_durable_and_decode - read - Durable_storage_path.sequencer_key - (fun bytes -> Signature.Public_key.of_b58check_exn (String.of_bytes bytes)) + 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 + match answer with + | Some bytes -> Ethereum_types.Qty (Bytes.to_string bytes |> Z.of_bits) + | None -> + raise + @@ Invalid_block_structure + "Unexpected [None] value for [current_number]'s [answer]") module Make (Reader : READER) = struct - let read = Reader.read - let read_with_state ?block () = let open Lwt_result_syntax in let* state = Reader.get_state ?block () in return (Reader.read state) - let balance address block = - let open Lwt_result_syntax in - let* read = read_with_state ~block () in - balance read address - - let nonce address block = - let open Lwt_result_syntax in - let* read = read_with_state ~block () in - nonce read address - - let code address block = - let open Lwt_result_syntax in - let* read = read_with_state ~block () in - code read address - let chain_id () = let open Lwt_result_syntax in let* read = read_with_state () in @@ -493,21 +162,6 @@ module Make (Reader : READER) = struct let* read = read_with_state () in world_state read chain_id - let base_fee_per_gas () = - let open Lwt_result_syntax in - let* read = read_with_state () in - base_fee_per_gas read - - let backlog () = - let open Lwt_result_syntax in - let* read = read_with_state () in - backlog read - - let minimum_base_fee_per_gas () = - let open Lwt_result_syntax in - let* read = read_with_state () in - minimum_base_fee_per_gas read - let storage_version () = let open Lwt_result_syntax in let* read = read_with_state () in @@ -522,68 +176,4 @@ module Make (Reader : READER) = struct let open Lwt_result_syntax in let* read = read_with_state () in kernel_root_hash read - - let storage_at address pos block = - let open Lwt_result_syntax in - let* read = read_with_state ~block () in - storage_at read address pos - - let coinbase () = - let open Lwt_result_syntax in - let* read = read_with_state () in - coinbase read -end - -module Make_block_storage (Reader : READER) = struct - let read = Reader.read - - let read_with_state () = - let open Lwt_result_syntax in - let* state = Reader.get_state () in - return (Reader.read state) - - let transaction_receipt tx_hash = - let open Lwt_result_syntax in - let* read = read_with_state () in - transaction_receipt read tx_hash - - let current_block_number () = - let open Lwt_result_syntax in - let* read = read_with_state () in - current_block_number read - - let nth_block_hash n = - let open Lwt_result_syntax in - let* read = read_with_state () in - nth_block_hash read n - - let nth_block ~full_transaction_object n = - let open Lwt_result_syntax in - let* read = read_with_state () in - let+ block = nth_block read ~full_transaction_object n in - Transaction_object.block_from_legacy block - - let tez_nth_block n = - let open Lwt_result_syntax in - let* read = read_with_state () in - tez_nth_block read n - - let block_by_hash ~full_transaction_object block_hash = - let open Lwt_result_syntax in - let* read = read_with_state () in - let+ block = block_by_hash read ~full_transaction_object block_hash in - Transaction_object.block_from_legacy block - - let block_receipts n = - let open Lwt_result_syntax in - let* read = read_with_state () in - block_receipts read n - - let transaction_object tx_hash = - let open Lwt_result_syntax in - let* read = read_with_state () in - let+ transaction_object = transaction_object read tx_hash in - Option.map - Transaction_object.from_store_transaction_object - transaction_object end diff --git a/etherlink/bin_node/lib_dev/etherlink_durable_storage.ml b/etherlink/bin_node/lib_dev/etherlink_durable_storage.ml new file mode 100644 index 000000000000..843748d1a05e --- /dev/null +++ b/etherlink/bin_node/lib_dev/etherlink_durable_storage.ml @@ -0,0 +1,424 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs *) +(* *) +(*****************************************************************************) + +open Durable_storage +open Ethereum_types + +let balance read address = + inspect_durable_and_decode_default + ~default:(Ethereum_types.Qty Z.zero) + read + (Durable_storage_path.Accounts.balance address) + decode_number_le + +let nonce read address = + inspect_durable_and_decode_opt + read + (Durable_storage_path.Accounts.nonce address) + decode_number_le + +let code read address = + let open Lwt_result_syntax in + let default = Ethereum_types.Hex "" in + let decode bytes = + bytes |> Hex.of_bytes |> Hex.show |> Ethereum_types.hex_of_string + in + let* answer = + inspect_durable_and_decode_opt + read + (Durable_storage_path.Accounts.code address) + decode + in + match answer with + | Some code -> return code + | None -> ( + let* hash_opt = + inspect_durable_and_decode_opt + read + (Durable_storage_path.Accounts.code_hash address) + (fun bytes -> + Hex.of_bytes bytes |> Hex.show |> Ethereum_types.hash_of_string) + in + match hash_opt with + | None -> return default + | Some hash -> + inspect_durable_and_decode_default + ~default + read + (Durable_storage_path.Code.code hash) + decode) + +let current_block_number read = + Durable_storage.block_number read Durable_storage_path.Block.Current + +let un_qty (Qty z) = z + +let mock_block_hash = Block_hash (Hex (String.make 64 'a')) + +let transaction_receipt read ?block_hash tx_hash = + let open Lwt_result_syntax in + (* We use a mock block hash to decode the rest of the receipt, + so that we can get the number to query for the actual block + hash (only if the block hash isn't already available). *) + let block = Option.value block_hash ~default:mock_block_hash in + let* opt_receipt = + inspect_durable_and_decode_opt + read + (Durable_storage_path.Transaction_receipt.receipt tx_hash) + (Transaction_receipt.of_rlp_bytes block) + in + match block_hash with + | Some _ -> + (* Correct receipt *) + return opt_receipt + | None -> ( + (* Need to replace with correct block hash *) + match opt_receipt with + | Some temp_receipt -> + let+ blockHash = + inspect_durable_and_decode + read + (Durable_storage_path.Indexes.block_by_number + (Nth (un_qty temp_receipt.blockNumber))) + decode_block_hash + in + let logs = + List.map + (fun (log : transaction_log) -> + {log with blockHash = Some blockHash}) + temp_receipt.logs + in + Some {temp_receipt with blockHash; logs} + | None -> return_none) + +let transaction_object read tx_hash = + let open Lwt_result_syntax in + (* We use a mock block hash to decode the rest of the receipt, + so that we can get the number to query for the actual block + hash. *) + let mock_block_hash = Block_hash (Hex (String.make 64 'a')) in + let* opt_object = + inspect_durable_and_decode_opt + read + (Durable_storage_path.Transaction_object.object_ tx_hash) + (Ethereum_types.legacy_transaction_object_from_rlp (Some mock_block_hash)) + in + match opt_object with + | Some temp_object -> + let*? (blockNumber : quantity) = + match temp_object.blockNumber with + | None -> error_with "Unexpected null blockNumber in valid object" + | Some n -> Ok n + in + let+ blockHash = + inspect_durable_and_decode + read + (Durable_storage_path.Indexes.block_by_number + (Nth (un_qty blockNumber))) + decode_block_hash + in + Some {temp_object with blockHash = Some blockHash} + | None -> return_none + +let transaction_object_with_block_hash read block_hash tx_hash = + inspect_durable_and_decode_opt + read + (Durable_storage_path.Transaction_object.object_ tx_hash) + (Ethereum_types.legacy_transaction_object_from_rlp block_hash) + +let full_transactions read block_hash transactions = + let open Lwt_result_syntax in + match transactions with + | TxHash hashes -> + let+ objects = + List.filter_map_es + (transaction_object_with_block_hash read block_hash) + hashes + in + TxFull objects + | TxFull l -> return (TxFull l) + +let populate_tx_objects read ~full_transaction_object + (block : legacy_transaction_object block) = + let open Lwt_result_syntax in + if full_transaction_object then + let* transactions = + full_transactions read (Some block.hash) block.transactions + in + return {block with transactions} + else return block + +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* block_hash_opt = + inspect_durable_and_decode_opt + read + (Durable_storage_path.Indexes.block_by_number (Nth level)) + decode_block_hash + in + match block_hash_opt with + | None -> failwith "Block %a not found" Z.pp_print level + | Some block_hash -> ( + let* block_opt = + inspect_durable_and_decode_opt + read + (Durable_storage_path.Block.by_hash block_hash) + Ethereum_types.block_from_rlp + in + match block_opt with + | None -> raise @@ Invalid_block_structure "Couldn't decode bytes" + | Some block -> populate_tx_objects read ~full_transaction_object block) + +let nth_block read ~full_transaction_object n = + blocks_by_number + read + ~full_transaction_object + ~number:Durable_storage_path.Block.(Nth n) + +let tez_nth_block read n = + let open Lwt_result_syntax in + let number = Durable_storage_path.Block.(Nth n) in + let* (Ethereum_types.Qty level) = block_number read number in + let* block_hash_opt = + inspect_durable_and_decode_opt + read + (Durable_storage_path.Indexes.block_by_number (Nth level)) + decode_block_hash + in + match block_hash_opt with + | None -> failwith "Block %a not found" Z.pp_print level + | Some block_hash -> ( + let* block_opt = + inspect_durable_and_decode_opt + read + (Durable_storage_path.Block.by_hash block_hash) + L2_types.Tezos_block.block_from_binary + in + match block_opt with + | None -> raise @@ Invalid_block_structure "Couldn't decode bytes" + | Some block -> return block) + +let nth_block_hash read n = + let number = Durable_storage_path.Block.(Nth n) in + inspect_durable_and_decode_opt + read + (Durable_storage_path.Indexes.block_by_number number) + decode_block_hash + +let block_by_hash read ~full_transaction_object block_hash = + let open Lwt_result_syntax in + let* block_opt = + inspect_durable_and_decode_opt + read + (Durable_storage_path.Block.by_hash block_hash) + Ethereum_types.block_from_rlp + in + match block_opt with + | None -> raise @@ Invalid_block_structure "Couldn't decode bytes" + | Some block -> populate_tx_objects read ~full_transaction_object block + +let block_receipts_of_block read block = + let get_receipt_from_hash tx_hash = + Lwt.map + (function Ok receipt -> receipt | _ -> None) + (transaction_receipt read ~block_hash:block.hash tx_hash) + in + let tx_hashes : hash list = + match block.transactions with + | TxHash tx_hashes -> tx_hashes + | TxFull tx_objects -> + (* This case should never happen, because there is no ways + to ask for full objects when requestion block receipts. *) + List.map (fun (obj : legacy_transaction_object) -> obj.hash) tx_objects + in + Lwt_list.filter_map_s get_receipt_from_hash tx_hashes + +let block_receipts read n = + let number = Durable_storage_path.Block.(Nth n) in + let open Lwt_result_syntax in + let* block = blocks_by_number read ~full_transaction_object:false ~number in + let*! receipts = block_receipts_of_block read block in + Lwt.return_ok receipts + +let base_fee_per_gas read = + let open Lwt_result_syntax in + let* block = + blocks_by_number + read + ~full_transaction_object:false + ~number:Durable_storage_path.Block.Current + in + match block.baseFeePerGas with + | Some base_fee_per_gas -> return base_fee_per_gas + | None -> + Error_monad.failwith + "Attempted to get the base fee per gas from a block which does not \ + have one." + +let backlog read = + let open Lwt_result_syntax in + let+ read_result = read Durable_storage_path.backlog in + match read_result with + | Some backlog_bytes -> + Z.of_int64_unsigned + Data_encoding.(Binary.of_bytes_exn Little_endian.int64 backlog_bytes) + | None -> Z.zero + +let minimum_base_fee_per_gas read = + inspect_durable_and_decode + read + Durable_storage_path.minimum_base_fee_per_gas + Helpers.decode_z_le + +let storage_at read address (Qty pos) = + let open Lwt_result_syntax in + let pad32left0 s = + let open Ethereum_types in + (* Strip 0x *) + let (Hex s) = hex_of_string s in + let len = String.length s in + (* This is a Hex string of 32 bytes, therefore the length is 64 *) + String.make (64 - len) '0' ^ s + in + let index = Z.format "#x" pos |> pad32left0 in + let+ answer = read (Durable_storage_path.Accounts.storage address index) in + match answer with + | Some bytes -> + Bytes.to_string bytes |> Hex.of_string |> Hex.show + |> Ethereum_types.hex_of_string + | None -> Ethereum_types.Hex (pad32left0 "0") + +let coinbase read = + inspect_durable_and_decode_default + ~default: + (Address + (Ethereum_types.hex_of_string + "0x0000000000000000000000000000000000000000")) + read + Durable_storage_path.sequencer_pool_address + (fun bytes -> + Address (Hex.of_bytes bytes |> Hex.show |> Ethereum_types.hex_of_string)) + +let maximum_gas_per_transaction read = + (* In future iterations of the kernel, the default value will be + written to the storage. This default value will no longer need to + be declared here. *) + inspect_durable_and_decode_default + ~default:(Qty (Z.of_string "30_000_000")) + read + Durable_storage_path.maximum_gas_per_transaction + decode_number_le + +let da_fee_per_byte read = + inspect_durable_and_decode + read + Durable_storage_path.da_fee_per_byte + decode_number_le + +module Make (Reader : READER) = struct + let read = Reader.read + + let read_with_state ?block () = + let open Lwt_result_syntax in + let* state = Reader.get_state ?block () in + return (Reader.read state) + + let balance address block = + let open Lwt_result_syntax in + let* read = read_with_state ~block () in + balance read address + + let nonce address block = + let open Lwt_result_syntax in + let* read = read_with_state ~block () in + nonce read address + + let code address block = + let open Lwt_result_syntax in + let* read = read_with_state ~block () in + code read address + + let base_fee_per_gas () = + let open Lwt_result_syntax in + let* read = read_with_state () in + base_fee_per_gas read + + let backlog () = + let open Lwt_result_syntax in + let* read = read_with_state () in + backlog read + + let minimum_base_fee_per_gas () = + let open Lwt_result_syntax in + let* read = read_with_state () in + minimum_base_fee_per_gas read + + let storage_at address pos block = + let open Lwt_result_syntax in + let* read = read_with_state ~block () in + storage_at read address pos + + let coinbase () = + let open Lwt_result_syntax in + let* read = read_with_state () in + coinbase read +end + +module Make_block_storage (Reader : READER) = struct + let read = Reader.read + + let read_with_state () = + let open Lwt_result_syntax in + let* state = Reader.get_state () in + return (Reader.read state) + + let transaction_receipt tx_hash = + let open Lwt_result_syntax in + let* read = read_with_state () in + transaction_receipt read tx_hash + + let current_block_number () = + let open Lwt_result_syntax in + let* read = read_with_state () in + current_block_number read + + let nth_block_hash n = + let open Lwt_result_syntax in + let* read = read_with_state () in + nth_block_hash read n + + let nth_block ~full_transaction_object n = + let open Lwt_result_syntax in + let* read = read_with_state () in + let+ block = nth_block read ~full_transaction_object n in + Transaction_object.block_from_legacy block + + let tez_nth_block n = + let open Lwt_result_syntax in + let* read = read_with_state () in + tez_nth_block read n + + let block_by_hash ~full_transaction_object block_hash = + let open Lwt_result_syntax in + let* read = read_with_state () in + let+ block = block_by_hash read ~full_transaction_object block_hash in + Transaction_object.block_from_legacy block + + let block_receipts n = + let open Lwt_result_syntax in + let* read = read_with_state () in + block_receipts read n + + let transaction_object tx_hash = + let open Lwt_result_syntax in + let* read = read_with_state () in + let+ transaction_object = transaction_object read tx_hash in + Option.map + Transaction_object.from_store_transaction_object + transaction_object +end diff --git a/etherlink/bin_node/lib_dev/evm_context.ml b/etherlink/bin_node/lib_dev/evm_context.ml index 5f5831971f1e..5e7464ad1c34 100644 --- a/etherlink/bin_node/lib_dev/evm_context.ml +++ b/etherlink/bin_node/lib_dev/evm_context.ml @@ -630,7 +630,7 @@ module State = struct (fun hash -> let* receipt = let* receipt_opt = - Durable_storage.transaction_receipt + Etherlink_durable_storage.transaction_receipt (read_from_state evm_state) ~block_hash:block.hash hash @@ -642,7 +642,7 @@ module State = struct in let* object_ = let* object_opt = - Durable_storage.transaction_object + Etherlink_durable_storage.transaction_object (read_from_state evm_state) hash in @@ -802,7 +802,7 @@ module State = struct let*! receipts = match block with | Eth block -> - Durable_storage.block_receipts_of_block + Etherlink_durable_storage.block_receipts_of_block (read_from_state evm_state) block | Tez _ -> diff --git a/etherlink/bin_node/lib_dev/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index d6edcf72f031..fb62f9b88d72 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -178,8 +178,9 @@ end module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct module Reader = Backend.Reader - include Durable_storage.Make (Backend.Reader) - module Block_storage = Durable_storage.Make_block_storage (Backend.Reader) + include Etherlink_durable_storage.Make (Backend.Reader) + module Block_storage = + Etherlink_durable_storage.Make_block_storage (Backend.Reader) include Publisher.Make (Backend.TxEncoder) (Backend.Publisher) include Simulator.Make (Backend.SimulatorBackend) @@ -206,6 +207,8 @@ module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct failwith "Could not replay a tezlink block" | Apply_failure -> failwith "Could not replay the block" + include Durable_storage.Make (Reader) + let smart_rollup_address = Backend.smart_rollup_address let list_l1_l2_levels = Backend.list_l1_l2_levels diff --git a/etherlink/bin_node/lib_dev/simulator.ml b/etherlink/bin_node/lib_dev/simulator.ml index aca96c96b612..b82259f66fab 100644 --- a/etherlink/bin_node/lib_dev/simulator.ml +++ b/etherlink/bin_node/lib_dev/simulator.ml @@ -132,7 +132,8 @@ module Make (SimulationBackend : SimulationBackend) = struct Option.map Ethereum_types.decode_number_le bytes in let* da_fee_per_byte = - Durable_storage.da_fee_per_byte (SimulationBackend.read simulation_state) + Etherlink_durable_storage.da_fee_per_byte + (SimulationBackend.read simulation_state) in let* (Qty gas_price) = (* In future iterations of the kernel, the default value will be @@ -222,7 +223,7 @@ module Make (SimulationBackend : SimulationBackend) = struct in let timestamp = Misc.now () in let* (Qty maximum_gas_per_transaction) = - Durable_storage.maximum_gas_per_transaction + Etherlink_durable_storage.maximum_gas_per_transaction (SimulationBackend.read simulation_state) in let* simulation_version = simulation_version simulation_state in diff --git a/etherlink/bin_node/lib_dev/validate.ml b/etherlink/bin_node/lib_dev/validate.ml index d2ab2dd0680b..71f54704f133 100644 --- a/etherlink/bin_node/lib_dev/validate.ml +++ b/etherlink/bin_node/lib_dev/validate.ml @@ -146,10 +146,11 @@ let validate_with_state_from_backend let* base_fee_per_gas = Backend_rpc.base_fee_per_gas () in let* state = Backend_rpc.Reader.get_state () in let* maximum_gas_limit = - Durable_storage.maximum_gas_per_transaction (Backend_rpc.Reader.read state) + Etherlink_durable_storage.maximum_gas_per_transaction + (Backend_rpc.Reader.read state) in let* da_fee_per_byte = - Durable_storage.da_fee_per_byte (Backend_rpc.Reader.read state) + Etherlink_durable_storage.da_fee_per_byte (Backend_rpc.Reader.read state) in let** _total_cost = validate_balance_and_gas diff --git a/etherlink/bin_node/test/test_wasm_runtime.ml b/etherlink/bin_node/test/test_wasm_runtime.ml index 8d7f4e4bb7d9..f7bf58438b64 100644 --- a/etherlink/bin_node/test/test_wasm_runtime.ml +++ b/etherlink/bin_node/test/test_wasm_runtime.ml @@ -47,7 +47,7 @@ let test_wasm_runtime_id () = in Log.info "Check state consistency" ; let* quantity = - Durable_storage.current_block_number (fun key -> + Etherlink_durable_storage.current_block_number (fun key -> let* candidate = Evm_state.inspect tree key in return (Ok candidate)) in -- GitLab From 44cf4e9daf2ac9951f1aea60d5be204720e99f13 Mon Sep 17 00:00:00 2001 From: arnaud Date: Thu, 22 May 2025 11:13:28 +0200 Subject: [PATCH 2/6] L2/Node: Rename Tezlink_backend module in Tezlink --- etherlink/bin_node/lib_dev/evm_ro_context.ml | 4 ++-- etherlink/bin_node/lib_dev/rpc_server.ml | 2 +- etherlink/bin_node/lib_dev/services_backend_sig.ml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/etherlink/bin_node/lib_dev/evm_ro_context.ml b/etherlink/bin_node/lib_dev/evm_ro_context.ml index a09624d74108..4af65f9b30c2 100644 --- a/etherlink/bin_node/lib_dev/evm_ro_context.ml +++ b/etherlink/bin_node/lib_dev/evm_ro_context.ml @@ -555,8 +555,8 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) failwith "Missing block %a" Ethereum_types.pp_block_hash hash) | param -> block_param_to_block_number param - (* Overwrites Tezlink_backend using the store instead of the durable_storage *) - module Tezlink_backend = Tezlink_services_impl.Make (struct + (* Overwrites Tezlink using the store instead of the durable_storage *) + module Tezlink = Tezlink_services_impl.Make (struct include Backend.Reader let block_param_to_block_number = block_param_to_block_number diff --git a/etherlink/bin_node/lib_dev/rpc_server.ml b/etherlink/bin_node/lib_dev/rpc_server.ml index 890cc920e1f1..8989a5bbef2e 100644 --- a/etherlink/bin_node/lib_dev/rpc_server.ml +++ b/etherlink/bin_node/lib_dev/rpc_server.ml @@ -176,7 +176,7 @@ let start_public_server ~(rpc_server_family : Rpc_types.rpc_server_family) return @@ Evm_directory.init_from_resto_directory @@ Tezos_services.register_tezlink_services ~l2_chain_id - (module Backend.Tezlink_backend) + (module Backend.Tezlink) | Single_chain_node_rpc_server L2_types.EVM | Multichain_sequencer_rpc_server -> return @@ Evm_directory.empty config.experimental_features.rpc_server diff --git a/etherlink/bin_node/lib_dev/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index fb62f9b88d72..0c8104dd40f5 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -9,7 +9,7 @@ module type S = sig module Block_storage : Block_storage_sig.S - module Tezlink_backend : Tezlink_backend_sig.S + module Tezlink : Tezlink_backend_sig.S (** [balance address block_param] returns the [address]'s balance at block [block_param]. *) @@ -184,7 +184,7 @@ module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct include Publisher.Make (Backend.TxEncoder) (Backend.Publisher) include Simulator.Make (Backend.SimulatorBackend) - module Tezlink_backend = Tezlink_services_impl.Make (struct + module Tezlink = Tezlink_services_impl.Make (struct include Backend.Reader let block_param_to_block_number = Backend.block_param_to_block_number -- GitLab From a142595942ee8f6968e30f98e4c304b95a554975 Mon Sep 17 00:00:00 2001 From: arnaud Date: Thu, 15 May 2025 13:36:26 +0200 Subject: [PATCH 3/6] L2/Node: Put Etherlink function from service_backend_sig in modules --- .../bin_node/lib_dev/etherlink_backend_sig.ml | 85 +++++++++++++ etherlink/bin_node/lib_dev/evm_ro_context.ml | 12 +- etherlink/bin_node/lib_dev/proxy.ml | 2 +- etherlink/bin_node/lib_dev/services.ml | 51 +++++--- .../bin_node/lib_dev/services_backend_sig.ml | 113 ++++-------------- etherlink/bin_node/lib_dev/tx_pool.ml | 16 +-- etherlink/bin_node/lib_dev/validate.ml | 10 +- 7 files changed, 164 insertions(+), 125 deletions(-) create mode 100644 etherlink/bin_node/lib_dev/etherlink_backend_sig.ml diff --git a/etherlink/bin_node/lib_dev/etherlink_backend_sig.ml b/etherlink/bin_node/lib_dev/etherlink_backend_sig.ml new file mode 100644 index 000000000000..81417b42372d --- /dev/null +++ b/etherlink/bin_node/lib_dev/etherlink_backend_sig.ml @@ -0,0 +1,85 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs *) +(* Copyright (c) 2025 Functori *) +(* *) +(*****************************************************************************) + +module type S = sig + (** [balance address block_param] returns the [address]'s balance at block + [block_param]. *) + val balance : + Ethereum_types.address -> + Ethereum_types.Block_parameter.extended -> + Ethereum_types.quantity tzresult Lwt.t + + (** [nonce address block_param] returns the [address]'s nonce at + block [block_param]. *) + val nonce : + Ethereum_types.address -> + Ethereum_types.Block_parameter.extended -> + Ethereum_types.quantity option tzresult Lwt.t + + (** [code address block_param] returns the [address]'s code at block + [block_param]. *) + val code : + Ethereum_types.address -> + Ethereum_types.Block_parameter.extended -> + Ethereum_types.hex tzresult Lwt.t + + (** [inject_transactions ~timestamp ~smart_rollup_address + ~transactions] crafts the hashes and chunks of each transaction + of [transactions]. Injects the chunks and returns the hashes of + injected transactions. *) + val inject_transactions : + timestamp:Time.Protocol.t -> + smart_rollup_address:string -> + transactions:(string * Ethereum_types.legacy_transaction_object) list -> + Ethereum_types.hash list 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 + + (** [backlog ()] returns the current backlog of the chain, used to determine + the base fee per gas for the next block. *) + val backlog : unit -> Z.t tzresult Lwt.t + + (** [minimum_base_fee_per_gas ()] returns the floor price for one unit of + gas. *) + val minimum_base_fee_per_gas : unit -> Z.t tzresult Lwt.t + + (** [simulate_call call_info block_param state_override] simulates a call on + context [block_param] (optionally updated with [state_override]) and + returns the result. *) + val simulate_call : + overwrite_tick_limit:bool -> + Ethereum_types.call -> + Ethereum_types.Block_parameter.extended -> + Ethereum_types.state_override -> + Simulation.call_result Simulation.simulation_result tzresult Lwt.t + + (** [estimate_gas call_info] asks the rollup to simulate a call, and + returns the gas used to execute the call. *) + val estimate_gas : + Ethereum_types.call -> + Ethereum_types.Block_parameter.t -> + Simulation.call_result Simulation.simulation_result tzresult Lwt.t + + (** [storage_at address pos block_param] returns the value at index + [pos] of the account [address]'s storage on block + [block_param]. *) + val storage_at : + Ethereum_types.address -> + Ethereum_types.quantity -> + Ethereum_types.Block_parameter.extended -> + Ethereum_types.hex tzresult Lwt.t + + val replay : + Ethereum_types.quantity -> + Ethereum_types.legacy_transaction_object Ethereum_types.block tzresult Lwt.t + + (** [coinbase ()] returns the sequencer pool address if it exists, + or the zero address. *) + val coinbase : unit -> Ethereum_types.address tzresult Lwt.t +end diff --git a/etherlink/bin_node/lib_dev/evm_ro_context.ml b/etherlink/bin_node/lib_dev/evm_ro_context.ml index 4af65f9b30c2..2bf55c9e12b3 100644 --- a/etherlink/bin_node/lib_dev/evm_ro_context.ml +++ b/etherlink/bin_node/lib_dev/evm_ro_context.ml @@ -482,6 +482,7 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) (module struct include Backend + (* Overwrite Block_storage module *) module Block_storage = struct (* Current block number is kept in durable storage. *) let current_block_number = Block_storage.current_block_number @@ -542,6 +543,10 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) Evm_store.Transactions.find_object conn hash end + (* Overwrite Etherlink Tracer using the new Etherlink_block_storage *) + module Tracer_etherlink = + Tracer_sig.Make (Executor) (Block_storage) (Tracer) + let block_param_to_block_number (block_param : Ethereum_types.Block_parameter.extended) = let open Lwt_result_syntax in @@ -565,13 +570,12 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) let nth_block_hash = Block_storage.nth_block_hash end) - - include Tracer_sig.Make (Executor) (Block_storage) (Tracer) end) else (module struct include Backend + (* Overwrite Block_storage module *) module Block_storage = struct (* Current block number is kept in durable storage. *) let current_block_number = Block_storage.current_block_number @@ -635,7 +639,9 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) | None -> return_none end - include Tracer_sig.Make (Executor) (Block_storage) (Tracer) + (* Overwrite Etherlink Tracer using the new Etherlink_block_storage *) + module Tracer_etherlink = + Tracer_sig.Make (Executor) (Block_storage) (Tracer) end) let next_blueprint_number ctxt = diff --git a/etherlink/bin_node/lib_dev/proxy.ml b/etherlink/bin_node/lib_dev/proxy.ml index 63ac6020f543..d62898ca96a5 100644 --- a/etherlink/bin_node/lib_dev/proxy.ml +++ b/etherlink/bin_node/lib_dev/proxy.ml @@ -85,7 +85,7 @@ let tx_queue_pop_and_inject (module Rollup_node_rpc : Services_backend_sig.S) ~validate_tx in let*! hashes = - Rollup_node_rpc.inject_transactions + Rollup_node_rpc.Etherlink.inject_transactions (* The timestamp is ignored in observer and proxy mode, it's just for compatibility with sequencer mode. *) ~timestamp:(Misc.now ()) diff --git a/etherlink/bin_node/lib_dev/services.ml b/etherlink/bin_node/lib_dev/services.ml index f67587dc5fb2..fe554a3d7c31 100644 --- a/etherlink/bin_node/lib_dev/services.ml +++ b/etherlink/bin_node/lib_dev/services.ml @@ -400,7 +400,8 @@ let get_fee_history block_count block_parameter config (module Backend_rpc) in let* base_fee_per_gas_next_block = - if newest_block.number = nb_latest then Backend_rpc.base_fee_per_gas () + if newest_block.number = nb_latest then + Backend_rpc.Etherlink.base_fee_per_gas () else let next_block_number = Qty.next newest_block.number in let* next_block = @@ -527,14 +528,16 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) build_with_input ~f module_ parameters | Get_balance.Method -> let f (address, block_param) = - let* balance = Backend_rpc.balance address block_param in + let* balance = + Backend_rpc.Etherlink.balance address block_param + in rpc_ok balance in build_with_input ~f module_ parameters | Get_storage_at.Method -> let f (address, position, block_param) = let* value = - Backend_rpc.storage_at address position block_param + Backend_rpc.Etherlink.storage_at address position block_param in rpc_ok value in @@ -578,7 +581,7 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) build_with_input ~f module_ parameters | Get_code.Method -> let f (address, block_param) = - let* code = Backend_rpc.code address block_param in + let* code = Backend_rpc.Etherlink.code address block_param in rpc_ok code in build_with_input ~f module_ parameters @@ -603,9 +606,13 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) increase to 33% of what it was before. For a current gas price of 1.5Gwei, the result of `eth_gasPrice` cannot be larger than 2 Gwei (¾ * 1.5). *) - let* minimum = Backend_rpc.minimum_base_fee_per_gas () in - let* (Qty latest_price) = Backend_rpc.base_fee_per_gas () in - let* backlog = Backend_rpc.backlog () in + let* minimum = + Backend_rpc.Etherlink.minimum_base_fee_per_gas () + in + let* (Qty latest_price) = + Backend_rpc.Etherlink.base_fee_per_gas () + in + let* backlog = Backend_rpc.Etherlink.backlog () in let* storage_version = Backend_rpc.storage_version () in let base_fee = let open Z in @@ -623,12 +630,16 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) let f (address, block_param) = match block_param with | Ethereum_types.Block_parameter.(Block_parameter Pending) -> - let* next_nonce = Backend_rpc.nonce address block_param in + let* next_nonce = + Backend_rpc.Etherlink.nonce address block_param + in let next_nonce = Option.value ~default:Qty.zero next_nonce in let* nonce = Tx_container.nonce ~next_nonce address in rpc_ok nonce | _ -> - let* nonce = Backend_rpc.nonce address block_param in + let* nonce = + Backend_rpc.Etherlink.nonce address block_param + in let nonce = Option.value ~default:Qty.zero nonce in rpc_ok nonce in @@ -765,7 +776,7 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) | Eth_call.Method -> let f (call, block_param, state_override) = let* call_result = - Backend_rpc.simulate_call + Backend_rpc.Etherlink.simulate_call ~overwrite_tick_limit: config.experimental_features.overwrite_simulation_tick_limit call @@ -791,7 +802,7 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) build_with_input ~f module_ parameters | Get_estimate_gas.Method -> let f (call, block) = - let* result = Backend_rpc.estimate_gas call block in + let* result = Backend_rpc.Etherlink.estimate_gas call block in match result with | Ok (Ok {value = _; gas_used = Some gas}) -> rpc_ok gas | Ok (Ok {value = _; gas_used = None}) -> @@ -857,7 +868,9 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) build ~f module_ parameters | Trace_transaction.Method -> let f ((hash, config) : Tracer_types.input) = - let*! trace = Backend_rpc.trace_transaction hash config in + let*! trace = + Backend_rpc.Tracer_etherlink.trace_transaction hash config + in process_trace_result trace in build_with_input ~f module_ parameters @@ -881,13 +894,15 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) | Coinbase.Method -> let f (_ : unit option) = let open Lwt_result_syntax in - let* coinbase = Backend_rpc.coinbase () in + let* coinbase = Backend_rpc.Etherlink.coinbase () in rpc_ok coinbase in build ~f module_ parameters | Trace_call.Method -> let f (((call, block), config) : Tracer_types.call_input) = - let*! trace = Backend_rpc.trace_call call block config in + let*! trace = + Backend_rpc.Tracer_etherlink.trace_call call block config + in process_trace_result trace in build_with_input ~f module_ parameters @@ -898,7 +913,9 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) (Block_parameter block_param) in let*! traces = - Backend_rpc.trace_block (Qty block_number) config + Backend_rpc.Tracer_etherlink.trace_block + (Qty block_number) + config in process_trace_result traces in @@ -990,7 +1007,7 @@ let dispatch_private_request (rpc_server_family : Rpc_types.rpc_server_family) let* is_valid = let get_nonce () = let* next_nonce = - Backend_rpc.nonce + Backend_rpc.Etherlink.nonce transaction_object.from (Block_parameter Latest) in @@ -1056,7 +1073,7 @@ let dispatch_private_request (rpc_server_family : Rpc_types.rpc_server_family) ~none:[error_of_fmt "missing block number"] block_number in - let* block = Backend_rpc.replay block_number in + let* block = Backend_rpc.Etherlink.replay block_number in rpc_ok block in build ~f module_ parameters diff --git a/etherlink/bin_node/lib_dev/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index 0c8104dd40f5..19fea3b8518e 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -11,36 +11,9 @@ module type S = sig module Tezlink : Tezlink_backend_sig.S - (** [balance address block_param] returns the [address]'s balance at block - [block_param]. *) - val balance : - Ethereum_types.address -> - Ethereum_types.Block_parameter.extended -> - Ethereum_types.quantity tzresult Lwt.t + module Etherlink : Etherlink_backend_sig.S - (** [nonce address block_param] returns the [address]'s nonce at - block [block_param]. *) - val nonce : - Ethereum_types.address -> - Ethereum_types.Block_parameter.extended -> - Ethereum_types.quantity option tzresult Lwt.t - - (** [code address block_param] returns the [address]'s code at block - [block_param]. *) - val code : - Ethereum_types.address -> - Ethereum_types.Block_parameter.extended -> - Ethereum_types.hex tzresult Lwt.t - - (** [inject_transactions ~timestamp ~smart_rollup_address - ~transactions] crafts the hashes and chunks of each transaction - of [transactions]. Injects the chunks and returns the hashes of - injected transactions. *) - val inject_transactions : - timestamp:Time.Protocol.t -> - smart_rollup_address:string -> - transactions:(string * Ethereum_types.legacy_transaction_object) list -> - Ethereum_types.hash list tzresult Lwt.t + module Tracer_etherlink : Tracer_sig.S val block_param_to_block_number : Ethereum_types.Block_parameter.extended -> @@ -74,22 +47,11 @@ module type S = sig enable_multichain:bool -> (L2_types.chain_id option * 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 - - (** [backlog ()] returns the current backlog of the chain, used to determine - the base fee per gas for the next block. *) - val backlog : unit -> Z.t tzresult Lwt.t - (** [storage_version ()] returns the latest storage version known to the current kernel. This can be used to determine which features are and are not supported. *) val storage_version : unit -> int tzresult Lwt.t - (** [minimum_base_fee_per_gas ()] returns the floor price for one unit of - gas. *) - val minimum_base_fee_per_gas : unit -> Z.t tzresult Lwt.t - (** [kernel_version ()] returns the internal kernel version (i.e the commit hash where the kernel was compiled). *) val kernel_version : unit -> string tzresult Lwt.t @@ -98,45 +60,8 @@ module type S = sig latest root hash that was applied during an upgrade). *) val kernel_root_hash : unit -> string option tzresult Lwt.t - (** [simulate_call call_info block_param state_override] simulates a call on - context [block_param] (optionally updated with [state_override]) and - returns the result. *) - val simulate_call : - overwrite_tick_limit:bool -> - Ethereum_types.call -> - Ethereum_types.Block_parameter.extended -> - Ethereum_types.state_override -> - Simulation.call_result Simulation.simulation_result tzresult Lwt.t - - (** [estimate_gas call_info] asks the rollup to simulate a call, and - returns the gas used to execute the call. *) - val estimate_gas : - Ethereum_types.call -> - Ethereum_types.Block_parameter.t -> - Simulation.call_result Simulation.simulation_result tzresult Lwt.t - - (** [storage_at address pos block_param] returns the value at index - [pos] of the account [address]'s storage on block - [block_param]. *) - val storage_at : - Ethereum_types.address -> - Ethereum_types.quantity -> - Ethereum_types.Block_parameter.extended -> - Ethereum_types.hex tzresult Lwt.t - val smart_rollup_address : string - val replay : - Ethereum_types.quantity -> - Ethereum_types.legacy_transaction_object Ethereum_types.block tzresult Lwt.t - - (** [coinbase ()] returns the sequencer pool address if it exists, - or the zero address. *) - val coinbase : unit -> Ethereum_types.address tzresult Lwt.t - - (** [is_multichain_enabled ()] returns the value of the multichain feature flag - this method targets proxy nodes that do not have direct access - to the durable storage. *) val is_multichain_enabled : unit -> bool tzresult Lwt.t val list_l1_l2_levels : @@ -145,8 +70,6 @@ module type S = sig val l2_levels_of_l1_level : int32 -> Evm_store.L1_l2_finalized_levels.t option tzresult Lwt.t - - include Tracer_sig.S end module type Backend = sig @@ -178,11 +101,26 @@ end module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct module Reader = Backend.Reader - include Etherlink_durable_storage.Make (Backend.Reader) module Block_storage = Etherlink_durable_storage.Make_block_storage (Backend.Reader) - include Publisher.Make (Backend.TxEncoder) (Backend.Publisher) - include Simulator.Make (Backend.SimulatorBackend) + + module Etherlink = struct + include Etherlink_durable_storage.Make (Backend.Reader) + include Publisher.Make (Backend.TxEncoder) (Backend.Publisher) + include Simulator.Make (Backend.SimulatorBackend) + + let replay number = + let open Lwt_result_syntax in + let* result = Executor.replay ~log_file:"replay_rpc" number 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" + end + + module Tracer_etherlink = + Tracer_sig.Make (Executor) (Block_storage) (Backend.Tracer) module Tezlink = Tezlink_services_impl.Make (struct include Backend.Reader @@ -196,17 +134,6 @@ module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct let block_param_to_block_number = Backend.block_param_to_block_number - include Tracer_sig.Make (Executor) (Block_storage) (Backend.Tracer) - - let replay number = - let open Lwt_result_syntax in - let* result = Executor.replay ~log_file:"replay_rpc" number 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" - include Durable_storage.Make (Reader) let smart_rollup_address = Backend.smart_rollup_address diff --git a/etherlink/bin_node/lib_dev/tx_pool.ml b/etherlink/bin_node/lib_dev/tx_pool.ml index 3a226c4029c0..0c24e07f4ce3 100644 --- a/etherlink/bin_node/lib_dev/tx_pool.ml +++ b/etherlink/bin_node/lib_dev/tx_pool.ml @@ -511,13 +511,13 @@ let pop_transactions state ~maximum_cumulative_size = Lwt_list.map_p (fun address -> let* nonce = - Backend.nonce + Backend.Etherlink.nonce address Ethereum_types.Block_parameter.(Block_parameter Latest) in let (Qty nonce) = Option.value ~default:(Qty Z.zero) nonce in let* (Qty balance) = - Backend.balance + Backend.Etherlink.balance address Ethereum_types.Block_parameter.(Block_parameter Latest) in @@ -527,7 +527,7 @@ let pop_transactions state ~maximum_cumulative_size = let addr_with_nonces = List.filter_ok addr_with_nonces in (* Remove transactions with too low nonce, timed-out and the ones that can not be prepayed anymore. *) - let* (Qty base_fee_per_gas) = Backend.base_fee_per_gas () in + let* (Qty base_fee_per_gas) = Backend.Etherlink.base_fee_per_gas () in let current_timestamp = Misc.now () in let pool = List.fold_left @@ -635,7 +635,7 @@ let pop_and_inject_transactions state = if not (List.is_empty txs) then let (module Backend : Services_backend_sig.S) = state.backend in let*! hashes = - Backend.inject_transactions + Backend.Etherlink.inject_transactions (* The timestamp is ignored in observer and proxy mode, it's just for compatibility with sequencer mode. *) ~timestamp:(Misc.now ()) @@ -820,7 +820,9 @@ let nonce pkey = let*? w = Lazy.force worker in let Types.{backend = (module Backend); pool; _} = Worker.state w in let+ current_nonce = - Backend.nonce pkey Ethereum_types.Block_parameter.(Block_parameter Latest) + Backend.Etherlink.nonce + pkey + Ethereum_types.Block_parameter.(Block_parameter Latest) in let current_nonce = Option.value ~default:Ethereum_types.Qty.zero current_nonce @@ -880,13 +882,13 @@ let get_tx_pool_content () = Lwt_list.map_p (fun address -> let* nonce = - Backend.nonce + Backend.Etherlink.nonce address Ethereum_types.Block_parameter.(Block_parameter Latest) in let (Qty nonce) = Option.value ~default:(Qty Z.zero) nonce in let* (Qty balance) = - Backend.balance + Backend.Etherlink.balance address Ethereum_types.Block_parameter.(Block_parameter Latest) in diff --git a/etherlink/bin_node/lib_dev/validate.ml b/etherlink/bin_node/lib_dev/validate.ml index 71f54704f133..f23e468696f5 100644 --- a/etherlink/bin_node/lib_dev/validate.ml +++ b/etherlink/bin_node/lib_dev/validate.ml @@ -67,7 +67,7 @@ let validate_sender_not_a_contract (module Backend_rpc : Services_backend_sig.S) caller : (unit, string) result tzresult Lwt.t = let open Lwt_result_syntax in let* (Hex code) = - Backend_rpc.code caller Block_parameter.(Block_parameter Latest) + Backend_rpc.Etherlink.code caller Block_parameter.(Block_parameter Latest) in if code = "" then return (Ok ()) else return (Error "Sender is a contract which is not possible") @@ -141,9 +141,11 @@ let validate_with_state_from_backend (module Backend_rpc : Services_backend_sig.S) transaction ~caller = let open Lwt_result_syntax in let* from_balance = - Backend_rpc.balance caller Block_parameter.(Block_parameter Latest) + Backend_rpc.Etherlink.balance + caller + Block_parameter.(Block_parameter Latest) in - let* base_fee_per_gas = Backend_rpc.base_fee_per_gas () in + let* base_fee_per_gas = Backend_rpc.Etherlink.base_fee_per_gas () in let* state = Backend_rpc.Reader.get_state () in let* maximum_gas_limit = Etherlink_durable_storage.maximum_gas_per_transaction @@ -170,7 +172,7 @@ let valid_transaction_object ?max_number_of_chunks ~backend_rpc ~hash ~mode tx = let caller = tx_object.from in let* next_nonce = let (module Backend_rpc : Services_backend_sig.S) = backend_rpc in - Backend_rpc.nonce caller Block_parameter.(Block_parameter Latest) + Backend_rpc.Etherlink.nonce caller Block_parameter.(Block_parameter Latest) in let next_nonce = match next_nonce with None -> Qty Z.zero | Some next_nonce -> next_nonce -- GitLab From 8fc05234f3dcad8d1879e060227b3056d32e2905 Mon Sep 17 00:00:00 2001 From: arnaud Date: Tue, 20 May 2025 17:48:48 +0200 Subject: [PATCH 4/6] L2/Node: Introduce tezlink_durable_storage module --- .../lib_dev/tezlink_durable_storage.ml | 80 +++++++++++++++++++ .../bin_node/lib_dev/tezlink_services_impl.ml | 22 +---- 2 files changed, 83 insertions(+), 19 deletions(-) create mode 100644 etherlink/bin_node/lib_dev/tezlink_durable_storage.ml diff --git a/etherlink/bin_node/lib_dev/tezlink_durable_storage.ml b/etherlink/bin_node/lib_dev/tezlink_durable_storage.ml new file mode 100644 index 000000000000..54339675f963 --- /dev/null +++ b/etherlink/bin_node/lib_dev/tezlink_durable_storage.ml @@ -0,0 +1,80 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Nomadic Labs *) +(* Copyright (c) 2025 Functori *) +(* *) +(*****************************************************************************) +open Tezos_types + +module Path = struct + (** [to_path encoding value] uses [encoding] to encode [value] in + hexadecimal *) + let to_path encoding value = + let raw_key = Data_encoding.Binary.to_bytes_exn encoding value in + let (`Hex s) = Hex.of_bytes raw_key in + s + + let account contract = + "/tezlink/context/contracts/index/" ^ to_path Contract.encoding contract + + let balance contract = account contract ^ "/balance" + + let manager_key contract = account contract ^ "/manager_key" + + let counter contract = account contract ^ "/counter" +end + +let balance read c = + Durable_storage.inspect_durable_and_decode_default + ~default:Tezos_types.Tez.zero + read + (Path.balance c) + (Data_encoding.Binary.of_bytes_exn Tez.encoding) + +let manager_key read c = + Durable_storage.inspect_durable_and_decode_opt + read + (Path.manager_key c) + (Data_encoding.Binary.of_bytes_exn Signature.V1.Public_key.encoding) + +let counter read c = + Durable_storage.inspect_durable_and_decode_default + (* FIXME: #7960 + This default should be the global counter *) + ~default:Z.one + read + (Path.counter c) + (Data_encoding.Binary.of_bytes_exn Data_encoding.z) + +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* block_hash_opt = + Durable_storage.inspect_durable_and_decode_opt + read + (Durable_storage_path.Indexes.block_by_number (Nth level)) + Ethereum_types.decode_block_hash + in + match block_hash_opt with + | None -> failwith "Block %a not found" Z.pp_print level + | Some block_hash -> ( + let* block_opt = + Durable_storage.inspect_durable_and_decode_opt + read + (Durable_storage_path.Block.by_hash block_hash) + L2_types.Tezos_block.block_from_binary + in + match block_opt with + | None -> + raise + @@ Durable_storage.Invalid_block_structure "Couldn't decode bytes" + | Some block -> return block) + +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) + Ethereum_types.decode_block_hash diff --git a/etherlink/bin_node/lib_dev/tezlink_services_impl.ml b/etherlink/bin_node/lib_dev/tezlink_services_impl.ml index 669cf93c7f86..b05b9f2fc9b0 100644 --- a/etherlink/bin_node/lib_dev/tezlink_services_impl.ml +++ b/etherlink/bin_node/lib_dev/tezlink_services_impl.ml @@ -101,35 +101,19 @@ module Make (Backend : Backend) : Tezlink_backend_sig.S = struct let balance chain block c = let `Main = chain in - - Durable_storage.inspect_durable_and_decode_default - ~default:Tezos_types.Tez.zero - (read ~block) - (Path.balance c) - (Data_encoding.Binary.of_bytes_exn Tez.encoding) + Tezlink_durable_storage.balance (read ~block) c let manager_key chain block c = (* TODO: #7831 !17664 Support non-default chain and block parameters. *) let `Main = chain in - - Durable_storage.inspect_durable_and_decode_opt - (read ~block) - (Path.manager_key c) - (Data_encoding.Binary.of_bytes_exn Signature.V1.Public_key.encoding) + Tezlink_durable_storage.manager_key (read ~block) c let counter chain block c = (* TODO: #7831 !17664 Support non-default chain and block parameters. *) let `Main = chain in - - Durable_storage.inspect_durable_and_decode_default - (* FIXME: #7960 - This default should be the global counter *) - ~default:Z.one - (read ~block) - (Path.counter c) - (Data_encoding.Binary.of_bytes_exn Data_encoding.z) + Tezlink_durable_storage.counter (read ~block) c let header chain block = let open Lwt_result_syntax in -- GitLab From 47a065a1e9ed5e5914c32fdbdae2d084efdada9e Mon Sep 17 00:00:00 2001 From: arnaud Date: Wed, 14 May 2025 11:02:10 +0200 Subject: [PATCH 5/6] L2/node: Introduce a Tezlink_block_storage module like for Etherlink --- .../bin_node/lib_dev/block_storage_sig.ml | 6 --- .../lib_dev/etherlink_durable_storage.ml | 40 -------------- etherlink/bin_node/lib_dev/evm_ro_context.ml | 53 ++++++++++--------- .../bin_node/lib_dev/services_backend_sig.ml | 17 +++--- .../tezlink/tezlink_block_storage_sig.ml | 14 +++++ .../lib_dev/tezlink_durable_storage.ml | 18 +++++++ .../bin_node/lib_dev/tezlink_services_impl.ml | 16 +++--- 7 files changed, 74 insertions(+), 90 deletions(-) create mode 100644 etherlink/bin_node/lib_dev/tezlink/tezlink_block_storage_sig.ml diff --git a/etherlink/bin_node/lib_dev/block_storage_sig.ml b/etherlink/bin_node/lib_dev/block_storage_sig.ml index f0aef9e94a85..5d644efcb764 100644 --- a/etherlink/bin_node/lib_dev/block_storage_sig.ml +++ b/etherlink/bin_node/lib_dev/block_storage_sig.ml @@ -21,12 +21,6 @@ module type S = sig Z.t -> Transaction_object.t Ethereum_types.block tzresult Lwt.t - (** [tez_nth_block n] returns the [n]th processed and stored tez block. *) - val tez_nth_block : Z.t -> L2_types.Tezos_block.t tzresult Lwt.t - - (** [nth_block_hash n] returns the hash of the [n]th processed and stored block. *) - val nth_block_hash : Z.t -> Ethereum_types.block_hash option tzresult Lwt.t - (** [block_by_hash ~full_transaction_object hash] returns the block with the given [hash]. diff --git a/etherlink/bin_node/lib_dev/etherlink_durable_storage.ml b/etherlink/bin_node/lib_dev/etherlink_durable_storage.ml index 843748d1a05e..0234210f5288 100644 --- a/etherlink/bin_node/lib_dev/etherlink_durable_storage.ml +++ b/etherlink/bin_node/lib_dev/etherlink_durable_storage.ml @@ -180,36 +180,6 @@ let nth_block read ~full_transaction_object n = ~full_transaction_object ~number:Durable_storage_path.Block.(Nth n) -let tez_nth_block read n = - let open Lwt_result_syntax in - let number = Durable_storage_path.Block.(Nth n) in - let* (Ethereum_types.Qty level) = block_number read number in - let* block_hash_opt = - inspect_durable_and_decode_opt - read - (Durable_storage_path.Indexes.block_by_number (Nth level)) - decode_block_hash - in - match block_hash_opt with - | None -> failwith "Block %a not found" Z.pp_print level - | Some block_hash -> ( - let* block_opt = - inspect_durable_and_decode_opt - read - (Durable_storage_path.Block.by_hash block_hash) - L2_types.Tezos_block.block_from_binary - in - match block_opt with - | None -> raise @@ Invalid_block_structure "Couldn't decode bytes" - | Some block -> return block) - -let nth_block_hash read n = - let number = Durable_storage_path.Block.(Nth n) in - inspect_durable_and_decode_opt - read - (Durable_storage_path.Indexes.block_by_number number) - decode_block_hash - let block_by_hash read ~full_transaction_object block_hash = let open Lwt_result_syntax in let* block_opt = @@ -387,22 +357,12 @@ module Make_block_storage (Reader : READER) = struct let* read = read_with_state () in current_block_number read - let nth_block_hash n = - let open Lwt_result_syntax in - let* read = read_with_state () in - nth_block_hash read n - let nth_block ~full_transaction_object n = let open Lwt_result_syntax in let* read = read_with_state () in let+ block = nth_block read ~full_transaction_object n in Transaction_object.block_from_legacy block - let tez_nth_block n = - let open Lwt_result_syntax in - let* read = read_with_state () in - tez_nth_block read n - let block_by_hash ~full_transaction_object block_hash = let open Lwt_result_syntax in let* read = read_with_state () in diff --git a/etherlink/bin_node/lib_dev/evm_ro_context.ml b/etherlink/bin_node/lib_dev/evm_ro_context.ml index 2bf55c9e12b3..1452c02f6700 100644 --- a/etherlink/bin_node/lib_dev/evm_ro_context.ml +++ b/etherlink/bin_node/lib_dev/evm_ro_context.ml @@ -482,6 +482,12 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) (module struct include Backend + (* This function is generic that's why we don't define it in Tezlink block storage + (even if for now this is the only place where it's used) *) + let nth_block_hash level = + Evm_store.use ctxt.store @@ fun conn -> + Evm_store.Blocks.find_hash_of_number conn (Qty level) + (* Overwrite Block_storage module *) module Block_storage = struct (* Current block number is kept in durable storage. *) @@ -500,20 +506,6 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) | None -> failwith "Block %a not found" Z.pp_print level | Some block -> return block - let tez_nth_block level = - let open Lwt_result_syntax in - Evm_store.use ctxt.store @@ fun conn -> - let* block_opt = - Evm_store.Blocks.tez_find_with_level conn (Qty level) - in - match block_opt with - | None -> failwith "Block %a not found" Z.pp_print level - | Some block -> return block - - let nth_block_hash level = - Evm_store.use ctxt.store @@ fun conn -> - Evm_store.Blocks.find_hash_of_number conn (Qty level) - let block_by_hash ~full_transaction_object hash = let open Lwt_result_syntax in Evm_store.use ctxt.store @@ fun conn -> @@ -560,16 +552,29 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) failwith "Missing block %a" Ethereum_types.pp_block_hash hash) | param -> block_param_to_block_number param - (* Overwrites Tezlink using the store instead of the durable_storage *) - module Tezlink = Tezlink_services_impl.Make (struct - include Backend.Reader - - let block_param_to_block_number = block_param_to_block_number + module Tezlink_block_storage : Tezlink_block_storage_sig.S = struct + let nth_block level = + let open Lwt_result_syntax in + Evm_store.use ctxt.store @@ fun conn -> + let* block_opt = + Evm_store.Blocks.tez_find_with_level conn (Qty level) + in + match block_opt with + | None -> failwith "Block %a not found" Z.pp_print level + | Some block -> return block - let tez_nth_block = Block_storage.tez_nth_block + let nth_block_hash = nth_block_hash + end - let nth_block_hash = Block_storage.nth_block_hash - end) + (* Overwrites Tezlink using the store instead of the durable_storage *) + module Tezlink = + Tezlink_services_impl.Make + (struct + include Backend.Reader + + let block_param_to_block_number = block_param_to_block_number + end) + (Tezlink_block_storage) end) else (module struct @@ -601,10 +606,6 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) need to try to reconstruct the transaction objects. *) return block - let tez_nth_block = Block_storage.tez_nth_block - - let nth_block_hash = Block_storage.nth_block_hash - let block_by_hash ~full_transaction_object hash = let open Lwt_result_syntax in let* block = diff --git a/etherlink/bin_node/lib_dev/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index 19fea3b8518e..79664e3dbe2c 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -121,16 +121,17 @@ module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct module Tracer_etherlink = Tracer_sig.Make (Executor) (Block_storage) (Backend.Tracer) + module Tezlink_block_storage = + Tezlink_durable_storage.Make_block_storage (Backend.Reader) - module Tezlink = Tezlink_services_impl.Make (struct - include Backend.Reader + module Tezlink = + Tezlink_services_impl.Make + (struct + include Backend.Reader - let block_param_to_block_number = Backend.block_param_to_block_number - - let nth_block_hash = Block_storage.nth_block_hash - - let tez_nth_block = Block_storage.tez_nth_block - end) + let block_param_to_block_number = Backend.block_param_to_block_number + end) + (Tezlink_block_storage) let block_param_to_block_number = Backend.block_param_to_block_number diff --git a/etherlink/bin_node/lib_dev/tezlink/tezlink_block_storage_sig.ml b/etherlink/bin_node/lib_dev/tezlink/tezlink_block_storage_sig.ml new file mode 100644 index 000000000000..82c3a93a4068 --- /dev/null +++ b/etherlink/bin_node/lib_dev/tezlink/tezlink_block_storage_sig.ml @@ -0,0 +1,14 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs *) +(* *) +(*****************************************************************************) + +module type S = sig + (** [nth_block n] returns the [n]th processed and stored tez block. *) + val nth_block : Z.t -> L2_types.Tezos_block.t tzresult Lwt.t + + (** [nth_block_hash n] returns the hash of the [n]th processed and stored block. *) + val nth_block_hash : Z.t -> Ethereum_types.block_hash option tzresult Lwt.t +end diff --git a/etherlink/bin_node/lib_dev/tezlink_durable_storage.ml b/etherlink/bin_node/lib_dev/tezlink_durable_storage.ml index 54339675f963..7b51ac27b6be 100644 --- a/etherlink/bin_node/lib_dev/tezlink_durable_storage.ml +++ b/etherlink/bin_node/lib_dev/tezlink_durable_storage.ml @@ -78,3 +78,21 @@ let nth_block_hash read n = read (Durable_storage_path.Indexes.block_by_number number) Ethereum_types.decode_block_hash + +module Make_block_storage (Reader : Durable_storage.READER) : + Tezlink_block_storage_sig.S = struct + let read_with_state () = + let open Lwt_result_syntax in + let* state = Reader.get_state () in + return (Reader.read state) + + let nth_block n = + let open Lwt_result_syntax in + let* read = read_with_state () in + nth_block read n + + let nth_block_hash n = + let open Lwt_result_syntax in + let* read = read_with_state () in + nth_block_hash read n +end diff --git a/etherlink/bin_node/lib_dev/tezlink_services_impl.ml b/etherlink/bin_node/lib_dev/tezlink_services_impl.ml index b05b9f2fc9b0..d103d355b365 100644 --- a/etherlink/bin_node/lib_dev/tezlink_services_impl.ml +++ b/etherlink/bin_node/lib_dev/tezlink_services_impl.ml @@ -30,13 +30,10 @@ module type Backend = sig val block_param_to_block_number : Ethereum_types.Block_parameter.extended -> Ethereum_types.quantity tzresult Lwt.t - - val tez_nth_block : Z.t -> L2_types.Tezos_block.t tzresult Lwt.t - - val nth_block_hash : Z.t -> Ethereum_types.block_hash option tzresult Lwt.t end -module Make (Backend : Backend) : Tezlink_backend_sig.S = struct +module Make (Backend : Backend) (Block_storage : Tezlink_block_storage_sig.S) : + Tezlink_backend_sig.S = struct type block_param = [`Head of int32 | `Level of int32] let shell_block_param_to_block_number = @@ -119,7 +116,7 @@ module Make (Backend : Backend) : Tezlink_backend_sig.S = struct let open Lwt_result_syntax in let `Main = chain in let* block_number = shell_block_param_to_block_number block in - Backend.tez_nth_block (Z.of_int32 block_number) + Block_storage.nth_block (Z.of_int32 block_number) let monitor_heads chain query = (* TODO: #7831 @@ -146,7 +143,7 @@ module Make (Backend : Backend) : Tezlink_backend_sig.S = struct return_none | delay_ms :: rest -> ( let* () = Lwt_unix.sleep (delay_ms /. 1000.) in - let* block_result = Backend.tez_nth_block level in + let* block_result = Block_storage.nth_block level in match block_result with | Ok block -> return_some block | Error _ -> fetch_block level rest) @@ -170,13 +167,12 @@ module Make (Backend : Backend) : Tezlink_backend_sig.S = struct let* (Qty current_block_number) = Backend.block_param_to_block_number (Block_parameter Latest) in - let* block = Backend.tez_nth_block current_block_number in + let* block = Block_storage.nth_block current_block_number in return (block.hash, block.timestamp) let block_hash chain block = let open Lwt_result_syntax in let `Main = chain in let* number = shell_block_param_to_block_number block in - - Backend.nth_block_hash (Z.of_int32 number) + Block_storage.nth_block_hash (Z.of_int32 number) end -- GitLab From 5efc906778249a2ffdbec6cba818ef42cb9e582a Mon Sep 17 00:00:00 2001 From: arnaud Date: Thu, 15 May 2025 13:03:07 +0200 Subject: [PATCH 6/6] L2/node: Rename Block_storage in Etherlink_block_storage --- etherlink/bin_node/lib_dev/evm_ro_context.ml | 28 ++++++++++--------- etherlink/bin_node/lib_dev/filter_helpers.ml | 8 ++++-- etherlink/bin_node/lib_dev/services.ml | 25 ++++++++++------- .../bin_node/lib_dev/services_backend_sig.ml | 6 ++-- 4 files changed, 38 insertions(+), 29 deletions(-) diff --git a/etherlink/bin_node/lib_dev/evm_ro_context.ml b/etherlink/bin_node/lib_dev/evm_ro_context.ml index 1452c02f6700..d2643b75030c 100644 --- a/etherlink/bin_node/lib_dev/evm_ro_context.ml +++ b/etherlink/bin_node/lib_dev/evm_ro_context.ml @@ -488,10 +488,10 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) Evm_store.use ctxt.store @@ fun conn -> Evm_store.Blocks.find_hash_of_number conn (Qty level) - (* Overwrite Block_storage module *) - module Block_storage = struct + (* Overwrite Etherlink_block_storage module *) + module Etherlink_block_storage = struct (* Current block number is kept in durable storage. *) - let current_block_number = Block_storage.current_block_number + let current_block_number = Etherlink_block_storage.current_block_number let nth_block ~full_transaction_object level = let open Lwt_result_syntax in @@ -537,7 +537,7 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) (* Overwrite Etherlink Tracer using the new Etherlink_block_storage *) module Tracer_etherlink = - Tracer_sig.Make (Executor) (Block_storage) (Tracer) + Tracer_sig.Make (Executor) (Etherlink_block_storage) (Tracer) let block_param_to_block_number (block_param : Ethereum_types.Block_parameter.extended) = @@ -580,10 +580,10 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) (module struct include Backend - (* Overwrite Block_storage module *) - module Block_storage = struct + (* Overwrite Etherlink_block_storage module *) + module Etherlink_block_storage = struct (* Current block number is kept in durable storage. *) - let current_block_number = Block_storage.current_block_number + let current_block_number = Etherlink_block_storage.current_block_number let with_blueprint ~default level k = let open Lwt_result_syntax in @@ -596,7 +596,9 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) let nth_block ~full_transaction_object level = let open Lwt_result_syntax in - let* block = Block_storage.nth_block ~full_transaction_object level in + let* block = + Etherlink_block_storage.nth_block ~full_transaction_object level + in if full_transaction_object then with_blueprint ~default:block block.number @@ fun blueprint -> Lwt.return @@ -609,7 +611,7 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) let block_by_hash ~full_transaction_object hash = let open Lwt_result_syntax in let* block = - Block_storage.block_by_hash ~full_transaction_object hash + Etherlink_block_storage.block_by_hash ~full_transaction_object hash in if full_transaction_object then with_blueprint ~default:block block.number @@ fun blueprint -> @@ -620,13 +622,13 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) need to try to reconstruct the transaction objects. *) return block - let block_receipts = Block_storage.block_receipts + let block_receipts = Etherlink_block_storage.block_receipts - let transaction_receipt = Block_storage.transaction_receipt + let transaction_receipt = Etherlink_block_storage.transaction_receipt let transaction_object hash = let open Lwt_result_syntax in - let* obj = Block_storage.transaction_object hash in + let* obj = Etherlink_block_storage.transaction_object hash in match obj with | Some obj -> ( match Transaction_object.block_number obj with @@ -642,7 +644,7 @@ let ro_backend ?evm_node_endpoint ctxt config : (module Services_backend_sig.S) (* Overwrite Etherlink Tracer using the new Etherlink_block_storage *) module Tracer_etherlink = - Tracer_sig.Make (Executor) (Block_storage) (Tracer) + Tracer_sig.Make (Executor) (Etherlink_block_storage) (Tracer) end) let next_blueprint_number ctxt = diff --git a/etherlink/bin_node/lib_dev/filter_helpers.ml b/etherlink/bin_node/lib_dev/filter_helpers.ml index 00f975d34f45..b4d33609f297 100644 --- a/etherlink/bin_node/lib_dev/filter_helpers.ml +++ b/etherlink/bin_node/lib_dev/filter_helpers.ml @@ -83,7 +83,7 @@ let validate_range log_filter_config tzfail Incompatible_block_params | {block_hash = Some block_hash; _} -> let* block = - Rollup_node_rpc.Block_storage.block_by_hash + Rollup_node_rpc.Etherlink_block_storage.block_by_hash ~full_transaction_object:false block_hash in @@ -213,7 +213,9 @@ let filter_one_tx (module Rollup_node_rpc : Services_backend_sig.S) : bloom_filter -> hash -> Filter.changes list option tzresult Lwt.t = fun filter tx_hash -> let open Lwt_result_syntax in - let* receipt = Rollup_node_rpc.Block_storage.transaction_receipt tx_hash in + let* receipt = + Rollup_node_rpc.Etherlink_block_storage.transaction_receipt tx_hash + in match receipt with | Some receipt -> return @@ filter_receipt filter receipt | None -> tzfail (Receipt_not_found tx_hash) @@ -224,7 +226,7 @@ let filter_one_block (module Rollup_node_rpc : Services_backend_sig.S) : fun filter block_number -> let open Lwt_result_syntax in let* block = - Rollup_node_rpc.Block_storage.nth_block + Rollup_node_rpc.Etherlink_block_storage.nth_block ~full_transaction_object:false block_number in diff --git a/etherlink/bin_node/lib_dev/services.ml b/etherlink/bin_node/lib_dev/services.ml index fe554a3d7c31..1fcf74e07dd3 100644 --- a/etherlink/bin_node/lib_dev/services.ml +++ b/etherlink/bin_node/lib_dev/services.ml @@ -180,7 +180,7 @@ let get_block_by_number ~full_transaction_object block_param let* (Ethereum_types.Qty n) = Rollup_node_rpc.block_param_to_block_number (Block_parameter block_param) in - Rollup_node_rpc.Block_storage.nth_block ~full_transaction_object n + Rollup_node_rpc.Etherlink_block_storage.nth_block ~full_transaction_object n let get_block_receipts block_param (module Rollup_node_rpc : Services_backend_sig.S) = @@ -188,7 +188,7 @@ let get_block_receipts block_param let* (Ethereum_types.Qty n) = Rollup_node_rpc.block_param_to_block_number (Block_parameter block_param) in - Rollup_node_rpc.Block_storage.block_receipts n + Rollup_node_rpc.Etherlink_block_storage.block_receipts n let get_transaction_from_index block index (module Rollup_node_rpc : Services_backend_sig.S) = @@ -197,7 +197,8 @@ let get_transaction_from_index block index | TxHash l -> ( match List.nth_opt l index with | None -> return_none - | Some hash -> Rollup_node_rpc.Block_storage.transaction_object hash) + | Some hash -> + Rollup_node_rpc.Etherlink_block_storage.transaction_object hash) | TxFull l -> return @@ List.nth_opt l index let block_transaction_count block = @@ -385,7 +386,9 @@ let get_fee_history block_count block_parameter config | Unlimited -> block_count | Limit block_count_limit -> Z.(min (of_int block_count_limit) block_count) in - let* nb_latest = Backend_rpc.Block_storage.current_block_number () in + let* nb_latest = + Backend_rpc.Etherlink_block_storage.current_block_number () + in let is_reachable nb = match Configuration.(config.fee_history.max_past) with | None -> true @@ -545,7 +548,7 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) | Block_number.Method -> let f (_ : unit option) = let* block_number = - Backend_rpc.Block_storage.current_block_number () + Backend_rpc.Etherlink_block_storage.current_block_number () in rpc_ok block_number in @@ -564,7 +567,7 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) | Get_block_by_hash.Method -> let f (block_hash, full_transaction_object) = let* block = - Backend_rpc.Block_storage.block_by_hash + Backend_rpc.Etherlink_block_storage.block_by_hash ~full_transaction_object block_hash in @@ -647,7 +650,7 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) | Get_block_transaction_count_by_hash.Method -> let f block_hash = let* block = - Backend_rpc.Block_storage.block_by_hash + Backend_rpc.Etherlink_block_storage.block_by_hash ~full_transaction_object:false block_hash in @@ -674,7 +677,7 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) | Get_transaction_receipt.Method -> let f tx_hash = let* receipt = - Backend_rpc.Block_storage.transaction_receipt tx_hash + Backend_rpc.Etherlink_block_storage.transaction_receipt tx_hash in rpc_ok receipt in @@ -685,7 +688,9 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) let* transaction_object = match transaction_object with | Some transaction_object -> return_some transaction_object - | None -> Backend_rpc.Block_storage.transaction_object tx_hash + | None -> + Backend_rpc.Etherlink_block_storage.transaction_object + tx_hash in rpc_ok transaction_object in @@ -693,7 +698,7 @@ let dispatch_request (rpc_server_family : Rpc_types.rpc_server_family) | Get_transaction_by_block_hash_and_index.Method -> let f (block_hash, Qty index) = let* block = - Backend_rpc.Block_storage.block_by_hash + Backend_rpc.Etherlink_block_storage.block_by_hash ~full_transaction_object:false block_hash in diff --git a/etherlink/bin_node/lib_dev/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index 79664e3dbe2c..c6b181962b55 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -7,7 +7,7 @@ module type S = sig module Reader : Durable_storage.READER - module Block_storage : Block_storage_sig.S + module Etherlink_block_storage : Block_storage_sig.S module Tezlink : Tezlink_backend_sig.S @@ -101,7 +101,7 @@ end module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct module Reader = Backend.Reader - module Block_storage = + module Etherlink_block_storage = Etherlink_durable_storage.Make_block_storage (Backend.Reader) module Etherlink = struct @@ -120,7 +120,7 @@ module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct end module Tracer_etherlink = - Tracer_sig.Make (Executor) (Block_storage) (Backend.Tracer) + Tracer_sig.Make (Executor) (Etherlink_block_storage) (Backend.Tracer) module Tezlink_block_storage = Tezlink_durable_storage.Make_block_storage (Backend.Reader) -- GitLab