From 123b557514c2747cab49ba1c7676db74bef4703d Mon Sep 17 00:00:00 2001 From: Adam Allombert-Goget Date: Thu, 5 Dec 2024 17:56:18 +0100 Subject: [PATCH 1/4] accuser: add double consensus ignored event --- .../lib_delegate/delegate_events.ml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/proto_alpha/lib_delegate/delegate_events.ml b/src/proto_alpha/lib_delegate/delegate_events.ml index 1efa1dd56e68..a65d269c5d21 100644 --- a/src/proto_alpha/lib_delegate/delegate_events.ml +++ b/src/proto_alpha/lib_delegate/delegate_events.ml @@ -65,6 +65,15 @@ module Denunciator = struct ~pp2:pp_ignore ("bytes", Data_encoding.bytes) + let double_attestation_ignored = + declare_2 + ~section + ~level + ~name:"double_attestation_ignored" + ~msg:"ignoring non-denunciable double attestation" + ("existing_attestation", Operation_hash.encoding) + ("new_attestation", Operation_hash.encoding) + let double_preattestation_detected = declare_2 ~alternative_color:Internal_event.Magenta @@ -86,6 +95,15 @@ module Denunciator = struct ~pp2:pp_ignore ("bytes", Data_encoding.bytes) + let double_preattestation_ignored = + declare_2 + ~section + ~level + ~name:"double_preattestation_ignored" + ~msg:"ignoring non-denunciable double pre-attestation" + ("existing_preattestation", Operation_hash.encoding) + ("new_preattestation", Operation_hash.encoding) + let double_consensus_already_denounced = declare_1 ~section -- GitLab From 4120f9a79b3a2f2bc9698a1c9c9b8b9126deb311 Mon Sep 17 00:00:00 2001 From: Adam Allombert-Goget Date: Mon, 10 Feb 2025 11:06:21 +0100 Subject: [PATCH 2/4] accuser: store protocol constants in the state --- .../lib_delegate/client_baking_denunciation.ml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/proto_alpha/lib_delegate/client_baking_denunciation.ml b/src/proto_alpha/lib_delegate/client_baking_denunciation.ml index ac69cc47a448..8d2b069a926d 100644 --- a/src/proto_alpha/lib_delegate/client_baking_denunciation.ml +++ b/src/proto_alpha/lib_delegate/client_baking_denunciation.ml @@ -69,6 +69,8 @@ type recorded_consensus_operations = { } type 'a state = { + (* Protocol constants *) + constants : Constants.t; (* Validators rights for the last preserved levels *) validators_rights : public_key_hash Slot.Map.t Validators_cache.t; (* Consensus operations seen so far *) @@ -100,13 +102,19 @@ type 'a denunciable_consensus_operation = | Attestation : Kind.attestation denunciable_consensus_operation | Preattestation : Kind.preattestation denunciable_consensus_operation -let create_state ~preserved_levels blocks_stream ops_stream ops_stream_stopper = +let create_state (cctxt : #Protocol_client_context.full) ~preserved_levels + blocks_stream ops_stream ops_stream_stopper = + let open Lwt_result_syntax in + let* constants = + Plugin.Alpha_services.Constants.all cctxt (cctxt#chain, cctxt#block) + in let clean_frequency = max 1 (preserved_levels / 10) in let validators_rights = Validators_cache.create (preserved_levels + 2) in (* We keep rights for [preserved_levels] in the past, and 2 levels in the future from [highest_level_encountered] *) - Lwt.return + return { + constants; validators_rights; consensus_operations_table = HLevel.create preserved_levels; blocks_table = HLevel.create preserved_levels; @@ -567,8 +575,9 @@ let create (cctxt : #Protocol_client_context.full) ?canceler ~preserved_levels let open Lwt_result_syntax in let*! () = B_Events.(emit daemon_setup) name in let* ops_stream, ops_stream_stopper = start_ops_monitor cctxt in - let*! state = + let* state = create_state + cctxt ~preserved_levels valid_blocks_stream ops_stream -- GitLab From bdf264483f86cfede88b46f46fb73accf2f2446e Mon Sep 17 00:00:00 2001 From: Adam Allombert-Goget Date: Mon, 10 Feb 2025 12:18:14 +0100 Subject: [PATCH 3/4] accuser: attestations with different slots are not denunced Under [aggregate_attestation] feature flag --- .../client_baking_denunciation.ml | 53 +++++++++++++------ 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/proto_alpha/lib_delegate/client_baking_denunciation.ml b/src/proto_alpha/lib_delegate/client_baking_denunciation.ml index 8d2b069a926d..a5bc5f71a262 100644 --- a/src/proto_alpha/lib_delegate/client_baking_denunciation.ml +++ b/src/proto_alpha/lib_delegate/client_baking_denunciation.ml @@ -227,6 +227,29 @@ let get_validator_rights state cctxt level = return validators | Some t -> return t +let events_of_kind (type kind) (op_kind : kind denunciable_consensus_operation) + = + match op_kind with + | Attestation -> + Events. + ( double_attestation_detected, + double_attestation_denounced, + double_attestation_ignored ) + | Preattestation -> + Events. + ( double_preattestation_detected, + double_preattestation_denounced, + double_preattestation_ignored ) + +let should_different_slots_be_denunced (type kind) state + (op_kind : kind denunciable_consensus_operation) = + match op_kind with + | Attestation -> + (* attestations with different slots are not denunced under + aggregate_attestation feature flag *) + not state.constants.parametric.aggregate_attestation + | _ -> true + let process_consensus_op (type kind) state cctxt (op_kind : kind denunciable_consensus_operation) (new_op : kind Operation.t) chain_id level round slot = @@ -271,19 +294,23 @@ let process_consensus_op (type kind) state cctxt {operation = new_op; previously_denounced_oph = None}) round_map) | Operation_seen {operation = existing_op; previously_denounced_oph} -> + let double_op_detected, double_op_denounced, double_op_ignored = + events_of_kind op_kind + in + let new_op_hash, existing_op_hash = + (Operation.hash new_op, Operation.hash existing_op) + in let existing_payload_hash = get_payload_hash op_kind existing_op in let new_payload_hash = get_payload_hash op_kind new_op in let existing_slot = get_slot op_kind existing_op in if Block_payload_hash.(existing_payload_hash <> new_payload_hash) || Slot.(existing_slot <> slot) + && should_different_slots_be_denunced state op_kind || Block_hash.(existing_op.shell.branch <> new_op.shell.branch) then ( (* Same level, round, and delegate, and: different payload hash OR different slot OR different branch *) - let new_op_hash, existing_op_hash = - (Operation.hash new_op, Operation.hash existing_op) - in let op1, op2 = if Operation_hash.(new_op_hash < existing_op_hash) then (new_op, existing_op) @@ -305,20 +332,8 @@ let process_consensus_op (type kind) state cctxt () in let bytes = Signature.concat bytes Signature.zero in - let* double_op_detected, double_op_denounced = - Events.( - match op_kind with - | Attestation -> - return - ( double_attestation_detected, - double_attestation_denounced ) - | Preattestation -> - return - ( double_preattestation_detected, - double_preattestation_denounced )) - in let*! () = - Events.(emit double_op_detected) (new_op_hash, existing_op_hash) + Events.(emit double_op_detected) (existing_op_hash, new_op_hash) in let* op_hash = Shell_services.Injection.private_operation cctxt ~chain bytes @@ -343,7 +358,11 @@ let process_consensus_op (type kind) state cctxt round_map) ; let*! () = Events.(emit double_op_denounced) (op_hash, bytes) in return_unit) - else return_unit) + else + let*! () = + Events.(emit double_op_ignored) (existing_op_hash, new_op_hash) + in + return_unit) let process_operations (cctxt : #Protocol_client_context.full) state (attestations : 'a list) ~packed_op chain_id = -- GitLab From 4fcc3d4606320a4e2cd349f7380e8e0ab64a6747 Mon Sep 17 00:00:00 2001 From: Adam Allombert-Goget Date: Thu, 5 Dec 2024 17:58:00 +0100 Subject: [PATCH 4/4] tezt/accuser: add test for double attestation denunciation --- tezt/tests/double_consensus.ml | 52 ++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/tezt/tests/double_consensus.ml b/tezt/tests/double_consensus.ml index 37f715a0fa1f..bb3a5e5ffc80 100644 --- a/tezt/tests/double_consensus.ml +++ b/tezt/tests/double_consensus.ml @@ -72,8 +72,10 @@ let double_attestation_init ?key:string list -> ?force:bool -> Client.t -> - unit Lwt.t) consensus_name protocol () = - let* node, client = Client.init_with_protocol ~protocol `Client () in + unit Lwt.t) ?parameter_file consensus_name protocol () = + let* node, client = + Client.init_with_protocol ?parameter_file ~protocol `Client () + in let* accuser = Accuser.init ~event_level:`Debug ~protocol node in let* () = repeat 5 (fun () -> Client.bake_for_and_wait client) in Log.info "Recover available slots for %s." Constant.bootstrap1.alias ; @@ -149,6 +151,41 @@ let double_consensus_wrong_slot let* () = waiter_already_denounced in unit +(** Adaptation of [double_consensus_wrong_slot] under [aggregate_attestations] + feature flag *) +let double_consensus_wrong_slot_feature_flag + (consensus_for, mk_consensus, _, consensus_name) protocol = + let* parameter_file = + Protocol.write_parameter_file + ~base:(Right (protocol, None)) + [(["aggregate_attestation"], `Bool true)] + in + let* (client, accuser), (branch, level, round, slots, block_payload_hash) = + double_attestation_init + ~parameter_file + consensus_for + consensus_name + protocol + () + in + Log.info "Inject an invalid %s and wait for denounciation" consensus_name ; + let op = + mk_consensus ~slot:(List.nth slots 1) ~level ~round ~block_payload_hash + in + let waiter = + Accuser.wait_for accuser "double_attestation_ignored.v0" (fun _ -> Some ()) + in + let* _ = + Operation.Consensus.inject + ~protocol + ~branch + ~signer:Constant.bootstrap1 + op + client + in + let* () = waiter in + unit + let attest_utils = ( Client.attest_for, (fun ~slot ~level ~round ~block_payload_hash -> @@ -178,6 +215,16 @@ let double_preattestation_wrong_slot = ~uses:(fun protocol -> [Protocol.accuser protocol]) @@ fun protocol -> double_consensus_wrong_slot preattest_utils protocol +let double_attestation_wrong_slot_feature_flag = + Protocol.register_test + ~__FILE__ + ~title:"double attestation using wrong slot under feature flag" + ~tags:[Tag.layer1; "double"; "attestation"; "accuser"; "slot"; "node"] + ~supports:(Protocol.From_protocol 023) + ~uses:(fun protocol -> [Protocol.accuser protocol]) + @@ fun protocol -> + double_consensus_wrong_slot_feature_flag attest_utils protocol + let double_consensus_wrong_block_payload_hash (consensus_for, mk_consensus, consensus_waiter, consensus_name) protocol = let* (client, accuser), (branch, level, round, slots, _block_payload_hash) = @@ -465,6 +512,7 @@ let operation_too_far_in_future = let register ~protocols = double_attestation_wrong_slot protocols ; double_preattestation_wrong_slot protocols ; + double_attestation_wrong_slot_feature_flag protocols ; double_attestation_wrong_block_payload_hash protocols ; double_preattestation_wrong_block_payload_hash protocols ; double_attestation_wrong_branch protocols ; -- GitLab