From f7355d014769eccea92e92f7f7b60d50e6cfb5c6 Mon Sep 17 00:00:00 2001 From: Marina Polubelova Date: Tue, 6 May 2025 11:31:02 +0200 Subject: [PATCH 1/3] Baker: issue attestation without DAL when there is no companion key Co-authored-by: Diane Gallois-Wong --- .../lib_delegate/baking_actions.ml | 114 +++++++++--------- src/proto_alpha/lib_delegate/baking_errors.ml | 19 +-- 2 files changed, 61 insertions(+), 72 deletions(-) diff --git a/src/proto_alpha/lib_delegate/baking_actions.ml b/src/proto_alpha/lib_delegate/baking_actions.ml index 1257539e613e..b50d578f8045 100644 --- a/src/proto_alpha/lib_delegate/baking_actions.ml +++ b/src/proto_alpha/lib_delegate/baking_actions.ml @@ -663,15 +663,31 @@ let forge_and_sign_consensus_vote global_state ~branch unsigned_consensus_vote : | Preattestation -> Operation.(to_watermark (Preattestation chain_id)) | Attestation -> Operation.(to_watermark (Attestation chain_id)) in - let (Contents_list contents) = + let bls_mode = + match delegate.consensus_key.public_key with + | Bls _ -> global_state.constants.parametric.aggregate_attestation + | _ -> false + in + let Contents_list contents, companion_key_opt = match vote_kind with | Preattestation -> - Contents_list (Single (Preattestation vote_consensus_content)) + (Contents_list (Single (Preattestation vote_consensus_content)), None) | Attestation -> - Contents_list - (Single - (Attestation - {consensus_content = vote_consensus_content; dal_content})) + let dal_content, companion_key_opt = + if not bls_mode then (dal_content, None) + else + match dal_content with + | None -> (dal_content, None) + | Some _ -> ( + match delegate.companion_key with + | None -> (* TODO: warning *) (None, None) + | Some companion_key -> (dal_content, Some companion_key)) + in + ( Contents_list + (Single + (Attestation + {consensus_content = vote_consensus_content; dal_content})), + companion_key_opt ) in let signing_request = match vote_kind with @@ -679,11 +695,6 @@ let forge_and_sign_consensus_vote global_state ~branch unsigned_consensus_vote : | Attestation -> `Attestation in let unsigned_operation = (shell, Contents_list contents) in - let bls_mode = - match delegate.consensus_key.public_key with - | Bls _ -> global_state.constants.parametric.aggregate_attestation - | _ -> false - in let encoding = if bls_mode then Operation.bls_mode_unsigned_encoding else Operation.unsigned_encoding @@ -702,49 +713,44 @@ let forge_and_sign_consensus_vote global_state ~branch unsigned_consensus_vote : unsigned_operation_bytes in let* signature = - if not bls_mode then return consensus_sig - else - match dal_content with - | None -> return consensus_sig - | Some {attestation = dal_attestation} -> ( - let* companion_key = - match delegate.companion_key with - | None -> - tzfail - (Baking_errors.Missing_bls_companion_key_for_dal - delegate.consensus_key) - | Some companion_key -> return companion_key - in - let sk_companion_uri = companion_key.secret_key_uri in - let* companion_sig = - sign - ?timeout:global_state.config.remote_calls_timeout - ~signing_request - cctxt - ~watermark - sk_companion_uri - unsigned_operation_bytes - in - match (consensus_sig, companion_sig) with - (* This if-else branch is for BLS mode so both signatures - should be BLS signatures *) - | Signature.Bls consensus_sig, Signature.Bls companion_sig -> ( - let dal_dependent_bls_sig_opt = - Alpha_context.Dal.Attestation.Dal_dependent_signing - .aggregate_sig - ~subgroup_check:false - ~consensus_sig - ~companion_sig - dal_attestation - in - match dal_dependent_bls_sig_opt with - | None -> tzfail Baking_errors.Signature_aggregation_failure - | Some dal_dependent_bls_sig_opt -> - return (Signature.Bls dal_dependent_bls_sig_opt : Signature.t) - ) - | Signature.Bls _, _ -> - tzfail (Baking_errors.Unexpected_signature_type companion_sig) - | _ -> tzfail (Baking_errors.Unexpected_signature_type consensus_sig)) + match (dal_content, companion_key_opt) with + | None, None -> return consensus_sig + | None, Some _ -> + (* should not be possible by construction of + companion_key_opt *) + return consensus_sig + | Some _, None -> + (* dal_content has been discarded from contents *) + return consensus_sig + | Some {attestation = dal_attestation}, Some companion_key -> ( + let sk_companion_uri = companion_key.secret_key_uri in + let* companion_sig = + sign + ?timeout:global_state.config.remote_calls_timeout + ~signing_request + cctxt + ~watermark + sk_companion_uri + unsigned_operation_bytes + in + match (consensus_sig, companion_sig) with + (* This if-else branch is for BLS mode so both signatures + should be BLS signatures *) + | Signature.Bls consensus_sig, Signature.Bls companion_sig -> ( + let dal_dependent_bls_sig_opt = + Alpha_context.Dal.Attestation.Dal_dependent_signing.aggregate_sig + ~subgroup_check:false + ~consensus_sig + ~companion_sig + dal_attestation + in + match dal_dependent_bls_sig_opt with + | None -> tzfail Baking_errors.Signature_aggregation_failure + | Some dal_dependent_bls_sig -> + return (Signature.Bls dal_dependent_bls_sig : Signature.t)) + | Signature.Bls _, _ -> + tzfail (Baking_errors.Unexpected_signature_type companion_sig) + | _ -> tzfail (Baking_errors.Unexpected_signature_type consensus_sig)) in let protocol_data = Operation_data {contents; signature = Some signature} in let signed_operation : Operation.packed = {shell; protocol_data} in diff --git a/src/proto_alpha/lib_delegate/baking_errors.ml b/src/proto_alpha/lib_delegate/baking_errors.ml index 16a802021f75..b55184dc5c5b 100644 --- a/src/proto_alpha/lib_delegate/baking_errors.ml +++ b/src/proto_alpha/lib_delegate/baking_errors.ml @@ -440,7 +440,6 @@ let () = type error += | Signature_aggregation_failure | Unexpected_signature_type of Signature.t - | Missing_bls_companion_key_for_dal of Baking_state_types.Key.t let () = register_error_kind @@ -465,20 +464,4 @@ let () = s) Data_encoding.(obj1 (req "signature" Signature.encoding)) (function Unexpected_signature_type s -> Some s | _ -> None) - (fun s -> Unexpected_signature_type s) ; - register_error_kind - `Permanent - ~id:"Baking_actions.Missing_bls_companion_key_for_dal" - ~title:"Missing a BLS companion key for DAL attestations" - ~description: - "The consensus key is a BLS key but is missing a companion key, so it \ - cannot sign a DAL attestation." - ~pp:(fun ppf s -> - Format.fprintf - ppf - "Expected a BLS companion key for the consensus key %a." - Baking_state_types.Key.pp - s) - Data_encoding.(obj1 (req "consensus_key" Baking_state_types.Key.encoding)) - (function Missing_bls_companion_key_for_dal ck -> Some ck | _ -> None) - (fun ck -> Missing_bls_companion_key_for_dal ck) + (fun s -> Unexpected_signature_type s) -- GitLab From e2469a3a06a460135dfef1762ba4eb42ec687a01 Mon Sep 17 00:00:00 2001 From: Marina Polubelova Date: Tue, 6 May 2025 11:45:40 +0200 Subject: [PATCH 2/3] Baker: issue warning when missing companion key for BLS attestation with DAL Co-authored-by: Diane Gallois-Wong --- .../lib_delegate/baking_actions.ml | 35 ++++++++++++------- src/proto_alpha/lib_delegate/baking_events.ml | 12 +++++++ 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/proto_alpha/lib_delegate/baking_actions.ml b/src/proto_alpha/lib_delegate/baking_actions.ml index b50d578f8045..d28e84214c1c 100644 --- a/src/proto_alpha/lib_delegate/baking_actions.ml +++ b/src/proto_alpha/lib_delegate/baking_actions.ml @@ -668,26 +668,37 @@ let forge_and_sign_consensus_vote global_state ~branch unsigned_consensus_vote : | Bls _ -> global_state.constants.parametric.aggregate_attestation | _ -> false in - let Contents_list contents, companion_key_opt = + let* Contents_list contents, companion_key_opt = match vote_kind with | Preattestation -> - (Contents_list (Single (Preattestation vote_consensus_content)), None) + return + (Contents_list (Single (Preattestation vote_consensus_content)), None) | Attestation -> - let dal_content, companion_key_opt = - if not bls_mode then (dal_content, None) + let* dal_content, companion_key_opt = + if not bls_mode then return (dal_content, None) else match dal_content with - | None -> (dal_content, None) + | None -> return (dal_content, None) | Some _ -> ( match delegate.companion_key with - | None -> (* TODO: warning *) (None, None) - | Some companion_key -> (dal_content, Some companion_key)) + | None -> + let*! () = + Events.( + emit + missing_companion_key_for_dal_with_bls + ( delegate.delegate_id, + Raw_level.to_int32 vote_consensus_content.level )) + in + return (None, None) + | Some companion_key -> return (dal_content, Some companion_key) + ) in - ( Contents_list - (Single - (Attestation - {consensus_content = vote_consensus_content; dal_content})), - companion_key_opt ) + return + ( Contents_list + (Single + (Attestation + {consensus_content = vote_consensus_content; dal_content})), + companion_key_opt ) in let signing_request = match vote_kind with diff --git a/src/proto_alpha/lib_delegate/baking_events.ml b/src/proto_alpha/lib_delegate/baking_events.ml index a38b63dcc05c..b2a41166f26c 100644 --- a/src/proto_alpha/lib_delegate/baking_events.ml +++ b/src/proto_alpha/lib_delegate/baking_events.ml @@ -956,6 +956,18 @@ module Actions = struct ("delegate", Baking_state_types.Delegate_id.encoding) ("attestation_level", Data_encoding.int32) + let missing_companion_key_for_dal_with_bls = + declare_2 + ~section + ~name:"missing_companion_key_for_dal_with_bls" + ~level:Warning + ~msg: + "Cannot issue an attestation with DAL because the BLS consensus key \ + has no corresponding companion key. Crafting the attestation without \ + DAL at level {attestation_level} for {delegate}" + ("delegate", Baking_state_types.Delegate_id.encoding) + ("attestation_level", Data_encoding.int32) + let synchronizing_round = declare_1 ~section -- GitLab From 400da73b5dc7f77d5cbee8cd93e4e0b3720cd434 Mon Sep 17 00:00:00 2001 From: Marina Polubelova Date: Tue, 6 May 2025 12:08:31 +0200 Subject: [PATCH 3/3] Baker: issue error when companion key missing from wallet Co-authored-by: Diane Gallois-Wong --- src/proto_alpha/lib_delegate/baking_state.ml | 68 ++++++++++++++------ 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/src/proto_alpha/lib_delegate/baking_state.ml b/src/proto_alpha/lib_delegate/baking_state.ml index 39fa60ca020a..7fdc0acbaf37 100644 --- a/src/proto_alpha/lib_delegate/baking_state.ml +++ b/src/proto_alpha/lib_delegate/baking_state.ml @@ -799,6 +799,17 @@ module Events = struct ~level:Warning ~msg:"found an outdated or corrupted baking state: discarding it" () + + let companion_key_is_not_in_wallet = + declare_2 + ~section:[Protocol.name; "baker"; "delegates"] + ~name:"companion_key_is_not_in_wallet" + ~level:Error + ~msg: + "Companion key {companion_key} is not provided in the wallet but \ + registered in the protocol for {delegate}" + ("delegate", Baking_state_types.Delegate_id.encoding) + ("companion_key", Environment.Bls.Public_key_hash.encoding) end type state_data = { @@ -986,9 +997,10 @@ module DelegateSet = struct end let delegate_slots attesting_rights delegates = + let open Lwt_syntax in let own_delegates = DelegateSet.of_list delegates in - let own_delegate_first_slots, own_delegate_slots, all_delegate_voting_power = - List.fold_left + let* own_delegate_first_slots, own_delegate_slots, all_delegate_voting_power = + Lwt_list.fold_left_s (fun (own_list, own_map, all_map) slot -> let { Plugin.RPC.Validators.consensus_key; @@ -1002,12 +1014,25 @@ let delegate_slots attesting_rights delegates = let first_slot = Stdlib.List.hd slots in let attesting_power = List.length slots in let all_map = SlotMap.add first_slot attesting_power all_map in - let own_list, own_map = + let* own_list, own_map = match DelegateSet.find_pkh consensus_key own_delegates with | Some consensus_key -> - let companion_key = - Option.bind companion_key (fun companion_key -> - DelegateSet.find_pkh (Bls companion_key) own_delegates) + let* companion_key = + match companion_key with + | None -> return None + | Some companion_key -> ( + match + DelegateSet.find_pkh (Bls companion_key) own_delegates + with + | None -> + let* () = + Events.( + emit + companion_key_is_not_in_wallet + (Delegate_id.of_pkh delegate, companion_key)) + in + return None + | Some companion_key -> return (Some companion_key)) in let attesting_slot = { @@ -1021,23 +1046,26 @@ let delegate_slots attesting_rights delegates = attesting_power; } in - ( attesting_slot :: own_list, - List.fold_left - (fun own_map slot -> SlotMap.add slot attesting_slot own_map) - own_map - slots ) - | None -> (own_list, own_map) + return + ( attesting_slot :: own_list, + List.fold_left + (fun own_map slot -> + SlotMap.add slot attesting_slot own_map) + own_map + slots ) + | None -> return (own_list, own_map) in - (own_list, own_map, all_map)) + return (own_list, own_map, all_map)) ([], SlotMap.empty, SlotMap.empty) attesting_rights in - Delegate_slots. - { - own_delegates = own_delegate_first_slots; - own_delegate_slots; - all_delegate_voting_power; - } + return + Delegate_slots. + { + own_delegates = own_delegate_first_slots; + own_delegate_slots; + all_delegate_voting_power; + } let compute_delegate_slots (cctxt : Protocol_client_context.full) ?(block = `Head 0) ~level ~chain delegates = @@ -1050,7 +1078,7 @@ let compute_delegate_slots (cctxt : Protocol_client_context.full) ~levels:[level] [@profiler.record_s {verbosity = Debug} "RPC: get attesting rights"]) in - let delegate_slots = + let*! delegate_slots = (delegate_slots attesting_rights delegates [@profiler.record_f {verbosity = Debug} "delegate_slots"]) -- GitLab