Source file delegate_consensus_key.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
type error +=
| Invalid_consensus_key_update_noop of Cycle_repr.t
| Invalid_consensus_key_update_active
let () =
register_error_kind
`Permanent
~id:"delegate.consensus_key.invalid_noop"
~title:"Invalid key for consensus key update"
~description:"Tried to update the consensus key with the active key"
~pp:(fun ppf cycle ->
Format.fprintf
ppf
"Invalid key while updating a consensus key (already active since %a)."
Cycle_repr.pp
cycle)
Data_encoding.(obj1 (req "cycle" Cycle_repr.encoding))
(function Invalid_consensus_key_update_noop c -> Some c | _ -> None)
(fun c -> Invalid_consensus_key_update_noop c) ;
register_error_kind
`Permanent
~id:"delegate.consensus_key.active"
~title:"Active consensus key"
~description:
"The delegate consensus key is already used by another delegate"
~pp:(fun ppf () ->
Format.fprintf
ppf
"The delegate consensus key is already used by another delegate")
Data_encoding.empty
(function Invalid_consensus_key_update_active -> Some () | _ -> None)
(fun () -> Invalid_consensus_key_update_active)
type pk = Raw_context.consensus_pk = {
delegate : Signature.Public_key_hash.t;
consensus_pk : Signature.Public_key.t;
consensus_pkh : Signature.Public_key_hash.t;
}
type t = {
delegate : Signature.Public_key_hash.t;
consensus_pkh : Signature.Public_key_hash.t;
}
let pkh {delegate; consensus_pkh; consensus_pk = _} = {delegate; consensus_pkh}
let zero =
{
consensus_pkh = Signature.Public_key_hash.zero;
delegate = Signature.Public_key_hash.zero;
}
let pp ppf {delegate; consensus_pkh} =
Format.fprintf ppf "@[<v 2>%a" Signature.Public_key_hash.pp delegate ;
if not (Signature.Public_key_hash.equal delegate consensus_pkh) then
Format.fprintf
ppf
"@,Active key: %a"
Signature.Public_key_hash.pp
consensus_pkh ;
Format.fprintf ppf "@]"
let check_inactive ctxt pkh =
let open Lwt_tzresult_syntax in
let*! is_active = Storage.Consensus_keys.mem ctxt pkh in
fail_when is_active Invalid_consensus_key_update_active
let set_inactive = Storage.Consensus_keys.remove
let set_active = Storage.Consensus_keys.add
let init ctxt delegate pk =
let open Lwt_tzresult_syntax in
let pkh = Signature.Public_key.hash pk in
let* () = check_inactive ctxt pkh in
let*! ctxt = set_active ctxt pkh in
Storage.Contract.Consensus_key.init ctxt (Contract_repr.Implicit delegate) pk
let active_pubkey ctxt delegate =
let open Lwt_tzresult_syntax in
let* pk =
Storage.Contract.Consensus_key.get ctxt (Contract_repr.Implicit delegate)
in
let pkh = Signature.Public_key.hash pk in
return {consensus_pk = pk; consensus_pkh = pkh; delegate}
let active_key ctxt delegate =
let open Lwt_tzresult_syntax in
let* pk = active_pubkey ctxt delegate in
return (pkh pk)
let raw_pending_updates ctxt delegate =
let open Lwt_tzresult_syntax in
let*! pendings =
Storage.Contract.Pending_consensus_keys.bindings
(ctxt, Contract_repr.Implicit delegate)
in
return pendings
let pending_updates ctxt delegate =
let open Lwt_tzresult_syntax in
let* updates = raw_pending_updates ctxt delegate in
let updates =
List.sort (fun (c1, _) (c2, _) -> Cycle_repr.compare c1 c2) updates
in
return (List.map (fun (c, pk) -> (c, Signature.Public_key.hash pk)) updates)
let raw_active_pubkey_for_cycle ctxt delegate cycle =
let open Lwt_tzresult_syntax in
let* pendings = raw_pending_updates ctxt delegate in
let* active = active_pubkey ctxt delegate in
let current_level = Raw_context.current_level ctxt in
let active_for_cycle =
List.fold_left
(fun (c1, active) (c2, pk) ->
if Cycle_repr.(c1 < c2 && c2 <= cycle) then (c2, pk) else (c1, active))
(current_level.cycle, active.consensus_pk)
pendings
in
return active_for_cycle
let active_pubkey_for_cycle ctxt delegate cycle =
let open Lwt_tzresult_syntax in
let* _, consensus_pk = raw_active_pubkey_for_cycle ctxt delegate cycle in
return
{
consensus_pk;
consensus_pkh = Signature.Public_key.hash consensus_pk;
delegate;
}
let register_update ctxt delegate pk =
let open Lwt_tzresult_syntax in
let update_cycle =
let current_level = Raw_context.current_level ctxt in
let preserved_cycles = Constants_storage.preserved_cycles ctxt in
Cycle_repr.add current_level.cycle (preserved_cycles + 1)
in
let* () =
let* first_active_cycle, active_pubkey =
raw_active_pubkey_for_cycle ctxt delegate update_cycle
in
fail_when
Signature.Public_key.(pk = active_pubkey)
(Invalid_consensus_key_update_noop first_active_cycle)
in
let pkh = Signature.Public_key.hash pk in
let* () = check_inactive ctxt pkh in
let*! ctxt = set_active ctxt pkh in
let* {consensus_pkh = old_pkh; _} =
active_pubkey_for_cycle ctxt delegate update_cycle
in
let*! ctxt = set_inactive ctxt old_pkh in
let*! ctxt =
Storage.Contract.Pending_consensus_keys.add
(ctxt, Contract_repr.Implicit delegate)
update_cycle
pk
in
return ctxt
let activate ctxt ~new_cycle =
let open Lwt_tzresult_syntax in
Storage.Delegates.fold
ctxt
~order:`Undefined
~init:(ok ctxt)
~f:(fun delegate ctxt ->
let*? ctxt = ctxt in
let delegate = Contract_repr.Implicit delegate in
let* update =
Storage.Contract.Pending_consensus_keys.find (ctxt, delegate) new_cycle
in
match update with
| None -> return ctxt
| Some pk ->
let*! ctxt = Storage.Contract.Consensus_key.add ctxt delegate pk in
let*! ctxt =
Storage.Contract.Pending_consensus_keys.remove
(ctxt, delegate)
new_cycle
in
return ctxt)