diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index 3d8b02a84d..6be19f02ae 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -80,7 +80,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 123, - impl_version: 123, + impl_version: 124, apis: RUNTIME_API_VERSIONS, }; diff --git a/substrate/srml/contracts/src/wasm/prepare.rs b/substrate/srml/contracts/src/wasm/prepare.rs index 4539b9d388..8dc137fc01 100644 --- a/substrate/srml/contracts/src/wasm/prepare.rs +++ b/substrate/srml/contracts/src/wasm/prepare.rs @@ -22,7 +22,7 @@ use crate::wasm::env_def::ImportSatisfyCheck; use crate::wasm::PrefabWasmModule; use crate::Schedule; -use parity_wasm::elements::{self, Internal, External, MemoryType, Type}; +use parity_wasm::elements::{self, Internal, External, MemoryType, Type, ValueType}; use pwasm_utils; use pwasm_utils::rules; use rstd::prelude::*; @@ -93,6 +93,50 @@ impl<'a> ContractModule<'a> { Ok(()) } + /// Ensures that no floating point types are in use. + fn ensure_no_floating_types(&self) -> Result<(), &'static str> { + if let Some(global_section) = self.module.global_section() { + for global in global_section.entries() { + match global.global_type().content_type() { + ValueType::F32 | ValueType::F64 => + return Err("use of floating point type in globals is forbidden"), + _ => {} + } + } + } + + if let Some(code_section) = self.module.code_section() { + for func_body in code_section.bodies() { + for local in func_body.locals() { + match local.value_type() { + ValueType::F32 | ValueType::F64 => + return Err("use of floating point type in locals is forbidden"), + _ => {} + } + } + } + } + + if let Some(type_section) = self.module.type_section() { + for wasm_type in type_section.types() { + match wasm_type { + Type::Function(func_type) => { + let return_type = func_type.return_type(); + for value_type in func_type.params().iter().chain(return_type.iter()) { + match value_type { + ValueType::F32 | ValueType::F64 => + return Err("use of floating point type in function types is forbidden"), + _ => {} + } + } + } + } + } + } + + Ok(()) + } + fn inject_gas_metering(self) -> Result { let gas_rules = rules::Set::new( @@ -291,6 +335,7 @@ pub fn prepare_contract( contract_module.scan_exports()?; contract_module.ensure_no_internal_memory()?; contract_module.ensure_table_size_limit(schedule.max_table_size)?; + contract_module.ensure_no_floating_types()?; struct MemoryDefinition { initial: u32, @@ -740,5 +785,49 @@ mod tests { "#, Err("unknown export: expecting only deploy and call functions") ); + + prepare_test!(global_float, + r#" + (module + (global $x f32 (f32.const 0)) + (func (export "call")) + (func (export "deploy")) + ) + "#, + Err("use of floating point type in globals is forbidden") + ); + + prepare_test!(local_float, + r#" + (module + (func $foo (local f32)) + (func (export "call")) + (func (export "deploy")) + ) + "#, + Err("use of floating point type in locals is forbidden") + ); + + prepare_test!(param_float, + r#" + (module + (func $foo (param f32)) + (func (export "call")) + (func (export "deploy")) + ) + "#, + Err("use of floating point type in function types is forbidden") + ); + + prepare_test!(result_float, + r#" + (module + (func $foo (result f32) (f32.const 0)) + (func (export "call")) + (func (export "deploy")) + ) + "#, + Err("use of floating point type in function types is forbidden") + ); } }