1use move_binary_format::errors::{PartialVMError, PartialVMResult};
5use move_bytecode_verifier_meter::{Meter, Scope};
6use move_core_types::vm_status::StatusCode;
7use move_vm_config::verifier::MeterConfig;
8
9struct SuiVerifierMeterBounds {
10 name: String,
11 ticks: u128,
12 max_ticks: Option<u128>,
13}
14
15impl SuiVerifierMeterBounds {
16 fn add(&mut self, ticks: u128) -> PartialVMResult<()> {
17 let max_ticks = self.max_ticks.unwrap_or(u128::MAX);
18
19 let new_ticks = self.ticks.saturating_add(ticks);
20 if new_ticks >= max_ticks {
21 return Err(PartialVMError::new(StatusCode::PROGRAM_TOO_COMPLEX)
22 .with_message(format!(
23 "program too complex. Ticks exceeded `{}` will exceed limits: `{} current + {} new > {} max`)",
24 self.name, self.ticks, ticks, max_ticks
25 )));
26 }
27 self.ticks = new_ticks;
28 Ok(())
29 }
30}
31
32pub struct SuiVerifierMeter {
33 transaction_bounds: SuiVerifierMeterBounds,
34 package_bounds: SuiVerifierMeterBounds,
35 module_bounds: SuiVerifierMeterBounds,
36 function_bounds: SuiVerifierMeterBounds,
37}
38
39impl SuiVerifierMeter {
40 pub fn new(config: MeterConfig) -> Self {
41 Self {
42 transaction_bounds: SuiVerifierMeterBounds {
43 name: "<unknown>".to_string(),
44 ticks: 0,
45 max_ticks: None,
46 },
47
48 package_bounds: SuiVerifierMeterBounds {
50 name: "<unknown>".to_string(),
51 ticks: 0,
52 max_ticks: None,
53 },
54 module_bounds: SuiVerifierMeterBounds {
55 name: "<unknown>".to_string(),
56 ticks: 0,
57 max_ticks: config.max_per_mod_meter_units,
58 },
59 function_bounds: SuiVerifierMeterBounds {
60 name: "<unknown>".to_string(),
61 ticks: 0,
62 max_ticks: config.max_per_fun_meter_units,
63 },
64 }
65 }
66
67 fn get_bounds_mut(&mut self, scope: Scope) -> &mut SuiVerifierMeterBounds {
68 match scope {
69 Scope::Transaction => &mut self.transaction_bounds,
70 Scope::Package => &mut self.package_bounds,
71 Scope::Module => &mut self.module_bounds,
72 Scope::Function => &mut self.function_bounds,
73 }
74 }
75
76 fn get_bounds(&self, scope: Scope) -> &SuiVerifierMeterBounds {
77 match scope {
78 Scope::Transaction => &self.transaction_bounds,
79 Scope::Package => &self.package_bounds,
80 Scope::Module => &self.module_bounds,
81 Scope::Function => &self.function_bounds,
82 }
83 }
84
85 pub fn get_usage(&self, scope: Scope) -> u128 {
86 self.get_bounds(scope).ticks
87 }
88
89 pub fn get_limit(&self, scope: Scope) -> Option<u128> {
90 self.get_bounds(scope).max_ticks
91 }
92}
93
94impl Meter for SuiVerifierMeter {
95 fn enter_scope(&mut self, name: &str, scope: Scope) {
96 let bounds = self.get_bounds_mut(scope);
97 bounds.name = name.into();
98 bounds.ticks = 0;
99 }
100
101 fn transfer(&mut self, from: Scope, to: Scope, factor: f32) -> PartialVMResult<()> {
102 let ticks = (self.get_bounds_mut(from).ticks as f32 * factor) as u128;
103 self.add(to, ticks)
104 }
105
106 fn add(&mut self, scope: Scope, ticks: u128) -> PartialVMResult<()> {
107 self.get_bounds_mut(scope).add(ticks)
108 }
109}