Skip to main content

cosmwasm_vm/
config.rs

1use std::{collections::HashSet, path::PathBuf};
2
3use serde::{Deserialize, Serialize};
4
5use crate::Size;
6
7const DEFAULT_MEMORY_LIMIT: u32 = 512; // in pages
8/// As of March 2023, on Juno mainnet the largest value for production contracts
9/// is 485. Most are between 100 and 300.
10const DEFAULT_TABLE_SIZE_LIMIT: u32 = 2500; // entries
11
12/// We keep this number high since failing early gives less detailed error messages. Especially
13/// when a user accidentally includes wasm-bindgen, they get a bunch of unsupported imports.
14const DEFAULT_MAX_IMPORTS: usize = 100;
15
16const DEFAULT_MAX_FUNCTIONS: usize = 20_000;
17
18const DEFAULT_MAX_FUNCTION_PARAMS: usize = 100;
19
20const DEFAULT_MAX_TOTAL_FUNCTION_PARAMS: usize = 10_000;
21
22const DEFAULT_MAX_FUNCTION_RESULTS: usize = 1;
23
24/// Default maximum value of locals in a single function.
25const DEFAULT_MAX_FUNCTION_LOCALS: usize = 100;
26
27/// Default maximum value of locals in all functions in module.
28const DEFAULT_MAX_TOTAL_FUNCTION_LOCALS: usize = 10_000;
29
30/// Various configurations for the VM.
31#[derive(Clone, Debug, Serialize, Deserialize)]
32#[non_exhaustive]
33pub struct Config {
34    /// Configuration for limitations placed on Wasm files.
35    /// This defines a few limits on the Wasm file that are checked during static validation before
36    /// storing the Wasm file.
37    pub wasm_limits: WasmLimits,
38
39    /// Configuration for the cache.
40    pub cache: CacheOptions,
41}
42
43impl Config {
44    pub fn new(cache: CacheOptions) -> Self {
45        Self {
46            wasm_limits: WasmLimits::default(),
47            cache,
48        }
49    }
50}
51
52/// Limits for static validation of Wasm files. These are checked before storing the Wasm file.
53/// All limits are optional because they are coming from the Go-side and have default values.
54#[derive(Clone, Debug, Default, Serialize, Deserialize)]
55#[non_exhaustive]
56pub struct WasmLimits {
57    /// Maximum number of memory pages that a module can request.
58    ///
59    /// Every Wasm memory has an initial size and an optional maximum size,
60    /// both measured in Wasm pages. This limit applies to the initial size.
61    pub initial_memory_limit_pages: Option<u32>,
62    /// The upper limit for the `max` value of each table. CosmWasm contracts have
63    /// initial=max for 1 table. See
64    ///
65    /// ```plain
66    /// $ wasm-objdump --section=table -x packages/vm/testdata/hackatom.wasm
67    /// Section Details:
68    ///
69    /// Table[1]:
70    /// - table[0] type=funcref initial=161 max=161
71    /// ```
72    ///
73    pub table_size_limit_elements: Option<u32>,
74    /// If the contract has more than this amount of imports, it will be rejected
75    /// during static validation before even looking into the imports.
76    pub max_imports: Option<usize>,
77
78    /// The maximum number of functions a contract can have.
79    /// Any contract with more functions than this will be rejected during static validation.
80    pub max_functions: Option<usize>,
81
82    /// The maximum number of parameters a Wasm function can have.
83    pub max_function_params: Option<usize>,
84    /// The maximum total number of parameters of all functions in the Wasm.
85    /// For each function in the Wasm, take the number of parameters and sum all of these up.
86    /// If that sum exceeds this limit, the Wasm will be rejected during static validation.
87    ///
88    /// Be careful when adjusting this limit, as it prevents an attack where a small Wasm file
89    /// explodes in size when compiled.
90    pub max_total_function_params: Option<usize>,
91
92    /// The maximum number of results a Wasm function type can have.
93    pub max_function_results: Option<usize>,
94
95    /// The maximum number of locals a Wasm function can have.
96    pub max_function_locals: Option<usize>,
97
98    /// The maximum total number of locals in all functions a Wasm module can have.
99    pub max_total_function_locals: Option<usize>,
100}
101
102impl WasmLimits {
103    pub fn initial_memory_limit_pages(&self) -> u32 {
104        self.initial_memory_limit_pages
105            .unwrap_or(DEFAULT_MEMORY_LIMIT)
106    }
107
108    pub fn table_size_limit_elements(&self) -> u32 {
109        self.table_size_limit_elements
110            .unwrap_or(DEFAULT_TABLE_SIZE_LIMIT)
111    }
112
113    pub fn max_imports(&self) -> usize {
114        self.max_imports.unwrap_or(DEFAULT_MAX_IMPORTS)
115    }
116
117    pub fn max_functions(&self) -> usize {
118        self.max_functions.unwrap_or(DEFAULT_MAX_FUNCTIONS)
119    }
120
121    pub fn max_function_params(&self) -> usize {
122        self.max_function_params
123            .unwrap_or(DEFAULT_MAX_FUNCTION_PARAMS)
124    }
125
126    pub fn max_total_function_params(&self) -> usize {
127        self.max_total_function_params
128            .unwrap_or(DEFAULT_MAX_TOTAL_FUNCTION_PARAMS)
129    }
130
131    pub fn max_function_results(&self) -> usize {
132        self.max_function_results
133            .unwrap_or(DEFAULT_MAX_FUNCTION_RESULTS)
134    }
135
136    pub fn max_function_locals(&self) -> usize {
137        self.max_function_locals
138            .unwrap_or(DEFAULT_MAX_FUNCTION_LOCALS)
139    }
140
141    pub fn max_total_function_locals(&self) -> usize {
142        self.max_total_function_locals
143            .unwrap_or(DEFAULT_MAX_TOTAL_FUNCTION_LOCALS)
144    }
145}
146
147#[derive(Clone, Debug, Serialize, Deserialize)]
148#[non_exhaustive]
149pub struct CacheOptions {
150    /// The base directory of this cache.
151    ///
152    /// If this does not exist, it will be created. Not sure if this behaviour
153    /// is desired but wasmd relies on it.
154    pub base_dir: PathBuf,
155    pub available_capabilities: HashSet<String>,
156    /// Memory limit for the cache, in bytes.
157    pub memory_cache_size_bytes: Size,
158    /// Memory limit for instances, in bytes. Use a value that is divisible by the Wasm page size 65536,
159    /// e.g. full MiBs.
160    pub instance_memory_limit_bytes: Size,
161}
162
163impl CacheOptions {
164    pub fn new(
165        base_dir: impl Into<PathBuf>,
166        available_capabilities: impl Into<HashSet<String>>,
167        memory_cache_size_bytes: Size,
168        instance_memory_limit_bytes: Size,
169    ) -> Self {
170        Self {
171            base_dir: base_dir.into(),
172            available_capabilities: available_capabilities.into(),
173            memory_cache_size_bytes,
174            instance_memory_limit_bytes,
175        }
176    }
177}