Skip to content

Commit

Permalink
optimize handle gas
Browse files Browse the repository at this point in the history
optimize handle gas
  • Loading branch information
scf0220 committed Jul 20, 2023
1 parent 0dae968 commit be81b83
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 4 deletions.
7 changes: 7 additions & 0 deletions packages/vm/src/calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ mod tests {
call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg)
.unwrap()
.unwrap();
assert_eq!(instance.get_gas_left(), 494235049729);
}

#[test]
Expand All @@ -625,6 +626,7 @@ mod tests {
call_execute::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg)
.unwrap()
.unwrap();
assert_eq!(instance.get_gas_left(), 485686146123);
}

#[test]
Expand All @@ -643,6 +645,7 @@ mod tests {
let err =
call_execute::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg).unwrap_err();
assert!(matches!(err, VmError::GasDepletion {}));
assert_eq!(instance.get_gas_left(), 0);
}

#[test]
Expand All @@ -667,6 +670,7 @@ mod tests {
}
err => panic!("Unexpected error: {err:?}"),
}
assert_eq!(instance.get_gas_left(), 493100600000);
}

#[test]
Expand All @@ -689,6 +693,7 @@ mod tests {
}
err => panic!("Unexpected error: {err:?}"),
}
assert_eq!(instance.get_gas_left(), 493655750000);
}

#[test]
Expand All @@ -714,6 +719,7 @@ mod tests {
query_response.as_slice(),
b"{\"verifier\":\"someone else\"}"
);
assert_eq!(instance.get_gas_left(), 485028949541);
}

#[test]
Expand All @@ -732,6 +738,7 @@ mod tests {
let contract_result = call_query(&mut instance, &mock_env(), msg).unwrap();
let query_response = contract_result.unwrap();
assert_eq!(query_response.as_slice(), b"{\"verifier\":\"verifies\"}");
assert_eq!(instance.get_gas_left(), 489741349723);
}

#[cfg(feature = "stargate")]
Expand Down
48 changes: 44 additions & 4 deletions packages/vm/src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::rc::Rc;
use std::sync::{Arc, RwLock};

use derivative::Derivative;
use wasmer::{AsStoreMut, Instance as WasmerInstance, Memory, MemoryView, Value};
use wasmer::{AsStoreMut, Global, Instance as WasmerInstance, Memory, MemoryView, Value};
use wasmer_middlewares::metering::{get_remaining_points, set_remaining_points, MeteringPoints};

use crate::backend::{BackendApi, GasInfo, Querier, Storage};
Expand Down Expand Up @@ -111,6 +111,8 @@ pub type DebugHandlerFn = dyn for<'a, 'b> FnMut(/* msg */ &'a str, DebugInfo<'b>
/// The environment is clonable but clones access the same underlying data.
pub struct Environment<A, S, Q> {
pub memory: Option<Memory>,
pub global_remaining_points: Option<Global>,
pub global_points_exhausted: Option<Global>,
pub api: A,
pub gas_config: GasConfig,
data: Arc<RwLock<ContextData<S, Q>>>,
Expand All @@ -124,6 +126,8 @@ impl<A: BackendApi, S: Storage, Q: Querier> Clone for Environment<A, S, Q> {
fn clone(&self) -> Self {
Environment {
memory: None,
global_remaining_points: self.global_remaining_points.clone(),
global_points_exhausted: self.global_points_exhausted.clone(),
api: self.api,
gas_config: self.gas_config.clone(),
data: self.data.clone(),
Expand All @@ -135,6 +139,8 @@ impl<A: BackendApi, S: Storage, Q: Querier> Environment<A, S, Q> {
pub fn new(api: A, gas_limit: u64) -> Self {
Environment {
memory: None,
global_remaining_points: None,
global_points_exhausted: None,
api,
gas_config: GasConfig::default(),
data: Arc::new(RwLock::new(ContextData::new(gas_limit))),
Expand All @@ -147,6 +153,11 @@ impl<A: BackendApi, S: Storage, Q: Querier> Environment<A, S, Q> {
})
}

pub fn set_global(&mut self, remain: Global, exhausted: Global) {
self.global_remaining_points = Some(remain);
self.global_points_exhausted = Some(exhausted)
}

pub fn debug_handler(&self) -> Option<Rc<RefCell<DebugHandlerFn>>> {
self.with_context_data(|context_data| {
// This clone here requires us to wrap the function in Rc instead of Box
Expand Down Expand Up @@ -322,6 +333,18 @@ impl<A: BackendApi, S: Storage, Q: Querier> Environment<A, S, Q> {
})
}

pub fn get_gas_left_ex(
&self,
remain: &Global,
exhausted: &Global,
store: &mut impl AsStoreMut,
) -> u64 {
match exhausted.get(store) {
value if value.unwrap_i32() > 0 => 0,
_ => u64::try_from(remain.get(store)).unwrap(),
}
}

pub fn get_gas_left(&self, store: &mut impl AsStoreMut) -> u64 {
self.with_wasmer_instance(|instance| {
Ok(match get_remaining_points(store, instance) {
Expand All @@ -332,6 +355,11 @@ impl<A: BackendApi, S: Storage, Q: Querier> Environment<A, S, Q> {
.expect("Wasmer instance is not set. This is a bug in the lifecycle.")
}

pub fn set_gas_left_ex(&self, a: &Global, store: &mut impl AsStoreMut, new_limit: u64) {
a.set(store, new_limit.into())
.expect("Can't set `wasmer_metering_remaining_points` in Instance");
}

pub fn set_gas_left(&self, store: &mut impl AsStoreMut, new_value: u64) {
self.with_wasmer_instance(|instance| {
set_remaining_points(store, instance, new_value);
Expand Down Expand Up @@ -417,7 +445,9 @@ pub fn process_gas_info<A: BackendApi, S: Storage, Q: Querier>(
store: &mut impl AsStoreMut,
info: GasInfo,
) -> VmResult<()> {
let gas_left = env.get_gas_left(store);
let remain_points = env.global_remaining_points.as_ref().unwrap();
let exhausted_points = env.global_points_exhausted.as_ref().unwrap();
let gas_left = env.get_gas_left_ex(remain_points, exhausted_points, store);

let new_limit = env.with_gas_state_mut(|gas_state| {
gas_state.externally_used_gas += info.externally_used;
Expand All @@ -429,7 +459,7 @@ pub fn process_gas_info<A: BackendApi, S: Storage, Q: Querier>(
});

// This tells wasmer how much more gas it can consume from this point in time.
env.set_gas_left(store, new_limit);
env.set_gas_left_ex(remain_points, store, new_limit);

if info.externally_used + info.cost > gas_left {
Err(VmError::gas_depletion())
Expand Down Expand Up @@ -473,7 +503,7 @@ mod tests {
Store,
Box<WasmerInstance>,
) {
let env = Environment::new(MockApi::default(), gas_limit);
let mut env = Environment::new(MockApi::default(), gas_limit);

let (engine, module) = compile(CONTRACT, &[]).unwrap();
let mut store = make_store_with_engine(engine, TESTING_MEMORY_LIMIT);
Expand Down Expand Up @@ -503,6 +533,16 @@ mod tests {
let instance_ptr = NonNull::from(instance.as_ref());
env.set_wasmer_instance(Some(instance_ptr));
env.set_gas_left(&mut store, gas_limit);
let remaining_points = instance
.exports
.get_global("wasmer_metering_remaining_points");
let points_exhausted = instance
.exports
.get_global("wasmer_metering_points_exhausted");
env.set_global(
remaining_points.unwrap().clone(),
points_exhausted.unwrap().clone(),
);

(env, store, instance)
}
Expand Down
10 changes: 10 additions & 0 deletions packages/vm/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,16 @@ mod tests {

env.set_wasmer_instance(Some(instance_ptr));
env.set_gas_left(&mut store, gas_limit);
let remaining_points = wasmer_instance
.exports
.get_global("wasmer_metering_remaining_points");
let points_exhausted = wasmer_instance
.exports
.get_global("wasmer_metering_points_exhausted");
env.set_global(
remaining_points.unwrap().clone(),
points_exhausted.unwrap().clone(),
);
env.set_storage_readonly(false);
}

Expand Down
10 changes: 10 additions & 0 deletions packages/vm/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,16 @@ where
env.memory = Some(memory);
env.set_wasmer_instance(Some(instance_ptr));
env.set_gas_left(&mut store, gas_limit);
let remaining_points = wasmer_instance
.exports
.get_global("wasmer_metering_remaining_points");
let points_exhausted = wasmer_instance
.exports
.get_global("wasmer_metering_points_exhausted");
env.set_global(
remaining_points.unwrap().clone(),
points_exhausted.unwrap().clone(),
);
env.move_in(backend.storage, backend.querier);
}

Expand Down

0 comments on commit be81b83

Please sign in to comment.