package tezos-protocol-alpha

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file delegate_missed_attestations_storage.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
(*****************************************************************************)
(*                                                                           *)
(* Open Source License                                                       *)
(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com>     *)
(* Copyright (c) 2021 Nomadic Labs, <contact@nomadic-labs.com>               *)
(* Copyright (c) 2022 G.B. Fefe, <gb.fefe@protonmail.com>                    *)
(*                                                                           *)
(* Permission is hereby granted, free of charge, to any person obtaining a   *)
(* copy of this software and associated documentation files (the "Software"),*)
(* to deal in the Software without restriction, including without limitation *)
(* the rights to use, copy, modify, merge, publish, distribute, sublicense,  *)
(* and/or sell copies of the Software, and to permit persons to whom the     *)
(* Software is furnished to do so, subject to the following conditions:      *)
(*                                                                           *)
(* The above copyright notice and this permission notice shall be included   *)
(* in all copies or substantial portions of the Software.                    *)
(*                                                                           *)
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  *)
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL   *)
(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING   *)
(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER       *)
(* DEALINGS IN THE SOFTWARE.                                                 *)
(*                                                                           *)
(*****************************************************************************)

let expected_slots_for_given_active_stake ctxt ~total_active_stake_weight
    ~active_stake_weight =
  let blocks_per_cycle =
    Int32.to_int (Constants_storage.blocks_per_cycle ctxt)
  in
  let consensus_committee_size =
    Constants_storage.consensus_committee_size ctxt
  in
  let number_of_attestations_per_cycle =
    blocks_per_cycle * consensus_committee_size
  in
  Z.to_int
    (Z.div
       (Z.mul
          (Z.of_int64 active_stake_weight)
          (Z.of_int number_of_attestations_per_cycle))
       (Z.of_int64 total_active_stake_weight))

type level_participation = Participated | Didn't_participate

(* Note that the participation for the last block of a cycle is
   recorded in the next cycle. *)
let record_attesting_participation ctxt ~delegate ~participation
    ~attesting_power =
  let open Lwt_result_syntax in
  match participation with
  | Participated -> Stake_storage.set_active ctxt delegate
  | Didn't_participate -> (
      let contract = Contract_repr.Implicit delegate in
      let* result = Storage.Contract.Missed_attestations.find ctxt contract in
      match result with
      | Some {remaining_slots; missed_levels} ->
          let remaining_slots = remaining_slots - attesting_power in
          Storage.Contract.Missed_attestations.update
            ctxt
            contract
            {remaining_slots; missed_levels = missed_levels + 1}
      | None -> (
          let level = Level_storage.current ctxt in
          let*? stake_distribution =
            Raw_context.stake_distribution_for_current_cycle ctxt
          in
          match
            Signature.Public_key_hash.Map.find delegate stake_distribution
          with
          | None ->
              (* This happens when the block is the first one in a
                 cycle, and therefore the attestations are for the last
                 block of the previous cycle, and when the delegate does
                 not have an active stake at the current cycle; in this
                 case its participation is simply ignored. *)
              assert (Compare.Int32.(level.cycle_position = 0l)) ;
              return ctxt
          | Some active_stake ->
              let* total_active_stake =
                Stake_storage.get_total_active_stake ctxt level.cycle
              in
              let expected_slots =
                let active_stake_weight =
                  Stake_repr.staking_weight active_stake
                in
                let total_active_stake_weight =
                  Stake_repr.staking_weight total_active_stake
                in
                expected_slots_for_given_active_stake
                  ctxt
                  ~total_active_stake_weight
                  ~active_stake_weight
              in
              let Ratio_repr.{numerator; denominator} =
                Constants_storage.minimal_participation_ratio ctxt
              in
              let minimal_activity = expected_slots * numerator / denominator in
              let maximal_inactivity = expected_slots - minimal_activity in
              let remaining_slots = maximal_inactivity - attesting_power in
              Storage.Contract.Missed_attestations.init
                ctxt
                contract
                {remaining_slots; missed_levels = 1}))

let record_baking_activity_and_pay_rewards_and_fees ctxt ~payload_producer
    ~block_producer ~baking_reward ~reward_bonus =
  let open Lwt_result_syntax in
  let* ctxt = Stake_storage.set_active ctxt payload_producer in
  let* ctxt =
    if not (Signature.Public_key_hash.equal payload_producer block_producer)
    then Stake_storage.set_active ctxt block_producer
    else return ctxt
  in
  let pay_payload_producer ctxt delegate =
    let contract = Contract_repr.Implicit delegate in
    let* ctxt, block_fees = Token.balance ctxt `Block_fees in
    let* ctxt, balance_updates_block_fees =
      Token.transfer ctxt `Block_fees (`Contract contract) block_fees
    in
    let+ ctxt, balance_updates_baking_rewards =
      Shared_stake.pay_rewards
        ctxt
        ~source:`Baking_rewards
        ~delegate
        baking_reward
    in
    (ctxt, balance_updates_block_fees @ balance_updates_baking_rewards)
  in
  let pay_block_producer ctxt delegate bonus =
    Shared_stake.pay_rewards ctxt ~source:`Baking_bonuses ~delegate bonus
  in
  let* ctxt, balance_updates_payload_producer =
    pay_payload_producer ctxt payload_producer
  in
  let* ctxt, balance_updates_block_producer =
    match reward_bonus with
    | Some bonus -> pay_block_producer ctxt block_producer bonus
    | None -> return (ctxt, [])
  in
  return
    (ctxt, balance_updates_payload_producer @ balance_updates_block_producer)

let check_and_reset_delegate_participation ctxt delegate =
  let open Lwt_result_syntax in
  let contract = Contract_repr.Implicit delegate in
  let* missed = Storage.Contract.Missed_attestations.find ctxt contract in
  match missed with
  | None -> return (ctxt, true)
  | Some missed_attestations ->
      let*! ctxt = Storage.Contract.Missed_attestations.remove ctxt contract in
      return (ctxt, Compare.Int.(missed_attestations.remaining_slots >= 0))

module For_RPC = struct
  type participation_info = {
    expected_cycle_activity : int;
    minimal_cycle_activity : int;
    missed_slots : int;
    missed_levels : int;
    remaining_allowed_missed_slots : int;
    expected_attesting_rewards : Tez_repr.t;
  }

  (* Inefficient, only for RPC *)
  let participation_info ctxt delegate =
    let open Lwt_result_syntax in
    let level = Level_storage.current ctxt in
    let* stake_distribution =
      Stake_storage.get_selected_distribution ctxt level.cycle
    in
    match
      List.assoc_opt
        ~equal:Signature.Public_key_hash.equal
        delegate
        stake_distribution
    with
    | None ->
        (* delegate does not have an active stake at the current cycle *)
        return
          {
            expected_cycle_activity = 0;
            minimal_cycle_activity = 0;
            missed_slots = 0;
            missed_levels = 0;
            remaining_allowed_missed_slots = 0;
            expected_attesting_rewards = Tez_repr.zero;
          }
    | Some active_stake ->
        let* total_active_stake =
          Stake_storage.get_total_active_stake ctxt level.cycle
        in
        let expected_cycle_activity =
          let active_stake_weight = Stake_repr.staking_weight active_stake in
          let total_active_stake_weight =
            Stake_repr.staking_weight total_active_stake
          in
          expected_slots_for_given_active_stake
            ctxt
            ~total_active_stake_weight
            ~active_stake_weight
        in
        let Ratio_repr.{numerator; denominator} =
          Constants_storage.minimal_participation_ratio ctxt
        in
        let*? attesting_reward_per_slot =
          Delegate_rewards.attesting_reward_per_slot ctxt
        in
        let minimal_cycle_activity =
          expected_cycle_activity * numerator / denominator
        in
        let maximal_cycle_inactivity =
          expected_cycle_activity - minimal_cycle_activity
        in
        let expected_attesting_rewards =
          Tez_repr.mul_exn attesting_reward_per_slot expected_cycle_activity
        in
        let contract = Contract_repr.Implicit delegate in
        let* missed_attestations =
          Storage.Contract.Missed_attestations.find ctxt contract
        in
        let missed_slots, missed_levels, remaining_allowed_missed_slots =
          match missed_attestations with
          | None -> (0, 0, maximal_cycle_inactivity)
          | Some {remaining_slots; missed_levels} ->
              ( maximal_cycle_inactivity - remaining_slots,
                missed_levels,
                Compare.Int.max 0 remaining_slots )
        in
        let expected_attesting_rewards =
          match missed_attestations with
          | Some r when Compare.Int.(r.remaining_slots < 0) -> Tez_repr.zero
          | _ -> expected_attesting_rewards
        in
        return
          {
            expected_cycle_activity;
            minimal_cycle_activity;
            missed_slots;
            missed_levels;
            remaining_allowed_missed_slots;
            expected_attesting_rewards;
          }
end
OCaml

Innovation. Community. Security.