propagate evmjit errors upstream
This commit is contained in:
		
							parent
							
								
									dea9ec203b
								
							
						
					
					
						commit
						bbb25fb6ce
					
				| @ -4,6 +4,7 @@ use util::uint::U256; | |||||||
| use evm::{EvmParams, Ext}; | use evm::{EvmParams, Ext}; | ||||||
| 
 | 
 | ||||||
| /// Evm errors.
 | /// Evm errors.
 | ||||||
|  | #[derive(Debug)] | ||||||
| pub enum EvmError { | pub enum EvmError { | ||||||
| 	/// `OutOfGas` is returned when transaction execution runs out of gas.
 | 	/// `OutOfGas` is returned when transaction execution runs out of gas.
 | ||||||
| 	/// The state should be reverted to the state from before the
 | 	/// The state should be reverted to the state from before the
 | ||||||
|  | |||||||
| @ -123,9 +123,9 @@ impl<'a> Executive<'a> { | |||||||
| 		Executive::new_with_depth(state, info, engine, 0) | 		Executive::new_with_depth(state, info, engine, 0) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/// Populates executive from parent externalities. Increments executive depth.
 | 	/// Populates executive from parent properties. Increments executive depth.
 | ||||||
| 	fn from_parent(e: &'a mut Externalities) -> Self { | 	fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self { | ||||||
| 		Executive::new_with_depth(e.state, e.info, e.engine, e.depth + 1) | 		Executive::new_with_depth(state, info, engine, depth + 1) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/// Helper constructor. Should be used to create `Executive` with desired depth.
 | 	/// Helper constructor. Should be used to create `Executive` with desired depth.
 | ||||||
| @ -353,10 +353,10 @@ impl<'a> Ext for Externalities<'a> { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn create(&mut self, gas: u64, endowment: &U256, code: &[u8]) -> Option<(u64, Address)> { | 	fn create(&mut self, gas: u64, value: &U256, code: &[u8]) -> Result<(u64, Option<Address>), EvmError> { | ||||||
| 		// if balance is insufficient or we are to deep, return
 | 		// if balance is insufficient or we are to deep, return
 | ||||||
| 		if self.state.balance(&self.params.address) < *endowment && self.depth >= 1024 { | 		if self.state.balance(&self.params.address) < *value && self.depth >= 1024 { | ||||||
| 			return None | 			return Ok((gas, None)); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// create new contract address
 | 		// create new contract address
 | ||||||
| @ -369,28 +369,17 @@ impl<'a> Ext for Externalities<'a> { | |||||||
| 			origin: self.params.origin.clone(), | 			origin: self.params.origin.clone(), | ||||||
| 			gas: U256::from(gas), | 			gas: U256::from(gas), | ||||||
| 			gas_price: self.params.gas_price.clone(), | 			gas_price: self.params.gas_price.clone(), | ||||||
| 			value: endowment.clone(), | 			value: value.clone(), | ||||||
| 			code: code.to_vec(), | 			code: code.to_vec(), | ||||||
| 			data: vec![], | 			data: vec![], | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		let mut substate = Substate::new(); | 		let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); | ||||||
| 		{ | 		ex.state.inc_nonce(&self.params.address); | ||||||
| 			let mut ex = Executive::from_parent(self); | 		ex.create(¶ms, self.substate).map(|gas_left| (gas_left.low_u64(), Some(address))) | ||||||
| 			ex.state.inc_nonce(&address); |  | ||||||
| 			let res = ex.create(¶ms, &mut substate); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		self.substate.accrue(substate); |  | ||||||
| 		Some((gas, address)) |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn call(&mut self, gas: u64, call_gas: u64, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address, output: &mut [u8]) -> Option<u64> { | 	fn call(&mut self, gas: u64, call_gas: u64, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address, output: &mut [u8]) -> Result<u64, EvmError> { | ||||||
| 		// TODO: validation of the call
 |  | ||||||
| 		
 |  | ||||||
| 		println!("gas: {:?}", gas); |  | ||||||
| 		println!("call_gas: {:?}", call_gas); |  | ||||||
| 
 |  | ||||||
| 		let mut gas_cost = call_gas; | 		let mut gas_cost = call_gas; | ||||||
| 		let mut call_gas = call_gas; | 		let mut call_gas = call_gas; | ||||||
| 
 | 
 | ||||||
| @ -406,13 +395,15 @@ impl<'a> Ext for Externalities<'a> { | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if gas_cost > gas { | 		if gas_cost > gas { | ||||||
| 			return None; | 			return Err(EvmError::OutOfGas) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// if we are too deep, return
 | 		let mut gas = gas - gas_cost; | ||||||
| 		// TODO: replace with >= 1024
 | 
 | ||||||
| 		if self.depth == 1 { | 		//println!("depth: {:?}", self.depth);
 | ||||||
| 			return None; | 		// if balance is insufficient or we are to deep, return
 | ||||||
|  | 		if self.state.balance(&self.params.address) < *value && self.depth >= 1024 { | ||||||
|  | 			return Ok(gas + call_gas) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		let params = EvmParams { | 		let params = EvmParams { | ||||||
| @ -426,18 +417,8 @@ impl<'a> Ext for Externalities<'a> { | |||||||
| 			data: data.to_vec(), | 			data: data.to_vec(), | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		println!("params: {:?}", params); | 		let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); | ||||||
| 
 | 		ex.call(¶ms, self.substate, output).map(|gas_left| gas + gas_left.low_u64()) | ||||||
| 		let mut substate = Substate::new(); |  | ||||||
| 		{ |  | ||||||
| 			let mut ex = Executive::from_parent(self); |  | ||||||
| 			// TODO: take output into account
 |  | ||||||
| 			ex.call(¶ms, &mut substate, output); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		self.substate.accrue(substate); |  | ||||||
| 		// TODO: replace call_gas with what's actually left
 |  | ||||||
| 		Some(gas - gas_cost + call_gas) |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn extcode(&self, address: &Address) -> Vec<u8> { | 	fn extcode(&self, address: &Address) -> Vec<u8> { | ||||||
| @ -556,6 +537,7 @@ mod tests { | |||||||
| 		{ | 		{ | ||||||
| 			let mut ex = Executive::new(&mut state, &info, engine.deref()); | 			let mut ex = Executive::new(&mut state, &info, engine.deref()); | ||||||
| 			let _res = ex.create(¶ms, &mut substate); | 			let _res = ex.create(¶ms, &mut substate); | ||||||
|  | 			println!("res: {:?}", _res); | ||||||
| 		} | 		} | ||||||
| 		
 | 		
 | ||||||
| 		assert_eq!(state.storage_at(&address, &H256::new()), H256::from(next_address.clone())); | 		assert_eq!(state.storage_at(&address, &H256::new()), H256::from(next_address.clone())); | ||||||
| @ -584,7 +566,7 @@ mod tests { | |||||||
| 		// 60 01 - push 1
 | 		// 60 01 - push 1
 | ||||||
| 		// 55 - store
 | 		// 55 - store
 | ||||||
| 		let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); | 		let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); | ||||||
| 		let code = "600160005401600055600060006000600060003360e05a03f1600155".from_hex().unwrap(); | 		let code = "600160005401600055600060006000600060003060e05a03f1600155".from_hex().unwrap(); | ||||||
| 		let address = contract_address(&sender, &U256::zero()); | 		let address = contract_address(&sender, &U256::zero()); | ||||||
| 		let mut params = EvmParams::new(); | 		let mut params = EvmParams::new(); | ||||||
| 		params.address = address.clone(); | 		params.address = address.clone(); | ||||||
| @ -603,6 +585,7 @@ mod tests { | |||||||
| 		{ | 		{ | ||||||
| 			let mut ex = Executive::new(&mut state, &info, engine.deref()); | 			let mut ex = Executive::new(&mut state, &info, engine.deref()); | ||||||
| 			let _res = ex.call(¶ms, &mut substate, &mut []); | 			let _res = ex.call(¶ms, &mut substate, &mut []); | ||||||
|  | 			println!("res: {:?}", _res); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		assert!(false); | 		assert!(false); | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ use util::hash::*; | |||||||
| use util::uint::*; | use util::uint::*; | ||||||
| use util::bytes::*; | use util::bytes::*; | ||||||
| use evm_schedule::*; | use evm_schedule::*; | ||||||
|  | use evm::EvmError; | ||||||
| 
 | 
 | ||||||
| pub trait Ext { | pub trait Ext { | ||||||
| 	/// Returns a value for given key.
 | 	/// Returns a value for given key.
 | ||||||
| @ -19,15 +20,24 @@ pub trait Ext { | |||||||
| 	fn blockhash(&self, number: &U256) -> H256; | 	fn blockhash(&self, number: &U256) -> H256; | ||||||
| 
 | 
 | ||||||
| 	/// Creates new contract.
 | 	/// Creates new contract.
 | ||||||
| 	/// If contract creation is successfull, 
 | 	/// 
 | ||||||
| 	/// return gas_left and contract address,
 | 	/// If contract creation is successfull, return gas_left and contract address,
 | ||||||
| 	/// otherwise `None`.
 | 	/// If depth is too big or transfer value exceeds balance, return None
 | ||||||
| 	fn create(&mut self, gas: u64, endowment: &U256, code: &[u8]) -> Option<(u64, Address)>; | 	/// Otherwise return appropriate `EvmError`.
 | ||||||
|  | 	fn create(&mut self, gas: u64, value: &U256, code: &[u8]) -> Result<(u64, Option<Address>), EvmError>; | ||||||
| 
 | 
 | ||||||
| 	/// Message call.
 | 	/// Message call.
 | ||||||
|  | 	/// 
 | ||||||
| 	/// If call is successfull, returns gas left.
 | 	/// If call is successfull, returns gas left.
 | ||||||
| 	/// otherwise `None`.
 | 	/// otherwise `EvmError`.
 | ||||||
| 	fn call(&mut self, gas: u64, call_gas: u64, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address, output: &mut [u8]) -> Option<u64>; | 	fn call(&mut self, 
 | ||||||
|  | 			gas: u64, 
 | ||||||
|  | 			call_gas: u64, 
 | ||||||
|  | 			receive_address: &Address, 
 | ||||||
|  | 			value: &U256, 
 | ||||||
|  | 			data: &[u8], 
 | ||||||
|  | 			code_address: &Address, 
 | ||||||
|  | 			output: &mut [u8]) -> Result<u64, EvmError>; | ||||||
| 
 | 
 | ||||||
| 	/// Returns code at given address
 | 	/// Returns code at given address
 | ||||||
| 	fn extcode(&self, address: &Address) -> Vec<u8>; | 	fn extcode(&self, address: &Address) -> Vec<u8>; | ||||||
|  | |||||||
| @ -160,13 +160,15 @@ impl IntoJit<evmjit::RuntimeDataHandle> for RuntimeData { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct ExtAdapter<'a> { | struct ExtAdapter<'a> { | ||||||
| 	ext: &'a mut evm::Ext | 	ext: &'a mut evm::Ext, | ||||||
|  | 	err: &'a mut Option<evm::EvmError> | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'a> ExtAdapter<'a> { | impl<'a> ExtAdapter<'a> { | ||||||
| 	fn new(ext: &'a mut evm::Ext) -> Self { | 	fn new(ext: &'a mut evm::Ext, err: &'a mut Option<evm::EvmError>) -> Self { | ||||||
| 		ExtAdapter { | 		ExtAdapter { | ||||||
| 			ext: ext | 			ext: ext, | ||||||
|  | 			err: err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -210,12 +212,21 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> { | |||||||
| 			  address: *mut evmjit::H256) { | 			  address: *mut evmjit::H256) { | ||||||
| 		unsafe { | 		unsafe { | ||||||
| 			match self.ext.create(*io_gas, &U256::from_jit(&*endowment), slice::from_raw_parts(init_beg, init_size as usize)) { | 			match self.ext.create(*io_gas, &U256::from_jit(&*endowment), slice::from_raw_parts(init_beg, init_size as usize)) { | ||||||
| 				Some((gas_left, addr)) => { | 				Ok((gas_left, opt)) => { | ||||||
| 					*io_gas = gas_left; | 					*io_gas = gas_left; | ||||||
| 					*address = addr.into_jit(); | 					if let Some(addr) = opt { | ||||||
|  | 						*address = addr.into_jit(); | ||||||
|  | 					} | ||||||
| 				}, | 				}, | ||||||
| 				None => () | 				Err(err @ evm::EvmError::OutOfGas) => { | ||||||
| 			}; | 					*self.err = Some(err); | ||||||
|  | 					// hack to propagate `OutOfGas` to evmjit and stop
 | ||||||
|  | 					// the execution immediately.
 | ||||||
|  | 					// Works, cause evmjit uses i64, not u64
 | ||||||
|  | 					*io_gas = -1i64 as u64 | ||||||
|  | 				}, | ||||||
|  | 				Err(err) => *self.err = Some(err) | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -230,7 +241,7 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> { | |||||||
| 				out_size: u64, | 				out_size: u64, | ||||||
| 				code_address: *const evmjit::H256) -> bool { | 				code_address: *const evmjit::H256) -> bool { | ||||||
| 		unsafe { | 		unsafe { | ||||||
| 			let opt = self.ext.call(*io_gas, 
 | 			let res = self.ext.call(*io_gas, 
 | ||||||
| 									call_gas, 
 | 									call_gas, 
 | ||||||
| 									&Address::from_jit(&*receive_address), | 									&Address::from_jit(&*receive_address), | ||||||
| 									&U256::from_jit(&*value), | 									&U256::from_jit(&*value), | ||||||
| @ -238,11 +249,22 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> { | |||||||
| 									&Address::from_jit(&*code_address), | 									&Address::from_jit(&*code_address), | ||||||
| 									slice::from_raw_parts_mut(out_beg, out_size as usize)); | 									slice::from_raw_parts_mut(out_beg, out_size as usize)); | ||||||
| 
 | 
 | ||||||
| 			match opt { | 			match res { | ||||||
| 				None => false, | 				Ok(gas_left) => { | ||||||
| 				Some(gas_left) => { |  | ||||||
| 					*io_gas = gas_left; | 					*io_gas = gas_left; | ||||||
| 					true | 					true | ||||||
|  | 				}, | ||||||
|  | 				Err(err @ evm::EvmError::OutOfGas) => { | ||||||
|  | 					*self.err = Some(err); | ||||||
|  | 					// hack to propagate `OutOfGas` to evmjit and stop
 | ||||||
|  | 					// the execution immediately.
 | ||||||
|  | 					// Works, cause evmjit uses i64, not u64
 | ||||||
|  | 					*io_gas = -1i64 as u64; | ||||||
|  | 					false | ||||||
|  | 				}, | ||||||
|  | 				Err(err) => { | ||||||
|  | 					*self.err = Some(err); | ||||||
|  | 					false | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -294,8 +316,9 @@ pub struct JitEvm; | |||||||
| 
 | 
 | ||||||
| impl evm::Evm for JitEvm { | impl evm::Evm for JitEvm { | ||||||
| 	fn exec(&self, params: &evm::EvmParams, ext: &mut evm::Ext) -> evm::EvmResult { | 	fn exec(&self, params: &evm::EvmParams, ext: &mut evm::Ext) -> evm::EvmResult { | ||||||
|  | 		let mut optional_err = None; | ||||||
| 		// Dirty hack. This is unsafe, but we interact with ffi, so it's justified.
 | 		// Dirty hack. This is unsafe, but we interact with ffi, so it's justified.
 | ||||||
| 		let ext_adapter: ExtAdapter<'static> = unsafe { ::std::mem::transmute(ExtAdapter::new(ext)) }; | 		let ext_adapter: ExtAdapter<'static> = unsafe { ::std::mem::transmute(ExtAdapter::new(ext, &mut optional_err)) }; | ||||||
| 		let mut ext_handle = evmjit::ExtHandle::new(ext_adapter); | 		let mut ext_handle = evmjit::ExtHandle::new(ext_adapter); | ||||||
| 		let mut data = RuntimeData::new(); | 		let mut data = RuntimeData::new(); | ||||||
| 		data.gas = params.gas; | 		data.gas = params.gas; | ||||||
| @ -315,7 +338,14 @@ impl evm::Evm for JitEvm { | |||||||
| 		data.timestamp = 0; | 		data.timestamp = 0; | ||||||
| 		
 | 		
 | ||||||
| 		let mut context = unsafe { evmjit::ContextHandle::new(data.into_jit(), &mut ext_handle) }; | 		let mut context = unsafe { evmjit::ContextHandle::new(data.into_jit(), &mut ext_handle) }; | ||||||
| 		match context.exec() { | 		let res = context.exec(); | ||||||
|  | 		
 | ||||||
|  | 		// check in adapter if execution of children contracts failed.
 | ||||||
|  | 		if let Some(err) = optional_err { | ||||||
|  | 			return Err(err); | ||||||
|  | 		} | ||||||
|  | 		
 | ||||||
|  | 		match res { | ||||||
| 			evmjit::ReturnCode::Stop => Ok(U256::from(context.gas_left())), | 			evmjit::ReturnCode::Stop => Ok(U256::from(context.gas_left())), | ||||||
| 			evmjit::ReturnCode::Return => match ext.ret(context.gas_left(), context.output_data()) { | 			evmjit::ReturnCode::Return => match ext.ret(context.gas_left(), context.output_data()) { | ||||||
| 				Some(gas_left) => Ok(U256::from(gas_left)), | 				Some(gas_left) => Ok(U256::from(gas_left)), | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user