Skip to content

Instantly share code, notes, and snippets.

@dakom
Last active November 17, 2022 15:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dakom/e1d8bdbe7f604a7445f80f889ec19acc to your computer and use it in GitHub Desktop.
Save dakom/e1d8bdbe7f604a7445f80f889ec19acc to your computer and use it in GitHub Desktop.
cosmwasm vm gas profiling
// EXAMPLE:
// let contract_1 = Contract::new("contract_1", contract_1::msg::InstantiateMsg{});
// let (gas_used, resp) = contract_1.execute(contract_1::msg::ExecuteMsg::Foo{inner_msg_data: "bar"});
// println!("computational gas used: {}", gas);
// println!("execution response: {:?}", resp);
//
// storage actions can also be calculated by estimating as follows:
// let data_len = storage_binary_len(&SomeStorageStruct{});
// calculate costs according to https://github.com/cosmos/cosmos-sdk/blob/65015c2f96fa0087891d4caa3267c426e737ddeb/store/types/gas.go#L231
use std::{
fs::File,
io::Read,
path::Path,
str,
};
use cosmwasm_std::{coins, Empty, Response};
use cosmwasm_vm::testing::{
mock_backend, mock_env, mock_info, MockApi, MockStorage, MockQuerier
};
use cosmwasm_vm::{
call_execute, call_instantiate, Instance,
InstanceOptions, Size,
};
use serde::Serialize;
// set this to the path where your compiled .wasm resides
const ARTIFACTS_PATH:&str = "../artifacts";
const DEFAULT_MEMORY_LIMIT: Size = Size::mebi(64);
const HIGH_GAS_LIMIT: u64 = 20_000_000_000_000_000; // ~20s, allows many calls on one instance
const COIN_DENOM:&str = "uwasm";
// vm gas -> sdk gas multiplier
// see https://github.com/CosmWasm/wasmd/blob/ab4ffa51e651a9a21095dbb102a032d62b11729c/x/wasm/keeper/gas_register.go#L31
const GAS_MULTIPLIER:u64 = 140_000_000;
pub type MockInstance = Instance<MockApi, MockStorage, MockQuerier>;
pub struct Contract {
pub instance: MockInstance
}
impl Contract {
pub fn new(contract_name: &str, instantiate_msg: impl Serialize) -> Self {
let bytes = load_file_bytes(contract_name).unwrap();
let backend = mock_backend(&[]);
let options: InstanceOptions = InstanceOptions {
gas_limit: HIGH_GAS_LIMIT,
print_debug: true,
};
let mut instance =
Instance::from_code(&bytes, backend, options, Some(DEFAULT_MEMORY_LIMIT)).unwrap();
let admin = mock_info("admin", &coins(1000, COIN_DENOM));
let msg = serde_json_wasm::to_vec(&instantiate_msg).unwrap();
call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &admin, &msg).unwrap().unwrap();
Self {
instance
}
}
// returns (gas_used_in_sdk_units, Response)
pub fn execute(&mut self, execute_msg: impl Serialize) -> (u64, Response) {
let user = mock_info("user", &[]);
println!("EXECUTING: [{}]", serde_json_wasm::to_string(&execute_msg).unwrap());
let msg = serde_json_wasm::to_vec(&execute_msg).unwrap();
let gas_before = self.instance.get_gas_left();
let res =
call_execute::<_, _, _, Empty>(&mut self.instance, &mock_env(), &user, &msg).unwrap().unwrap();
let gas_used = gas_before - self.instance.get_gas_left();
((gas_used / CONFIG.wasm_gas_multiplier), res)
}
}
pub fn load_file_bytes(contract_name: &str) -> Result<Vec<u8>, String> {
let path_str = format!("{}/{}.wasm", ARTIFACTS_PATH, contract_name);
let path = Path::new(&path_str);
let mut f = File::open(path.clone()).map_err(|_| format!("file not found: {:?}", path))?;
let mut contents = Vec::new();
f.read_to_end(&mut contents)
.map_err(|_| "unable to read the file")?;
Ok(contents)
}
fn storage_binary_len(data: &impl Serialize) -> usize {
let bytes:Vec<u8> = cosmwasm_std::to_vec(data).unwrap();
let bytes_len = bytes.len();
((bytes_len as f32 / 3.0).ceil() * 4.0) as usize
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment