sui_verifier_v1/
meter.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use 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            // Not used for now to keep backward compat
49            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}