diff --git a/src/proto_020_PsParisC/lib_delegate/baking_actions.ml b/src/proto_020_PsParisC/lib_delegate/baking_actions.ml index 8ffaeb6252980132be5fb2f66a2c40054ed8dc41..0e63577655e3359ecc9465637039b511dd94e891 100644 --- a/src/proto_020_PsParisC/lib_delegate/baking_actions.ml +++ b/src/proto_020_PsParisC/lib_delegate/baking_actions.ml @@ -389,7 +389,7 @@ let prepare_block (global_state : global_state) (block_to_bake : block_to_bake) ~block:pred_block () [@profiler.record_s {verbosity = Info} "live blocks"]) in - let* {unsigned_block_header; operations} = + let* {unsigned_block_header; operations; manager_operations_infos} = (Block_forge.forge cctxt ~chain_id @@ -436,7 +436,15 @@ let prepare_block (global_state : global_state) (block_to_bake : block_to_bake) let baking_votes = {Per_block_votes.liquidity_baking_vote; adaptive_issuance_vote} in - return {signed_block_header; round; delegate; operations; baking_votes} + return + { + signed_block_header; + round; + delegate; + operations; + manager_operations_infos; + baking_votes; + } let only_if_dal_feature_enabled = let no_dal_node_warning_counter = ref 0 in @@ -777,7 +785,14 @@ let inject_consensus_votes state signed_consensus_vote_batch = let inject_block ?(force_injection = false) ?(asynchronous = true) state prepared_block = let open Lwt_result_syntax in - let {signed_block_header; round; delegate; operations; baking_votes} = + let { + signed_block_header; + round; + delegate; + operations; + manager_operations_infos; + baking_votes; + } = prepared_block in (* Cache last per-block votes to use in case of vote file errors *) @@ -817,7 +832,11 @@ let inject_block ?(force_injection = false) ?(asynchronous = true) state Events.( emit block_injected - (bh, signed_block_header.shell.level, round, delegate)) + ( bh, + signed_block_header.shell.level, + round, + delegate, + manager_operations_infos )) in return_unit in diff --git a/src/proto_020_PsParisC/lib_delegate/baking_events.ml b/src/proto_020_PsParisC/lib_delegate/baking_events.ml index 583ba7344a625d1d961c03b59a8039e68e08d4d8..27a904d4c5dbf856719a94430a827d9266754ad8 100644 --- a/src/proto_020_PsParisC/lib_delegate/baking_events.ml +++ b/src/proto_020_PsParisC/lib_delegate/baking_events.ml @@ -1010,21 +1010,33 @@ module Actions = struct ("delegate", Baking_state.consensus_key_and_delegate_encoding) let block_injected = - declare_4 + declare_5 ~alternative_color:Internal_event.Blue ~section ~name:"block_injected" ~level:Notice ~msg: - "block {block} at level {level}, round {round} injected for {delegate}" + "block {block} at level {level}, round {round} injected for \ + {delegate}{manager_operations_infos}" ~pp1:Block_hash.pp ~pp2:pp_int32 ~pp3:Round.pp ~pp4:Baking_state.pp_consensus_key_and_delegate + ~pp5: + (Format.pp_print_option + (fun fmt Baking_state.{manager_operation_number; total_fees} -> + Format.fprintf + fmt + " with %d manager operations summing %a μtz in fees" + manager_operation_number + pp_int64 + total_fees)) ("block", Block_hash.encoding) ("level", Data_encoding.int32) ("round", Round.encoding) ("delegate", Baking_state.consensus_key_and_delegate_encoding) + ( "manager_operations_infos", + Data_encoding.option Baking_state.manager_operations_infos_encoding ) let block_injection_failed = declare_2 diff --git a/src/proto_020_PsParisC/lib_delegate/baking_state.ml b/src/proto_020_PsParisC/lib_delegate/baking_state.ml index 7319e1cc63e79dd45334fa36b56ee0d40c074d4a..13578c56158d21a6ea697ee108ca2ca9e3d72139 100644 --- a/src/proto_020_PsParisC/lib_delegate/baking_state.ml +++ b/src/proto_020_PsParisC/lib_delegate/baking_state.ml @@ -281,11 +281,17 @@ type elected_block = { attestation_qc : Kind.attestation Operation.t list; } +type manager_operations_infos = { + manager_operation_number : int; + total_fees : Int64.t; +} + type prepared_block = { signed_block_header : block_header; round : Round.t; delegate : consensus_key_and_delegate; operations : Tezos_base.Operation.t list list; + manager_operations_infos : manager_operations_infos option; baking_votes : Per_block_votes_repr.per_block_votes; } @@ -723,21 +729,55 @@ let signed_consensus_vote_encoding = (req "unsigned_consensus_vote" unsigned_consensus_vote_encoding) (req "signed_operation" (dynamic_size Operation.encoding))) +let manager_operations_infos_encoding = + let open Data_encoding in + conv + (fun {manager_operation_number; total_fees} -> + (manager_operation_number, total_fees)) + (fun (manager_operation_number, total_fees) -> + {manager_operation_number; total_fees}) + (obj2 (req "manager_operation_number" int31) (req "total_fees" int64)) + let forge_event_encoding = let open Data_encoding in let prepared_block_encoding = conv - (fun {signed_block_header; round; delegate; operations; baking_votes} -> - (signed_block_header, round, delegate, operations, baking_votes)) - (fun (signed_block_header, round, delegate, operations, baking_votes) -> - {signed_block_header; round; delegate; operations; baking_votes}) - (obj5 + (fun { + signed_block_header; + round; + delegate; + operations; + manager_operations_infos; + baking_votes; + } -> + ( signed_block_header, + round, + delegate, + operations, + manager_operations_infos, + baking_votes )) + (fun ( signed_block_header, + round, + delegate, + operations, + manager_operations_infos, + baking_votes ) -> + { + signed_block_header; + round; + delegate; + operations; + manager_operations_infos; + baking_votes; + }) + (obj6 (req "header" (dynamic_size Block_header.encoding)) (req "round" Round.encoding) (req "delegate" consensus_key_and_delegate_encoding) (req "operations" (list (list (dynamic_size Tezos_base.Operation.encoding)))) + (opt "operations_infos" manager_operations_infos_encoding) (req "baking_votes" Per_block_votes.per_block_votes_encoding)) in union diff --git a/src/proto_020_PsParisC/lib_delegate/baking_state.mli b/src/proto_020_PsParisC/lib_delegate/baking_state.mli index 35e74c776d3b50448e507fbba598676a24645f8a..e8260a03c49295d948fb89bb2baf9e43865558da 100644 --- a/src/proto_020_PsParisC/lib_delegate/baking_state.mli +++ b/src/proto_020_PsParisC/lib_delegate/baking_state.mli @@ -156,11 +156,21 @@ type elected_block = { attestation_qc : Kind.attestation operation list; } +(** [manager_operations_infos] contains information about the number of manager + operations in the forged block and the summing fees from these operations *) +type manager_operations_infos = { + manager_operation_number : int; + total_fees : Int64.t; +} + +val manager_operations_infos_encoding : manager_operations_infos Data_encoding.t + type prepared_block = { signed_block_header : block_header; round : Round.t; delegate : consensus_key_and_delegate; operations : Tezos_base.Operation.t list list; + manager_operations_infos : manager_operations_infos option; baking_votes : Per_block_votes_repr.per_block_votes; } diff --git a/src/proto_020_PsParisC/lib_delegate/block_forge.ml b/src/proto_020_PsParisC/lib_delegate/block_forge.ml index 7338ce67d0dbafd11b6330210b319ac877f650d5..61985125b2fbbba9570149e1727c002221e20368 100644 --- a/src/proto_020_PsParisC/lib_delegate/block_forge.ml +++ b/src/proto_020_PsParisC/lib_delegate/block_forge.ml @@ -29,6 +29,7 @@ open Alpha_context type unsigned_block = { unsigned_block_header : Block_header.t; operations : Tezos_base.Operation.t list list; + manager_operations_infos : Baking_state.manager_operations_infos option; } type simulation_kind = @@ -198,7 +199,12 @@ let filter_via_node ~chain_id ~fees_config ~hard_gas_limit_per_block ~payload_round operation_hashes in - return (shell_header, operations, payload_hash) + let manager_operations_infos = + None + (* We do not compute operations infos from node results to avoid potential + costly computation *) + in + return (shell_header, operations, manager_operations_infos, payload_hash) (* [filter_with_context] filters operations using a local context via {!Operation_selection.filter_operations_with_simulation} and a fresh state @@ -221,7 +227,13 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block pred_info chain_id in - let* {Operation_selection.operations; validation_result; operations_hash; _} = + let* { + Operation_selection.operations; + validation_result; + operations_hash; + manager_operations_infos; + _; + } = Operation_selection.filter_operations_with_simulation incremental fees_config @@ -269,7 +281,7 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block ~payload_round operation_hashes in - return (shell_header, operations, payload_hash) + return (shell_header, operations, manager_operations_infos, 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 @@ -289,7 +301,12 @@ let apply_via_node ~chain_id ~faked_protocol_data ~timestamp operations in let operations = List.map (List.map convert_operation) operations in - return (shell_header, operations, payload_hash) + let manager_operations_infos = + None + (* We do not compute operations infos from node results to avoid potential + costly computation *) + in + return (shell_header, operations, manager_operations_infos, payload_hash) (* [apply_with_context] is similar to [filter_with_context] but filters consensus operations only from an [ordered_pool] via @@ -372,7 +389,12 @@ let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades ~locked_round:locked_round_when_no_validation_result in let operations = List.map (List.map convert_operation) operations in - return (shell_header, operations, payload_hash) + let manager_operations_infos = + None + (* We do not compute operations infos from node results to avoid potential + costly computation *) + in + return (shell_header, operations, manager_operations_infos, payload_hash) (* [forge] a new [unsigned_block] in accordance with [simulation_kind] and [simulation_mode] *) @@ -398,7 +420,7 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id Filter filtered_pool | Apply _ as x -> x in - let* shell_header, operations, payload_hash = + let* shell_header, operations, manager_operations_infos, payload_hash = match (simulation_mode, simulation_kind) with | Baking_state.Node, Filter operation_pool -> let faked_protocol_data = @@ -508,4 +530,4 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id protocol_data = {contents; signature = Signature.zero}; } in - return {unsigned_block_header; operations} + return {unsigned_block_header; operations; manager_operations_infos} diff --git a/src/proto_020_PsParisC/lib_delegate/block_forge.mli b/src/proto_020_PsParisC/lib_delegate/block_forge.mli index e85bc5f1fc61eb28fae159cb4a8b21f8dd6cbafe..81efcfcc71c314eb8b4b12d0e5a16c256a5c633e 100644 --- a/src/proto_020_PsParisC/lib_delegate/block_forge.mli +++ b/src/proto_020_PsParisC/lib_delegate/block_forge.mli @@ -29,6 +29,7 @@ open Alpha_context type unsigned_block = { unsigned_block_header : Block_header.t; operations : Tezos_base.Operation.t list list; + manager_operations_infos : Baking_state.manager_operations_infos option; } (** The simulation kind specifies whether the baker should first filter (and diff --git a/src/proto_020_PsParisC/lib_delegate/operation_selection.ml b/src/proto_020_PsParisC/lib_delegate/operation_selection.ml index d83f7c55369a129dc5f18718b7d795bfabfc7de8..313c727ca0cda5cbe8bd813c3f06e27802d270af 100644 --- a/src/proto_020_PsParisC/lib_delegate/operation_selection.ml +++ b/src/proto_020_PsParisC/lib_delegate/operation_selection.ml @@ -166,6 +166,7 @@ type simulation_result = { block_header_metadata : block_header_metadata option; operations : packed_operation list list; operations_hash : Operation_list_list_hash.t; + manager_operations_infos : Baking_state.manager_operations_infos option; } let validate_operation inc op = @@ -230,28 +231,33 @@ let filter_valid_managers_up_to_quota inc ~hard_gas_limit_per_block (ops, quota) = let open Lwt_syntax in let {Tezos_protocol_environment.max_size; max_op} = quota in - let rec loop (inc, curr_size, nb_ops, remaining_gas, acc) = function - | [] -> return (inc, List.rev acc) - | {op; size = op_size; gas = op_gas; _} :: l -> ( + let rec loop (inc, curr_size, nb_ops, total_fees, remaining_gas, acc) = + function + | [] -> return (inc, nb_ops, total_fees, List.rev acc) + | {op; size = op_size; gas = op_gas; fee; _} :: l -> ( match max_op with - | Some max_op when max_op = nb_ops + 1 -> return (inc, List.rev acc) + | Some max_op when max_op = nb_ops + 1 -> + return (inc, nb_ops, total_fees, List.rev acc) | None | Some _ -> ( if Gas.Arith.(remaining_gas < op_gas) then (* If the remaining available gas is lower than the considered operation's gas, we ignore this operation. *) - loop (inc, curr_size, nb_ops, remaining_gas, acc) l + loop (inc, curr_size, nb_ops, total_fees, remaining_gas, acc) l else let new_size = curr_size + op_size in if new_size > max_size then (* We ignore the operation if summing its size to the size of managers operations already validated is greater than the quota. *) - loop (inc, curr_size, nb_ops, remaining_gas, acc) l + loop (inc, curr_size, nb_ops, total_fees, remaining_gas, acc) l else let packed_op = Prioritized_operation.packed op in let* inc'_opt = validate_operation inc packed_op in match inc'_opt with - | None -> loop (inc, curr_size, nb_ops, remaining_gas, acc) l + | None -> + loop + (inc, curr_size, nb_ops, total_fees, remaining_gas, acc) + l | Some inc' -> let new_remaining_gas = Gas.Arith.sub remaining_gas op_gas @@ -260,11 +266,12 @@ let filter_valid_managers_up_to_quota inc ~hard_gas_limit_per_block (ops, quota) ( inc', new_size, succ nb_ops, + Int64.add total_fees (Tez.to_mutez fee), new_remaining_gas, packed_op :: acc ) l)) in - loop (inc, 0, 0, hard_gas_limit_per_block, []) ops + loop (inc, 0, 0, Int64.zero, hard_gas_limit_per_block, []) ops let filter_operations_with_simulation initial_inc fees_config ~hard_gas_limit_per_block {consensus; votes; anonymous; managers} = @@ -300,7 +307,7 @@ let filter_operations_with_simulation initial_inc fees_config ~minimal_nanotez_per_byte managers in - let*! inc, managers = + let*! inc, manager_operation_number, total_fees, managers = filter_valid_managers_up_to_quota inc ~hard_gas_limit_per_block @@ -324,6 +331,7 @@ let filter_operations_with_simulation initial_inc fees_config block_header_metadata = Some block_header_metadata; operations; operations_hash; + manager_operations_infos = Some {manager_operation_number; total_fees}; } | None -> return @@ -332,6 +340,7 @@ let filter_operations_with_simulation initial_inc fees_config block_header_metadata = None; operations; operations_hash; + manager_operations_infos = None; } let filter_valid_operations_up_to_quota_without_simulation (ops, quota) = diff --git a/src/proto_020_PsParisC/lib_delegate/operation_selection.mli b/src/proto_020_PsParisC/lib_delegate/operation_selection.mli index d83fd0dda258c5c7017567d9cabe24a2e98a714e..af0ca76580963d75ff5a7c1c4bdd937d6b00f175 100644 --- a/src/proto_020_PsParisC/lib_delegate/operation_selection.mli +++ b/src/proto_020_PsParisC/lib_delegate/operation_selection.mli @@ -32,6 +32,7 @@ type simulation_result = { block_header_metadata : Apply_results.block_metadata option; operations : packed_operation list list; operations_hash : Operation_list_list_hash.t; + manager_operations_infos : Baking_state.manager_operations_infos option; } (** [filter_operations_with_simulation incremental fees_config diff --git a/src/proto_021_PsQuebec/lib_delegate/baking_actions.ml b/src/proto_021_PsQuebec/lib_delegate/baking_actions.ml index 4211c302bccd8cd73aca88510e16f67b3eab5551..1cc0ab1e1561601d6c81d2ffd4b2c680d8181ddb 100644 --- a/src/proto_021_PsQuebec/lib_delegate/baking_actions.ml +++ b/src/proto_021_PsQuebec/lib_delegate/baking_actions.ml @@ -391,7 +391,7 @@ let prepare_block (global_state : global_state) (block_to_bake : block_to_bake) ~block:pred_block () [@profiler.record_s {verbosity = Info} "live blocks"]) in - let* {unsigned_block_header; operations} = + let* {unsigned_block_header; operations; manager_operations_infos} = (Block_forge.forge cctxt ~chain_id @@ -438,7 +438,15 @@ let prepare_block (global_state : global_state) (block_to_bake : block_to_bake) let baking_votes = {Per_block_votes.liquidity_baking_vote; adaptive_issuance_vote} in - return {signed_block_header; round; delegate; operations; baking_votes} + return + { + signed_block_header; + round; + delegate; + operations; + manager_operations_infos; + baking_votes; + } let only_if_dal_feature_enabled = let no_dal_node_warning_counter = ref 0 in @@ -779,7 +787,14 @@ let inject_consensus_votes state signed_consensus_vote_batch = let inject_block ?(force_injection = false) ?(asynchronous = true) state prepared_block = let open Lwt_result_syntax in - let {signed_block_header; round; delegate; operations; baking_votes} = + let { + signed_block_header; + round; + delegate; + operations; + manager_operations_infos; + baking_votes; + } = prepared_block in (* Cache last per-block votes to use in case of vote file errors *) @@ -819,7 +834,11 @@ let inject_block ?(force_injection = false) ?(asynchronous = true) state Events.( emit block_injected - (bh, signed_block_header.shell.level, round, delegate)) + ( bh, + signed_block_header.shell.level, + round, + delegate, + manager_operations_infos )) in return_unit in diff --git a/src/proto_021_PsQuebec/lib_delegate/baking_events.ml b/src/proto_021_PsQuebec/lib_delegate/baking_events.ml index 3b0dfceb64583e5c936c25763a73b57b8a629c8b..85f1afa35327562cfcffd0ee7239d24f7ab8402b 100644 --- a/src/proto_021_PsQuebec/lib_delegate/baking_events.ml +++ b/src/proto_021_PsQuebec/lib_delegate/baking_events.ml @@ -1013,21 +1013,33 @@ module Actions = struct ("delegate", Baking_state.consensus_key_and_delegate_encoding) let block_injected = - declare_4 + declare_5 ~alternative_color:Internal_event.Blue ~section ~name:"block_injected" ~level:Notice ~msg: - "block {block} at level {level}, round {round} injected for {delegate}" + "block {block} at level {level}, round {round} injected for \ + {delegate}{manager_operations_infos}" ~pp1:Block_hash.pp ~pp2:pp_int32 ~pp3:Round.pp ~pp4:Baking_state.pp_consensus_key_and_delegate + ~pp5: + (Format.pp_print_option + (fun fmt Baking_state.{manager_operation_number; total_fees} -> + Format.fprintf + fmt + " with %d manager operations summing %a μtz in fees" + manager_operation_number + pp_int64 + total_fees)) ("block", Block_hash.encoding) ("level", Data_encoding.int32) ("round", Round.encoding) ("delegate", Baking_state.consensus_key_and_delegate_encoding) + ( "manager_operations_infos", + Data_encoding.option Baking_state.manager_operations_infos_encoding ) let block_injection_failed = declare_2 diff --git a/src/proto_021_PsQuebec/lib_delegate/baking_state.ml b/src/proto_021_PsQuebec/lib_delegate/baking_state.ml index 7319e1cc63e79dd45334fa36b56ee0d40c074d4a..13578c56158d21a6ea697ee108ca2ca9e3d72139 100644 --- a/src/proto_021_PsQuebec/lib_delegate/baking_state.ml +++ b/src/proto_021_PsQuebec/lib_delegate/baking_state.ml @@ -281,11 +281,17 @@ type elected_block = { attestation_qc : Kind.attestation Operation.t list; } +type manager_operations_infos = { + manager_operation_number : int; + total_fees : Int64.t; +} + type prepared_block = { signed_block_header : block_header; round : Round.t; delegate : consensus_key_and_delegate; operations : Tezos_base.Operation.t list list; + manager_operations_infos : manager_operations_infos option; baking_votes : Per_block_votes_repr.per_block_votes; } @@ -723,21 +729,55 @@ let signed_consensus_vote_encoding = (req "unsigned_consensus_vote" unsigned_consensus_vote_encoding) (req "signed_operation" (dynamic_size Operation.encoding))) +let manager_operations_infos_encoding = + let open Data_encoding in + conv + (fun {manager_operation_number; total_fees} -> + (manager_operation_number, total_fees)) + (fun (manager_operation_number, total_fees) -> + {manager_operation_number; total_fees}) + (obj2 (req "manager_operation_number" int31) (req "total_fees" int64)) + let forge_event_encoding = let open Data_encoding in let prepared_block_encoding = conv - (fun {signed_block_header; round; delegate; operations; baking_votes} -> - (signed_block_header, round, delegate, operations, baking_votes)) - (fun (signed_block_header, round, delegate, operations, baking_votes) -> - {signed_block_header; round; delegate; operations; baking_votes}) - (obj5 + (fun { + signed_block_header; + round; + delegate; + operations; + manager_operations_infos; + baking_votes; + } -> + ( signed_block_header, + round, + delegate, + operations, + manager_operations_infos, + baking_votes )) + (fun ( signed_block_header, + round, + delegate, + operations, + manager_operations_infos, + baking_votes ) -> + { + signed_block_header; + round; + delegate; + operations; + manager_operations_infos; + baking_votes; + }) + (obj6 (req "header" (dynamic_size Block_header.encoding)) (req "round" Round.encoding) (req "delegate" consensus_key_and_delegate_encoding) (req "operations" (list (list (dynamic_size Tezos_base.Operation.encoding)))) + (opt "operations_infos" manager_operations_infos_encoding) (req "baking_votes" Per_block_votes.per_block_votes_encoding)) in union diff --git a/src/proto_021_PsQuebec/lib_delegate/baking_state.mli b/src/proto_021_PsQuebec/lib_delegate/baking_state.mli index 59c662b14f9cac405bdbdd7694760d535aaa8e1f..b44af70c3658ed47217032ff7e0d70d1c0d0b4b3 100644 --- a/src/proto_021_PsQuebec/lib_delegate/baking_state.mli +++ b/src/proto_021_PsQuebec/lib_delegate/baking_state.mli @@ -156,11 +156,21 @@ type elected_block = { attestation_qc : Kind.attestation operation list; } +(** [manager_operations_infos] contains information about the number of manager + operations in the forged block and the summing fees from these operations *) +type manager_operations_infos = { + manager_operation_number : int; + total_fees : Int64.t; +} + +val manager_operations_infos_encoding : manager_operations_infos Data_encoding.t + type prepared_block = { signed_block_header : block_header; round : Round.t; delegate : consensus_key_and_delegate; operations : Tezos_base.Operation.t list list; + manager_operations_infos : manager_operations_infos option; baking_votes : Per_block_votes_repr.per_block_votes; } diff --git a/src/proto_021_PsQuebec/lib_delegate/block_forge.ml b/src/proto_021_PsQuebec/lib_delegate/block_forge.ml index 7338ce67d0dbafd11b6330210b319ac877f650d5..61985125b2fbbba9570149e1727c002221e20368 100644 --- a/src/proto_021_PsQuebec/lib_delegate/block_forge.ml +++ b/src/proto_021_PsQuebec/lib_delegate/block_forge.ml @@ -29,6 +29,7 @@ open Alpha_context type unsigned_block = { unsigned_block_header : Block_header.t; operations : Tezos_base.Operation.t list list; + manager_operations_infos : Baking_state.manager_operations_infos option; } type simulation_kind = @@ -198,7 +199,12 @@ let filter_via_node ~chain_id ~fees_config ~hard_gas_limit_per_block ~payload_round operation_hashes in - return (shell_header, operations, payload_hash) + let manager_operations_infos = + None + (* We do not compute operations infos from node results to avoid potential + costly computation *) + in + return (shell_header, operations, manager_operations_infos, payload_hash) (* [filter_with_context] filters operations using a local context via {!Operation_selection.filter_operations_with_simulation} and a fresh state @@ -221,7 +227,13 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block pred_info chain_id in - let* {Operation_selection.operations; validation_result; operations_hash; _} = + let* { + Operation_selection.operations; + validation_result; + operations_hash; + manager_operations_infos; + _; + } = Operation_selection.filter_operations_with_simulation incremental fees_config @@ -269,7 +281,7 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block ~payload_round operation_hashes in - return (shell_header, operations, payload_hash) + return (shell_header, operations, manager_operations_infos, 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 @@ -289,7 +301,12 @@ let apply_via_node ~chain_id ~faked_protocol_data ~timestamp operations in let operations = List.map (List.map convert_operation) operations in - return (shell_header, operations, payload_hash) + let manager_operations_infos = + None + (* We do not compute operations infos from node results to avoid potential + costly computation *) + in + return (shell_header, operations, manager_operations_infos, payload_hash) (* [apply_with_context] is similar to [filter_with_context] but filters consensus operations only from an [ordered_pool] via @@ -372,7 +389,12 @@ let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades ~locked_round:locked_round_when_no_validation_result in let operations = List.map (List.map convert_operation) operations in - return (shell_header, operations, payload_hash) + let manager_operations_infos = + None + (* We do not compute operations infos from node results to avoid potential + costly computation *) + in + return (shell_header, operations, manager_operations_infos, payload_hash) (* [forge] a new [unsigned_block] in accordance with [simulation_kind] and [simulation_mode] *) @@ -398,7 +420,7 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id Filter filtered_pool | Apply _ as x -> x in - let* shell_header, operations, payload_hash = + let* shell_header, operations, manager_operations_infos, payload_hash = match (simulation_mode, simulation_kind) with | Baking_state.Node, Filter operation_pool -> let faked_protocol_data = @@ -508,4 +530,4 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id protocol_data = {contents; signature = Signature.zero}; } in - return {unsigned_block_header; operations} + return {unsigned_block_header; operations; manager_operations_infos} diff --git a/src/proto_021_PsQuebec/lib_delegate/block_forge.mli b/src/proto_021_PsQuebec/lib_delegate/block_forge.mli index e85bc5f1fc61eb28fae159cb4a8b21f8dd6cbafe..81efcfcc71c314eb8b4b12d0e5a16c256a5c633e 100644 --- a/src/proto_021_PsQuebec/lib_delegate/block_forge.mli +++ b/src/proto_021_PsQuebec/lib_delegate/block_forge.mli @@ -29,6 +29,7 @@ open Alpha_context type unsigned_block = { unsigned_block_header : Block_header.t; operations : Tezos_base.Operation.t list list; + manager_operations_infos : Baking_state.manager_operations_infos option; } (** The simulation kind specifies whether the baker should first filter (and diff --git a/src/proto_021_PsQuebec/lib_delegate/operation_selection.ml b/src/proto_021_PsQuebec/lib_delegate/operation_selection.ml index d83f7c55369a129dc5f18718b7d795bfabfc7de8..313c727ca0cda5cbe8bd813c3f06e27802d270af 100644 --- a/src/proto_021_PsQuebec/lib_delegate/operation_selection.ml +++ b/src/proto_021_PsQuebec/lib_delegate/operation_selection.ml @@ -166,6 +166,7 @@ type simulation_result = { block_header_metadata : block_header_metadata option; operations : packed_operation list list; operations_hash : Operation_list_list_hash.t; + manager_operations_infos : Baking_state.manager_operations_infos option; } let validate_operation inc op = @@ -230,28 +231,33 @@ let filter_valid_managers_up_to_quota inc ~hard_gas_limit_per_block (ops, quota) = let open Lwt_syntax in let {Tezos_protocol_environment.max_size; max_op} = quota in - let rec loop (inc, curr_size, nb_ops, remaining_gas, acc) = function - | [] -> return (inc, List.rev acc) - | {op; size = op_size; gas = op_gas; _} :: l -> ( + let rec loop (inc, curr_size, nb_ops, total_fees, remaining_gas, acc) = + function + | [] -> return (inc, nb_ops, total_fees, List.rev acc) + | {op; size = op_size; gas = op_gas; fee; _} :: l -> ( match max_op with - | Some max_op when max_op = nb_ops + 1 -> return (inc, List.rev acc) + | Some max_op when max_op = nb_ops + 1 -> + return (inc, nb_ops, total_fees, List.rev acc) | None | Some _ -> ( if Gas.Arith.(remaining_gas < op_gas) then (* If the remaining available gas is lower than the considered operation's gas, we ignore this operation. *) - loop (inc, curr_size, nb_ops, remaining_gas, acc) l + loop (inc, curr_size, nb_ops, total_fees, remaining_gas, acc) l else let new_size = curr_size + op_size in if new_size > max_size then (* We ignore the operation if summing its size to the size of managers operations already validated is greater than the quota. *) - loop (inc, curr_size, nb_ops, remaining_gas, acc) l + loop (inc, curr_size, nb_ops, total_fees, remaining_gas, acc) l else let packed_op = Prioritized_operation.packed op in let* inc'_opt = validate_operation inc packed_op in match inc'_opt with - | None -> loop (inc, curr_size, nb_ops, remaining_gas, acc) l + | None -> + loop + (inc, curr_size, nb_ops, total_fees, remaining_gas, acc) + l | Some inc' -> let new_remaining_gas = Gas.Arith.sub remaining_gas op_gas @@ -260,11 +266,12 @@ let filter_valid_managers_up_to_quota inc ~hard_gas_limit_per_block (ops, quota) ( inc', new_size, succ nb_ops, + Int64.add total_fees (Tez.to_mutez fee), new_remaining_gas, packed_op :: acc ) l)) in - loop (inc, 0, 0, hard_gas_limit_per_block, []) ops + loop (inc, 0, 0, Int64.zero, hard_gas_limit_per_block, []) ops let filter_operations_with_simulation initial_inc fees_config ~hard_gas_limit_per_block {consensus; votes; anonymous; managers} = @@ -300,7 +307,7 @@ let filter_operations_with_simulation initial_inc fees_config ~minimal_nanotez_per_byte managers in - let*! inc, managers = + let*! inc, manager_operation_number, total_fees, managers = filter_valid_managers_up_to_quota inc ~hard_gas_limit_per_block @@ -324,6 +331,7 @@ let filter_operations_with_simulation initial_inc fees_config block_header_metadata = Some block_header_metadata; operations; operations_hash; + manager_operations_infos = Some {manager_operation_number; total_fees}; } | None -> return @@ -332,6 +340,7 @@ let filter_operations_with_simulation initial_inc fees_config block_header_metadata = None; operations; operations_hash; + manager_operations_infos = None; } let filter_valid_operations_up_to_quota_without_simulation (ops, quota) = diff --git a/src/proto_021_PsQuebec/lib_delegate/operation_selection.mli b/src/proto_021_PsQuebec/lib_delegate/operation_selection.mli index d83fd0dda258c5c7017567d9cabe24a2e98a714e..af0ca76580963d75ff5a7c1c4bdd937d6b00f175 100644 --- a/src/proto_021_PsQuebec/lib_delegate/operation_selection.mli +++ b/src/proto_021_PsQuebec/lib_delegate/operation_selection.mli @@ -32,6 +32,7 @@ type simulation_result = { block_header_metadata : Apply_results.block_metadata option; operations : packed_operation list list; operations_hash : Operation_list_list_hash.t; + manager_operations_infos : Baking_state.manager_operations_infos option; } (** [filter_operations_with_simulation incremental fees_config diff --git a/src/proto_alpha/lib_delegate/baking_actions.ml b/src/proto_alpha/lib_delegate/baking_actions.ml index c452a3b78a41a7a3a5049f47be62f3eb10c05dd5..fcca27f9629fdcd5213067f3aac9f6512b30913e 100644 --- a/src/proto_alpha/lib_delegate/baking_actions.ml +++ b/src/proto_alpha/lib_delegate/baking_actions.ml @@ -399,7 +399,7 @@ let prepare_block (global_state : global_state) (block_to_bake : block_to_bake) ~block:pred_block () [@profiler.record_s {verbosity = Info} "live blocks"]) in - let* {unsigned_block_header; operations} = + let* {unsigned_block_header; operations; manager_operations_infos} = (Block_forge.forge cctxt ~chain_id @@ -446,7 +446,15 @@ let prepare_block (global_state : global_state) (block_to_bake : block_to_bake) let baking_votes = {Per_block_votes.liquidity_baking_vote; adaptive_issuance_vote} in - return {signed_block_header; round; delegate; operations; baking_votes} + return + { + signed_block_header; + round; + delegate; + operations; + manager_operations_infos; + baking_votes; + } let only_if_dal_feature_enabled = let no_dal_node_warning_counter = ref 0 in @@ -790,7 +798,14 @@ let inject_consensus_votes state signed_consensus_vote_batch = let inject_block ?(force_injection = false) ?(asynchronous = true) state prepared_block = let open Lwt_result_syntax in - let {signed_block_header; round; delegate; operations; baking_votes} = + let { + signed_block_header; + round; + delegate; + operations; + manager_operations_infos; + baking_votes; + } = prepared_block in (* Cache last per-block votes to use in case of vote file errors *) @@ -830,7 +845,11 @@ let inject_block ?(force_injection = false) ?(asynchronous = true) state Events.( emit block_injected - (bh, signed_block_header.shell.level, round, delegate)) + ( bh, + signed_block_header.shell.level, + round, + delegate, + manager_operations_infos )) in return_unit in diff --git a/src/proto_alpha/lib_delegate/baking_events.ml b/src/proto_alpha/lib_delegate/baking_events.ml index 2d18a35865f034390a623f166a0494a16c2f76a6..958ba6f3e962b3c0acdf491eb657f3ab7b5e55dd 100644 --- a/src/proto_alpha/lib_delegate/baking_events.ml +++ b/src/proto_alpha/lib_delegate/baking_events.ml @@ -992,21 +992,33 @@ module Actions = struct ("delegate", Baking_state.consensus_key_and_delegate_encoding) let block_injected = - declare_4 + declare_5 ~alternative_color:Internal_event.Blue ~section ~name:"block_injected" ~level:Notice ~msg: - "block {block} at level {level}, round {round} injected for {delegate}" + "block {block} at level {level}, round {round} injected for \ + {delegate}{manager_operations_infos}" ~pp1:Block_hash.pp ~pp2:pp_int32 ~pp3:Round.pp ~pp4:Baking_state.pp_consensus_key_and_delegate + ~pp5: + (Format.pp_print_option + (fun fmt Baking_state.{manager_operation_number; total_fees} -> + Format.fprintf + fmt + " with %d manager operations summing %a μtz in fees" + manager_operation_number + pp_int64 + total_fees)) ("block", Block_hash.encoding) ("level", Data_encoding.int32) ("round", Round.encoding) ("delegate", Baking_state.consensus_key_and_delegate_encoding) + ( "manager_operations_infos", + Data_encoding.option Baking_state.manager_operations_infos_encoding ) let block_injection_failed = declare_2 diff --git a/src/proto_alpha/lib_delegate/baking_state.ml b/src/proto_alpha/lib_delegate/baking_state.ml index 121a62d6a17da833d06bb663393e1df96bc6e2c2..fc9e2f0bea0d4bd1b18392e70f8c855f8621b7c3 100644 --- a/src/proto_alpha/lib_delegate/baking_state.ml +++ b/src/proto_alpha/lib_delegate/baking_state.ml @@ -273,11 +273,17 @@ type elected_block = { attestation_qc : Kind.attestation Operation.t list; } +type manager_operations_infos = { + manager_operation_number : int; + total_fees : Int64.t; +} + type prepared_block = { signed_block_header : block_header; round : Round.t; delegate : consensus_key_and_delegate; operations : Tezos_base.Operation.t list list; + manager_operations_infos : manager_operations_infos option; baking_votes : Per_block_votes_repr.per_block_votes; } @@ -741,21 +747,55 @@ let signed_consensus_vote_encoding = (req "unsigned_consensus_vote" unsigned_consensus_vote_encoding) (req "signed_operation" (dynamic_size Operation.encoding))) +let manager_operations_infos_encoding = + let open Data_encoding in + conv + (fun {manager_operation_number; total_fees} -> + (manager_operation_number, total_fees)) + (fun (manager_operation_number, total_fees) -> + {manager_operation_number; total_fees}) + (obj2 (req "manager_operation_number" int31) (req "total_fees" int64)) + let forge_event_encoding = let open Data_encoding in let prepared_block_encoding = conv - (fun {signed_block_header; round; delegate; operations; baking_votes} -> - (signed_block_header, round, delegate, operations, baking_votes)) - (fun (signed_block_header, round, delegate, operations, baking_votes) -> - {signed_block_header; round; delegate; operations; baking_votes}) - (obj5 + (fun { + signed_block_header; + round; + delegate; + operations; + manager_operations_infos; + baking_votes; + } -> + ( signed_block_header, + round, + delegate, + operations, + manager_operations_infos, + baking_votes )) + (fun ( signed_block_header, + round, + delegate, + operations, + manager_operations_infos, + baking_votes ) -> + { + signed_block_header; + round; + delegate; + operations; + manager_operations_infos; + baking_votes; + }) + (obj6 (req "header" (dynamic_size Block_header.encoding)) (req "round" Round.encoding) (req "delegate" consensus_key_and_delegate_encoding) (req "operations" (list (list (dynamic_size Tezos_base.Operation.encoding)))) + (opt "operations_infos" manager_operations_infos_encoding) (req "baking_votes" Per_block_votes.per_block_votes_encoding)) in union diff --git a/src/proto_alpha/lib_delegate/baking_state.mli b/src/proto_alpha/lib_delegate/baking_state.mli index 7986a8b583c1383bf2ca78677c7430d52b6f5cc1..8da69e3b16874db223d0eb534476b9d660520ca8 100644 --- a/src/proto_alpha/lib_delegate/baking_state.mli +++ b/src/proto_alpha/lib_delegate/baking_state.mli @@ -379,6 +379,15 @@ type forge_request = unsigned_attestations : unsigned_consensus_vote_batch; } +(** [manager_operations_infos] contains information about the number of manager + operations in the forged block and the summing fees from these operations *) +type manager_operations_infos = { + manager_operation_number : int; + total_fees : Int64.t; +} + +val manager_operations_infos_encoding : manager_operations_infos Data_encoding.t + (** [prepared_block] type returned by the forge worker and that contains all information useful for block injection. *) type prepared_block = { @@ -386,6 +395,7 @@ type prepared_block = { round : Round.t; delegate : consensus_key_and_delegate; operations : Tezos_base.Operation.t list list; + manager_operations_infos : manager_operations_infos option; baking_votes : Per_block_votes_repr.per_block_votes; } diff --git a/src/proto_alpha/lib_delegate/block_forge.ml b/src/proto_alpha/lib_delegate/block_forge.ml index 7338ce67d0dbafd11b6330210b319ac877f650d5..61985125b2fbbba9570149e1727c002221e20368 100644 --- a/src/proto_alpha/lib_delegate/block_forge.ml +++ b/src/proto_alpha/lib_delegate/block_forge.ml @@ -29,6 +29,7 @@ open Alpha_context type unsigned_block = { unsigned_block_header : Block_header.t; operations : Tezos_base.Operation.t list list; + manager_operations_infos : Baking_state.manager_operations_infos option; } type simulation_kind = @@ -198,7 +199,12 @@ let filter_via_node ~chain_id ~fees_config ~hard_gas_limit_per_block ~payload_round operation_hashes in - return (shell_header, operations, payload_hash) + let manager_operations_infos = + None + (* We do not compute operations infos from node results to avoid potential + costly computation *) + in + return (shell_header, operations, manager_operations_infos, payload_hash) (* [filter_with_context] filters operations using a local context via {!Operation_selection.filter_operations_with_simulation} and a fresh state @@ -221,7 +227,13 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block pred_info chain_id in - let* {Operation_selection.operations; validation_result; operations_hash; _} = + let* { + Operation_selection.operations; + validation_result; + operations_hash; + manager_operations_infos; + _; + } = Operation_selection.filter_operations_with_simulation incremental fees_config @@ -269,7 +281,7 @@ let filter_with_context ~chain_id ~fees_config ~hard_gas_limit_per_block ~payload_round operation_hashes in - return (shell_header, operations, payload_hash) + return (shell_header, operations, manager_operations_infos, 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 @@ -289,7 +301,12 @@ let apply_via_node ~chain_id ~faked_protocol_data ~timestamp operations in let operations = List.map (List.map convert_operation) operations in - return (shell_header, operations, payload_hash) + let manager_operations_infos = + None + (* We do not compute operations infos from node results to avoid potential + costly computation *) + in + return (shell_header, operations, manager_operations_infos, payload_hash) (* [apply_with_context] is similar to [filter_with_context] but filters consensus operations only from an [ordered_pool] via @@ -372,7 +389,12 @@ let apply_with_context ~chain_id ~faked_protocol_data ~user_activated_upgrades ~locked_round:locked_round_when_no_validation_result in let operations = List.map (List.map convert_operation) operations in - return (shell_header, operations, payload_hash) + let manager_operations_infos = + None + (* We do not compute operations infos from node results to avoid potential + costly computation *) + in + return (shell_header, operations, manager_operations_infos, payload_hash) (* [forge] a new [unsigned_block] in accordance with [simulation_kind] and [simulation_mode] *) @@ -398,7 +420,7 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id Filter filtered_pool | Apply _ as x -> x in - let* shell_header, operations, payload_hash = + let* shell_header, operations, manager_operations_infos, payload_hash = match (simulation_mode, simulation_kind) with | Baking_state.Node, Filter operation_pool -> let faked_protocol_data = @@ -508,4 +530,4 @@ let forge (cctxt : #Protocol_client_context.full) ~chain_id protocol_data = {contents; signature = Signature.zero}; } in - return {unsigned_block_header; operations} + return {unsigned_block_header; operations; manager_operations_infos} diff --git a/src/proto_alpha/lib_delegate/block_forge.mli b/src/proto_alpha/lib_delegate/block_forge.mli index e85bc5f1fc61eb28fae159cb4a8b21f8dd6cbafe..81efcfcc71c314eb8b4b12d0e5a16c256a5c633e 100644 --- a/src/proto_alpha/lib_delegate/block_forge.mli +++ b/src/proto_alpha/lib_delegate/block_forge.mli @@ -29,6 +29,7 @@ open Alpha_context type unsigned_block = { unsigned_block_header : Block_header.t; operations : Tezos_base.Operation.t list list; + manager_operations_infos : Baking_state.manager_operations_infos option; } (** The simulation kind specifies whether the baker should first filter (and diff --git a/src/proto_alpha/lib_delegate/operation_selection.ml b/src/proto_alpha/lib_delegate/operation_selection.ml index d83f7c55369a129dc5f18718b7d795bfabfc7de8..313c727ca0cda5cbe8bd813c3f06e27802d270af 100644 --- a/src/proto_alpha/lib_delegate/operation_selection.ml +++ b/src/proto_alpha/lib_delegate/operation_selection.ml @@ -166,6 +166,7 @@ type simulation_result = { block_header_metadata : block_header_metadata option; operations : packed_operation list list; operations_hash : Operation_list_list_hash.t; + manager_operations_infos : Baking_state.manager_operations_infos option; } let validate_operation inc op = @@ -230,28 +231,33 @@ let filter_valid_managers_up_to_quota inc ~hard_gas_limit_per_block (ops, quota) = let open Lwt_syntax in let {Tezos_protocol_environment.max_size; max_op} = quota in - let rec loop (inc, curr_size, nb_ops, remaining_gas, acc) = function - | [] -> return (inc, List.rev acc) - | {op; size = op_size; gas = op_gas; _} :: l -> ( + let rec loop (inc, curr_size, nb_ops, total_fees, remaining_gas, acc) = + function + | [] -> return (inc, nb_ops, total_fees, List.rev acc) + | {op; size = op_size; gas = op_gas; fee; _} :: l -> ( match max_op with - | Some max_op when max_op = nb_ops + 1 -> return (inc, List.rev acc) + | Some max_op when max_op = nb_ops + 1 -> + return (inc, nb_ops, total_fees, List.rev acc) | None | Some _ -> ( if Gas.Arith.(remaining_gas < op_gas) then (* If the remaining available gas is lower than the considered operation's gas, we ignore this operation. *) - loop (inc, curr_size, nb_ops, remaining_gas, acc) l + loop (inc, curr_size, nb_ops, total_fees, remaining_gas, acc) l else let new_size = curr_size + op_size in if new_size > max_size then (* We ignore the operation if summing its size to the size of managers operations already validated is greater than the quota. *) - loop (inc, curr_size, nb_ops, remaining_gas, acc) l + loop (inc, curr_size, nb_ops, total_fees, remaining_gas, acc) l else let packed_op = Prioritized_operation.packed op in let* inc'_opt = validate_operation inc packed_op in match inc'_opt with - | None -> loop (inc, curr_size, nb_ops, remaining_gas, acc) l + | None -> + loop + (inc, curr_size, nb_ops, total_fees, remaining_gas, acc) + l | Some inc' -> let new_remaining_gas = Gas.Arith.sub remaining_gas op_gas @@ -260,11 +266,12 @@ let filter_valid_managers_up_to_quota inc ~hard_gas_limit_per_block (ops, quota) ( inc', new_size, succ nb_ops, + Int64.add total_fees (Tez.to_mutez fee), new_remaining_gas, packed_op :: acc ) l)) in - loop (inc, 0, 0, hard_gas_limit_per_block, []) ops + loop (inc, 0, 0, Int64.zero, hard_gas_limit_per_block, []) ops let filter_operations_with_simulation initial_inc fees_config ~hard_gas_limit_per_block {consensus; votes; anonymous; managers} = @@ -300,7 +307,7 @@ let filter_operations_with_simulation initial_inc fees_config ~minimal_nanotez_per_byte managers in - let*! inc, managers = + let*! inc, manager_operation_number, total_fees, managers = filter_valid_managers_up_to_quota inc ~hard_gas_limit_per_block @@ -324,6 +331,7 @@ let filter_operations_with_simulation initial_inc fees_config block_header_metadata = Some block_header_metadata; operations; operations_hash; + manager_operations_infos = Some {manager_operation_number; total_fees}; } | None -> return @@ -332,6 +340,7 @@ let filter_operations_with_simulation initial_inc fees_config block_header_metadata = None; operations; operations_hash; + manager_operations_infos = None; } let filter_valid_operations_up_to_quota_without_simulation (ops, quota) = diff --git a/src/proto_alpha/lib_delegate/operation_selection.mli b/src/proto_alpha/lib_delegate/operation_selection.mli index d83fd0dda258c5c7017567d9cabe24a2e98a714e..af0ca76580963d75ff5a7c1c4bdd937d6b00f175 100644 --- a/src/proto_alpha/lib_delegate/operation_selection.mli +++ b/src/proto_alpha/lib_delegate/operation_selection.mli @@ -32,6 +32,7 @@ type simulation_result = { block_header_metadata : Apply_results.block_metadata option; operations : packed_operation list list; operations_hash : Operation_list_list_hash.t; + manager_operations_infos : Baking_state.manager_operations_infos option; } (** [filter_operations_with_simulation incremental fees_config