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