@@ -4,10 +4,11 @@ use futures::TryStreamExt as _;
4
4
use jmt:: RootHash ;
5
5
use pbjson_types:: Any ;
6
6
use penumbra_app:: app:: StateReadExt as _;
7
+ use penumbra_governance:: StateReadExt as _;
7
8
use penumbra_proto:: { DomainType as _, StateReadProto as _, StateWriteProto as _} ;
8
9
use penumbra_sct:: component:: clock:: EpochRead as _;
9
10
use penumbra_stake:: validator:: Validator ;
10
- use std:: { path:: PathBuf , time :: Duration } ;
11
+ use std:: path:: PathBuf ;
11
12
use tracing:: instrument;
12
13
13
14
use crate :: testnet:: generate:: TestnetConfig ;
@@ -17,22 +18,24 @@ use crate::testnet::generate::TestnetConfig;
17
18
/// Menu:
18
19
/// - Truncate various user-supplied `String` fields to a maximum length.
19
20
/// * Validators:
20
- /// - `name` (140 characters )
21
- /// - `website` (70 characters )
22
- /// - `description` (280 characters )
21
+ /// - `name` (140 bytes )
22
+ /// - `website` (70 bytes )
23
+ /// - `description` (280 bytes )
23
24
/// * Governance Parameter Changes:
24
- /// - `key` (64 characters )
25
- /// - `value` (2048 characters )
26
- /// - `component` (64 characters )
25
+ /// - `key` (64 bytes )
26
+ /// - `value` (2048 bytes )
27
+ /// - `component` (64 bytes )
27
28
/// * Governance Proposals:
28
- /// - `title` (80 characters )
29
- /// - `description` (10,000 characters )
29
+ /// - `title` (80 bytes )
30
+ /// - `description` (10,000 bytes )
30
31
/// * Governance Proposal Withdrawals:
31
- /// - `reason` (1024 characters )
32
+ /// - `reason` (1024 bytes )
32
33
/// * Governance IBC Client Freeze Proposals:
33
- /// - `client_id` (128 characters)
34
- /// * Signaling Proposals:
35
- /// - `commit hash` (64 characters)
34
+ /// - `client_id` (128 bytes)
35
+ /// * Governance IBC Client Unfreeze Proposals:
36
+ /// - `client_id` (128 bytes)
37
+ /// * Governance Signaling Proposals:
38
+ /// - `commit hash` (255 bytes)
36
39
#[ instrument]
37
40
pub async fn migrate (
38
41
storage : Storage ,
@@ -61,6 +64,12 @@ pub async fn migrate(
61
64
// Adjust the length of `Validator` fields.
62
65
truncate_validator_fields ( & mut delta) . await ?;
63
66
67
+ // Adjust the length of governance proposal fields.
68
+ truncate_proposal_fields ( & mut delta) . await ?;
69
+
70
+ // Adjust the length of governance proposal outcome fields.
71
+ truncate_proposal_outcome_fields ( & mut delta) . await ?;
72
+
64
73
let post_upgrade_root_hash = storage. commit_in_place ( delta) . await ?;
65
74
tracing:: info!( ?post_upgrade_root_hash, "post-migration root hash" ) ;
66
75
@@ -115,6 +124,10 @@ pub async fn migrate(
115
124
Ok ( ( ) )
116
125
}
117
126
127
+ /// * Validators:
128
+ /// - `name` (140 bytes)
129
+ /// - `website` (70 bytes)
130
+ /// - `description` (280 bytes)
118
131
async fn truncate_validator_fields ( delta : & mut StateDelta < Snapshot > ) -> anyhow:: Result < ( ) > {
119
132
let key_prefix_validators = penumbra_stake:: state_key:: validators:: definitions:: prefix ( ) ;
120
133
let all_validators = delta
@@ -125,13 +138,205 @@ async fn truncate_validator_fields(delta: &mut StateDelta<Snapshot>) -> anyhow::
125
138
126
139
for ( key, mut validator) in all_validators {
127
140
validator. name = truncate ( & validator. name , 140 ) . to_string ( ) ;
141
+ validator. website = truncate ( & validator. website , 70 ) . to_string ( ) ;
142
+ validator. description = truncate ( & validator. description , 280 ) . to_string ( ) ;
128
143
129
144
delta. put ( key, validator) ;
130
145
}
131
146
132
147
Ok ( ( ) )
133
148
}
134
149
150
+ /// * Governance Proposals:
151
+ /// - `title` (80 bytes)
152
+ /// - `description` (10,000 bytes)
153
+ /// * Governance Parameter Changes:
154
+ /// - `key` (64 bytes)
155
+ /// - `value` (2048 bytes)
156
+ /// - `component` (64 bytes)
157
+ /// * Governance IBC Client Freeze Proposals:
158
+ /// - `client_id` (128 bytes)
159
+ /// * Governance IBC Client Unfreeze Proposals:
160
+ /// - `client_id` (128 bytes)
161
+ /// * Governance Signaling Proposals:
162
+ /// - `commit hash` (255 bytes)
163
+ async fn truncate_proposal_fields ( delta : & mut StateDelta < Snapshot > ) -> anyhow:: Result < ( ) > {
164
+ let next_proposal_id: u64 = delta. next_proposal_id ( ) . await ?;
165
+
166
+ // Range each proposal and truncate the fields.
167
+ for proposal_id in 0 ..next_proposal_id {
168
+ let proposal = delta. proposal_definition ( proposal_id) . await ?;
169
+
170
+ if proposal. is_none ( ) {
171
+ break ;
172
+ }
173
+
174
+ let mut proposal = proposal. unwrap ( ) ;
175
+
176
+ proposal. title = truncate ( & proposal. title , 80 ) . to_string ( ) ;
177
+ proposal. description = truncate ( & proposal. description , 10_000 ) . to_string ( ) ;
178
+
179
+ // Depending on the proposal type, we may need to truncate additional fields.
180
+ match proposal. payload {
181
+ penumbra_governance:: ProposalPayload :: Signaling { commit } => {
182
+ proposal. payload = penumbra_governance:: ProposalPayload :: Signaling {
183
+ commit : commit. map ( |commit| truncate ( & commit, 255 ) . to_string ( ) ) ,
184
+ } ;
185
+ }
186
+ penumbra_governance:: ProposalPayload :: Emergency { halt_chain : _ } => { }
187
+ penumbra_governance:: ProposalPayload :: ParameterChange ( mut param_change) => {
188
+ for ( i, mut change) in param_change. changes . clone ( ) . into_iter ( ) . enumerate ( ) {
189
+ let key = truncate ( & change. key , 64 ) . to_string ( ) ;
190
+ let value = truncate ( & change. value , 2048 ) . to_string ( ) ;
191
+ let component = truncate ( & change. component , 64 ) . to_string ( ) ;
192
+
193
+ change. key = key;
194
+ change. value = value;
195
+ change. component = component;
196
+
197
+ param_change. changes [ i] = change;
198
+ }
199
+
200
+ for ( i, mut change) in param_change. preconditions . clone ( ) . into_iter ( ) . enumerate ( ) {
201
+ let key = truncate ( & change. key , 64 ) . to_string ( ) ;
202
+ let value = truncate ( & change. value , 2048 ) . to_string ( ) ;
203
+ let component = truncate ( & change. component , 64 ) . to_string ( ) ;
204
+
205
+ change. key = key;
206
+ change. value = value;
207
+ change. component = component;
208
+
209
+ param_change. preconditions [ i] = change;
210
+ }
211
+
212
+ proposal. payload =
213
+ penumbra_governance:: ProposalPayload :: ParameterChange ( param_change) ;
214
+ }
215
+ penumbra_governance:: ProposalPayload :: CommunityPoolSpend {
216
+ transaction_plan : _,
217
+ } => { }
218
+ penumbra_governance:: ProposalPayload :: UpgradePlan { height : _ } => { }
219
+ penumbra_governance:: ProposalPayload :: FreezeIbcClient { client_id } => {
220
+ proposal. payload = penumbra_governance:: ProposalPayload :: FreezeIbcClient {
221
+ client_id : truncate ( & client_id, 128 ) . to_string ( ) ,
222
+ } ;
223
+ }
224
+ penumbra_governance:: ProposalPayload :: UnfreezeIbcClient { client_id } => {
225
+ proposal. payload = penumbra_governance:: ProposalPayload :: UnfreezeIbcClient {
226
+ client_id : truncate ( & client_id, 128 ) . to_string ( ) ,
227
+ } ;
228
+ }
229
+ } ;
230
+
231
+ // Store the truncated proposal data
232
+ delta. put (
233
+ penumbra_governance:: state_key:: proposal_definition ( proposal_id) ,
234
+ proposal. clone ( ) ,
235
+ ) ;
236
+ }
237
+
238
+ Ok ( ( ) )
239
+ }
240
+
241
+ /// * Governance Proposal Withdrawals:
242
+ /// - `reason` (1024 bytes)
243
+ async fn truncate_proposal_outcome_fields ( delta : & mut StateDelta < Snapshot > ) -> anyhow:: Result < ( ) > {
244
+ let next_proposal_id: u64 = delta. next_proposal_id ( ) . await ?;
245
+
246
+ // Range each proposal outcome and truncate the fields.
247
+ for proposal_id in 0 ..next_proposal_id {
248
+ let proposal_state = delta. proposal_state ( proposal_id) . await ?;
249
+
250
+ if proposal_state. is_none ( ) {
251
+ break ;
252
+ }
253
+
254
+ let mut proposal_state = proposal_state. unwrap ( ) ;
255
+
256
+ match proposal_state {
257
+ penumbra_governance:: proposal_state:: State :: Withdrawn { reason } => {
258
+ proposal_state = penumbra_governance:: proposal_state:: State :: Withdrawn {
259
+ reason : truncate ( & reason, 1024 ) . to_string ( ) ,
260
+ } ;
261
+ }
262
+ penumbra_governance:: proposal_state:: State :: Voting => { }
263
+ penumbra_governance:: proposal_state:: State :: Finished { ref outcome } => match outcome {
264
+ penumbra_governance:: proposal_state:: Outcome :: Passed => { }
265
+ penumbra_governance:: proposal_state:: Outcome :: Failed { withdrawn } => {
266
+ match withdrawn {
267
+ penumbra_governance:: proposal_state:: Withdrawn :: No => { }
268
+ penumbra_governance:: proposal_state:: Withdrawn :: WithReason { reason } => {
269
+ proposal_state = penumbra_governance:: proposal_state:: State :: Finished {
270
+ outcome : penumbra_governance:: proposal_state:: Outcome :: Failed {
271
+ withdrawn :
272
+ penumbra_governance:: proposal_state:: Withdrawn :: WithReason {
273
+ reason : truncate ( & reason, 1024 ) . to_string ( ) ,
274
+ } ,
275
+ } ,
276
+ } ;
277
+ }
278
+ }
279
+ }
280
+ penumbra_governance:: proposal_state:: Outcome :: Slashed { withdrawn } => {
281
+ match withdrawn {
282
+ penumbra_governance:: proposal_state:: Withdrawn :: No => { }
283
+ penumbra_governance:: proposal_state:: Withdrawn :: WithReason { reason } => {
284
+ proposal_state = penumbra_governance:: proposal_state:: State :: Finished {
285
+ outcome : penumbra_governance:: proposal_state:: Outcome :: Slashed {
286
+ withdrawn :
287
+ penumbra_governance:: proposal_state:: Withdrawn :: WithReason {
288
+ reason : truncate ( & reason, 1024 ) . to_string ( ) ,
289
+ } ,
290
+ } ,
291
+ } ;
292
+ }
293
+ }
294
+ }
295
+ } ,
296
+ penumbra_governance:: proposal_state:: State :: Claimed { ref outcome } => match outcome {
297
+ penumbra_governance:: proposal_state:: Outcome :: Passed => { }
298
+ penumbra_governance:: proposal_state:: Outcome :: Failed { withdrawn } => {
299
+ match withdrawn {
300
+ penumbra_governance:: proposal_state:: Withdrawn :: No => { }
301
+ penumbra_governance:: proposal_state:: Withdrawn :: WithReason { reason } => {
302
+ proposal_state = penumbra_governance:: proposal_state:: State :: Claimed {
303
+ outcome : penumbra_governance:: proposal_state:: Outcome :: Failed {
304
+ withdrawn :
305
+ penumbra_governance:: proposal_state:: Withdrawn :: WithReason {
306
+ reason : truncate ( & reason, 1024 ) . to_string ( ) ,
307
+ } ,
308
+ } ,
309
+ } ;
310
+ }
311
+ }
312
+ }
313
+ penumbra_governance:: proposal_state:: Outcome :: Slashed { withdrawn } => {
314
+ match withdrawn {
315
+ penumbra_governance:: proposal_state:: Withdrawn :: No => { }
316
+ penumbra_governance:: proposal_state:: Withdrawn :: WithReason { reason } => {
317
+ proposal_state = penumbra_governance:: proposal_state:: State :: Claimed {
318
+ outcome : penumbra_governance:: proposal_state:: Outcome :: Slashed {
319
+ withdrawn :
320
+ penumbra_governance:: proposal_state:: Withdrawn :: WithReason {
321
+ reason : truncate ( & reason, 1024 ) . to_string ( ) ,
322
+ } ,
323
+ } ,
324
+ } ;
325
+ }
326
+ }
327
+ }
328
+ } ,
329
+ }
330
+
331
+ // Store the truncated proposal state data
332
+ delta. put (
333
+ penumbra_governance:: state_key:: proposal_state ( proposal_id) ,
334
+ proposal_state. clone ( ) ,
335
+ ) ;
336
+ }
337
+ Ok ( ( ) )
338
+ }
339
+
135
340
// Since the limits are based on `String::len`, which returns
136
341
// the number of bytes, we need to truncate the UTF-8 strings at the
137
342
// correct byte boundaries.
@@ -168,10 +373,10 @@ fn truncate(s: &str, max_bytes: usize) -> &str {
168
373
}
169
374
170
375
mod tests {
171
- use super :: * ;
172
376
173
377
#[ test]
174
378
fn truncation ( ) {
379
+ use super :: truncate;
175
380
let s = "Hello, world!" ;
176
381
177
382
assert_eq ! ( truncate( s, 5 ) , "Hello" ) ;
0 commit comments