Skip to main content

iota_config/
verifier_signing_config.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2025 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use move_vm_config::verifier::MeterConfig;
6use serde::{Deserialize, Serialize};
7
8// Default values for verifier signing config.
9pub const DEFAULT_MAX_PER_FUN_METER_UNITS: usize = 2_200_000;
10pub const DEFAULT_MAX_PER_MOD_METER_UNITS: usize = 2_200_000;
11pub const DEFAULT_MAX_PER_PKG_METER_UNITS: usize = 2_200_000;
12
13pub const DEFAULT_MAX_BACK_EDGES_PER_FUNCTION: usize = 10_000;
14pub const DEFAULT_MAX_BACK_EDGES_PER_MODULE: usize = 10_000;
15
16pub const DEFAULT_SANITY_CHECK_WITH_REGEX_REFERENCE_SAFETY_UNITS: usize = 2_200_000;
17
18/// This holds limits that are only set and used by the verifier during signing
19/// _only_. There are additional limits in the `MeterConfig` and
20/// `VerifierConfig` that are used during both signing and execution, however
21/// those limits cannot be set here and must be protocol versioned.
22///
23/// Post-consensus validation has to reach the same verdict on every validator,
24/// so it meters published packages with the protocol config's limits instead;
25/// see `ProtocolConfig::meter_config` and
26/// `ProtocolConfig::verifier_signing_limits`. The defaults here equal those
27/// protocol values.
28#[derive(Clone, Debug, Default, Deserialize, Serialize)]
29#[serde(rename_all = "kebab-case")]
30pub struct VerifierSigningConfig {
31    #[serde(default)]
32    max_per_fun_meter_units: Option<usize>,
33    #[serde(default)]
34    max_per_mod_meter_units: Option<usize>,
35    #[serde(default)]
36    max_per_pkg_meter_units: Option<usize>,
37
38    #[serde(default)]
39    max_back_edges_per_function: Option<usize>,
40    #[serde(default)]
41    max_back_edges_per_module: Option<usize>,
42
43    #[serde(default)]
44    pub sanity_check_with_regex_reference_safety: Option<usize>,
45}
46
47impl VerifierSigningConfig {
48    pub fn max_per_fun_meter_units(&self) -> usize {
49        self.max_per_fun_meter_units
50            .unwrap_or(DEFAULT_MAX_PER_FUN_METER_UNITS)
51    }
52
53    pub fn max_per_mod_meter_units(&self) -> usize {
54        self.max_per_mod_meter_units
55            .unwrap_or(DEFAULT_MAX_PER_MOD_METER_UNITS)
56    }
57
58    pub fn max_per_pkg_meter_units(&self) -> usize {
59        self.max_per_pkg_meter_units
60            .unwrap_or(DEFAULT_MAX_PER_PKG_METER_UNITS)
61    }
62
63    pub fn max_back_edges_per_function(&self) -> usize {
64        self.max_back_edges_per_function
65            .unwrap_or(DEFAULT_MAX_BACK_EDGES_PER_FUNCTION)
66    }
67
68    pub fn max_back_edges_per_module(&self) -> usize {
69        self.max_back_edges_per_module
70            .unwrap_or(DEFAULT_MAX_BACK_EDGES_PER_MODULE)
71    }
72
73    pub fn sanity_check_with_regex_reference_safety(&self) -> usize {
74        self.sanity_check_with_regex_reference_safety
75            .unwrap_or(DEFAULT_SANITY_CHECK_WITH_REGEX_REFERENCE_SAFETY_UNITS)
76    }
77
78    /// Return sign-time only limit for back edges for the verifier.
79    pub fn limits_for_signing(&self) -> (usize, usize, usize) {
80        (
81            self.max_back_edges_per_function(),
82            self.max_back_edges_per_module(),
83            self.sanity_check_with_regex_reference_safety(),
84        )
85    }
86
87    /// MeterConfig for metering packages during signing. It is NOT stable
88    /// between binaries and cannot used during execution.
89    pub fn meter_config_for_signing(&self) -> MeterConfig {
90        MeterConfig {
91            max_per_fun_meter_units: Some(self.max_per_fun_meter_units() as u128),
92            max_per_mod_meter_units: Some(self.max_per_mod_meter_units() as u128),
93            max_per_pkg_meter_units: Some(self.max_per_pkg_meter_units() as u128),
94        }
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use iota_protocol_config::ProtocolConfig;
101
102    use super::*;
103
104    /// A validator that leaves its `VerifierSigningConfig` at the defaults must
105    /// reach the same verdict at admission as post-consensus validation
106    /// does with the protocol config's limits, so the two sets of defaults
107    /// have to agree.
108    #[test]
109    fn defaults_match_protocol_config() {
110        let protocol_config = ProtocolConfig::get_for_max_version_UNSAFE();
111        let signing_config = VerifierSigningConfig::default();
112
113        assert_eq!(
114            signing_config.limits_for_signing(),
115            protocol_config.verifier_signing_limits()
116        );
117
118        let from_node = signing_config.meter_config_for_signing();
119        let from_protocol = protocol_config.meter_config();
120        assert_eq!(
121            from_node.max_per_fun_meter_units,
122            from_protocol.max_per_fun_meter_units
123        );
124        assert_eq!(
125            from_node.max_per_mod_meter_units,
126            from_protocol.max_per_mod_meter_units
127        );
128        assert_eq!(
129            from_node.max_per_pkg_meter_units,
130            from_protocol.max_per_pkg_meter_units
131        );
132    }
133}