URI: 
       truntime: Implement gas metering. - wasm-runtime - A wasm runtime
  HTML git clone https://git.parazyd.org/wasm-runtime
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
   DIR commit f87baa72e4447be535de9e5f64edd04095f5a500
   DIR parent 48ba506e1bc994ce7c1f4bd216c876b3f82c4843
  HTML Author: parazyd <parazyd@dyne.org>
       Date:   Wed,  9 Mar 2022 09:13:32 +0100
       
       runtime: Implement gas metering.
       
       Diffstat:
         M Cargo.toml                          |       1 +
         M src/runtime.rs                      |      58 ++++++++++++++++++++++++++++---
       
       2 files changed, 54 insertions(+), 5 deletions(-)
       ---
   DIR diff --git a/Cargo.toml b/Cargo.toml
       t@@ -18,6 +18,7 @@ drk-sdk = { path = "./drk-sdk" }
        thiserror = "1.0.30"
        wasmer = "2.2.0"
        wasmer-compiler-singlepass = "2.2.0"
       +wasmer-middlewares = "2.2.0"
        
        [dev-dependencies]
        borsh = "0.9.3"
   DIR diff --git a/src/runtime.rs b/src/runtime.rs
       t@@ -1,7 +1,15 @@
        use anyhow::{anyhow, Result};
        use drk_sdk::entrypoint;
       -use wasmer::{imports, Instance, Memory, Module, Store, Universal, Value};
       +use std::sync::Arc;
       +use wasmer::{
       +    imports, wasmparser::Operator, CompilerConfig, Instance, Memory, Module, Store, Universal,
       +    Value,
       +};
        use wasmer_compiler_singlepass::Singlepass;
       +use wasmer_middlewares::{
       +    metering::{get_remaining_points, MeteringPoints},
       +    Metering,
       +};
        
        use crate::memory::MemoryManipulation;
        
       t@@ -10,7 +18,9 @@ const WASM_MEM_ALLOC: &str = "__drkruntime_mem_alloc";
        /// Name of the wasm linear memory of our guest module
        const MEMORY: &str = "memory";
        /// Hardcoded entrypoint function of a contract
       -const ENTRYPOINT: &str = "entrypoint";
       +pub const ENTRYPOINT: &str = "entrypoint";
       +/// Gas limit for a contract
       +pub const GAS_LIMIT: u64 = 20000;
        
        pub struct Runtime {
            pub(crate) instance: Instance,
       t@@ -19,8 +29,25 @@ pub struct Runtime {
        impl Runtime {
            /// Create a new wasm runtime instance that contains the given wasm module.
            pub fn new(wasm_bytes: &[u8]) -> Result<Self> {
       -        // Define the compiler, engine, and store
       -        let compiler = Singlepass::new();
       +        // This function will be called for each `Operator` encountered during
       +        // the wasm module execution. It should return the cost of the operator
       +        // that it received as its first argument.
       +        let cost_function = |operator: &Operator| -> u64 {
       +            match operator {
       +                Operator::LocalGet { .. } | Operator::I32Const { .. } => 1,
       +                Operator::I32Add { .. } => 2,
       +                _ => 0,
       +            }
       +        };
       +
       +        // `Metering` needs to be configured with a limit and a const function.
       +        // For each `Operator`, the metering middleware will call the cost
       +        // function and subtract the cost from the remaining points.
       +        let metering = Arc::new(Metering::new(GAS_LIMIT, cost_function));
       +
       +        // Define the compiler and middleware, engine, and store
       +        let mut compiler = Singlepass::new();
       +        compiler.push_middleware(metering);
                let store = Store::new(&Universal::new(compiler).engine());
        
                println!("Compiling module...");
       t@@ -49,7 +76,16 @@ impl Runtime {
                println!("{:#?}", entrypoint);
        
                println!("Executing wasm...");
       -        let ret = entrypoint.call(&[Value::I32(mem_offset as i32)])?;
       +        let ret = match entrypoint.call(&[Value::I32(mem_offset as i32)]) {
       +            Ok(v) => {
       +                println!("{}", self.gas_info());
       +                v
       +            }
       +            Err(e) => {
       +                println!("{}", self.gas_info());
       +                return Err(e.into())
       +            }
       +        };
        
                println!("Executed successfully");
                println!("Contract returned: {:?}", ret[0]);
       t@@ -65,6 +101,18 @@ impl Runtime {
                }
            }
        
       +    fn gas_info(&self) -> String {
       +        let remaining_points = get_remaining_points(&self.instance);
       +        match remaining_points {
       +            MeteringPoints::Remaining(rem) => {
       +                format!("Gas used: {}/{}", GAS_LIMIT - rem, GAS_LIMIT)
       +            }
       +            MeteringPoints::Exhausted => {
       +                format!("Gas fully exhausted: {}/{}", GAS_LIMIT + 1, GAS_LIMIT)
       +            }
       +        }
       +    }
       +
            /// Allocate some memory space on a wasm linear memory to allow direct rw
            fn guest_mem_alloc(&self, size: usize) -> Result<u32> {
                let mem_alloc = self.instance.exports.get_function(WASM_MEM_ALLOC)?;