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}