diff --git a/substrate/srml/contract/src/wasm/prepare.rs b/substrate/srml/contract/src/wasm/prepare.rs index ae09ad87af..9d401a6a7c 100644 --- a/substrate/srml/contract/src/wasm/prepare.rs +++ b/substrate/srml/contract/src/wasm/prepare.rs @@ -229,7 +229,10 @@ impl<'a, Gas: 'a + As + Clone> ContractModule<'a, Gas> { .get(*type_idx as usize) .ok_or_else(|| "validation: import entry points to a non-existent type")?; - if !C::can_satisfy(import.field().as_bytes(), func_ty) { + // We disallow importing `gas` function here since it is treated as implementation detail. + if import.field().as_bytes() == b"gas" + || !C::can_satisfy(import.field().as_bytes(), func_ty) + { return Err("module imports a non-existent function"); } } @@ -263,8 +266,6 @@ pub fn prepare_contract( let mut contract_module = ContractModule::new(original_code, schedule)?; contract_module.scan_exports()?; contract_module.ensure_no_internal_memory()?; - contract_module.inject_gas_metering()?; - contract_module.inject_stack_height_metering()?; struct MemoryDefinition { initial: u32, @@ -300,6 +301,9 @@ pub fn prepare_contract( } }; + contract_module.inject_gas_metering()?; + contract_module.inject_stack_height_metering()?; + Ok(PrefabWasmModule { schedule_version: schedule.version, initial: memory_def.initial, @@ -327,7 +331,11 @@ mod tests { // implementation from it. So actual implementations doesn't matter. define_env!(TestEnv, , panic(_ctx) => { unreachable!(); }, + + // gas is an implementation defined function and a contract can't import it. gas(_ctx, _amount: u32) => { unreachable!(); }, + + nop(_ctx, _unused: u64) => { unreachable!(); }, ); macro_rules! prepare_test { @@ -445,7 +453,7 @@ mod tests { prepare_test!(can_import_legit_function, r#" (module - (import "env" "gas" (func (param i32))) + (import "env" "nop" (func (param i64))) (func (export "call")) (func (export "deploy")) @@ -454,6 +462,20 @@ mod tests { Ok(_) ); + // even though gas is defined the contract can't import it since + // it is an implementation defined. + prepare_test!(can_not_import_gas_function, + r#" + (module + (import "env" "gas" (func (param i32))) + + (func (export "call")) + (func (export "deploy")) + ) + "#, + Err("module imports a non-existent function") + ); + // nothing can be imported from non-"env" module for now. prepare_test!(non_env_import, r#" diff --git a/substrate/srml/contract/src/wasm/runtime.rs b/substrate/srml/contract/src/wasm/runtime.rs index b1bd1e9f1f..314bdbf5a1 100644 --- a/substrate/srml/contract/src/wasm/runtime.rs +++ b/substrate/srml/contract/src/wasm/runtime.rs @@ -202,6 +202,9 @@ define_env!(Env, , // Account for used gas. Traps if gas used is greater than gas limit. // + // NOTE: This is a implementation defined call and is NOT a part of the public API. + // This call is supposed to be called only by instrumentation injected code. + // // - amount: How much gas is used. gas(ctx, amount: u32) => { charge_gas(&mut ctx.gas_meter, ctx.schedule, RuntimeToken::Explicit(amount))?;