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 a2570709e17c91c5d37105d27e8695a7e6c2b8c4..d6d19835a031bffffbc003487ef490da11c8cf23 100644 --- a/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_slashed_deposits_storage.ml @@ -52,44 +52,15 @@ 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 - (* 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 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 - 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 - 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 = @@ -127,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: @@ -281,6 +245,40 @@ 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 previous_total_slashing_percentage = + Storage.Slashed_deposits_history.get level.cycle slash_history + 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 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 diff --git a/src/proto_alpha/lib_protocol/staking.ml b/src/proto_alpha/lib_protocol/staking.ml index 90fc59695f5e553947a304826dec852ac6a0dd6a..7d66398ce24fdedcfc031383c189b9ee03f988ce 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 = diff --git a/src/proto_alpha/lib_protocol/unstake_requests_storage.ml b/src/proto_alpha/lib_protocol/unstake_requests_storage.ml index 579378b7cf2e13c02c230d673137a6fdfa21e38a..89508fb9e16ccf1f5510e83f3dba76522ba1aef7 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 =