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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
use crate::cost::{ExtCostsConfig, ParameterCost};
use borsh::BorshSerialize;
use near_primitives_core::config::AccountIdValidityRulesVersion;
use near_primitives_core::types::Gas;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
// NOTE that VMKind is part of serialization protocol, so we cannot remove entries from this list
// if particular VM reached publicly visible networks.
//
// Additionally, this is public only for the purposes of internal tools like the estimator. This
// API should otherwise be considered a private configuration of the `near-vm-runner`
// crate.
#[derive(
Clone,
Copy,
Debug,
Hash,
BorshSerialize,
PartialEq,
Eq,
strum::EnumString,
serde::Serialize,
serde::Deserialize,
)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
pub enum VMKind {
/// Wasmer 0.17.x VM.
Wasmer0,
/// Wasmtime VM.
Wasmtime,
/// Wasmer 2.x VM.
Wasmer2,
/// NearVM.
NearVm,
}
impl VMKind {
pub fn replace_with_wasmtime_if_unsupported(self) -> Self {
if cfg!(not(target_arch = "x86_64")) {
Self::Wasmtime
} else {
self
}
}
}
/// This enum represents if a storage_get call will be performed through flat storage or trie
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
pub enum StorageGetMode {
FlatStorage,
Trie,
}
/// Describes limits for VM and Runtime.
/// TODO #4139: consider switching to strongly-typed wrappers instead of raw quantities
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)]
pub struct LimitConfig {
/// Max amount of gas that can be used, excluding gas attached to promises.
pub max_gas_burnt: Gas,
/// How tall the stack is allowed to grow?
///
/// See <https://wiki.parity.io/WebAssembly-StackHeight> to find out how the stack frame cost
/// is calculated.
pub max_stack_height: u32,
/// Whether a legacy version of stack limiting should be used, see
/// [`ContractPrepareVersion`].
#[serde(default = "ContractPrepareVersion::v0")]
pub contract_prepare_version: ContractPrepareVersion,
/// The initial number of memory pages.
/// NOTE: It's not a limiter itself, but it's a value we use for initial_memory_pages.
pub initial_memory_pages: u32,
/// What is the maximal memory pages amount is allowed to have for a contract.
pub max_memory_pages: u32,
/// Limit of memory used by registers.
pub registers_memory_limit: u64,
/// Maximum number of bytes that can be stored in a single register.
pub max_register_size: u64,
/// Maximum number of registers that can be used simultaneously.
///
/// Note that due to an implementation quirk [read: a bug] in VMLogic, if we
/// have this number of registers, no subsequent writes to the registers
/// will succeed even if they replace an existing register.
pub max_number_registers: u64,
/// Maximum number of log entries.
pub max_number_logs: u64,
/// Maximum total length in bytes of all log messages.
pub max_total_log_length: u64,
/// Max total prepaid gas for all function call actions per receipt.
pub max_total_prepaid_gas: Gas,
/// Max number of actions per receipt.
pub max_actions_per_receipt: u64,
/// Max total length of all method names (including terminating character) for a function call
/// permission access key.
pub max_number_bytes_method_names: u64,
/// Max length of any method name (without terminating character).
pub max_length_method_name: u64,
/// Max length of arguments in a function call action.
pub max_arguments_length: u64,
/// Max length of returned data
pub max_length_returned_data: u64,
/// Max contract size
pub max_contract_size: u64,
/// Max transaction size
pub max_transaction_size: u64,
/// Max storage key size
pub max_length_storage_key: u64,
/// Max storage value size
pub max_length_storage_value: u64,
/// Max number of promises that a function call can create
pub max_promises_per_function_call_action: u64,
/// Max number of input data dependencies
pub max_number_input_data_dependencies: u64,
/// If present, stores max number of functions in one contract
#[serde(skip_serializing_if = "Option::is_none")]
pub max_functions_number_per_contract: Option<u64>,
/// If present, stores the secondary stack limit as implemented by wasmer2.
///
/// This limit should never be hit normally.
#[serde(default = "wasmer2_stack_limit_default")]
pub wasmer2_stack_limit: i32,
/// If present, stores max number of locals declared globally in one contract
#[serde(skip_serializing_if = "Option::is_none")]
pub max_locals_per_contract: Option<u64>,
/// Whether to enforce account_id well-formedness where it wasn't enforced
/// historically.
#[serde(default = "AccountIdValidityRulesVersion::v0")]
pub account_id_validity_rules_version: AccountIdValidityRulesVersion,
}
/// Dynamic configuration parameters required for the WASM runtime to
/// execute a smart contract.
///
/// This (`VMConfig`) and `RuntimeFeesConfig` combined are sufficient to define
/// protocol specific behavior of the contract runtime. The former contains
/// configuration for the WASM runtime specifically, while the latter contains
/// configuration for the transaction runtime and WASM runtime.
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Config {
/// Costs for runtime externals
pub ext_costs: ExtCostsConfig,
/// Gas cost of a growing memory by single page.
pub grow_mem_cost: u32,
/// Gas cost of a regular operation.
pub regular_op_cost: u32,
/// The kind of the VM implementation to use
pub vm_kind: VMKind,
/// Disable the fix for the #9393 issue in near-vm-runner.
pub disable_9393_fix: bool,
/// Set to `StorageGetMode::FlatStorage` in order to enable the `FlatStorageReads` protocol
/// feature.
pub storage_get_mode: StorageGetMode,
/// Enable the `FixContractLoadingCost` protocol feature.
pub fix_contract_loading_cost: bool,
/// Enable the `ImplicitAccountCreation` protocol feature.
pub implicit_account_creation: bool,
/// Enable the host functions added by the `MathExtension` protocol feature.
pub math_extension: bool,
/// Enable the host functions added by the `Ed25519Verify` protocol feature.
pub ed25519_verify: bool,
/// Enable the host functions added by the `AltBn128` protocol feature.
pub alt_bn128: bool,
/// Enable the `FunctionCallWeight` protocol feature.
pub function_call_weight: bool,
/// Enable the `EthImplicitAccounts` protocol feature.
pub eth_implicit_accounts: bool,
/// Describes limits for VM and Runtime.
pub limit_config: LimitConfig,
}
impl Config {
/// Computes non-cryptographically-proof hash. The computation is fast but not cryptographically
/// secure.
pub fn non_crypto_hash(&self) -> u64 {
let mut s = DefaultHasher::new();
self.hash(&mut s);
s.finish()
}
pub fn make_free(&mut self) {
self.ext_costs = ExtCostsConfig {
costs: near_primitives_core::enum_map::enum_map! {
_ => ParameterCost { gas: 0, compute: 0 }
},
};
self.grow_mem_cost = 0;
self.regular_op_cost = 0;
self.limit_config.max_gas_burnt = u64::MAX;
}
}
fn wasmer2_stack_limit_default() -> i32 {
100 * 1024
}
/// Our original code for limiting WASM stack was buggy. We fixed that, but we
/// still have to use old (`V0`) limiter for old protocol versions.
///
/// This struct here exists to enforce that the value in the config is either
/// `0` or `1`. We could have used a `bool` instead, but there's a chance that
/// our current impl isn't perfect either and would need further tweaks in the
/// future.
#[derive(
Debug,
Clone,
Copy,
Hash,
PartialEq,
Eq,
serde_repr::Serialize_repr,
serde_repr::Deserialize_repr,
)]
#[repr(u8)]
pub enum ContractPrepareVersion {
/// Oldest, buggiest version.
///
/// Don't use it unless specifically to support old protocol version.
V0,
/// Old, slow and buggy version.
///
/// Better than V0, but don’t use this nevertheless.
V1,
/// finite-wasm 0.3.0 based contract preparation code.
V2,
}
impl ContractPrepareVersion {
pub fn v0() -> ContractPrepareVersion {
ContractPrepareVersion::V0
}
}