1use self::sui_system_state_inner_v1::{SuiSystemStateInnerV1, ValidatorV1};
5use self::sui_system_state_summary::{SuiSystemStateSummary, SuiValidatorSummary};
6use crate::base_types::ObjectID;
7use crate::collection_types::Bag;
8use crate::committee::CommitteeWithNetworkMetadata;
9use crate::dynamic_field::{
10 Field, get_dynamic_field_from_store, get_dynamic_field_object_from_store,
11};
12use crate::error::{SuiError, SuiErrorKind};
13use crate::gas::GasCostSummary;
14use crate::object::{MoveObject, Object};
15use crate::storage::ObjectStore;
16use crate::sui_system_state::epoch_start_sui_system_state::EpochStartSystemState;
17use crate::sui_system_state::sui_system_state_inner_v2::SuiSystemStateInnerV2;
18use crate::versioned::Versioned;
19use crate::{MoveTypeTagTrait, SUI_SYSTEM_ADDRESS, SUI_SYSTEM_STATE_OBJECT_ID, id::UID};
20use anyhow::Result;
21use enum_dispatch::enum_dispatch;
22use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag};
23use serde::de::DeserializeOwned;
24use serde::{Deserialize, Serialize};
25use std::fmt;
26use sui_protocol_config::{ProtocolConfig, ProtocolVersion};
27
28pub mod epoch_start_sui_system_state;
29pub mod mock;
30pub mod sui_system_state_inner_v1;
31pub mod sui_system_state_inner_v2;
32pub mod sui_system_state_summary;
33
34#[cfg(msim)]
35mod simtest_sui_system_state_inner;
36#[cfg(msim)]
37use self::simtest_sui_system_state_inner::{
38 SimTestSuiSystemStateInnerDeepV2, SimTestSuiSystemStateInnerShallowV2,
39 SimTestSuiSystemStateInnerV1, SimTestValidatorDeepV2, SimTestValidatorV1,
40};
41
42const SUI_SYSTEM_STATE_WRAPPER_STRUCT_NAME: &IdentStr = ident_str!("SuiSystemState");
43
44pub const SUI_SYSTEM_MODULE_NAME: &IdentStr = ident_str!("sui_system");
45pub const SUI_SYSTEM_STATE_INNER_MODULE_NAME: &IdentStr = ident_str!("sui_system_state_inner");
46pub const SUI_SYSTEM_STATE_INNER_V1_STRUCT_NAME: &IdentStr = ident_str!("SuiSystemStateInner");
47pub const SUI_SYSTEM_STATE_INNER_V2_STRUCT_NAME: &IdentStr = ident_str!("SuiSystemStateInnerV2");
48pub const VALIDATOR_MODULE_NAME: &IdentStr = ident_str!("validator");
49pub const VALIDATOR_STRUCT_NAME: &IdentStr = ident_str!("Validator");
50pub const ADVANCE_EPOCH_FUNCTION_NAME: &IdentStr = ident_str!("advance_epoch");
51pub const ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME: &IdentStr = ident_str!("advance_epoch_safe_mode");
52
53#[cfg(msim)]
54pub const SUI_SYSTEM_STATE_SIM_TEST_V1: u64 = 18446744073709551605; #[cfg(msim)]
56pub const SUI_SYSTEM_STATE_SIM_TEST_SHALLOW_V2: u64 = 18446744073709551606; #[cfg(msim)]
58pub const SUI_SYSTEM_STATE_SIM_TEST_DEEP_V2: u64 = 18446744073709551607; #[derive(Debug, Serialize, Deserialize, Clone)]
68pub struct SuiSystemStateWrapper {
69 pub id: UID,
70 pub version: u64,
71}
72
73impl SuiSystemStateWrapper {
74 pub fn type_() -> StructTag {
75 StructTag {
76 address: SUI_SYSTEM_ADDRESS,
77 name: SUI_SYSTEM_STATE_WRAPPER_STRUCT_NAME.to_owned(),
78 module: SUI_SYSTEM_MODULE_NAME.to_owned(),
79 type_params: vec![],
80 }
81 }
82
83 pub fn advance_epoch_safe_mode(
87 &self,
88 params: &AdvanceEpochParams,
89 object_store: &dyn ObjectStore,
90 protocol_config: &ProtocolConfig,
91 ) -> (Object, Object) {
92 let id = self.id.id.bytes;
93 let old_field_object = get_dynamic_field_object_from_store(object_store, id, &self.version)
94 .expect("Dynamic field object of wrapper should always be present in the object store");
95 let mut new_field_object = old_field_object.clone();
96 let move_object = new_field_object
97 .data
98 .try_as_move_mut()
99 .expect("Dynamic field object must be a Move object");
100 match self.version {
101 1 => {
102 Self::advance_epoch_safe_mode_impl::<SuiSystemStateInnerV1>(
103 move_object,
104 params,
105 protocol_config,
106 );
107 }
108 2 => {
109 Self::advance_epoch_safe_mode_impl::<SuiSystemStateInnerV2>(
110 move_object,
111 params,
112 protocol_config,
113 );
114 }
115 #[cfg(msim)]
116 SUI_SYSTEM_STATE_SIM_TEST_V1 => {
117 Self::advance_epoch_safe_mode_impl::<SimTestSuiSystemStateInnerV1>(
118 move_object,
119 params,
120 protocol_config,
121 );
122 }
123 #[cfg(msim)]
124 SUI_SYSTEM_STATE_SIM_TEST_SHALLOW_V2 => {
125 Self::advance_epoch_safe_mode_impl::<SimTestSuiSystemStateInnerShallowV2>(
126 move_object,
127 params,
128 protocol_config,
129 );
130 }
131 #[cfg(msim)]
132 SUI_SYSTEM_STATE_SIM_TEST_DEEP_V2 => {
133 Self::advance_epoch_safe_mode_impl::<SimTestSuiSystemStateInnerDeepV2>(
134 move_object,
135 params,
136 protocol_config,
137 );
138 }
139 _ => unreachable!(),
140 }
141 (old_field_object, new_field_object)
142 }
143
144 fn advance_epoch_safe_mode_impl<T>(
145 move_object: &mut MoveObject,
146 params: &AdvanceEpochParams,
147 protocol_config: &ProtocolConfig,
148 ) where
149 T: Serialize + DeserializeOwned + SuiSystemStateTrait,
150 {
151 let mut field: Field<u64, T> =
152 bcs::from_bytes(move_object.contents()).expect("bcs deserialization should never fail");
153 tracing::info!(
154 "Advance epoch safe mode: current epoch: {}, protocol_version: {}, system_state_version: {}",
155 field.value.epoch(),
156 field.value.protocol_version(),
157 field.value.system_state_version()
158 );
159 field.value.advance_epoch_safe_mode(params);
160 tracing::info!(
161 "Safe mode activated. New epoch: {}, protocol_version: {}, system_state_version: {}",
162 field.value.epoch(),
163 field.value.protocol_version(),
164 field.value.system_state_version()
165 );
166 let new_contents = bcs::to_bytes(&field).expect("bcs serialization should never fail");
167 move_object
168 .update_contents_advance_epoch_safe_mode(new_contents, protocol_config)
169 .expect("Update sui system object content cannot fail since it should be small or unbounded");
170 }
171}
172
173#[enum_dispatch]
175pub trait SuiSystemStateTrait {
176 fn epoch(&self) -> u64;
177 fn reference_gas_price(&self) -> u64;
178 fn protocol_version(&self) -> u64;
179 fn system_state_version(&self) -> u64;
180 fn epoch_start_timestamp_ms(&self) -> u64;
181 fn epoch_duration_ms(&self) -> u64;
182 fn extra_fields(&self) -> &Bag;
183 fn safe_mode(&self) -> bool;
184 fn safe_mode_gas_cost_summary(&self) -> GasCostSummary;
185 fn advance_epoch_safe_mode(&mut self, params: &AdvanceEpochParams);
186 fn get_current_epoch_committee(&self) -> CommitteeWithNetworkMetadata;
187 fn get_pending_active_validators<S: ObjectStore + ?Sized>(
188 &self,
189 object_store: &S,
190 ) -> Result<Vec<SuiValidatorSummary>, SuiError>;
191 fn into_epoch_start_state(self) -> EpochStartSystemState;
192 fn into_sui_system_state_summary(self) -> SuiSystemStateSummary;
193}
194
195#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
200#[enum_dispatch(SuiSystemStateTrait)]
201pub enum SuiSystemState {
202 V1(SuiSystemStateInnerV1),
203 V2(SuiSystemStateInnerV2),
204 #[cfg(msim)]
205 SimTestV1(SimTestSuiSystemStateInnerV1),
206 #[cfg(msim)]
207 SimTestShallowV2(SimTestSuiSystemStateInnerShallowV2),
208 #[cfg(msim)]
209 SimTestDeepV2(SimTestSuiSystemStateInnerDeepV2),
210}
211
212pub type SuiSystemStateInnerGenesis = SuiSystemStateInnerV1;
214pub type SuiValidatorGenesis = ValidatorV1;
215
216impl SuiSystemState {
217 pub fn into_genesis_version_for_tooling(self) -> SuiSystemStateInnerGenesis {
222 match self {
223 SuiSystemState::V1(inner) => inner,
224 _ => unreachable!(),
225 }
226 }
227
228 pub fn version(&self) -> u64 {
229 self.system_state_version()
230 }
231}
232
233pub fn get_sui_system_state_wrapper(
234 object_store: &dyn ObjectStore,
235) -> Result<SuiSystemStateWrapper, SuiError> {
236 let wrapper = object_store
237 .get_object(&SUI_SYSTEM_STATE_OBJECT_ID)
238 .ok_or_else(|| {
240 SuiErrorKind::SuiSystemStateReadError(
241 "SuiSystemStateWrapper object not found".to_owned(),
242 )
243 })?;
244 let move_object = wrapper.data.try_as_move().ok_or_else(|| {
245 SuiErrorKind::SuiSystemStateReadError(
246 "SuiSystemStateWrapper object must be a Move object".to_owned(),
247 )
248 })?;
249 let result = bcs::from_bytes::<SuiSystemStateWrapper>(move_object.contents())
250 .map_err(|err| SuiErrorKind::SuiSystemStateReadError(err.to_string()))?;
251 Ok(result)
252}
253
254pub fn get_sui_system_state(object_store: &dyn ObjectStore) -> Result<SuiSystemState, SuiError> {
255 let wrapper = get_sui_system_state_wrapper(object_store)?;
256 let id = wrapper.id.id.bytes;
257 match wrapper.version {
258 1 => {
259 let result: SuiSystemStateInnerV1 =
260 get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err(
261 |err| {
262 SuiErrorKind::DynamicFieldReadError(format!(
263 "Failed to load sui system state inner object with ID {:?} and version {:?}: {:?}",
264 id, wrapper.version, err
265 ))
266 },
267 )?;
268 Ok(SuiSystemState::V1(result))
269 }
270 2 => {
271 let result: SuiSystemStateInnerV2 =
272 get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err(
273 |err| {
274 SuiErrorKind::DynamicFieldReadError(format!(
275 "Failed to load sui system state inner object with ID {:?} and version {:?}: {:?}",
276 id, wrapper.version, err
277 ))
278 },
279 )?;
280 Ok(SuiSystemState::V2(result))
281 }
282 #[cfg(msim)]
283 SUI_SYSTEM_STATE_SIM_TEST_V1 => {
284 let result: SimTestSuiSystemStateInnerV1 =
285 get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err(
286 |err| {
287 SuiErrorKind::DynamicFieldReadError(format!(
288 "Failed to load sui system state inner object with ID {:?} and version {:?}: {:?}",
289 id, wrapper.version, err
290 ))
291 },
292 )?;
293 Ok(SuiSystemState::SimTestV1(result))
294 }
295 #[cfg(msim)]
296 SUI_SYSTEM_STATE_SIM_TEST_SHALLOW_V2 => {
297 let result: SimTestSuiSystemStateInnerShallowV2 =
298 get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err(
299 |err| {
300 SuiErrorKind::DynamicFieldReadError(format!(
301 "Failed to load sui system state inner object with ID {:?} and version {:?}: {:?}",
302 id, wrapper.version, err
303 ))
304 },
305 )?;
306 Ok(SuiSystemState::SimTestShallowV2(result))
307 }
308 #[cfg(msim)]
309 SUI_SYSTEM_STATE_SIM_TEST_DEEP_V2 => {
310 let result: SimTestSuiSystemStateInnerDeepV2 =
311 get_dynamic_field_from_store(object_store, id, &wrapper.version).map_err(
312 |err| {
313 SuiErrorKind::DynamicFieldReadError(format!(
314 "Failed to load sui system state inner object with ID {:?} and version {:?}: {:?}",
315 id, wrapper.version, err
316 ))
317 },
318 )?;
319 Ok(SuiSystemState::SimTestDeepV2(result))
320 }
321 _ => Err(SuiErrorKind::SuiSystemStateReadError(format!(
322 "Unsupported SuiSystemState version: {}",
323 wrapper.version
324 ))
325 .into()),
326 }
327}
328
329pub fn get_validator_from_table<K>(
334 object_store: &dyn ObjectStore,
335 table_id: ObjectID,
336 key: &K,
337) -> Result<SuiValidatorSummary, SuiError>
338where
339 K: Clone + MoveTypeTagTrait + Serialize + DeserializeOwned + fmt::Debug,
340{
341 let field: ValidatorWrapper = get_dynamic_field_from_store(object_store, table_id, key)
342 .map_err(|err| {
343 SuiErrorKind::SuiSystemStateReadError(format!(
344 "Failed to load validator wrapper from table: {:?}",
345 err
346 ))
347 })?;
348 let versioned = field.inner;
349 let version = versioned.version;
350 match version {
351 1 => {
352 let validator: ValidatorV1 =
353 get_dynamic_field_from_store(object_store, versioned.id.id.bytes, &version)
354 .map_err(|err| {
355 SuiErrorKind::SuiSystemStateReadError(format!(
356 "Failed to load inner validator from the wrapper: {:?}",
357 err
358 ))
359 })?;
360 Ok(validator.into_sui_validator_summary())
361 }
362 #[cfg(msim)]
363 SUI_SYSTEM_STATE_SIM_TEST_V1 => {
364 let validator: SimTestValidatorV1 =
365 get_dynamic_field_from_store(object_store, versioned.id.id.bytes, &version)
366 .map_err(|err| {
367 SuiErrorKind::SuiSystemStateReadError(format!(
368 "Failed to load inner validator from the wrapper: {:?}",
369 err
370 ))
371 })?;
372 Ok(validator.into_sui_validator_summary())
373 }
374 #[cfg(msim)]
375 SUI_SYSTEM_STATE_SIM_TEST_DEEP_V2 => {
376 let validator: SimTestValidatorDeepV2 =
377 get_dynamic_field_from_store(object_store, versioned.id.id.bytes, &version)
378 .map_err(|err| {
379 SuiErrorKind::SuiSystemStateReadError(format!(
380 "Failed to load inner validator from the wrapper: {:?}",
381 err
382 ))
383 })?;
384 Ok(validator.into_sui_validator_summary())
385 }
386 _ => Err(SuiErrorKind::SuiSystemStateReadError(format!(
387 "Unsupported Validator version: {}",
388 version
389 ))
390 .into()),
391 }
392}
393
394pub fn get_validators_from_table_vec<S, ValidatorType>(
395 object_store: &S,
396 table_id: ObjectID,
397 table_size: u64,
398) -> Result<Vec<ValidatorType>, SuiError>
399where
400 S: ObjectStore + ?Sized,
401 ValidatorType: Serialize + DeserializeOwned,
402{
403 let mut validators = vec![];
404 for i in 0..table_size {
405 let validator: ValidatorType = get_dynamic_field_from_store(&object_store, table_id, &i)
406 .map_err(|err| {
407 SuiErrorKind::SuiSystemStateReadError(format!(
408 "Failed to load validator from table: {:?}",
409 err
410 ))
411 })?;
412 validators.push(validator);
413 }
414 Ok(validators)
415}
416
417#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Default)]
418pub struct PoolTokenExchangeRate {
419 sui_amount: u64,
420 pool_token_amount: u64,
421}
422
423impl PoolTokenExchangeRate {
424 pub fn rate(&self) -> f64 {
426 if self.sui_amount == 0 {
427 1_f64
428 } else {
429 self.pool_token_amount as f64 / self.sui_amount as f64
430 }
431 }
432
433 pub fn new(sui_amount: u64, pool_token_amount: u64) -> Self {
434 Self {
435 sui_amount,
436 pool_token_amount,
437 }
438 }
439}
440
441#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
442pub struct ValidatorWrapper {
443 pub inner: Versioned,
444}
445
446#[derive(Debug)]
447pub struct AdvanceEpochParams {
448 pub epoch: u64,
449 pub next_protocol_version: ProtocolVersion,
450 pub storage_charge: u64,
451 pub computation_charge: u64,
452 pub storage_rebate: u64,
453 pub non_refundable_storage_fee: u64,
454 pub storage_fund_reinvest_rate: u64,
455 pub reward_slashing_rate: u64,
456 pub epoch_start_timestamp_ms: u64,
457}
458
459#[cfg(msim)]
460pub mod advance_epoch_result_injection {
461 use crate::{
462 committee::EpochId,
463 error::{ExecutionError, ExecutionErrorKind},
464 execution::ResultWithTimings,
465 };
466 use std::cell::RefCell;
467
468 thread_local! {
469 static OVERRIDE: RefCell<Option<(EpochId, EpochId)>> = RefCell::new(None);
471 }
472
473 pub fn set_override(value: Option<(EpochId, EpochId)>) {
475 OVERRIDE.with(|o| *o.borrow_mut() = value);
476 }
477
478 pub fn maybe_modify_result(
481 result: ResultWithTimings<(), ExecutionError>,
482 current_epoch: EpochId,
483 ) -> ResultWithTimings<(), ExecutionError> {
484 if let Some((start, end)) = OVERRIDE.with(|o| *o.borrow()) {
485 if current_epoch >= start && current_epoch < end {
486 return Err((
487 ExecutionError::new(ExecutionErrorKind::FunctionNotFound, None),
488 vec![],
489 ));
490 }
491 }
492 result
493 }
494
495 pub fn maybe_modify_result_legacy(
497 result: Result<(), ExecutionError>,
498 current_epoch: EpochId,
499 ) -> Result<(), ExecutionError> {
500 if let Some((start, end)) = OVERRIDE.with(|o| *o.borrow()) {
501 if current_epoch >= start && current_epoch < end {
502 return Err(ExecutionError::new(
503 ExecutionErrorKind::FunctionNotFound,
504 None,
505 ));
506 }
507 }
508 result
509 }
510}