ext call refactored
This commit is contained in:
		
							parent
							
								
									777ac4dc87
								
							
						
					
					
						commit
						6fb580f621
					
				| @ -6,6 +6,20 @@ use util::bytes::*; | ||||
| use evm::{Schedule, Error}; | ||||
| use env_info::*; | ||||
| 
 | ||||
| pub struct CallResult { | ||||
| 	pub gas_left: U256, | ||||
| 	pub success: bool | ||||
| } | ||||
| 
 | ||||
| impl CallResult { | ||||
| 	pub fn new(gas_left: U256, success: bool) -> Self { | ||||
| 		CallResult { | ||||
| 			gas_left: gas_left, | ||||
| 			success: success | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub trait Ext { | ||||
| 	/// Returns a value for given key.
 | ||||
| 	fn sload(&self, key: &H256) -> H256; | ||||
| @ -26,8 +40,9 @@ pub trait Ext { | ||||
| 
 | ||||
| 	/// Message call.
 | ||||
| 	/// 
 | ||||
| 	/// If call is successfull, returns gas left.
 | ||||
| 	/// otherwise `Error`.
 | ||||
| 	/// Returns None, if we run out of gas.
 | ||||
| 	/// Otherwise returns call_result which contains gas left 
 | ||||
| 	/// and true if subcall was successfull.
 | ||||
| 	fn call(&mut self, 
 | ||||
| 			gas: &U256, 
 | ||||
| 			call_gas: &U256, 
 | ||||
| @ -35,7 +50,7 @@ pub trait Ext { | ||||
| 			value: &U256, 
 | ||||
| 			data: &[u8], 
 | ||||
| 			code_address: &Address, 
 | ||||
| 			output: &mut [u8]) -> Result<U256, Error>; | ||||
| 			output: &mut [u8]) -> Option<CallResult>; | ||||
| 
 | ||||
| 	/// Returns code at given address
 | ||||
| 	fn extcode(&self, address: &Address) -> Vec<u8>; | ||||
|  | ||||
| @ -229,30 +229,21 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> { | ||||
| 				out_size: u64, | ||||
| 				code_address: *const evmjit::H256) -> bool { | ||||
| 		unsafe { | ||||
| 			let res = self.ext.call(&U256::from(*io_gas), 
 | ||||
| 			let opt = self.ext.call(&U256::from(*io_gas), 
 | ||||
| 									&U256::from(call_gas), 
 | ||||
| 									&Address::from_jit(&*receive_address), | ||||
| 									&U256::from_jit(&*value), | ||||
| 									slice::from_raw_parts(in_beg, in_size as usize), | ||||
| 									&Address::from_jit(&*code_address), | ||||
| 									slice::from_raw_parts_mut(out_beg, out_size as usize)); | ||||
| 
 | ||||
| 			match res { | ||||
| 				Ok(gas_left) => { | ||||
| 					*io_gas = gas_left.low_u64(); | ||||
| 					true | ||||
| 				}, | ||||
| 				Err(err @ evm::Error::OutOfGas) => { | ||||
| 					*self.err = Some(err); | ||||
| 					// hack to propagate `OutOfGas` to evmjit and stop
 | ||||
| 					// the execution immediately.
 | ||||
| 					// Works, cause evmjit uses i64, not u64
 | ||||
| 			match opt { | ||||
| 				None => { | ||||
| 					*io_gas = -1i64 as u64; | ||||
| 					false | ||||
| 				}, | ||||
| 				Err(err) => { | ||||
| 					*self.err = Some(err); | ||||
| 					false | ||||
| 				Some(res) => { | ||||
| 					*io_gas = res.gas_left.low_u64(); | ||||
| 					res.success | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @ -11,6 +11,6 @@ mod jit; | ||||
| mod tests; | ||||
| 
 | ||||
| pub use self::evm::{Evm, Error, Result}; | ||||
| pub use self::ext::Ext; | ||||
| pub use self::ext::{Ext, CallResult}; | ||||
| pub use self::factory::Factory; | ||||
| pub use self::schedule::Schedule; | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| use common::*; | ||||
| use evm; | ||||
| use evm::{Ext, Schedule, Factory}; | ||||
| use evm::{Ext, Schedule, Factory, CallResult}; | ||||
| 
 | ||||
| struct FakeLogEntry { | ||||
| 	topics: Vec<H256>, | ||||
| @ -53,7 +53,7 @@ impl Ext for FakeExt { | ||||
| 			_value: &U256, 
 | ||||
| 			_data: &[u8], 
 | ||||
| 			_code_address: &Address, 
 | ||||
| 			_output: &mut [u8]) -> result::Result<U256, evm::Error> { | ||||
| 			_output: &mut [u8]) -> Option<CallResult> { | ||||
| 		unimplemented!(); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| use common::*; | ||||
| use state::*; | ||||
| use engine::*; | ||||
| use evm::{self, Schedule, Factory, Ext}; | ||||
| use evm::{self, Schedule, Factory, Ext, CallResult}; | ||||
| 
 | ||||
| /// Returns new address created from address and given nonce.
 | ||||
| pub fn contract_address(address: &Address, nonce: &U256) -> Address { | ||||
| @ -38,6 +38,8 @@ impl Substate { | ||||
| 			contracts_created: vec![] | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	pub fn out_of_gas(&self) -> bool { self.out_of_gas } | ||||
| } | ||||
| 
 | ||||
| /// Transaction execution receipt.
 | ||||
| @ -207,7 +209,8 @@ impl<'a> Executive<'a> { | ||||
| 				let evm = Factory::create(); | ||||
| 				evm.exec(¶ms, &mut ext) | ||||
| 			}; | ||||
| 			self.handle_out_of_gas(res, substate, backup) | ||||
| 			self.revert_if_needed(&res, substate, backup); | ||||
| 			res | ||||
| 		} else { | ||||
| 			// otherwise, nothing
 | ||||
| 			Ok(params.gas) | ||||
| @ -232,7 +235,8 @@ impl<'a> Executive<'a> { | ||||
| 			let evm = Factory::create(); | ||||
| 			evm.exec(¶ms, &mut ext) | ||||
| 		}; | ||||
| 		self.handle_out_of_gas(res, substate, backup) | ||||
| 		self.revert_if_needed(&res, substate, backup); | ||||
| 		res | ||||
| 	} | ||||
| 
 | ||||
| 	/// Finalizes the transaction (does refunds and suicides).
 | ||||
| @ -278,12 +282,11 @@ impl<'a> Executive<'a> { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	pub fn handle_out_of_gas(&mut self, result: evm::Result, substate: &mut Substate, backup: State) -> evm::Result { | ||||
| 		if let &Err(evm::Error::OutOfGas) = &result { | ||||
| 	pub fn revert_if_needed(&mut self, result: &evm::Result, substate: &mut Substate, backup: State) { | ||||
| 		if let &Err(evm::Error::OutOfGas) = result { | ||||
| 			substate.out_of_gas = true; | ||||
| 			self.state.revert(backup); | ||||
| 		} | ||||
| 		result | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -398,7 +401,14 @@ impl<'a> Ext for Externalities<'a> { | ||||
| 		//ex.create(¶ms, self.substate).map(|gas_left| (gas_left, Some(address)))
 | ||||
| 	} | ||||
| 
 | ||||
| 	fn call(&mut self, gas: &U256, call_gas: &U256, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address, output: &mut [u8]) -> Result<U256, evm::Error> { | ||||
| 	fn call(&mut self, 
 | ||||
| 			gas: &U256, 
 | ||||
| 			call_gas: &U256, 
 | ||||
| 			receive_address: &Address, 
 | ||||
| 			value: &U256, 
 | ||||
| 			data: &[u8], 
 | ||||
| 			code_address: &Address, 
 | ||||
| 			output: &mut [u8]) -> Option<CallResult> { | ||||
| 		let mut gas_cost = *call_gas; | ||||
| 		let mut call_gas = *call_gas; | ||||
| 
 | ||||
| @ -414,14 +424,17 @@ impl<'a> Ext for Externalities<'a> { | ||||
| 		} | ||||
| 
 | ||||
| 		if gas_cost > *gas { | ||||
| 			return Err(evm::Error::OutOfGas) | ||||
| 			self.substate.out_of_gas = true; | ||||
| 			return None; | ||||
| 			//return (U256::from(-1i64 as u64), false);
 | ||||
| 		} | ||||
| 
 | ||||
| 		let gas = *gas - gas_cost; | ||||
| 
 | ||||
| 		// if balance is insufficient or we are to deep, return
 | ||||
| 		if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth { | ||||
| 			return Ok(gas + call_gas) | ||||
| 			return Some(CallResult::new(gas + call_gas, true)); | ||||
| 			//return (gas + call_gas, true);
 | ||||
| 		} | ||||
| 
 | ||||
| 		let params = ActionParams { | ||||
| @ -436,7 +449,14 @@ impl<'a> Ext for Externalities<'a> { | ||||
| 		}; | ||||
| 
 | ||||
| 		let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); | ||||
| 		ex.call(¶ms, self.substate, BytesRef::Fixed(output)).map(|gas_left| gas + gas_left) | ||||
| 		match ex.call(¶ms, self.substate, BytesRef::Fixed(output)) { | ||||
| 			Ok(gas_left) => Some(CallResult::new(gas + gas_left, true)), | ||||
| 			_ => { | ||||
| 				self.substate.out_of_gas = true; | ||||
| 				Some(CallResult::new(gas, false)) | ||||
| 			} | ||||
| 		} | ||||
| 		//ex.call(¶ms, self.substate, BytesRef::Fixed(output)).map(|gas_left| gas + gas_left)
 | ||||
| 	} | ||||
| 
 | ||||
| 	fn extcode(&self, address: &Address) -> Vec<u8> { | ||||
|  | ||||
| @ -4,7 +4,7 @@ use executive::*; | ||||
| use spec::*; | ||||
| use engine::*; | ||||
| use evm; | ||||
| use evm::{Schedule, Ext, Factory}; | ||||
| use evm::{Schedule, Ext, Factory, CallResult}; | ||||
| use ethereum; | ||||
| 
 | ||||
| struct TestEngine { | ||||
| @ -110,21 +110,20 @@ impl<'a> Ext for TestExt<'a> { | ||||
| 			value: &U256, 
 | ||||
| 			data: &[u8], 
 | ||||
| 			code_address: &Address, 
 | ||||
| 			output: &mut [u8]) -> Result<U256, evm::Error> { | ||||
| 		let res = self.ext.call(gas, call_gas, receive_address, value, data, code_address, output); | ||||
| 			output: &mut [u8]) -> Option<CallResult> { | ||||
| 		let opt = self.ext.call(gas, call_gas, receive_address, value, data, code_address, output); | ||||
| 		let ext = &self.ext; | ||||
| 		match res { | ||||
| 			Ok(gas_left) if ext.state.balance(&ext.params.address) >= *value => { | ||||
| 		if let &Some(_) = &opt { | ||||
| 			if ext.state.balance(&ext.params.address) >= *value { | ||||
| 				self.callcreates.push(CallCreate { | ||||
| 					data: data.to_vec(), | ||||
| 					destination: receive_address.clone(), | ||||
| 					_gas_limit: *call_gas, | ||||
| 					value: *value | ||||
| 				}); | ||||
| 				Ok(gas_left) | ||||
| 			}, | ||||
| 			other => other | ||||
| 			} | ||||
| 		} | ||||
| 		opt | ||||
| 	} | ||||
| 
 | ||||
| 	fn extcode(&self, address: &Address) -> Vec<u8> { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user