parent
							
								
									407c8c3fb9
								
							
						
					
					
						commit
						9e4c122cf3
					
				| @ -1 +1 @@ | ||||
| Subproject commit 330f748b1eece451f460224b48d515489dd86f5c | ||||
| Subproject commit 85e76c5ea2a54c6c54e35014643b5080a50460c5 | ||||
| @ -17,8 +17,9 @@ | ||||
| //! Wasm env module bindings
 | ||||
| 
 | ||||
| use parity_wasm::elements::ValueType::*; | ||||
| use parity_wasm::interpreter::UserFunctionDescriptor; | ||||
| use parity_wasm::interpreter::{self, UserFunctionDescriptor}; | ||||
| use parity_wasm::interpreter::UserFunctionDescriptor::*; | ||||
| use super::runtime::Runtime; | ||||
| 
 | ||||
| pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[ | ||||
| 	Static( | ||||
| @ -93,4 +94,17 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[ | ||||
| 		&[I32; 0], | ||||
| 		None | ||||
| 	), | ||||
| 
 | ||||
| 	Static( | ||||
| 		"_llvm_bswap_i64", | ||||
| 		&[I32; 2], | ||||
| 		Some(I32) | ||||
| 	), | ||||
| ]; | ||||
| 
 | ||||
| pub fn native_bindings<'a>(runtime: &'a mut Runtime) -> interpreter::UserFunctions<'a> { | ||||
| 	interpreter::UserFunctions { | ||||
| 		executor: runtime, | ||||
| 		functions: ::std::borrow::Cow::from(SIGNATURES), | ||||
| 	} | ||||
| } | ||||
| @ -32,8 +32,6 @@ mod result; | ||||
| mod tests; | ||||
| mod env; | ||||
| 
 | ||||
| use std::sync::Arc; | ||||
| 
 | ||||
| const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024; | ||||
| 
 | ||||
| use parity_wasm::{interpreter, elements}; | ||||
| @ -89,6 +87,7 @@ impl vm::Vm for WasmInterpreter { | ||||
| 			DEFAULT_STACK_SPACE, | ||||
| 			params.gas.low_u64(), | ||||
| 			RuntimeContext::new(params.address, params.sender), | ||||
| 			&self.program, | ||||
| 		); | ||||
| 
 | ||||
| 		let mut cursor = ::std::io::Cursor::new(&*code); | ||||
| @ -112,16 +111,8 @@ impl vm::Vm for WasmInterpreter { | ||||
| 		)?; | ||||
| 
 | ||||
| 		{ | ||||
| 			let execution_params = interpreter::ExecutionParams::with_external( | ||||
| 				"env".into(), | ||||
| 				Arc::new( | ||||
| 					interpreter::env_native_module(env_instance, native_bindings(&mut runtime)) | ||||
| 						.map_err(|err| { | ||||
| 							// todo: prefer explicit panic here also?
 | ||||
| 							vm::Error::Wasm(format!("Error instantiating native bindings: {:?}", err)) | ||||
| 						})? | ||||
| 				) | ||||
| 			).add_argument(interpreter::RuntimeValue::I32(d_ptr.as_raw() as i32)); | ||||
| 			let execution_params = runtime.execution_params() | ||||
| 				.add_argument(interpreter::RuntimeValue::I32(d_ptr.as_raw() as i32)); | ||||
| 
 | ||||
| 			let module_instance = self.program.add_module("contract", contract_module, Some(&execution_params.externals)) | ||||
| 				.map_err(|err| { | ||||
| @ -158,13 +149,6 @@ impl vm::Vm for WasmInterpreter { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn native_bindings<'a>(runtime: &'a mut Runtime) -> interpreter::UserFunctions<'a> { | ||||
| 	interpreter::UserFunctions { | ||||
| 		executor: runtime, | ||||
| 		functions: ::std::borrow::Cow::from(env::SIGNATURES), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl From<runtime::Error> for vm::Error { | ||||
| 	fn from(err: runtime::Error) -> vm::Error { | ||||
| 		vm::Error::Wasm(format!("WASM runtime-error: {:?}", err)) | ||||
|  | ||||
| @ -72,24 +72,26 @@ impl RuntimeContext { | ||||
| } | ||||
| 
 | ||||
| /// Runtime enviroment data for wasm contract execution
 | ||||
| pub struct Runtime<'a> { | ||||
| pub struct Runtime<'a, 'b> { | ||||
| 	gas_counter: u64, | ||||
| 	gas_limit: u64, | ||||
| 	dynamic_top: u32, | ||||
| 	ext: &'a mut vm::Ext, | ||||
| 	memory: Arc<interpreter::MemoryInstance>, | ||||
| 	context: RuntimeContext, | ||||
| 	instance: &'b interpreter::ProgramInstance, | ||||
| } | ||||
| 
 | ||||
| impl<'a> Runtime<'a> { | ||||
| impl<'a, 'b> Runtime<'a, 'b> { | ||||
| 	/// New runtime for wasm contract with specified params
 | ||||
| 	pub fn with_params<'b>( | ||||
| 		ext: &'b mut vm::Ext, | ||||
| 	pub fn with_params<'c, 'd>( | ||||
| 		ext: &'c mut vm::Ext, | ||||
| 		memory: Arc<interpreter::MemoryInstance>, | ||||
| 		stack_space: u32, | ||||
| 		gas_limit: u64, | ||||
| 		context: RuntimeContext, | ||||
| 	) -> Runtime<'b> { | ||||
| 		program_instance: &'d interpreter::ProgramInstance, | ||||
| 	) -> Runtime<'c, 'd> { | ||||
| 		Runtime { | ||||
| 			gas_counter: 0, | ||||
| 			gas_limit: gas_limit, | ||||
| @ -97,6 +99,7 @@ impl<'a> Runtime<'a> { | ||||
| 			memory: memory, | ||||
| 			ext: ext, | ||||
| 			context: context, | ||||
| 			instance: program_instance, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -449,9 +452,58 @@ impl<'a> Runtime<'a> { | ||||
| 
 | ||||
| 		Ok(Some(0i32.into())) | ||||
| 	} | ||||
| 
 | ||||
| 	fn bswap_32(x: u32) -> u32 { | ||||
| 		x >> 24 | x >> 8 & 0xff00 | x << 8 & 0xff0000 | x << 24 | ||||
| 	} | ||||
| 
 | ||||
| 	fn bitswap_i64(&mut self, context: interpreter::CallerContext) | ||||
| 		-> Result<Option<interpreter::RuntimeValue>, interpreter::Error> | ||||
| 	{ | ||||
| 		let x1 = context.value_stack.pop_as::<i32>()?; | ||||
| 		let x2 = context.value_stack.pop_as::<i32>()?; | ||||
| 
 | ||||
| 		let result = ((Runtime::bswap_32(x2 as u32) as u64) << 32 | ||||
| 			| Runtime::bswap_32(x1 as u32) as u64) as i64; | ||||
| 
 | ||||
| 		self.return_i64(result) | ||||
| 	} | ||||
| 
 | ||||
| 	fn return_i64(&mut self, val: i64) -> Result<Option<interpreter::RuntimeValue>, interpreter::Error> { | ||||
| 		let uval = val as u64; | ||||
| 		let hi = (uval >> 32) as i32; | ||||
| 		let lo = (uval << 32 >> 32) as i32; | ||||
| 
 | ||||
| 		let target = self.instance.module("contract") | ||||
| 			.ok_or(interpreter::Error::Trap("Error locating main execution entry".to_owned()))?; | ||||
| 		target.execute_export( | ||||
| 			"setTempRet0", | ||||
| 			self.execution_params().add_argument( | ||||
| 				interpreter::RuntimeValue::I32(hi).into() | ||||
| 			), | ||||
| 		)?; | ||||
| 		Ok(Some( | ||||
| 			(lo).into() | ||||
| 		)) | ||||
| 	} | ||||
| 
 | ||||
| 	pub fn execution_params(&mut self) -> interpreter::ExecutionParams { | ||||
| 		use super::env; | ||||
| 
 | ||||
| 		let env_instance = self.instance.module("env") | ||||
| 			.expect("Env module always exists; qed"); | ||||
| 
 | ||||
| 		interpreter::ExecutionParams::with_external( | ||||
| 			"env".into(), | ||||
| 			Arc::new( | ||||
| 				interpreter::env_native_module(env_instance, env::native_bindings(self)) | ||||
| 					.expect("Env module always exists; qed") | ||||
| 			) | ||||
| 		) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<'a> interpreter::UserFunctionExecutor for Runtime<'a> { | ||||
| impl<'a, 'b> interpreter::UserFunctionExecutor for Runtime<'a, 'b> { | ||||
| 	fn execute(&mut self, name: &str, context: interpreter::CallerContext) | ||||
| 		-> Result<Option<interpreter::RuntimeValue>, interpreter::Error> | ||||
| 	{ | ||||
| @ -494,6 +546,9 @@ impl<'a> interpreter::UserFunctionExecutor for Runtime<'a> { | ||||
| 			"_emscripten_memcpy_big" => { | ||||
| 				self.mem_copy(context) | ||||
| 			}, | ||||
| 			"_llvm_bswap_i64" => { | ||||
| 				self.bitswap_i64(context) | ||||
| 			}, | ||||
| 			_ => { | ||||
| 				trace!(target: "wasm", "Trapped due to unhandled function: '{}'", name); | ||||
| 				self.user_trap(context) | ||||
|  | ||||
| @ -414,3 +414,37 @@ fn storage_read() { | ||||
| 	assert_eq!(gas_left, U256::from(99682)); | ||||
| 	assert_eq!(Address::from(&result[12..32]), address); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // Tests that contract's ability to read from a storage
 | ||||
| // Test prepopulates address into storage, than executes a contract which read that address from storage and write this address into result
 | ||||
| #[test] | ||||
| fn math_add() { | ||||
| 	::ethcore_logger::init_log(); | ||||
| 	let code = load_sample!("math.wasm"); | ||||
| 
 | ||||
| 	let mut params = ActionParams::default(); | ||||
| 	params.gas = U256::from(100_000); | ||||
| 	params.code = Some(Arc::new(code)); | ||||
| 
 | ||||
| 	let mut args = [0u8; 64]; | ||||
| 	let arg_a = U256::from_dec_str("999999999999999999999999999999").unwrap(); | ||||
| 	let arg_b = U256::from_dec_str("888888888888888888888888888888").unwrap(); | ||||
| 	arg_a.to_big_endian(&mut args[0..32]); | ||||
| 	arg_b.to_big_endian(&mut args[32..64]); | ||||
| 	params.data = Some(args.to_vec()); | ||||
| 
 | ||||
| 	let (gas_left, result) = { | ||||
| 		let mut interpreter = wasm_interpreter(); | ||||
| 		let result = interpreter.exec(params, &mut FakeExt::new()).expect("Interpreter to execute without any errors"); | ||||
| 		match result { | ||||
| 				GasLeft::Known(_) => { panic!("storage_read should return payload"); }, | ||||
| 				GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	let sum: U256 = (&result[..]).into(); | ||||
| 
 | ||||
| 	assert_eq!(gas_left, U256::from(96284)); | ||||
| 	assert_eq!(sum, U256::from_dec_str("1888888888888888888888888888887").unwrap()); | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user