Skip to content

Commit

Permalink
Make get_remaining_points/set_remaining_points free functions
Browse files Browse the repository at this point in the history
  • Loading branch information
webmaster128 committed Dec 16, 2020
1 parent 69f54e6 commit b30b3b6
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 41 deletions.
14 changes: 7 additions & 7 deletions examples/metering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use wasmer::CompilerConfig;
use wasmer::{imports, wat2wasm, Instance, Module, Store};
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_jit::JIT;
use wasmer_middlewares::Metering;
use wasmer_middlewares::{get_remaining_points, set_remaining_points, Metering};

fn main() -> anyhow::Result<()> {
// Let's declare the Wasm module.
Expand Down Expand Up @@ -62,7 +62,7 @@ fn main() -> anyhow::Result<()> {
// function and subtract the cost from the gas.
let metering = Arc::new(Metering::new(10, cost_function));
let mut compiler_config = Cranelift::default();
compiler_config.push_middleware(metering.clone());
compiler_config.push_middleware(metering);

// Create a Store.
//
Expand Down Expand Up @@ -99,7 +99,7 @@ fn main() -> anyhow::Result<()> {
// * `local.get $value` is a `Operator::LocalGet` which costs 1 point;
// * `i32.const` is a `Operator::I32Const` which costs 1 point;
// * `i32.add` is a `Operator::I32Add` which costs 2 points.
let remaining_points_after_first_call = metering.get_remaining_points(&instance);
let remaining_points_after_first_call = get_remaining_points(&instance);
assert_eq!(remaining_points_after_first_call, 6);

println!(
Expand All @@ -112,7 +112,7 @@ fn main() -> anyhow::Result<()> {

// We spent 4 more gas points with the second call.
// We have 2 remaining points.
let remaining_points_after_second_call = metering.get_remaining_points(&instance);
let remaining_points_after_second_call = get_remaining_points(&instance);
assert_eq!(remaining_points_after_second_call, 2);

println!(
Expand All @@ -138,7 +138,7 @@ fn main() -> anyhow::Result<()> {

// Becasue the previous call failed, it did not consume any gas point.
// We still have 2 remaining points.
let remaining_points_after_third_call = metering.get_remaining_points(&instance);
let remaining_points_after_third_call = get_remaining_points(&instance);
assert_eq!(remaining_points_after_third_call, 2);

println!(
Expand All @@ -149,9 +149,9 @@ fn main() -> anyhow::Result<()> {
// Now let's see how we can set a new limit...
println!("Set new remaining points points to 10");
let new_limit = 10;
metering.set_remaining_points(&instance, new_limit);
set_remaining_points(&instance, new_limit);

let remaining_points = metering.get_remaining_points(&instance);
let remaining_points = get_remaining_points(&instance);
assert_eq!(remaining_points, new_limit);

println!("Remaining points: {:?}", remaining_points);
Expand Down
2 changes: 1 addition & 1 deletion lib/middlewares/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
pub mod metering;

pub use metering::Metering;
pub use metering::{get_remaining_points, set_remaining_points, Metering};
78 changes: 45 additions & 33 deletions lib/middlewares/src/metering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,31 +53,6 @@ impl<F: Fn(&Operator) -> u64 + Copy + Clone + Send + Sync> Metering<F> {
remaining_points_index: Mutex::new(None),
}
}

/// Get the remaining points in an Instance.
///
/// Important: the instance Module must been processed with the `Metering` middleware.
pub fn get_remaining_points(&self, instance: &Instance) -> u64 {
instance
.exports
.get_global("remaining_points")
.expect("Can't get `remaining_points` from Instance")
.get()
.try_into()
.expect("`remaining_points` from Instance has wrong type")
}

/// Set the provided remaining points in an Instance.
///
/// Important: the instance Module must been processed with the `Metering` middleware.
pub fn set_remaining_points(&self, instance: &Instance, points: u64) {
instance
.exports
.get_global("remaining_points")
.expect("Can't get `remaining_points` from Instance")
.set(points.into())
.expect("Can't set `remaining_points` in Instance");
}
}

impl<F: Fn(&Operator) -> u64 + Copy + Clone + Send + Sync> fmt::Debug for Metering<F> {
Expand Down Expand Up @@ -189,6 +164,43 @@ impl<F: Fn(&Operator) -> u64 + Copy + Clone + Send + Sync> FunctionMiddleware
}
}

/// Get the remaining points in an `Instance`.
///
/// This can be used in a headless engine after an ahead of time compilation
/// as all required state lives in the instance.
///
/// # Panic
///
/// The instance Module must have been processed with the [`Metering`] middleware
/// at compile time, otherwise this will panic.
pub fn get_remaining_points(instance: &Instance) -> u64 {
instance
.exports
.get_global("remaining_points")
.expect("Can't get `remaining_points` from Instance")
.get()
.try_into()
.expect("`remaining_points` from Instance has wrong type")
}

/// Set the provided remaining points in an `Instance`.
///
/// This can be used in a headless engine after an ahead of time compilation
/// as all required state lives in the instance.
///
/// # Panic
///
/// The instance Module must have been processed with the [`Metering`] middleware
/// at compile time, otherwise this will panic.
pub fn set_remaining_points(instance: &Instance, points: u64) {
instance
.exports
.get_global("remaining_points")
.expect("Can't get `remaining_points` from Instance")
.set(points.into())
.expect("Can't set `remaining_points` in Instance");
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -230,7 +242,7 @@ mod tests {

// Instantiate
let instance = Instance::new(&module, &imports! {}).unwrap();
assert_eq!(metering.get_remaining_points(&instance), 10);
assert_eq!(get_remaining_points(&instance), 10);

// First call
//
Expand All @@ -245,11 +257,11 @@ mod tests {
.native::<i32, i32>()
.unwrap();
add_one.call(1).unwrap();
assert_eq!(metering.get_remaining_points(&instance), 6);
assert_eq!(get_remaining_points(&instance), 6);

// Second call
add_one.call(1).unwrap();
assert_eq!(metering.get_remaining_points(&instance), 2);
assert_eq!(get_remaining_points(&instance), 2);

// Third call fails due to limit
assert!(add_one.call(1).is_err());
Expand All @@ -268,7 +280,7 @@ mod tests {

// Instantiate
let instance = Instance::new(&module, &imports! {}).unwrap();
assert_eq!(metering.get_remaining_points(&instance), 10);
assert_eq!(get_remaining_points(&instance), 10);
let add_one = instance
.exports
.get_function("add_one")
Expand All @@ -277,14 +289,14 @@ mod tests {
.unwrap();

// Increase a bit to have enough for 3 calls
metering.set_remaining_points(&instance, 12);
set_remaining_points(&instance, 12);

// Ensure we can use the new points now
add_one.call(1).unwrap();
assert_eq!(metering.get_remaining_points(&instance), 8);
assert_eq!(get_remaining_points(&instance), 8);
add_one.call(1).unwrap();
assert_eq!(metering.get_remaining_points(&instance), 4);
assert_eq!(get_remaining_points(&instance), 4);
add_one.call(1).unwrap();
assert_eq!(metering.get_remaining_points(&instance), 0);
assert_eq!(get_remaining_points(&instance), 0);
}
}

0 comments on commit b30b3b6

Please sign in to comment.