From 3eb0a599b7486ba54bf00054a3316c90935c9446 Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Wed, 18 Jan 2023 15:09:19 +0100 Subject: [PATCH 01/12] lib_delegate: use lwt_result_syntax in block_forge --- .../lib_delegate/block_forge.ml | 335 ++++++++++-------- src/proto_alpha/lib_delegate/block_forge.ml | 335 ++++++++++-------- 2 files changed, 360 insertions(+), 310 deletions(-) diff --git a/src/proto_016_PtMumbai/lib_delegate/block_forge.ml b/src/proto_016_PtMumbai/lib_delegate/block_forge.ml index 062306d6367d..5b71c801341a 100644 --- a/src/proto_016_PtMumbai/lib_delegate/block_forge.ml +++ b/src/proto_016_PtMumbai/lib_delegate/block_forge.ml @@ -68,33 +68,38 @@ let convert_operation (op : packed_operation) : Tezos_base.Operation.t = let finalize_block_header shell_header timestamp validation_result operations_hash predecessor_block_metadata_hash predecessor_ops_metadata_hash predecessor_resulting_context = + let open Lwt_result_syntax in let {Tezos_protocol_environment.context; fitness; message; _} = validation_result in let validation_passes = List.length Main.validation_passes in - (Context_ops.get_test_chain context >>= function - | Not_running -> return context - | Running {expiration; _} -> - if Time.Protocol.(expiration <= timestamp) then - Context_ops.add_test_chain context Not_running >>= fun context -> - return context - else return context - | Forking _ -> assert false) - >>=? fun context -> - (match predecessor_block_metadata_hash with - | Some predecessor_block_metadata_hash -> - Context_ops.add_predecessor_block_metadata_hash - context - predecessor_block_metadata_hash - | None -> Lwt.return context) - >>= fun context -> - (match predecessor_ops_metadata_hash with - | Some predecessor_ops_metadata_hash -> - Context_ops.add_predecessor_ops_metadata_hash - context - predecessor_ops_metadata_hash - | None -> Lwt.return context) - >>= fun context -> + let*! test_chain = Context_ops.get_test_chain context in + let* context = + match test_chain with + | Not_running -> return context + | Running {expiration; _} -> + if Time.Protocol.(expiration <= timestamp) then + let*! context = Context_ops.add_test_chain context Not_running in + return context + else return context + | Forking _ -> assert false + in + let*! context = + match predecessor_block_metadata_hash with + | Some predecessor_block_metadata_hash -> + Context_ops.add_predecessor_block_metadata_hash + context + predecessor_block_metadata_hash + | None -> Lwt.return context + in + let*! context = + match predecessor_ops_metadata_hash with + | Some predecessor_ops_metadata_hash -> + Context_ops.add_predecessor_ops_metadata_hash + context + predecessor_ops_metadata_hash + | None -> Lwt.return context + in let context = Context_ops.hash ~time:timestamp ?message context in (* For the time being, we still fully build the block while we build confidence to fully unplug the baker validation. The resulting @@ -124,6 +129,7 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~timestamp ~liquidity_baking_toggle_vote ~user_activated_upgrades fees_config ~seed_nonce_hash ~payload_round simulation_mode simulation_kind constants = + let open Lwt_result_syntax in let predecessor_block = (pred_info : Baking_state.block_info) in let hard_gas_limit_per_block = constants.Constants.Parametric.hard_gas_limit_per_block @@ -131,7 +137,7 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info let chain = `Hash chain_id in let check_protocol_changed ~(validation_result : Tezos_protocol_environment.validation_result) = - Context_ops.get_protocol validation_result.context >>= fun next_protocol -> + let*! next_protocol = Context_ops.get_protocol validation_result.context in let next_protocol = match Tezos_base.Block_header.get_forced_protocol_upgrade @@ -157,14 +163,15 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~liquidity_baking_toggle_vote () in - Node_rpc.preapply_block - cctxt - ~chain - ~head:predecessor_block.hash - ~timestamp - ~protocol_data:faked_protocol_data - filtered_operations - >>=? fun (shell_header, preapply_result) -> + let* shell_header, preapply_result = + Node_rpc.preapply_block + cctxt + ~chain + ~head:predecessor_block.hash + ~timestamp + ~protocol_data:faked_protocol_data + filtered_operations + in (* only retain valid operations *) let operations = List.map (fun l -> List.map snd l.Preapply_result.applied) preapply_result @@ -189,59 +196,64 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~liquidity_baking_toggle_vote () in - Baking_simulator.begin_construction - ~timestamp - ~protocol_data:faked_protocol_data - context_index - predecessor_block - chain_id - >>=? fun incremental -> - Operation_selection.filter_operations_with_simulation - incremental - fees_config - ~hard_gas_limit_per_block - operation_pool - >>=? fun { - Operation_selection.operations; - validation_result; - operations_hash; - _; - } -> - check_protocol_changed ~validation_result >>=? fun changed -> + let* incremental = + Baking_simulator.begin_construction + ~timestamp + ~protocol_data:faked_protocol_data + context_index + predecessor_block + chain_id + in + + let* {Operation_selection.operations; validation_result; operations_hash; _} + = + Operation_selection.filter_operations_with_simulation + incremental + fees_config + ~hard_gas_limit_per_block + operation_pool + in + let* changed = check_protocol_changed ~validation_result in if changed then (* Fallback to processing via node, which knows both old and new protocol. *) filter_via_node ~operation_pool else - protect - ~on_error:(fun _ -> return_none) - (fun () -> - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - >>=? fun pred_block_metadata_hash -> - return (Some pred_block_metadata_hash)) - >>=? fun pred_block_metadata_hash -> - protect - ~on_error:(fun _ -> return_none) - (fun () -> - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - >>=? fun pred_op_metadata_hash -> return (Some pred_op_metadata_hash)) - >>=? fun pred_op_metadata_hash -> - finalize_block_header - incremental.header - timestamp - validation_result - operations_hash - pred_block_metadata_hash - pred_op_metadata_hash - predecessor_block.resulting_context_hash - >>=? fun shell_header -> + let* pred_block_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_block_metadata_hash = + Shell_services.Blocks.metadata_hash + cctxt + ~block:(`Hash (predecessor_block.hash, 0)) + ~chain + () + in + Some pred_block_metadata_hash) + in + let* pred_op_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_op_metadata_hash = + Shell_services.Blocks.Operation_metadata_hashes.root + cctxt + ~block:(`Hash (predecessor_block.hash, 0)) + ~chain + () + in + Some pred_op_metadata_hash) + in + let* shell_header = + finalize_block_header + incremental.header + timestamp + validation_result + operations_hash + pred_block_metadata_hash + pred_op_metadata_hash + predecessor_block.resulting_context_hash + in let operations = List.map (List.map convert_operation) operations in let payload_hash = let operation_hashes = @@ -265,14 +277,15 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~payload_round () in - Node_rpc.preapply_block - cctxt - ~chain - ~head:predecessor_block.hash - ~timestamp - ~protocol_data:faked_protocol_data - operations - >>=? fun (shell_header, _preapply_result) -> + let* shell_header, _preapply_result = + Node_rpc.preapply_block + cctxt + ~chain + ~head:predecessor_block.hash + ~timestamp + ~protocol_data:faked_protocol_data + operations + in let operations = List.map (List.map convert_operation) operations in return (shell_header, operations, payload_hash) in @@ -285,20 +298,22 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~payload_round () in - Shell_services.Chain.chain_id cctxt ~chain () >>=? fun chain_id -> - Baking_simulator.begin_construction - ~timestamp - ~protocol_data:faked_protocol_data - context_index - predecessor_block - chain_id - >>=? fun incremental -> + let* chain_id = Shell_services.Chain.chain_id cctxt ~chain () in + let* incremental = + Baking_simulator.begin_construction + ~timestamp + ~protocol_data:faked_protocol_data + context_index + predecessor_block + chain_id + in (* We still need to filter endorsements. Two endorsements could be referring to the same slot. *) - Operation_selection.filter_consensus_operations_only - incremental - ordered_pool - >>=? fun (incremental, ordered_pool) -> + let* incremental, ordered_pool = + Operation_selection.filter_consensus_operations_only + incremental + ordered_pool + in let operations = Operation_pool.ordered_to_list_list ordered_pool in let operations_hash = Operation_list_list_hash.compute @@ -312,43 +327,50 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info let incremental = {incremental with header = {incremental.header with operations_hash}} in - Baking_simulator.finalize_construction incremental - >>=? fun (validation_result, _) -> - check_protocol_changed ~validation_result >>=? fun changed -> + let* validation_result, _ = + Baking_simulator.finalize_construction incremental + in + let* changed = check_protocol_changed ~validation_result in if changed then (* Fallback to processing via node, which knows both old and new protocol. *) apply_via_node ~ordered_pool ~payload_hash else - protect - ~on_error:(fun _ -> return_none) - (fun () -> - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - >>=? fun pred_block_metadata_hash -> - return (Some pred_block_metadata_hash)) - >>=? fun pred_block_metadata_hash -> - protect - ~on_error:(fun _ -> return_none) - (fun () -> - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - >>=? fun pred_op_metadata_hash -> return (Some pred_op_metadata_hash)) - >>=? fun pred_op_metadata_hash -> - finalize_block_header - incremental.header - timestamp - validation_result - operations_hash - pred_block_metadata_hash - pred_op_metadata_hash - predecessor_block.resulting_context_hash - >>=? fun shell_header -> + let* pred_block_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_block_metadata_hash = + Shell_services.Blocks.metadata_hash + cctxt + ~block:(`Hash (predecessor_block.hash, 0)) + ~chain + () + in + Some pred_block_metadata_hash) + in + let* pred_op_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_op_metadata_hash = + Shell_services.Blocks.Operation_metadata_hashes.root + cctxt + ~block:(`Hash (predecessor_block.hash, 0)) + ~chain + () + in + Some pred_op_metadata_hash) + in + let* shell_header = + finalize_block_header + incremental.header + timestamp + validation_result + operations_hash + pred_block_metadata_hash + pred_op_metadata_hash + predecessor_block.resulting_context_hash + in let operations = List.map (List.map convert_operation) operations in return (shell_header, operations, payload_hash) in @@ -365,27 +387,30 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info Filter filtered_pool | Apply _ as x -> x in - (match (simulation_mode, simulation_kind) with - | Baking_state.Node, Filter operation_pool -> filter_via_node ~operation_pool - | Node, Apply {ordered_pool; payload_hash} -> - apply_via_node ~ordered_pool ~payload_hash - | Local context_index, Filter operation_pool -> - filter_with_context ~context_index ~operation_pool - | Local context_index, Apply {ordered_pool; payload_hash} -> - apply_with_context ~context_index ~ordered_pool ~payload_hash) - >>=? fun (shell_header, operations, payload_hash) -> - Baking_pow.mine - ~proof_of_work_threshold:constants.proof_of_work_threshold - shell_header - (fun proof_of_work_nonce -> - { - Block_header.payload_hash; - payload_round; - seed_nonce_hash; - proof_of_work_nonce; - liquidity_baking_toggle_vote; - }) - >>=? fun contents -> + let* shell_header, operations, payload_hash = + match (simulation_mode, simulation_kind) with + | Baking_state.Node, Filter operation_pool -> + filter_via_node ~operation_pool + | Node, Apply {ordered_pool; payload_hash} -> + apply_via_node ~ordered_pool ~payload_hash + | Local context_index, Filter operation_pool -> + filter_with_context ~context_index ~operation_pool + | Local context_index, Apply {ordered_pool; payload_hash} -> + apply_with_context ~context_index ~ordered_pool ~payload_hash + in + let* contents = + Baking_pow.mine + ~proof_of_work_threshold:constants.proof_of_work_threshold + shell_header + (fun proof_of_work_nonce -> + { + Block_header.payload_hash; + payload_round; + seed_nonce_hash; + proof_of_work_nonce; + liquidity_baking_toggle_vote; + }) + in let unsigned_block_header = { Block_header.shell = shell_header; diff --git a/src/proto_alpha/lib_delegate/block_forge.ml b/src/proto_alpha/lib_delegate/block_forge.ml index 062306d6367d..5b71c801341a 100644 --- a/src/proto_alpha/lib_delegate/block_forge.ml +++ b/src/proto_alpha/lib_delegate/block_forge.ml @@ -68,33 +68,38 @@ let convert_operation (op : packed_operation) : Tezos_base.Operation.t = let finalize_block_header shell_header timestamp validation_result operations_hash predecessor_block_metadata_hash predecessor_ops_metadata_hash predecessor_resulting_context = + let open Lwt_result_syntax in let {Tezos_protocol_environment.context; fitness; message; _} = validation_result in let validation_passes = List.length Main.validation_passes in - (Context_ops.get_test_chain context >>= function - | Not_running -> return context - | Running {expiration; _} -> - if Time.Protocol.(expiration <= timestamp) then - Context_ops.add_test_chain context Not_running >>= fun context -> - return context - else return context - | Forking _ -> assert false) - >>=? fun context -> - (match predecessor_block_metadata_hash with - | Some predecessor_block_metadata_hash -> - Context_ops.add_predecessor_block_metadata_hash - context - predecessor_block_metadata_hash - | None -> Lwt.return context) - >>= fun context -> - (match predecessor_ops_metadata_hash with - | Some predecessor_ops_metadata_hash -> - Context_ops.add_predecessor_ops_metadata_hash - context - predecessor_ops_metadata_hash - | None -> Lwt.return context) - >>= fun context -> + let*! test_chain = Context_ops.get_test_chain context in + let* context = + match test_chain with + | Not_running -> return context + | Running {expiration; _} -> + if Time.Protocol.(expiration <= timestamp) then + let*! context = Context_ops.add_test_chain context Not_running in + return context + else return context + | Forking _ -> assert false + in + let*! context = + match predecessor_block_metadata_hash with + | Some predecessor_block_metadata_hash -> + Context_ops.add_predecessor_block_metadata_hash + context + predecessor_block_metadata_hash + | None -> Lwt.return context + in + let*! context = + match predecessor_ops_metadata_hash with + | Some predecessor_ops_metadata_hash -> + Context_ops.add_predecessor_ops_metadata_hash + context + predecessor_ops_metadata_hash + | None -> Lwt.return context + in let context = Context_ops.hash ~time:timestamp ?message context in (* For the time being, we still fully build the block while we build confidence to fully unplug the baker validation. The resulting @@ -124,6 +129,7 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~timestamp ~liquidity_baking_toggle_vote ~user_activated_upgrades fees_config ~seed_nonce_hash ~payload_round simulation_mode simulation_kind constants = + let open Lwt_result_syntax in let predecessor_block = (pred_info : Baking_state.block_info) in let hard_gas_limit_per_block = constants.Constants.Parametric.hard_gas_limit_per_block @@ -131,7 +137,7 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info let chain = `Hash chain_id in let check_protocol_changed ~(validation_result : Tezos_protocol_environment.validation_result) = - Context_ops.get_protocol validation_result.context >>= fun next_protocol -> + let*! next_protocol = Context_ops.get_protocol validation_result.context in let next_protocol = match Tezos_base.Block_header.get_forced_protocol_upgrade @@ -157,14 +163,15 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~liquidity_baking_toggle_vote () in - Node_rpc.preapply_block - cctxt - ~chain - ~head:predecessor_block.hash - ~timestamp - ~protocol_data:faked_protocol_data - filtered_operations - >>=? fun (shell_header, preapply_result) -> + let* shell_header, preapply_result = + Node_rpc.preapply_block + cctxt + ~chain + ~head:predecessor_block.hash + ~timestamp + ~protocol_data:faked_protocol_data + filtered_operations + in (* only retain valid operations *) let operations = List.map (fun l -> List.map snd l.Preapply_result.applied) preapply_result @@ -189,59 +196,64 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~liquidity_baking_toggle_vote () in - Baking_simulator.begin_construction - ~timestamp - ~protocol_data:faked_protocol_data - context_index - predecessor_block - chain_id - >>=? fun incremental -> - Operation_selection.filter_operations_with_simulation - incremental - fees_config - ~hard_gas_limit_per_block - operation_pool - >>=? fun { - Operation_selection.operations; - validation_result; - operations_hash; - _; - } -> - check_protocol_changed ~validation_result >>=? fun changed -> + let* incremental = + Baking_simulator.begin_construction + ~timestamp + ~protocol_data:faked_protocol_data + context_index + predecessor_block + chain_id + in + + let* {Operation_selection.operations; validation_result; operations_hash; _} + = + Operation_selection.filter_operations_with_simulation + incremental + fees_config + ~hard_gas_limit_per_block + operation_pool + in + let* changed = check_protocol_changed ~validation_result in if changed then (* Fallback to processing via node, which knows both old and new protocol. *) filter_via_node ~operation_pool else - protect - ~on_error:(fun _ -> return_none) - (fun () -> - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - >>=? fun pred_block_metadata_hash -> - return (Some pred_block_metadata_hash)) - >>=? fun pred_block_metadata_hash -> - protect - ~on_error:(fun _ -> return_none) - (fun () -> - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - >>=? fun pred_op_metadata_hash -> return (Some pred_op_metadata_hash)) - >>=? fun pred_op_metadata_hash -> - finalize_block_header - incremental.header - timestamp - validation_result - operations_hash - pred_block_metadata_hash - pred_op_metadata_hash - predecessor_block.resulting_context_hash - >>=? fun shell_header -> + let* pred_block_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_block_metadata_hash = + Shell_services.Blocks.metadata_hash + cctxt + ~block:(`Hash (predecessor_block.hash, 0)) + ~chain + () + in + Some pred_block_metadata_hash) + in + let* pred_op_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_op_metadata_hash = + Shell_services.Blocks.Operation_metadata_hashes.root + cctxt + ~block:(`Hash (predecessor_block.hash, 0)) + ~chain + () + in + Some pred_op_metadata_hash) + in + let* shell_header = + finalize_block_header + incremental.header + timestamp + validation_result + operations_hash + pred_block_metadata_hash + pred_op_metadata_hash + predecessor_block.resulting_context_hash + in let operations = List.map (List.map convert_operation) operations in let payload_hash = let operation_hashes = @@ -265,14 +277,15 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~payload_round () in - Node_rpc.preapply_block - cctxt - ~chain - ~head:predecessor_block.hash - ~timestamp - ~protocol_data:faked_protocol_data - operations - >>=? fun (shell_header, _preapply_result) -> + let* shell_header, _preapply_result = + Node_rpc.preapply_block + cctxt + ~chain + ~head:predecessor_block.hash + ~timestamp + ~protocol_data:faked_protocol_data + operations + in let operations = List.map (List.map convert_operation) operations in return (shell_header, operations, payload_hash) in @@ -285,20 +298,22 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~payload_round () in - Shell_services.Chain.chain_id cctxt ~chain () >>=? fun chain_id -> - Baking_simulator.begin_construction - ~timestamp - ~protocol_data:faked_protocol_data - context_index - predecessor_block - chain_id - >>=? fun incremental -> + let* chain_id = Shell_services.Chain.chain_id cctxt ~chain () in + let* incremental = + Baking_simulator.begin_construction + ~timestamp + ~protocol_data:faked_protocol_data + context_index + predecessor_block + chain_id + in (* We still need to filter endorsements. Two endorsements could be referring to the same slot. *) - Operation_selection.filter_consensus_operations_only - incremental - ordered_pool - >>=? fun (incremental, ordered_pool) -> + let* incremental, ordered_pool = + Operation_selection.filter_consensus_operations_only + incremental + ordered_pool + in let operations = Operation_pool.ordered_to_list_list ordered_pool in let operations_hash = Operation_list_list_hash.compute @@ -312,43 +327,50 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info let incremental = {incremental with header = {incremental.header with operations_hash}} in - Baking_simulator.finalize_construction incremental - >>=? fun (validation_result, _) -> - check_protocol_changed ~validation_result >>=? fun changed -> + let* validation_result, _ = + Baking_simulator.finalize_construction incremental + in + let* changed = check_protocol_changed ~validation_result in if changed then (* Fallback to processing via node, which knows both old and new protocol. *) apply_via_node ~ordered_pool ~payload_hash else - protect - ~on_error:(fun _ -> return_none) - (fun () -> - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - >>=? fun pred_block_metadata_hash -> - return (Some pred_block_metadata_hash)) - >>=? fun pred_block_metadata_hash -> - protect - ~on_error:(fun _ -> return_none) - (fun () -> - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - >>=? fun pred_op_metadata_hash -> return (Some pred_op_metadata_hash)) - >>=? fun pred_op_metadata_hash -> - finalize_block_header - incremental.header - timestamp - validation_result - operations_hash - pred_block_metadata_hash - pred_op_metadata_hash - predecessor_block.resulting_context_hash - >>=? fun shell_header -> + let* pred_block_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_block_metadata_hash = + Shell_services.Blocks.metadata_hash + cctxt + ~block:(`Hash (predecessor_block.hash, 0)) + ~chain + () + in + Some pred_block_metadata_hash) + in + let* pred_op_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_op_metadata_hash = + Shell_services.Blocks.Operation_metadata_hashes.root + cctxt + ~block:(`Hash (predecessor_block.hash, 0)) + ~chain + () + in + Some pred_op_metadata_hash) + in + let* shell_header = + finalize_block_header + incremental.header + timestamp + validation_result + operations_hash + pred_block_metadata_hash + pred_op_metadata_hash + predecessor_block.resulting_context_hash + in let operations = List.map (List.map convert_operation) operations in return (shell_header, operations, payload_hash) in @@ -365,27 +387,30 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info Filter filtered_pool | Apply _ as x -> x in - (match (simulation_mode, simulation_kind) with - | Baking_state.Node, Filter operation_pool -> filter_via_node ~operation_pool - | Node, Apply {ordered_pool; payload_hash} -> - apply_via_node ~ordered_pool ~payload_hash - | Local context_index, Filter operation_pool -> - filter_with_context ~context_index ~operation_pool - | Local context_index, Apply {ordered_pool; payload_hash} -> - apply_with_context ~context_index ~ordered_pool ~payload_hash) - >>=? fun (shell_header, operations, payload_hash) -> - Baking_pow.mine - ~proof_of_work_threshold:constants.proof_of_work_threshold - shell_header - (fun proof_of_work_nonce -> - { - Block_header.payload_hash; - payload_round; - seed_nonce_hash; - proof_of_work_nonce; - liquidity_baking_toggle_vote; - }) - >>=? fun contents -> + let* shell_header, operations, payload_hash = + match (simulation_mode, simulation_kind) with + | Baking_state.Node, Filter operation_pool -> + filter_via_node ~operation_pool + | Node, Apply {ordered_pool; payload_hash} -> + apply_via_node ~ordered_pool ~payload_hash + | Local context_index, Filter operation_pool -> + filter_with_context ~context_index ~operation_pool + | Local context_index, Apply {ordered_pool; payload_hash} -> + apply_with_context ~context_index ~ordered_pool ~payload_hash + in + let* contents = + Baking_pow.mine + ~proof_of_work_threshold:constants.proof_of_work_threshold + shell_header + (fun proof_of_work_nonce -> + { + Block_header.payload_hash; + payload_round; + seed_nonce_hash; + proof_of_work_nonce; + liquidity_baking_toggle_vote; + }) + in let unsigned_block_header = { Block_header.shell = shell_header; -- GitLab From f1c7df5a2fe6c5daedbc9ef230f8ba594b6446c6 Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Wed, 18 Jan 2023 14:44:42 +0100 Subject: [PATCH 02/12] lib_delegate: move check_protocol_changed outside forge function --- .../lib_delegate/block_forge.ml | 50 ++++++++++++------- src/proto_alpha/lib_delegate/block_forge.ml | 50 ++++++++++++------- 2 files changed, 64 insertions(+), 36 deletions(-) diff --git a/src/proto_016_PtMumbai/lib_delegate/block_forge.ml b/src/proto_016_PtMumbai/lib_delegate/block_forge.ml index 5b71c801341a..0b5bd9db7649 100644 --- a/src/proto_016_PtMumbai/lib_delegate/block_forge.ml +++ b/src/proto_016_PtMumbai/lib_delegate/block_forge.ml @@ -40,6 +40,11 @@ type simulation_kind = type simulation_mode = Local of Context.index | Node +(* [forge_faked_protocol_data ?payload_hash ~payload_round ~seed_nonce_hash + ~liquidity_baking_toggle_vote] forges a fake [block_header_data] with + [payload_hash] ([zero] by default), [payload_round], [seed_nonce_hash], + [liquidity_baking_toggle_vote] and with an empty [proof_of_work_nonce] and a + dummy [signature]. *) let forge_faked_protocol_data ?(payload_hash = Block_payload_hash.zero) ~payload_round ~seed_nonce_hash ~liquidity_baking_toggle_vote () = Block_header. @@ -64,7 +69,6 @@ let convert_operation (op : packed_operation) : Tezos_base.Operation.t = op.protocol_data; } -(* Build the block header : mimics node prevalidation *) let finalize_block_header shell_header timestamp validation_result operations_hash predecessor_block_metadata_hash predecessor_ops_metadata_hash predecessor_resulting_context = @@ -125,6 +129,21 @@ let retain_live_operations_only ~live_blocks operation_pool = Block_hash.Set.mem shell.branch live_blocks) operation_pool +let check_protocol_changed ~user_activated_upgrades ~level + ~(validation_result : Tezos_protocol_environment.validation_result) = + let open Lwt_result_syntax in + let*! next_protocol = Context_ops.get_protocol validation_result.context in + let next_protocol = + match + Tezos_base.Block_header.get_forced_protocol_upgrade + ~user_activated_upgrades + ~level + with + | None -> next_protocol + | Some hash -> hash + in + return Protocol_hash.(Protocol.hash <> next_protocol) + let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~timestamp ~liquidity_baking_toggle_vote ~user_activated_upgrades fees_config ~seed_nonce_hash ~payload_round simulation_mode simulation_kind @@ -135,20 +154,6 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info constants.Constants.Parametric.hard_gas_limit_per_block in let chain = `Hash chain_id in - let check_protocol_changed - ~(validation_result : Tezos_protocol_environment.validation_result) = - let*! next_protocol = Context_ops.get_protocol validation_result.context in - let next_protocol = - match - Tezos_base.Block_header.get_forced_protocol_upgrade - ~user_activated_upgrades - ~level:(Int32.succ predecessor_block.shell.level) - with - | None -> next_protocol - | Some hash -> hash - in - return Protocol_hash.(Protocol.hash <> next_protocol) - in let filter_via_node ~operation_pool = let filtered_operations = Operation_selection.filter_operations_without_simulation @@ -204,7 +209,6 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info predecessor_block chain_id in - let* {Operation_selection.operations; validation_result; operations_hash; _} = Operation_selection.filter_operations_with_simulation @@ -213,7 +217,12 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~hard_gas_limit_per_block operation_pool in - let* changed = check_protocol_changed ~validation_result in + let* changed = + check_protocol_changed + ~level:(Int32.succ predecessor_block.shell.level) + ~user_activated_upgrades + ~validation_result + in if changed then (* Fallback to processing via node, which knows both old and new protocol. *) filter_via_node ~operation_pool @@ -330,7 +339,12 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info let* validation_result, _ = Baking_simulator.finalize_construction incremental in - let* changed = check_protocol_changed ~validation_result in + let* changed = + check_protocol_changed + ~level:(Int32.succ predecessor_block.shell.level) + ~user_activated_upgrades + ~validation_result + in if changed then (* Fallback to processing via node, which knows both old and new protocol. *) apply_via_node ~ordered_pool ~payload_hash diff --git a/src/proto_alpha/lib_delegate/block_forge.ml b/src/proto_alpha/lib_delegate/block_forge.ml index 5b71c801341a..0b5bd9db7649 100644 --- a/src/proto_alpha/lib_delegate/block_forge.ml +++ b/src/proto_alpha/lib_delegate/block_forge.ml @@ -40,6 +40,11 @@ type simulation_kind = type simulation_mode = Local of Context.index | Node +(* [forge_faked_protocol_data ?payload_hash ~payload_round ~seed_nonce_hash + ~liquidity_baking_toggle_vote] forges a fake [block_header_data] with + [payload_hash] ([zero] by default), [payload_round], [seed_nonce_hash], + [liquidity_baking_toggle_vote] and with an empty [proof_of_work_nonce] and a + dummy [signature]. *) let forge_faked_protocol_data ?(payload_hash = Block_payload_hash.zero) ~payload_round ~seed_nonce_hash ~liquidity_baking_toggle_vote () = Block_header. @@ -64,7 +69,6 @@ let convert_operation (op : packed_operation) : Tezos_base.Operation.t = op.protocol_data; } -(* Build the block header : mimics node prevalidation *) let finalize_block_header shell_header timestamp validation_result operations_hash predecessor_block_metadata_hash predecessor_ops_metadata_hash predecessor_resulting_context = @@ -125,6 +129,21 @@ let retain_live_operations_only ~live_blocks operation_pool = Block_hash.Set.mem shell.branch live_blocks) operation_pool +let check_protocol_changed ~user_activated_upgrades ~level + ~(validation_result : Tezos_protocol_environment.validation_result) = + let open Lwt_result_syntax in + let*! next_protocol = Context_ops.get_protocol validation_result.context in + let next_protocol = + match + Tezos_base.Block_header.get_forced_protocol_upgrade + ~user_activated_upgrades + ~level + with + | None -> next_protocol + | Some hash -> hash + in + return Protocol_hash.(Protocol.hash <> next_protocol) + let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~timestamp ~liquidity_baking_toggle_vote ~user_activated_upgrades fees_config ~seed_nonce_hash ~payload_round simulation_mode simulation_kind @@ -135,20 +154,6 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info constants.Constants.Parametric.hard_gas_limit_per_block in let chain = `Hash chain_id in - let check_protocol_changed - ~(validation_result : Tezos_protocol_environment.validation_result) = - let*! next_protocol = Context_ops.get_protocol validation_result.context in - let next_protocol = - match - Tezos_base.Block_header.get_forced_protocol_upgrade - ~user_activated_upgrades - ~level:(Int32.succ predecessor_block.shell.level) - with - | None -> next_protocol - | Some hash -> hash - in - return Protocol_hash.(Protocol.hash <> next_protocol) - in let filter_via_node ~operation_pool = let filtered_operations = Operation_selection.filter_operations_without_simulation @@ -204,7 +209,6 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info predecessor_block chain_id in - let* {Operation_selection.operations; validation_result; operations_hash; _} = Operation_selection.filter_operations_with_simulation @@ -213,7 +217,12 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info ~hard_gas_limit_per_block operation_pool in - let* changed = check_protocol_changed ~validation_result in + let* changed = + check_protocol_changed + ~level:(Int32.succ predecessor_block.shell.level) + ~user_activated_upgrades + ~validation_result + in if changed then (* Fallback to processing via node, which knows both old and new protocol. *) filter_via_node ~operation_pool @@ -330,7 +339,12 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info let* validation_result, _ = Baking_simulator.finalize_construction incremental in - let* changed = check_protocol_changed ~validation_result in + let* changed = + check_protocol_changed + ~level:(Int32.succ predecessor_block.shell.level) + ~user_activated_upgrades + ~validation_result + in if changed then (* Fallback to processing via node, which knows both old and new protocol. *) apply_via_node ~ordered_pool ~payload_hash -- GitLab From 083e1fb22c6ca2e0cff37a6127b3603278be7397 Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Wed, 18 Jan 2023 17:07:47 +0100 Subject: [PATCH 03/12] lib_delegate: split block_forge.forge --- .../lib_delegate/block_forge.ml | 513 ++++++++++-------- src/proto_alpha/lib_delegate/block_forge.ml | 513 ++++++++++-------- 2 files changed, 578 insertions(+), 448 deletions(-) diff --git a/src/proto_016_PtMumbai/lib_delegate/block_forge.ml b/src/proto_016_PtMumbai/lib_delegate/block_forge.ml index 0b5bd9db7649..36d743ba2a65 100644 --- a/src/proto_016_PtMumbai/lib_delegate/block_forge.ml +++ b/src/proto_016_PtMumbai/lib_delegate/block_forge.ml @@ -144,43 +144,119 @@ let check_protocol_changed ~user_activated_upgrades ~level in return Protocol_hash.(Protocol.hash <> next_protocol) -let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info - ~timestamp ~liquidity_baking_toggle_vote ~user_activated_upgrades - fees_config ~seed_nonce_hash ~payload_round simulation_mode simulation_kind - constants = +let filter_via_node ~chain_id ~fees_config ~hard_gas_limit_per_block + ~faked_protocol_data ~timestamp ~(pred_info : Baking_state.block_info) + ~payload_round ~operation_pool cctxt = let open Lwt_result_syntax in - let predecessor_block = (pred_info : Baking_state.block_info) in - let hard_gas_limit_per_block = - constants.Constants.Parametric.hard_gas_limit_per_block - in let chain = `Hash chain_id in - let filter_via_node ~operation_pool = - let filtered_operations = - Operation_selection.filter_operations_without_simulation - fees_config - ~hard_gas_limit_per_block - operation_pool + let filtered_operations = + Operation_selection.filter_operations_without_simulation + fees_config + ~hard_gas_limit_per_block + operation_pool + in + let* shell_header, preapply_result = + Node_rpc.preapply_block + cctxt + ~chain + ~head:pred_info.hash + ~timestamp + ~protocol_data:faked_protocol_data + filtered_operations + in + (* only retain valid operations *) + let operations = + List.map (fun l -> List.map snd l.Preapply_result.applied) preapply_result + in + let payload_hash = + let operation_hashes = + Stdlib.List.tl operations |> List.flatten + |> List.map Tezos_base.Operation.hash in - let faked_protocol_data = - forge_faked_protocol_data - ~payload_round - ~seed_nonce_hash - ~liquidity_baking_toggle_vote - () + Block_payload.hash + ~predecessor_hash:shell_header.predecessor + ~payload_round + operation_hashes + in + return (shell_header, operations, payload_hash) + +let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block + ~faked_protocol_data ~user_activated_upgrades ~timestamp + ~(pred_info : Baking_state.block_info) ~context_index ~payload_round + ~operation_pool cctxt = + let open Lwt_result_syntax in + let chain = `Hash chain_id in + let* incremental = + Baking_simulator.begin_construction + ~timestamp + ~protocol_data:faked_protocol_data + context_index + pred_info + chain_id + in + let* {Operation_selection.operations; validation_result; operations_hash; _} = + Operation_selection.filter_operations_with_simulation + incremental + fees_config + ~hard_gas_limit_per_block + operation_pool + in + let* changed = + check_protocol_changed + ~level:(Int32.succ pred_info.shell.level) + ~user_activated_upgrades + ~validation_result + in + if changed then + (* Fallback to processing via node, which knows both old and new protocol. *) + filter_via_node + ~chain_id + ~fees_config + ~hard_gas_limit_per_block + ~faked_protocol_data + ~timestamp + ~pred_info + ~payload_round + ~operation_pool + cctxt + else + let* pred_block_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_block_metadata_hash = + Shell_services.Blocks.metadata_hash + cctxt + ~block:(`Hash (pred_info.hash, 0)) + ~chain + () + in + Some pred_block_metadata_hash) in - let* shell_header, preapply_result = - Node_rpc.preapply_block - cctxt - ~chain - ~head:predecessor_block.hash - ~timestamp - ~protocol_data:faked_protocol_data - filtered_operations + let* pred_op_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_op_metadata_hash = + Shell_services.Blocks.Operation_metadata_hashes.root + cctxt + ~block:(`Hash (pred_info.hash, 0)) + ~chain + () + in + Some pred_op_metadata_hash) in - (* only retain valid operations *) - let operations = - List.map (fun l -> List.map snd l.Preapply_result.applied) preapply_result + let* shell_header = + finalize_block_header + incremental.header + timestamp + validation_result + operations_hash + pred_block_metadata_hash + pred_op_metadata_hash + pred_info.resulting_context_hash in + let operations = List.map (List.map convert_operation) operations in let payload_hash = let operation_hashes = Stdlib.List.tl operations |> List.flatten @@ -192,201 +268,124 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info operation_hashes in return (shell_header, operations, payload_hash) + +let apply_via_node ~chain_id ~faked_protocol_data ~timestamp + ~(pred_info : Baking_state.block_info) ~ordered_pool ~payload_hash cctxt = + let open Lwt_result_syntax in + let chain = `Hash chain_id in + let operations = Operation_pool.ordered_to_list_list ordered_pool in + let* shell_header, _preapply_result = + Node_rpc.preapply_block + cctxt + ~chain + ~head:pred_info.hash + ~timestamp + ~protocol_data:faked_protocol_data + operations in - let filter_with_context ~context_index ~operation_pool = - let faked_protocol_data = - forge_faked_protocol_data - ~payload_round - ~seed_nonce_hash - ~liquidity_baking_toggle_vote - () - in - let* incremental = - Baking_simulator.begin_construction - ~timestamp - ~protocol_data:faked_protocol_data - context_index - predecessor_block - chain_id - in - let* {Operation_selection.operations; validation_result; operations_hash; _} - = - Operation_selection.filter_operations_with_simulation - incremental - fees_config - ~hard_gas_limit_per_block - operation_pool - in - let* changed = - check_protocol_changed - ~level:(Int32.succ predecessor_block.shell.level) - ~user_activated_upgrades - ~validation_result - in - if changed then - (* Fallback to processing via node, which knows both old and new protocol. *) - filter_via_node ~operation_pool - else - let* pred_block_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_block_metadata_hash = - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - in - Some pred_block_metadata_hash) - in - let* pred_op_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_op_metadata_hash = - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - in - Some pred_op_metadata_hash) - in - let* shell_header = - finalize_block_header - incremental.header - timestamp - validation_result - operations_hash - pred_block_metadata_hash - pred_op_metadata_hash - predecessor_block.resulting_context_hash - in - let operations = List.map (List.map convert_operation) operations in - let payload_hash = - let operation_hashes = - Stdlib.List.tl operations |> List.flatten - |> List.map Tezos_base.Operation.hash - in - Block_payload.hash - ~predecessor_hash:shell_header.predecessor - ~payload_round - operation_hashes - in - return (shell_header, operations, payload_hash) + let operations = List.map (List.map convert_operation) operations in + return (shell_header, operations, payload_hash) + +let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades + ~timestamp ~(pred_info : Baking_state.block_info) ~ordered_pool + ~context_index ~payload_hash cctxt = + let open Lwt_result_syntax in + let chain = `Hash chain_id in + let* incremental = + Baking_simulator.begin_construction + ~timestamp + ~protocol_data:faked_protocol_data + context_index + pred_info + chain_id in - let apply_via_node ~ordered_pool ~payload_hash = - let operations = Operation_pool.ordered_to_list_list ordered_pool in - let faked_protocol_data = - forge_faked_protocol_data - ~seed_nonce_hash - ~liquidity_baking_toggle_vote - ~payload_hash - ~payload_round - () - in - let* shell_header, _preapply_result = - Node_rpc.preapply_block - cctxt - ~chain - ~head:predecessor_block.hash - ~timestamp - ~protocol_data:faked_protocol_data - operations - in - let operations = List.map (List.map convert_operation) operations in - return (shell_header, operations, payload_hash) + (* We still need to filter endorsements. Two endorsements could be + referring to the same slot. *) + let* incremental, ordered_pool = + Operation_selection.filter_consensus_operations_only + incremental + ordered_pool in - let apply_with_context ~context_index ~ordered_pool ~payload_hash = - let faked_protocol_data = - forge_faked_protocol_data - ~seed_nonce_hash - ~liquidity_baking_toggle_vote - ~payload_hash - ~payload_round - () - in - let* chain_id = Shell_services.Chain.chain_id cctxt ~chain () in - let* incremental = - Baking_simulator.begin_construction - ~timestamp - ~protocol_data:faked_protocol_data - context_index - predecessor_block - chain_id - in - (* We still need to filter endorsements. Two endorsements could be - referring to the same slot. *) - let* incremental, ordered_pool = - Operation_selection.filter_consensus_operations_only - incremental - ordered_pool - in - let operations = Operation_pool.ordered_to_list_list ordered_pool in - let operations_hash = - Operation_list_list_hash.compute - (List.map - (fun sl -> - Operation_list_hash.compute (List.map Operation.hash_packed sl)) - operations) - in - (* We need to compute the final [operations_hash] before - finalizing the block because it will be used in the cache's nonce. *) - let incremental = - {incremental with header = {incremental.header with operations_hash}} + let operations = Operation_pool.ordered_to_list_list ordered_pool in + let operations_hash = + Operation_list_list_hash.compute + (List.map + (fun sl -> + Operation_list_hash.compute (List.map Operation.hash_packed sl)) + operations) + in + (* We need to compute the final [operations_hash] before + finalizing the block because it will be used in the cache's nonce. *) + let incremental = + {incremental with header = {incremental.header with operations_hash}} + in + let* validation_result, _ = + Baking_simulator.finalize_construction incremental + in + let* changed = + check_protocol_changed + ~level:(Int32.succ pred_info.shell.level) + ~user_activated_upgrades + ~validation_result + in + if changed then + (* Fallback to processing via node, which knows both old and new protocol. *) + apply_via_node + ~chain_id + ~faked_protocol_data + ~timestamp + ~pred_info + ~ordered_pool + ~payload_hash + cctxt + else + let* pred_block_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_block_metadata_hash = + Shell_services.Blocks.metadata_hash + cctxt + ~block:(`Hash (pred_info.hash, 0)) + ~chain + () + in + Some pred_block_metadata_hash) in - let* validation_result, _ = - Baking_simulator.finalize_construction incremental + let* pred_op_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_op_metadata_hash = + Shell_services.Blocks.Operation_metadata_hashes.root + cctxt + ~block:(`Hash (pred_info.hash, 0)) + ~chain + () + in + Some pred_op_metadata_hash) in - let* changed = - check_protocol_changed - ~level:(Int32.succ predecessor_block.shell.level) - ~user_activated_upgrades - ~validation_result + let* shell_header = + finalize_block_header + incremental.header + timestamp + validation_result + operations_hash + pred_block_metadata_hash + pred_op_metadata_hash + pred_info.resulting_context_hash in - if changed then - (* Fallback to processing via node, which knows both old and new protocol. *) - apply_via_node ~ordered_pool ~payload_hash - else - let* pred_block_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_block_metadata_hash = - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - in - Some pred_block_metadata_hash) - in - let* pred_op_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_op_metadata_hash = - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - in - Some pred_op_metadata_hash) - in - let* shell_header = - finalize_block_header - incremental.header - timestamp - validation_result - operations_hash - pred_block_metadata_hash - pred_op_metadata_hash - predecessor_block.resulting_context_hash - in - let operations = List.map (List.map convert_operation) operations in - return (shell_header, operations, payload_hash) + let operations = List.map (List.map convert_operation) operations in + return (shell_header, operations, payload_hash) + +(* [forge] a new [unsigned_block] regarding of [simulation_kind] and [simulation_mode] *) +let forge (cctxt : #Protocol_client_context.full) ~chain_id + ~(pred_info : Baking_state.block_info) ~timestamp + ~liquidity_baking_toggle_vote ~user_activated_upgrades fees_config + ~seed_nonce_hash ~payload_round simulation_mode simulation_kind constants = + let open Lwt_result_syntax in + let hard_gas_limit_per_block = + constants.Constants.Parametric.hard_gas_limit_per_block in let simulation_kind = match simulation_kind with @@ -404,13 +403,79 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info let* shell_header, operations, payload_hash = match (simulation_mode, simulation_kind) with | Baking_state.Node, Filter operation_pool -> - filter_via_node ~operation_pool + let faked_protocol_data = + forge_faked_protocol_data + ~payload_round + ~seed_nonce_hash + ~liquidity_baking_toggle_vote + () + in + filter_via_node + ~chain_id + ~faked_protocol_data + ~fees_config + ~hard_gas_limit_per_block + ~timestamp + ~pred_info + ~payload_round + ~operation_pool + cctxt | Node, Apply {ordered_pool; payload_hash} -> - apply_via_node ~ordered_pool ~payload_hash + let faked_protocol_data = + forge_faked_protocol_data + ~payload_hash + ~payload_round + ~seed_nonce_hash + ~liquidity_baking_toggle_vote + () + in + apply_via_node + ~chain_id + ~faked_protocol_data + ~timestamp + ~pred_info + ~ordered_pool + ~payload_hash + cctxt | Local context_index, Filter operation_pool -> - filter_with_context ~context_index ~operation_pool + let faked_protocol_data = + forge_faked_protocol_data + ~payload_round + ~seed_nonce_hash + ~liquidity_baking_toggle_vote + () + in + filter_with_context + ~chain_id + ~faked_protocol_data + ~fees_config + ~hard_gas_limit_per_block + ~user_activated_upgrades + ~timestamp + ~pred_info + ~context_index + ~payload_round + ~operation_pool + cctxt | Local context_index, Apply {ordered_pool; payload_hash} -> - apply_with_context ~context_index ~ordered_pool ~payload_hash + let faked_protocol_data = + forge_faked_protocol_data + ~payload_hash + ~payload_round + ~seed_nonce_hash + ~liquidity_baking_toggle_vote + () + in + apply_with_context + ~chain_id + ~faked_protocol_data + ~user_activated_upgrades + ~timestamp + ~pred_info + ~ordered_pool + ~context_index + ~payload_hash + cctxt in let* contents = Baking_pow.mine diff --git a/src/proto_alpha/lib_delegate/block_forge.ml b/src/proto_alpha/lib_delegate/block_forge.ml index 0b5bd9db7649..36d743ba2a65 100644 --- a/src/proto_alpha/lib_delegate/block_forge.ml +++ b/src/proto_alpha/lib_delegate/block_forge.ml @@ -144,43 +144,119 @@ let check_protocol_changed ~user_activated_upgrades ~level in return Protocol_hash.(Protocol.hash <> next_protocol) -let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info - ~timestamp ~liquidity_baking_toggle_vote ~user_activated_upgrades - fees_config ~seed_nonce_hash ~payload_round simulation_mode simulation_kind - constants = +let filter_via_node ~chain_id ~fees_config ~hard_gas_limit_per_block + ~faked_protocol_data ~timestamp ~(pred_info : Baking_state.block_info) + ~payload_round ~operation_pool cctxt = let open Lwt_result_syntax in - let predecessor_block = (pred_info : Baking_state.block_info) in - let hard_gas_limit_per_block = - constants.Constants.Parametric.hard_gas_limit_per_block - in let chain = `Hash chain_id in - let filter_via_node ~operation_pool = - let filtered_operations = - Operation_selection.filter_operations_without_simulation - fees_config - ~hard_gas_limit_per_block - operation_pool + let filtered_operations = + Operation_selection.filter_operations_without_simulation + fees_config + ~hard_gas_limit_per_block + operation_pool + in + let* shell_header, preapply_result = + Node_rpc.preapply_block + cctxt + ~chain + ~head:pred_info.hash + ~timestamp + ~protocol_data:faked_protocol_data + filtered_operations + in + (* only retain valid operations *) + let operations = + List.map (fun l -> List.map snd l.Preapply_result.applied) preapply_result + in + let payload_hash = + let operation_hashes = + Stdlib.List.tl operations |> List.flatten + |> List.map Tezos_base.Operation.hash in - let faked_protocol_data = - forge_faked_protocol_data - ~payload_round - ~seed_nonce_hash - ~liquidity_baking_toggle_vote - () + Block_payload.hash + ~predecessor_hash:shell_header.predecessor + ~payload_round + operation_hashes + in + return (shell_header, operations, payload_hash) + +let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block + ~faked_protocol_data ~user_activated_upgrades ~timestamp + ~(pred_info : Baking_state.block_info) ~context_index ~payload_round + ~operation_pool cctxt = + let open Lwt_result_syntax in + let chain = `Hash chain_id in + let* incremental = + Baking_simulator.begin_construction + ~timestamp + ~protocol_data:faked_protocol_data + context_index + pred_info + chain_id + in + let* {Operation_selection.operations; validation_result; operations_hash; _} = + Operation_selection.filter_operations_with_simulation + incremental + fees_config + ~hard_gas_limit_per_block + operation_pool + in + let* changed = + check_protocol_changed + ~level:(Int32.succ pred_info.shell.level) + ~user_activated_upgrades + ~validation_result + in + if changed then + (* Fallback to processing via node, which knows both old and new protocol. *) + filter_via_node + ~chain_id + ~fees_config + ~hard_gas_limit_per_block + ~faked_protocol_data + ~timestamp + ~pred_info + ~payload_round + ~operation_pool + cctxt + else + let* pred_block_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_block_metadata_hash = + Shell_services.Blocks.metadata_hash + cctxt + ~block:(`Hash (pred_info.hash, 0)) + ~chain + () + in + Some pred_block_metadata_hash) in - let* shell_header, preapply_result = - Node_rpc.preapply_block - cctxt - ~chain - ~head:predecessor_block.hash - ~timestamp - ~protocol_data:faked_protocol_data - filtered_operations + let* pred_op_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_op_metadata_hash = + Shell_services.Blocks.Operation_metadata_hashes.root + cctxt + ~block:(`Hash (pred_info.hash, 0)) + ~chain + () + in + Some pred_op_metadata_hash) in - (* only retain valid operations *) - let operations = - List.map (fun l -> List.map snd l.Preapply_result.applied) preapply_result + let* shell_header = + finalize_block_header + incremental.header + timestamp + validation_result + operations_hash + pred_block_metadata_hash + pred_op_metadata_hash + pred_info.resulting_context_hash in + let operations = List.map (List.map convert_operation) operations in let payload_hash = let operation_hashes = Stdlib.List.tl operations |> List.flatten @@ -192,201 +268,124 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info operation_hashes in return (shell_header, operations, payload_hash) + +let apply_via_node ~chain_id ~faked_protocol_data ~timestamp + ~(pred_info : Baking_state.block_info) ~ordered_pool ~payload_hash cctxt = + let open Lwt_result_syntax in + let chain = `Hash chain_id in + let operations = Operation_pool.ordered_to_list_list ordered_pool in + let* shell_header, _preapply_result = + Node_rpc.preapply_block + cctxt + ~chain + ~head:pred_info.hash + ~timestamp + ~protocol_data:faked_protocol_data + operations in - let filter_with_context ~context_index ~operation_pool = - let faked_protocol_data = - forge_faked_protocol_data - ~payload_round - ~seed_nonce_hash - ~liquidity_baking_toggle_vote - () - in - let* incremental = - Baking_simulator.begin_construction - ~timestamp - ~protocol_data:faked_protocol_data - context_index - predecessor_block - chain_id - in - let* {Operation_selection.operations; validation_result; operations_hash; _} - = - Operation_selection.filter_operations_with_simulation - incremental - fees_config - ~hard_gas_limit_per_block - operation_pool - in - let* changed = - check_protocol_changed - ~level:(Int32.succ predecessor_block.shell.level) - ~user_activated_upgrades - ~validation_result - in - if changed then - (* Fallback to processing via node, which knows both old and new protocol. *) - filter_via_node ~operation_pool - else - let* pred_block_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_block_metadata_hash = - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - in - Some pred_block_metadata_hash) - in - let* pred_op_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_op_metadata_hash = - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - in - Some pred_op_metadata_hash) - in - let* shell_header = - finalize_block_header - incremental.header - timestamp - validation_result - operations_hash - pred_block_metadata_hash - pred_op_metadata_hash - predecessor_block.resulting_context_hash - in - let operations = List.map (List.map convert_operation) operations in - let payload_hash = - let operation_hashes = - Stdlib.List.tl operations |> List.flatten - |> List.map Tezos_base.Operation.hash - in - Block_payload.hash - ~predecessor_hash:shell_header.predecessor - ~payload_round - operation_hashes - in - return (shell_header, operations, payload_hash) + let operations = List.map (List.map convert_operation) operations in + return (shell_header, operations, payload_hash) + +let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades + ~timestamp ~(pred_info : Baking_state.block_info) ~ordered_pool + ~context_index ~payload_hash cctxt = + let open Lwt_result_syntax in + let chain = `Hash chain_id in + let* incremental = + Baking_simulator.begin_construction + ~timestamp + ~protocol_data:faked_protocol_data + context_index + pred_info + chain_id in - let apply_via_node ~ordered_pool ~payload_hash = - let operations = Operation_pool.ordered_to_list_list ordered_pool in - let faked_protocol_data = - forge_faked_protocol_data - ~seed_nonce_hash - ~liquidity_baking_toggle_vote - ~payload_hash - ~payload_round - () - in - let* shell_header, _preapply_result = - Node_rpc.preapply_block - cctxt - ~chain - ~head:predecessor_block.hash - ~timestamp - ~protocol_data:faked_protocol_data - operations - in - let operations = List.map (List.map convert_operation) operations in - return (shell_header, operations, payload_hash) + (* We still need to filter endorsements. Two endorsements could be + referring to the same slot. *) + let* incremental, ordered_pool = + Operation_selection.filter_consensus_operations_only + incremental + ordered_pool in - let apply_with_context ~context_index ~ordered_pool ~payload_hash = - let faked_protocol_data = - forge_faked_protocol_data - ~seed_nonce_hash - ~liquidity_baking_toggle_vote - ~payload_hash - ~payload_round - () - in - let* chain_id = Shell_services.Chain.chain_id cctxt ~chain () in - let* incremental = - Baking_simulator.begin_construction - ~timestamp - ~protocol_data:faked_protocol_data - context_index - predecessor_block - chain_id - in - (* We still need to filter endorsements. Two endorsements could be - referring to the same slot. *) - let* incremental, ordered_pool = - Operation_selection.filter_consensus_operations_only - incremental - ordered_pool - in - let operations = Operation_pool.ordered_to_list_list ordered_pool in - let operations_hash = - Operation_list_list_hash.compute - (List.map - (fun sl -> - Operation_list_hash.compute (List.map Operation.hash_packed sl)) - operations) - in - (* We need to compute the final [operations_hash] before - finalizing the block because it will be used in the cache's nonce. *) - let incremental = - {incremental with header = {incremental.header with operations_hash}} + let operations = Operation_pool.ordered_to_list_list ordered_pool in + let operations_hash = + Operation_list_list_hash.compute + (List.map + (fun sl -> + Operation_list_hash.compute (List.map Operation.hash_packed sl)) + operations) + in + (* We need to compute the final [operations_hash] before + finalizing the block because it will be used in the cache's nonce. *) + let incremental = + {incremental with header = {incremental.header with operations_hash}} + in + let* validation_result, _ = + Baking_simulator.finalize_construction incremental + in + let* changed = + check_protocol_changed + ~level:(Int32.succ pred_info.shell.level) + ~user_activated_upgrades + ~validation_result + in + if changed then + (* Fallback to processing via node, which knows both old and new protocol. *) + apply_via_node + ~chain_id + ~faked_protocol_data + ~timestamp + ~pred_info + ~ordered_pool + ~payload_hash + cctxt + else + let* pred_block_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_block_metadata_hash = + Shell_services.Blocks.metadata_hash + cctxt + ~block:(`Hash (pred_info.hash, 0)) + ~chain + () + in + Some pred_block_metadata_hash) in - let* validation_result, _ = - Baking_simulator.finalize_construction incremental + let* pred_op_metadata_hash = + protect + ~on_error:(fun _ -> return_none) + (fun () -> + let+ pred_op_metadata_hash = + Shell_services.Blocks.Operation_metadata_hashes.root + cctxt + ~block:(`Hash (pred_info.hash, 0)) + ~chain + () + in + Some pred_op_metadata_hash) in - let* changed = - check_protocol_changed - ~level:(Int32.succ predecessor_block.shell.level) - ~user_activated_upgrades - ~validation_result + let* shell_header = + finalize_block_header + incremental.header + timestamp + validation_result + operations_hash + pred_block_metadata_hash + pred_op_metadata_hash + pred_info.resulting_context_hash in - if changed then - (* Fallback to processing via node, which knows both old and new protocol. *) - apply_via_node ~ordered_pool ~payload_hash - else - let* pred_block_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_block_metadata_hash = - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - in - Some pred_block_metadata_hash) - in - let* pred_op_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_op_metadata_hash = - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (predecessor_block.hash, 0)) - ~chain - () - in - Some pred_op_metadata_hash) - in - let* shell_header = - finalize_block_header - incremental.header - timestamp - validation_result - operations_hash - pred_block_metadata_hash - pred_op_metadata_hash - predecessor_block.resulting_context_hash - in - let operations = List.map (List.map convert_operation) operations in - return (shell_header, operations, payload_hash) + let operations = List.map (List.map convert_operation) operations in + return (shell_header, operations, payload_hash) + +(* [forge] a new [unsigned_block] regarding of [simulation_kind] and [simulation_mode] *) +let forge (cctxt : #Protocol_client_context.full) ~chain_id + ~(pred_info : Baking_state.block_info) ~timestamp + ~liquidity_baking_toggle_vote ~user_activated_upgrades fees_config + ~seed_nonce_hash ~payload_round simulation_mode simulation_kind constants = + let open Lwt_result_syntax in + let hard_gas_limit_per_block = + constants.Constants.Parametric.hard_gas_limit_per_block in let simulation_kind = match simulation_kind with @@ -404,13 +403,79 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~pred_info let* shell_header, operations, payload_hash = match (simulation_mode, simulation_kind) with | Baking_state.Node, Filter operation_pool -> - filter_via_node ~operation_pool + let faked_protocol_data = + forge_faked_protocol_data + ~payload_round + ~seed_nonce_hash + ~liquidity_baking_toggle_vote + () + in + filter_via_node + ~chain_id + ~faked_protocol_data + ~fees_config + ~hard_gas_limit_per_block + ~timestamp + ~pred_info + ~payload_round + ~operation_pool + cctxt | Node, Apply {ordered_pool; payload_hash} -> - apply_via_node ~ordered_pool ~payload_hash + let faked_protocol_data = + forge_faked_protocol_data + ~payload_hash + ~payload_round + ~seed_nonce_hash + ~liquidity_baking_toggle_vote + () + in + apply_via_node + ~chain_id + ~faked_protocol_data + ~timestamp + ~pred_info + ~ordered_pool + ~payload_hash + cctxt | Local context_index, Filter operation_pool -> - filter_with_context ~context_index ~operation_pool + let faked_protocol_data = + forge_faked_protocol_data + ~payload_round + ~seed_nonce_hash + ~liquidity_baking_toggle_vote + () + in + filter_with_context + ~chain_id + ~faked_protocol_data + ~fees_config + ~hard_gas_limit_per_block + ~user_activated_upgrades + ~timestamp + ~pred_info + ~context_index + ~payload_round + ~operation_pool + cctxt | Local context_index, Apply {ordered_pool; payload_hash} -> - apply_with_context ~context_index ~ordered_pool ~payload_hash + let faked_protocol_data = + forge_faked_protocol_data + ~payload_hash + ~payload_round + ~seed_nonce_hash + ~liquidity_baking_toggle_vote + () + in + apply_with_context + ~chain_id + ~faked_protocol_data + ~user_activated_upgrades + ~timestamp + ~pred_info + ~ordered_pool + ~context_index + ~payload_hash + cctxt in let* contents = Baking_pow.mine -- GitLab From 88c21585ecb1b6dc2770e6f614ceb27d707fffb4 Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Tue, 17 Jan 2023 18:06:40 +0100 Subject: [PATCH 04/12] lib_delegate: add force_apply argument to the baker configuration this argument is use to choose the way operation are handle by the baker. If force_apply is set, the operations are applied after being validated. --- .../lib_delegate/baking_commands.ml | 21 +++- .../lib_delegate/baking_configuration.ml | 96 ++++++++++--------- .../lib_delegate/baking_configuration.mli | 4 + .../lib_delegate/baking_lib.ml | 6 +- .../lib_delegate/baking_lib.mli | 2 + .../lib_delegate/client_daemon.ml | 3 +- .../lib_delegate/client_daemon.mli | 1 + .../lib_delegate/baking_commands.ml | 21 +++- .../lib_delegate/baking_configuration.ml | 35 ++++--- .../lib_delegate/baking_configuration.mli | 4 + src/proto_alpha/lib_delegate/baking_lib.ml | 6 +- src/proto_alpha/lib_delegate/baking_lib.mli | 2 + src/proto_alpha/lib_delegate/client_daemon.ml | 4 +- .../lib_delegate/client_daemon.mli | 1 + 14 files changed, 136 insertions(+), 70 deletions(-) diff --git a/src/proto_016_PtMumbai/lib_delegate/baking_commands.ml b/src/proto_016_PtMumbai/lib_delegate/baking_commands.ml index b827d5b7cadd..33dd83a2bdcc 100644 --- a/src/proto_016_PtMumbai/lib_delegate/baking_commands.ml +++ b/src/proto_016_PtMumbai/lib_delegate/baking_commands.ml @@ -114,6 +114,12 @@ let context_path_arg = 'preapply' RPC." string_parameter +let force_apply_switch_arg = + Tezos_clic.switch + ~long:"force-apply" + ~doc:"Force the baker to not only validate but also apply operations." + () + let endorsement_force_switch_arg = Tezos_clic.switch ~long:"force" @@ -218,11 +224,12 @@ let delegate_commands () : Protocol_client_context.full Tezos_clic.command list command ~group ~desc:"Forge and inject block using the delegates' rights." - (args8 + (args9 minimal_fees_arg minimal_nanotez_per_gas_unit_arg minimal_nanotez_per_byte_arg minimal_timestamp_switch + force_apply_switch_arg force_switch operations_arg context_path_arg @@ -232,6 +239,7 @@ let delegate_commands () : Protocol_client_context.full Tezos_clic.command list minimal_nanotez_per_gas_unit, minimal_nanotez_per_byte, minimal_timestamp, + force_apply, force, extra_operations, context_path, @@ -245,6 +253,7 @@ let delegate_commands () : Protocol_client_context.full Tezos_clic.command list ~minimal_timestamp ~minimal_nanotez_per_byte ~minimal_fees + ~force_apply ~force ~monitor_node_mempool:(not do_not_monitor_node_mempool) ?extra_operations @@ -269,11 +278,12 @@ let delegate_commands () : Protocol_client_context.full Tezos_clic.command list command ~group ~desc:"Send a Tenderbake proposal" - (args7 + (args8 minimal_fees_arg minimal_nanotez_per_gas_unit_arg minimal_nanotez_per_byte_arg minimal_timestamp_switch + force_apply_switch_arg force_switch operations_arg context_path_arg) @@ -282,6 +292,7 @@ let delegate_commands () : Protocol_client_context.full Tezos_clic.command list minimal_nanotez_per_gas_unit, minimal_nanotez_per_byte, minimal_timestamp, + force_apply, force, extra_operations, context_path ) @@ -294,6 +305,7 @@ let delegate_commands () : Protocol_client_context.full Tezos_clic.command list ~minimal_timestamp ~minimal_nanotez_per_byte ~minimal_fees + ~force_apply ~force ?extra_operations ?context_path @@ -326,11 +338,12 @@ let baker_commands () : Protocol_client_context.full Tezos_clic.command list = command ~group ~desc:"Launch the baker daemon." - (args8 + (args9 pidfile_arg minimal_fees_arg minimal_nanotez_per_gas_unit_arg minimal_nanotez_per_byte_arg + force_apply_switch_arg keep_alive_arg liquidity_baking_toggle_vote_arg per_block_vote_file_arg @@ -345,6 +358,7 @@ let baker_commands () : Protocol_client_context.full Tezos_clic.command list = minimal_fees, minimal_nanotez_per_gas_unit, minimal_nanotez_per_byte, + force_apply, keep_alive, liquidity_baking_toggle_vote, per_block_vote_file, @@ -378,6 +392,7 @@ let baker_commands () : Protocol_client_context.full Tezos_clic.command list = ~liquidity_baking_toggle_vote ?per_block_vote_file ?extra_operations + ~force_apply ~chain:cctxt#chain ~context_path ~keep_alive diff --git a/src/proto_016_PtMumbai/lib_delegate/baking_configuration.ml b/src/proto_016_PtMumbai/lib_delegate/baking_configuration.ml index 2b8dca57b0f6..6db8eccb9f3d 100644 --- a/src/proto_016_PtMumbai/lib_delegate/baking_configuration.ml +++ b/src/proto_016_PtMumbai/lib_delegate/baking_configuration.ml @@ -85,6 +85,7 @@ type t = { liquidity_baking_toggle_vote : Protocol.Alpha_context.Liquidity_baking.liquidity_baking_toggle_vote; per_block_vote_file : string option; + force_apply : bool; force : bool; state_recorder : state_recorder_config; extra_operations : Operations_source.t option; @@ -113,6 +114,8 @@ let default_liquidity_baking_toggle_vote = let default_force = false +let default_force_apply = false + let default_state_recorder_config = Filesystem let default_extra_operations = None @@ -127,6 +130,7 @@ let default_config = retries_on_failure = default_retries_on_failure_config; user_activated_upgrades = default_user_activated_upgrades; liquidity_baking_toggle_vote = default_liquidity_baking_toggle_vote; + force_apply = default_force_apply; force = default_force; state_recorder = default_state_recorder_config; extra_operations = default_extra_operations; @@ -141,8 +145,9 @@ let make ?(minimal_fees = default_fees_config.minimal_fees) ?(retries_on_failure = default_retries_on_failure_config) ?(user_activated_upgrades = default_user_activated_upgrades) ?(liquidity_baking_toggle_vote = default_liquidity_baking_toggle_vote) - ?per_block_vote_file ?(force = default_force) - ?(state_recorder = default_state_recorder_config) ?extra_operations () = + ?per_block_vote_file ?(force_apply = default_force_apply) + ?(force = default_force) ?(state_recorder = default_state_recorder_config) + ?extra_operations () = let fees = {minimal_fees; minimal_nanotez_per_gas_unit; minimal_nanotez_per_byte} in @@ -159,6 +164,7 @@ let make ?(minimal_fees = default_fees_config.minimal_fees) user_activated_upgrades; liquidity_baking_toggle_vote; per_block_vote_file; + force_apply; force; state_recorder; extra_operations; @@ -228,6 +234,8 @@ let liquidity_baking_toggle_vote_config_encoding = let force_config_encoding = Data_encoding.bool +let force_apply_config_encoding = Data_encoding.bool + let state_recorder_config_encoding = let open Data_encoding in union @@ -254,37 +262,28 @@ let encoding : t Data_encoding.t = ~title:"Baking configuration" ~description:"Baking configuration" @@ conv - (fun { - fees; - validation; - nonce; - retries_on_failure; - user_activated_upgrades; - liquidity_baking_toggle_vote; - per_block_vote_file; - force; - state_recorder; - extra_operations; - } -> - ( fees, - validation, - nonce, - retries_on_failure, - user_activated_upgrades, - liquidity_baking_toggle_vote, - per_block_vote_file, - force, - state_recorder, - extra_operations )) - (fun ( fees, - validation, - nonce, - retries_on_failure, - user_activated_upgrades, - liquidity_baking_toggle_vote, - per_block_vote_file, - force, - state_recorder, + (fun c -> + ( ( c.fees, + c.validation, + c.nonce, + c.retries_on_failure, + c.user_activated_upgrades, + c.liquidity_baking_toggle_vote, + c.per_block_vote_file, + c.force_apply, + c.force, + c.state_recorder ), + c.extra_operations )) + (fun ( ( fees, + validation, + nonce, + retries_on_failure, + user_activated_upgrades, + liquidity_baking_toggle_vote, + per_block_vote_file, + force_apply, + force, + state_recorder ), extra_operations ) -> { fees; @@ -294,23 +293,28 @@ let encoding : t Data_encoding.t = user_activated_upgrades; liquidity_baking_toggle_vote; per_block_vote_file; + force_apply; force; state_recorder; extra_operations; }) - (obj10 - (req "fees" fees_config_encoding) - (req "validation" validation_config_encoding) - (req "nonce" nonce_config_encoding) - (req "retries_on_failure" retries_on_failure_config_encoding) - (req "user_activated_upgrades" user_activate_upgrades_config_encoding) - (req - "liquidity_baking_toggle_vote" - liquidity_baking_toggle_vote_config_encoding) - (opt "per_block_vote_file" Data_encoding.string) - (req "force" force_config_encoding) - (req "state_recorder" state_recorder_config_encoding) - (opt "extra_operations" Operations_source.encoding)) + (merge_objs + (obj10 + (req "fees" fees_config_encoding) + (req "validation" validation_config_encoding) + (req "nonce" nonce_config_encoding) + (req "retries_on_failure" retries_on_failure_config_encoding) + (req + "user_activated_upgrades" + user_activate_upgrades_config_encoding) + (req + "liquidity_baking_toggle_vote" + liquidity_baking_toggle_vote_config_encoding) + (opt "per_block_vote_file" Data_encoding.string) + (req "force_apply" force_apply_config_encoding) + (req "force" force_config_encoding) + (req "state_recorder" state_recorder_config_encoding)) + (obj1 (opt "extra_operations" Operations_source.encoding))) let pp fmt t = let json = Data_encoding.Json.construct encoding t in diff --git a/src/proto_016_PtMumbai/lib_delegate/baking_configuration.mli b/src/proto_016_PtMumbai/lib_delegate/baking_configuration.mli index a1908d29dd22..2cd4946e14a8 100644 --- a/src/proto_016_PtMumbai/lib_delegate/baking_configuration.mli +++ b/src/proto_016_PtMumbai/lib_delegate/baking_configuration.mli @@ -60,6 +60,7 @@ type t = { liquidity_baking_toggle_vote : Protocol.Alpha_context.Liquidity_baking.liquidity_baking_toggle_vote; per_block_vote_file : string option; + force_apply : bool; force : bool; state_recorder : state_recorder_config; extra_operations : Operations_source.t option; @@ -78,6 +79,8 @@ val default_user_activated_upgrades : (int32 * Protocol_hash.t) list val default_liquidity_baking_toggle_vote : Protocol.Alpha_context.Liquidity_baking.liquidity_baking_toggle_vote +val default_force_apply : bool + val default_force : bool val default_state_recorder_config : state_recorder_config @@ -99,6 +102,7 @@ val make : ?liquidity_baking_toggle_vote: Protocol.Alpha_context.Liquidity_baking.liquidity_baking_toggle_vote -> ?per_block_vote_file:string -> + ?force_apply:bool -> ?force:bool -> ?state_recorder:state_recorder_config -> ?extra_operations:Operations_source.t -> diff --git a/src/proto_016_PtMumbai/lib_delegate/baking_lib.ml b/src/proto_016_PtMumbai/lib_delegate/baking_lib.ml index bb2cb7b3f4ec..5adbda789e44 100644 --- a/src/proto_016_PtMumbai/lib_delegate/baking_lib.ml +++ b/src/proto_016_PtMumbai/lib_delegate/baking_lib.ml @@ -279,7 +279,7 @@ let endorsement_quorum state = - Yes :: repropose block with right payload and preendorsements for current round - No :: repropose fresh block for current round *) let propose (cctxt : Protocol_client_context.full) ?minimal_fees - ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?force + ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?force_apply ?force ?(minimal_timestamp = false) ?extra_operations ?context_path delegates = let open Lwt_result_syntax in let* _block_stream, current_proposal = get_current_proposal cctxt in @@ -289,6 +289,7 @@ let propose (cctxt : Protocol_client_context.full) ?minimal_fees ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?context_path + ?force_apply ?force ?extra_operations () @@ -490,7 +491,7 @@ let baking_minimal_timestamp state = return_unit let bake (cctxt : Protocol_client_context.full) ?minimal_fees - ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?force + ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?force_apply ?force ?(minimal_timestamp = false) ?extra_operations ?(monitor_node_mempool = true) ?context_path delegates = let open Lwt_result_syntax in @@ -500,6 +501,7 @@ let bake (cctxt : Protocol_client_context.full) ?minimal_fees ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?context_path + ?force_apply ?force ?extra_operations () diff --git a/src/proto_016_PtMumbai/lib_delegate/baking_lib.mli b/src/proto_016_PtMumbai/lib_delegate/baking_lib.mli index e37f01ac7bb5..b1de5798925a 100644 --- a/src/proto_016_PtMumbai/lib_delegate/baking_lib.mli +++ b/src/proto_016_PtMumbai/lib_delegate/baking_lib.mli @@ -32,6 +32,7 @@ val bake : ?minimal_fees:Tez.t -> ?minimal_nanotez_per_gas_unit:Q.t -> ?minimal_nanotez_per_byte:Q.t -> + ?force_apply:bool -> ?force:bool -> ?minimal_timestamp:bool -> ?extra_operations:Baking_configuration.Operations_source.t -> @@ -57,6 +58,7 @@ val propose : ?minimal_fees:Tez.t -> ?minimal_nanotez_per_gas_unit:Q.t -> ?minimal_nanotez_per_byte:Q.t -> + ?force_apply:bool -> ?force:bool -> ?minimal_timestamp:bool -> ?extra_operations:Baking_configuration.Operations_source.t -> diff --git a/src/proto_016_PtMumbai/lib_delegate/client_daemon.ml b/src/proto_016_PtMumbai/lib_delegate/client_daemon.ml index afc9f52d6aa7..a76a83271938 100644 --- a/src/proto_016_PtMumbai/lib_delegate/client_daemon.ml +++ b/src/proto_016_PtMumbai/lib_delegate/client_daemon.ml @@ -70,7 +70,7 @@ module Baker = struct let run (cctxt : Protocol_client_context.full) ?minimal_fees ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?liquidity_baking_toggle_vote ?per_block_vote_file ?extra_operations - ~chain ~context_path ~keep_alive delegates = + ?force_apply ~chain ~context_path ~keep_alive delegates = let process () = Config_services.user_activated_upgrades cctxt >>=? fun user_activated_upgrades -> @@ -82,6 +82,7 @@ module Baker = struct ?liquidity_baking_toggle_vote ?per_block_vote_file ?extra_operations + ?force_apply ~context_path ~user_activated_upgrades () diff --git a/src/proto_016_PtMumbai/lib_delegate/client_daemon.mli b/src/proto_016_PtMumbai/lib_delegate/client_daemon.mli index 751db5058857..65119e84040c 100644 --- a/src/proto_016_PtMumbai/lib_delegate/client_daemon.mli +++ b/src/proto_016_PtMumbai/lib_delegate/client_daemon.mli @@ -36,6 +36,7 @@ module Baker : sig Protocol.Alpha_context.Liquidity_baking.liquidity_baking_toggle_vote -> ?per_block_vote_file:string -> ?extra_operations:Baking_configuration.Operations_source.t -> + ?force_apply:bool -> chain:Shell_services.chain -> context_path:string -> keep_alive:bool -> diff --git a/src/proto_alpha/lib_delegate/baking_commands.ml b/src/proto_alpha/lib_delegate/baking_commands.ml index 4e84a87318dd..8484b2191238 100644 --- a/src/proto_alpha/lib_delegate/baking_commands.ml +++ b/src/proto_alpha/lib_delegate/baking_commands.ml @@ -114,6 +114,12 @@ let context_path_arg = 'preapply' RPC." string_parameter +let force_apply_switch_arg = + Tezos_clic.switch + ~long:"force-apply" + ~doc:"Force the baker to not only validate but also apply operations." + () + let endorsement_force_switch_arg = Tezos_clic.switch ~long:"force" @@ -225,11 +231,12 @@ let delegate_commands () : Protocol_client_context.full Tezos_clic.command list command ~group ~desc:"Forge and inject block using the delegates' rights." - (args9 + (args10 minimal_fees_arg minimal_nanotez_per_gas_unit_arg minimal_nanotez_per_byte_arg minimal_timestamp_switch + force_apply_switch_arg force_switch operations_arg context_path_arg @@ -240,6 +247,7 @@ let delegate_commands () : Protocol_client_context.full Tezos_clic.command list minimal_nanotez_per_gas_unit, minimal_nanotez_per_byte, minimal_timestamp, + force_apply, force, extra_operations, context_path, @@ -254,6 +262,7 @@ let delegate_commands () : Protocol_client_context.full Tezos_clic.command list ~minimal_timestamp ~minimal_nanotez_per_byte ~minimal_fees + ~force_apply ~force ~monitor_node_mempool:(not do_not_monitor_node_mempool) ?extra_operations @@ -279,11 +288,12 @@ let delegate_commands () : Protocol_client_context.full Tezos_clic.command list command ~group ~desc:"Send a Tenderbake proposal" - (args7 + (args8 minimal_fees_arg minimal_nanotez_per_gas_unit_arg minimal_nanotez_per_byte_arg minimal_timestamp_switch + force_apply_switch_arg force_switch operations_arg context_path_arg) @@ -292,6 +302,7 @@ let delegate_commands () : Protocol_client_context.full Tezos_clic.command list minimal_nanotez_per_gas_unit, minimal_nanotez_per_byte, minimal_timestamp, + force_apply, force, extra_operations, context_path ) @@ -304,6 +315,7 @@ let delegate_commands () : Protocol_client_context.full Tezos_clic.command list ~minimal_timestamp ~minimal_nanotez_per_byte ~minimal_fees + ~force_apply ~force ?extra_operations ?context_path @@ -336,11 +348,12 @@ let baker_commands () : Protocol_client_context.full Tezos_clic.command list = command ~group ~desc:"Launch the baker daemon." - (args9 + (args10 pidfile_arg minimal_fees_arg minimal_nanotez_per_gas_unit_arg minimal_nanotez_per_byte_arg + force_apply_switch_arg keep_alive_arg liquidity_baking_toggle_vote_arg per_block_vote_file_arg @@ -356,6 +369,7 @@ let baker_commands () : Protocol_client_context.full Tezos_clic.command list = minimal_fees, minimal_nanotez_per_gas_unit, minimal_nanotez_per_byte, + force_apply, keep_alive, liquidity_baking_toggle_vote, per_block_vote_file, @@ -391,6 +405,7 @@ let baker_commands () : Protocol_client_context.full Tezos_clic.command list = ?per_block_vote_file ?extra_operations ?dal_node_endpoint + ~force_apply ~chain:cctxt#chain ~context_path ~keep_alive diff --git a/src/proto_alpha/lib_delegate/baking_configuration.ml b/src/proto_alpha/lib_delegate/baking_configuration.ml index c28284d0eec7..7895474cbf26 100644 --- a/src/proto_alpha/lib_delegate/baking_configuration.ml +++ b/src/proto_alpha/lib_delegate/baking_configuration.ml @@ -85,6 +85,7 @@ type t = { liquidity_baking_toggle_vote : Protocol.Alpha_context.Liquidity_baking.liquidity_baking_toggle_vote; per_block_vote_file : string option; + force_apply : bool; force : bool; state_recorder : state_recorder_config; extra_operations : Operations_source.t option; @@ -114,6 +115,8 @@ let default_liquidity_baking_toggle_vote = let default_force = false +let default_force_apply = false + let default_state_recorder_config = Filesystem let default_extra_operations = None @@ -128,6 +131,7 @@ let default_config = retries_on_failure = default_retries_on_failure_config; user_activated_upgrades = default_user_activated_upgrades; liquidity_baking_toggle_vote = default_liquidity_baking_toggle_vote; + force_apply = default_force_apply; force = default_force; state_recorder = default_state_recorder_config; extra_operations = default_extra_operations; @@ -143,9 +147,9 @@ let make ?(minimal_fees = default_fees_config.minimal_fees) ?(retries_on_failure = default_retries_on_failure_config) ?(user_activated_upgrades = default_user_activated_upgrades) ?(liquidity_baking_toggle_vote = default_liquidity_baking_toggle_vote) - ?per_block_vote_file ?(force = default_force) - ?(state_recorder = default_state_recorder_config) ?extra_operations - ?dal_node_endpoint () = + ?per_block_vote_file ?(force_apply = default_force_apply) + ?(force = default_force) ?(state_recorder = default_state_recorder_config) + ?extra_operations ?dal_node_endpoint () = let fees = {minimal_fees; minimal_nanotez_per_gas_unit; minimal_nanotez_per_byte} in @@ -162,6 +166,7 @@ let make ?(minimal_fees = default_fees_config.minimal_fees) user_activated_upgrades; liquidity_baking_toggle_vote; per_block_vote_file; + force_apply; force; state_recorder; extra_operations; @@ -232,6 +237,8 @@ let liquidity_baking_toggle_vote_config_encoding = let force_config_encoding = Data_encoding.bool +let force_apply_config_encoding = Data_encoding.bool + let state_recorder_config_encoding = let open Data_encoding in union @@ -266,6 +273,7 @@ let encoding : t Data_encoding.t = user_activated_upgrades; liquidity_baking_toggle_vote; per_block_vote_file; + force_apply; force; state_recorder; extra_operations; @@ -278,10 +286,10 @@ let encoding : t Data_encoding.t = user_activated_upgrades, liquidity_baking_toggle_vote, per_block_vote_file, + force_apply, force, - state_recorder, - extra_operations ), - dal_node_endpoint )) + state_recorder ), + (extra_operations, dal_node_endpoint) )) (fun ( ( fees, validation, nonce, @@ -289,10 +297,10 @@ let encoding : t Data_encoding.t = user_activated_upgrades, liquidity_baking_toggle_vote, per_block_vote_file, + force_apply, force, - state_recorder, - extra_operations ), - dal_node_endpoint ) -> + state_recorder ), + (extra_operations, dal_node_endpoint) ) -> { fees; validation; @@ -301,6 +309,7 @@ let encoding : t Data_encoding.t = user_activated_upgrades; liquidity_baking_toggle_vote; per_block_vote_file; + force_apply; force; state_recorder; extra_operations; @@ -319,10 +328,12 @@ let encoding : t Data_encoding.t = "liquidity_baking_toggle_vote" liquidity_baking_toggle_vote_config_encoding) (opt "per_block_vote_file" Data_encoding.string) + (req "force_apply" force_apply_config_encoding) (req "force" force_config_encoding) - (req "state_recorder" state_recorder_config_encoding) - (opt "extra_operations" Operations_source.encoding)) - (obj1 (opt "dal_node_endpoint" Tezos_rpc.Encoding.uri_encoding))) + (req "state_recorder" state_recorder_config_encoding)) + (obj2 + (opt "extra_operations" Operations_source.encoding) + (opt "dal_node_endpoint" Tezos_rpc.Encoding.uri_encoding))) let pp fmt t = let json = Data_encoding.Json.construct encoding t in diff --git a/src/proto_alpha/lib_delegate/baking_configuration.mli b/src/proto_alpha/lib_delegate/baking_configuration.mli index ac5f331b4e8f..10ea2829e21d 100644 --- a/src/proto_alpha/lib_delegate/baking_configuration.mli +++ b/src/proto_alpha/lib_delegate/baking_configuration.mli @@ -60,6 +60,7 @@ type t = { liquidity_baking_toggle_vote : Protocol.Alpha_context.Liquidity_baking.liquidity_baking_toggle_vote; per_block_vote_file : string option; + force_apply : bool; force : bool; state_recorder : state_recorder_config; extra_operations : Operations_source.t option; @@ -79,6 +80,8 @@ val default_user_activated_upgrades : (int32 * Protocol_hash.t) list val default_liquidity_baking_toggle_vote : Protocol.Alpha_context.Liquidity_baking.liquidity_baking_toggle_vote +val default_force_apply : bool + val default_force : bool val default_state_recorder_config : state_recorder_config @@ -100,6 +103,7 @@ val make : ?liquidity_baking_toggle_vote: Protocol.Alpha_context.Liquidity_baking.liquidity_baking_toggle_vote -> ?per_block_vote_file:string -> + ?force_apply:bool -> ?force:bool -> ?state_recorder:state_recorder_config -> ?extra_operations:Operations_source.t -> diff --git a/src/proto_alpha/lib_delegate/baking_lib.ml b/src/proto_alpha/lib_delegate/baking_lib.ml index dbd7128f05b7..c2b68be69490 100644 --- a/src/proto_alpha/lib_delegate/baking_lib.ml +++ b/src/proto_alpha/lib_delegate/baking_lib.ml @@ -279,7 +279,7 @@ let endorsement_quorum state = - Yes :: repropose block with right payload and preendorsements for current round - No :: repropose fresh block for current round *) let propose (cctxt : Protocol_client_context.full) ?minimal_fees - ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?force + ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?force_apply ?force ?(minimal_timestamp = false) ?extra_operations ?context_path delegates = let open Lwt_result_syntax in let* _block_stream, current_proposal = get_current_proposal cctxt in @@ -289,6 +289,7 @@ let propose (cctxt : Protocol_client_context.full) ?minimal_fees ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?context_path + ?force_apply ?force ?extra_operations () @@ -500,7 +501,7 @@ let baking_minimal_timestamp state = return_unit let bake (cctxt : Protocol_client_context.full) ?minimal_fees - ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?force + ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?force_apply ?force ?(minimal_timestamp = false) ?extra_operations ?(monitor_node_mempool = true) ?context_path ?dal_node_endpoint delegates = let open Lwt_result_syntax in @@ -510,6 +511,7 @@ let bake (cctxt : Protocol_client_context.full) ?minimal_fees ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?context_path + ?force_apply ?force ?extra_operations ?dal_node_endpoint diff --git a/src/proto_alpha/lib_delegate/baking_lib.mli b/src/proto_alpha/lib_delegate/baking_lib.mli index b58c2fc9b161..8cfb36ced83d 100644 --- a/src/proto_alpha/lib_delegate/baking_lib.mli +++ b/src/proto_alpha/lib_delegate/baking_lib.mli @@ -32,6 +32,7 @@ val bake : ?minimal_fees:Tez.t -> ?minimal_nanotez_per_gas_unit:Q.t -> ?minimal_nanotez_per_byte:Q.t -> + ?force_apply:bool -> ?force:bool -> ?minimal_timestamp:bool -> ?extra_operations:Baking_configuration.Operations_source.t -> @@ -58,6 +59,7 @@ val propose : ?minimal_fees:Tez.t -> ?minimal_nanotez_per_gas_unit:Q.t -> ?minimal_nanotez_per_byte:Q.t -> + ?force_apply:bool -> ?force:bool -> ?minimal_timestamp:bool -> ?extra_operations:Baking_configuration.Operations_source.t -> diff --git a/src/proto_alpha/lib_delegate/client_daemon.ml b/src/proto_alpha/lib_delegate/client_daemon.ml index 0afbd46b8d4e..e5eec8251438 100644 --- a/src/proto_alpha/lib_delegate/client_daemon.ml +++ b/src/proto_alpha/lib_delegate/client_daemon.ml @@ -70,7 +70,8 @@ module Baker = struct let run (cctxt : Protocol_client_context.full) ?minimal_fees ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?liquidity_baking_toggle_vote ?per_block_vote_file ?extra_operations - ?dal_node_endpoint ~chain ~context_path ~keep_alive delegates = + ?dal_node_endpoint ?force_apply ~chain ~context_path ~keep_alive delegates + = let process () = Config_services.user_activated_upgrades cctxt >>=? fun user_activated_upgrades -> @@ -83,6 +84,7 @@ module Baker = struct ?per_block_vote_file ?extra_operations ?dal_node_endpoint + ?force_apply ~context_path ~user_activated_upgrades () diff --git a/src/proto_alpha/lib_delegate/client_daemon.mli b/src/proto_alpha/lib_delegate/client_daemon.mli index d8a23802d32b..aabc7620886c 100644 --- a/src/proto_alpha/lib_delegate/client_daemon.mli +++ b/src/proto_alpha/lib_delegate/client_daemon.mli @@ -37,6 +37,7 @@ module Baker : sig ?per_block_vote_file:string -> ?extra_operations:Baking_configuration.Operations_source.t -> ?dal_node_endpoint:Uri.t -> + ?force_apply:bool -> chain:Shell_services.chain -> context_path:string -> keep_alive:bool -> -- GitLab From 49cf951ec682df9d013fa807b7264e308ebc4749 Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Tue, 24 Jan 2023 15:19:37 +0100 Subject: [PATCH 05/12] lib_delegate: do not apply operation in the baker if force_apply is not set --- .../lib_delegate/baking_actions.ml | 2 + .../lib_delegate/baking_simulator.ml | 32 +- .../lib_delegate/baking_simulator.mli | 7 +- .../lib_delegate/block_forge.ml | 308 +++++++++++------- .../lib_delegate/block_forge.mli | 10 +- .../lib_delegate/operation_selection.ml | 29 +- .../lib_delegate/operation_selection.mli | 4 +- .../lib_delegate/baking_actions.ml | 2 + .../lib_delegate/baking_simulator.ml | 32 +- .../lib_delegate/baking_simulator.mli | 7 +- src/proto_alpha/lib_delegate/block_forge.ml | 307 ++++++++++------- src/proto_alpha/lib_delegate/block_forge.mli | 10 +- .../lib_delegate/operation_selection.ml | 29 +- .../lib_delegate/operation_selection.mli | 4 +- 14 files changed, 473 insertions(+), 310 deletions(-) diff --git a/src/proto_016_PtMumbai/lib_delegate/baking_actions.ml b/src/proto_016_PtMumbai/lib_delegate/baking_actions.ml index 56f56616c151..e05821d643bc 100644 --- a/src/proto_016_PtMumbai/lib_delegate/baking_actions.ml +++ b/src/proto_016_PtMumbai/lib_delegate/baking_actions.ml @@ -306,10 +306,12 @@ let inject_block ~state_recorder state block_to_bake ~updated_state = ~chain_id ~pred_info:predecessor ~timestamp + ~round ~seed_nonce_hash ~payload_round ~liquidity_baking_toggle_vote ~user_activated_upgrades + ~force_apply:state.global_state.config.force_apply state.global_state.config.fees simulation_mode simulation_kind diff --git a/src/proto_016_PtMumbai/lib_delegate/baking_simulator.ml b/src/proto_016_PtMumbai/lib_delegate/baking_simulator.ml index 5ae61e3f47c9..bfb41a1bb140 100644 --- a/src/proto_016_PtMumbai/lib_delegate/baking_simulator.ml +++ b/src/proto_016_PtMumbai/lib_delegate/baking_simulator.ml @@ -54,7 +54,7 @@ let () = type incremental = { predecessor : Baking_state.block_info; context : Tezos_protocol_environment.Context.t; - state : Protocol.validation_state * Protocol.application_state; + state : Protocol.validation_state * Protocol.application_state option; rev_operations : Operation.packed list; header : Tezos_base.Block_header.shell_header; } @@ -76,7 +76,7 @@ let check_context_consistency (abstract_index : Abstract_context_index.t) | true -> return_unit | false -> fail Invalid_context)) -let begin_construction ~timestamp ~protocol_data +let begin_construction ~timestamp ~protocol_data ~force_apply (abstract_index : Abstract_context_index.t) predecessor chain_id = protect (fun () -> let { @@ -119,12 +119,15 @@ let begin_construction ~timestamp ~protocol_data ~predecessor:pred_shell ~cache:`Lazy >>=? fun validation_state -> - Lifted_protocol.begin_application - context - chain_id - mode - ~predecessor:pred_shell - ~cache:`Lazy + (if force_apply then + Lifted_protocol.begin_application + context + chain_id + mode + ~predecessor:pred_shell + ~cache:`Lazy + >>=? return_some + else return_none) >>=? fun application_state -> let state = (validation_state, application_state) in return {predecessor; context; state; rev_operations = []; header}) @@ -143,7 +146,12 @@ let add_operation st (op : Operation.packed) = Protocol.validate_operation validation_state oph op in let** application_state, receipt = - Protocol.apply_operation application_state oph op + match application_state with + | Some application_state -> + Protocol.apply_operation application_state oph op + >>=? fun (application_state, receipt) -> + return (Some application_state, Some receipt) + | None -> return (None, None) in let state = (validation_state, application_state) in return ({st with state; rev_operations = op :: st.rev_operations}, receipt)) @@ -153,6 +161,10 @@ let finalize_construction inc = let validation_state, application_state = inc.state in let** () = Protocol.finalize_validation validation_state in let** result = - Protocol.finalize_application application_state (Some inc.header) + match application_state with + | Some application_state -> + Protocol.finalize_application application_state (Some inc.header) + >>=? return_some + | None -> return_none in return result) diff --git a/src/proto_016_PtMumbai/lib_delegate/baking_simulator.mli b/src/proto_016_PtMumbai/lib_delegate/baking_simulator.mli index 0d0c7ac9f4d2..b05daf4f73da 100644 --- a/src/proto_016_PtMumbai/lib_delegate/baking_simulator.mli +++ b/src/proto_016_PtMumbai/lib_delegate/baking_simulator.mli @@ -29,7 +29,7 @@ open Alpha_context type incremental = { predecessor : Baking_state.block_info; context : Tezos_protocol_environment.Context.t; - state : validation_state * application_state; + state : validation_state * application_state option; rev_operations : Operation.packed list; header : Tezos_base.Block_header.shell_header; } @@ -44,6 +44,7 @@ val check_context_consistency : val begin_construction : timestamp:Time.Protocol.t -> protocol_data:block_header_data -> + force_apply:bool -> Abstract_context_index.t -> Baking_state.block_info -> Chain_id.t -> @@ -52,10 +53,10 @@ val begin_construction : val add_operation : incremental -> Operation.packed -> - (incremental * operation_receipt) tzresult Lwt.t + (incremental * operation_receipt option) tzresult Lwt.t val finalize_construction : incremental -> - (Tezos_protocol_environment.validation_result * block_header_metadata) + (Tezos_protocol_environment.validation_result * block_header_metadata) option tzresult Lwt.t diff --git a/src/proto_016_PtMumbai/lib_delegate/block_forge.ml b/src/proto_016_PtMumbai/lib_delegate/block_forge.ml index 36d743ba2a65..012a0ed4010f 100644 --- a/src/proto_016_PtMumbai/lib_delegate/block_forge.ml +++ b/src/proto_016_PtMumbai/lib_delegate/block_forge.ml @@ -69,47 +69,93 @@ let convert_operation (op : packed_operation) : Tezos_base.Operation.t = op.protocol_data; } -let finalize_block_header shell_header timestamp validation_result - operations_hash predecessor_block_metadata_hash - predecessor_ops_metadata_hash predecessor_resulting_context = +(* [finalize_block_header ~chain ~shell_header ~timestamp ~validation_result + ~operations_hash ~pred_info ~round ~locked_round cctxt] updates the + [shell_header] that was created with dummy fields at the beginning of the + block construction. It increments the [level] and sets the actual + [operations_hash], [fitness], [validation_passes], and [context] (the + predecessor resulting context hash). + + When the operations from the block have been applied, the [fitness] is simply + retrieved from the [validation_result]. Otherwise, the [fitness] is computed + from the [round] and [locked_round] arguments. *) +let finalize_block_header ~chain ~shell_header ~timestamp ~validation_result + ~operations_hash ~(pred_info : Baking_state.block_info) ~round ~locked_round + cctxt = let open Lwt_result_syntax in - let {Tezos_protocol_environment.context; fitness; message; _} = - validation_result + let* fitness = + match validation_result with + | Some {Tezos_protocol_environment.context; fitness; message; _} -> + let*! test_chain = Context_ops.get_test_chain context in + let* context = + match test_chain with + | Not_running -> return context + | Running {expiration; _} -> + if Time.Protocol.(expiration <= timestamp) then + let*! context = + Context_ops.add_test_chain context Not_running + in + return context + else return context + | Forking _ -> assert false + in + let* context = + protect + ~on_error:(fun _ -> return context) + (fun () -> + let* predecessor_block_metadata_hash = + Shell_services.Blocks.metadata_hash + cctxt + ~block:(`Hash (pred_info.hash, 0)) + ~chain + () + in + Lwt.map + Result.ok + (Context_ops.add_predecessor_block_metadata_hash + context + predecessor_block_metadata_hash)) + in + let* context = + protect + ~on_error:(fun _ -> return context) + (fun () -> + let* predecessor_ops_metadata_hash = + Shell_services.Blocks.Operation_metadata_hashes.root + cctxt + ~block:(`Hash (pred_info.hash, 0)) + ~chain + () + in + Lwt.map + Result.ok + (Context_ops.add_predecessor_ops_metadata_hash + context + predecessor_ops_metadata_hash)) + in + let context = Context_ops.hash ~time:timestamp ?message context in + (* For the time being, we still fully build the block while we build + confidence to fully unplug the baker validation. The resulting + context hash is ignored as it is not necessary to craft a block. + See: https://gitlab.com/tezos/tezos/-/issues/4285 *) + ignore context ; + return fitness + | None -> + let*? level = + Environment.wrap_tzresult @@ Raw_level.of_int32 + @@ Int32.succ shell_header.Tezos_base.Block_header.level + in + let*? fitness = + Environment.wrap_tzresult + @@ Fitness.create + ~level + ~round + ~predecessor_round:pred_info.round + ~locked_round + in + return (Fitness.to_raw fitness) in let validation_passes = List.length Main.validation_passes in - let*! test_chain = Context_ops.get_test_chain context in - let* context = - match test_chain with - | Not_running -> return context - | Running {expiration; _} -> - if Time.Protocol.(expiration <= timestamp) then - let*! context = Context_ops.add_test_chain context Not_running in - return context - else return context - | Forking _ -> assert false - in - let*! context = - match predecessor_block_metadata_hash with - | Some predecessor_block_metadata_hash -> - Context_ops.add_predecessor_block_metadata_hash - context - predecessor_block_metadata_hash - | None -> Lwt.return context - in - let*! context = - match predecessor_ops_metadata_hash with - | Some predecessor_ops_metadata_hash -> - Context_ops.add_predecessor_ops_metadata_hash - context - predecessor_ops_metadata_hash - | None -> Lwt.return context - in - let context = Context_ops.hash ~time:timestamp ?message context in - (* For the time being, we still fully build the block while we build - confidence to fully unplug the baker validation. The resulting - context hash is ignored as it is not necessary to craft a block. - See: https://gitlab.com/tezos/tezos/-/issues/4285 *) - ignore context ; let header = Tezos_base.Block_header. { @@ -118,7 +164,7 @@ let finalize_block_header shell_header timestamp validation_result validation_passes; operations_hash; fitness; - context = predecessor_resulting_context; + context = pred_info.resulting_context_hash; } in return header @@ -129,21 +175,46 @@ let retain_live_operations_only ~live_blocks operation_pool = Block_hash.Set.mem shell.branch live_blocks) operation_pool +(* [check_protocol_changed] checks whether the protocol will change with the current + block. This function returns true if the block is the last of an [adoption] + period. It can also return true if an [user_activated_upgrades] is given. *) let check_protocol_changed ~user_activated_upgrades ~level - ~(validation_result : Tezos_protocol_environment.validation_result) = + ~(validation_result : Tezos_protocol_environment.validation_result option) + ~(incremental : Baking_simulator.incremental) = let open Lwt_result_syntax in - let*! next_protocol = Context_ops.get_protocol validation_result.context in - let next_protocol = - match - Tezos_base.Block_header.get_forced_protocol_upgrade - ~user_activated_upgrades - ~level - with - | None -> next_protocol - | Some hash -> hash - in - return Protocol_hash.(Protocol.hash <> next_protocol) + match + Tezos_base.Block_header.get_forced_protocol_upgrade + ~user_activated_upgrades + ~level + with + | None -> ( + match validation_result with + | None -> ( + let context = Validate.get_initial_ctxt (fst incremental.state) in + let* voting_period = + Lwt.map + Environment.wrap_tzresult + (Voting_period.get_current context) + in + match voting_period.kind with + | Voting_period.Proposal | Exploration | Cooldown | Promotion -> + return false + | Adoption -> + Lwt.map + Environment.wrap_tzresult + (Voting_period.is_last_block context)) + | Some validation_result -> + let*! next_protocol = + Context_ops.get_protocol validation_result.context + in + return Protocol_hash.(Protocol.hash <> next_protocol)) + | Some next_protocol -> return Protocol_hash.(Protocol.hash <> next_protocol) +(* [filter_via_node] filters operations using + {!Operation_selection.filter_operations_without_simulation} and then applies + them in a block via {!Node_rpc.preapply_block}. [filter_via_node] returns a + [shell_header], the list of operations that have been applied in the block + and the [payload_hash] corresponding to these operations. *) let filter_via_node ~chain_id ~fees_config ~hard_gas_limit_per_block ~faked_protocol_data ~timestamp ~(pred_info : Baking_state.block_info) ~payload_round ~operation_pool cctxt = @@ -180,16 +251,23 @@ let filter_via_node ~chain_id ~fees_config ~hard_gas_limit_per_block in return (shell_header, operations, payload_hash) +(* [filter_with_context] filters operations using a local context via + {!Operation_selection.filter_operations_with_simulation} and a fresh state + from {!Baking_simulator.begin_construction}. [finalize_block_header] is then + called and a [shell_header], the list of operations and the corresponding + [payload_hash] are returned. If the block is a transition block, + [filter_via_node] is called to return these values. *) let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block ~faked_protocol_data ~user_activated_upgrades ~timestamp - ~(pred_info : Baking_state.block_info) ~context_index ~payload_round - ~operation_pool cctxt = + ~(pred_info : Baking_state.block_info) ~force_apply ~round ~context_index + ~payload_round ~operation_pool cctxt = let open Lwt_result_syntax in let chain = `Hash chain_id in let* incremental = Baking_simulator.begin_construction ~timestamp ~protocol_data:faked_protocol_data + ~force_apply context_index pred_info chain_id @@ -206,6 +284,7 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block ~level:(Int32.succ pred_info.shell.level) ~user_activated_upgrades ~validation_result + ~incremental in if changed then (* Fallback to processing via node, which knows both old and new protocol. *) @@ -220,41 +299,17 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block ~operation_pool cctxt else - let* pred_block_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_block_metadata_hash = - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (pred_info.hash, 0)) - ~chain - () - in - Some pred_block_metadata_hash) - in - let* pred_op_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_op_metadata_hash = - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (pred_info.hash, 0)) - ~chain - () - in - Some pred_op_metadata_hash) - in let* shell_header = finalize_block_header - incremental.header - timestamp - validation_result - operations_hash - pred_block_metadata_hash - pred_op_metadata_hash - pred_info.resulting_context_hash + ~chain + ~shell_header:incremental.header + ~timestamp + ~validation_result + ~operations_hash + ~pred_info + ~round + ~locked_round:None + cctxt in let operations = List.map (List.map convert_operation) operations in let payload_hash = @@ -269,6 +324,9 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block in return (shell_header, operations, payload_hash) +(* [apply_via_node] applies already filtered and validated operations in a block + via {!Node_rpc.preapply_block}. A [shell_header] is recovered from this call + and returned alongside of the list of operations and the payload_hash. *) let apply_via_node ~chain_id ~faked_protocol_data ~timestamp ~(pred_info : Baking_state.block_info) ~ordered_pool ~payload_hash cctxt = let open Lwt_result_syntax in @@ -286,15 +344,19 @@ let apply_via_node ~chain_id ~faked_protocol_data ~timestamp let operations = List.map (List.map convert_operation) operations in return (shell_header, operations, payload_hash) +(* [apply_with_context] is similar to [filter_with_context] but filters + consensus operations only from an [ordered_pool] via + {!Operation_selection.filter_consensus_operations_only}. *) let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades - ~timestamp ~(pred_info : Baking_state.block_info) ~ordered_pool - ~context_index ~payload_hash cctxt = + ~timestamp ~(pred_info : Baking_state.block_info) ~force_apply ~round + ~ordered_pool ~context_index ~payload_hash cctxt = let open Lwt_result_syntax in let chain = `Hash chain_id in let* incremental = Baking_simulator.begin_construction ~timestamp ~protocol_data:faked_protocol_data + ~force_apply context_index pred_info chain_id @@ -319,14 +381,14 @@ let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades let incremental = {incremental with header = {incremental.header with operations_hash}} in - let* validation_result, _ = - Baking_simulator.finalize_construction incremental - in + let* validation_result = Baking_simulator.finalize_construction incremental in + let validation_result = Option.map fst validation_result in let* changed = check_protocol_changed ~level:(Int32.succ pred_info.shell.level) ~user_activated_upgrades ~validation_result + ~incremental in if changed then (* Fallback to processing via node, which knows both old and new protocol. *) @@ -339,50 +401,40 @@ let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades ~payload_hash cctxt else - let* pred_block_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_block_metadata_hash = - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (pred_info.hash, 0)) - ~chain - () - in - Some pred_block_metadata_hash) - in - let* pred_op_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_op_metadata_hash = - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (pred_info.hash, 0)) - ~chain - () - in - Some pred_op_metadata_hash) + let locked_round_when_no_validation_result = + (* [locked_round] will not be used in [finalize_block_header] if there is + a [validation_result] *) + if Option.is_some validation_result then None + else + List.find_map + (fun {protocol_data = Operation_data protocol_data; _} -> + match protocol_data.contents with + | Single (Preendorsement {round; _}) -> Some round + | _ -> None) + (Option.value (List.hd operations) ~default:[]) in let* shell_header = finalize_block_header - incremental.header - timestamp - validation_result - operations_hash - pred_block_metadata_hash - pred_op_metadata_hash - pred_info.resulting_context_hash + ~chain + ~shell_header:incremental.header + ~timestamp + ~validation_result + ~operations_hash + ~pred_info + ~round + ~locked_round:locked_round_when_no_validation_result + cctxt in let operations = List.map (List.map convert_operation) operations in return (shell_header, operations, payload_hash) -(* [forge] a new [unsigned_block] regarding of [simulation_kind] and [simulation_mode] *) +(* [forge] a new [unsigned_block] in accordance with [simulation_kind] and + [simulation_mode] *) let forge (cctxt : #Protocol_client_context.full) ~chain_id - ~(pred_info : Baking_state.block_info) ~timestamp + ~(pred_info : Baking_state.block_info) ~timestamp ~round ~liquidity_baking_toggle_vote ~user_activated_upgrades fees_config - ~seed_nonce_hash ~payload_round simulation_mode simulation_kind constants = + ~force_apply ~seed_nonce_hash ~payload_round simulation_mode simulation_kind + constants = let open Lwt_result_syntax in let hard_gas_limit_per_block = constants.Constants.Parametric.hard_gas_limit_per_block @@ -453,6 +505,8 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~user_activated_upgrades ~timestamp ~pred_info + ~force_apply + ~round ~context_index ~payload_round ~operation_pool @@ -472,6 +526,8 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~user_activated_upgrades ~timestamp ~pred_info + ~force_apply + ~round ~ordered_pool ~context_index ~payload_hash diff --git a/src/proto_016_PtMumbai/lib_delegate/block_forge.mli b/src/proto_016_PtMumbai/lib_delegate/block_forge.mli index b111e27b417c..77fb619a192f 100644 --- a/src/proto_016_PtMumbai/lib_delegate/block_forge.mli +++ b/src/proto_016_PtMumbai/lib_delegate/block_forge.mli @@ -40,22 +40,16 @@ type simulation_kind = type simulation_mode = Local of Context.index | Node -val forge_faked_protocol_data : - ?payload_hash:Block_payload_hash.t -> - payload_round:Round.t -> - seed_nonce_hash:Nonce_hash.t option -> - liquidity_baking_toggle_vote:Liquidity_baking.liquidity_baking_toggle_vote -> - unit -> - block_header_data - val forge : #Protocol_client_context.full -> chain_id:Chain_id.t -> pred_info:Baking_state.block_info -> timestamp:Time.Protocol.t -> + round:Round.t -> liquidity_baking_toggle_vote:Liquidity_baking.liquidity_baking_toggle_vote -> user_activated_upgrades:User_activated.upgrades -> Baking_configuration.fees_config -> + force_apply:bool -> seed_nonce_hash:Nonce_hash.t option -> payload_round:Round.t -> Baking_state.validation_mode -> diff --git a/src/proto_016_PtMumbai/lib_delegate/operation_selection.ml b/src/proto_016_PtMumbai/lib_delegate/operation_selection.ml index 9a4fbf4d0b92..cc33ddbfca71 100644 --- a/src/proto_016_PtMumbai/lib_delegate/operation_selection.ml +++ b/src/proto_016_PtMumbai/lib_delegate/operation_selection.ml @@ -160,8 +160,8 @@ let prioritize_managers ~hard_gas_limit_per_block ~minimal_fees (** Simulation *) type simulation_result = { - validation_result : Tezos_protocol_environment.validation_result; - block_header_metadata : block_header_metadata; + validation_result : Tezos_protocol_environment.validation_result option; + block_header_metadata : block_header_metadata option; operations : packed_operation list list; operations_hash : Operation_list_list_hash.t; } @@ -171,7 +171,10 @@ let validate_operation inc op = | Error errs -> Events.(emit invalid_operation_filtered) (Operation.hash_packed op, errs) >>= fun () -> Lwt.return_none - | Ok (resulting_state, receipt) -> ( + | Ok (resulting_state, None) -> + (* No receipt if force_apply is not set *) + Lwt.return_some resulting_state + | Ok (resulting_state, Some receipt) -> ( (* Check that the metadata are serializable/deserializable *) let encoding_result = let enc = Protocol.operation_receipt_encoding in @@ -255,9 +258,23 @@ let filter_operations_with_simulation initial_inc fees_config operations) in let inc = {inc with header = {inc.header with operations_hash}} in - Baking_simulator.finalize_construction inc - >>=? fun (validation_result, block_header_metadata) -> - return {validation_result; block_header_metadata; operations; operations_hash} + Baking_simulator.finalize_construction inc >>=? function + | Some (validation_result, block_header_metadata) -> + return + { + validation_result = Some validation_result; + block_header_metadata = Some block_header_metadata; + operations; + operations_hash; + } + | None -> + return + { + validation_result = None; + block_header_metadata = None; + operations; + operations_hash; + } let filter_valid_operations_up_to_quota_without_simulation (ops, quota) = let {Tezos_protocol_environment.max_size; max_op} = quota in diff --git a/src/proto_016_PtMumbai/lib_delegate/operation_selection.mli b/src/proto_016_PtMumbai/lib_delegate/operation_selection.mli index 78caab5c158c..8844dbed806d 100644 --- a/src/proto_016_PtMumbai/lib_delegate/operation_selection.mli +++ b/src/proto_016_PtMumbai/lib_delegate/operation_selection.mli @@ -28,8 +28,8 @@ open Alpha_context open Tezos_protocol_environment type simulation_result = { - validation_result : validation_result; - block_header_metadata : Apply_results.block_metadata; + validation_result : validation_result option; + block_header_metadata : Apply_results.block_metadata option; operations : packed_operation list list; operations_hash : Operation_list_list_hash.t; } diff --git a/src/proto_alpha/lib_delegate/baking_actions.ml b/src/proto_alpha/lib_delegate/baking_actions.ml index 444566f0e59b..c03c099c50d1 100644 --- a/src/proto_alpha/lib_delegate/baking_actions.ml +++ b/src/proto_alpha/lib_delegate/baking_actions.ml @@ -306,10 +306,12 @@ let inject_block ~state_recorder state block_to_bake ~updated_state = ~chain_id ~pred_info:predecessor ~timestamp + ~round ~seed_nonce_hash ~payload_round ~liquidity_baking_toggle_vote ~user_activated_upgrades + ~force_apply:state.global_state.config.force_apply state.global_state.config.fees simulation_mode simulation_kind diff --git a/src/proto_alpha/lib_delegate/baking_simulator.ml b/src/proto_alpha/lib_delegate/baking_simulator.ml index 5ae61e3f47c9..bfb41a1bb140 100644 --- a/src/proto_alpha/lib_delegate/baking_simulator.ml +++ b/src/proto_alpha/lib_delegate/baking_simulator.ml @@ -54,7 +54,7 @@ let () = type incremental = { predecessor : Baking_state.block_info; context : Tezos_protocol_environment.Context.t; - state : Protocol.validation_state * Protocol.application_state; + state : Protocol.validation_state * Protocol.application_state option; rev_operations : Operation.packed list; header : Tezos_base.Block_header.shell_header; } @@ -76,7 +76,7 @@ let check_context_consistency (abstract_index : Abstract_context_index.t) | true -> return_unit | false -> fail Invalid_context)) -let begin_construction ~timestamp ~protocol_data +let begin_construction ~timestamp ~protocol_data ~force_apply (abstract_index : Abstract_context_index.t) predecessor chain_id = protect (fun () -> let { @@ -119,12 +119,15 @@ let begin_construction ~timestamp ~protocol_data ~predecessor:pred_shell ~cache:`Lazy >>=? fun validation_state -> - Lifted_protocol.begin_application - context - chain_id - mode - ~predecessor:pred_shell - ~cache:`Lazy + (if force_apply then + Lifted_protocol.begin_application + context + chain_id + mode + ~predecessor:pred_shell + ~cache:`Lazy + >>=? return_some + else return_none) >>=? fun application_state -> let state = (validation_state, application_state) in return {predecessor; context; state; rev_operations = []; header}) @@ -143,7 +146,12 @@ let add_operation st (op : Operation.packed) = Protocol.validate_operation validation_state oph op in let** application_state, receipt = - Protocol.apply_operation application_state oph op + match application_state with + | Some application_state -> + Protocol.apply_operation application_state oph op + >>=? fun (application_state, receipt) -> + return (Some application_state, Some receipt) + | None -> return (None, None) in let state = (validation_state, application_state) in return ({st with state; rev_operations = op :: st.rev_operations}, receipt)) @@ -153,6 +161,10 @@ let finalize_construction inc = let validation_state, application_state = inc.state in let** () = Protocol.finalize_validation validation_state in let** result = - Protocol.finalize_application application_state (Some inc.header) + match application_state with + | Some application_state -> + Protocol.finalize_application application_state (Some inc.header) + >>=? return_some + | None -> return_none in return result) diff --git a/src/proto_alpha/lib_delegate/baking_simulator.mli b/src/proto_alpha/lib_delegate/baking_simulator.mli index 0d0c7ac9f4d2..b05daf4f73da 100644 --- a/src/proto_alpha/lib_delegate/baking_simulator.mli +++ b/src/proto_alpha/lib_delegate/baking_simulator.mli @@ -29,7 +29,7 @@ open Alpha_context type incremental = { predecessor : Baking_state.block_info; context : Tezos_protocol_environment.Context.t; - state : validation_state * application_state; + state : validation_state * application_state option; rev_operations : Operation.packed list; header : Tezos_base.Block_header.shell_header; } @@ -44,6 +44,7 @@ val check_context_consistency : val begin_construction : timestamp:Time.Protocol.t -> protocol_data:block_header_data -> + force_apply:bool -> Abstract_context_index.t -> Baking_state.block_info -> Chain_id.t -> @@ -52,10 +53,10 @@ val begin_construction : val add_operation : incremental -> Operation.packed -> - (incremental * operation_receipt) tzresult Lwt.t + (incremental * operation_receipt option) tzresult Lwt.t val finalize_construction : incremental -> - (Tezos_protocol_environment.validation_result * block_header_metadata) + (Tezos_protocol_environment.validation_result * block_header_metadata) option tzresult Lwt.t diff --git a/src/proto_alpha/lib_delegate/block_forge.ml b/src/proto_alpha/lib_delegate/block_forge.ml index 36d743ba2a65..effadb789594 100644 --- a/src/proto_alpha/lib_delegate/block_forge.ml +++ b/src/proto_alpha/lib_delegate/block_forge.ml @@ -69,47 +69,92 @@ let convert_operation (op : packed_operation) : Tezos_base.Operation.t = op.protocol_data; } -let finalize_block_header shell_header timestamp validation_result - operations_hash predecessor_block_metadata_hash - predecessor_ops_metadata_hash predecessor_resulting_context = +(* [finalize_block_header ~shell_header ~validation_result ~operations_hash + ~pred_info ~round ~locked_round cctxt] updates the [shell_header] that was created + with dummy fields at the beginning of the block construction. It increments + the [level] and sets the actual [operations_hash], [fitness], + [validation_passes], and [context] (the predecessor resulting context hash). + + When the operations from the block have been applied, the [fitness] is simply + retrieved from the [validation_result]. Otherwise, the [fitness] is computed + from the [round] and [locked_round] arguments. *) +let finalize_block_header ~chain ~shell_header ~timestamp ~validation_result + ~operations_hash ~(pred_info : Baking_state.block_info) ~round ~locked_round + cctxt = let open Lwt_result_syntax in - let {Tezos_protocol_environment.context; fitness; message; _} = - validation_result + let* fitness = + match validation_result with + | Some {Tezos_protocol_environment.context; fitness; message; _} -> + let*! test_chain = Context_ops.get_test_chain context in + let* context = + match test_chain with + | Not_running -> return context + | Running {expiration; _} -> + if Time.Protocol.(expiration <= timestamp) then + let*! context = + Context_ops.add_test_chain context Not_running + in + return context + else return context + | Forking _ -> assert false + in + let* context = + protect + ~on_error:(fun _ -> return context) + (fun () -> + let* predecessor_block_metadata_hash = + Shell_services.Blocks.metadata_hash + cctxt + ~block:(`Hash (pred_info.hash, 0)) + ~chain + () + in + Lwt.map + Result.ok + (Context_ops.add_predecessor_block_metadata_hash + context + predecessor_block_metadata_hash)) + in + let* context = + protect + ~on_error:(fun _ -> return context) + (fun () -> + let* predecessor_ops_metadata_hash = + Shell_services.Blocks.Operation_metadata_hashes.root + cctxt + ~block:(`Hash (pred_info.hash, 0)) + ~chain + () + in + Lwt.map + Result.ok + (Context_ops.add_predecessor_ops_metadata_hash + context + predecessor_ops_metadata_hash)) + in + let context = Context_ops.hash ~time:timestamp ?message context in + (* For the time being, we still fully build the block while we build + confidence to fully unplug the baker validation. The resulting + context hash is ignored as it is not necessary to craft a block. + See: https://gitlab.com/tezos/tezos/-/issues/4285 *) + ignore context ; + return fitness + | None -> + let*? level = + Environment.wrap_tzresult @@ Raw_level.of_int32 + @@ Int32.succ shell_header.Tezos_base.Block_header.level + in + let*? fitness = + Environment.wrap_tzresult + @@ Fitness.create + ~level + ~round + ~predecessor_round:pred_info.round + ~locked_round + in + return (Fitness.to_raw fitness) in let validation_passes = List.length Main.validation_passes in - let*! test_chain = Context_ops.get_test_chain context in - let* context = - match test_chain with - | Not_running -> return context - | Running {expiration; _} -> - if Time.Protocol.(expiration <= timestamp) then - let*! context = Context_ops.add_test_chain context Not_running in - return context - else return context - | Forking _ -> assert false - in - let*! context = - match predecessor_block_metadata_hash with - | Some predecessor_block_metadata_hash -> - Context_ops.add_predecessor_block_metadata_hash - context - predecessor_block_metadata_hash - | None -> Lwt.return context - in - let*! context = - match predecessor_ops_metadata_hash with - | Some predecessor_ops_metadata_hash -> - Context_ops.add_predecessor_ops_metadata_hash - context - predecessor_ops_metadata_hash - | None -> Lwt.return context - in - let context = Context_ops.hash ~time:timestamp ?message context in - (* For the time being, we still fully build the block while we build - confidence to fully unplug the baker validation. The resulting - context hash is ignored as it is not necessary to craft a block. - See: https://gitlab.com/tezos/tezos/-/issues/4285 *) - ignore context ; let header = Tezos_base.Block_header. { @@ -118,7 +163,7 @@ let finalize_block_header shell_header timestamp validation_result validation_passes; operations_hash; fitness; - context = predecessor_resulting_context; + context = pred_info.resulting_context_hash; } in return header @@ -129,21 +174,46 @@ let retain_live_operations_only ~live_blocks operation_pool = Block_hash.Set.mem shell.branch live_blocks) operation_pool +(* [check_protocol_changed] checks whether the protocol will change with the current + block. This function returns true if the block is the last of an [adoption] + period. It can also return true if an [user_activated_upgrades] is given. *) let check_protocol_changed ~user_activated_upgrades ~level - ~(validation_result : Tezos_protocol_environment.validation_result) = + ~(validation_result : Tezos_protocol_environment.validation_result option) + ~(incremental : Baking_simulator.incremental) = let open Lwt_result_syntax in - let*! next_protocol = Context_ops.get_protocol validation_result.context in - let next_protocol = - match - Tezos_base.Block_header.get_forced_protocol_upgrade - ~user_activated_upgrades - ~level - with - | None -> next_protocol - | Some hash -> hash - in - return Protocol_hash.(Protocol.hash <> next_protocol) + match + Tezos_base.Block_header.get_forced_protocol_upgrade + ~user_activated_upgrades + ~level + with + | None -> ( + match validation_result with + | None -> ( + let context = Validate.get_initial_ctxt (fst incremental.state) in + let* voting_period = + Lwt.map + Environment.wrap_tzresult + (Voting_period.get_current context) + in + match voting_period.kind with + | Voting_period.Proposal | Exploration | Cooldown | Promotion -> + return false + | Adoption -> + Lwt.map + Environment.wrap_tzresult + (Voting_period.is_last_block context)) + | Some validation_result -> + let*! next_protocol = + Context_ops.get_protocol validation_result.context + in + return Protocol_hash.(Protocol.hash <> next_protocol)) + | Some next_protocol -> return Protocol_hash.(Protocol.hash <> next_protocol) +(* [filter_via_node] filters operations using + {!Operation_selection.filter_operations_without_simulation} and then applies + them in a block via {!Node_rpc.preapply_block}. [filter_via_node] returns a + [shell_header], the list of operations that have been applied in the block + and the [payload_hash] corresponding to these operations. *) let filter_via_node ~chain_id ~fees_config ~hard_gas_limit_per_block ~faked_protocol_data ~timestamp ~(pred_info : Baking_state.block_info) ~payload_round ~operation_pool cctxt = @@ -180,16 +250,23 @@ let filter_via_node ~chain_id ~fees_config ~hard_gas_limit_per_block in return (shell_header, operations, payload_hash) +(* [filter_with_context] filters operations using a local context via + {!Operation_selection.filter_operations_with_simulation} and a fresh state + from {!Baking_simulator.begin_construction}. [finalize_block_header] is then + called and a [shell_header], the list of operations and the corresponding + [payload_hash] are returned. If the block is a transition block, + [filter_via_node] is called to return these values. *) let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block ~faked_protocol_data ~user_activated_upgrades ~timestamp - ~(pred_info : Baking_state.block_info) ~context_index ~payload_round - ~operation_pool cctxt = + ~(pred_info : Baking_state.block_info) ~force_apply ~round ~context_index + ~payload_round ~operation_pool cctxt = let open Lwt_result_syntax in let chain = `Hash chain_id in let* incremental = Baking_simulator.begin_construction ~timestamp ~protocol_data:faked_protocol_data + ~force_apply context_index pred_info chain_id @@ -206,6 +283,7 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block ~level:(Int32.succ pred_info.shell.level) ~user_activated_upgrades ~validation_result + ~incremental in if changed then (* Fallback to processing via node, which knows both old and new protocol. *) @@ -220,41 +298,17 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block ~operation_pool cctxt else - let* pred_block_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_block_metadata_hash = - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (pred_info.hash, 0)) - ~chain - () - in - Some pred_block_metadata_hash) - in - let* pred_op_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_op_metadata_hash = - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (pred_info.hash, 0)) - ~chain - () - in - Some pred_op_metadata_hash) - in let* shell_header = finalize_block_header - incremental.header - timestamp - validation_result - operations_hash - pred_block_metadata_hash - pred_op_metadata_hash - pred_info.resulting_context_hash + ~chain + ~shell_header:incremental.header + ~timestamp + ~validation_result + ~operations_hash + ~pred_info + ~round + ~locked_round:None + cctxt in let operations = List.map (List.map convert_operation) operations in let payload_hash = @@ -269,6 +323,9 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block in return (shell_header, operations, payload_hash) +(* [apply_via_node] applies already filtered and validated operations in a block + via {!Node_rpc.preapply_block}. A [shell_header] is recovered from this call + and returned alongside of the list of operations and the payload_hash. *) let apply_via_node ~chain_id ~faked_protocol_data ~timestamp ~(pred_info : Baking_state.block_info) ~ordered_pool ~payload_hash cctxt = let open Lwt_result_syntax in @@ -286,15 +343,19 @@ let apply_via_node ~chain_id ~faked_protocol_data ~timestamp let operations = List.map (List.map convert_operation) operations in return (shell_header, operations, payload_hash) +(* [apply_with_context] is similar to [filter_with_context] but filters + consensus operations only from an [ordered_pool] via + {!Operation_selection.filter_consensus_operations_only}. *) let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades - ~timestamp ~(pred_info : Baking_state.block_info) ~ordered_pool - ~context_index ~payload_hash cctxt = + ~timestamp ~(pred_info : Baking_state.block_info) ~force_apply ~round + ~ordered_pool ~context_index ~payload_hash cctxt = let open Lwt_result_syntax in let chain = `Hash chain_id in let* incremental = Baking_simulator.begin_construction ~timestamp ~protocol_data:faked_protocol_data + ~force_apply context_index pred_info chain_id @@ -319,14 +380,14 @@ let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades let incremental = {incremental with header = {incremental.header with operations_hash}} in - let* validation_result, _ = - Baking_simulator.finalize_construction incremental - in + let* validation_result = Baking_simulator.finalize_construction incremental in + let validation_result = Option.map fst validation_result in let* changed = check_protocol_changed ~level:(Int32.succ pred_info.shell.level) ~user_activated_upgrades ~validation_result + ~incremental in if changed then (* Fallback to processing via node, which knows both old and new protocol. *) @@ -339,50 +400,40 @@ let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades ~payload_hash cctxt else - let* pred_block_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_block_metadata_hash = - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (pred_info.hash, 0)) - ~chain - () - in - Some pred_block_metadata_hash) - in - let* pred_op_metadata_hash = - protect - ~on_error:(fun _ -> return_none) - (fun () -> - let+ pred_op_metadata_hash = - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (pred_info.hash, 0)) - ~chain - () - in - Some pred_op_metadata_hash) + let locked_round_when_no_validation_result = + (* [locked_round] will not be used in [finalize_block_header] if there is + a [validation_result] *) + if Option.is_some validation_result then None + else + List.find_map + (fun {protocol_data = Operation_data protocol_data; _} -> + match protocol_data.contents with + | Single (Preendorsement {round; _}) -> Some round + | _ -> None) + (Option.value (List.hd operations) ~default:[]) in let* shell_header = finalize_block_header - incremental.header - timestamp - validation_result - operations_hash - pred_block_metadata_hash - pred_op_metadata_hash - pred_info.resulting_context_hash + ~chain + ~shell_header:incremental.header + ~timestamp + ~validation_result + ~operations_hash + ~pred_info + ~round + ~locked_round:locked_round_when_no_validation_result + cctxt in let operations = List.map (List.map convert_operation) operations in return (shell_header, operations, payload_hash) -(* [forge] a new [unsigned_block] regarding of [simulation_kind] and [simulation_mode] *) +(* [forge] a new [unsigned_block] in accordance with [simulation_kind] and + [simulation_mode] *) let forge (cctxt : #Protocol_client_context.full) ~chain_id - ~(pred_info : Baking_state.block_info) ~timestamp + ~(pred_info : Baking_state.block_info) ~timestamp ~round ~liquidity_baking_toggle_vote ~user_activated_upgrades fees_config - ~seed_nonce_hash ~payload_round simulation_mode simulation_kind constants = + ~force_apply ~seed_nonce_hash ~payload_round simulation_mode simulation_kind + constants = let open Lwt_result_syntax in let hard_gas_limit_per_block = constants.Constants.Parametric.hard_gas_limit_per_block @@ -453,6 +504,8 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~user_activated_upgrades ~timestamp ~pred_info + ~force_apply + ~round ~context_index ~payload_round ~operation_pool @@ -472,6 +525,8 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id ~user_activated_upgrades ~timestamp ~pred_info + ~force_apply + ~round ~ordered_pool ~context_index ~payload_hash diff --git a/src/proto_alpha/lib_delegate/block_forge.mli b/src/proto_alpha/lib_delegate/block_forge.mli index b111e27b417c..77fb619a192f 100644 --- a/src/proto_alpha/lib_delegate/block_forge.mli +++ b/src/proto_alpha/lib_delegate/block_forge.mli @@ -40,22 +40,16 @@ type simulation_kind = type simulation_mode = Local of Context.index | Node -val forge_faked_protocol_data : - ?payload_hash:Block_payload_hash.t -> - payload_round:Round.t -> - seed_nonce_hash:Nonce_hash.t option -> - liquidity_baking_toggle_vote:Liquidity_baking.liquidity_baking_toggle_vote -> - unit -> - block_header_data - val forge : #Protocol_client_context.full -> chain_id:Chain_id.t -> pred_info:Baking_state.block_info -> timestamp:Time.Protocol.t -> + round:Round.t -> liquidity_baking_toggle_vote:Liquidity_baking.liquidity_baking_toggle_vote -> user_activated_upgrades:User_activated.upgrades -> Baking_configuration.fees_config -> + force_apply:bool -> seed_nonce_hash:Nonce_hash.t option -> payload_round:Round.t -> Baking_state.validation_mode -> diff --git a/src/proto_alpha/lib_delegate/operation_selection.ml b/src/proto_alpha/lib_delegate/operation_selection.ml index 9a4fbf4d0b92..cc33ddbfca71 100644 --- a/src/proto_alpha/lib_delegate/operation_selection.ml +++ b/src/proto_alpha/lib_delegate/operation_selection.ml @@ -160,8 +160,8 @@ let prioritize_managers ~hard_gas_limit_per_block ~minimal_fees (** Simulation *) type simulation_result = { - validation_result : Tezos_protocol_environment.validation_result; - block_header_metadata : block_header_metadata; + validation_result : Tezos_protocol_environment.validation_result option; + block_header_metadata : block_header_metadata option; operations : packed_operation list list; operations_hash : Operation_list_list_hash.t; } @@ -171,7 +171,10 @@ let validate_operation inc op = | Error errs -> Events.(emit invalid_operation_filtered) (Operation.hash_packed op, errs) >>= fun () -> Lwt.return_none - | Ok (resulting_state, receipt) -> ( + | Ok (resulting_state, None) -> + (* No receipt if force_apply is not set *) + Lwt.return_some resulting_state + | Ok (resulting_state, Some receipt) -> ( (* Check that the metadata are serializable/deserializable *) let encoding_result = let enc = Protocol.operation_receipt_encoding in @@ -255,9 +258,23 @@ let filter_operations_with_simulation initial_inc fees_config operations) in let inc = {inc with header = {inc.header with operations_hash}} in - Baking_simulator.finalize_construction inc - >>=? fun (validation_result, block_header_metadata) -> - return {validation_result; block_header_metadata; operations; operations_hash} + Baking_simulator.finalize_construction inc >>=? function + | Some (validation_result, block_header_metadata) -> + return + { + validation_result = Some validation_result; + block_header_metadata = Some block_header_metadata; + operations; + operations_hash; + } + | None -> + return + { + validation_result = None; + block_header_metadata = None; + operations; + operations_hash; + } let filter_valid_operations_up_to_quota_without_simulation (ops, quota) = let {Tezos_protocol_environment.max_size; max_op} = quota in diff --git a/src/proto_alpha/lib_delegate/operation_selection.mli b/src/proto_alpha/lib_delegate/operation_selection.mli index 78caab5c158c..8844dbed806d 100644 --- a/src/proto_alpha/lib_delegate/operation_selection.mli +++ b/src/proto_alpha/lib_delegate/operation_selection.mli @@ -28,8 +28,8 @@ open Alpha_context open Tezos_protocol_environment type simulation_result = { - validation_result : validation_result; - block_header_metadata : Apply_results.block_metadata; + validation_result : validation_result option; + block_header_metadata : Apply_results.block_metadata option; operations : packed_operation list list; operations_hash : Operation_list_list_hash.t; } -- GitLab From 5858b6364f46ba8b02b417fc317dc518a0dbc8b1 Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Wed, 25 Jan 2023 16:39:48 +0100 Subject: [PATCH 06/12] lib_delegate: remove context finalisation in block_forge --- .../lib_delegate/block_forge.ml | 80 ++----------------- src/proto_alpha/lib_delegate/block_forge.ml | 71 +--------------- 2 files changed, 12 insertions(+), 139 deletions(-) diff --git a/src/proto_016_PtMumbai/lib_delegate/block_forge.ml b/src/proto_016_PtMumbai/lib_delegate/block_forge.ml index 012a0ed4010f..d3be206ac6b6 100644 --- a/src/proto_016_PtMumbai/lib_delegate/block_forge.ml +++ b/src/proto_016_PtMumbai/lib_delegate/block_forge.ml @@ -69,77 +69,21 @@ let convert_operation (op : packed_operation) : Tezos_base.Operation.t = op.protocol_data; } -(* [finalize_block_header ~chain ~shell_header ~timestamp ~validation_result - ~operations_hash ~pred_info ~round ~locked_round cctxt] updates the - [shell_header] that was created with dummy fields at the beginning of the - block construction. It increments the [level] and sets the actual - [operations_hash], [fitness], [validation_passes], and [context] (the - predecessor resulting context hash). +(* [finalize_block_header ~shell_header ~validation_result ~operations_hash + ~pred_info ~round ~locked_round] updates the [shell_header] that was created + with dummy fields at the beginning of the block construction. It increments + the [level] and sets the actual [operations_hash], [fitness], + [validation_passes], and [context] (the predecessor resulting context hash). When the operations from the block have been applied, the [fitness] is simply retrieved from the [validation_result]. Otherwise, the [fitness] is computed from the [round] and [locked_round] arguments. *) -let finalize_block_header ~chain ~shell_header ~timestamp ~validation_result - ~operations_hash ~(pred_info : Baking_state.block_info) ~round ~locked_round - cctxt = +let finalize_block_header ~shell_header ~validation_result ~operations_hash + ~(pred_info : Baking_state.block_info) ~round ~locked_round = let open Lwt_result_syntax in let* fitness = match validation_result with - | Some {Tezos_protocol_environment.context; fitness; message; _} -> - let*! test_chain = Context_ops.get_test_chain context in - let* context = - match test_chain with - | Not_running -> return context - | Running {expiration; _} -> - if Time.Protocol.(expiration <= timestamp) then - let*! context = - Context_ops.add_test_chain context Not_running - in - return context - else return context - | Forking _ -> assert false - in - let* context = - protect - ~on_error:(fun _ -> return context) - (fun () -> - let* predecessor_block_metadata_hash = - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (pred_info.hash, 0)) - ~chain - () - in - Lwt.map - Result.ok - (Context_ops.add_predecessor_block_metadata_hash - context - predecessor_block_metadata_hash)) - in - let* context = - protect - ~on_error:(fun _ -> return context) - (fun () -> - let* predecessor_ops_metadata_hash = - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (pred_info.hash, 0)) - ~chain - () - in - Lwt.map - Result.ok - (Context_ops.add_predecessor_ops_metadata_hash - context - predecessor_ops_metadata_hash)) - in - let context = Context_ops.hash ~time:timestamp ?message context in - (* For the time being, we still fully build the block while we build - confidence to fully unplug the baker validation. The resulting - context hash is ignored as it is not necessary to craft a block. - See: https://gitlab.com/tezos/tezos/-/issues/4285 *) - ignore context ; - return fitness + | Some {Tezos_protocol_environment.fitness; _} -> return fitness | None -> let*? level = Environment.wrap_tzresult @@ Raw_level.of_int32 @@ -262,7 +206,6 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block ~(pred_info : Baking_state.block_info) ~force_apply ~round ~context_index ~payload_round ~operation_pool cctxt = let open Lwt_result_syntax in - let chain = `Hash chain_id in let* incremental = Baking_simulator.begin_construction ~timestamp @@ -301,15 +244,12 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block else let* shell_header = finalize_block_header - ~chain ~shell_header:incremental.header - ~timestamp ~validation_result ~operations_hash ~pred_info ~round ~locked_round:None - cctxt in let operations = List.map (List.map convert_operation) operations in let payload_hash = @@ -351,7 +291,6 @@ let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades ~timestamp ~(pred_info : Baking_state.block_info) ~force_apply ~round ~ordered_pool ~context_index ~payload_hash cctxt = let open Lwt_result_syntax in - let chain = `Hash chain_id in let* incremental = Baking_simulator.begin_construction ~timestamp @@ -415,15 +354,12 @@ let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades in let* shell_header = finalize_block_header - ~chain ~shell_header:incremental.header - ~timestamp ~validation_result ~operations_hash ~pred_info ~round ~locked_round:locked_round_when_no_validation_result - cctxt in let operations = List.map (List.map convert_operation) operations in return (shell_header, operations, payload_hash) diff --git a/src/proto_alpha/lib_delegate/block_forge.ml b/src/proto_alpha/lib_delegate/block_forge.ml index effadb789594..d3be206ac6b6 100644 --- a/src/proto_alpha/lib_delegate/block_forge.ml +++ b/src/proto_alpha/lib_delegate/block_forge.ml @@ -70,7 +70,7 @@ let convert_operation (op : packed_operation) : Tezos_base.Operation.t = } (* [finalize_block_header ~shell_header ~validation_result ~operations_hash - ~pred_info ~round ~locked_round cctxt] updates the [shell_header] that was created + ~pred_info ~round ~locked_round] updates the [shell_header] that was created with dummy fields at the beginning of the block construction. It increments the [level] and sets the actual [operations_hash], [fitness], [validation_passes], and [context] (the predecessor resulting context hash). @@ -78,67 +78,12 @@ let convert_operation (op : packed_operation) : Tezos_base.Operation.t = When the operations from the block have been applied, the [fitness] is simply retrieved from the [validation_result]. Otherwise, the [fitness] is computed from the [round] and [locked_round] arguments. *) -let finalize_block_header ~chain ~shell_header ~timestamp ~validation_result - ~operations_hash ~(pred_info : Baking_state.block_info) ~round ~locked_round - cctxt = +let finalize_block_header ~shell_header ~validation_result ~operations_hash + ~(pred_info : Baking_state.block_info) ~round ~locked_round = let open Lwt_result_syntax in let* fitness = match validation_result with - | Some {Tezos_protocol_environment.context; fitness; message; _} -> - let*! test_chain = Context_ops.get_test_chain context in - let* context = - match test_chain with - | Not_running -> return context - | Running {expiration; _} -> - if Time.Protocol.(expiration <= timestamp) then - let*! context = - Context_ops.add_test_chain context Not_running - in - return context - else return context - | Forking _ -> assert false - in - let* context = - protect - ~on_error:(fun _ -> return context) - (fun () -> - let* predecessor_block_metadata_hash = - Shell_services.Blocks.metadata_hash - cctxt - ~block:(`Hash (pred_info.hash, 0)) - ~chain - () - in - Lwt.map - Result.ok - (Context_ops.add_predecessor_block_metadata_hash - context - predecessor_block_metadata_hash)) - in - let* context = - protect - ~on_error:(fun _ -> return context) - (fun () -> - let* predecessor_ops_metadata_hash = - Shell_services.Blocks.Operation_metadata_hashes.root - cctxt - ~block:(`Hash (pred_info.hash, 0)) - ~chain - () - in - Lwt.map - Result.ok - (Context_ops.add_predecessor_ops_metadata_hash - context - predecessor_ops_metadata_hash)) - in - let context = Context_ops.hash ~time:timestamp ?message context in - (* For the time being, we still fully build the block while we build - confidence to fully unplug the baker validation. The resulting - context hash is ignored as it is not necessary to craft a block. - See: https://gitlab.com/tezos/tezos/-/issues/4285 *) - ignore context ; - return fitness + | Some {Tezos_protocol_environment.fitness; _} -> return fitness | None -> let*? level = Environment.wrap_tzresult @@ Raw_level.of_int32 @@ -261,7 +206,6 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block ~(pred_info : Baking_state.block_info) ~force_apply ~round ~context_index ~payload_round ~operation_pool cctxt = let open Lwt_result_syntax in - let chain = `Hash chain_id in let* incremental = Baking_simulator.begin_construction ~timestamp @@ -300,15 +244,12 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block else let* shell_header = finalize_block_header - ~chain ~shell_header:incremental.header - ~timestamp ~validation_result ~operations_hash ~pred_info ~round ~locked_round:None - cctxt in let operations = List.map (List.map convert_operation) operations in let payload_hash = @@ -350,7 +291,6 @@ let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades ~timestamp ~(pred_info : Baking_state.block_info) ~force_apply ~round ~ordered_pool ~context_index ~payload_hash cctxt = let open Lwt_result_syntax in - let chain = `Hash chain_id in let* incremental = Baking_simulator.begin_construction ~timestamp @@ -414,15 +354,12 @@ let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades in let* shell_header = finalize_block_header - ~chain ~shell_header:incremental.header - ~timestamp ~validation_result ~operations_hash ~pred_info ~round ~locked_round:locked_round_when_no_validation_result - cctxt in let operations = List.map (List.map convert_operation) operations in return (shell_header, operations, payload_hash) -- GitLab From 95a9f9135976acc06cd39400b2c5355113161b9d Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Tue, 24 Jan 2023 17:05:17 +0100 Subject: [PATCH 07/12] lib_delegate: disable signature check on operations already validated in the prevalidator --- .../lib_delegate/baking_simulator.ml | 10 +++++++++- src/proto_alpha/lib_delegate/baking_simulator.ml | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/proto_016_PtMumbai/lib_delegate/baking_simulator.ml b/src/proto_016_PtMumbai/lib_delegate/baking_simulator.ml index bfb41a1bb140..74f2b7519cfb 100644 --- a/src/proto_016_PtMumbai/lib_delegate/baking_simulator.ml +++ b/src/proto_016_PtMumbai/lib_delegate/baking_simulator.ml @@ -143,7 +143,15 @@ let add_operation st (op : Operation.packed) = let validation_state, application_state = st.state in let oph = Operation.hash_packed op in let** validation_state = - Protocol.validate_operation validation_state oph op + Protocol.validate_operation + ~check_signature:false + (* We assume that the operation has already been validated in the + node, therefore the signature has already been checked, but we + still need to validate it again because the context may be + different. *) + validation_state + oph + op in let** application_state, receipt = match application_state with diff --git a/src/proto_alpha/lib_delegate/baking_simulator.ml b/src/proto_alpha/lib_delegate/baking_simulator.ml index bfb41a1bb140..74f2b7519cfb 100644 --- a/src/proto_alpha/lib_delegate/baking_simulator.ml +++ b/src/proto_alpha/lib_delegate/baking_simulator.ml @@ -143,7 +143,15 @@ let add_operation st (op : Operation.packed) = let validation_state, application_state = st.state in let oph = Operation.hash_packed op in let** validation_state = - Protocol.validate_operation validation_state oph op + Protocol.validate_operation + ~check_signature:false + (* We assume that the operation has already been validated in the + node, therefore the signature has already been checked, but we + still need to validate it again because the context may be + different. *) + validation_state + oph + op in let** application_state, receipt = match application_state with -- GitLab From b7a622da64e9d00c45120f71facc9155c1cce7af Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Wed, 25 Jan 2023 17:32:19 +0100 Subject: [PATCH 08/12] lib_delegate: add some documentation for operation_selection --- .../lib_delegate/operation_selection.mli | 18 ++++++++++++++++++ .../lib_delegate/operation_selection.mli | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/proto_016_PtMumbai/lib_delegate/operation_selection.mli b/src/proto_016_PtMumbai/lib_delegate/operation_selection.mli index 8844dbed806d..d83fd0dda258 100644 --- a/src/proto_016_PtMumbai/lib_delegate/operation_selection.mli +++ b/src/proto_016_PtMumbai/lib_delegate/operation_selection.mli @@ -34,6 +34,15 @@ type simulation_result = { operations_hash : Operation_list_list_hash.t; } +(** [filter_operations_with_simulation incremental fees_config + ~hard_gas_limit_per_block ops] tries to validate prioritized operations (and + apply them if [incremental] has been initialised with an + [application_state]) and filter them regarding the quota of each validation + pass. Manager operations are prioritized based on a weight computed from + their fees/gas/bytes. [filter_operations_with_simulation] function returns a + [simulation_result], containing the validated operation, their resulting + [operations_hash], optional [validation_result] and [block_header_metadata] + if the operations were applied. *) val filter_operations_with_simulation : Baking_simulator.incremental -> Baking_configuration.fees_config -> @@ -41,12 +50,21 @@ val filter_operations_with_simulation : Operation_pool.Prioritized.t -> simulation_result tzresult Lwt.t +(** [filter_operations_without_simulation fees_config ~hard_gas_limit_per_block + ops] is similar to [filter_operations_with_simulation] but does not validate + (and apply) operations from [ops] and returns only the operations instead of + a [simulation_result]. + + Hypothesis: operations from [ops] have previously been validated. *) val filter_operations_without_simulation : Baking_configuration.fees_config -> hard_gas_limit_per_block:Gas.Arith.integral -> Operation_pool.Prioritized.t -> packed_operation list list +(** [filter_consensus_operations_only incremental ops] is similar to + [filter_operations_with_simulation] but only filters consensus operations + from [ops]. *) val filter_consensus_operations_only : Baking_simulator.incremental -> Operation_pool.ordered_pool -> diff --git a/src/proto_alpha/lib_delegate/operation_selection.mli b/src/proto_alpha/lib_delegate/operation_selection.mli index 8844dbed806d..d83fd0dda258 100644 --- a/src/proto_alpha/lib_delegate/operation_selection.mli +++ b/src/proto_alpha/lib_delegate/operation_selection.mli @@ -34,6 +34,15 @@ type simulation_result = { operations_hash : Operation_list_list_hash.t; } +(** [filter_operations_with_simulation incremental fees_config + ~hard_gas_limit_per_block ops] tries to validate prioritized operations (and + apply them if [incremental] has been initialised with an + [application_state]) and filter them regarding the quota of each validation + pass. Manager operations are prioritized based on a weight computed from + their fees/gas/bytes. [filter_operations_with_simulation] function returns a + [simulation_result], containing the validated operation, their resulting + [operations_hash], optional [validation_result] and [block_header_metadata] + if the operations were applied. *) val filter_operations_with_simulation : Baking_simulator.incremental -> Baking_configuration.fees_config -> @@ -41,12 +50,21 @@ val filter_operations_with_simulation : Operation_pool.Prioritized.t -> simulation_result tzresult Lwt.t +(** [filter_operations_without_simulation fees_config ~hard_gas_limit_per_block + ops] is similar to [filter_operations_with_simulation] but does not validate + (and apply) operations from [ops] and returns only the operations instead of + a [simulation_result]. + + Hypothesis: operations from [ops] have previously been validated. *) val filter_operations_without_simulation : Baking_configuration.fees_config -> hard_gas_limit_per_block:Gas.Arith.integral -> Operation_pool.Prioritized.t -> packed_operation list list +(** [filter_consensus_operations_only incremental ops] is similar to + [filter_operations_with_simulation] but only filters consensus operations + from [ops]. *) val filter_consensus_operations_only : Baking_simulator.incremental -> Operation_pool.ordered_pool -> -- GitLab From 9288a008f7829d692a3676b01caef3b2eaac5aab Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Wed, 25 Jan 2023 17:59:52 +0100 Subject: [PATCH 09/12] lib_delegate: add some documentation to baking_simulator --- .../lib_delegate/baking_simulator.mli | 18 ++++++++++++++++++ .../lib_delegate/baking_simulator.mli | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/proto_016_PtMumbai/lib_delegate/baking_simulator.mli b/src/proto_016_PtMumbai/lib_delegate/baking_simulator.mli index b05daf4f73da..959546fe6d21 100644 --- a/src/proto_016_PtMumbai/lib_delegate/baking_simulator.mli +++ b/src/proto_016_PtMumbai/lib_delegate/baking_simulator.mli @@ -41,6 +41,13 @@ val load_context : val check_context_consistency : Abstract_context_index.t -> Context_hash.t -> unit tzresult Lwt.t +(** [begin_construction ~timestamp ~protocol_data ~force_apply abstract_context + predecessor chain_id] creates a new [incremental] value with an empty + operation list. A [context] is recovered from the [abstract_index] and the + resulting_context_hash from [predecessor]. This context is used to create a + [validation_state] and an [application_state] (if [force_apply] is set). A + partial [shell_header] is created from [predecessor] information and + [timestamp]. *) val begin_construction : timestamp:Time.Protocol.t -> protocol_data:block_header_data -> @@ -50,11 +57,22 @@ val begin_construction : Chain_id.t -> incremental tzresult Lwt.t +(** [add_operation incremental op] validates [op] in + [incremental.validation_state] without checking its signature. Indeed, the + operation has already been validated in the node so it has a correct + signature. We still need to validate it again because the context may be + different. [op] is also applied if [incremental] has been created with + [force_apply] set. This function returns an [incremental] with updated + operations list and [validation_state] (and [application_state]). *) val add_operation : incremental -> Operation.packed -> (incremental * operation_receipt option) tzresult Lwt.t +(** [finalize_construction incremental] calls the [finalize_validation] of the + protocol on the [validation_state] from [incremental]. If [incremental] has + been created with [force_apply] set, [finalize_application] is also called + and its results returned. *) val finalize_construction : incremental -> (Tezos_protocol_environment.validation_result * block_header_metadata) option diff --git a/src/proto_alpha/lib_delegate/baking_simulator.mli b/src/proto_alpha/lib_delegate/baking_simulator.mli index b05daf4f73da..959546fe6d21 100644 --- a/src/proto_alpha/lib_delegate/baking_simulator.mli +++ b/src/proto_alpha/lib_delegate/baking_simulator.mli @@ -41,6 +41,13 @@ val load_context : val check_context_consistency : Abstract_context_index.t -> Context_hash.t -> unit tzresult Lwt.t +(** [begin_construction ~timestamp ~protocol_data ~force_apply abstract_context + predecessor chain_id] creates a new [incremental] value with an empty + operation list. A [context] is recovered from the [abstract_index] and the + resulting_context_hash from [predecessor]. This context is used to create a + [validation_state] and an [application_state] (if [force_apply] is set). A + partial [shell_header] is created from [predecessor] information and + [timestamp]. *) val begin_construction : timestamp:Time.Protocol.t -> protocol_data:block_header_data -> @@ -50,11 +57,22 @@ val begin_construction : Chain_id.t -> incremental tzresult Lwt.t +(** [add_operation incremental op] validates [op] in + [incremental.validation_state] without checking its signature. Indeed, the + operation has already been validated in the node so it has a correct + signature. We still need to validate it again because the context may be + different. [op] is also applied if [incremental] has been created with + [force_apply] set. This function returns an [incremental] with updated + operations list and [validation_state] (and [application_state]). *) val add_operation : incremental -> Operation.packed -> (incremental * operation_receipt option) tzresult Lwt.t +(** [finalize_construction incremental] calls the [finalize_validation] of the + protocol on the [validation_state] from [incremental]. If [incremental] has + been created with [force_apply] set, [finalize_application] is also called + and its results returned. *) val finalize_construction : incremental -> (Tezos_protocol_environment.validation_result * block_header_metadata) option -- GitLab From a56ee498d30568a260426acbd755f9a009d6d3cc Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Thu, 26 Jan 2023 17:15:05 +0100 Subject: [PATCH 10/12] tezt/lib_tezos: add support for force-apply baker option --- tezt/lib_tezos/baker.ml | 16 +++++++++++----- tezt/lib_tezos/baker.mli | 12 +++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/tezt/lib_tezos/baker.ml b/tezt/lib_tezos/baker.ml index aced38b54a47..027dc225af34 100644 --- a/tezt/lib_tezos/baker.ml +++ b/tezt/lib_tezos/baker.ml @@ -46,6 +46,7 @@ module Parameters = struct mutable pending_ready : unit option Lwt.u list; votefile : string option; liquidity_baking_toggle_vote : liquidity_baking_vote option; + force_apply : bool; operations_pool : string option; dal_node : Dal_node.t option; } @@ -90,8 +91,8 @@ let liquidity_baking_votefile ?path vote = votefile let create ~protocol ?name ?color ?event_pipe ?runner ?(delegates = []) - ?votefile ?(liquidity_baking_toggle_vote = Some Pass) ?operations_pool - ?dal_node node client = + ?votefile ?(liquidity_baking_toggle_vote = Some Pass) ?(force_apply = false) + ?operations_pool ?dal_node node client = let baker = create ~path:(Protocol.baker protocol) @@ -108,6 +109,7 @@ let create ~protocol ?name ?color ?event_pipe ?runner ?(delegates = []) pending_ready = []; votefile; liquidity_baking_toggle_vote; + force_apply; operations_pool; dal_node; } @@ -135,6 +137,9 @@ let run ?event_level ?event_sections_levels (baker : t) = liquidity_baking_vote_to_string baker.persistent_state.liquidity_baking_toggle_vote in + let force_apply = + Cli_arg.optional_switch "force-apply" baker.persistent_state.force_apply + in let operations_pool = Cli_arg.optional_arg "operations-pool" @@ -163,7 +168,7 @@ let run ?event_level ?event_sections_levels (baker : t) = "node"; Node.data_dir node; ] - @ liquidity_baking_toggle_vote @ votefile @ operations_pool + @ liquidity_baking_toggle_vote @ votefile @ force_apply @ operations_pool @ dal_node_endpoint @ delegates in let on_terminate _ = @@ -197,8 +202,8 @@ let wait_for_ready baker = check_event baker "Baker started." promise let init ~protocol ?name ?color ?event_pipe ?runner ?event_sections_levels - ?(delegates = []) ?votefile ?liquidity_baking_toggle_vote ?operations_pool - ?dal_node node client = + ?(delegates = []) ?votefile ?liquidity_baking_toggle_vote ?force_apply + ?operations_pool ?dal_node node client = let* () = Node.wait_for_ready node in let baker = create @@ -209,6 +214,7 @@ let init ~protocol ?name ?color ?event_pipe ?runner ?event_sections_levels ?runner ?votefile ?liquidity_baking_toggle_vote + ?force_apply ?operations_pool ?dal_node ~delegates diff --git a/tezt/lib_tezos/baker.mli b/tezt/lib_tezos/baker.mli index 14274f76c47f..f29da85b5b91 100644 --- a/tezt/lib_tezos/baker.mli +++ b/tezt/lib_tezos/baker.mli @@ -119,8 +119,8 @@ val liquidity_baking_votefile : ?path:string -> liquidity_baking_vote -> string is not passed. If it is [Some x] then [--liquidity-baking-toggle-vote x] is passed. The default value is [Some Pass]. - [operations_pool] is passed to the baker daemon through the flag - [--operations-pool]. + [operations_pool] and [force_apply] are passed to the baker daemon through + the flag [--operations-pool] and [--force_apply]. If [dal_node] is specified, then it is the DAL node that the baker queries in order to determine the attestations it sends to the L1 node. A @@ -134,6 +134,7 @@ val create : ?delegates:string list -> ?votefile:string -> ?liquidity_baking_toggle_vote:liquidity_baking_vote option -> + ?force_apply:bool -> ?operations_pool:string -> ?dal_node:Dal_node.t -> Node.t -> @@ -170,10 +171,10 @@ val create : baker. This defaults to the empty list, which is a shortcut for "every known account". - [votefile], [liquidity_baking_toggle_vote] respectively + [votefile], [liquidity_baking_toggle_vote], [force_apply] respectively [operations_pool] are passed to the baker daemon through the flags - [--votefile], [--liquidity-baking-toggle-vote] respectively - [--operations-pool]. + [--votefile], [--liquidity-baking-toggle-vote], [--should-apply] + respectively [--operations-pool]. If [dal_node] is specified, then it is the DAL node that the baker queries in order to determine the attestations it sends to the L1 node. A @@ -188,6 +189,7 @@ val init : ?delegates:string list -> ?votefile:string -> ?liquidity_baking_toggle_vote:liquidity_baking_vote option -> + ?force_apply:bool -> ?operations_pool:string -> ?dal_node:Dal_node.t -> Node.t -> -- GitLab From 81681a40e0a81b22187fdce90c1a2333c98530e6 Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Thu, 26 Jan 2023 17:16:08 +0100 Subject: [PATCH 11/12] tezt/lib_tezos: add baker test that force apply operation on alpha --- tezt/tests/baker_test.ml | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/tezt/tests/baker_test.ml b/tezt/tests/baker_test.ml index 63c01c506d9d..a2d2f8a19418 100644 --- a/tezt/tests/baker_test.ml +++ b/tezt/tests/baker_test.ml @@ -30,7 +30,7 @@ Subject: Run the baker while performing a lot of transfers *) -let baker_test protocol ~keys = +let baker_test ?force_apply protocol ~keys = let* parameter_file = Protocol.write_parameter_file ~bootstrap_accounts:(List.map (fun k -> (k, None)) keys) @@ -48,7 +48,7 @@ let baker_test protocol ~keys = in let level_2_promise = Node.wait_for_level node 2 in let level_3_promise = Node.wait_for_level node 3 in - let* baker = Baker.init ~protocol node client in + let* baker = Baker.init ?force_apply ~protocol node client in Log.info "Wait for new head." ; Baker.log_events baker ; let* _ = level_2_promise in @@ -80,6 +80,23 @@ let baker_stresstest = let* () = Client.stresstest ~tps:25 ~transfers:100 client in Lwt.return_unit +(* Force the baker to apply operations after validating them *) +let baker_stresstest_apply = + Protocol.register_test + ~__FILE__ + ~supports:Protocol.(From_protocol (number Mumbai)) + ~title:"baker stresstest with forced application" + ~tags:["node"; "baker"; "stresstest"; "apply"] + @@ fun protocol -> + let* node, client = + Client.init_with_protocol `Client ~protocol () ~timestamp:Now + in + let* _ = Baker.init ~force_apply:true ~protocol node client in + let* _ = Node.wait_for_level node 3 in + (* Use a large tps, to have failing operations too *) + let* () = Client.stresstest ~tps:25 ~transfers:100 client in + unit + let baker_bls_test = Protocol.register_test ~__FILE__ @@ -124,4 +141,5 @@ let baker_bls_test = let register ~protocols = baker_simple_test protocols ; baker_stresstest protocols ; + baker_stresstest_apply protocols ; baker_bls_test protocols -- GitLab From a9e9f48a121a9cefd089ce936810d13fc1191c2a Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Wed, 25 Jan 2023 14:16:10 +0100 Subject: [PATCH 12/12] Changes: add entries for the baker modifications --- CHANGES.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 266e524c3a84..27fb9e5078f3 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -59,6 +59,21 @@ Client Baker ----- +- Changed the baker default semantics so that it performs a light + validation of operations to classify them instead of fully applying + them. Hence, the block production is now more + time/cpu/disk-efficient. In this mode, application-dependent checks + are disabled. Setting the ``--force-apply`` flag on the command line + restores the previous behavior. (MR :gl:`!7490`) + +- **Breaking Change**: Disabled the verification of signature of + operations in the baker when baking a block. The baker must always + be provided operations with a valid signature, otherwise produced + blocks will be invalid and rejected by local nodes during their + injection. Default setups are not affected but external mempools + should make sure that their operations' signatures are correct. + (MR :gl:`!7490`) + Accuser ------- -- GitLab