Ton

Форк
0
643 строки · 23.2 Кб
1
;; Simple configuration smart contract
2

3
#include "stdlib.fc";
4

5
() set_conf_param(int index, cell value) impure {
6
  var cs = get_data().begin_parse();
7
  var cfg_dict = cs~load_ref();
8
  cfg_dict~idict_set_ref(32, index, value);
9
  set_data(begin_cell().store_ref(cfg_dict).store_slice(cs).end_cell());
10
}
11

12
(cell, int, int, cell) load_data() inline {
13
  var cs = get_data().begin_parse();
14
  var res = (cs~load_ref(), cs~load_uint(32), cs~load_uint(256), cs~load_dict());
15
  cs.end_parse();
16
  return res;
17
}
18

19
() store_data(cfg_dict, stored_seqno, public_key, vote_dict) impure inline {
20
  set_data(begin_cell()
21
    .store_ref(cfg_dict)
22
    .store_uint(stored_seqno, 32)
23
    .store_uint(public_key, 256)
24
    .store_dict(vote_dict)
25
  .end_cell());
26
}
27

28
;; (min_tot_rounds, max_tot_rounds, min_wins, max_losses, min_store_sec, max_store_sec, bit_price, cell_price)
29
_ parse_vote_config(cell c) inline {
30
  var cs = c.begin_parse();
31
  throw_unless(44, cs~load_uint(8) == 0x36);
32
  var res = (cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(32), cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));
33
  cs.end_parse();
34
  return res;
35
}
36

37
;; cfg_vote_setup#91 normal_params:^ConfigProposalSetup critical_params:^ConfigProposalSetup = ConfigVotingSetup;
38
_ get_vote_config_internal(int critical?, cell cparam11) inline_ref {
39
  var cs = cparam11.begin_parse();
40
  throw_unless(44, cs~load_uint(8) == 0x91);
41
  if (critical?) {
42
    cs~load_ref();
43
  }
44
  return parse_vote_config(cs.preload_ref());
45
}
46

47
_ get_vote_config(int critical?) inline {
48
  return get_vote_config_internal(critical?, config_param(11));
49
}
50

51
(int, int) check_validator_set(cell vset) {
52
  var cs = vset.begin_parse();
53
  throw_unless(9, cs~load_uint(8) == 0x12);  ;; validators_ext#12 only
54
  int utime_since = cs~load_uint(32);
55
  int utime_until = cs~load_uint(32);
56
  int total = cs~load_uint(16);
57
  int main = cs~load_uint(16);
58
  throw_unless(9, main > 0);
59
  throw_unless(9, total >= main);
60
  return (utime_since, utime_until);
61
}
62

63
() send_answer(addr, query_id, ans_tag, mode) impure {
64
  ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 011000
65
  send_raw_message(begin_cell()
66
    .store_uint(0x18, 6)
67
    .store_slice(addr)
68
    .store_uint(0, 5 + 4 + 4 + 64 + 32 + 1 + 1)
69
    .store_uint(ans_tag, 32)
70
    .store_uint(query_id, 64)
71
  .end_cell(), mode);
72
}
73

74
() send_confirmation(addr, query_id, ans_tag) impure inline {
75
  return send_answer(addr, query_id, ans_tag, 64);
76
}
77

78
() send_error(addr, query_id, ans_tag) impure inline {
79
  return send_answer(addr, query_id, ans_tag, 64);
80
}
81

82
;; forward a message to elector smart contract to make it upgrade its code
83
() change_elector_code(slice cs) impure {
84
  var dest_addr = config_param(1).begin_parse().preload_uint(256);
85
  var query_id = now();
86
  send_raw_message(begin_cell()
87
   .store_uint(0xc4ff, 17)
88
   .store_uint(dest_addr, 256)
89
   .store_grams(1 << 30)         ;; ~ 1 Gram (will be returned back)
90
   .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
91
   .store_uint(0x4e436f64, 32)   ;; action
92
   .store_uint(query_id, 64)
93
   .store_slice(cs)
94
  .end_cell(), 0);
95
}
96

97
() after_code_upgrade(slice param, cont old_code) impure method_id(1666) {
98
}
99

100
_ perform_action(cfg_dict, public_key, action, cs) inline_ref {
101
  if (action == 0x43665021) {
102
    ;; change one configuration parameter
103
    var param_index = cs~load_int(32);
104
    var param_value = cs~load_ref();
105
    cs.end_parse();
106
    cfg_dict~idict_set_ref(32, param_index, param_value);
107
    return (cfg_dict, public_key);
108
  } elseif (action == 0x4e436f64) {
109
    ;; change configuration smart contract code
110
    var new_code = cs~load_ref();
111
    set_code(new_code);
112
    var old_code = get_c3();
113
    set_c3(new_code.begin_parse().bless());
114
    after_code_upgrade(cs, old_code);
115
    throw(0);
116
    return (cfg_dict, public_key);
117
  } elseif (action == 0x50624b21) {
118
    ;; change configuration master public key
119
    public_key = cs~load_uint(256);
120
    cs.end_parse();
121
    return (cfg_dict, public_key);
122
  } elseif (action == 0x4e43ef05) {
123
    ;; change election smart contract code
124
    change_elector_code(cs);
125
    return (cfg_dict, public_key);
126
  } else {
127
    throw_if(32, action);
128
    return (cfg_dict, public_key);
129
  }
130
}
131

132
(cell, int, cell) get_current_vset() inline_ref {
133
  var vset = config_param(34);
134
  var cs = begin_parse(vset);
135
  ;; validators_ext#12 utime_since:uint32 utime_until:uint32 
136
  ;; total:(## 16) main:(## 16) { main <= total } { main >= 1 } 
137
  ;; total_weight:uint64
138
  throw_unless(40, cs~load_uint(8) == 0x12);
139
  cs~skip_bits(32 + 32 + 16 + 16);
140
  var (total_weight, dict) = (cs~load_uint(64), cs~load_dict());
141
  cs.end_parse();
142
  return (vset, total_weight, dict);
143
}
144

145
(slice, int) get_validator_descr(int idx) inline_ref {
146
  var (vset, total_weight, dict) = get_current_vset();
147
  var (value, _) = dict.udict_get?(16, idx);
148
  return (value, total_weight);
149
}
150

151
(int, int) unpack_validator_descr(slice cs) inline {
152
  ;; ed25519_pubkey#8e81278a pubkey:bits256 = SigPubKey;
153
  ;; validator#53 public_key:SigPubKey weight:uint64 = ValidatorDescr;
154
  ;; validator_addr#73 public_key:SigPubKey weight:uint64 adnl_addr:bits256 = ValidatorDescr;
155
  throw_unless(41, (cs~load_uint(8) & ~ 0x20) == 0x53);
156
  throw_unless(41, cs~load_uint(32) == 0x8e81278a);
157
  return (cs~load_uint(256), cs~load_uint(64));
158
}
159

160
;; cfg_proposal#f3 param_id:int32 param_value:(Maybe ^Cell) if_hash_equal:(Maybe uint256)
161
;; c -> (param-id param-cell maybe-hash)
162
(int, cell, int) parse_config_proposal(cell c) inline_ref {
163
  var cs = c.begin_parse();
164
  throw_unless(44, cs~load_int(8) == 0xf3 - 0x100);
165
  var (id, val, hash) = (cs~load_int(32), cs~load_maybe_ref(), cs~load_int(1));
166
  if (hash) {
167
    hash = cs~load_uint(256);
168
  } else {
169
    hash = -1;
170
  }
171
  cs.end_parse();
172
  return (id, val, hash);
173
}
174

175
(cell, int, cell) accept_proposal(cell cfg_dict, cell proposal, int critical?) inline_ref {
176
  var (param_id, param_val, req_hash) = parse_config_proposal(proposal);
177
  cell cur_val = cfg_dict.idict_get_ref(32, param_id);
178
  int cur_hash = null?(cur_val) ? 0 : cell_hash(cur_val);
179
  if ((cur_hash != req_hash) & (req_hash >= 0)) {
180
    ;; current value has incorrect hash, do not apply changes
181
    return (cfg_dict, 0, null());
182
  }
183
  cell mparams = cfg_dict.idict_get_ref(32, 9);  ;; mandatory parameters
184
  var (_, found?) = mparams.idict_get?(32, param_id);
185
  if (found? & param_val.null?()) {
186
    ;; cannot set a mandatory parameter to (null)
187
    return (cfg_dict, 0, null());
188
  }
189
  cell cparams = cfg_dict.idict_get_ref(32, 10);  ;; critical parameters
190
  (_, found?) = cparams.idict_get?(32, param_id);
191
  if (found? < critical?) {
192
    ;; trying to set a critical parameter after a non-critical voting
193
    return (cfg_dict, 0, null());
194
  }
195
  ;; CHANGE ONE CONFIGURATION PARAMETER (!)
196
  cfg_dict~idict_set_ref(32, param_id, param_val);
197
  return (cfg_dict, param_id, param_val);
198
}
199

200
(cell, int) perform_proposed_action(cell cfg_dict, int public_key, int param_id, cell param_val) inline_ref {
201
  if (param_id == -999) {
202
    ;; appoint or depose dictator
203
    return (cfg_dict, param_val.null?() ? 0 : param_val.begin_parse().preload_uint(256));
204
  }
205
  if (param_val.null?()) {
206
    return (cfg_dict, public_key);
207
  }
208
  if (param_id == -1000) {
209
    ;; upgrade code
210
    var cs = param_val.begin_parse();
211
    var new_code = cs~load_ref();
212
    set_code(new_code);
213
    var old_code = get_c3();
214
    set_c3(new_code.begin_parse().bless());
215
    after_code_upgrade(cs, old_code);
216
    throw(0);
217
    return (cfg_dict, public_key);
218
  }
219
  if (param_id == -1001) {
220
    ;; update elector code
221
    var cs = param_val.begin_parse();
222
    change_elector_code(cs);
223
  }
224
  return (cfg_dict, public_key);
225
}
226

227
;; cfg_proposal_status#ce expires:uint32 proposal:^ConfigProposal is_critical:Bool
228
;;  voters:(HashmapE 16 True) remaining_weight:int64 validator_set_id:uint256
229
;;  rounds_remaining:uint8 wins:uint8 losses:uint8 = ConfigProposalStatus;
230
(int, cell, int, cell, int, int, slice) unpack_proposal_status(slice cs) inline_ref {
231
  throw_unless(44, cs~load_int(8) == 0xce - 0x100);
232
  return (cs~load_uint(32), cs~load_ref(), cs~load_int(1), cs~load_dict(), cs~load_int(64), cs~load_uint(256), cs);
233
}
234

235
slice update_proposal_status(slice rest, int weight_remaining, int critical?) inline_ref {
236
  var (min_tot_rounds, max_tot_rounds, min_wins, max_losses, _, _, _, _) = get_vote_config(critical?);
237
  var (rounds_remaining, wins, losses) = (rest~load_uint(8), rest~load_uint(8), rest~load_uint(8));
238
  losses -= (weight_remaining >= 0);
239
  if (losses > max_losses) {
240
    ;; lost too many times
241
    return null();
242
  }
243
  rounds_remaining -= 1;
244
  if (rounds_remaining < 0) {
245
    ;; existed for too many rounds
246
    return null();
247
  }
248
  return begin_cell()
249
    .store_uint(rounds_remaining, 8)
250
    .store_uint(wins, 8)
251
    .store_uint(losses, 8)
252
  .end_cell().begin_parse();
253
}
254

255
builder begin_pack_proposal_status(int expires, cell proposal, int critical?, cell voters, int weight_remaining, int vset_id) inline {
256
  return begin_cell()
257
    .store_int(0xce - 0x100, 8)
258
    .store_uint(expires, 32)
259
    .store_ref(proposal)
260
    .store_int(critical?, 1)
261
    .store_dict(voters)
262
    .store_int(weight_remaining, 64)
263
    .store_uint(vset_id, 256);
264
}
265

266
(cell, cell, int) register_vote(vote_dict, phash, idx, weight) inline_ref {
267
  var (pstatus, found?) = vote_dict.udict_get?(256, phash);
268
  ifnot (found?) {
269
    ;; config proposal not found
270
    return (vote_dict, null(), -1);
271
  }
272
  var (cur_vset, total_weight, _) = get_current_vset();
273
  int cur_vset_id = cur_vset.cell_hash();
274
  var (expires, proposal, critical?, voters, weight_remaining, vset_id, rest) = unpack_proposal_status(pstatus);
275
  if (expires <= now()) {
276
    ;; config proposal expired, delete and report not found
277
    vote_dict~udict_delete?(256, phash);
278
    return (vote_dict, null(), -1);
279
  }
280
  if (vset_id != cur_vset_id) {
281
    ;; config proposal belongs to a previous validator set
282
    vset_id = cur_vset_id;
283
    rest = update_proposal_status(rest, weight_remaining, critical?);
284
    voters = null();
285
    weight_remaining = muldiv(total_weight, 3, 4);
286
  }
287
  if (rest.null?()) {
288
    ;; discard proposal (existed for too many rounds, or too many losses)
289
    vote_dict~udict_delete?(256, phash);
290
    return (vote_dict, null(), -1);
291
  }
292
  var (_, found?) = voters.udict_get?(16, idx);
293
  if (found?) {
294
    ;; already voted for this proposal, ignore vote
295
    return (vote_dict, null(), -2);
296
  }
297
  ;; register vote
298
  voters~udict_set_builder(16, idx, begin_cell().store_uint(now(), 32));
299
  int old_wr = weight_remaining;
300
  weight_remaining -= weight;
301
  if ((weight_remaining ^ old_wr) >= 0) {
302
    ;; not enough votes, or proposal already accepted in this round
303
    ;; simply update weight_remaining
304
    vote_dict~udict_set_builder(256, phash, begin_pack_proposal_status(expires, proposal, critical?, voters, weight_remaining, vset_id).store_slice(rest));
305
    return (vote_dict, null(), 2);
306
  }
307
  ;; proposal wins in this round
308
  var (min_tot_rounds, max_tot_rounds, min_wins, max_losses, _, _, _, _) = get_vote_config(critical?);
309
  var (rounds_remaining, wins, losses) = (rest~load_uint(8), rest~load_uint(8), rest~load_uint(8));
310
  wins += 1;
311
  if (wins >= min_wins) {
312
    ;; proposal is accepted, remove and process
313
    vote_dict~udict_delete?(256, phash);
314
    return (vote_dict, proposal, 6 - critical?);
315
  }
316
  ;; update proposal info
317
  vote_dict~udict_set_builder(256, phash,
318
    begin_pack_proposal_status(expires, proposal, critical?, voters, weight_remaining, vset_id)
319
    .store_uint(rounds_remaining, 8)
320
    .store_uint(wins, 8)
321
    .store_uint(losses, 8));
322
  return (vote_dict, null(), 2);
323
}
324

325
int proceed_register_vote(phash, idx, weight) impure inline_ref {
326
  var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data();
327
  (vote_dict, var accepted_proposal, var status) = register_vote(vote_dict, phash, idx, weight);
328
  store_data(cfg_dict, stored_seqno, public_key, vote_dict);
329
  ifnot (accepted_proposal.null?()) {
330
    var critical? = 6 - status;
331
    (cfg_dict, var param_id, var param_val) = accept_proposal(cfg_dict, accepted_proposal, critical?);
332
    store_data(cfg_dict, stored_seqno, public_key, vote_dict);
333
    if (param_id) {
334
      commit();
335
      (cfg_dict, public_key) = perform_proposed_action(cfg_dict, public_key, param_id, param_val);
336
      store_data(cfg_dict, stored_seqno, public_key, vote_dict);
337
    }
338
  }
339
  return status;
340
}
341

342
(slice, int) scan_proposal(int phash, slice pstatus) inline_ref {
343
  var (cur_vset, total_weight, _) = get_current_vset();
344
  int cur_vset_id = cur_vset.cell_hash();
345
  var (expires, proposal, critical?, voters, weight_remaining, vset_id, rest) = unpack_proposal_status(pstatus);
346
  if (expires <= now()) {
347
    ;; config proposal expired, delete
348
    return (null(), true);
349
  }
350
  if (vset_id == cur_vset_id) {
351
    ;; config proposal already processed or voted for in this round, change nothing
352
    return (pstatus, false);
353
  }
354
  ;; config proposal belongs to a previous validator set
355
  vset_id = cur_vset_id;
356
  rest = update_proposal_status(rest, weight_remaining, critical?);
357
  voters = null();
358
  weight_remaining = muldiv(total_weight, 3, 4);
359
  if (rest.null?()) {
360
    ;; discard proposal (existed for too many rounds, or too many losses)
361
    return (null(), true);
362
  }
363
  ;; return updated proposal
364
  return (begin_pack_proposal_status(expires, proposal, critical?, voters, weight_remaining, vset_id).store_slice(rest).end_cell().begin_parse(), true);
365
}
366

367
cell scan_random_proposal(cell vote_dict) inline_ref {
368
  var (phash, pstatus, found?) = vote_dict.udict_get_nexteq?(256, random());
369
  ifnot (found?) {
370
    return vote_dict;
371
  }
372
  (pstatus, var changed?) = scan_proposal(phash, pstatus);
373
  if (changed?) {
374
    if (pstatus.null?()) {
375
      vote_dict~udict_delete?(256, phash);
376
    } else {
377
      vote_dict~udict_set(256, phash, pstatus);
378
    }
379
  }
380
  return vote_dict;
381
}
382

383
int register_voting_proposal(slice cs, int msg_value) impure inline_ref {
384
  var (expire_at, proposal, critical?) = (cs~load_uint(32), cs~load_ref(), cs~load_int(1));
385
  if (expire_at >> 30) {
386
    expire_at -= now();
387
  }
388
  var (param_id, param_val, hash) = parse_config_proposal(proposal);
389
  if (hash >= 0) {
390
    cell cur_val = config_param(param_id);
391
    int cur_hash = null?(cur_val) ? 0 : cell_hash(cur_val);
392
    if (cur_hash != hash) {
393
      hash = -0xe2646356;  ;; bad current value
394
    }
395
  } else {
396
    var m_params = config_param(9);
397
    var (_, found?) = m_params.idict_get?(32, param_id);
398
    if (found?) {
399
      hash = -0xcd506e6c;  ;; cannot set mandatory parameter to null
400
    }
401
  }
402
  if (param_val.cell_depth() >= 256) {
403
    hash = -0xc2616456;  ;; bad value
404
  }
405
  if (hash < -1) {
406
    return hash;  ;; return error if any
407
  }
408
  ifnot (critical?) {
409
    var crit_params = config_param(10);
410
    var (_, found?) = crit_params.idict_get?(32, param_id);
411
    if (found?) {
412
      hash = -0xc3726954;  ;; trying to set a critical parameter without critical flag
413
    }
414
  }
415
  if (hash < -1) {
416
    return hash;
417
  }
418
  ;; obtain vote proposal configuration
419
  var vote_cfg = get_vote_config(critical?);
420
  var (min_tot_rounds, max_tot_rounds, min_wins, max_losses, min_store_sec, max_store_sec, bit_price, cell_price) = vote_cfg;
421
  if (expire_at < min_store_sec) {
422
    return -0xc5787069;   ;; expired
423
  }
424
  expire_at = min(expire_at, max_store_sec);
425
  ;; compute price
426
  var (_, bits, refs) = compute_data_size(param_val, 1024);
427
  var pps = bit_price * (bits + 1024) + cell_price * (refs + 2);
428
  var price = pps * expire_at;
429
  expire_at += now();
430
  var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data();
431
  int phash = proposal.cell_hash();
432
  var (pstatus, found?) = vote_dict.udict_get?(256, phash);
433
  if (found?) {
434
    ;; proposal already exists; we can only extend it
435
    var (expires, r_proposal, r_critical?, voters, weight_remaining, vset_id, rest) = unpack_proposal_status(pstatus);
436
    if (r_critical? != critical?) {
437
      return -0xc3726955;  ;; cannot upgrade critical parameter to non-critical...
438
    }
439
    if (expires >= expire_at) {
440
      return -0xc16c7245;  ;; proposal already exists
441
    }
442
    ;; recompute price
443
    price = pps * (expire_at - expires + 16384);
444
    if (msg_value - price < (1 << 30)) {
445
      return -0xf0617924;   ;; need more money
446
    }
447
    ;; update expiration time
448
    vote_dict~udict_set_builder(256, phash, begin_pack_proposal_status(expire_at, r_proposal, r_critical?, voters, weight_remaining, vset_id).store_slice(rest));
449
    store_data(cfg_dict, stored_seqno, public_key, vote_dict);
450
    return price;
451
  }
452
  if (msg_value - price < (1 << 30)) {
453
    return -0xf0617924;   ;; need more money
454
  }
455
  ;; obtain current validator set data
456
  var (vset, total_weight, _) = get_current_vset();
457
  int weight_remaining = muldiv(total_weight, 3, 4);
458
  ;; create new proposal
459
  vote_dict~udict_set_builder(256, phash,
460
    begin_pack_proposal_status(expire_at, proposal, critical?, null(), weight_remaining, vset.cell_hash())
461
    .store_uint(max_tot_rounds, 8).store_uint(0, 16));
462
  store_data(cfg_dict, stored_seqno, public_key, vote_dict);
463
  return price;
464
}
465

466
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure {
467
  var cs = in_msg_cell.begin_parse();
468
  var flags = cs~load_uint(4);  ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
469
  var s_addr = cs~load_msg_addr();
470
  (int src_wc, int src_addr) = s_addr.parse_std_addr();
471
  if ((src_wc + 1) | (flags & 1) | in_msg.slice_empty?()) {
472
    ;; source not in masterchain, or a bounced message, or a simple transfer
473
    return ();
474
  }
475
  int tag = in_msg~load_uint(32);
476
  int query_id = in_msg~load_uint(64);
477
  if (tag == 0x4e565354) {
478
    ;; set next validator set
479
    var vset = in_msg~load_ref();
480
    in_msg.end_parse();
481
    var elector_param = config_param(1);
482
    var elector_addr = cell_null?(elector_param) ? -1 : elector_param.begin_parse().preload_uint(256);
483
    var ok = false;
484
    if (src_addr == elector_addr) {
485
      ;; message from elector smart contract
486
      ;; set next validator set
487
      (var t_since, var t_until) = check_validator_set(vset);
488
      var t = now();
489
      ok = (t_since > t) & (t_until > t_since);
490
    }
491
    if (ok) {
492
      set_conf_param(36, vset);
493
      ;; send confirmation
494
      return send_confirmation(s_addr, query_id, 0xee764f4b);
495
    } else {
496
      return send_error(s_addr, query_id, 0xee764f6f);
497
    }
498
  }
499
  if (tag == 0x6e565052) {
500
    ;; new voting proposal
501
    var price = register_voting_proposal(in_msg, msg_value);
502
    int mode = 64;
503
    int ans_tag = - price;
504
    if (price >= 0) {
505
      ;; ok, debit price
506
      raw_reserve(price, 4);
507
      ans_tag = 0xee565052;
508
      mode = 128;
509
    }
510
    return send_answer(s_addr, query_id, ans_tag, mode);
511
  }
512
  if (tag == 0x566f7465) {
513
    ;; vote for a configuration proposal
514
    var signature = in_msg~load_bits(512);
515
    var msg_body = in_msg;
516
    var (sign_tag, idx, phash) = (in_msg~load_uint(32), in_msg~load_uint(16), in_msg~load_uint(256));
517
    in_msg.end_parse();
518
    throw_unless(37, sign_tag == 0x566f7445);
519
    var (vdescr, total_weight) = get_validator_descr(idx);
520
    var (val_pubkey, weight) = unpack_validator_descr(vdescr);
521
    throw_unless(34, check_data_signature(msg_body, signature, val_pubkey));
522
    int res = proceed_register_vote(phash, idx, weight);
523
    return send_confirmation(s_addr, query_id, res + 0xd6745240);
524
  }
525
  ;; if tag is non-zero and its higher bit is zero, throw an exception (the message is an unsupported query)
526
  ;; to bounce message back to sender
527
  throw_unless(37, (tag == 0) | (tag & (1 << 31)));
528
  ;; do nothing for other internal messages
529
}
530

531
() recv_external(slice in_msg) impure {
532
  var signature = in_msg~load_bits(512);
533
  var cs = in_msg;
534
  int action = cs~load_uint(32);
535
  int msg_seqno = cs~load_uint(32);
536
  var valid_until = cs~load_uint(32);
537
  throw_if(35, valid_until < now());
538
  throw_if(39, slice_depth(cs) > 128);
539
  var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data();
540
  throw_unless(33, msg_seqno == stored_seqno);
541
  if (action == 0x566f7465) {
542
    ;; vote for a configuration proposal
543
    var (idx, phash) = (cs~load_uint(16), cs~load_uint(256));
544
    cs.end_parse();
545
    var (vdescr, total_weight) = get_validator_descr(idx);
546
    var (val_pubkey, weight) = unpack_validator_descr(vdescr);
547
    throw_unless(34, check_data_signature(in_msg, signature, val_pubkey));
548
    accept_message();
549
    stored_seqno = (stored_seqno + 1) % (1 << 32);
550
    store_data(cfg_dict, stored_seqno, public_key, vote_dict);
551
    commit();
552
    proceed_register_vote(phash, idx, weight);
553
    return ();
554
  }
555
  throw_unless(34, check_signature(slice_hash(in_msg), signature, public_key));
556
  accept_message();
557
  stored_seqno = (stored_seqno + 1) % (1 << 32);
558
  store_data(cfg_dict, stored_seqno, public_key, vote_dict);
559
  commit();
560
  (cfg_dict, public_key) = perform_action(cfg_dict, public_key, action, cs);
561
  store_data(cfg_dict, stored_seqno, public_key, vote_dict);
562
}
563

564
() run_ticktock(int is_tock) impure {
565
  var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data();
566
  int kl = 32;
567
  var next_vset = cfg_dict.idict_get_ref(kl, 36);
568
  var updated? = false;
569
  ifnot (next_vset.null?()) {
570
    ;; check whether we have to set next_vset as the current validator set
571
    var ds = next_vset.begin_parse();
572
    if (ds.slice_bits() >= 40) {
573
      var tag = ds~load_uint(8);
574
      var since = ds.preload_uint(32);
575
      if ((since <= now()) & (tag == 0x12)) {
576
        ;; next validator set becomes active!
577
        var cur_vset = cfg_dict~idict_set_get_ref(kl, 34, next_vset);  ;; next_vset -> cur_vset
578
        cfg_dict~idict_set_get_ref(kl, 32, cur_vset);   ;; cur_vset -> prev_vset
579
        cfg_dict~idict_delete?(kl, 36);             ;; (null) -> next_vset
580
        updated? = true;
581
      }
582
    }
583
  }
584
  ifnot (updated?) {
585
    ;; if nothing has been done so far, scan a random voting proposal instead
586
    vote_dict = scan_random_proposal(vote_dict);
587
  }
588
  ;; save data and return
589
  return store_data(cfg_dict, stored_seqno, public_key, vote_dict);
590
}
591

592
int seqno() method_id {
593
  return get_data().begin_parse().preload_uint(32);
594
}
595

596
_ unpack_proposal(slice pstatus) inline_ref {
597
  (int expires, cell proposal, int critical?, cell voters, int weight_remaining, int vset_id, slice rest) = unpack_proposal_status(pstatus);
598
  var voters_list = null();
599
  var voter_id = (1 << 32);
600
  do {
601
    (voter_id, _, var f) = voters.udict_get_prev?(16, voter_id);
602
    if (f) {
603
      voters_list = cons(voter_id, voters_list);
604
    }
605
  } until (~ f);
606
  var (rounds_remaining, losses, wins) = (rest~load_uint(8), rest~load_uint(8), rest~load_uint(8));
607
  rest.end_parse();
608
  var (param_id, param_val, param_hash) = parse_config_proposal(proposal);
609
  return [expires, critical?, [param_id, param_val, param_hash], vset_id, voters_list, weight_remaining, rounds_remaining, losses, wins];
610
}
611

612
_ get_proposal(int phash) method_id {
613
  (_, _, _, var vote_dict) = load_data();
614
  var (pstatus, found?) = vote_dict.udict_get?(256, phash);
615
  ifnot (found?) {
616
    return null();
617
  }
618
  return unpack_proposal(pstatus);
619
}
620

621
_ list_proposals() method_id {
622
  (_, _, _, var vote_dict) = load_data();
623
  var phash = (1 << 255) + ((1 << 255) - 1);
624
  var list = null();
625
  do {
626
    (phash, var pstatus, var f) = vote_dict.udict_get_prev?(256, phash);
627
    if (f) {
628
      list = cons([phash, unpack_proposal(pstatus)], list);
629
    }
630
  } until (~ f);
631
  return list;
632
}
633

634
_ proposal_storage_price(int critical?, int seconds, int bits, int refs) method_id {
635
  var cfg_dict = get_data().begin_parse().preload_ref();
636
  var cparam11 = cfg_dict.idict_get_ref(32, 11);
637
  var (min_tot_rounds, max_tot_rounds, min_wins, max_losses, min_store_sec, max_store_sec, bit_price, cell_price) = get_vote_config_internal(critical?, cparam11);
638
  if (seconds < min_store_sec) {
639
    return -1;
640
  }
641
  seconds = min(seconds, max_store_sec);
642
  return (bit_price * (bits + 1024) + cell_price * (refs + 2)) * seconds;
643
}
644

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.