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/// Various configurations for the VM.
25#[derive(Clone, Debug, Serialize, Deserialize)]
26#[non_exhaustive]
27pub struct Config {
28    /// Configuration for limitations placed on Wasm files.
29    /// This defines a few limits on the Wasm file that are checked during static validation before
30    /// storing the Wasm file.
31    pub wasm_limits: WasmLimits,
32
33    /// Configuration for the cache.
34    pub cache: CacheOptions,
35}
36
37impl Config {
38    pub fn new(cache: CacheOptions) -> Self {
39        Self {
40            wasm_limits: WasmLimits::default(),
41            cache,
42        }
43    }
44}
45
46/// Limits for static validation of Wasm files. These are checked before storing the Wasm file.
47/// All limits are optional because they are coming from the Go-side and have default values.
48#[derive(Clone, Debug, Default, Serialize, Deserialize)]
49#[non_exhaustive]
50pub struct WasmLimits {
51    /// Maximum number of memory pages that a module can request.
52    ///
53    /// Every Wasm memory has an initial size and an optional maximum size,
54    /// both measured in Wasm pages. This limit applies to the initial size.
55    pub initial_memory_limit_pages: Option<u32>,
56    /// The upper limit for the `max` value of each table. CosmWasm contracts have
57    /// initial=max for 1 table. See
58    ///
59    /// ```plain
60    /// $ wasm-objdump --section=table -x packages/vm/testdata/hackatom.wasm
61    /// Section Details:
62    ///
63    /// Table[1]:
64    /// - table[0] type=funcref initial=161 max=161
65    /// ```
66    ///
67    pub table_size_limit_elements: Option<u32>,
68    /// If the contract has more than this amount of imports, it will be rejected
69    /// during static validation before even looking into the imports.
70    pub max_imports: Option<usize>,
71
72    /// The maximum number of functions a contract can have.
73    /// Any contract with more functions than this will be rejected during static validation.
74    pub max_functions: Option<usize>,
75
76    /// The maximum number of parameters a Wasm function can have.
77    pub max_function_params: Option<usize>,
78    /// The maximum total number of parameters of all functions in the Wasm.
79    /// For each function in the Wasm, take the number of parameters and sum all of these up.
80    /// If that sum exceeds this limit, the Wasm will be rejected during static validation.
81    ///
82    /// Be careful when adjusting this limit, as it prevents an attack where a small Wasm file
83    /// explodes in size when compiled.
84    pub max_total_function_params: Option<usize>,
85
86    /// The maximum number of results a Wasm function type can have.
87    pub max_function_results: Option<usize>,
88}
89
90impl WasmLimits {
91    pub fn initial_memory_limit_pages(&self) -> u32 {
92        self.initial_memory_limit_pages
93            .unwrap_or(DEFAULT_MEMORY_LIMIT)
94    }
95
96    pub fn table_size_limit_elements(&self) -> u32 {
97        self.table_size_limit_elements
98            .unwrap_or(DEFAULT_TABLE_SIZE_LIMIT)
99    }
100
101    pub fn max_imports(&self) -> usize {
102        self.max_imports.unwrap_or(DEFAULT_MAX_IMPORTS)
103    }
104
105    pub fn max_functions(&self) -> usize {
106        self.max_functions.unwrap_or(DEFAULT_MAX_FUNCTIONS)
107    }
108
109    pub fn max_function_params(&self) -> usize {
110        self.max_function_params
111            .unwrap_or(DEFAULT_MAX_FUNCTION_PARAMS)
112    }
113
114    pub fn max_total_function_params(&self) -> usize {
115        self.max_total_function_params
116            .unwrap_or(DEFAULT_MAX_TOTAL_FUNCTION_PARAMS)
117    }
118
119    pub fn max_function_results(&self) -> usize {
120        self.max_function_results
121            .unwrap_or(DEFAULT_MAX_FUNCTION_RESULTS)
122    }
123}
124
125#[derive(Clone, Debug, Serialize, Deserialize)]
126#[non_exhaustive]
127pub struct CacheOptions {
128    /// The base directory of this cache.
129    ///
130    /// If this does not exist, it will be created. Not sure if this behaviour
131    /// is desired but wasmd relies on it.
132    pub base_dir: PathBuf,
133    pub available_capabilities: HashSet<String>,
134    /// Memory limit for the cache, in bytes.
135    pub memory_cache_size_bytes: Size,
136    /// Memory limit for instances, in bytes. Use a value that is divisible by the Wasm page size 65536,
137    /// e.g. full MiBs.
138    pub instance_memory_limit_bytes: Size,
139}
140
141impl CacheOptions {
142    pub fn new(
143        base_dir: impl Into<PathBuf>,
144        available_capabilities: impl Into<HashSet<String>>,
145        memory_cache_size_bytes: Size,
146        instance_memory_limit_bytes: Size,
147    ) -> Self {
148        Self {
149            base_dir: base_dir.into(),
150            available_capabilities: available_capabilities.into(),
151            memory_cache_size_bytes,
152            instance_memory_limit_bytes,
153        }
154    }
155}