/
sui_system.move
765 lines (695 loc) · 29.7 KB
/
sui_system.move
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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
/// Sui System State Type Upgrade Guide
/// `SuiSystemState` is a thin wrapper around `SuiSystemStateInner` that provides a versioned interface.
/// The `SuiSystemState` object has a fixed ID 0x5, and the `SuiSystemStateInner` object is stored as a dynamic field.
/// There are a few different ways to upgrade the `SuiSystemStateInner` type:
///
/// The simplest and one that doesn't involve a real upgrade is to just add dynamic fields to the `extra_fields` field
/// of `SuiSystemStateInner` or any of its sub type. This is useful when we are in a rush, or making a small change,
/// or still experimenting a new field.
///
/// To properly upgrade the `SuiSystemStateInner` type, we need to ship a new framework that does the following:
/// 1. Define a new `SuiSystemStateInner`type (e.g. `SuiSystemStateInnerV2`).
/// 2. Define a data migration function that migrates the old `SuiSystemStateInner` to the new one (i.e. SuiSystemStateInnerV2).
/// 3. Replace all uses of `SuiSystemStateInner` with `SuiSystemStateInnerV2` in both sui_system.move and sui_system_state_inner.move,
/// with the exception of the `sui_system_state_inner::create` function, which should always return the genesis type.
/// 4. Inside `load_inner_maybe_upgrade` function, check the current version in the wrapper, and if it's not the latest version,
/// call the data migration function to upgrade the inner object. Make sure to also update the version in the wrapper.
/// A detailed example can be found in sui/tests/framework_upgrades/mock_sui_systems/shallow_upgrade.
/// Along with the Move change, we also need to update the Rust code to support the new type. This includes:
/// 1. Define a new `SuiSystemStateInner` struct type that matches the new Move type, and implement the SuiSystemStateTrait.
/// 2. Update the `SuiSystemState` struct to include the new version as a new enum variant.
/// 3. Update the `get_sui_system_state` function to handle the new version.
/// To test that the upgrade will be successful, we need to modify `sui_system_state_production_upgrade_test` test in
/// protocol_version_tests and trigger a real upgrade using the new framework. We will need to keep this directory as old version,
/// put the new framework in a new directory, and run the test to exercise the upgrade.
///
/// To upgrade Validator type, besides everything above, we also need to:
/// 1. Define a new Validator type (e.g. ValidatorV2).
/// 2. Define a data migration function that migrates the old Validator to the new one (i.e. ValidatorV2).
/// 3. Replace all uses of Validator with ValidatorV2 except the genesis creation function.
/// 4. In validator_wrapper::upgrade_to_latest, check the current version in the wrapper, and if it's not the latest version,
/// call the data migration function to upgrade it.
/// In Rust, we also need to add a new case in `get_validator_from_table`.
/// Note that it is possible to upgrade SuiSystemStateInner without upgrading Validator, but not the other way around.
/// And when we only upgrade SuiSystemStateInner, the version of Validator in the wrapper will not be updated, and hence may become
/// inconsistent with the version of SuiSystemStateInner. This is fine as long as we don't use the Validator version to determine
/// the SuiSystemStateInner version, or vice versa.
module sui_system::sui_system {
use sui::balance::Balance;
use sui::coin::Coin;
use sui_system::staking_pool::StakedSui;
use sui::sui::SUI;
use sui::table::Table;
use sui_system::validator::Validator;
use sui_system::validator_cap::UnverifiedValidatorOperationCap;
use sui_system::sui_system_state_inner::{Self, SystemParameters, SuiSystemStateInner, SuiSystemStateInnerV2};
use sui_system::stake_subsidy::StakeSubsidy;
use sui_system::staking_pool::PoolTokenExchangeRate;
use sui::dynamic_field;
#[test_only] use sui::balance;
#[test_only] use sui_system::validator_set::ValidatorSet;
#[test_only] use sui::vec_set::VecSet;
public struct SuiSystemState has key {
id: UID,
version: u64,
}
const ENotSystemAddress: u64 = 0;
const EWrongInnerVersion: u64 = 1;
// ==== functions that can only be called by genesis ====
/// Create a new SuiSystemState object and make it shared.
/// This function will be called only once in genesis.
public(package) fun create(
id: UID,
validators: vector<Validator>,
storage_fund: Balance<SUI>,
protocol_version: u64,
epoch_start_timestamp_ms: u64,
parameters: SystemParameters,
stake_subsidy: StakeSubsidy,
ctx: &mut TxContext,
) {
let system_state = sui_system_state_inner::create(
validators,
storage_fund,
protocol_version,
epoch_start_timestamp_ms,
parameters,
stake_subsidy,
ctx,
);
let version = sui_system_state_inner::genesis_system_state_version();
let mut self = SuiSystemState {
id,
version,
};
dynamic_field::add(&mut self.id, version, system_state);
transfer::share_object(self);
}
// ==== entry functions ====
/// Can be called by anyone who wishes to become a validator candidate and starts accuring delegated
/// stakes in their staking pool. Once they have at least `MIN_VALIDATOR_JOINING_STAKE` amount of stake they
/// can call `request_add_validator` to officially become an active validator at the next epoch.
/// Aborts if the caller is already a pending or active validator, or a validator candidate.
/// Note: `proof_of_possession` MUST be a valid signature using sui_address and protocol_pubkey_bytes.
/// To produce a valid PoP, run [fn test_proof_of_possession].
public entry fun request_add_validator_candidate(
wrapper: &mut SuiSystemState,
pubkey_bytes: vector<u8>,
network_pubkey_bytes: vector<u8>,
worker_pubkey_bytes: vector<u8>,
proof_of_possession: vector<u8>,
name: vector<u8>,
description: vector<u8>,
image_url: vector<u8>,
project_url: vector<u8>,
net_address: vector<u8>,
p2p_address: vector<u8>,
primary_address: vector<u8>,
worker_address: vector<u8>,
gas_price: u64,
commission_rate: u64,
ctx: &mut TxContext,
) {
let self = load_system_state_mut(wrapper);
self.request_add_validator_candidate(
pubkey_bytes,
network_pubkey_bytes,
worker_pubkey_bytes,
proof_of_possession,
name,
description,
image_url,
project_url,
net_address,
p2p_address,
primary_address,
worker_address,
gas_price,
commission_rate,
ctx,
)
}
/// Called by a validator candidate to remove themselves from the candidacy. After this call
/// their staking pool becomes deactivate.
public entry fun request_remove_validator_candidate(
wrapper: &mut SuiSystemState,
ctx: &mut TxContext,
) {
let self = load_system_state_mut(wrapper);
self.request_remove_validator_candidate(ctx)
}
/// Called by a validator candidate to add themselves to the active validator set beginning next epoch.
/// Aborts if the validator is a duplicate with one of the pending or active validators, or if the amount of
/// stake the validator has doesn't meet the min threshold, or if the number of new validators for the next
/// epoch has already reached the maximum.
public entry fun request_add_validator(
wrapper: &mut SuiSystemState,
ctx: &mut TxContext,
) {
let self = load_system_state_mut(wrapper);
self.request_add_validator(ctx)
}
/// A validator can call this function to request a removal in the next epoch.
/// We use the sender of `ctx` to look up the validator
/// (i.e. sender must match the sui_address in the validator).
/// At the end of the epoch, the `validator` object will be returned to the sui_address
/// of the validator.
public entry fun request_remove_validator(
wrapper: &mut SuiSystemState,
ctx: &mut TxContext,
) {
let self = load_system_state_mut(wrapper);
self.request_remove_validator(ctx)
}
/// A validator can call this entry function to submit a new gas price quote, to be
/// used for the reference gas price calculation at the end of the epoch.
public entry fun request_set_gas_price(
wrapper: &mut SuiSystemState,
cap: &UnverifiedValidatorOperationCap,
new_gas_price: u64,
) {
let self = load_system_state_mut(wrapper);
self.request_set_gas_price(cap, new_gas_price)
}
/// This entry function is used to set new gas price for candidate validators
public entry fun set_candidate_validator_gas_price(
wrapper: &mut SuiSystemState,
cap: &UnverifiedValidatorOperationCap,
new_gas_price: u64,
) {
let self = load_system_state_mut(wrapper);
self.set_candidate_validator_gas_price(cap, new_gas_price)
}
/// A validator can call this entry function to set a new commission rate, updated at the end of
/// the epoch.
public entry fun request_set_commission_rate(
wrapper: &mut SuiSystemState,
new_commission_rate: u64,
ctx: &mut TxContext,
) {
let self = load_system_state_mut(wrapper);
self.request_set_commission_rate(new_commission_rate, ctx)
}
/// This entry function is used to set new commission rate for candidate validators
public entry fun set_candidate_validator_commission_rate(
wrapper: &mut SuiSystemState,
new_commission_rate: u64,
ctx: &mut TxContext,
) {
let self = load_system_state_mut(wrapper);
self.set_candidate_validator_commission_rate(new_commission_rate, ctx)
}
/// Add stake to a validator's staking pool.
public entry fun request_add_stake(
wrapper: &mut SuiSystemState,
stake: Coin<SUI>,
validator_address: address,
ctx: &mut TxContext,
) {
let staked_sui = request_add_stake_non_entry(wrapper, stake, validator_address, ctx);
transfer::public_transfer(staked_sui, ctx.sender());
}
/// The non-entry version of `request_add_stake`, which returns the staked SUI instead of transferring it to the sender.
public fun request_add_stake_non_entry(
wrapper: &mut SuiSystemState,
stake: Coin<SUI>,
validator_address: address,
ctx: &mut TxContext,
): StakedSui {
let self = load_system_state_mut(wrapper);
self.request_add_stake(stake, validator_address, ctx)
}
/// Add stake to a validator's staking pool using multiple coins.
public entry fun request_add_stake_mul_coin(
wrapper: &mut SuiSystemState,
stakes: vector<Coin<SUI>>,
stake_amount: option::Option<u64>,
validator_address: address,
ctx: &mut TxContext,
) {
let self = load_system_state_mut(wrapper);
let staked_sui = self.request_add_stake_mul_coin(stakes, stake_amount, validator_address, ctx);
transfer::public_transfer(staked_sui, ctx.sender());
}
/// Withdraw stake from a validator's staking pool.
public entry fun request_withdraw_stake(
wrapper: &mut SuiSystemState,
staked_sui: StakedSui,
ctx: &mut TxContext,
) {
let withdrawn_stake = request_withdraw_stake_non_entry(wrapper, staked_sui, ctx);
transfer::public_transfer(withdrawn_stake.into_coin(ctx), ctx.sender());
}
/// Non-entry version of `request_withdraw_stake` that returns the withdrawn SUI instead of transferring it to the sender.
public fun request_withdraw_stake_non_entry(
wrapper: &mut SuiSystemState,
staked_sui: StakedSui,
ctx: &mut TxContext,
) : Balance<SUI> {
let self = load_system_state_mut(wrapper);
self.request_withdraw_stake(staked_sui, ctx)
}
/// Report a validator as a bad or non-performant actor in the system.
/// Succeeds if all the following are satisfied:
/// 1. both the reporter in `cap` and the input `reportee_addr` are active validators.
/// 2. reporter and reportee not the same address.
/// 3. the cap object is still valid.
/// This function is idempotent.
public entry fun report_validator(
wrapper: &mut SuiSystemState,
cap: &UnverifiedValidatorOperationCap,
reportee_addr: address,
) {
let self = load_system_state_mut(wrapper);
self.report_validator(cap, reportee_addr)
}
/// Undo a `report_validator` action. Aborts if
/// 1. the reportee is not a currently active validator or
/// 2. the sender has not previously reported the `reportee_addr`, or
/// 3. the cap is not valid
public entry fun undo_report_validator(
wrapper: &mut SuiSystemState,
cap: &UnverifiedValidatorOperationCap,
reportee_addr: address,
) {
let self = load_system_state_mut(wrapper);
self.undo_report_validator(cap, reportee_addr)
}
// ==== validator metadata management functions ====
/// Create a new `UnverifiedValidatorOperationCap`, transfer it to the
/// validator and registers it. The original object is thus revoked.
public entry fun rotate_operation_cap(
self: &mut SuiSystemState,
ctx: &mut TxContext,
) {
let self = load_system_state_mut(self);
self.rotate_operation_cap(ctx)
}
/// Update a validator's name.
public entry fun update_validator_name(
self: &mut SuiSystemState,
name: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_validator_name(name, ctx)
}
/// Update a validator's description
public entry fun update_validator_description(
self: &mut SuiSystemState,
description: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_validator_description(description, ctx)
}
/// Update a validator's image url
public entry fun update_validator_image_url(
self: &mut SuiSystemState,
image_url: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_validator_image_url(image_url, ctx)
}
/// Update a validator's project url
public entry fun update_validator_project_url(
self: &mut SuiSystemState,
project_url: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_validator_project_url(project_url, ctx)
}
/// Update a validator's network address.
/// The change will only take effects starting from the next epoch.
public entry fun update_validator_next_epoch_network_address(
self: &mut SuiSystemState,
network_address: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_validator_next_epoch_network_address(network_address, ctx)
}
/// Update candidate validator's network address.
public entry fun update_candidate_validator_network_address(
self: &mut SuiSystemState,
network_address: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_candidate_validator_network_address(network_address, ctx)
}
/// Update a validator's p2p address.
/// The change will only take effects starting from the next epoch.
public entry fun update_validator_next_epoch_p2p_address(
self: &mut SuiSystemState,
p2p_address: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_validator_next_epoch_p2p_address(p2p_address, ctx)
}
/// Update candidate validator's p2p address.
public entry fun update_candidate_validator_p2p_address(
self: &mut SuiSystemState,
p2p_address: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_candidate_validator_p2p_address(p2p_address, ctx)
}
/// Update a validator's narwhal primary address.
/// The change will only take effects starting from the next epoch.
public entry fun update_validator_next_epoch_primary_address(
self: &mut SuiSystemState,
primary_address: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_validator_next_epoch_primary_address(primary_address, ctx)
}
/// Update candidate validator's narwhal primary address.
public entry fun update_candidate_validator_primary_address(
self: &mut SuiSystemState,
primary_address: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_candidate_validator_primary_address(primary_address, ctx)
}
/// Update a validator's narwhal worker address.
/// The change will only take effects starting from the next epoch.
public entry fun update_validator_next_epoch_worker_address(
self: &mut SuiSystemState,
worker_address: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_validator_next_epoch_worker_address(worker_address, ctx)
}
/// Update candidate validator's narwhal worker address.
public entry fun update_candidate_validator_worker_address(
self: &mut SuiSystemState,
worker_address: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_candidate_validator_worker_address(worker_address, ctx)
}
/// Update a validator's public key of protocol key and proof of possession.
/// The change will only take effects starting from the next epoch.
public entry fun update_validator_next_epoch_protocol_pubkey(
self: &mut SuiSystemState,
protocol_pubkey: vector<u8>,
proof_of_possession: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_validator_next_epoch_protocol_pubkey(protocol_pubkey, proof_of_possession, ctx)
}
/// Update candidate validator's public key of protocol key and proof of possession.
public entry fun update_candidate_validator_protocol_pubkey(
self: &mut SuiSystemState,
protocol_pubkey: vector<u8>,
proof_of_possession: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_candidate_validator_protocol_pubkey(protocol_pubkey, proof_of_possession, ctx)
}
/// Update a validator's public key of worker key.
/// The change will only take effects starting from the next epoch.
public entry fun update_validator_next_epoch_worker_pubkey(
self: &mut SuiSystemState,
worker_pubkey: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_validator_next_epoch_worker_pubkey(worker_pubkey, ctx)
}
/// Update candidate validator's public key of worker key.
public entry fun update_candidate_validator_worker_pubkey(
self: &mut SuiSystemState,
worker_pubkey: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_candidate_validator_worker_pubkey(worker_pubkey, ctx)
}
/// Update a validator's public key of network key.
/// The change will only take effects starting from the next epoch.
public entry fun update_validator_next_epoch_network_pubkey(
self: &mut SuiSystemState,
network_pubkey: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_validator_next_epoch_network_pubkey(network_pubkey, ctx)
}
/// Update candidate validator's public key of network key.
public entry fun update_candidate_validator_network_pubkey(
self: &mut SuiSystemState,
network_pubkey: vector<u8>,
ctx: &TxContext,
) {
let self = load_system_state_mut(self);
self.update_candidate_validator_network_pubkey(network_pubkey, ctx)
}
/// Getter of the pool token exchange rate of a staking pool. Works for both active and inactive pools.
public fun pool_exchange_rates(
wrapper: &mut SuiSystemState,
pool_id: &ID
): &Table<u64, PoolTokenExchangeRate> {
let self = load_system_state_mut(wrapper);
self.pool_exchange_rates(pool_id)
}
/// Getter returning addresses of the currently active validators.
public fun active_validator_addresses(wrapper: &mut SuiSystemState): vector<address> {
let self = load_system_state(wrapper);
self.active_validator_addresses()
}
#[allow(unused_function)]
/// This function should be called at the end of an epoch, and advances the system to the next epoch.
/// It does the following things:
/// 1. Add storage charge to the storage fund.
/// 2. Burn the storage rebates from the storage fund. These are already refunded to transaction sender's
/// gas coins.
/// 3. Distribute computation charge to validator stake.
/// 4. Update all validators.
fun advance_epoch(
storage_reward: Balance<SUI>,
computation_reward: Balance<SUI>,
wrapper: &mut SuiSystemState,
new_epoch: u64,
next_protocol_version: u64,
storage_rebate: u64,
non_refundable_storage_fee: u64,
storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested
// into storage fund, in basis point.
reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps.
epoch_start_timestamp_ms: u64, // Timestamp of the epoch start
ctx: &mut TxContext,
) : Balance<SUI> {
let self = load_system_state_mut(wrapper);
// Validator will make a special system call with sender set as 0x0.
assert!(ctx.sender() == @0x0, ENotSystemAddress);
let storage_rebate = self.advance_epoch(
new_epoch,
next_protocol_version,
storage_reward,
computation_reward,
storage_rebate,
non_refundable_storage_fee,
storage_fund_reinvest_rate,
reward_slashing_rate,
epoch_start_timestamp_ms,
ctx,
);
storage_rebate
}
fun load_system_state(self: &mut SuiSystemState): &SuiSystemStateInnerV2 {
load_inner_maybe_upgrade(self)
}
fun load_system_state_mut(self: &mut SuiSystemState): &mut SuiSystemStateInnerV2 {
load_inner_maybe_upgrade(self)
}
fun load_inner_maybe_upgrade(self: &mut SuiSystemState): &mut SuiSystemStateInnerV2 {
if (self.version == 1) {
let v1: SuiSystemStateInner = dynamic_field::remove(&mut self.id, self.version);
let v2 = v1.v1_to_v2();
self.version = 2;
dynamic_field::add(&mut self.id, self.version, v2);
};
let inner: &mut SuiSystemStateInnerV2 = dynamic_field::borrow_mut(
&mut self.id,
self.version
);
assert!(inner.system_state_version() == self.version, EWrongInnerVersion);
inner
}
#[test_only]
/// Return the current epoch number. Useful for applications that need a coarse-grained concept of time,
/// since epochs are ever-increasing and epoch changes are intended to happen every 24 hours.
public fun epoch(wrapper: &mut SuiSystemState): u64 {
let self = load_system_state(wrapper);
self.epoch()
}
#[test_only]
/// Returns unix timestamp of the start of current epoch
public fun epoch_start_timestamp_ms(wrapper: &mut SuiSystemState): u64 {
let self = load_system_state(wrapper);
self.epoch_start_timestamp_ms()
}
#[test_only]
/// Returns the total amount staked with `validator_addr`.
/// Aborts if `validator_addr` is not an active validator.
public fun validator_stake_amount(wrapper: &mut SuiSystemState, validator_addr: address): u64 {
let self = load_system_state(wrapper);
self.validator_stake_amount(validator_addr)
}
#[test_only]
/// Returns the staking pool id of a given validator.
/// Aborts if `validator_addr` is not an active validator.
public fun validator_staking_pool_id(wrapper: &mut SuiSystemState, validator_addr: address): ID {
let self = load_system_state(wrapper);
self.validator_staking_pool_id(validator_addr)
}
#[test_only]
/// Returns reference to the staking pool mappings that map pool ids to active validator addresses
public fun validator_staking_pool_mappings(wrapper: &mut SuiSystemState): &Table<ID, address> {
let self = load_system_state(wrapper);
self.validator_staking_pool_mappings()
}
#[test_only]
/// Returns all the validators who are currently reporting `addr`
public fun get_reporters_of(wrapper: &mut SuiSystemState, addr: address): VecSet<address> {
let self = load_system_state(wrapper);
self.get_reporters_of(addr)
}
#[test_only]
/// Return the current validator set
public fun validators(wrapper: &mut SuiSystemState): &ValidatorSet {
let self = load_system_state(wrapper);
self.validators()
}
#[test_only]
/// Return the currently active validator by address
public fun active_validator_by_address(self: &mut SuiSystemState, validator_address: address): &Validator {
validators(self).get_active_validator_ref(validator_address)
}
#[test_only]
/// Return the currently pending validator by address
public fun pending_validator_by_address(self: &mut SuiSystemState, validator_address: address): &Validator {
validators(self).get_pending_validator_ref(validator_address)
}
#[test_only]
/// Return the currently candidate validator by address
public fun candidate_validator_by_address(self: &mut SuiSystemState, validator_address: address): &Validator {
validators(self).get_candidate_validator_ref(validator_address)
}
#[test_only]
public fun set_epoch_for_testing(wrapper: &mut SuiSystemState, epoch_num: u64) {
let self = load_system_state_mut(wrapper);
self.set_epoch_for_testing(epoch_num)
}
#[test_only]
public fun request_add_validator_for_testing(
wrapper: &mut SuiSystemState,
min_joining_stake_for_testing: u64,
ctx: &TxContext,
) {
let self = load_system_state_mut(wrapper);
self.request_add_validator_for_testing(min_joining_stake_for_testing, ctx)
}
#[test_only]
public fun get_storage_fund_total_balance(wrapper: &mut SuiSystemState): u64 {
let self = load_system_state(wrapper);
self.get_storage_fund_total_balance()
}
#[test_only]
public fun get_storage_fund_object_rebates(wrapper: &mut SuiSystemState): u64 {
let self = load_system_state(wrapper);
self.get_storage_fund_object_rebates()
}
#[test_only]
public fun get_stake_subsidy_distribution_counter(wrapper: &mut SuiSystemState): u64 {
let self = load_system_state(wrapper);
self.get_stake_subsidy_distribution_counter()
}
// CAUTION: THIS CODE IS ONLY FOR TESTING AND THIS MACRO MUST NEVER EVER BE REMOVED. Creates a
// candidate validator - bypassing the proof of possession check and other metadata validation
// in the process.
#[test_only]
public entry fun request_add_validator_candidate_for_testing(
wrapper: &mut SuiSystemState,
pubkey_bytes: vector<u8>,
network_pubkey_bytes: vector<u8>,
worker_pubkey_bytes: vector<u8>,
proof_of_possession: vector<u8>,
name: vector<u8>,
description: vector<u8>,
image_url: vector<u8>,
project_url: vector<u8>,
net_address: vector<u8>,
p2p_address: vector<u8>,
primary_address: vector<u8>,
worker_address: vector<u8>,
gas_price: u64,
commission_rate: u64,
ctx: &mut TxContext,
) {
let self = load_system_state_mut(wrapper);
self.request_add_validator_candidate_for_testing(
pubkey_bytes,
network_pubkey_bytes,
worker_pubkey_bytes,
proof_of_possession,
name,
description,
image_url,
project_url,
net_address,
p2p_address,
primary_address,
worker_address,
gas_price,
commission_rate,
ctx
)
}
// CAUTION: THIS CODE IS ONLY FOR TESTING AND THIS MACRO MUST NEVER EVER BE REMOVED.
#[test_only]
public(package) fun advance_epoch_for_testing(
wrapper: &mut SuiSystemState,
new_epoch: u64,
next_protocol_version: u64,
storage_charge: u64,
computation_charge: u64,
storage_rebate: u64,
non_refundable_storage_fee: u64,
storage_fund_reinvest_rate: u64,
reward_slashing_rate: u64,
epoch_start_timestamp_ms: u64,
ctx: &mut TxContext,
): Balance<SUI> {
let storage_reward = balance::create_for_testing(storage_charge);
let computation_reward = balance::create_for_testing(computation_charge);
let storage_rebate = advance_epoch(
storage_reward,
computation_reward,
wrapper,
new_epoch,
next_protocol_version,
storage_rebate,
non_refundable_storage_fee,
storage_fund_reinvest_rate,
reward_slashing_rate,
epoch_start_timestamp_ms,
ctx,
);
storage_rebate
}
}