From 6ea2425027ef64be12694066e00f0be28e927c9d Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Thu, 25 Jan 2024 16:14:05 +0100 Subject: [PATCH 1/6] Proto: remove misbehaviour cycle --- .../delegate_slashed_deposits_storage.ml | 38 ++++++++----------- .../lib_protocol/denunciations_repr.ml | 30 ++++----------- .../lib_protocol/denunciations_repr.mli | 13 +------ .../test/helpers/adaptive_issuance_helpers.ml | 18 ++++----- .../test_adaptive_issuance_roundtrip.ml | 10 ++--- 5 files changed, 37 insertions(+), 72 deletions(-) diff --git a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml index 6c042a7c1aef..61698ca5c82c 100644 --- a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml @@ -116,22 +116,11 @@ let punish_double_signing ctxt ~operation_hash Storage.Current_cycle_denunciations.find ctxt delegate in let denunciations = Option.value denunciations_opt ~default:[] in - let cycle = - if Cycle_repr.(level.cycle = current_cycle) then - Denunciations_repr.Current - else if Cycle_repr.(succ level.cycle = current_cycle) then - Denunciations_repr.Previous - else - (* [max_slashing_period = 2] according to - {!Constants_repr.check_constants}. *) - assert false - in let denunciations = Denunciations_repr.add operation_hash rewarded misbehaviour - cycle denunciations in let*! ctxt = @@ -192,8 +181,7 @@ let apply_and_clear_current_cycle_denunciations ctxt = let+ ctxt, percentage, balance_updates = List.fold_left_es (fun (ctxt, percentage, balance_updates) - Denunciations_repr. - {operation_hash; rewarded; misbehaviour; misbehaviour_cycle} -> + Denunciations_repr.{operation_hash; rewarded; misbehaviour} -> let slashing_percentage = match misbehaviour.kind with | Double_baking -> @@ -205,15 +193,21 @@ let apply_and_clear_current_cycle_denunciations ctxt = .percentage_of_frozen_deposits_slashed_per_double_attestation ctxt in - let ( misbehaviour_cycle, - get_initial_frozen_deposits_of_misbehaviour_cycle ) = - match misbehaviour_cycle with - | Current -> - (current_cycle, Delegate_storage.initial_frozen_deposits) - | Previous -> - ( previous_cycle, - Delegate_storage.initial_frozen_deposits_of_previous_cycle - ) + let misbehaviour_cycle = + (Level_repr.level_from_raw + ~cycle_eras:(Raw_context.cycle_eras ctxt) + misbehaviour.level) + .cycle + in + let get_initial_frozen_deposits_of_misbehaviour_cycle = + if Cycle_repr.(equal current_cycle misbehaviour_cycle) then + Delegate_storage.initial_frozen_deposits + else if Cycle_repr.(equal previous_cycle misbehaviour_cycle) + then Delegate_storage.initial_frozen_deposits_of_previous_cycle + else fun _ _ -> return Tez_repr.zero + (* (denunciation applied too late) + We could assert false, but we can also be permissive + while keeping the same invariants *) in let* frozen_deposits = let* initial_amount = diff --git a/src/proto_alpha/lib_protocol/denunciations_repr.ml b/src/proto_alpha/lib_protocol/denunciations_repr.ml index c0a3b9d09bc6..63b7aa6633d9 100644 --- a/src/proto_alpha/lib_protocol/denunciations_repr.ml +++ b/src/proto_alpha/lib_protocol/denunciations_repr.ml @@ -5,41 +5,27 @@ (* *) (*****************************************************************************) -type misbehaviour_cycle = Current | Previous - -let misbehaviour_cycle_encoding = - let open Data_encoding in - conv_with_guard - (function Current -> 0 | Previous -> 1) - (function - | 0 -> Ok Current - | 1 -> Ok Previous - | _ -> Error "Invalid misbehaviour cycle") - int8 - type item = { operation_hash : Operation_hash.t; rewarded : Signature.public_key_hash; misbehaviour : Misbehaviour_repr.t; - misbehaviour_cycle : misbehaviour_cycle; } let item_encoding = let open Data_encoding in conv - (fun {operation_hash; rewarded; misbehaviour; misbehaviour_cycle} -> - (operation_hash, rewarded, misbehaviour, misbehaviour_cycle)) - (fun (operation_hash, rewarded, misbehaviour, misbehaviour_cycle) -> - {operation_hash; rewarded; misbehaviour; misbehaviour_cycle}) - (obj4 + (fun {operation_hash; rewarded; misbehaviour} -> + (operation_hash, rewarded, misbehaviour)) + (fun (operation_hash, rewarded, misbehaviour) -> + {operation_hash; rewarded; misbehaviour}) + (obj3 (req "operation_hash" Operation_hash.encoding) (req "rewarded" Signature.Public_key_hash.encoding) - (req "misbehaviour" Misbehaviour_repr.encoding) - (req "misbehaviour_cycle" misbehaviour_cycle_encoding)) + (req "misbehaviour" Misbehaviour_repr.encoding)) type t = item list let encoding = Data_encoding.list item_encoding -let add operation_hash rewarded misbehaviour misbehaviour_cycle list = - list @ [{operation_hash; rewarded; misbehaviour; misbehaviour_cycle}] +let add operation_hash rewarded misbehaviour list = + list @ [{operation_hash; rewarded; misbehaviour}] diff --git a/src/proto_alpha/lib_protocol/denunciations_repr.mli b/src/proto_alpha/lib_protocol/denunciations_repr.mli index 75ca75a11a81..867529e7a1b2 100644 --- a/src/proto_alpha/lib_protocol/denunciations_repr.mli +++ b/src/proto_alpha/lib_protocol/denunciations_repr.mli @@ -5,11 +5,6 @@ (* *) (*****************************************************************************) -(* Given that [max_slashing_period = 2] (see {!Constants_repr.check_constants}), - a misbehaviour can only have happened during the same cycle as the - denunciation or the preceding one. *) -type misbehaviour_cycle = Current | Previous - (** Internal representation of a pending denunciation, meaning that a denunciation operation has been observed in an applied block, but the corresponding slashing has not happened yet. @@ -21,7 +16,6 @@ type item = { operation_hash : Operation_hash.t; rewarded : Signature.public_key_hash; misbehaviour : Misbehaviour_repr.t; - misbehaviour_cycle : misbehaviour_cycle; } (** List of all pending denunciations about the same culprit. *) @@ -33,9 +27,4 @@ val encoding : t Data_encoding.t (** Append a new pending denunciation to the end of the given list. *) val add : - Operation_hash.t -> - Signature.public_key_hash -> - Misbehaviour_repr.t -> - misbehaviour_cycle -> - t -> - t + Operation_hash.t -> Signature.public_key_hash -> Misbehaviour_repr.t -> t -> t diff --git a/src/proto_alpha/lib_protocol/test/helpers/adaptive_issuance_helpers.ml b/src/proto_alpha/lib_protocol/test/helpers/adaptive_issuance_helpers.ml index 96db7e3a82cf..58862eb7a96a 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/adaptive_issuance_helpers.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/adaptive_issuance_helpers.ml @@ -1013,9 +1013,8 @@ let balance_and_total_balance_of_account account_name account_map = let apply_slashing ( culprit, - Protocol.Denunciations_repr. - {rewarded; misbehaviour; misbehaviour_cycle; operation_hash = _} ) - current_cycle constants account_map = + Protocol.Denunciations_repr.{rewarded; misbehaviour; operation_hash = _} + ) constants account_map = let find_account_name_from_pkh_exn pkh account_map = match Option.map @@ -1030,15 +1029,14 @@ let apply_slashing | None -> assert false | Some x -> x in - let culprit_name = find_account_name_from_pkh_exn culprit account_map in - let rewarded_name = find_account_name_from_pkh_exn rewarded account_map in let slashed_cycle = - match misbehaviour_cycle with - | Current -> current_cycle - | Previous -> - Cycle.pred current_cycle - |> Option.value_f ~default:(fun _ -> assert false) + Block.current_cycle_of_level + ~blocks_per_cycle: + constants.Protocol.Alpha_context.Constants.Parametric.blocks_per_cycle + ~current_level:(Protocol.Raw_level_repr.to_int32 misbehaviour.level) in + let culprit_name = find_account_name_from_pkh_exn culprit account_map in + let rewarded_name = find_account_name_from_pkh_exn rewarded account_map in let slashed_pct = match misbehaviour.kind with | Double_baking -> diff --git a/src/proto_alpha/lib_protocol/test/integration/test_adaptive_issuance_roundtrip.ml b/src/proto_alpha/lib_protocol/test/integration/test_adaptive_issuance_roundtrip.ml index 6631a08c47ff..7e54b42ec6ed 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_adaptive_issuance_roundtrip.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_adaptive_issuance_roundtrip.ml @@ -406,13 +406,11 @@ module State = struct let apply_slashing ( culprit, - Protocol.Denunciations_repr. - {rewarded; misbehaviour; misbehaviour_cycle; operation_hash} ) - current_cycle (state : t) : t * Tez.t = + Protocol.Denunciations_repr.{rewarded; misbehaviour; operation_hash} ) + (state : t) : t * Tez.t = let account_map, total_burnt = apply_slashing - (culprit, {rewarded; misbehaviour; misbehaviour_cycle; operation_hash}) - current_cycle + (culprit, {rewarded; misbehaviour; operation_hash}) state.constants state.account_map in @@ -429,7 +427,7 @@ module State = struct let state, total_burnt = List.fold_left (fun (acc_state, acc_total) x -> - let state, burnt = apply_slashing x current_cycle acc_state in + let state, burnt = apply_slashing x acc_state in (state, Tez.(acc_total +! burnt))) (state, Tez.zero) state.pending_slashes -- GitLab From e8740da96a08758775fdab2e0b3abb0f310549f7 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Thu, 25 Jan 2024 16:14:41 +0100 Subject: [PATCH 2/6] Proto: slash later with ns_enable --- .../delegate_slashed_deposits_storage.ml | 59 ++++++++++++++++--- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml index 61698ca5c82c..692ab7eb7994 100644 --- a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml @@ -171,13 +171,37 @@ let apply_and_clear_current_cycle_denunciations ctxt = let+ amount_to_burn = Tez_repr.(punishing_amount -? reward) in {reward; amount_to_burn} in - let* ctxt, slashings, balance_updates = + let* ctxt, slashings, balance_updates, remaining_denunciations = Storage.Current_cycle_denunciations.fold ctxt ~order:`Undefined - ~init:(Ok (ctxt, Signature.Public_key_hash.Map.empty, [])) + ~init:(Ok (ctxt, Signature.Public_key_hash.Map.empty, [], [])) ~f:(fun delegate denunciations acc -> - let*? ctxt, slashings, balance_updates = acc in + let*? ctxt, slashings, balance_updates, remaining_denunciations = acc in + (* Since the [max_slashing_period] is 2, and we want to apply denunciations at the + end of this period, we "delay" the current cycle's misbehaviour's denunciations, + while we apply the older denunciations. + Indeed, we apply denunciations in the cycle following the misbehaviour, so that + the time between the misbehaviour and the slashing is at most + [max_slashing_period = 2] cycles. *) + let denunciations_to_apply, denunciations_to_delay = + if not (Constants_storage.adaptive_issuance_ns_enable ctxt) then + (denunciations, []) + else + List.partition + (fun denunciation -> + let level = + denunciation.Denunciations_repr.misbehaviour.level + in + let misb_cycle = + (Level_repr.level_from_raw + ~cycle_eras:(Raw_context.cycle_eras ctxt) + level) + .cycle + in + Cycle_repr.(misb_cycle < current_cycle)) + denunciations + in let+ ctxt, percentage, balance_updates = List.fold_left_es (fun (ctxt, percentage, balance_updates) @@ -200,11 +224,12 @@ let apply_and_clear_current_cycle_denunciations ctxt = .cycle in let get_initial_frozen_deposits_of_misbehaviour_cycle = - if Cycle_repr.(equal current_cycle misbehaviour_cycle) then + if Cycle_repr.equal current_cycle misbehaviour_cycle then Delegate_storage.initial_frozen_deposits - else if Cycle_repr.(equal previous_cycle misbehaviour_cycle) - then Delegate_storage.initial_frozen_deposits_of_previous_cycle - else fun _ _ -> return Tez_repr.zero + else if Cycle_repr.equal previous_cycle misbehaviour_cycle then + Delegate_storage.initial_frozen_deposits_of_previous_cycle + else fun (_ : Raw_context.t) (_ : Signature.public_key_hash) -> + return Tez_repr.zero (* (denunciation applied too late) We could assert false, but we can also be permissive while keeping the same invariants *) @@ -305,12 +330,28 @@ let apply_and_clear_current_cycle_denunciations ctxt = punish_balance_updates @ reward_balance_updates @ balance_updates )) (ctxt, Int_percentage.p0, balance_updates) - denunciations + denunciations_to_apply in let slashings = Signature.Public_key_hash.Map.add delegate percentage slashings in - (ctxt, slashings, balance_updates)) + ( ctxt, + slashings, + balance_updates, + (delegate, denunciations_to_delay) :: remaining_denunciations )) in let*! ctxt = Storage.Current_cycle_denunciations.clear ctxt in + let*! ctxt = + List.fold_left_s + (fun ctxt (delegate, current_cycle_denunciations) -> + match current_cycle_denunciations with + | [] -> Lwt.return ctxt + | _ -> + Storage.Current_cycle_denunciations.add + ctxt + delegate + current_cycle_denunciations) + ctxt + remaining_denunciations + in return (ctxt, slashings, balance_updates) -- GitLab From 1d15fab6e9b5c99421234032bf42cd3cac109cb9 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Thu, 25 Jan 2024 16:15:04 +0100 Subject: [PATCH 3/6] Proto/RPC: update RPC with late slashing --- .../lib_protocol/unstake_requests_storage.ml | 108 +++++++++++------- 1 file changed, 64 insertions(+), 44 deletions(-) diff --git a/src/proto_alpha/lib_protocol/unstake_requests_storage.ml b/src/proto_alpha/lib_protocol/unstake_requests_storage.ml index 80ba7b60eb80..e41f18d93816 100644 --- a/src/proto_alpha/lib_protocol/unstake_requests_storage.ml +++ b/src/proto_alpha/lib_protocol/unstake_requests_storage.ml @@ -169,51 +169,71 @@ module For_RPC = struct (Contract_repr.Implicit delegate) in let slashing_history = Option.value slashing_history_opt ~default:[] in - (* Remove slashes that haven't been applied yet *) - let slashing_history = - if not is_last_of_cycle then - List.filter - (fun (cycle, _) -> Cycle_repr.(cycle < current_level.cycle)) - slashing_history - else slashing_history - in - (* We get the current cycle's denunciations for events in the previous cycle, - and remove them from the slashing events (since they haven't been applied yet). - Another solution would be to add the slashing cycle in Storage.Contract.Slashed_deposits, - but since it's only used for this specific RPC, let's not. *) - let* denunciations_opt = - Storage.Current_cycle_denunciations.find ctxt delegate - in - let denunciations = Option.value denunciations_opt ~default:[] in - let not_yet_slashed_pct = - if is_last_of_cycle then Int_percentage.p0 - else - List.fold_left - (fun acc Denunciations_repr.{misbehaviour; misbehaviour_cycle; _} -> - match (misbehaviour_cycle, misbehaviour.kind) with - | Current, _ -> acc - | Previous, Double_baking -> - Int_percentage.add_bounded - acc - (Constants_storage - .percentage_of_frozen_deposits_slashed_per_double_baking - ctxt) - | Previous, Double_attesting -> - Int_percentage.add_bounded + let* slashing_history = + if not (Constants_storage.adaptive_issuance_ns_enable ctxt) then + (* Remove slashes that haven't been applied yet *) + let slashing_history = + if not is_last_of_cycle then + List.filter + (fun (cycle, _) -> Cycle_repr.(cycle < current_level.cycle)) + slashing_history + else slashing_history + in + (* We get the current cycle's denunciations for events in the previous cycle, + and remove them from the slashing events (since they haven't been applied yet). + Another solution would be to add the slashing cycle in Storage.Contract.Slashed_deposits, + but since it's only used for this specific RPC, let's not. *) + let* denunciations_opt = + Storage.Current_cycle_denunciations.find ctxt delegate + in + let denunciations = Option.value denunciations_opt ~default:[] in + let not_yet_slashed_pct = + if is_last_of_cycle then Int_percentage.p0 + else + List.fold_left + (fun acc Denunciations_repr.{misbehaviour; _} -> + let misbehaviour_cycle = + (Level_repr.level_from_raw + ~cycle_eras:(Raw_context.cycle_eras ctxt) + misbehaviour.level) + .cycle + in + if Cycle_repr.(misbehaviour_cycle = current_level.cycle) then acc - (Constants_storage - .percentage_of_frozen_deposits_slashed_per_double_attestation - ctxt)) - Int_percentage.p0 - denunciations - in - let slashing_history = - List.map - (fun (cycle, pct) -> - if Cycle_repr.(succ cycle = current_level.cycle) then - (cycle, Int_percentage.(sub_bounded pct not_yet_slashed_pct)) - else (cycle, pct)) - slashing_history + else + match misbehaviour.kind with + | Double_baking -> + Int_percentage.add_bounded + acc + (Constants_storage + .percentage_of_frozen_deposits_slashed_per_double_baking + ctxt) + | Double_attesting -> + Int_percentage.add_bounded + acc + (Constants_storage + .percentage_of_frozen_deposits_slashed_per_double_attestation + ctxt)) + Int_percentage.p0 + denunciations + in + return + @@ List.map + (fun (cycle, pct) -> + if Cycle_repr.(succ cycle = current_level.cycle) then + (cycle, Int_percentage.(sub_bounded pct not_yet_slashed_pct)) + else (cycle, pct)) + slashing_history + else if not is_last_of_cycle then + return + @@ List.filter + (fun (cycle, _) -> Cycle_repr.(succ cycle < current_level.cycle)) + slashing_history + else + return + @@ List.filter + (fun (cycle, _) -> Cycle_repr.(cycle < current_level.cycle)) + slashing_history in List.map_es (fun (request_cycle, request_amount) -> -- GitLab From 42b534b3fc2df4a8988dfaed4e2ba60d827f2c65 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Thu, 25 Jan 2024 16:15:35 +0100 Subject: [PATCH 4/6] Proto/tests: update tests --- .../consensus/test_double_attestation.ml | 10 +- .../test_adaptive_issuance_roundtrip.ml | 301 ++++++++++-------- 2 files changed, 174 insertions(+), 137 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_attestation.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_attestation.ml index c21cc1c48454..480b70f1b952 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_attestation.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_attestation.ml @@ -52,14 +52,15 @@ let block_fork b = (blk_a, blk_b) (* Checks that there is exactly one denunciation for the given delegate *) -let check_denunciations ~(cycle : Denunciations_repr.misbehaviour_cycle) b - delegate = +let check_denunciations ~(level : Raw_level.t) b delegate = let open Lwt_result_syntax in let* denunciations = Context.get_denunciations (B b) in match denunciations with | [(d, item)] when Signature.Public_key_hash.equal d delegate -> assert (item.Denunciations_repr.misbehaviour.kind = Double_attesting) ; - assert (item.Denunciations_repr.misbehaviour_cycle = cycle) ; + assert ( + Raw_level_repr.to_int32 item.Denunciations_repr.misbehaviour.level + = Raw_level.to_int32 level) ; return_unit | _ -> assert false @@ -131,7 +132,8 @@ let test_valid_double_attestation_evidence () = let* () = check_empty_denunciations blk_a in let* blk_final = Block.bake ~policy:(By_account baker) ~operation blk_a in (* Check that parts of the frozen deposits are slashed *) - let* () = check_denunciations ~cycle:Current blk_final delegate in + let*? double_level = Context.get_level (B blk_a) in + let* () = check_denunciations ~level:double_level blk_final delegate in let* frozen_deposits_before = Context.Delegate.current_frozen_deposits (B blk_a) delegate in diff --git a/src/proto_alpha/lib_protocol/test/integration/test_adaptive_issuance_roundtrip.ml b/src/proto_alpha/lib_protocol/test/integration/test_adaptive_issuance_roundtrip.ml index 7e54b42ec6ed..852e5ad932e2 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_adaptive_issuance_roundtrip.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_adaptive_issuance_roundtrip.ml @@ -424,16 +424,38 @@ module State = struct (state, total_burnt) let apply_all_slashes_at_cycle_end current_cycle (state : t) : t = + let to_slash_later, to_slash_now = + if + not + state.constants + .Protocol.Alpha_context.Constants.Parametric.adaptive_issuance + .ns_enable + then ([], state.pending_slashes) + else + List.partition + (fun (_, Protocol.Denunciations_repr.{misbehaviour; _}) -> + let cycle = + Block.current_cycle_of_level + ~blocks_per_cycle: + state.constants + .Protocol.Alpha_context.Constants.Parametric + .blocks_per_cycle + ~current_level: + (Protocol.Raw_level_repr.to_int32 misbehaviour.level) + in + Cycle.(cycle = current_cycle)) + state.pending_slashes + in let state, total_burnt = List.fold_left (fun (acc_state, acc_total) x -> let state, burnt = apply_slashing x acc_state in (state, Tez.(acc_total +! burnt))) (state, Tez.zero) - state.pending_slashes + to_slash_now in let total_supply = Tez.(state.total_supply -! total_burnt) in - {state with pending_slashes = []; total_supply} + {state with pending_slashes = to_slash_later; total_supply} (** Given an account name and new account state, updates [state] accordingly Preferably use other specific update functions *) @@ -1086,101 +1108,111 @@ let exec_op f = (* ======== Definition of basic actions ======== *) (** Initialize the test, given some initial parameters *) -let begin_test ~activate_ai ?(burn_rewards = false) +let begin_test ~activate_ai ?(burn_rewards = false) ?(ns_enable_fork = false) ?(constants : Protocol.Alpha_context.Constants.Parametric.t option) ?(constants_list : (string * Protocol.Alpha_context.Constants.Parametric.t) list option) delegates_name_list : (unit, t) scenarios = - (match (constants, constants_list) with - | None, None -> Stdlib.failwith "No constants provided to begin_test" - | Some _, Some _ -> - Stdlib.failwith - "You cannot provide ~constants and ~constants_list to begin_test" - | None, Some constants_list -> list_to_branch constants_list - | Some constants, None -> Action (fun () -> return constants)) - --> exec (fun (constants : Protocol.Alpha_context.Constants.Parametric.t) -> - let open Lwt_result_syntax in - Log.info ~color:begin_end_color "-- Begin test --" ; - let bootstrap = "__bootstrap__" in - let delegates_name_list = bootstrap :: delegates_name_list in - (* Override threshold value if activate *) - let constants = - if activate_ai then ( - Log.info ~color:event_color "Setting ai threshold to 0" ; - { - constants with - adaptive_issuance = - { - constants.adaptive_issuance with - launch_ema_threshold = 0l; - activation_vote_enable = true; - }; - }) - else constants - in - let n = List.length delegates_name_list in - let* block, delegates = Context.init_with_constants_n constants n in - let*? init_level = Context.get_level (B block) in - let init_staked = Tez.of_mutez 200_000_000_000L in - let*? account_map = - List.fold_left2 - ~when_different_lengths: - [Inconsistent_number_of_bootstrap_accounts] - (fun account_map name contract -> - let liquid = - Tez.(Account.default_initial_balance -! init_staked) - in - let frozen_deposits = Frozen_tez.init init_staked name name in - let frozen_rights = - List.fold_left - (fun map cycle -> CycleMap.add cycle init_staked map) - CycleMap.empty - Cycle.(root ---> add root constants.preserved_cycles) - in - let pkh = Context.Contract.pkh contract in - let account = - init_account - ~delegate:name - ~pkh - ~contract - ~parameters:default_params - ~liquid - ~frozen_deposits - ~frozen_rights - () - in - let account_map = String.Map.add name account account_map in - let balance, total_balance = - balance_and_total_balance_of_account name account_map - in - Log.debug "Initial balance for %s:\n%a" name balance_pp balance ; - Log.debug "Initial total balance: %a" Tez.pp total_balance ; - account_map) - String.Map.empty - delegates_name_list - delegates - in - let* total_supply = Context.get_total_supply (B block) in - let state = - State. - { - account_map; - total_supply; - constants; - param_requests = []; - activate_ai; - baking_policy = None; - last_level_rewards = init_level; - snapshot_balances = String.Map.empty; - saved_rate = None; - burn_rewards; - pending_operations = []; - pending_slashes = []; - double_signings = []; - } - in - let* () = check_all_balances block state in - return (block, state)) + let f ns_enable = + (match (constants, constants_list) with + | None, None -> Stdlib.failwith "No constants provided to begin_test" + | Some _, Some _ -> + Stdlib.failwith + "You cannot provide ~constants and ~constants_list to begin_test" + | None, Some constants_list -> list_to_branch constants_list + | Some constants, None -> Action (fun () -> return constants)) + --> exec (fun (constants : Protocol.Alpha_context.Constants.Parametric.t) -> + let open Lwt_result_syntax in + Log.info ~color:begin_end_color "-- Begin test --" ; + let bootstrap = "__bootstrap__" in + let delegates_name_list = bootstrap :: delegates_name_list in + (* Override threshold value if activate *) + let constants = + if activate_ai then ( + Log.info ~color:event_color "Setting ai threshold to 0" ; + { + constants with + adaptive_issuance = + { + constants.adaptive_issuance with + launch_ema_threshold = 0l; + activation_vote_enable = true; + ns_enable; + }; + }) + else constants + in + let n = List.length delegates_name_list in + let* block, delegates = Context.init_with_constants_n constants n in + let*? init_level = Context.get_level (B block) in + let init_staked = Tez.of_mutez 200_000_000_000L in + let*? account_map = + List.fold_left2 + ~when_different_lengths: + [Inconsistent_number_of_bootstrap_accounts] + (fun account_map name contract -> + let liquid = + Tez.(Account.default_initial_balance -! init_staked) + in + let frozen_deposits = Frozen_tez.init init_staked name name in + let frozen_rights = + List.fold_left + (fun map cycle -> CycleMap.add cycle init_staked map) + CycleMap.empty + Cycle.(root ---> add root constants.preserved_cycles) + in + let pkh = Context.Contract.pkh contract in + let account = + init_account + ~delegate:name + ~pkh + ~contract + ~parameters:default_params + ~liquid + ~frozen_deposits + ~frozen_rights + () + in + let account_map = String.Map.add name account account_map in + let balance, total_balance = + balance_and_total_balance_of_account name account_map + in + Log.debug + "Initial balance for %s:\n%a" + name + balance_pp + balance ; + Log.debug "Initial total balance: %a" Tez.pp total_balance ; + account_map) + String.Map.empty + delegates_name_list + delegates + in + let* total_supply = Context.get_total_supply (B block) in + let state = + State. + { + account_map; + total_supply; + constants; + param_requests = []; + activate_ai; + baking_policy = None; + last_level_rewards = init_level; + snapshot_balances = String.Map.empty; + saved_rate = None; + burn_rewards; + pending_operations = []; + pending_slashes = []; + double_signings = []; + } + in + let* () = check_all_balances block state in + return (block, state)) + in + if ns_enable_fork then + Tag "ns_enable = true" --> f true |+ Tag "ns_enable = false" --> f false + else f false (** Set delegate parameters for the given delegate *) let set_delegate_params delegate_name parameters : (t, t) scenarios = @@ -1350,35 +1382,24 @@ let check_pending_slashings (block, state) : unit tzresult Lwt.t = let open Lwt_result_syntax in let open Protocol.Denunciations_repr in let* denunciations_rpc = Context.get_denunciations (B block) in - let denunciations_obj_equal - (pkh_1, {rewarded = r1; misbehaviour = m1; misbehaviour_cycle = mc1; _}) - (pkh_2, {rewarded = r2; misbehaviour = m2; misbehaviour_cycle = mc2; _}) = + let denunciations_obj_equal (pkh_1, {rewarded = r1; misbehaviour = m1; _}) + (pkh_2, {rewarded = r2; misbehaviour = m2; _}) = Signature.Public_key_hash.equal pkh_1 pkh_2 && Signature.Public_key_hash.equal r1 r2 && Stdlib.(m1.kind = m2.kind) - && Stdlib.(mc1 = mc2) in - let compare_denunciations - (pkh_1, {rewarded = r1; misbehaviour = m1; misbehaviour_cycle = mc1; _}) - (pkh_2, {rewarded = r2; misbehaviour = m2; misbehaviour_cycle = mc2; _}) = + let compare_denunciations (pkh_1, {rewarded = r1; misbehaviour = m1; _}) + (pkh_2, {rewarded = r2; misbehaviour = m2; _}) = let c1 = Signature.Public_key_hash.compare pkh_1 pkh_2 in if c1 <> 0 then c1 else let c2 = Signature.Public_key_hash.compare r1 r2 in if c2 <> 0 then c2 else - let c3 = - match (m1.kind, m2.kind) with - | Double_baking, Double_attesting -> -1 - | x, y when x = y -> 0 - | _ -> 1 - in - if c3 <> 0 then c3 - else - match (mc1, mc2) with - | Current, Previous -> -1 - | x, y when x = y -> 0 - | _ -> 1 + match (m1.kind, m2.kind) with + | Double_baking, Double_attesting -> -1 + | x, y when x = y -> 0 + | _ -> 1 in let denunciations_rpc = List.sort compare_denunciations denunciations_rpc in let denunciations_state = @@ -1386,10 +1407,10 @@ let check_pending_slashings (block, state) : unit tzresult Lwt.t = in let denunciations_equal = List.equal denunciations_obj_equal in let denunciations_obj_pp fmt - (pkh, {rewarded; misbehaviour; misbehaviour_cycle; operation_hash = _}) = + (pkh, {rewarded; misbehaviour; operation_hash = _}) = Format.fprintf fmt - "slashed: %a; rewarded: %a; kind: %s; cycle: %s@." + "slashed: %a; rewarded: %a; kind: %s@." Signature.Public_key_hash.pp pkh Signature.Public_key_hash.pp @@ -1397,9 +1418,6 @@ let check_pending_slashings (block, state) : unit tzresult Lwt.t = (match misbehaviour.kind with | Double_baking -> "double baking" | Double_attesting -> "double attesting") - (match misbehaviour_cycle with - | Current -> "current" - | Previous -> "previous") in let denunciations_pp = Format.pp_print_list denunciations_obj_pp in let* () = @@ -1587,12 +1605,6 @@ let update_state_denunciation (block, state) following cycle? *) return (state, denounced) else - let misbehaviour_cycle = - if Cycle.(ds_cycle = inclusion_cycle) then - Protocol.Denunciations_repr.Current - else if Cycle.(succ ds_cycle = inclusion_cycle) then Previous - else assert false - in let kind = match kind with | Double_baking -> Protocol.Misbehaviour_repr.Double_baking @@ -1630,7 +1642,6 @@ let update_state_denunciation (block, state) { Protocol.Denunciations_repr.rewarded; misbehaviour; - misbehaviour_cycle; operation_hash = Operation_hash.zero; (* unused *) } ) @@ -2510,6 +2521,7 @@ module Slashing = struct in begin_test ~activate_ai:true + ~ns_enable_fork:true ~constants ["delegate"; "bootstrap1"; "bootstrap2"] --> (Tag "No AI" --> next_cycle @@ -2526,7 +2538,12 @@ module Slashing = struct --> check_snapshot_balances "before slash" --> exec_unit check_pending_slashings --> next_cycle - --> assert_failure (check_snapshot_balances "before slash") + --> assert_failure + (exec_unit (fun (_block, state) -> + if state.State.constants.adaptive_issuance.ns_enable then + failwith "ns_enable = true: slash not applied yet" + else return_unit) + --> check_snapshot_balances "before slash") --> exec_unit check_pending_slashings --> next_block |+ Tag "denounce too late" --> next_cycle --> next_cycle @@ -2575,6 +2592,7 @@ module Slashing = struct in begin_test ~activate_ai:false + ~ns_enable_fork:true ~constants ["delegate"; "bootstrap1"; "bootstrap2"] --> set_baker "bootstrap1" @@ -2646,6 +2664,7 @@ module Slashing = struct let constants = init_constants ~autostaking_enable:false () in begin_test ~activate_ai:false + ~ns_enable_fork:true ~constants ["delegate"; "bootstrap1"; "bootstrap2"] --> set_baker "bootstrap1" --> next_cycle --> unstake "delegate" Half @@ -2659,7 +2678,7 @@ module Slashing = struct let constants = init_constants ~blocks_per_cycle:8l ~autostaking_enable:false () in - begin_test ~activate_ai:false ~constants ["delegate"] + begin_test ~activate_ai:false ~ns_enable_fork:true ~constants ["delegate"] --> next_cycle --> loop 6 @@ -2683,7 +2702,7 @@ module Slashing = struct let constants = init_constants ~blocks_per_cycle:8l ~autostaking_enable:false () in - begin_test ~activate_ai:false ~constants ["delegate"] + begin_test ~activate_ai:false ~ns_enable_fork:true ~constants ["delegate"] --> next_cycle --> (Tag "stake" --> stake "delegate" Half |+ Tag "unstake" --> unstake "delegate" Half) @@ -2715,7 +2734,11 @@ module Slashing = struct edge_of_baking_over_staking = Q.one; } in - begin_test ~activate_ai:true ~constants [delegate_name; faucet_name] + begin_test + ~activate_ai:true + ~ns_enable_fork:true + ~constants + [delegate_name; faucet_name] --> set_baker faucet_name --> set_delegate_params "delegate" init_params --> init_delegators delegators_list @@ -2766,7 +2789,7 @@ module Slashing = struct let constants = init_constants ~autostaking_enable:false () in let amount = Amount (Tez.of_mutez 333_000_000_000L) in let preserved_cycles = constants.preserved_cycles in - begin_test ~activate_ai:true ~constants ["delegate"] + begin_test ~activate_ai:true ~ns_enable_fork:false ~constants ["delegate"] --> next_block --> wait_ai_activation --> stake "delegate" (Amount (Tez.of_mutez 1_800_000_000_000L)) --> next_cycle --> double_bake "delegate" --> make_denunciations () @@ -2790,7 +2813,7 @@ module Slashing = struct let amount_to_restake = Amount (Tez.of_mutez 100_000_000_000L) in let amount_expected_in_unstake_after_slash = Tez.of_mutez 50_000_000_000L in let preserved_cycles = constants.preserved_cycles in - begin_test ~activate_ai:true ~constants ["delegate"] + begin_test ~activate_ai:true ~ns_enable_fork:false ~constants ["delegate"] --> next_block --> wait_ai_activation --> stake "delegate" (Amount (Tez.of_mutez 1_800_000_000_000L)) --> next_cycle @@ -2810,10 +2833,18 @@ module Slashing = struct let test_mini_slash = let constants = init_constants ~autostaking_enable:false () in (Tag "Yes AI" - --> begin_test ~activate_ai:true ~constants ["delegate"; "baker"] + --> begin_test + ~activate_ai:true + ~ns_enable_fork:false + ~constants + ["delegate"; "baker"] --> next_block --> wait_ai_activation |+ Tag "No AI" - --> begin_test ~activate_ai:false ~constants ["delegate"; "baker"]) + --> begin_test + ~activate_ai:false + ~ns_enable_fork:false + ~constants + ["delegate"; "baker"]) --> unstake "delegate" (Amount Tez.one_mutez) --> set_baker "baker" --> next_cycle --> ((Tag "7% slash" --> double_bake "delegate" --> make_denunciations () @@ -2826,7 +2857,11 @@ module Slashing = struct let test_slash_rounding = let constants = init_constants ~autostaking_enable:false () in - begin_test ~activate_ai:true ~constants ["delegate"; "baker"] + begin_test + ~activate_ai:true + ~ns_enable_fork:true + ~constants + ["delegate"; "baker"] --> set_baker "baker" --> next_block --> wait_ai_activation --> unstake "delegate" (Amount (Tez.of_mutez 2L)) --> next_cycle --> double_bake "delegate" --> double_bake "delegate" -- GitLab From 49256ac8b99ad4b9cce05e6c818ccadc586cfaa5 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 31 Jan 2024 14:32:08 +0100 Subject: [PATCH 5/6] Proto: rename apply denunciations function --- src/proto_alpha/lib_protocol/delegate_cycles.ml | 4 +--- .../lib_protocol/delegate_slashed_deposits_storage.ml | 2 +- .../lib_protocol/delegate_slashed_deposits_storage.mli | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/proto_alpha/lib_protocol/delegate_cycles.ml b/src/proto_alpha/lib_protocol/delegate_cycles.ml index 94510caa4530..ed32b9476f55 100644 --- a/src/proto_alpha/lib_protocol/delegate_cycles.ml +++ b/src/proto_alpha/lib_protocol/delegate_cycles.ml @@ -191,9 +191,7 @@ let cycle_end ctxt last_cycle = distribute_attesting_rewards ctxt last_cycle unrevealed_nonces in let* ctxt, slashings, slashing_balance_updates = - Delegate_slashed_deposits_storage - .apply_and_clear_current_cycle_denunciations - ctxt + Delegate_slashed_deposits_storage.apply_and_clear_denunciations ctxt in let new_cycle = Cycle_repr.add last_cycle 1 in let* ctxt = diff --git a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml index 692ab7eb7994..54dbc6610bff 100644 --- a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml @@ -136,7 +136,7 @@ let clear_outdated_slashed_deposits ctxt ~new_cycle = | None -> Lwt.return ctxt | Some outdated_cycle -> Storage.Slashed_deposits.clear (ctxt, outdated_cycle) -let apply_and_clear_current_cycle_denunciations ctxt = +let apply_and_clear_denunciations ctxt = let open Lwt_result_syntax in let current_cycle = (Raw_context.current_level ctxt).cycle in let previous_cycle = diff --git a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.mli b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.mli index 75fd1689edba..af4d3c729ea8 100644 --- a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.mli +++ b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.mli @@ -89,7 +89,7 @@ val punish_double_signing : val clear_outdated_slashed_deposits : Raw_context.t -> new_cycle:Cycle_repr.t -> Raw_context.t Lwt.t -val apply_and_clear_current_cycle_denunciations : +val apply_and_clear_denunciations : Raw_context.t -> (Raw_context.t * Int_percentage.t Signature.Public_key_hash.Map.t -- GitLab From aef50443a1d00975682a2acbe3b5ab6cf70d1c41 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 31 Jan 2024 14:36:14 +0100 Subject: [PATCH 6/6] Proto: rename denunciations storage --- src/proto_alpha/lib_protocol/alpha_context.ml | 4 ++-- src/proto_alpha/lib_protocol/alpha_context.mli | 2 +- src/proto_alpha/lib_protocol/alpha_services.ml | 2 +- .../lib_protocol/delegate_slashed_deposits_storage.ml | 10 +++++----- .../lib_protocol/delegate_slashed_deposits_storage.mli | 2 +- src/proto_alpha/lib_protocol/storage.ml | 2 +- src/proto_alpha/lib_protocol/storage.mli | 7 ++++--- .../lib_protocol/unstake_requests_storage.ml | 2 +- 8 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index d275e9f8c772..34ad0246ff31 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -561,9 +561,9 @@ module Delegate = struct include Delegate_storage.For_RPC include Delegate_missed_attestations_storage.For_RPC - let current_cycle_denunciations_list ctxt = + let pending_denunciations_list ctxt = let open Lwt_syntax in - let* r = Storage.Current_cycle_denunciations.bindings ctxt in + let* r = Storage.Pending_denunciations.bindings ctxt in let r = List.map (fun (x, l) -> List.map (fun y -> (x, y)) l) r |> List.flatten in diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index eeb600498d61..806789257853 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2470,7 +2470,7 @@ module Delegate : sig val staking_balance : context -> public_key_hash -> Tez.t tzresult Lwt.t - val current_cycle_denunciations_list : + val pending_denunciations_list : context -> (public_key_hash * Denunciations_repr.item) list Lwt.t end end diff --git a/src/proto_alpha/lib_protocol/alpha_services.ml b/src/proto_alpha/lib_protocol/alpha_services.ml index b7b33e8b7bf8..bdbaedbaafe8 100644 --- a/src/proto_alpha/lib_protocol/alpha_services.ml +++ b/src/proto_alpha/lib_protocol/alpha_services.ml @@ -328,7 +328,7 @@ module Denunciations = struct let open Lwt_result_syntax in register0 ~chunked:false S.denunciations (fun ctxt () () -> let*! r = - Alpha_context.Delegate.For_RPC.current_cycle_denunciations_list ctxt + Alpha_context.Delegate.For_RPC.pending_denunciations_list ctxt in return r) diff --git a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml index 54dbc6610bff..db950bd8ac4b 100644 --- a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml @@ -113,7 +113,7 @@ let punish_double_signing ctxt ~operation_hash (* Do not store denunciations that have no effects .*) return ctxt else let* denunciations_opt = - Storage.Current_cycle_denunciations.find ctxt delegate + Storage.Pending_denunciations.find ctxt delegate in let denunciations = Option.value denunciations_opt ~default:[] in let denunciations = @@ -124,7 +124,7 @@ let punish_double_signing ctxt ~operation_hash denunciations in let*! ctxt = - Storage.Current_cycle_denunciations.add ctxt delegate denunciations + Storage.Pending_denunciations.add ctxt delegate denunciations in return ctxt in @@ -172,7 +172,7 @@ let apply_and_clear_denunciations ctxt = {reward; amount_to_burn} in let* ctxt, slashings, balance_updates, remaining_denunciations = - Storage.Current_cycle_denunciations.fold + Storage.Pending_denunciations.fold ctxt ~order:`Undefined ~init:(Ok (ctxt, Signature.Public_key_hash.Map.empty, [], [])) @@ -340,14 +340,14 @@ let apply_and_clear_denunciations ctxt = balance_updates, (delegate, denunciations_to_delay) :: remaining_denunciations )) in - let*! ctxt = Storage.Current_cycle_denunciations.clear ctxt in + let*! ctxt = Storage.Pending_denunciations.clear ctxt in let*! ctxt = List.fold_left_s (fun ctxt (delegate, current_cycle_denunciations) -> match current_cycle_denunciations with | [] -> Lwt.return ctxt | _ -> - Storage.Current_cycle_denunciations.add + Storage.Pending_denunciations.add ctxt delegate current_cycle_denunciations) diff --git a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.mli b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.mli index af4d3c729ea8..617368f9aa46 100644 --- a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.mli +++ b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.mli @@ -28,7 +28,7 @@ (** This module maintains the storage related to slashing of delegates for double signing. In particular, it is responsible for maintaining the {!Storage.Slashed_deposits}, {!Storage.Contract.Slashed_deposits}, and - {!Storage.Current_cycle_denunciations} tables. + {!Storage.Pending_denunciations} tables. *) (** Returns true if the given delegate has already been slashed diff --git a/src/proto_alpha/lib_protocol/storage.ml b/src/proto_alpha/lib_protocol/storage.ml index 1f383877fa40..ccfc2b5d6a6b 100644 --- a/src/proto_alpha/lib_protocol/storage.ml +++ b/src/proto_alpha/lib_protocol/storage.ml @@ -1079,7 +1079,7 @@ module Consensus_keys = end)) (Public_key_hash_index) -module Current_cycle_denunciations = +module Pending_denunciations = Make_indexed_data_storage (Make_subcontext (Registered) (Raw_context) (struct diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index 54319f6a6d59..4ca9d1c11796 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -465,9 +465,10 @@ module Pending_consensus_keys : and type key = Contract_repr.t and type value = Signature.public_key -(** All denunciations of the current cycle that will have an effect (slashing, - reward), i.e. all below 100%, deferred to the cycle end. *) -module Current_cycle_denunciations : +(** All denunciations of the current and previous cycles that will have an effect + (slashing, reward), i.e. all below 100%, deferred to the end of their + slashing period. *) +module Pending_denunciations : Indexed_data_storage with type t := Raw_context.t and type key = Signature.public_key_hash diff --git a/src/proto_alpha/lib_protocol/unstake_requests_storage.ml b/src/proto_alpha/lib_protocol/unstake_requests_storage.ml index e41f18d93816..afc6ea045656 100644 --- a/src/proto_alpha/lib_protocol/unstake_requests_storage.ml +++ b/src/proto_alpha/lib_protocol/unstake_requests_storage.ml @@ -184,7 +184,7 @@ module For_RPC = struct Another solution would be to add the slashing cycle in Storage.Contract.Slashed_deposits, but since it's only used for this specific RPC, let's not. *) let* denunciations_opt = - Storage.Current_cycle_denunciations.find ctxt delegate + Storage.Pending_denunciations.find ctxt delegate in let denunciations = Option.value denunciations_opt ~default:[] in let not_yet_slashed_pct = -- GitLab