From 4355a8064c46b23abf07754e52f80f2d6665fd52 Mon Sep 17 00:00:00 2001 From: Julien Tesson Date: Wed, 7 Feb 2024 18:19:45 +0100 Subject: [PATCH 1/6] proto/delegate_slashed: inconditionnaly store denunciations As slashing is moved at cycle end, and percentage can vary if adaptive slashing is enabled, we cannot know beforehand if we are above the 100% threshold. --- .../delegate_slashed_deposits_storage.ml | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 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 a2570709e17c..f7f763031a0f 100644 --- a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml @@ -60,14 +60,10 @@ let record_denunciation ctxt ~operation_hash Slash_percentage.get ctxt ~kind:misbehaviour.kind ~level [delegate] in let delegate_contract = Contract_repr.Implicit delegate in - let current_cycle = (Raw_context.current_level ctxt).cycle in let* slash_history_opt = Storage.Contract.Slashed_deposits.find ctxt delegate_contract in let slash_history = Option.value slash_history_opt ~default:[] in - let previously_slashed_this_cycle = - Storage.Slashed_deposits_history.get current_cycle slash_history - in let slash_history = Storage.Slashed_deposits_history.add level.cycle @@ -78,18 +74,12 @@ let record_denunciation ctxt ~operation_hash Storage.Contract.Slashed_deposits.add ctxt delegate_contract slash_history in let*! ctxt = Forbidden_delegates_storage.forbid ctxt delegate in - let* ctxt = - if Percentage.(Compare.(previously_slashed_this_cycle >= p100)) then - (* Do not store denunciations that have no effects .*) return ctxt - else - Pending_denunciations_storage.add_denunciation - ctxt - ~misbehaving_delegate:delegate - operation_hash - ~rewarded_delegate:rewarded - misbehaviour - in - return ctxt + Pending_denunciations_storage.add_denunciation + ctxt + ~misbehaving_delegate:delegate + operation_hash + ~rewarded_delegate:rewarded + misbehaviour let punish_double_signing ctxt ~operation_hash misbehaviour delegate (level : Level_repr.t) ~rewarded = -- GitLab From 0dfe6c25e77fa31eaaf79589e8b7bf3f3f821ada Mon Sep 17 00:00:00 2001 From: Julien Tesson Date: Thu, 15 Feb 2024 21:05:48 +0100 Subject: [PATCH 2/6] proto/delegate_slashed: move slashing registration after slashing --- .../delegate_slashed_deposits_storage.ml | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 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 f7f763031a0f..b73e1ec7c4c2 100644 --- a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml @@ -52,27 +52,9 @@ type punishing_amounts = { } let record_denunciation ctxt ~operation_hash - (misbehaviour : Misbehaviour_repr.t) delegate (level : Level_repr.t) + (misbehaviour : Misbehaviour_repr.t) delegate (_level : Level_repr.t) ~rewarded = let open Lwt_result_syntax in - (* Placeholder value *) - let* ctxt, slashing_percentage = - Slash_percentage.get ctxt ~kind:misbehaviour.kind ~level [delegate] - in - let delegate_contract = Contract_repr.Implicit delegate in - let* slash_history_opt = - Storage.Contract.Slashed_deposits.find ctxt delegate_contract - in - let slash_history = Option.value slash_history_opt ~default:[] in - let slash_history = - Storage.Slashed_deposits_history.add - level.cycle - slashing_percentage - slash_history - in - let*! ctxt = - Storage.Contract.Slashed_deposits.add ctxt delegate_contract slash_history - in let*! ctxt = Forbidden_delegates_storage.forbid ctxt delegate in Pending_denunciations_storage.add_denunciation ctxt @@ -271,6 +253,24 @@ let apply_and_clear_denunciations ctxt = We could assert false, but we can also be permissive while keeping the same invariants *) in + let delegate_contract = Contract_repr.Implicit delegate in + let* slash_history_opt = + Storage.Contract.Slashed_deposits.find ctxt delegate_contract + in + let slash_history = Option.value slash_history_opt ~default:[] in + let slash_history = + Storage.Slashed_deposits_history.add + level.cycle + slashing_percentage + slash_history + in + let*! ctxt = + Storage.Contract.Slashed_deposits.add + ctxt + delegate_contract + slash_history + in + let* frozen_deposits = let* initial_amount = get_initial_frozen_deposits_of_misbehaviour_cycle -- GitLab From 4cda8d644546d2b360498c8bf383891da0ef5fbd Mon Sep 17 00:00:00 2001 From: Julien Tesson Date: Thu, 15 Feb 2024 21:06:48 +0100 Subject: [PATCH 3/6] proto/delegate_slashed: remove now useless argument --- .../delegate_slashed_deposits_storage.ml | 12 ++---------- 1 file changed, 2 insertions(+), 10 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 b73e1ec7c4c2..5a97c871243a 100644 --- a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml @@ -52,8 +52,7 @@ type punishing_amounts = { } let record_denunciation ctxt ~operation_hash - (misbehaviour : Misbehaviour_repr.t) delegate (_level : Level_repr.t) - ~rewarded = + (misbehaviour : Misbehaviour_repr.t) delegate ~rewarded = let open Lwt_result_syntax in let*! ctxt = Forbidden_delegates_storage.forbid ctxt delegate in Pending_denunciations_storage.add_denunciation @@ -99,14 +98,7 @@ let punish_double_signing ctxt ~operation_hash misbehaviour delegate exception here would cause the whole block application to fail, which we don't want. *) return ctxt - else - record_denunciation - ctxt - ~operation_hash - misbehaviour - delegate - level - ~rewarded + else record_denunciation ctxt ~operation_hash misbehaviour delegate ~rewarded (* Misbehaviour Map: orders denunciations for application. See {!Misbehaviour_repr.compare} for the order on misbehaviours: -- GitLab From 00bb6575d5288ce17eb94109868bd93c5c624133 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 14 Feb 2024 17:12:04 +0100 Subject: [PATCH 4/6] proto/delegate_slashed: do not slash above 100% --- .../delegate_slashed_deposits_storage.ml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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 5a97c871243a..d6d19835a031 100644 --- a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml @@ -250,6 +250,9 @@ let apply_and_clear_denunciations ctxt = Storage.Contract.Slashed_deposits.find ctxt delegate_contract in let slash_history = Option.value slash_history_opt ~default:[] in + let previous_total_slashing_percentage = + Storage.Slashed_deposits_history.get level.cycle slash_history + in let slash_history = Storage.Slashed_deposits_history.add level.cycle @@ -263,6 +266,19 @@ let apply_and_clear_denunciations ctxt = slash_history in + let new_total_slashing_percentage = + Storage.Slashed_deposits_history.get level.cycle slash_history + in + (* We do not slash above 100%: if the slashing percentage would + make the total sum of the slashing history above 100%, we rectify + it to reach exactly 100%. This also means that subsequent slashes + are effectively ignored (set to 0%) *) + let slashing_percentage = + Percentage.sub_bounded + new_total_slashing_percentage + previous_total_slashing_percentage + in + let* frozen_deposits = let* initial_amount = get_initial_frozen_deposits_of_misbehaviour_cycle -- GitLab From 6a14c64b79716c0bd44a8f0ae2c94e849ebca0a3 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 14 Feb 2024 17:15:01 +0100 Subject: [PATCH 5/6] proto/delegate_slashed: check is_denounced in stake_from_unstake --- src/proto_alpha/lib_protocol/staking.ml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/proto_alpha/lib_protocol/staking.ml b/src/proto_alpha/lib_protocol/staking.ml index 90fc59695f5e..7d66398ce24f 100644 --- a/src/proto_alpha/lib_protocol/staking.ml +++ b/src/proto_alpha/lib_protocol/staking.ml @@ -149,11 +149,15 @@ let can_stake_from_unstake ctxt ~for_next_cycle_use_only_after_slashing Cycle_repr.sub current_cycle (slashable_deposits_period + 1) |> Option.value ~default:Cycle_repr.root in - return - @@ not - (List.exists - (fun (x, _) -> Cycle_repr.(x >= oldest_slashable_cycle)) - slashing_history) + let*! is_denounced = + Pending_denunciations_storage.has_pending_denunciations ctxt delegate + in + let is_slashed = + List.exists + (fun (x, _) -> Cycle_repr.(x >= oldest_slashable_cycle)) + slashing_history + in + return @@ not (is_denounced || is_slashed) let stake_from_unstake_for_delegate ctxt ~for_next_cycle_use_only_after_slashing ~delegate ~unfinalizable_requests_opt amount = -- GitLab From 63f0a046b0cdcc57fe000373856b1172d4367f99 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Thu, 15 Feb 2024 11:02:21 +0100 Subject: [PATCH 6/6] Proto/RPC: simplify unstake RPC --- .../lib_protocol/unstake_requests_storage.ml | 66 ------------------- 1 file changed, 66 deletions(-) diff --git a/src/proto_alpha/lib_protocol/unstake_requests_storage.ml b/src/proto_alpha/lib_protocol/unstake_requests_storage.ml index 579378b7cf2e..89508fb9e16c 100644 --- a/src/proto_alpha/lib_protocol/unstake_requests_storage.ml +++ b/src/proto_alpha/lib_protocol/unstake_requests_storage.ml @@ -166,9 +166,6 @@ let add ctxt ~contract ~delegate cycle amount = module For_RPC = struct let apply_slash_to_unstaked_unfinalizable ctxt {requests; delegate} = let open Lwt_result_syntax in - let current_level = Raw_context.current_level ctxt in - let cycle_eras = Raw_context.cycle_eras ctxt in - let is_last_of_cycle = Level_repr.last_of_cycle ~cycle_eras current_level in let slashable_deposits_period = Constants_storage.slashable_deposits_period ctxt in @@ -178,69 +175,6 @@ module For_RPC = struct (Contract_repr.Implicit delegate) in let slashing_history = Option.value slashing_history_opt ~default:[] in - 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 = Pending_denunciations_storage.find ctxt delegate in - let not_yet_slashed_pct = - if is_last_of_cycle then 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 - else - match misbehaviour.kind with - | Double_baking -> - Percentage.add_bounded - acc - (Constants_storage - .percentage_of_frozen_deposits_slashed_per_double_baking - ctxt) - | Double_attesting | Double_preattesting -> - Percentage.add_bounded - acc - (Constants_storage - .percentage_of_frozen_deposits_slashed_per_double_attestation - ctxt)) - Percentage.p0 - denunciations - in - return - @@ List.map - (fun (cycle, pct) -> - if Cycle_repr.(succ cycle = current_level.cycle) then - (cycle, 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) -> let new_amount = -- GitLab