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