From ff89caede5620e6d7c49a5c53d9af70bc9be3f78 Mon Sep 17 00:00:00 2001 From: Hantang Sun Date: Thu, 9 May 2024 22:14:55 +0800 Subject: [PATCH 1/9] Etherlink: implement eth_feeHistory rpc --- .../lib_dev/encodings/ethereum_types.ml | 26 +++++++++ .../lib_dev/encodings/ethereum_types.mli | 16 ++++++ etherlink/bin_node/lib_dev/rpc_encodings.ml | 22 +++++++- etherlink/bin_node/lib_dev/rpc_encodings.mli | 6 +++ etherlink/bin_node/lib_dev/services.ml | 54 +++++++++++++++++++ 5 files changed, 123 insertions(+), 1 deletion(-) diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml index c48d53637000..314d4f70fadf 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml @@ -68,6 +68,14 @@ let timestamp_of_bytes timestamp_bytes = type quantity = Qty of Z.t [@@ocaml.unboxed] +module Qty = struct + let pred (Qty z) = Qty (Z.pred z) + + let to_z (Qty z) = z + + let zero = Qty Z.zero +end + let quantity_of_z z = Qty z let z_to_hexa = Z.format "#x" @@ -1370,6 +1378,24 @@ let filter_changes_encoding = (fun f -> Log f); ] +type fee_history = { + oldest_block : quantity; + base_fee_per_gas : quantity list; + gas_used_ratio : float list; +} + +let fee_history_encoding = + let open Data_encoding in + conv + (fun {oldest_block; base_fee_per_gas; gas_used_ratio} -> + (oldest_block, base_fee_per_gas, gas_used_ratio)) + (fun (oldest_block, base_fee_per_gas, gas_used_ratio) -> + {oldest_block; base_fee_per_gas; gas_used_ratio}) + (obj3 + (req "oldestBlock" quantity_encoding) + (req "baseFeePerGas" (list quantity_encoding)) + (req "gasUsedRatio" (list float))) + module Delayed_transaction = struct type kind = Transaction | Deposit diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli index f35591bfbdd9..cbcac7ab17a4 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli @@ -54,6 +54,14 @@ val block_hash_of_string : string -> block_hash (** Ethereum generic quantity, always encoded in hexadecimal. *) type quantity = Qty of Z.t [@@unboxed] +module Qty : sig + val pred : quantity -> quantity + + val to_z : quantity -> Z.t + + val zero : quantity +end + val quantity_encoding : quantity Data_encoding.t val pp_quantity : Format.formatter -> quantity -> unit @@ -291,6 +299,14 @@ type filter = { val filter_encoding : filter Data_encoding.t +type fee_history = { + oldest_block : quantity; + base_fee_per_gas : quantity list; + gas_used_ratio : float list; +} + +val fee_history_encoding : fee_history Data_encoding.t + module Address : sig type t = address diff --git a/etherlink/bin_node/lib_dev/rpc_encodings.ml b/etherlink/bin_node/lib_dev/rpc_encodings.ml index a33891477de2..eee6262c8bad 100644 --- a/etherlink/bin_node/lib_dev/rpc_encodings.ml +++ b/etherlink/bin_node/lib_dev/rpc_encodings.ml @@ -736,6 +736,26 @@ module Trace_transaction = struct type ('input, 'output) method_ += Method : (input, output) method_ end +module Eth_fee_history = struct + open Ethereum_types + + type input = quantity * Block_parameter.t * float list + + type output = Ethereum_types.fee_history + + let input_encoding = + Data_encoding.tup3 + quantity_encoding + Block_parameter.encoding + (Data_encoding.list Data_encoding.float) + + let output_encoding = Ethereum_types.fee_history_encoding + + let method_ = "eth_feeHistory" + + type ('input, 'output) method_ += Method : (input, output) method_ +end + type map_result = | Method : ('input, 'output) method_ @@ -783,6 +803,7 @@ let supported_methods : (module METHOD) list = (module Eth_max_priority_fee_per_gas); (module Replay_block); (module Trace_transaction); + (module Eth_fee_history); ] let unsupported_methods : string list = @@ -801,7 +822,6 @@ let unsupported_methods : string list = "eth_blobBaseFee"; "eth_getProof"; "eth_createAccessList"; - "eth_feeHistory"; "eth_getFilterChanges"; "eth_getFilterLogs"; "eth_newBlockFilter"; diff --git a/etherlink/bin_node/lib_dev/rpc_encodings.mli b/etherlink/bin_node/lib_dev/rpc_encodings.mli index fd1838b22c70..dfde4cd4fc64 100644 --- a/etherlink/bin_node/lib_dev/rpc_encodings.mli +++ b/etherlink/bin_node/lib_dev/rpc_encodings.mli @@ -287,6 +287,12 @@ module Trace_transaction : with type input = Tracer_types.input and type output = Tracer_types.output +module Eth_fee_history : + METHOD + with type input = + Ethereum_types.quantity * Ethereum_types.Block_parameter.t * Float.t list + and type output = Ethereum_types.fee_history + type map_result = | Method : ('input, 'output) method_ diff --git a/etherlink/bin_node/lib_dev/services.ml b/etherlink/bin_node/lib_dev/services.ml index b5b41b0b43d4..9a20e40beb6f 100644 --- a/etherlink/bin_node/lib_dev/services.ml +++ b/etherlink/bin_node/lib_dev/services.ml @@ -152,6 +152,52 @@ let expect_input input f = let build_with_input method_ ~f parameters = build method_ ~f:(fun input -> expect_input input f) parameters +let get_fee_history block_count block_parameter + (module Backend_rpc : Services_backend_sig.S) = + (* TODO: exclude 0 blocks *) + let open Lwt_result_syntax in + let open Ethereum_types in + let rec get_fee_history_aux block_count block_parameter history_acc = + if block_count = Z.zero || block_parameter = Block_parameter.Number Qty.zero + then return history_acc + else + let* block = + get_block_by_number + ~full_transaction_object:false + block_parameter + (module Backend_rpc) + in + let gas_used_ratio = + Float.div + (Z.to_float @@ Qty.to_z block.gasUsed) + (Z.to_float @@ Qty.to_z block.gasLimit) + :: history_acc.gas_used_ratio + in + (* 0 for block pre EIP-1559 *) + let base_fee_per_gas = + Option.value block.baseFeePerGas ~default:Qty.zero + :: history_acc.base_fee_per_gas + in + let oldest_block = block.number in + let history_acc = {oldest_block; base_fee_per_gas; gas_used_ratio} in + get_fee_history_aux + Z.(block_count - one) + (Block_parameter.Number (Qty.pred block.number)) + history_acc + in + let init_acc = + { + (* default value if no block (which is a terrible + corner case) *) + oldest_block = Qty.zero; + (* TODO: should include baseFeePerGas of next block of newest block in + range *) + base_fee_per_gas = []; + gas_used_ratio = []; + } + in + get_fee_history_aux block_count block_parameter init_acc + let dispatch_request (config : Configuration.t) ((module Backend_rpc : Services_backend_sig.S), _) ({method_; parameters; id} : JSONRPC.request) : JSONRPC.response Lwt.t = @@ -447,6 +493,14 @@ let dispatch_request (config : Configuration.t) rpc_error (Rpc_errors.internal_error msg) in build_with_input ~f module_ parameters + | Method (Eth_fee_history.Method, module_) -> + let f (Qty block_count, newest_block, _reward_percentile) = + let* fee_history_result = + get_fee_history block_count newest_block (module Backend_rpc) + in + rpc_ok fee_history_result + in + build_with_input ~f module_ parameters | Method (_, _) -> Stdlib.failwith "The pattern matching of methods is not exhaustive" in -- GitLab From 69573db648a693948eb393ff66ace6a4a741428c Mon Sep 17 00:00:00 2001 From: Hantang Sun Date: Mon, 3 Jun 2024 14:44:04 +0100 Subject: [PATCH 2/9] EVM: tezt feehistory --- etherlink/tezt/lib/rpc.ml | 43 ++++++++++ etherlink/tezt/lib/rpc.mli | 13 +++ etherlink/tezt/tests/evm_rollup.ml | 123 ++++++++++++++++++++++++++++- 3 files changed, 178 insertions(+), 1 deletion(-) diff --git a/etherlink/tezt/lib/rpc.ml b/etherlink/tezt/lib/rpc.ml index e810737d5cb0..79ac0092e01c 100644 --- a/etherlink/tezt/lib/rpc.ml +++ b/etherlink/tezt/lib/rpc.ml @@ -155,6 +155,19 @@ module Request = struct | config -> `A [`String transaction_hash; `O config] in {method_ = "debug_traceTransaction"; parameters} + + let eth_feeHistory ~block_count ~newest_block = + { + method_ = "eth_feeHistory"; + parameters = + `A + [ + `String block_count; + `String newest_block; + (* rewards query, not relevant to etherlink *) + `A [`Float 0.; `Float 1.; `Float 2.; `Float 3.]; + ]; + } end let net_version evm_node = @@ -384,3 +397,33 @@ let trace_transaction ~transaction_hash ?tracer ?tracer_config evm_node = in return @@ decode_or_error (fun response -> Evm_node.extract_result response) response + +type fee_history = { + oldest_block : int64; + base_fee_per_gas : int64 list; + gas_used_ratio : float list; +} + +let fee_history block_count newest_block evm_node = + let* response = + Evm_node.( + call_evm_rpc evm_node (Request.eth_feeHistory ~block_count ~newest_block)) + in + + let decode_fee_history_result response = + let oldest_block = + JSON.(response |-> "result" |-> "oldestBlock" |> as_int64) + in + let base_fee_per_gas = + JSON.( + response |-> "result" |-> "baseFeePerGas" |> as_list + |> List.map as_int64) + in + let gas_used_ratio = + JSON.( + response |-> "result" |-> "gasUsedRatio" |> as_list |> List.map as_float) + in + {oldest_block; base_fee_per_gas; gas_used_ratio} + in + + return @@ decode_or_error decode_fee_history_result response diff --git a/etherlink/tezt/lib/rpc.mli b/etherlink/tezt/lib/rpc.mli index 0760dc9ba9a8..869d83888405 100644 --- a/etherlink/tezt/lib/rpc.mli +++ b/etherlink/tezt/lib/rpc.mli @@ -45,6 +45,9 @@ module Request : sig val eth_maxPriorityFeePerGas : Evm_node.request val txpool_content : Evm_node.request + + val eth_feeHistory : + block_count:string -> newest_block:string -> Evm_node.request end (** [net_version evm_node] calls [net_version]. *) @@ -170,3 +173,13 @@ val trace_transaction : ?tracer_config:(string * JSON.u) list -> Evm_node.t -> (JSON.t, error) result Lwt.t + +type fee_history = { + oldest_block : int64; + base_fee_per_gas : int64 list; + gas_used_ratio : float list; +} + +(** [fee_history block_count newest_block evm_node] calls [eth_feeHistory]. *) +val fee_history : + string -> string -> Evm_node.t -> (fee_history, error) result Lwt.t diff --git a/etherlink/tezt/tests/evm_rollup.ml b/etherlink/tezt/tests/evm_rollup.ml index ad05f38e09d2..6b0f447f39eb 100644 --- a/etherlink/tezt/tests/evm_rollup.ml +++ b/etherlink/tezt/tests/evm_rollup.ml @@ -5675,6 +5675,123 @@ let test_validation_with_legacy_encoding = "The transaction should have been included, meaning the validation \ failed." +let test_rpc_feeHistory = + register_both + ~tags:["evm"; "rpc"; "fee_history"] + ~title:"RPC methods eth_feeHistory" + @@ fun ~protocol:_ ~evm_setup -> + let {evm_node; sc_rollup_node; client; _} = evm_setup in + let* _ = + repeat 2 (fun _ -> next_evm_level ~evm_node ~sc_rollup_node ~client) + in + let* _ = + send + ~sender:Eth_account.bootstrap_accounts.(0) + ~receiver:Eth_account.bootstrap_accounts.(1) + ~value:Wei.one + evm_setup + in + let* _ = + repeat 2 (fun _ -> next_evm_level ~evm_node ~sc_rollup_node ~client) + in + let*@ history = Rpc.fee_history "0x03" "latest" evm_setup.evm_node in + let*@ latest_block = + Rpc.get_block_by_number ~block:"latest" evm_setup.evm_node + in + Check.( + Int64.(history.oldest_block = sub (of_int32 latest_block.number) 2L) int64) + ~error_msg:"Expected block %R, but got %L" ; + Check.((List.length history.base_fee_per_gas = 3) int) + ~error_msg:"Expected list of size %R, but got %L" ; + Check.((List.length history.gas_used_ratio = 3) int) + ~error_msg:"Expected list of size %R, but got %L" ; + List.iter + (fun fee -> + Check.((fee = latest_block.baseFeePerGas) int64) + ~error_msg:"Expected fee %L to be %R") + history.base_fee_per_gas ; + + (* 21000 / (2 ^ 50) = 1.86517e-11 *) + Check.((List.hd history.gas_used_ratio = 1.86517e-11) float) + ~error_msg:"Expected gas used ratio to be %R, but got %L" ; + + List.iter + (fun ratio -> + Check.((ratio <= 1.) float) + ~error_msg:"Expected gas used ratio to be less than 1, but got %L") + history.gas_used_ratio ; + unit + +let test_rpc_feeHistory_past = + register_both + ~tags:["evm"; "rpc"; "fee_history"; "past"] + ~title:"RPC methods eth_feeHistory in the past" + @@ fun ~protocol:_ ~evm_setup -> + let {evm_node; sc_rollup_node; client; _} = evm_setup in + let* _ = + repeat 6 (fun () -> next_evm_level ~evm_node ~sc_rollup_node ~client) + in + let*@ latest_block = + Rpc.get_block_by_number ~block:"latest" evm_setup.evm_node + in + let old_block = Int64.of_int32 @@ Int32.sub latest_block.number 2l in + let block_count = 3L in + let*@ history = + Rpc.fee_history + (Int64.to_string block_count) + (Int64.to_string old_block) + evm_setup.evm_node + in + Check.(Int64.(history.oldest_block = sub old_block @@ pred block_count) int64) + ~error_msg:"Expected block %R, but got %L" ; + Check.((List.length history.base_fee_per_gas = Int64.to_int block_count) int) + ~error_msg:"Expected list of size %R, but got %L" ; + Check.((List.length history.gas_used_ratio = Int64.to_int block_count) int) + ~error_msg:"Expected list of size %R, but got %L" ; + unit + +let test_rpc_feeHistory_future = + register_both + ~tags:["evm"; "rpc"; "fee_history"; "future"] + ~title:"RPC methods eth_feeHistory in the future" + @@ fun ~protocol:_ ~evm_setup -> + let {evm_node; sc_rollup_node; client; _} = evm_setup in + let* _ = + repeat 3 (fun () -> next_evm_level ~evm_node ~sc_rollup_node ~client) + in + let*@? error = Rpc.fee_history "0x02" "0xFFFFFFFF" evm_setup.evm_node in + Check.( + ((error.message + = "Evm_node_lib_dev.Durable_storage.Make(Reader).Invalid_block_index(4294967295)" + ) + string) + ~error_msg:"The transaction should fail with message %R, got &L") ; + unit + +let test_rpc_feeHistory_long = + register_both + ~tags:["evm"; "rpc"; "fee_history"; "block_count"] + ~title:"RPC methods eth_feeHistory with high blockCount" + @@ fun ~protocol:_ ~evm_setup -> + let {evm_node; sc_rollup_node; client; _} = evm_setup in + let* _ = + repeat 3 (fun () -> next_evm_level ~evm_node ~sc_rollup_node ~client) + in + let*@ history = Rpc.fee_history "0xffffffffff" "latest" evm_setup.evm_node in + let*@ latest_block = + Rpc.get_block_by_number ~block:"latest" evm_setup.evm_node + in + Check.((history.oldest_block = 1L) int64) + ~error_msg:"Expected block %R, but got %L" ; + Check.( + (List.length history.base_fee_per_gas = Int32.to_int latest_block.number) + int) + ~error_msg:"Expected list of size %R, but got %L" ; + Check.( + (List.length history.gas_used_ratio = Int32.to_int latest_block.number) int) + ~error_msg:"Expected list of size %R, but got %L" ; + unit + let register_evm_node ~protocols = test_originate_evm_kernel protocols ; test_kernel_root_hash_originate_absent protocols ; @@ -5780,7 +5897,11 @@ let register_evm_node ~protocols = test_proxy_read_only protocols ; test_unsupported_rpc protocols ; test_validation_with_legacy_encoding protocols ; - test_rpc_getBlockBy_return_base_fee_per_gas_and_mix_hash protocols + test_rpc_getBlockBy_return_base_fee_per_gas_and_mix_hash protocols ; + test_rpc_feeHistory protocols ; + test_rpc_feeHistory_past protocols ; + test_rpc_feeHistory_future protocols ; + test_rpc_feeHistory_long protocols let protocols = Protocol.all -- GitLab From 159f0c62ac26c2f01c3f5ce167f0d51b208117e1 Mon Sep 17 00:00:00 2001 From: pecornilleau Date: Thu, 23 May 2024 10:11:07 +0200 Subject: [PATCH 3/9] Etherlink: changelog feeHistory --- etherlink/CHANGES_NODE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/etherlink/CHANGES_NODE.md b/etherlink/CHANGES_NODE.md index f965a89c4bf9..b3898e4289b2 100644 --- a/etherlink/CHANGES_NODE.md +++ b/etherlink/CHANGES_NODE.md @@ -34,6 +34,7 @@ (!13268, !13321, !13350, !13378) - Return `baseFeePerGas` and `mixHash` field for `eth_getBlockBy*` RPCs. The former only when appropriate, the later with a default value. (!13159) +- Support for the `eth_feeHistory` RPC. (!13259) ### Experimental -- GitLab From f5552185ce739195f3ad7866dd33ed3f46960c1c Mon Sep 17 00:00:00 2001 From: pecornilleau Date: Thu, 23 May 2024 16:29:51 +0200 Subject: [PATCH 4/9] Etherlink: small refacto Qty.zero --- etherlink/bin_node/lib_dev/services.ml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/etherlink/bin_node/lib_dev/services.ml b/etherlink/bin_node/lib_dev/services.ml index 9a20e40beb6f..d21e17558627 100644 --- a/etherlink/bin_node/lib_dev/services.ml +++ b/etherlink/bin_node/lib_dev/services.ml @@ -287,9 +287,7 @@ let dispatch_request (config : Configuration.t) rpc_ok nonce | _ -> let* nonce = Backend_rpc.nonce address block_param in - let nonce = - Option.value ~default:(Ethereum_types.Qty Z.zero) nonce - in + let nonce = Option.value ~default:Qty.zero nonce in rpc_ok nonce in build_with_input ~f module_ parameters @@ -313,10 +311,10 @@ let dispatch_request (config : Configuration.t) in build_with_input ~f module_ parameters | Method (Get_uncle_count_by_block_hash.Method, module_) -> - let f _block_param = rpc_ok (Qty Z.zero) in + let f _block_param = rpc_ok Qty.zero in build_with_input ~f module_ parameters | Method (Get_uncle_count_by_block_number.Method, module_) -> - let f _block_param = rpc_ok (Qty Z.zero) in + let f _block_param = rpc_ok Qty.zero in build_with_input ~f module_ parameters | Method (Get_transaction_receipt.Method, module_) -> let f tx_hash = @@ -472,7 +470,7 @@ let dispatch_request (config : Configuration.t) in build ~f module_ parameters | Method (Eth_max_priority_fee_per_gas.Method, module_) -> - let f (_ : unit option) = rpc_ok @@ Qty Z.zero in + let f (_ : unit option) = rpc_ok Qty.zero in build ~f module_ parameters | Method (Trace_transaction.Method, module_) -> let f ((hash, config) : Tracer_types.input) = -- GitLab From 4ff4fd8e4afc120549f6347518a082e18e6fae84 Mon Sep 17 00:00:00 2001 From: pecornilleau Date: Mon, 27 May 2024 17:43:30 +0200 Subject: [PATCH 5/9] Etherlink: feeHistory configuration --- etherlink/bin_node/config/configuration.ml | 27 ++++++++++++++++++--- etherlink/bin_node/config/configuration.mli | 3 +++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/etherlink/bin_node/config/configuration.ml b/etherlink/bin_node/config/configuration.ml index 1a4edac0724d..85868d684fd5 100644 --- a/etherlink/bin_node/config/configuration.ml +++ b/etherlink/bin_node/config/configuration.ml @@ -62,6 +62,8 @@ type observer = { type proxy = unit +type fee_history = {max_count : int option; max_past : int option} + type t = { rpc_addr : string; rpc_port : int; @@ -82,6 +84,7 @@ type t = { rollup_node_endpoint : Uri.t; verbose : Internal_event.level; experimental_features : experimental_features; + fee_history : fee_history; } let default_filter_config ?max_nb_blocks ?max_nb_logs ?chunk_size () = @@ -151,6 +154,8 @@ let default_blueprints_publisher_config = catchup_cooldown = 1; } +let default_fee_history = {max_count = None; max_past = None} + let sequencer_config_dft ~data_dir ?preimages ?preimages_endpoint ?time_between_blocks ?max_number_of_chunks ?private_rpc_port ~sequencer ?max_blueprints_lag ?max_blueprints_ahead ?max_blueprints_catchup @@ -489,6 +494,13 @@ let proxy_encoding = Data_encoding.unit let default_proxy = () +let fee_history_encoding = + let open Data_encoding in + conv + (fun {max_count; max_past} -> (max_count, max_past)) + (fun (max_count, max_past) -> {max_count; max_past}) + (obj2 (opt "max_count" int31) (opt "max_past" int31)) + let encoding data_dir : t Data_encoding.t = let open Data_encoding in conv @@ -511,6 +523,7 @@ let encoding data_dir : t Data_encoding.t = rollup_node_endpoint; verbose; experimental_features; + fee_history; } -> ( ( rpc_addr, rpc_port, @@ -529,7 +542,8 @@ let encoding data_dir : t Data_encoding.t = Uri.to_string rollup_node_endpoint, verbose, experimental_features, - proxy ) )) + proxy, + fee_history ) )) (fun ( ( rpc_addr, rpc_port, devmode, @@ -547,7 +561,8 @@ let encoding data_dir : t Data_encoding.t = rollup_node_endpoint, verbose, experimental_features, - proxy ) ) -> + proxy, + fee_history ) ) -> { rpc_addr; rpc_port; @@ -567,6 +582,7 @@ let encoding data_dir : t Data_encoding.t = rollup_node_endpoint = Uri.of_string rollup_node_endpoint; verbose; experimental_features; + fee_history; }) (merge_objs (obj10 @@ -589,7 +605,7 @@ let encoding data_dir : t Data_encoding.t = Tezos_rpc_http_server.RPC_server.Max_active_rpc_connections .encoding default_max_active_connections)) - (obj8 + (obj9 (dft "tx-pool-timeout-limit" ~description: @@ -616,7 +632,8 @@ let encoding data_dir : t Data_encoding.t = "experimental_features" experimental_features_encoding default_experimental_features) - (dft "proxy" proxy_encoding default_proxy))) + (dft "proxy" proxy_encoding default_proxy) + (dft "fee_history" fee_history_encoding default_fee_history))) let save ~force ~data_dir config = let open Lwt_result_syntax in @@ -743,6 +760,7 @@ module Cli = struct rollup_node_endpoint; verbose = (if verbose then Debug else Internal_event.Notice); experimental_features = default_experimental_features; + fee_history = default_fee_history; } let patch_configuration_from_args ~data_dir ~devmode ?rpc_addr ?rpc_port @@ -991,6 +1009,7 @@ module Cli = struct rollup_node_endpoint; verbose = (if verbose then Debug else configuration.verbose); experimental_features = configuration.experimental_features; + fee_history = configuration.fee_history; } let create_or_read_config ~data_dir ~devmode ?rpc_addr ?rpc_port ?cors_origins diff --git a/etherlink/bin_node/config/configuration.mli b/etherlink/bin_node/config/configuration.mli index 1c4724bcd1b0..acf35c3c7f13 100644 --- a/etherlink/bin_node/config/configuration.mli +++ b/etherlink/bin_node/config/configuration.mli @@ -97,6 +97,8 @@ type observer = { type proxy = unit +type fee_history = {max_count : int option; max_past : int option} + type t = { rpc_addr : string; rpc_port : int; @@ -117,6 +119,7 @@ type t = { rollup_node_endpoint : Uri.t; verbose : Internal_event.level; experimental_features : experimental_features; + fee_history : fee_history; } (** [default_data_dir] is the default value for [data_dir]. *) -- GitLab From fabc55827c012667211e67a5b84c71d542439a1e Mon Sep 17 00:00:00 2001 From: pecornilleau Date: Mon, 27 May 2024 17:49:56 +0200 Subject: [PATCH 6/9] Etherlink: feeHistory contains next block fee --- etherlink/bin_node/lib_dev/services.ml | 10 ++++++++-- etherlink/tezt/tests/evm_rollup.ml | 7 ++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/etherlink/bin_node/lib_dev/services.ml b/etherlink/bin_node/lib_dev/services.ml index d21e17558627..14d58ba52259 100644 --- a/etherlink/bin_node/lib_dev/services.ml +++ b/etherlink/bin_node/lib_dev/services.ml @@ -174,9 +174,15 @@ let get_fee_history block_count block_parameter :: history_acc.gas_used_ratio in (* 0 for block pre EIP-1559 *) - let base_fee_per_gas = + let block_base_fee_per_gas = Option.value block.baseFeePerGas ~default:Qty.zero - :: history_acc.base_fee_per_gas + in + let base_fee_per_gas = + match history_acc.base_fee_per_gas with + (* TODO : the list should start with the fee for the next block. + until then we double the first value to keep a list of correct length *) + | [] -> [block_base_fee_per_gas; block_base_fee_per_gas] + | l -> block_base_fee_per_gas :: l in let oldest_block = block.number in let history_acc = {oldest_block; base_fee_per_gas; gas_used_ratio} in diff --git a/etherlink/tezt/tests/evm_rollup.ml b/etherlink/tezt/tests/evm_rollup.ml index 6b0f447f39eb..5452b87c40db 100644 --- a/etherlink/tezt/tests/evm_rollup.ml +++ b/etherlink/tezt/tests/evm_rollup.ml @@ -5701,7 +5701,7 @@ let test_rpc_feeHistory = Check.( Int64.(history.oldest_block = sub (of_int32 latest_block.number) 2L) int64) ~error_msg:"Expected block %R, but got %L" ; - Check.((List.length history.base_fee_per_gas = 3) int) + Check.((List.length history.base_fee_per_gas = 4) int) ~error_msg:"Expected list of size %R, but got %L" ; Check.((List.length history.gas_used_ratio = 3) int) ~error_msg:"Expected list of size %R, but got %L" ; @@ -5744,7 +5744,8 @@ let test_rpc_feeHistory_past = in Check.(Int64.(history.oldest_block = sub old_block @@ pred block_count) int64) ~error_msg:"Expected block %R, but got %L" ; - Check.((List.length history.base_fee_per_gas = Int64.to_int block_count) int) + Check.( + (List.length history.base_fee_per_gas = 1 + Int64.to_int block_count) int) ~error_msg:"Expected list of size %R, but got %L" ; Check.((List.length history.gas_used_ratio = Int64.to_int block_count) int) ~error_msg:"Expected list of size %R, but got %L" ; @@ -5784,7 +5785,7 @@ let test_rpc_feeHistory_long = Check.((history.oldest_block = 1L) int64) ~error_msg:"Expected block %R, but got %L" ; Check.( - (List.length history.base_fee_per_gas = Int32.to_int latest_block.number) + (List.length history.base_fee_per_gas = 1 + Int32.to_int latest_block.number) int) ~error_msg:"Expected list of size %R, but got %L" ; Check.( -- GitLab From 4c65bc3b0316e24d889f66d55fed0d3d97eafd13 Mon Sep 17 00:00:00 2001 From: pecornilleau Date: Mon, 27 May 2024 17:50:37 +0200 Subject: [PATCH 7/9] Etherlink: feeHistory max block_count config --- etherlink/bin_node/lib_dev/services.ml | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/etherlink/bin_node/lib_dev/services.ml b/etherlink/bin_node/lib_dev/services.ml index 14d58ba52259..43f083506044 100644 --- a/etherlink/bin_node/lib_dev/services.ml +++ b/etherlink/bin_node/lib_dev/services.ml @@ -152,11 +152,17 @@ let expect_input input f = let build_with_input method_ ~f parameters = build method_ ~f:(fun input -> expect_input input f) parameters -let get_fee_history block_count block_parameter +let get_fee_history block_count block_parameter config (module Backend_rpc : Services_backend_sig.S) = (* TODO: exclude 0 blocks *) let open Lwt_result_syntax in let open Ethereum_types in + (* block count can be bounded in configuration *) + let block_count = + match Configuration.(config.fee_history.max_count) with + | None -> block_count + | Some count -> Z.(min (of_int count) block_count) + in let rec get_fee_history_aux block_count block_parameter history_acc = if block_count = Z.zero || block_parameter = Block_parameter.Number Qty.zero then return history_acc @@ -499,10 +505,19 @@ let dispatch_request (config : Configuration.t) build_with_input ~f module_ parameters | Method (Eth_fee_history.Method, module_) -> let f (Qty block_count, newest_block, _reward_percentile) = - let* fee_history_result = - get_fee_history block_count newest_block (module Backend_rpc) - in - rpc_ok fee_history_result + if block_count = Z.zero then + rpc_error + (Rpc_errors.invalid_params + "Number of block should be greater than 0.") + else + let* fee_history_result = + get_fee_history + block_count + newest_block + config + (module Backend_rpc) + in + rpc_ok fee_history_result in build_with_input ~f module_ parameters | Method (_, _) -> -- GitLab From ff811a2db5a7c5d2eb7450ecee58ec05e1d13ad7 Mon Sep 17 00:00:00 2001 From: pecornilleau Date: Mon, 27 May 2024 19:12:52 +0200 Subject: [PATCH 8/9] Etherlink: feeHistory oldest reachable config --- etherlink/bin_node/lib_dev/services.ml | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/etherlink/bin_node/lib_dev/services.ml b/etherlink/bin_node/lib_dev/services.ml index 43f083506044..1651da50a68c 100644 --- a/etherlink/bin_node/lib_dev/services.ml +++ b/etherlink/bin_node/lib_dev/services.ml @@ -163,6 +163,14 @@ let get_fee_history block_count block_parameter config | None -> block_count | Some count -> Z.(min (of_int count) block_count) in + let* nb_latest = Backend_rpc.current_block_number () in + let is_reachable nb = + match Configuration.(config.fee_history.max_past) with + | None -> true + | Some delta -> + let oldest_reachable = Z.(sub (Qty.to_z nb_latest) (of_int delta)) in + Z.(gt (Qty.to_z nb) oldest_reachable) + in let rec get_fee_history_aux block_count block_parameter history_acc = if block_count = Z.zero || block_parameter = Block_parameter.Number Qty.zero then return history_acc @@ -192,10 +200,13 @@ let get_fee_history block_count block_parameter config in let oldest_block = block.number in let history_acc = {oldest_block; base_fee_per_gas; gas_used_ratio} in - get_fee_history_aux - Z.(block_count - one) - (Block_parameter.Number (Qty.pred block.number)) - history_acc + let next_block = Qty.pred block.number in + if is_reachable next_block then + get_fee_history_aux + Z.(block_count - one) + (Block_parameter.Number next_block) + history_acc + else return history_acc in let init_acc = { -- GitLab From ecdb7fd934d1678083dec3b22990718b1e83bd7a Mon Sep 17 00:00:00 2001 From: Hantang Sun Date: Wed, 5 Jun 2024 17:34:26 +0100 Subject: [PATCH 9/9] EVM: base_fee_per_gas for next block --- .../lib_dev/encodings/ethereum_types.ml | 2 ++ .../lib_dev/encodings/ethereum_types.mli | 2 ++ etherlink/bin_node/lib_dev/services.ml | 29 ++++++++++++++----- etherlink/kernel_evm/kernel/src/gas_price.rs | 8 +++-- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml index 314d4f70fadf..29487dc9f699 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml @@ -71,6 +71,8 @@ type quantity = Qty of Z.t [@@ocaml.unboxed] module Qty = struct let pred (Qty z) = Qty (Z.pred z) + let next (Qty z) = Qty (Z.add z Z.one) + let to_z (Qty z) = z let zero = Qty Z.zero diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli index cbcac7ab17a4..5bf8ac260483 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli @@ -57,6 +57,8 @@ type quantity = Qty of Z.t [@@unboxed] module Qty : sig val pred : quantity -> quantity + val next : quantity -> quantity + val to_z : quantity -> Z.t val zero : quantity diff --git a/etherlink/bin_node/lib_dev/services.ml b/etherlink/bin_node/lib_dev/services.ml index 1651da50a68c..b63fce7b6f8d 100644 --- a/etherlink/bin_node/lib_dev/services.ml +++ b/etherlink/bin_node/lib_dev/services.ml @@ -171,6 +171,25 @@ let get_fee_history block_count block_parameter config let oldest_reachable = Z.(sub (Qty.to_z nb_latest) (of_int delta)) in Z.(gt (Qty.to_z nb) oldest_reachable) in + let* newest_block = + get_block_by_number + ~full_transaction_object:false + block_parameter + (module Backend_rpc) + in + let* base_fee_per_gas_next_block = + if newest_block.number = nb_latest then Backend_rpc.base_fee_per_gas () + else + let next_block_number = Qty.next newest_block.number in + let* next_block = + get_block_by_number + ~full_transaction_object:false + (Block_parameter.Number next_block_number) + (module Backend_rpc) + in + return (Option.value next_block.baseFeePerGas ~default:Qty.zero) + in + let rec get_fee_history_aux block_count block_parameter history_acc = if block_count = Z.zero || block_parameter = Block_parameter.Number Qty.zero then return history_acc @@ -192,11 +211,7 @@ let get_fee_history block_count block_parameter config Option.value block.baseFeePerGas ~default:Qty.zero in let base_fee_per_gas = - match history_acc.base_fee_per_gas with - (* TODO : the list should start with the fee for the next block. - until then we double the first value to keep a list of correct length *) - | [] -> [block_base_fee_per_gas; block_base_fee_per_gas] - | l -> block_base_fee_per_gas :: l + block_base_fee_per_gas :: history_acc.base_fee_per_gas in let oldest_block = block.number in let history_acc = {oldest_block; base_fee_per_gas; gas_used_ratio} in @@ -213,9 +228,7 @@ let get_fee_history block_count block_parameter config (* default value if no block (which is a terrible corner case) *) oldest_block = Qty.zero; - (* TODO: should include baseFeePerGas of next block of newest block in - range *) - base_fee_per_gas = []; + base_fee_per_gas = [base_fee_per_gas_next_block]; gas_used_ratio = []; } in diff --git a/etherlink/kernel_evm/kernel/src/gas_price.rs b/etherlink/kernel_evm/kernel/src/gas_price.rs index 2aa1f23339f3..eda27c03a276 100644 --- a/etherlink/kernel_evm/kernel/src/gas_price.rs +++ b/etherlink/kernel_evm/kernel/src/gas_price.rs @@ -5,7 +5,7 @@ //! Adjustments of the gas price (a.k.a `base_fee_per_gas`), in response to load. use crate::block_in_progress::BlockInProgress; -use crate::storage::read_minimum_base_fee_per_gas; +use crate::storage::{read_minimum_base_fee_per_gas, store_base_fee_per_gas}; use primitive_types::U256; use softfloat::F64; @@ -32,7 +32,11 @@ pub fn register_block( anyhow::bail!("update_gas_price on non-empty block"); } - update_tick_backlog(host, bip.estimated_ticks_in_block, bip.timestamp) + update_tick_backlog(host, bip.estimated_ticks_in_block, bip.timestamp)?; + let base_fee_per_gas = base_fee_per_gas(host, bip.timestamp); + store_base_fee_per_gas(host, base_fee_per_gas)?; + + Ok(()) } /// Update the kernel-wide base fee per gas with a new value. -- GitLab