diff --git a/etherlink/CHANGES_NODE.md b/etherlink/CHANGES_NODE.md index 92845c4518773c6328752d9e21de150b1345bfd1..d251fe0565df4ca6c91296dc06d6520df3345be1 100644 --- a/etherlink/CHANGES_NODE.md +++ b/etherlink/CHANGES_NODE.md @@ -6,6 +6,11 @@ - The transaction pool is now removing any transaction that was included more than a defined thresold ago (one hour by default). (!12741) +- The transaction pool imposes a limit of users permitted simultaneously + (4000 by default). (!12749) +- The transaction pool has a threshold of simultaneous transactions allowed per user + (16 by default). (!12749) + ### Bug fixes diff --git a/etherlink/bin_node/config/configuration.ml b/etherlink/bin_node/config/configuration.ml index 73606798f8452ecc6529b291e286e7d1082202af..483db076bbac13240cb15bc33c0a1812bd78ac9a 100644 --- a/etherlink/bin_node/config/configuration.ml +++ b/etherlink/bin_node/config/configuration.ml @@ -45,6 +45,8 @@ type t = { max_active_connections : Tezos_rpc_http_server.RPC_server.Max_active_rpc_connections.t; tx_pool_timeout_limit : int64; + tx_pool_addr_limit : int64; + tx_pool_tx_per_addr_limit : int64; } let default_filter_config = @@ -86,6 +88,10 @@ let default_max_number_of_chunks = hard_maximum_number_of_chunks let default_tx_pool_timeout_limit = Int64.of_int 3600 +let default_tx_pool_addr_limit = Int64.of_int 4000 + +let default_tx_pool_tx_per_addr_limit = Int64.of_int 16 + let sequencer_config_dft ?preimages ?preimages_endpoint ?time_between_blocks ?max_number_of_chunks ?private_rpc_port ~rollup_node_endpoint ~sequencer () = @@ -221,6 +227,8 @@ let encoding : t Data_encoding.t = observer; max_active_connections; tx_pool_timeout_limit; + tx_pool_addr_limit; + tx_pool_tx_per_addr_limit; } -> ( ( rpc_addr, rpc_port, @@ -232,7 +240,8 @@ let encoding : t Data_encoding.t = sequencer, observer, max_active_connections ), - tx_pool_timeout_limit )) + (tx_pool_timeout_limit, tx_pool_addr_limit, tx_pool_tx_per_addr_limit) + )) (fun ( ( rpc_addr, rpc_port, devmode, @@ -243,7 +252,8 @@ let encoding : t Data_encoding.t = sequencer, observer, max_active_connections ), - tx_pool_timeout_limit ) -> + (tx_pool_timeout_limit, tx_pool_addr_limit, tx_pool_tx_per_addr_limit) + ) -> { rpc_addr; rpc_port; @@ -256,6 +266,8 @@ let encoding : t Data_encoding.t = observer; max_active_connections; tx_pool_timeout_limit; + tx_pool_addr_limit; + tx_pool_tx_per_addr_limit; }) (merge_objs (obj10 @@ -273,13 +285,26 @@ let encoding : t Data_encoding.t = Tezos_rpc_http_server.RPC_server.Max_active_rpc_connections .encoding default_max_active_connections)) - (obj1 + (obj3 (dft "tx-pool-timeout-limit" ~description: "Transaction timeout limit inside the transaction pool" int64 - default_tx_pool_timeout_limit))) + default_tx_pool_timeout_limit) + (dft + "tx-pool-addr-limit" + ~description: + "Maximum allowed addresses inside the transaction pool." + int64 + default_tx_pool_addr_limit) + (dft + "tx-pool-tx-per-addr-limit" + ~description: + "Maximum allowed transactions per user address inside the \ + transaction pool." + int64 + default_tx_pool_tx_per_addr_limit))) let save ~force ~data_dir config = let open Lwt_result_syntax in @@ -313,7 +338,8 @@ let observer_config_exn {observer; _} = module Cli = struct let create ~devmode ?rpc_addr ?rpc_port ?cors_origins ?cors_headers - ?log_filter ?proxy ?sequencer ?observer ?tx_pool_timeout_limit () = + ?log_filter ?proxy ?sequencer ?observer ?tx_pool_timeout_limit + ?tx_pool_addr_limit ?tx_pool_tx_per_addr_limit () = { rpc_addr = Option.value ~default:default_rpc_addr rpc_addr; rpc_port = Option.value ~default:default_rpc_port rpc_port; @@ -329,11 +355,18 @@ module Cli = struct Option.value ~default:default_tx_pool_timeout_limit tx_pool_timeout_limit; + tx_pool_addr_limit = + Option.value ~default:default_tx_pool_addr_limit tx_pool_addr_limit; + tx_pool_tx_per_addr_limit = + Option.value + ~default:default_tx_pool_tx_per_addr_limit + tx_pool_tx_per_addr_limit; } let patch_configuration_from_args ~devmode ?rpc_addr ?rpc_port ?cors_origins ?cors_headers ?log_filter ?proxy ?sequencer ?observer - ?tx_pool_timeout_limit configuration = + ?tx_pool_timeout_limit ?tx_pool_addr_limit ?tx_pool_tx_per_addr_limit + configuration = { rpc_addr = Option.value ~default:configuration.rpc_addr rpc_addr; rpc_port = Option.value ~default:configuration.rpc_port rpc_port; @@ -351,11 +384,19 @@ module Cli = struct Option.value ~default:configuration.tx_pool_timeout_limit tx_pool_timeout_limit; + tx_pool_addr_limit = + Option.value + ~default:configuration.tx_pool_addr_limit + tx_pool_addr_limit; + tx_pool_tx_per_addr_limit = + Option.value + ~default:configuration.tx_pool_tx_per_addr_limit + tx_pool_tx_per_addr_limit; } let create_or_read_config ~data_dir ~devmode ?rpc_addr ?rpc_port ?cors_origins ?cors_headers ?log_filter ?proxy ?sequencer ?observer - ?tx_pool_timeout_limit () = + ?tx_pool_timeout_limit ?tx_pool_addr_limit ?tx_pool_tx_per_addr_limit () = let open Lwt_result_syntax in let open Filename.Infix in (* Check if the data directory of the evm node is not the one of Octez @@ -388,6 +429,8 @@ module Cli = struct ?sequencer ?observer ?tx_pool_timeout_limit + ?tx_pool_addr_limit + ?tx_pool_tx_per_addr_limit configuration in return configuration @@ -404,6 +447,8 @@ module Cli = struct ?sequencer ?observer ?tx_pool_timeout_limit + ?tx_pool_addr_limit + ?tx_pool_tx_per_addr_limit () in return config diff --git a/etherlink/bin_node/config/configuration.mli b/etherlink/bin_node/config/configuration.mli index 7994513e0eaa5b85ec7740e1d3d473beae402dac..d9f51aeec1b8f1bdd8fa53c748973184eec3674e 100644 --- a/etherlink/bin_node/config/configuration.mli +++ b/etherlink/bin_node/config/configuration.mli @@ -59,6 +59,8 @@ type t = { max_active_connections : Tezos_rpc_http_server.RPC_server.Max_active_rpc_connections.t; tx_pool_timeout_limit : int64; + tx_pool_addr_limit : int64; + tx_pool_tx_per_addr_limit : int64; } (** [default_data_dir] is the default value for [data_dir]. *) @@ -122,6 +124,8 @@ module Cli : sig ?sequencer:sequencer -> ?observer:observer -> ?tx_pool_timeout_limit:int64 -> + ?tx_pool_addr_limit:int64 -> + ?tx_pool_tx_per_addr_limit:int64 -> unit -> t @@ -137,6 +141,8 @@ module Cli : sig ?sequencer:sequencer -> ?observer:observer -> ?tx_pool_timeout_limit:int64 -> + ?tx_pool_addr_limit:int64 -> + ?tx_pool_tx_per_addr_limit:int64 -> unit -> t tzresult Lwt.t end diff --git a/etherlink/bin_node/lib_dev/observer.ml b/etherlink/bin_node/lib_dev/observer.ml index afea15dc1011bc71a4761c89555ab1278991cd3d..816f6b19ba39d4adc65c844af5bdd9cbbed5cefc 100644 --- a/etherlink/bin_node/lib_dev/observer.ml +++ b/etherlink/bin_node/lib_dev/observer.ml @@ -259,6 +259,9 @@ let main ?kernel_path ~rollup_node_endpoint ~evm_node_endpoint ~data_dir smart_rollup_address; mode = Observer; tx_timeout_limit = config.tx_pool_timeout_limit; + tx_pool_addr_limit = Int64.to_int config.tx_pool_addr_limit; + tx_pool_tx_per_addr_limit = + Int64.to_int config.tx_pool_tx_per_addr_limit; } in diff --git a/etherlink/bin_node/lib_dev/proxy.ml b/etherlink/bin_node/lib_dev/proxy.ml index c9f33dd26629b5b939536abdf8c65d3460037b74..400541f786d9bc41089d25c13ee53d57bcf3bf39 100644 --- a/etherlink/bin_node/lib_dev/proxy.ml +++ b/etherlink/bin_node/lib_dev/proxy.ml @@ -110,6 +110,9 @@ let main (config : Configuration.t) ~keep_alive ~rollup_node_endpoint = smart_rollup_address; mode = Proxy {rollup_node_endpoint}; tx_timeout_limit = config.tx_pool_timeout_limit; + tx_pool_addr_limit = Int64.to_int config.tx_pool_addr_limit; + tx_pool_tx_per_addr_limit = + Int64.to_int config.tx_pool_tx_per_addr_limit; } in let () = Rollup_node_follower.start ~proxy:true ~rollup_node_endpoint in diff --git a/etherlink/bin_node/lib_dev/sequencer.ml b/etherlink/bin_node/lib_dev/sequencer.ml index c6ceb496199449c13a3303a9e27f85e26b58fd73..56e6172761fb2ba6fedb220ece1f697aa960d14c 100644 --- a/etherlink/bin_node/lib_dev/sequencer.ml +++ b/etherlink/bin_node/lib_dev/sequencer.ml @@ -244,6 +244,9 @@ let main ~data_dir ~rollup_node_endpoint ~max_blueprints_lag smart_rollup_address; mode = Sequencer; tx_timeout_limit = configuration.tx_pool_timeout_limit; + tx_pool_addr_limit = Int64.to_int configuration.tx_pool_addr_limit; + tx_pool_tx_per_addr_limit = + Int64.to_int configuration.tx_pool_tx_per_addr_limit; } in let* () = diff --git a/etherlink/bin_node/lib_dev/tx_pool.ml b/etherlink/bin_node/lib_dev/tx_pool.ml index 7e1bea8e69d43e582f3d19b0cc5e40ff0ff35eb7..ca2498f5c423c823d0ec42beacee1b511e3cabf4 100644 --- a/etherlink/bin_node/lib_dev/tx_pool.ml +++ b/etherlink/bin_node/lib_dev/tx_pool.ml @@ -125,6 +125,8 @@ type parameters = { smart_rollup_address : string; mode : mode; tx_timeout_limit : int64; + tx_pool_addr_limit : int; + tx_pool_tx_per_addr_limit : int; } module Types = struct @@ -134,6 +136,8 @@ module Types = struct mutable pool : Pool.t; mode : mode; tx_timeout_limit : int64; + tx_pool_addr_limit : int; + tx_pool_tx_per_addr_limit : int; mutable locked : bool; } @@ -243,10 +247,46 @@ module Worker = Worker.MakeSingle (Name) (Request) (Types) type worker = Worker.infinite Worker.queue Worker.t +let check_address_boundaries ~pool ~address ~tx_pool_addr_limit + ~tx_pool_tx_per_addr_limit = + let open Lwt_result_syntax in + let boundaries_are_not_reached = return (false, "") in + match Pool.Pkey_map.find address pool.Pool.transactions with + | None -> + if Pool.Pkey_map.cardinal pool.Pool.transactions < tx_pool_addr_limit then + boundaries_are_not_reached + else + let*! () = Tx_pool_events.users_threshold_reached () in + return + ( true, + "The transaction pool has reached its maximum threshold for user \ + transactions. Transaction is rejected." ) + | Some txs -> + if Pool.Nonce_map.cardinal txs < tx_pool_tx_per_addr_limit then + boundaries_are_not_reached + else + let*! () = + Tx_pool_events.txs_per_user_threshold_reached + ~address:(Ethereum_types.Address.to_string address) + in + return + ( true, + "Limit of transaction for a user was reached. Transaction is \ + rejected." ) + let on_normal_transaction state tx_raw = let open Lwt_result_syntax in let open Types in - let {rollup_node = (module Rollup_node); pool; _} = state in + let { + rollup_node = (module Rollup_node); + pool; + tx_pool_addr_limit; + tx_pool_tx_per_addr_limit; + _; + } = + state + in + let* is_valid = Rollup_node.is_tx_valid tx_raw in match is_valid with | Error err -> @@ -256,19 +296,28 @@ let on_normal_transaction state tx_raw = in return (Error err) | Ok {address} -> - (* Add the tx to the pool*) - let*? pool = Pool.add pool address tx_raw in - (* compute the hash *) - let tx_hash = Ethereum_types.hash_raw_tx tx_raw in - let hash = - Ethereum_types.hash_of_string Hex.(of_string tx_hash |> show) - in - let*! () = - Tx_pool_events.add_transaction - ~transaction:(Ethereum_types.hash_to_string hash) + let* address_boundaries_are_reached, error_msg = + check_address_boundaries + ~pool + ~address + ~tx_pool_addr_limit + ~tx_pool_tx_per_addr_limit in - state.pool <- pool ; - return (Ok hash) + if address_boundaries_are_reached then return @@ Error error_msg + else + (* Add the tx to the pool*) + let*? pool = Pool.add pool address tx_raw in + (* compute the hash *) + let tx_hash = Ethereum_types.hash_raw_tx tx_raw in + let hash = + Ethereum_types.hash_of_string Hex.(of_string tx_hash |> show) + in + let*! () = + Tx_pool_events.add_transaction + ~transaction:(Ethereum_types.hash_to_string hash) + in + state.pool <- pool ; + return (Ok hash) (** Checks that [balance] is enough to pay up to the maximum [gas_limit] the sender defined parametrized by the [gas_price]. *) @@ -465,7 +514,14 @@ module Handlers = struct type launch_error = error trace let on_launch _w () - ({rollup_node; smart_rollup_address; mode; tx_timeout_limit} : + ({ + rollup_node; + smart_rollup_address; + mode; + tx_timeout_limit; + tx_pool_addr_limit; + tx_pool_tx_per_addr_limit; + } : Types.parameters) = let state = Types. @@ -475,6 +531,8 @@ module Handlers = struct pool = Pool.empty; mode; tx_timeout_limit; + tx_pool_addr_limit; + tx_pool_tx_per_addr_limit; locked = false; } in diff --git a/etherlink/bin_node/lib_dev/tx_pool.mli b/etherlink/bin_node/lib_dev/tx_pool.mli index 8529448cd17b519ff6ba2736f98f869ccb6709ee..9663e6145b6e335d99cfba5bfb83c1d680edef84 100644 --- a/etherlink/bin_node/lib_dev/tx_pool.mli +++ b/etherlink/bin_node/lib_dev/tx_pool.mli @@ -13,6 +13,9 @@ type parameters = { smart_rollup_address : string; (** The address of the smart rollup. *) mode : mode; tx_timeout_limit : int64; (** TTL of a transaction inside the pool. *) + tx_pool_addr_limit : int; (** Maximum allowed addresses inside the pool. *) + tx_pool_tx_per_addr_limit : int; + (** Maximum allowed transactions per address inside the pool. *) } (** [start parameters] starts the tx-pool *) diff --git a/etherlink/bin_node/lib_dev/tx_pool_events.ml b/etherlink/bin_node/lib_dev/tx_pool_events.ml index 5534fa554bb14a3164f40b4c15b29b7fe7ca2dc2..a3f853446bf9ce3de42efabaaae0cd2a3a76cdb3 100644 --- a/etherlink/bin_node/lib_dev/tx_pool_events.ml +++ b/etherlink/bin_node/lib_dev/tx_pool_events.ml @@ -36,6 +36,25 @@ module Event = struct ("transaction", Data_encoding.string) ~pp1:Format.pp_print_string + let users_threshold_reached = + declare_0 + ~section + ~name:"tx_pool_users_threshold_reached" + ~msg: + "The transaction pool has reached its maximum threshold for user \ + transactions" + ~level:Info + () + + let txs_per_user_threshold_reached = + declare_1 + ~section + ~name:"txs_per_user_threshold_reached" + ~msg:"User {address} has reached the maximum threshold for transactions" + ~level:Info + ("address", Data_encoding.string) + ~pp1:Format.pp_print_string + let transaction_injected = declare_1 ~section @@ -86,6 +105,12 @@ let add_transaction ~transaction = let invalid_transaction ~transaction = Internal_event.Simple.emit Event.invalid_transaction transaction +let users_threshold_reached = + Internal_event.Simple.emit Event.users_threshold_reached + +let txs_per_user_threshold_reached ~address = + Internal_event.Simple.emit Event.txs_per_user_threshold_reached address + let transaction_injection_failed trace = Internal_event.Simple.emit Event.transaction_injection_failed trace diff --git a/etherlink/bin_node/main.ml b/etherlink/bin_node/main.ml index bbad89c9e9a2e7418a2ccb13d7b1e34e40d3c122..2b6fd72d3a33c45afaa160a6a3acc5225afdf626 100644 --- a/etherlink/bin_node/main.ml +++ b/etherlink/bin_node/main.ml @@ -351,6 +351,24 @@ let tx_pool_timeout_limit_arg = ~doc:"Transaction timeout limit inside the transaction pool (in seconds)." Params.int +let tx_pool_addr_limit_arg = + Tezos_clic.default_arg + ~long:"tx-pool-addr-limit" + ~placeholder:"4_000" + ~default:"4_000" + ~doc:"Maximum allowed addresses inside the transaction pool." + Params.int + +let tx_pool_tx_per_addr_limit_arg = + Tezos_clic.default_arg + ~long:"tx-pool-tx-per-addr-limit" + ~placeholder:"16" + ~default:"16" + ~doc: + "Maximum allowed transactions per user address inside the transaction \ + pool." + Params.int + let sequencer_key_arg = Tezos_clic.arg ~long:"sequencer-key" @@ -439,7 +457,7 @@ let sequencer_command = let open Lwt_result_syntax in command ~desc:"Start the EVM node in sequencer mode" - (args21 + (args23 data_dir_arg rpc_addr_arg rpc_port_arg @@ -460,6 +478,8 @@ let sequencer_command = devmode_arg wallet_dir_arg tx_pool_timeout_limit_arg + tx_pool_addr_limit_arg + tx_pool_tx_per_addr_limit_arg (Client_config.password_filename_arg ())) (prefixes ["run"; "sequencer"; "with"; "endpoint"] @@ param @@ -490,6 +510,8 @@ let sequencer_command = devmode, wallet_dir, tx_pool_timeout_limit, + tx_pool_addr_limit, + tx_pool_tx_per_addr_limit, password_filename ) rollup_node_endpoint sequencer_str @@ -544,6 +566,8 @@ let sequencer_command = ?cors_origins ?cors_headers ~tx_pool_timeout_limit:(Int64.of_int tx_pool_timeout_limit) + ~tx_pool_addr_limit:(Int64.of_int tx_pool_addr_limit) + ~tx_pool_tx_per_addr_limit:(Int64.of_int tx_pool_tx_per_addr_limit) ~sequencer () in diff --git a/etherlink/tezt/lib/evm_node.ml b/etherlink/tezt/lib/evm_node.ml index a2b0abe38f7650198c8a35b1317f37f677b812dc..8344b84774c25638b461877ffd39d44dab8c2c5d 100644 --- a/etherlink/tezt/lib/evm_node.ml +++ b/etherlink/tezt/lib/evm_node.ml @@ -49,6 +49,8 @@ type mode = devmode : bool; wallet_dir : string option; tx_pool_timeout_limit : int option; + tx_pool_addr_limit : int option; + tx_pool_tx_per_addr_limit : int option; } | Proxy of {devmode : bool} @@ -448,6 +450,8 @@ let run_args evm_node = devmode; wallet_dir; tx_pool_timeout_limit; + tx_pool_addr_limit; + tx_pool_tx_per_addr_limit; } -> [ "run"; @@ -501,6 +505,14 @@ let run_args evm_node = "tx-pool-timeout-limit" string_of_int tx_pool_timeout_limit + @ Cli_arg.optional_arg + "tx-pool-addr-limit" + string_of_int + tx_pool_addr_limit + @ Cli_arg.optional_arg + "tx-pool-tx-per-addr-limit" + string_of_int + tx_pool_tx_per_addr_limit | Observer {preimages_dir; initial_kernel; rollup_node_endpoint} -> [ "run"; diff --git a/etherlink/tezt/lib/evm_node.mli b/etherlink/tezt/lib/evm_node.mli index 0c2410e63ae08bb5bdf62a8d7b75ec22007fb681..d76564004299f68d8dcf2f0a273bd083200afb6b 100644 --- a/etherlink/tezt/lib/evm_node.mli +++ b/etherlink/tezt/lib/evm_node.mli @@ -62,6 +62,12 @@ type mode = wallet_dir : string option; (** --wallet-dir: client directory. *) tx_pool_timeout_limit : int option; (** --tx-pool-timeout-limit: transaction timeout inside the pool. *) + tx_pool_addr_limit : int option; + (** --tx-pool-addr-limit: maximum address allowed simultaneously inside + the pool. *) + tx_pool_tx_per_addr_limit : int option; + (** --tx-pool-tx-per-addr-limit: maximum transaction per address allowed + simultaneously inside the pool. *) } | Proxy of {devmode : bool (** --devmode flag. *)} diff --git a/etherlink/tezt/tests/evm_rollup.ml b/etherlink/tezt/tests/evm_rollup.ml index 8cc79eea6db292dd013e96a31203854703b6f61c..522802d57b7a2a9b5a1c57fe95ab0232dc37f490 100644 --- a/etherlink/tezt/tests/evm_rollup.ml +++ b/etherlink/tezt/tests/evm_rollup.ml @@ -284,8 +284,9 @@ let setup_evm_kernel ?(setup_kernel_root_hash = true) ?config ?(bootstrap_accounts = Eth_account.bootstrap_accounts) ?(with_administrator = true) ?da_fee_per_byte ?minimum_base_fee_per_gas ~admin ?sequencer_admin ?commitment_period ?challenge_window ?timestamp - ?tx_pool_timeout_limit ?(setup_mode = Setup_proxy {devmode = true}) - ?(force_install_kernel = true) protocol = + ?tx_pool_timeout_limit ?tx_pool_addr_limit ?tx_pool_tx_per_addr_limit + ?(setup_mode = Setup_proxy {devmode = true}) ?(force_install_kernel = true) + protocol = let* node, client = setup_l1 ?commitment_period ?challenge_window ?timestamp protocol in @@ -410,6 +411,8 @@ let setup_evm_kernel ?(setup_kernel_root_hash = true) ?config devmode; wallet_dir = Some (Client.base_dir client); tx_pool_timeout_limit; + tx_pool_addr_limit; + tx_pool_tx_per_addr_limit; }) in let* evm_node = @@ -4521,6 +4524,8 @@ let test_migrate_proxy_to_sequencer_future = devmode = true; wallet_dir = Some (Client.base_dir client); tx_pool_timeout_limit = None; + tx_pool_addr_limit = None; + tx_pool_tx_per_addr_limit = None; } in Evm_node.create ~mode (Sc_rollup_node.endpoint sc_rollup_node) @@ -4684,6 +4689,8 @@ let test_migrate_proxy_to_sequencer_past = devmode = true; wallet_dir = Some (Client.base_dir client); tx_pool_timeout_limit = None; + tx_pool_addr_limit = None; + tx_pool_tx_per_addr_limit = None; } in Evm_node.create ~mode (Sc_rollup_node.endpoint sc_rollup_node) @@ -5280,6 +5287,129 @@ let test_tx_pool_timeout = | Empty -> unit | _ -> Test.fail "Inspected block shoud be empty." +let test_tx_pool_address_boundaries = + Protocol.register_test + ~__FILE__ + ~tags:["evm"; "tx_pool"; "address"; "boundaries"] + ~title: + "Check that the boundaries set for the transaction pool are properly \ + behaving." + ~uses:(fun _protocol -> + [ + Constant.octez_smart_rollup_node; + Constant.octez_evm_node; + Constant.smart_rollup_installer; + Constant.WASM.evm_kernel; + ]) + @@ fun protocol -> + let sequencer_admin = Constant.bootstrap1 in + let admin = Some Constant.bootstrap3 in + let setup_mode = + Setup_sequencer + { + time_between_blocks = Some Nothing; + sequencer = sequencer_admin; + devmode = true; + } + in + let* {evm_node = sequencer_node; _} = + setup_evm_kernel + ~sequencer_admin + ~admin + ~minimum_base_fee_per_gas:base_fee_for_hardcoded_tx + ~tx_pool_addr_limit:1 + ~tx_pool_tx_per_addr_limit:1 + ~setup_mode + protocol + in + let tx = + (* { "chainId": "1337", + "type": "LegacyTransaction", + "valid": true, + "hash": "0xb941cbf32821471381b6f003f9013b95c788ad24260d2af54848a5b504c09bb0", + "nonce": "0", + "gasPrice": "21000", + "gasLimit": "2000000", + "from": "0x6ce4d79d4E77402e1ef3417Fdda433aA744C6e1c", + "to": "0x6ce4d79d4e77402e1ef3417fdda433aa744c6e1c", + "v": "0a95", + "r": "964f3d64696410dc1054af0aca06d5a4005a3bdf3db0b919e3de207af93e1004", + "s": "3eb79935b4e15a576955c104fd6a614437dd0464d382198dde4c52a8eed4061a", + "value": "0" } *) + "f86480825208831e8480946ce4d79d4e77402e1ef3417fdda433aa744c6e1c8080820a95a0964f3d64696410dc1054af0aca06d5a4005a3bdf3db0b919e3de207af93e1004a03eb79935b4e15a576955c104fd6a614437dd0464d382198dde4c52a8eed4061a" + in + let tx' = + (* { "chainId": "1337", + "type": "LegacyTransaction", + "valid": true, + "hash": "0x51a24a5cf2eb3095f522e4c500b1bf5b0de6476f04a108ea1005cfef7ceec750", + "nonce": "1", + "gasPrice": "21000", + "gasLimit": "2000000", + "from": "0x6ce4d79d4E77402e1ef3417Fdda433aA744C6e1c", + "to": "0x6ce4d79d4e77402e1ef3417fdda433aa744c6e1c", + "v": "0a95", + "r": "7298a47ad7fcbe70dc9d3705af6e47147364c5ac8ede95fb561ffaa3443dd776", + "s": "7042e72941ffdef02c773b7289d7e4241a5c819e78c7bfb362c7f151b0ba3e9e", + "value": "0" } *) + "f86401825208831e8480946ce4d79d4e77402e1ef3417fdda433aa744c6e1c8080820a95a07298a47ad7fcbe70dc9d3705af6e47147364c5ac8ede95fb561ffaa3443dd776a07042e72941ffdef02c773b7289d7e4241a5c819e78c7bfb362c7f151b0ba3e9e" + in + let tx'' = + (* { "chainId": "1337", + "type": "LegacyTransaction", + "valid": true, + "hash": "0x25a2f2e9c1cadada66ce255e609c0ace80435b0b595371a5da2bb104757e6ade", + "nonce": "0", + "gasPrice": "21000", + "gasLimit": "23300", + "from": "0xB53dc01974176E5dFf2298C5a94343c2585E3c54", + "to": "0xb53dc01974176e5dff2298c5a94343c2585e3c54", + "v": "0a95", + "r": "9bc3d2c48b9d3db98b277ddb804941deeb899d65b2a22c76600810270d1bcfcf", + "s": "5a3c7ead9bbf152acd4f7ea01a4cec70c921cde466840a9bdad4c2d8939963ef", + "value": "100000" } *) + "f86680825208825b0494b53dc01974176e5dff2298c5a94343c2585e3c54830186a080820a95a09bc3d2c48b9d3db98b277ddb804941deeb899d65b2a22c76600810270d1bcfcfa05a3c7ead9bbf152acd4f7ea01a4cec70c921cde466840a9bdad4c2d8939963ef" + in + let*@ tx_hash_expected = Rpc.send_raw_transaction ~raw_tx:tx sequencer_node in + (* Limitation on the number of transaction per address *) + let*@? rejected_transaction' = + Rpc.send_raw_transaction ~raw_tx:tx' sequencer_node + in + Check.( + (rejected_transaction'.message + = "Limit of transaction for a user was reached. Transaction is rejected.") + string) + ~error_msg:"This transaction should be rejected with error msg %R not %L" ; + (* Limitation on the number of allowed address inside the transaction pool *) + let*@? rejected_transaction'' = + Rpc.send_raw_transaction ~raw_tx:tx'' sequencer_node + in + Check.( + (rejected_transaction''.message + = "The transaction pool has reached its maximum threshold for user \ + transactions. Transaction is rejected.") + string) + ~error_msg:"This transaction should be rejected with error msg %R not %L" ; + let*@ block_number = Rpc.produce_block sequencer_node in + let*@ block = + Rpc.get_block_by_number ~block:(Int.to_string block_number) sequencer_node + in + let tx_hash = + match block.transactions with + | Hash txs -> List.hd txs + | Empty -> + Test.fail + "Inspected block should contain a list of one transaction hash and \ + not be empty." + | Full _ -> + Test.fail + "Inspected block should contain a list of one transaction hash, not \ + full objects." + in + Check.((tx_hash = tx_hash_expected) string) + ~error_msg:"Expected transaction hash is %R, got %L" ; + unit + let register_evm_node ~protocols = test_originate_evm_kernel protocols ; test_kernel_root_hash_originate_absent protocols ; @@ -5375,7 +5505,8 @@ let register_evm_node ~protocols = test_revert_is_correctly_propagated protocols ; test_outbox_size_limit_resilience ~slow:true protocols ; test_outbox_size_limit_resilience ~slow:false protocols ; - test_tx_pool_timeout protocols + test_tx_pool_timeout protocols ; + test_tx_pool_address_boundaries protocols let protocols = Protocol.all diff --git a/etherlink/tezt/tests/evm_sequencer.ml b/etherlink/tezt/tests/evm_sequencer.ml index 8295d2f58e54fe55a6bd51b8533350d915155557..4354cf15892443a6fda6990897f02fec4c671cba 100644 --- a/etherlink/tezt/tests/evm_sequencer.ml +++ b/etherlink/tezt/tests/evm_sequencer.ml @@ -206,6 +206,8 @@ let setup_sequencer ?(devmode = true) ?config ?genesis_timestamp devmode; wallet_dir = Some (Client.base_dir client); tx_pool_timeout_limit = None; + tx_pool_addr_limit = None; + tx_pool_tx_per_addr_limit = None; } in let* sequencer =