diff --git a/etherlink/bin_node/lib_dev/block_producer.ml b/etherlink/bin_node/lib_dev/block_producer.ml index 7b86cbc979fffeb996d5119d0c439d2e5c9bd63b..5643bfa0e2e2b663bb6087cfd2b1b162870d200e 100644 --- a/etherlink/bin_node/lib_dev/block_producer.ml +++ b/etherlink/bin_node/lib_dev/block_producer.ml @@ -10,8 +10,8 @@ type parameters = { smart_rollup_address : string; sequencer_key : Client_keys.sk_uri; maximum_number_of_chunks : int; - uses_tx_queue : bool; - l2_chains : Configuration.l2_chain list option; + chain_family : L2_types.chain_family; + tx_container : (module Services_backend_sig.Tx_container); } (* The size of a delayed transaction is overapproximated to the maximum size @@ -216,53 +216,67 @@ let validate_tx ~maximum_cumulative_size (current_size, validation_state) raw_tx in return `Drop -let tx_queue_pop_valid_tx (head_info : Evm_context.head) - ~maximum_cumulative_size = +let pop_valid_tx ~chain_family + ~(tx_container : (module Services_backend_sig.Tx_container)) + (head_info : Evm_context.head) ~maximum_cumulative_size = let open Lwt_result_syntax in - let read = Evm_state.read head_info.evm_state in - let* base_fee_per_gas = Durable_storage.base_fee_per_gas read in - let* maximum_gas_limit = Durable_storage.maximum_gas_per_transaction read in - let* da_fee_per_byte = 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); - } - in - let initial_validation_state = - ( 0, - Validate. - {config; addr_balance = String.Map.empty; addr_nonce = String.Map.empty} - ) - in - Tx_queue.pop_transactions - ~validate_tx:(validate_tx ~maximum_cumulative_size) - ~initial_validation_state + let (module Tx_container) = tx_container in + (* Skip validation if chain_family is Michelson. *) + match chain_family with + | L2_types.Michelson -> + let initial_validation_state = () in + Tx_container.pop_transactions + ~maximum_cumulative_size + ~validate_tx:(fun () _ _ -> return (`Keep ())) + ~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* maximum_gas_limit = + Durable_storage.maximum_gas_per_transaction read + in + let* da_fee_per_byte = 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); + } + in + let initial_validation_state = + ( 0, + Validate. + { + config; + addr_balance = String.Map.empty; + addr_nonce = String.Map.empty; + } ) + in + Tx_container.pop_transactions + ~maximum_cumulative_size + ~validate_tx:(validate_tx ~maximum_cumulative_size) + ~initial_validation_state (** Produces a block if we find at least one valid transaction in the transaction pool or if [force] is true. *) -let produce_block_if_needed ~cctxt ~l2_chains ~smart_rollup_address +let produce_block_if_needed ~cctxt ~chain_family ~smart_rollup_address ~sequencer_key ~force ~timestamp ~delayed_hashes ~remaining_cumulative_size - ~uses_tx_queue head_info = + ~(tx_container : (module Services_backend_sig.Tx_container)) head_info = let open Lwt_result_syntax in + let (module Tx_container) = tx_container in let* transactions_and_objects = (* Low key optimization to avoid even checking the txpool if there is not enough space for the smallest transaction. *) if remaining_cumulative_size <= minimum_ethereum_transaction_size then return [] - else if uses_tx_queue then - tx_queue_pop_valid_tx - head_info - ~maximum_cumulative_size:remaining_cumulative_size else - (* TODO: We should iterate when multichain https://gitlab.com/tezos/tezos/-/issues/7859 *) - let chain_family = Configuration.retrieve_chain_family ~l2_chains in - Tx_pool.pop_transactions + pop_valid_tx ~chain_family + ~tx_container + head_info ~maximum_cumulative_size:remaining_cumulative_size in let n = List.length transactions_and_objects + List.length delayed_hashes in @@ -278,11 +292,9 @@ let produce_block_if_needed ~cctxt ~l2_chains ~smart_rollup_address head_info in let* () = - if uses_tx_queue then - Tx_queue.confirm_transactions - ~clear_pending_queue_after:true - ~confirmed_txs - else Tx_pool.clear_popped_transactions () + Tx_container.confirm_transactions + ~clear_pending_queue_after:true + ~confirmed_txs in return (`Block_produced n) else return `No_block @@ -305,13 +317,12 @@ let head_info_and_delayed_transactions ~with_delayed_transactions let*! head_info = Evm_context.head_info () in return (head_info, delayed_hashes, remaining_cumulative_size) -let produce_block ~l2_chains ~uses_tx_queue ~cctxt ~smart_rollup_address - ~sequencer_key ~force ~timestamp ~maximum_number_of_chunks - ~with_delayed_transactions = +let produce_block ~chain_family ~cctxt ~smart_rollup_address ~sequencer_key + ~force ~timestamp ~maximum_number_of_chunks ~with_delayed_transactions + ~(tx_container : (module Services_backend_sig.Tx_container)) = let open Lwt_result_syntax in - let* is_locked = - if uses_tx_queue then Tx_queue.is_locked () else Tx_pool.is_locked () - in + let (module Tx_container) = tx_container in + let* is_locked = Tx_container.is_locked () in if is_locked then let*! () = Block_producer_events.production_locked () in return `No_block @@ -343,14 +354,14 @@ let produce_block ~l2_chains ~uses_tx_queue ~cctxt ~smart_rollup_address else produce_block_if_needed ~cctxt - ~l2_chains + ~chain_family ~sequencer_key ~timestamp ~smart_rollup_address ~force ~delayed_hashes ~remaining_cumulative_size - ~uses_tx_queue + ~tx_container head_info module Handlers = struct @@ -370,14 +381,13 @@ module Handlers = struct smart_rollup_address; sequencer_key; maximum_number_of_chunks; - uses_tx_queue; - l2_chains; + chain_family; + tx_container; } = state in produce_block - ~l2_chains - ~uses_tx_queue + ~chain_family ~cctxt ~smart_rollup_address ~sequencer_key @@ -385,6 +395,7 @@ module Handlers = struct ~timestamp ~maximum_number_of_chunks ~with_delayed_transactions + ~tx_container type launch_error = error trace diff --git a/etherlink/bin_node/lib_dev/block_producer.mli b/etherlink/bin_node/lib_dev/block_producer.mli index 877f1b1857f28ce5125a32d7358ef728d218a820..cabbd676e14ccf96c9d1dd2e6d94c2236b17c79d 100644 --- a/etherlink/bin_node/lib_dev/block_producer.mli +++ b/etherlink/bin_node/lib_dev/block_producer.mli @@ -10,8 +10,8 @@ type parameters = { smart_rollup_address : string; sequencer_key : Client_keys.sk_uri; maximum_number_of_chunks : int; - uses_tx_queue : bool; - l2_chains : Configuration.l2_chain list option; + chain_family : L2_types.chain_family; + tx_container : (module Services_backend_sig.Tx_container); } (** [start parameters] starts the events follower. *) diff --git a/etherlink/bin_node/lib_dev/observer.ml b/etherlink/bin_node/lib_dev/observer.ml index ed6433468b44c7fd52fbcb3e4f1996b165063227..a2ceba27a1b1e68962c76235714a2822ffaa1e27 100644 --- a/etherlink/bin_node/lib_dev/observer.ml +++ b/etherlink/bin_node/lib_dev/observer.ml @@ -7,15 +7,6 @@ (*****************************************************************************) open Ethereum_types -open L2_types - -let confirm_txs config confirmed_txs = - let open Lwt_result_syntax in - if Configuration.is_tx_queue_enabled config then - Tx_queue.confirm_transactions - ~clear_pending_queue_after:false - ~confirmed_txs - else return_unit (** [on_new_blueprint evm_node_endpoint next_blueprint_number blueprint] applies evm events found in the blueprint, then applies @@ -30,10 +21,12 @@ let confirm_txs config confirmed_txs = into a forced blueprint. The sequencer has performed a reorganization and starts submitting blocks from the new branch. *) -let on_new_blueprint config evm_node_endpoint next_blueprint_number +let on_new_blueprint (tx_container : (module Services_backend_sig.Tx_container)) + evm_node_endpoint next_blueprint_number (({delayed_transactions; blueprint; _} : Blueprint_types.with_events) as blueprint_with_events) = let open Lwt_result_syntax in + let (module Tx_container) = tx_container in let (Qty level) = blueprint.number in let (Qty number) = next_blueprint_number in if Z.(equal level number) then @@ -68,8 +61,12 @@ let on_new_blueprint config evm_node_endpoint next_blueprint_number failwith "Could not recover from failing to apply latest received \ blueprint.") - | Ok tx_hashes -> - let* () = confirm_txs config tx_hashes in + | Ok confirmed_txs -> + let* () = + Tx_container.confirm_transactions + ~clear_pending_queue_after:false + ~confirmed_txs + in return `Continue | Error (Node_error.Diverged {must_exit = false; _} :: _) -> (* If we have diverged, but should keep the node alive. This happens @@ -141,6 +138,15 @@ let container_forward_tx ~keep_alive ~evm_node_endpoint : let lock_transactions () = Lwt_result_syntax.return_unit let unlock_transactions () = Lwt_result_syntax.return_unit + + let is_locked () = Lwt_result_syntax.return_false + + let confirm_transactions ~clear_pending_queue_after:_ ~confirmed_txs:_ = + Lwt_result_syntax.return_unit + + let pop_transactions ~maximum_cumulative_size:_ ~validate_tx:_ + ~initial_validation_state:_ = + Lwt_result_syntax.return_nil end) let main ?network ?kernel_path ~data_dir ~(config : Configuration.t) ~no_sync @@ -221,6 +227,12 @@ let main ?network ?kernel_path ~data_dir ~(config : Configuration.t) ~no_sync Evm_ro_context.ro_backend ro_ctxt config ~evm_node_endpoint in + let* enable_multichain = Evm_ro_context.read_enable_multichain_flag ro_ctxt in + let* l2_chain_id, chain_family = + let (module Backend) = observer_backend in + Backend.single_chain_id_and_family ~config ~enable_multichain + in + let* () = match config.experimental_features.enable_tx_queue with | Some tx_queue_config -> @@ -239,6 +251,7 @@ let main ?network ?kernel_path ~data_dir ~(config : Configuration.t) ~no_sync 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; + chain_family; } in @@ -247,31 +260,6 @@ let main ?network ?kernel_path ~data_dir ~(config : Configuration.t) ~no_sync ~tx_pool_size_info:Tx_pool.size_info ~smart_rollup_address ; - let* enable_multichain = Evm_ro_context.read_enable_multichain_flag ro_ctxt in - - let* l2_chain_id, chain_family = - match (config.experimental_features.l2_chains, enable_multichain) with - | None, false -> return (None, EVM) - | None, true -> tzfail Node_error.Singlechain_node_multichain_kernel - | Some [l2_chain], false -> - let*! () = Events.multichain_node_singlechain_kernel () in - return (Some l2_chain.chain_id, EVM) - | Some [l2_chain], true -> - let chain_id = l2_chain.chain_id in - let* chain_family = Evm_ro_context.read_chain_family ro_ctxt chain_id in - if l2_chain.chain_family = chain_family then - return (Some chain_id, chain_family) - else - tzfail - (Node_error.Mismatched_chain_family - { - chain_id; - node_family = l2_chain.chain_family; - kernel_family = chain_family; - }) - | _ -> tzfail Node_error.Unexpected_multichain - in - let* finalizer_public_server = Rpc_server.start_public_server ~l2_chain_id @@ -360,7 +348,7 @@ let main ?network ?kernel_path ~data_dir ~(config : Configuration.t) ~no_sync ~time_between_blocks ~evm_node_endpoint ~next_blueprint_number - (on_new_blueprint config evm_node_endpoint) + (on_new_blueprint tx_container evm_node_endpoint) and* () = Drift_monitor.run ~evm_node_endpoint Evm_context.next_blueprint_number and* () = diff --git a/etherlink/bin_node/lib_dev/proxy.ml b/etherlink/bin_node/lib_dev/proxy.ml index 570a96c0aed7033aee40b9ce67264bd232acfd5c..63ac6020f543aebb460b224d72b527887d2bbdc3 100644 --- a/etherlink/bin_node/lib_dev/proxy.ml +++ b/etherlink/bin_node/lib_dev/proxy.ml @@ -53,9 +53,19 @@ let container_forward_tx ~evm_node_endpoint ~keep_alive : let lock_transactions () = Lwt_result_syntax.return_unit let unlock_transactions () = Lwt_result_syntax.return_unit + + let is_locked () = Lwt_result_syntax.return_false + + let pop_transactions ~maximum_cumulative_size:_ ~validate_tx:_ + ~initial_validation_state:_ = + Lwt_result_syntax.return_nil + + let confirm_transactions ~clear_pending_queue_after:_ ~confirmed_txs:_ = + Lwt_result_syntax.return_unit end) let tx_queue_pop_and_inject (module Rollup_node_rpc : Services_backend_sig.S) + (module Tx_container : Services_backend_sig.Tx_container) ~smart_rollup_address = let open Lwt_result_syntax in let maximum_cumulative_size = @@ -69,7 +79,10 @@ let tx_queue_pop_and_inject (module Rollup_node_rpc : Services_backend_sig.S) else return (`Keep new_size) in let* popped_txs = - Tx_queue.pop_transactions ~initial_validation_state ~validate_tx + Tx_container.pop_transactions + ~maximum_cumulative_size + ~initial_validation_state + ~validate_tx in let*! hashes = Rollup_node_rpc.inject_transactions @@ -85,7 +98,7 @@ let tx_queue_pop_and_inject (module Rollup_node_rpc : Services_backend_sig.S) return_unit | Ok hashes -> let* () = - Tx_queue.confirm_transactions + Tx_container.confirm_transactions ~clear_pending_queue_after:true ~confirmed_txs:(List.to_seq hashes) in @@ -142,6 +155,20 @@ let main | Some _base -> Validate.Stateless | None -> Validate.Full in + let* l2_chain_id, chain_family = + if finalized_view then + if + (* When finalized_view is set, it's too early to request the + feature flag from the rollup node. *) + Option.is_some config.experimental_features.l2_chains + then + (* The finalized view of the proxy mode and the multichain feature are not compatible. *) + tzfail (Node_error.Proxy_finalize_with_multichain `Node) + else return (None, L2_types.EVM) + else + let* enable_multichain = Rollup_node_rpc.is_multichain_enabled () in + Rollup_node_rpc.single_chain_id_and_family ~config ~enable_multichain + in let* on_new_head, tx_container = match ( config.experimental_features.enable_send_raw_transaction, @@ -155,14 +182,17 @@ let main ~keep_alive:config.keep_alive () in + let tx_container = + (module Tx_queue.Tx_container : Services_backend_sig.Tx_container) + in return @@ ( Some (fun () -> tx_queue_pop_and_inject (module Rollup_node_rpc) + tx_container ~smart_rollup_address), - (module Tx_queue.Tx_container : Services_backend_sig.Tx_container) - ) + tx_container ) | true, None, None -> let* () = Tx_pool.start @@ -174,6 +204,7 @@ let main 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; + chain_family; } in return @@ -192,39 +223,6 @@ let main ~rollup_node_endpoint () in - let* l2_chain_id, chain_family = - if finalized_view then - if - (* When finalized_view is set, it's too early to request the - feature flag from the rollup node. *) - Option.is_some config.experimental_features.l2_chains - then - (* The finalized view of the proxy mode and the multichain feature are not compatible. *) - tzfail (Node_error.Proxy_finalize_with_multichain `Node) - else return (None, L2_types.EVM) - else - let* enable_multichain = Rollup_node_rpc.is_multichain_enabled () in - match (config.experimental_features.l2_chains, enable_multichain) with - | None, false -> return (None, L2_types.EVM) - | None, true -> tzfail Node_error.Singlechain_node_multichain_kernel - | Some [l2_chain], false -> - let*! () = Events.multichain_node_singlechain_kernel () in - return (Some l2_chain.chain_id, L2_types.EVM) - | Some [l2_chain], true -> - let chain_id = l2_chain.chain_id in - let* chain_family = Rollup_node_rpc.chain_family chain_id in - if l2_chain.chain_family = chain_family then - return (Some chain_id, chain_family) - else - tzfail - (Node_error.Mismatched_chain_family - { - chain_id; - node_family = l2_chain.chain_family; - kernel_family = chain_family; - }) - | _ -> tzfail Node_error.Unexpected_multichain - in let* server_finalizer = Rpc_server.start_public_server diff --git a/etherlink/bin_node/lib_dev/rpc.ml b/etherlink/bin_node/lib_dev/rpc.ml index c394e3dd0dc30784e1eb53571fa4e307b410d131..fc3732870bba045c1aa1388e14e6a92b946ce3fe 100644 --- a/etherlink/bin_node/lib_dev/rpc.ml +++ b/etherlink/bin_node/lib_dev/rpc.ml @@ -146,6 +146,15 @@ let container_forward_request ~public_endpoint ~private_endpoint ~keep_alive : let lock_transactions () = Lwt_result_syntax.return_unit let unlock_transactions () = Lwt_result_syntax.return_unit + + let is_locked () = Lwt_result_syntax.return_false + + let confirm_transactions ~clear_pending_queue_after:_ ~confirmed_txs:_ = + Lwt_result_syntax.return_unit + + let pop_transactions ~maximum_cumulative_size:_ ~validate_tx:_ + ~initial_validation_state:_ = + Lwt_result_syntax.return_nil end) let main ~data_dir ~evm_node_endpoint ?evm_node_private_endpoint @@ -168,6 +177,12 @@ let main ~data_dir ~evm_node_endpoint ?evm_node_private_endpoint let rpc_backend = Evm_ro_context.ro_backend ctxt config ~evm_node_endpoint in + let* enable_multichain = Evm_ro_context.read_enable_multichain_flag ctxt in + let* l2_chain_id, chain_family = + let (module Backend) = rpc_backend in + Backend.single_chain_id_and_family ~config ~enable_multichain + in + let* ping_tx_pool, tx_container = match (evm_node_private_endpoint, config.experimental_features.enable_tx_queue) @@ -205,6 +220,7 @@ let main ~data_dir ~evm_node_endpoint ?evm_node_private_endpoint 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; + chain_family; } in return @@ -229,31 +245,6 @@ let main ~data_dir ~evm_node_endpoint ?evm_node_private_endpoint } in - let* enable_multichain = Evm_ro_context.read_enable_multichain_flag ctxt in - - let* l2_chain_id, chain_family = - match (config.experimental_features.l2_chains, enable_multichain) with - | None, false -> return (None, L2_types.EVM) - | None, true -> tzfail Node_error.Singlechain_node_multichain_kernel - | Some [l2_chain], false -> - let*! () = Events.multichain_node_singlechain_kernel () in - return (Some l2_chain.chain_id, L2_types.EVM) - | Some [l2_chain], true -> - let chain_id = l2_chain.chain_id in - let* chain_family = Evm_ro_context.read_chain_family ctxt chain_id in - if l2_chain.chain_family = chain_family then - return (Some chain_id, chain_family) - else - tzfail - (Node_error.Mismatched_chain_family - { - chain_id; - node_family = l2_chain.chain_family; - kernel_family = chain_family; - }) - | _ -> tzfail Node_error.Unexpected_multichain - in - let* server_public_finalizer = Rpc_server.start_public_server ~l2_chain_id diff --git a/etherlink/bin_node/lib_dev/sequencer.ml b/etherlink/bin_node/lib_dev/sequencer.ml index 46d5f268257f307c614402f3e8daad6546900e52..63882adc14174aaffc70dd84a5d8f678fd9f43df 100644 --- a/etherlink/bin_node/lib_dev/sequencer.ml +++ b/etherlink/bin_node/lib_dev/sequencer.ml @@ -286,6 +286,11 @@ let main ~data_dir ?(genesis_timestamp = Misc.now ()) ~cctxt in let backend = Evm_ro_context.ro_backend ro_ctxt configuration in + let* enable_multichain = Evm_ro_context.read_enable_multichain_flag ro_ctxt in + let* l2_chain_id, chain_family = + let (module Backend) = backend in + Backend.single_chain_id_and_family ~config:configuration ~enable_multichain + in let* () = match configuration.experimental_features.enable_tx_queue with | Some tx_queue_config -> @@ -303,6 +308,7 @@ let main ~data_dir ?(genesis_timestamp = Misc.now ()) ~cctxt 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; + chain_family; } in Metrics.init @@ -316,8 +322,8 @@ let main ~data_dir ?(genesis_timestamp = Misc.now ()) ~cctxt smart_rollup_address = smart_rollup_address_b58; sequencer_key = sequencer_config.sequencer; maximum_number_of_chunks = sequencer_config.max_number_of_chunks; - uses_tx_queue = Configuration.is_tx_queue_enabled configuration; - l2_chains = configuration.experimental_features.l2_chains; + chain_family; + tx_container; } in let* () = @@ -337,37 +343,9 @@ let main ~data_dir ?(genesis_timestamp = Misc.now ()) ~cctxt in return_unit in - let* enable_multichain = Evm_ro_context.read_enable_multichain_flag ro_ctxt in - let* () = - match - (configuration.experimental_features.l2_chains, enable_multichain) - with - | None, false -> return_unit - | None, true -> tzfail Node_error.Singlechain_node_multichain_kernel - | Some _, false -> - let*! () = Events.multichain_node_singlechain_kernel () in - return_unit - | Some l2_chains, true -> - List.iter_es - (fun l2_chain -> - let chain_id = l2_chain.chain_id in - let* chain_family = - Evm_ro_context.read_chain_family ro_ctxt chain_id - in - if chain_family = l2_chain.chain_family then return_unit - else - tzfail - (Node_error.Mismatched_chain_family - { - chain_id; - node_family = l2_chain.chain_family; - kernel_family = chain_family; - })) - l2_chains - in let* finalizer_public_server = Rpc_server.start_public_server - ~l2_chain_id:None + ~l2_chain_id ~evm_services: Evm_ro_context.( evm_services_methods ro_ctxt sequencer_config.time_between_blocks) diff --git a/etherlink/bin_node/lib_dev/services_backend_sig.ml b/etherlink/bin_node/lib_dev/services_backend_sig.ml index a81e5d95240e2f9486db9ff2e4c5a3590ffe076d..d6edcf72f0313479d292406e658f426d9429c427 100644 --- a/etherlink/bin_node/lib_dev/services_backend_sig.ml +++ b/etherlink/bin_node/lib_dev/services_backend_sig.ml @@ -52,6 +52,28 @@ module type S = sig (** [chain_family chain_id] returns chain family defined for the chain with id chain_id. *) val chain_family : L2_types.chain_id -> L2_types.chain_family tzresult Lwt.t + (** [single_chain_id_and_family] should only be called if the + node is expected to follow a single chain. It compares the + configuration of the node and the one of the kernel regarding the + chain id and chain family. + + If the multichain feature is disabled in both the kernel and the + node, the default value [(None, EVM)] is returned. + + If the multichain feature is enabled in the kernel, check that it + is also enabled in the node, that the node is configured to follow + exactly one of the chains, that its chain id is among the + configured ones in the kernel, and that the chain families for + this chain agree in the node and the kernel. + + If the multichain feature is disabled in the kernel but enabled in + the node, a warning is emmitted, the configured chain family is + ignored and the returned chain family is the default [EVM]. *) + val single_chain_id_and_family : + config:Configuration.t -> + 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 @@ -189,6 +211,30 @@ module Make (Backend : Backend) (Executor : Evm_execution.S) : S = struct let list_l1_l2_levels = Backend.list_l1_l2_levels let l2_levels_of_l1_level = Backend.l2_levels_of_l1_level + + let single_chain_id_and_family ~(config : Configuration.t) ~enable_multichain + = + let open Lwt_result_syntax in + match (config.experimental_features.l2_chains, enable_multichain) with + | None, false -> return (None, L2_types.EVM) + | None, true -> tzfail Node_error.Singlechain_node_multichain_kernel + | Some [l2_chain], false -> + let*! () = Events.multichain_node_singlechain_kernel () in + return (Some l2_chain.chain_id, L2_types.EVM) + | Some [l2_chain], true -> + let chain_id = l2_chain.chain_id in + let* chain_family = chain_family chain_id in + if l2_chain.chain_family = chain_family then + return (Some chain_id, chain_family) + else + tzfail + (Node_error.Mismatched_chain_family + { + chain_id; + node_family = l2_chain.chain_family; + kernel_family = chain_family; + }) + | _ -> tzfail Node_error.Unexpected_multichain end (** Inject transactions with either RPCs or on a websocket connection. *) @@ -247,4 +293,37 @@ module type Tx_container = sig (** [unlock_transactions] unlocks the transactions if it was locked by {!lock_transactions}. *) val unlock_transactions : unit -> unit tzresult Lwt.t + + (** [is_locked] checks if the queue is locked. *) + val is_locked : unit -> bool tzresult Lwt.t + + (** The Tx_queue has a table of pending transactions. There are two + ways for transactions to be removed from this table; either they + are confirmed because they have been seen in a block or they are + dropped. + + [confirm_transactions ~clear_pending_queue_after ~confirmed_txs] + confirms [confirmed_txs] hash. If [clear_pending_queue_after] + then any other pending transactions in the tx_queue are + dropped. *) + val confirm_transactions : + clear_pending_queue_after:bool -> + confirmed_txs:Ethereum_types.hash Seq.t -> + unit tzresult Lwt.t + + (** The Tx_pool pops transactions until the sum of the sizes of the + popped transactions reaches maximum_cumulative_size; it ignores + the [validate_tx] and [initial_validation_state] arguments, The + Tx_queue however ignores [maximum_cumulative_size] and instead + uses [validate_tx] to pop valid transactions until either `Drop + or `Stop is returned. *) + val pop_transactions : + maximum_cumulative_size:int -> + validate_tx: + ('a -> + string -> + Ethereum_types.legacy_transaction_object -> + [`Keep of 'a | `Drop | `Stop] tzresult Lwt.t) -> + initial_validation_state:'a -> + (string * Ethereum_types.legacy_transaction_object) list tzresult Lwt.t end diff --git a/etherlink/bin_node/lib_dev/tx_pool.ml b/etherlink/bin_node/lib_dev/tx_pool.ml index 7fdf52b2b041a5597a9b37cce091d7a01f00fec9..3a226c4029c008a75d7bdab103fce0b6b14d6662 100644 --- a/etherlink/bin_node/lib_dev/tx_pool.ml +++ b/etherlink/bin_node/lib_dev/tx_pool.ml @@ -231,6 +231,7 @@ type parameters = { tx_timeout_limit : int64; tx_pool_addr_limit : int; tx_pool_tx_per_addr_limit : int; + chain_family : L2_types.chain_family; } module Types = struct @@ -244,6 +245,7 @@ module Types = struct tx_pool_addr_limit : int; tx_pool_tx_per_addr_limit : int; mutable locked : bool; + chain_family : L2_types.chain_family; } type nonrec parameters = parameters @@ -268,11 +270,7 @@ module Request = struct Ethereum_types.legacy_transaction_object * string -> ((Ethereum_types.hash, string) result, tztrace) t | Pop_transactions : - (* TODO: https://gitlab.com/tezos/tezos/-/issues/7889 *) - (* We need the chain_family to verify if we are in Tezlink mode *) - (* If so, deactivate the pop_transactions and returns an empty list *) - L2_types.chain_family - * int + int -> ((string * Ethereum_types.legacy_transaction_object) list, tztrace) t | Pop_and_inject_transactions : (unit, tztrace) t | Lock_transactions : (unit, tztrace) t @@ -310,16 +308,15 @@ module Request = struct case (Tag 1) ~title:"Pop_transactions" - (obj3 + (obj2 (req "request" (constant "pop_transactions")) - (req "chain_family" L2_types.Chain_family.encoding) (req "maximum_cumulatize_size" int31)) (function - | View (Pop_transactions (chain_family, maximum_cumulative_size)) -> - Some ((), chain_family, maximum_cumulative_size) + | View (Pop_transactions maximum_cumulative_size) -> + Some ((), maximum_cumulative_size) | _ -> None) - (fun ((), chain_family, maximum_cumulative_size) -> - View (Pop_transactions (chain_family, maximum_cumulative_size))); + (fun ((), maximum_cumulative_size) -> + View (Pop_transactions maximum_cumulative_size)); case (Tag 2) ~title:"Pop_and_inject_transactions" @@ -373,7 +370,7 @@ module Request = struct ppf "Add tx [%s] to tx-pool" (Hex.of_string tx_raw |> Hex.show) - | Pop_transactions (_chain_family, maximum_cumulative_size) -> + | Pop_transactions maximum_cumulative_size -> Format.fprintf ppf "Popping transactions of maximum cumulative size %d bytes" @@ -493,7 +490,7 @@ let transaction_timed_out ~tx_timeout_limit ~current_timestamp ~inclusion_timestamp = Time.Protocol.diff current_timestamp inclusion_timestamp >= tx_timeout_limit -let pop_transactions state ~chain_family ~maximum_cumulative_size = +let pop_transactions state ~maximum_cumulative_size = let open Lwt_result_syntax in let Types. { @@ -505,7 +502,7 @@ let pop_transactions state ~chain_family ~maximum_cumulative_size = } = state in - if locked || chain_family = L2_types.Michelson then return [] + if locked || state.chain_family = L2_types.Michelson then return [] else (* Get all the addresses in the tx-pool. *) let addresses = Pool.addresses pool in @@ -623,7 +620,7 @@ let clear_popped_transactions state = state.Types.popped_txs <- [] are forwarded to a rollup node, in observer mode to the next evm node. The sequencer is not supposed to use this function, using it would make transaction disappear from the tx pool. *) -let pop_and_inject_transactions ~chain_family state = +let pop_and_inject_transactions state = let open Lwt_result_syntax in let open Types in (* We over approximate the number of transactions to pop in proxy and @@ -634,7 +631,7 @@ let pop_and_inject_transactions ~chain_family state = Sequencer_blueprint.maximum_usable_space_in_blueprint Sequencer_blueprint.maximum_chunks_per_l1_level in - let* txs = pop_transactions state ~chain_family ~maximum_cumulative_size in + let* txs = pop_transactions state ~maximum_cumulative_size in if not (List.is_empty txs) then let (module Backend : Services_backend_sig.S) = state.backend in let*! hashes = @@ -715,12 +712,10 @@ module Handlers = struct let* res = insert_valid_transaction state txn transaction_object in let* () = relay_self_inject_request w in return res - | Request.Pop_transactions (chain_family, maximum_cumulative_size) -> - protect @@ fun () -> - pop_transactions state ~chain_family ~maximum_cumulative_size + | Request.Pop_transactions maximum_cumulative_size -> + protect @@ fun () -> pop_transactions state ~maximum_cumulative_size | Request.Pop_and_inject_transactions -> - protect @@ fun () -> - pop_and_inject_transactions ~chain_family:L2_types.EVM state + protect @@ fun () -> pop_and_inject_transactions state | Request.Lock_transactions -> protect @@ fun () -> return (lock_transactions state) | Request.Unlock_transactions -> return (unlock_transactions state) @@ -741,6 +736,7 @@ module Handlers = struct tx_timeout_limit; tx_pool_addr_limit; tx_pool_tx_per_addr_limit; + chain_family; } : Types.parameters) = let state = @@ -755,6 +751,7 @@ module Handlers = struct tx_pool_addr_limit; tx_pool_tx_per_addr_limit; locked = false; + chain_family; } in Lwt_result_syntax.return state @@ -830,12 +827,12 @@ let nonce pkey = in Pool.next_nonce pkey current_nonce pool -let pop_transactions ~chain_family ~maximum_cumulative_size = +let pop_transactions ~maximum_cumulative_size = let open Lwt_result_syntax in let*? worker = Lazy.force worker in Worker.Queue.push_request_and_wait worker - (Request.Pop_transactions (chain_family, maximum_cumulative_size)) + (Request.Pop_transactions maximum_cumulative_size) |> handle_request_error let pop_and_inject_transactions () = @@ -868,12 +865,6 @@ let pop_and_inject_transactions_lazy () = in return_unit -let is_locked () = - let open Lwt_result_syntax in - let*? worker = Lazy.force worker in - Worker.Queue.push_request_and_wait worker Request.Is_locked - |> handle_request_error - let size_info () = let open Lwt_result_syntax in let*? worker = Lazy.force worker in @@ -977,4 +968,17 @@ module Tx_container = struct let*? worker = Lazy.force worker in Worker.Queue.push_request_and_wait worker Request.Unlock_transactions |> handle_request_error + + let is_locked () = + let open Lwt_result_syntax in + let*? worker = Lazy.force worker in + Worker.Queue.push_request_and_wait worker Request.Is_locked + |> handle_request_error + + let confirm_transactions ~clear_pending_queue_after:_ ~confirmed_txs:_ = + clear_popped_transactions () + + let pop_transactions ~maximum_cumulative_size ~validate_tx:_ + ~initial_validation_state:_ = + pop_transactions ~maximum_cumulative_size end diff --git a/etherlink/bin_node/lib_dev/tx_pool.mli b/etherlink/bin_node/lib_dev/tx_pool.mli index 47fe10f33c4fdc94f4b0dc22ed87477048e959c1..9f02a6c96f4e03871cec81d474df90d4522b6d6c 100644 --- a/etherlink/bin_node/lib_dev/tx_pool.mli +++ b/etherlink/bin_node/lib_dev/tx_pool.mli @@ -20,6 +20,7 @@ type parameters = { 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. *) + chain_family : L2_types.chain_family; } (** [start parameters] starts the tx-pool *) @@ -30,7 +31,6 @@ val start : parameters -> unit tzresult Lwt.t size exceeds `maximum_cumulative_size`. If the pool is locked or node in tezlink mode, returns no transactions. *) val pop_transactions : - chain_family:L2_types.chain_family -> maximum_cumulative_size:int -> (string * Ethereum_types.legacy_transaction_object) list tzresult Lwt.t @@ -44,9 +44,6 @@ val pop_and_inject_transactions : unit -> unit tzresult Lwt.t complete *) val pop_and_inject_transactions_lazy : unit -> unit tzresult Lwt.t -(** [is_locked] checks if the pools is locked. *) -val is_locked : unit -> bool tzresult Lwt.t - val size_info : unit -> Metrics.Tx_pool.size_info tzresult Lwt.t val clear_popped_transactions : unit -> unit tzresult Lwt.t diff --git a/etherlink/bin_node/lib_dev/tx_queue.ml b/etherlink/bin_node/lib_dev/tx_queue.ml index 652151590600aa1f2aee14aa11e79b06dd723c94..05c8d3643f8ac0d865f9eae326474fd422c3da59 100644 --- a/etherlink/bin_node/lib_dev/tx_queue.ml +++ b/etherlink/bin_node/lib_dev/tx_queue.ml @@ -1033,27 +1033,6 @@ let start ~config ~keep_alive () = let*! () = Tx_queue_events.is_ready () in return_unit -let is_locked () = - let open Lwt_result_syntax in - let*? worker = Lazy.force worker in - Worker.Queue.push_request_and_wait worker Is_locked |> handle_request_error - -let pop_transactions ~validate_tx ~initial_validation_state = - let open Lwt_result_syntax in - let*? w = Lazy.force worker in - Worker.Queue.push_request_and_wait - w - (Pop_transactions {validate_tx; validation_state = initial_validation_state}) - |> handle_request_error - -let confirm_transactions ~clear_pending_queue_after ~confirmed_txs = - let open Lwt_result_syntax in - let*? w = Lazy.force worker in - Worker.Queue.push_request_and_wait - w - (Confirm_transactions {confirmed_txs; clear_pending_queue_after}) - |> handle_request_error - module Internal_for_tests = struct module Nonce_bitset = Nonce_bitset module Address_nonce = Address_nonce @@ -1126,9 +1105,32 @@ module Tx_container = struct in loop () + let confirm_transactions ~clear_pending_queue_after ~confirmed_txs = + let open Lwt_result_syntax in + let*? w = Lazy.force worker in + Worker.Queue.push_request_and_wait + w + (Confirm_transactions {confirmed_txs; clear_pending_queue_after}) + |> handle_request_error + let lock_transactions () = bind_worker @@ fun w -> push_request w Lock_transactions let unlock_transactions () = bind_worker @@ fun w -> push_request w Unlock_transactions + + let is_locked () = + let open Lwt_result_syntax in + let*? worker = Lazy.force worker in + Worker.Queue.push_request_and_wait worker Is_locked |> handle_request_error + + let pop_transactions ~maximum_cumulative_size:_ ~validate_tx + ~initial_validation_state = + let open Lwt_result_syntax in + let*? w = Lazy.force worker in + Worker.Queue.push_request_and_wait + w + (Pop_transactions + {validate_tx; validation_state = initial_validation_state}) + |> handle_request_error end diff --git a/etherlink/bin_node/lib_dev/tx_queue.mli b/etherlink/bin_node/lib_dev/tx_queue.mli index c3d38e3600050b3fd5762cba8c0ae77be1d84b0f..2d419faf96f645d300674fba39ea4b656d50a6e6 100644 --- a/etherlink/bin_node/lib_dev/tx_queue.mli +++ b/etherlink/bin_node/lib_dev/tx_queue.mli @@ -33,36 +33,6 @@ val start : unit -> unit tzresult Lwt.t -(** [is_locked] checks if the queue is locked. *) -val is_locked : unit -> bool tzresult Lwt.t - -(** [pop_transactions ~validate_tx ~initial_validation_state] pops as - many transactions as possible from the queue, validating them with - [validate_tx]. If [validate_tx] returns [`Keep validation_state] - then the evaluated transaction is popped, else if it returns - [`Drop], it's considered invalid and it's callback is called with - [`Refused]. If [validate_tx] returns [`Stop] then the caller has - enough transactions. - - If the tx_queue is locked (c.f. {!lock_transactions} then returns - the empty list. *) -val pop_transactions : - validate_tx: - ('a -> - string -> - Ethereum_types.legacy_transaction_object -> - [`Keep of 'a | `Drop | `Stop] tzresult Lwt.t) -> - initial_validation_state:'a -> - (string * Ethereum_types.legacy_transaction_object) list tzresult Lwt.t - -(** [confirm_transactions ~clear_pending_queue_after ~confirmed_txs] - confirms [confirmed_txs] hash. If [drop_unconfirmed] then any - other pending transactions in the tx_queue are dropped. *) -val confirm_transactions : - clear_pending_queue_after:bool -> - confirmed_txs:Ethereum_types.hash Seq.t -> - unit tzresult Lwt.t - (** wrapper of the Tx_queue to be compatible with the Tx_container signature for the services. *) module Tx_container : Services_backend_sig.Tx_container diff --git a/etherlink/fa-bridge-watchtower/etherlink_monitor.ml b/etherlink/fa-bridge-watchtower/etherlink_monitor.ml index d9cca8fe8812a6cf263fd6e0ab3bbe2c1b3bd0e5..68d8a34cd05346746b84b5ab8977185c0f5c6c40 100644 --- a/etherlink/fa-bridge-watchtower/etherlink_monitor.ml +++ b/etherlink/fa-bridge-watchtower/etherlink_monitor.ml @@ -724,7 +724,7 @@ let handle_confirmed_txs {db; ws_client; _} in let* () = Db.Deposits.set_claimed db nonce exec in let* () = - Tx_queue.confirm_transactions + Tx_queue.Tx_container.confirm_transactions ~clear_pending_queue_after:false ~confirmed_txs:(Seq.cons tx_hash Seq.empty) in