diff --git a/Cargo.lock b/Cargo.lock
index 0aa633b9c..5aee726c1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -688,6 +688,7 @@ dependencies = [
"wasm-encoder 0.205.0",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
"wat",
]
diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock
index f67e8bebb..6b9976490 100644
--- a/contracts/burner/Cargo.lock
+++ b/contracts/burner/Cargo.lock
@@ -449,6 +449,7 @@ dependencies = [
"tracing",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
]
[[package]]
diff --git a/contracts/crypto-verify/Cargo.lock b/contracts/crypto-verify/Cargo.lock
index 50c7e4d34..ca21e331c 100644
--- a/contracts/crypto-verify/Cargo.lock
+++ b/contracts/crypto-verify/Cargo.lock
@@ -444,6 +444,7 @@ dependencies = [
"tracing",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
]
[[package]]
diff --git a/contracts/cyberpunk/Cargo.lock b/contracts/cyberpunk/Cargo.lock
index a79e93d69..d83185816 100644
--- a/contracts/cyberpunk/Cargo.lock
+++ b/contracts/cyberpunk/Cargo.lock
@@ -461,6 +461,7 @@ dependencies = [
"tracing",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
]
[[package]]
diff --git a/contracts/empty/Cargo.lock b/contracts/empty/Cargo.lock
index 5c95b66ce..28a0cce73 100644
--- a/contracts/empty/Cargo.lock
+++ b/contracts/empty/Cargo.lock
@@ -438,6 +438,7 @@ dependencies = [
"tracing",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
]
[[package]]
diff --git a/contracts/floaty/Cargo.lock b/contracts/floaty/Cargo.lock
index 497437c68..0ee048e1f 100644
--- a/contracts/floaty/Cargo.lock
+++ b/contracts/floaty/Cargo.lock
@@ -450,6 +450,7 @@ dependencies = [
"tracing",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
]
[[package]]
diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock
index f3860cdd4..3ab01a3c5 100644
--- a/contracts/hackatom/Cargo.lock
+++ b/contracts/hackatom/Cargo.lock
@@ -438,6 +438,7 @@ dependencies = [
"tracing",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
]
[[package]]
diff --git a/contracts/ibc-callbacks/Cargo.lock b/contracts/ibc-callbacks/Cargo.lock
index 7b61420be..8dc8d8530 100644
--- a/contracts/ibc-callbacks/Cargo.lock
+++ b/contracts/ibc-callbacks/Cargo.lock
@@ -450,6 +450,7 @@ dependencies = [
"tracing",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
]
[[package]]
diff --git a/contracts/ibc-reflect-send/Cargo.lock b/contracts/ibc-reflect-send/Cargo.lock
index 45da080a9..4eb973cdf 100644
--- a/contracts/ibc-reflect-send/Cargo.lock
+++ b/contracts/ibc-reflect-send/Cargo.lock
@@ -438,6 +438,7 @@ dependencies = [
"tracing",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
]
[[package]]
diff --git a/contracts/ibc-reflect/Cargo.lock b/contracts/ibc-reflect/Cargo.lock
index bd7ff40ba..84a9fae9f 100644
--- a/contracts/ibc-reflect/Cargo.lock
+++ b/contracts/ibc-reflect/Cargo.lock
@@ -438,6 +438,7 @@ dependencies = [
"tracing",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
]
[[package]]
diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock
index 7c80c06e8..1e78514dc 100644
--- a/contracts/queue/Cargo.lock
+++ b/contracts/queue/Cargo.lock
@@ -438,6 +438,7 @@ dependencies = [
"tracing",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
]
[[package]]
diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock
index c6233732b..503eeffb9 100644
--- a/contracts/reflect/Cargo.lock
+++ b/contracts/reflect/Cargo.lock
@@ -438,6 +438,7 @@ dependencies = [
"tracing",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
]
[[package]]
diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock
index e8fe84c3f..de46fc419 100644
--- a/contracts/staking/Cargo.lock
+++ b/contracts/staking/Cargo.lock
@@ -438,6 +438,7 @@ dependencies = [
"tracing",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
]
[[package]]
diff --git a/contracts/virus/Cargo.lock b/contracts/virus/Cargo.lock
index 8f8497dc3..6c9e9e1a7 100644
--- a/contracts/virus/Cargo.lock
+++ b/contracts/virus/Cargo.lock
@@ -438,6 +438,7 @@ dependencies = [
"tracing",
"wasmer",
"wasmer-middlewares",
+ "wasmer-types",
]
[[package]]
diff --git a/packages/vm/Cargo.toml b/packages/vm/Cargo.toml
index acfdc1dfa..45ec434b6 100644
--- a/packages/vm/Cargo.toml
+++ b/packages/vm/Cargo.toml
@@ -58,6 +58,7 @@ sha2 = "0.10.3"
thiserror = "1.0.26"
wasmer = { version = "=4.3.3", default-features = false, features = ["singlepass"] }
wasmer-middlewares = "=4.3.3"
+wasmer-types = "=4.3.3"
strum = { version = "0.26.2", default-features = false, features = ["derive"] }
# For heap profiling. Only used in the "heap_profiling" example. This has to be a non-dev dependency
# because cargo currently does not support optional dev-dependencies.
diff --git a/packages/vm/src/instance.rs b/packages/vm/src/instance.rs
index 7a52013b5..04b2260db 100644
--- a/packages/vm/src/instance.rs
+++ b/packages/vm/src/instance.rs
@@ -914,7 +914,7 @@ mod tests {
let report2 = instance.create_gas_report();
assert_eq!(report2.used_externally, 251);
- assert_eq!(report2.used_internally, 16995280);
+ assert_eq!(report2.used_internally, 21059380);
assert_eq!(report2.limit, LIMIT);
assert_eq!(
report2.remaining,
@@ -1105,7 +1105,7 @@ mod tests {
.unwrap();
let init_used = orig_gas - instance.get_gas_left();
- assert_eq!(init_used, 16995531);
+ assert_eq!(init_used, 21059631);
}
#[test]
@@ -1130,7 +1130,7 @@ mod tests {
.unwrap();
let execute_used = gas_before_execute - instance.get_gas_left();
- assert_eq!(execute_used, 19589666);
+ assert_eq!(execute_used, 25160611);
}
#[test]
@@ -1173,6 +1173,6 @@ mod tests {
);
let query_used = gas_before_query - instance.get_gas_left();
- assert_eq!(query_used, 11942871);
+ assert_eq!(query_used, 15106521);
}
}
diff --git a/packages/vm/src/modules/file_system_cache.rs b/packages/vm/src/modules/file_system_cache.rs
index f0c240f19..76c1c5df8 100644
--- a/packages/vm/src/modules/file_system_cache.rs
+++ b/packages/vm/src/modules/file_system_cache.rs
@@ -63,7 +63,13 @@ use super::CachedModule;
/// Module compatibility between Wasmer versions is not guaranteed.
/// - **v10**:
/// New version because of Metering middleware change.
-const MODULE_SERIALIZATION_VERSION: &str = "v10";
+/// - **v11**:
+/// Reserved for 1.5.x branch.
+/// - **v12**:
+/// Reserved for 2.0.x branch.
+/// - **v13**:
+/// New version because of Metering middleware change.
+const MODULE_SERIALIZATION_VERSION: &str = "v13";
/// Representation of a directory that contains compiled Wasm artifacts.
pub struct FileSystemCache {
@@ -315,7 +321,7 @@ mod tests {
cache.store(&checksum, &module).unwrap();
let mut globber = glob::glob(&format!(
- "{}/v10-wasmer7/**/{}.module",
+ "{}/v13-wasmer7/**/{}.module",
tmp_dir.path().to_string_lossy(),
checksum
))
@@ -398,9 +404,9 @@ mod tests {
assert_eq!(
p.as_os_str(),
if cfg!(windows) {
- "modules\\v10-wasmer17\\x86_64-nintendo-fuchsia-gnu-coff-01E9F9FE"
+ "modules\\v13-wasmer17\\x86_64-nintendo-fuchsia-gnu-coff-01E9F9FE"
} else {
- "modules/v10-wasmer17/x86_64-nintendo-fuchsia-gnu-coff-01E9F9FE"
+ "modules/v13-wasmer17/x86_64-nintendo-fuchsia-gnu-coff-01E9F9FE"
}
);
}
diff --git a/packages/vm/src/wasm_backend/engine.rs b/packages/vm/src/wasm_backend/engine.rs
index a6bdb62e0..1e481573f 100644
--- a/packages/vm/src/wasm_backend/engine.rs
+++ b/packages/vm/src/wasm_backend/engine.rs
@@ -3,12 +3,12 @@ use wasmer::NativeEngineExt;
use wasmer::{
sys::BaseTunables, wasmparser::Operator, CompilerConfig, Engine, Pages, Target, WASM_PAGE_SIZE,
};
-use wasmer_middlewares::Metering;
use crate::size::Size;
use super::gatekeeper::Gatekeeper;
use super::limiting_tunables::LimitingTunables;
+use super::metering::{is_accounting, Metering};
/// WebAssembly linear memory objects have sizes measured in pages. Each page
/// is 65536 (2^16) bytes. In WebAssembly version 1, a linear memory can have at
@@ -25,17 +25,10 @@ fn cost(operator: &Operator) -> u64 {
// precise enough to derive insights from it.
const GAS_PER_OPERATION: u64 = 115;
- match operator {
- Operator::Loop { .. }
- | Operator::End
- | Operator::Else
- | Operator::Br { .. }
- | Operator::BrTable { .. }
- | Operator::BrIf { .. }
- | Operator::Call { .. }
- | Operator::CallIndirect { .. }
- | Operator::Return => GAS_PER_OPERATION * 14,
- _ => GAS_PER_OPERATION,
+ if is_accounting(operator) {
+ GAS_PER_OPERATION * 14
+ } else {
+ GAS_PER_OPERATION
}
}
diff --git a/packages/vm/src/wasm_backend/metering.rs b/packages/vm/src/wasm_backend/metering.rs
new file mode 100644
index 000000000..e69f42fdb
--- /dev/null
+++ b/packages/vm/src/wasm_backend/metering.rs
@@ -0,0 +1,263 @@
+use std::fmt;
+use std::sync::{Arc, Mutex};
+use wasmer::wasmparser::{BlockType as WpTypeOrFuncType, Operator};
+use wasmer::{
+ ExportIndex, FunctionMiddleware, GlobalInit, GlobalType, LocalFunctionIndex, MiddlewareError,
+ MiddlewareReaderState, ModuleMiddleware, Mutability, Type,
+};
+use wasmer_types::{GlobalIndex, ModuleInfo};
+
+#[derive(Clone)]
+struct MeteringGlobalIndexes(GlobalIndex, GlobalIndex);
+
+impl MeteringGlobalIndexes {
+ /// The global index in the current module for remaining points.
+ fn remaining_points(&self) -> GlobalIndex {
+ self.0
+ }
+
+ /// The global index in the current module for a boolean indicating whether points are exhausted
+ /// or not.
+ /// This boolean is represented as a i32 global:
+ /// * 0: there are remaining points
+ /// * 1: points have been exhausted
+ fn points_exhausted(&self) -> GlobalIndex {
+ self.1
+ }
+}
+
+impl fmt::Debug for MeteringGlobalIndexes {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("MeteringGlobalIndexes")
+ .field("remaining_points", &self.remaining_points())
+ .field("points_exhausted", &self.points_exhausted())
+ .finish()
+ }
+}
+
+/// The module-level metering middleware.
+///
+/// # Panic
+///
+/// An instance of `Metering` should _not_ be shared among different
+/// modules, since it tracks module-specific information like the
+/// global index to store metering state. Attempts to use a `Metering`
+/// instance from multiple modules will result in a panic.
+///
+/// # Example
+///
+/// ```rust
+/// use std::sync::Arc;
+/// use wasmer::{wasmparser::Operator, CompilerConfig};
+/// use wasmer_middlewares::Metering;
+///
+/// fn create_metering_middleware(compiler_config: &mut dyn CompilerConfig) {
+/// // Let's define a dummy cost function,
+/// // which counts 1 for all operators.
+/// let cost_function = |_operator: &Operator| -> u64 { 1 };
+///
+/// // Let's define the initial limit.
+/// let initial_limit = 10;
+///
+/// // Let's creating the metering middleware.
+/// let metering = Arc::new(Metering::new(
+/// initial_limit,
+/// cost_function
+/// ));
+///
+/// // Finally, let's push the middleware.
+/// compiler_config.push_middleware(metering);
+/// }
+/// ```
+pub struct Metering u64 + Send + Sync> {
+ /// Initial limit of points.
+ initial_limit: u64,
+
+ /// Function that maps each operator to a cost in "points".
+ cost_function: Arc,
+
+ /// The global indexes for metering points.
+ global_indexes: Mutex