big refactor of executive in progress
This commit is contained in:
		
							parent
							
								
									b72da41ea7
								
							
						
					
					
						commit
						b273792ef0
					
				| @ -4,15 +4,26 @@ use util::uint::U256; | ||||
| use util::bytes::Bytes; | ||||
| use evm::{EvmParams, Ext}; | ||||
| 
 | ||||
| #[derive(Debug, Eq, PartialEq)] | ||||
| pub enum EvmResult { | ||||
| 	Stop { gas_left: U256 }, | ||||
| 	Return(Bytes), | ||||
| 	Suicide, | ||||
| /// Evm errors.
 | ||||
| pub enum EvmError { | ||||
| 	/// Returned when transaction execution run out of gas.
 | ||||
| 	/// The state should be reverted to the state from before the
 | ||||
| 	/// transaction execution. But it does not mean that transaction
 | ||||
| 	/// was invalid. Balance still should be transfered and nonce
 | ||||
| 	/// should be increased.
 | ||||
| 	OutOfGas, | ||||
| 	InternalError | ||||
| 	/// Returned on evm internal error. Should never be ignored during development.
 | ||||
| 	/// Likely to cause consensus issues.
 | ||||
| 	Internal, | ||||
| } | ||||
| 
 | ||||
| /// Evm result.
 | ||||
| /// 
 | ||||
| /// Returns gas_left if execution is successfull, otherwise error.
 | ||||
| pub type EvmResult = Result<U256, EvmError>; | ||||
| 
 | ||||
| /// Evm interface.
 | ||||
| pub trait Evm { | ||||
| 	/// This function should be used to execute transaction.
 | ||||
| 	fn exec(&self, params: &EvmParams, ext: &mut Ext) -> EvmResult; | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| use std::collections::HashSet; | ||||
| use std::cmp; | ||||
| use std::ptr; | ||||
| use util::hash::*; | ||||
| use util::uint::*; | ||||
| use util::rlp::*; | ||||
| @ -7,9 +8,10 @@ use util::sha3::*; | ||||
| use util::bytes::*; | ||||
| use state::*; | ||||
| use env_info::*; | ||||
| use evm_schedule::*; | ||||
| use engine::*; | ||||
| use transaction::*; | ||||
| use evm::{VmFactory, Ext, LogEntry, EvmParams, EvmResult}; | ||||
| use evm::{VmFactory, Ext, LogEntry, EvmParams, EvmResult, EvmError}; | ||||
| 
 | ||||
| /// Returns new address created from address and given nonce.
 | ||||
| pub fn contract_address(address: &Address, nonce: &U256) -> Address { | ||||
| @ -40,6 +42,7 @@ impl Substate { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: remove
 | ||||
| 	pub fn logs(&self) -> &[LogEntry] { | ||||
| 		&self.logs | ||||
| 	} | ||||
| @ -52,17 +55,59 @@ impl Substate { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /// Transaction execution result.
 | ||||
| pub struct Executed { | ||||
| 	/// Gas paid up front for execution of transaction.
 | ||||
| 	pub gas: U256, | ||||
| 	/// Gas used during execution of transaction.
 | ||||
| 	pub gas_used: U256, | ||||
| 	/// Gas refunded after the execution of transaction. 
 | ||||
| 	/// To get gas that was required up front, add `refunded` and `gas_used`.
 | ||||
| 	pub refunded: U256, | ||||
| 	/// Cumulative gas used in current block so far.
 | ||||
| 	/// 
 | ||||
| 	/// cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)
 | ||||
| 	///
 | ||||
| 	/// where `tn` is current transaction.
 | ||||
| 	pub cumulative_gas_used: U256, | ||||
| 	/// Transaction output.
 | ||||
| 	pub output: Bytes, | ||||
| 	/// Vector of logs generated by transaction.
 | ||||
| 	pub logs: Vec<LogEntry> | ||||
| } | ||||
| 
 | ||||
| impl Executed { | ||||
| 	fn new() -> Executed { | ||||
| 		Executed { | ||||
| 			gas: U256::zero(), | ||||
| 			gas_used: U256::zero(), | ||||
| 			refunded: U256::zero(), | ||||
| 			cumulative_gas_used: U256::zero(), | ||||
| 			output: vec![], | ||||
| 			logs: vec![] | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /// Result of executing the transaction.
 | ||||
| #[derive(PartialEq, Debug)] | ||||
| pub enum ExecutiveResult { | ||||
| 	Ok, | ||||
| pub enum ExecutionError { | ||||
| 	/// Returned when block (gas_used + gas) > gas_limit.
 | ||||
| 	/// 
 | ||||
| 	/// If gas =< gas_limit, upstream may try to execute the transaction
 | ||||
| 	/// in next block.
 | ||||
| 	BlockGasLimitReached { gas_limit: U256, gas_used: U256, gas: U256 }, | ||||
| 	/// Returned when transaction nonce does not match state nonce.
 | ||||
| 	InvalidNonce { expected: U256, is: U256 }, | ||||
| 	/// Returned when cost of transaction (value + gas_price * gas) exceeds 
 | ||||
| 	/// current sender balance.
 | ||||
| 	NotEnoughCash { required: U256, is: U256 }, | ||||
| 	OutOfGas, | ||||
| 	InternalError | ||||
| 	/// Returned when internal evm error occurs.
 | ||||
| 	Internal | ||||
| } | ||||
| 
 | ||||
| pub type ExecutionResult = Result<Executed, ExecutionError>; | ||||
| 
 | ||||
| /// Message-call/contract-creation executor; useful for executing transactions.
 | ||||
| pub struct Executive<'a> { | ||||
| 	state: &'a mut State, | ||||
| @ -94,22 +139,24 @@ impl<'a> Executive<'a> { | ||||
| 	} | ||||
| 
 | ||||
| 	/// This funtion should be used to execute transaction.
 | ||||
| 	pub fn transact(e: &mut Executive<'a>, t: &Transaction) -> ExecutiveResult { | ||||
| 		// validate if transaction fits into given block
 | ||||
| 		if e.info.gas_used + t.gas > e.info.gas_limit { | ||||
| 			return ExecutiveResult::BlockGasLimitReached { 
 | ||||
| 				gas_limit: e.info.gas_limit, 
 | ||||
| 				gas_used: e.info.gas_used, 
 | ||||
| 				gas: t.gas 
 | ||||
| 			}; | ||||
| 		} | ||||
| 	pub fn transact(e: &mut Executive<'a>, t: &Transaction) -> ExecutionResult { | ||||
| 		// TODO: validate transaction signature ?/ sender
 | ||||
| 
 | ||||
| 		let sender = t.sender(); | ||||
| 		let nonce = e.state.nonce(&sender); | ||||
| 
 | ||||
| 		// validate transaction nonce
 | ||||
| 		if t.nonce != nonce { | ||||
| 			return ExecutiveResult::InvalidNonce { expected: nonce, is: t.nonce }; | ||||
| 			return Err(ExecutionError::InvalidNonce { expected: nonce, is: t.nonce }); | ||||
| 		} | ||||
| 		
 | ||||
| 		// validate if transaction fits into given block
 | ||||
| 		if e.info.gas_used + t.gas > e.info.gas_limit { | ||||
| 			return Err(ExecutionError::BlockGasLimitReached { 
 | ||||
| 				gas_limit: e.info.gas_limit, 
 | ||||
| 				gas_used: e.info.gas_used, 
 | ||||
| 				gas: t.gas 
 | ||||
| 			}); | ||||
| 		} | ||||
| 
 | ||||
| 		// TODO: we might need bigints here, or at least check overflows.
 | ||||
| @ -119,9 +166,10 @@ impl<'a> Executive<'a> { | ||||
| 
 | ||||
| 		// avoid unaffordable transactions
 | ||||
| 		if balance < total_cost { | ||||
| 			return ExecutiveResult::NotEnoughCash { required: total_cost, is: balance }; | ||||
| 			return Err(ExecutionError::NotEnoughCash { required: total_cost, is: balance }); | ||||
| 		} | ||||
| 
 | ||||
| 		// NOTE: there can be no invalid transactions from this point.
 | ||||
| 		e.state.inc_nonce(&sender); | ||||
| 		let mut substate = Substate::new(); | ||||
| 
 | ||||
| @ -137,7 +185,7 @@ impl<'a> Executive<'a> { | ||||
| 					code: t.data.clone(), | ||||
| 					data: vec![], | ||||
| 				}; | ||||
| 				Executive::call(e, ¶ms, &mut substate) | ||||
| 				Executive::call(e, ¶ms, &mut substate, &mut []) | ||||
| 			}, | ||||
| 			TransactionKind::MessageCall => { | ||||
| 				let params = EvmParams { | ||||
| @ -156,78 +204,51 @@ impl<'a> Executive<'a> { | ||||
| 
 | ||||
| 		// finalize here!
 | ||||
| 		e.finalize(substate, &sender, U256::zero(), U256::zero(), t.gas_price); | ||||
| 		res | ||||
| 		//res
 | ||||
| 		Ok(Executed::new()) | ||||
| 	} | ||||
| 
 | ||||
| 	/// Calls contract function with given contract params.
 | ||||
| 	/// *Note. It does not finalize the transaction (doesn't do refunds, nor suicides).
 | ||||
| 	fn call(e: &mut Executive<'a>, params: &EvmParams, substate: &mut Substate) -> ExecutiveResult { | ||||
| 	/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
 | ||||
| 	/// Modifies the substate and the output.
 | ||||
| 	/// Returns either gas_left or `EvmError`.
 | ||||
| 	fn call(e: &mut Executive<'a>, params: &EvmParams, substate: &mut Substate, output: &mut [u8]) -> EvmResult { | ||||
| 		// at first, transfer value to destination
 | ||||
| 		e.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); | ||||
| 
 | ||||
| 		// if destination is builtin, try to execute it, or quickly return
 | ||||
| 		if e.engine.is_builtin(¶ms.address) { | ||||
| 			return match e.engine.cost_of_builtin(¶ms.address, ¶ms.data) > params.gas { | ||||
| 				true => ExecutiveResult::OutOfGas, | ||||
| 				false => { | ||||
| 					// TODO: substract gas for execution
 | ||||
| 					let mut out = vec![]; | ||||
| 					e.engine.execute_builtin(¶ms.address, ¶ms.data, &mut out); | ||||
| 					ExecutiveResult::Ok | ||||
| 			// if destination is builtin, try to execute it
 | ||||
| 			let cost = e.engine.cost_of_builtin(¶ms.address, ¶ms.data); | ||||
| 			match cost <= params.gas { | ||||
| 				true => { | ||||
| 					e.engine.execute_builtin(¶ms.address, ¶ms.data, output); | ||||
| 					Ok(params.gas - cost) | ||||
| 				}, | ||||
| 				false => Err(EvmError::OutOfGas) | ||||
| 			} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// otherwise do `normal` execution if destination is a contract
 | ||||
| 		// TODO: is executing contract with no code different from not executing contract at all?
 | ||||
| 		// if yes, there is a logic issue here. mk
 | ||||
| 		if params.code.len() > 0 { | ||||
| 			return match { | ||||
| 				let mut ext = Externalities::new(e.state, e.info, e.engine, e.depth, params, substate); | ||||
| 		} else if params.code.len() > 0 { | ||||
| 			// if destination is a contract, do normal message call
 | ||||
| 			let mut ext = Externalities::new(e.state, e.info, e.engine, e.depth, params, substate, OutputPolicy::Return(output)); | ||||
| 			let evm = VmFactory::create(); | ||||
| 			evm.exec(¶ms, &mut ext) | ||||
| 			} { | ||||
| 				EvmResult::Stop { gas_left } => ExecutiveResult::Ok, | ||||
| 				EvmResult::Return(_) => ExecutiveResult::Ok, | ||||
| 				EvmResult::Suicide => { | ||||
| 					substate.suicides.insert(params.address.clone()); | ||||
| 					ExecutiveResult::Ok | ||||
| 				}, | ||||
| 				EvmResult::OutOfGas => ExecutiveResult::OutOfGas, | ||||
| 				_err => ExecutiveResult::InternalError | ||||
| 		} else { | ||||
| 			// otherwise, nothing
 | ||||
| 			Ok(params.gas) | ||||
| 		} | ||||
| 	} | ||||
| 	
 | ||||
| 		ExecutiveResult::Ok | ||||
| 	} | ||||
| 	
 | ||||
| 	/// Creates contract with given contract params.
 | ||||
| 	/// *Note. It does not finalize the transaction (doesn't do refunds, nor suicides).
 | ||||
| 	fn create(e: &mut Executive<'a>, params: &EvmParams, substate: &mut Substate) -> ExecutiveResult { | ||||
| 	/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
 | ||||
| 	/// Modifies the substate.
 | ||||
| 	fn create(e: &mut Executive<'a>, params: &EvmParams, substate: &mut Substate) -> EvmResult { | ||||
| 		// at first create new contract
 | ||||
| 		e.state.new_contract(¶ms.address); | ||||
| 		// then transfer value to it
 | ||||
| 		e.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); | ||||
| 
 | ||||
| 		match { | ||||
| 			let mut ext = Externalities::new(e.state, e.info, e.engine, e.depth, params, substate); | ||||
| 		let mut ext = Externalities::new(e.state, e.info, e.engine, e.depth, params, substate, OutputPolicy::InitContract); | ||||
| 		let evm = VmFactory::create(); | ||||
| 		evm.exec(¶ms, &mut ext) | ||||
| 		} { | ||||
| 			EvmResult::Stop { gas_left } => { | ||||
| 				ExecutiveResult::Ok | ||||
| 			}, | ||||
| 			EvmResult::Return(output) => { | ||||
| 				e.state.init_code(¶ms.address, output); | ||||
| 				ExecutiveResult::Ok | ||||
| 			}, | ||||
| 			EvmResult::Suicide => { | ||||
| 				substate.suicides.insert(params.address.clone()); | ||||
| 				ExecutiveResult::Ok | ||||
| 			}, | ||||
| 			EvmResult::OutOfGas => ExecutiveResult::OutOfGas, | ||||
| 			_err => ExecutiveResult::InternalError | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/// Finalizes the transaction (does refunds and suicides).
 | ||||
| @ -256,6 +277,19 @@ impl<'a> Executive<'a> { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub enum ExtMode { | ||||
| 	Call, | ||||
| 	Create | ||||
| } | ||||
| 
 | ||||
| /// Wrapper structure for evm return data to avoid unnecessary copying.
 | ||||
| pub enum OutputPolicy<'a> { | ||||
| 	/// Reference to fixed sized output of a message call.
 | ||||
| 	Return(&'a mut [u8]), | ||||
| 	/// Use it, if you want return code to initialize contract.
 | ||||
| 	InitContract | ||||
| } | ||||
| 
 | ||||
| /// Implementation of evm Externalities.
 | ||||
| pub struct Externalities<'a> { | ||||
| 	state: &'a mut State, | ||||
| @ -263,19 +297,29 @@ pub struct Externalities<'a> { | ||||
| 	engine: &'a Engine, | ||||
| 	depth: usize, | ||||
| 	params: &'a EvmParams, | ||||
| 	substate: &'a mut Substate | ||||
| 	substate: &'a mut Substate, | ||||
| 	schedule: EvmSchedule, | ||||
| 	output: OutputPolicy<'a> | ||||
| } | ||||
| 
 | ||||
| impl<'a> Externalities<'a> { | ||||
| 	/// Basic `Externalities` constructor.
 | ||||
| 	pub fn new(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize, params: &'a EvmParams, substate: &'a mut Substate) -> Self { | ||||
| 	pub fn new(state: &'a mut State, 
 | ||||
| 			   info: &'a EnvInfo, 
 | ||||
| 			   engine: &'a Engine, 
 | ||||
| 			   depth: usize, 
 | ||||
| 			   params: &'a EvmParams, 
 | ||||
| 			   substate: &'a mut Substate, 
 | ||||
| 			   output: OutputPolicy<'a>) -> Self { | ||||
| 		Externalities { | ||||
| 			state: state, | ||||
| 			info: info, | ||||
| 			engine: engine, | ||||
| 			depth: depth, | ||||
| 			params: params, | ||||
| 			substate: substate | ||||
| 			substate: substate, | ||||
| 			schedule: engine.evm_schedule(info), | ||||
| 			output: output | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -345,19 +389,18 @@ impl<'a> Ext for Externalities<'a> { | ||||
| 		println!("gas: {:?}", gas); | ||||
| 		println!("call_gas: {:?}", call_gas); | ||||
| 
 | ||||
| 		let schedule = self.engine.evm_schedule(self.info); | ||||
| 		let mut gas_cost = call_gas; | ||||
| 		let mut call_gas = call_gas; | ||||
| 
 | ||||
| 		let is_call = receive_address == code_address; | ||||
| 		if is_call && self.state.code(&code_address).is_none() { | ||||
| 			gas_cost = gas_cost + schedule.call_new_account_gas as u64; | ||||
| 			gas_cost = gas_cost + self.schedule.call_new_account_gas as u64; | ||||
| 		} | ||||
| 
 | ||||
| 		if *value > U256::zero() { | ||||
| 			assert!(schedule.call_value_transfer_gas > schedule.call_stipend, "overflow possible"); | ||||
| 			gas_cost = gas_cost + schedule.call_value_transfer_gas as u64; | ||||
| 			call_gas = call_gas + schedule.call_stipend as u64; | ||||
| 			assert!(self.schedule.call_value_transfer_gas > self.schedule.call_stipend, "overflow possible"); | ||||
| 			gas_cost = gas_cost + self.schedule.call_value_transfer_gas as u64; | ||||
| 			call_gas = call_gas + self.schedule.call_stipend as u64; | ||||
| 		} | ||||
| 
 | ||||
| 		if gas_cost > gas { | ||||
| @ -387,9 +430,11 @@ impl<'a> Ext for Externalities<'a> { | ||||
| 		let mut substate = Substate::new(); | ||||
| 		{ | ||||
| 			let mut ex = Executive::from_parent(self); | ||||
| 			Executive::call(&mut ex, ¶ms, &mut substate); | ||||
| 			// TODO: take output into account
 | ||||
| 			Executive::call(&mut ex, ¶ms, &mut substate, &mut []); | ||||
| 		} | ||||
| 
 | ||||
| 		self.substate.accrue(substate); | ||||
| 		// TODO: replace call_gas with what's actually left
 | ||||
| 		Some((vec![], gas - gas_cost + call_gas)) | ||||
| 	} | ||||
| @ -398,10 +443,44 @@ impl<'a> Ext for Externalities<'a> { | ||||
| 		self.state.code(address).unwrap_or(vec![]) | ||||
| 	} | ||||
| 
 | ||||
| 	fn ret(&mut self, gas: u64, data: &[u8]) -> Option<u64> { | ||||
| 		match &mut self.output { | ||||
| 			&mut OutputPolicy::Return(ref mut slice) => unsafe { | ||||
| 				let len = cmp::min(slice.len(), data.len()); | ||||
| 				ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len); | ||||
| 				Some(gas) | ||||
| 			}, | ||||
| 			&mut OutputPolicy::InitContract => { | ||||
| 				let return_cost = data.len() as u64 * self.schedule.create_data_gas as u64; | ||||
| 				if return_cost > gas { | ||||
| 					return None; | ||||
| 				} | ||||
| 				let mut code = vec![]; | ||||
| 				code.reserve(data.len()); | ||||
| 				unsafe { | ||||
| 					ptr::copy(data.as_ptr(), code.as_mut_ptr(), data.len()); | ||||
| 					code.set_len(data.len()); | ||||
| 				} | ||||
| 				let address = &self.params.address; | ||||
| 				self.state.init_code(address, code); | ||||
| 				Some(gas - return_cost) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn log(&mut self, topics: Vec<H256>, data: Bytes) { | ||||
| 		let address = self.params.address.clone(); | ||||
| 		self.substate.logs.push(LogEntry::new(address, topics, data)); | ||||
| 	} | ||||
| 
 | ||||
| 	fn suicide(&mut self) { | ||||
| 		let address = self.params.address.clone(); | ||||
| 		self.substate.suicides.insert(address); | ||||
| 	} | ||||
| 
 | ||||
| 	fn schedule(&self) -> &EvmSchedule { | ||||
| 		&self.schedule | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| @ -462,7 +541,7 @@ mod tests { | ||||
| 
 | ||||
| 		{ | ||||
| 			let mut ex = Executive::new(&mut state, &info, &engine); | ||||
| 			assert_eq!(Executive::create(&mut ex, ¶ms, &mut substate), ExecutiveResult::Ok); | ||||
| 			assert_eq!(Executive::create(&mut ex, ¶ms, &mut substate), ExecutionResult::Ok); | ||||
| 		} | ||||
| 
 | ||||
| 		assert_eq!(state.storage_at(&address, &H256::new()), H256::from(&U256::from(0xf9u64))); | ||||
| @ -489,7 +568,7 @@ mod tests { | ||||
| 
 | ||||
| 		{ | ||||
| 			let mut ex = Executive::new(&mut state, &info, &engine); | ||||
| 			assert_eq!(Executive::create(&mut ex, ¶ms, &mut substate), ExecutiveResult::Ok); | ||||
| 			assert_eq!(Executive::create(&mut ex, ¶ms, &mut substate), ExecutionResult::Ok); | ||||
| 		} | ||||
| 		
 | ||||
| 		assert_eq!(state.storage_at(&address, &H256::new()), H256::from(next_address.clone())); | ||||
| @ -537,7 +616,7 @@ mod tests { | ||||
| 
 | ||||
| 		{ | ||||
| 			let mut ex = Executive::new(&mut state, &info, engine.deref()); | ||||
| 			assert_eq!(Executive::call(&mut ex, ¶ms, &mut substate), ExecutiveResult::Ok); | ||||
| 			assert_eq!(Executive::call(&mut ex, ¶ms, &mut substate), ExecutionResult::Ok); | ||||
| 		} | ||||
| 
 | ||||
| 		assert!(false); | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
| use util::hash::*; | ||||
| use util::uint::*; | ||||
| use util::bytes::*; | ||||
| use evm_schedule::*; | ||||
| 
 | ||||
| pub trait Ext { | ||||
| 	/// Returns a value for given key.
 | ||||
| @ -33,4 +34,14 @@ pub trait Ext { | ||||
| 
 | ||||
| 	/// Creates log entry with given topics and data
 | ||||
| 	fn log(&mut self, topics: Vec<H256>, data: Bytes); | ||||
| 
 | ||||
| 	/// Should be called when transaction calls `RETURN` opcode.
 | ||||
| 	/// Returns gas_left if cost of returning the data is not too high.
 | ||||
| 	fn ret(&mut self, gas: u64, data: &[u8]) -> Option<u64>; | ||||
| 
 | ||||
| 	/// Should be called when contract commits suicide.
 | ||||
| 	fn suicide(&mut self); | ||||
| 
 | ||||
| 	/// Returns schedule.
 | ||||
| 	fn schedule(&self) -> &EvmSchedule; | ||||
| } | ||||
|  | ||||
| @ -316,11 +316,21 @@ impl evm::Evm for JitEvm { | ||||
| 		
 | ||||
| 		let mut context = unsafe { evmjit::ContextHandle::new(data.into_jit(), &mut ext_handle) }; | ||||
| 		match context.exec() { | ||||
| 			evmjit::ReturnCode::Stop => evm::EvmResult::Stop { gas_left: U256::from(context.gas_left()) }, | ||||
| 			evmjit::ReturnCode::Return => evm::EvmResult::Return(context.output_data().to_vec()), | ||||
| 			evmjit::ReturnCode::Suicide => evm::EvmResult::Suicide, | ||||
| 			evmjit::ReturnCode::OutOfGas => evm::EvmResult::OutOfGas, | ||||
| 			_ => evm::EvmResult::InternalError | ||||
| 			evmjit::ReturnCode::Stop => Ok(evm::EvmOutput::new(U256::from(context.gas_left()), None)), | ||||
| 			evmjit::ReturnCode::Return => { | ||||
| 				if context.output_data().len() as u64 * ext.schedule().create_data_gas as u64 > context.gas_left() { | ||||
| 					return Err(evm::EvmError::OutOfGas); | ||||
| 				} | ||||
| 
 | ||||
| 				Ok(evm::EvmOutput::new(U256::from(context.gas_left()), Some(context.output_data().to_vec()))) | ||||
| 			}, | ||||
| 			evmjit::ReturnCode::Suicide => { 
 | ||||
| 				// what if there is a suicide and we run out of gas just after?
 | ||||
| 				ext.suicide(); | ||||
| 				Ok(evm::EvmOutput::new(U256::from(context.gas_left()), None)) | ||||
| 			}, | ||||
| 			evmjit::ReturnCode::OutOfGas => Err(evm::EvmError::OutOfGas), | ||||
| 			_err => Err(evm::EvmError::Internal) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -9,9 +9,9 @@ pub mod params; | ||||
| #[cfg(feature = "jit" )] | ||||
| mod jit; | ||||
| 
 | ||||
| pub use self::evm::{Evm, EvmResult}; | ||||
| pub use self::evm::{Evm, EvmError, EvmResult}; | ||||
| pub use self::ext::{Ext}; | ||||
| pub use self::logentry::LogEntry; | ||||
| pub use self::vmfactory::VmFactory; | ||||
| pub use self::executive::{Executive, ExecutiveResult, Externalities, Substate}; | ||||
| pub use self::executive::{Executive, ExecutionResult, Externalities, Substate}; | ||||
| pub use self::params::EvmParams; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user