sui_verifier_latest/
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            package_bounds: SuiVerifierMeterBounds {
48                name: "<unknown>".to_string(),
49                ticks: 0,
50                max_ticks: config.max_per_pkg_meter_units,
51            },
52            module_bounds: SuiVerifierMeterBounds {
53                name: "<unknown>".to_string(),
54                ticks: 0,
55                max_ticks: config.max_per_mod_meter_units,
56            },
57            function_bounds: SuiVerifierMeterBounds {
58                name: "<unknown>".to_string(),
59                ticks: 0,
60                max_ticks: config.max_per_fun_meter_units,
61            },
62        }
63    }
64
65    fn get_bounds_mut(&mut self, scope: Scope) -> &mut SuiVerifierMeterBounds {
66        match scope {
67            Scope::Transaction => &mut self.transaction_bounds,
68            Scope::Package => &mut self.package_bounds,
69            Scope::Module => &mut self.module_bounds,
70            Scope::Function => &mut self.function_bounds,
71        }
72    }
73
74    fn get_bounds(&self, scope: Scope) -> &SuiVerifierMeterBounds {
75        match scope {
76            Scope::Transaction => &self.transaction_bounds,
77            Scope::Package => &self.package_bounds,
78            Scope::Module => &self.module_bounds,
79            Scope::Function => &self.function_bounds,
80        }
81    }
82
83    pub fn get_usage(&self, scope: Scope) -> u128 {
84        self.get_bounds(scope).ticks
85    }
86
87    pub fn get_limit(&self, scope: Scope) -> Option<u128> {
88        self.get_bounds(scope).max_ticks
89    }
90}
91
92impl Meter for SuiVerifierMeter {
93    fn enter_scope(&mut self, name: &str, scope: Scope) {
94        let bounds = self.get_bounds_mut(scope);
95        bounds.name = name.into();
96        bounds.ticks = 0;
97    }
98
99    fn transfer(&mut self, from: Scope, to: Scope, factor: f32) -> PartialVMResult<()> {
100        let ticks = (self.get_bounds_mut(from).ticks as f32 * factor) as u128;
101        self.add(to, ticks)
102    }
103
104    fn add(&mut self, scope: Scope, ticks: u128) -> PartialVMResult<()> {
105        self.get_bounds_mut(scope).add(ticks)
106    }
107}