Merge branch 'master' of github.com:gavofyork/ethcore into client
This commit is contained in:
		
						commit
						bda04702c7
					
				
							
								
								
									
										274
									
								
								src/executive.rs
									
									
									
									
									
								
							
							
						
						
									
										274
									
								
								src/executive.rs
									
									
									
									
									
								
							| @ -2,7 +2,9 @@ | ||||
| use common::*; | ||||
| use state::*; | ||||
| use engine::*; | ||||
| use evm::{self, Schedule, Factory, Ext}; | ||||
| use evm::{self, Factory, Ext}; | ||||
| use externalities::*; | ||||
| use substate::*; | ||||
| 
 | ||||
| /// Returns new address created from address and given nonce.
 | ||||
| pub fn contract_address(address: &Address, nonce: &U256) -> Address { | ||||
| @ -12,38 +14,6 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address { | ||||
| 	From::from(stream.out().sha3()) | ||||
| } | ||||
| 
 | ||||
| /// State changes which should be applied in finalize,
 | ||||
| /// after transaction is fully executed.
 | ||||
| pub struct Substate { | ||||
| 	/// Any accounts that have suicided.
 | ||||
| 	suicides: HashSet<Address>, | ||||
| 	/// Any logs.
 | ||||
| 	logs: Vec<LogEntry>, | ||||
| 	/// Refund counter of SSTORE nonzero->zero.
 | ||||
| 	refunds_count: U256, | ||||
| 	/// Created contracts.
 | ||||
| 	contracts_created: Vec<Address> | ||||
| } | ||||
| 
 | ||||
| impl Substate { | ||||
| 	/// Creates new substate.
 | ||||
| 	pub fn new() -> Self { | ||||
| 		Substate { | ||||
| 			suicides: HashSet::new(), | ||||
| 			logs: vec![], | ||||
| 			refunds_count: U256::zero(), | ||||
| 			contracts_created: vec![] | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	pub fn accrue(&mut self, s: Substate) { | ||||
| 		self.suicides.extend(s.suicides.into_iter()); | ||||
| 		self.logs.extend(s.logs.into_iter()); | ||||
| 		self.refunds_count = self.refunds_count + s.refunds_count; | ||||
| 		self.contracts_created.extend(s.contracts_created.into_iter()); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /// Transaction execution receipt.
 | ||||
| #[derive(Debug)] | ||||
| pub struct Executed { | ||||
| @ -89,7 +59,7 @@ impl<'a> Executive<'a> { | ||||
| 	} | ||||
| 
 | ||||
| 	/// Populates executive from parent properties. Increments executive depth.
 | ||||
| 	fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self { | ||||
| 	pub fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self { | ||||
| 		Executive::new_with_depth(state, info, engine, depth + 1) | ||||
| 	} | ||||
| 
 | ||||
| @ -104,8 +74,13 @@ impl<'a> Executive<'a> { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/// Creates `Externalities` from `Executive`.
 | ||||
| 	pub fn to_externalities<'_>(&'_ mut self, params: &'_ ActionParams, substate: &'_ mut Substate, output: OutputPolicy<'_>) -> Externalities { | ||||
| 		Externalities::new(self.state, self.info, self.engine, self.depth, params, substate, output) | ||||
| 	} | ||||
| 
 | ||||
| 	/// This funtion should be used to execute transaction.
 | ||||
| 	pub fn transact(&mut self, t: &Transaction) -> Result<Executed, Error> { | ||||
| 	pub fn transact(&'a mut self, t: &Transaction) -> Result<Executed, Error> { | ||||
| 		let sender = try!(t.sender()); | ||||
| 		let nonce = self.state.nonce(&sender); | ||||
| 
 | ||||
| @ -215,7 +190,7 @@ impl<'a> Executive<'a> { | ||||
| 			let mut unconfirmed_substate = Substate::new(); | ||||
| 
 | ||||
| 			let res = { | ||||
| 				let mut ext = Externalities::from_executive(self, params, &mut unconfirmed_substate, OutputPolicy::Return(output)); | ||||
| 				let mut ext = self.to_externalities(params, &mut unconfirmed_substate, OutputPolicy::Return(output)); | ||||
| 				let evm = Factory::create(); | ||||
| 				evm.exec(¶ms, &mut ext) | ||||
| 			}; | ||||
| @ -230,7 +205,7 @@ impl<'a> Executive<'a> { | ||||
| 	/// Creates contract with given contract params.
 | ||||
| 	/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
 | ||||
| 	/// Modifies the substate.
 | ||||
| 	fn create(&mut self, params: &ActionParams, substate: &mut Substate) -> evm::Result { | ||||
| 	pub fn create(&mut self, params: &ActionParams, substate: &mut Substate) -> evm::Result { | ||||
| 		// backup used in case of running out of gas
 | ||||
| 		let backup = self.state.clone(); | ||||
| 
 | ||||
| @ -244,7 +219,7 @@ impl<'a> Executive<'a> { | ||||
| 		self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); | ||||
| 
 | ||||
| 		let res = { | ||||
| 			let mut ext = Externalities::from_executive(self, params, &mut unconfirmed_substate, OutputPolicy::InitContract); | ||||
| 			let mut ext = self.to_externalities(params, &mut unconfirmed_substate, OutputPolicy::InitContract); | ||||
| 			let evm = Factory::create(); | ||||
| 			evm.exec(¶ms, &mut ext) | ||||
| 		}; | ||||
| @ -319,228 +294,6 @@ impl<'a> Executive<'a> { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /// Policy for handling output data on `RETURN` opcode.
 | ||||
| pub enum OutputPolicy<'a> { | ||||
| 	/// Return reference to fixed sized output.
 | ||||
| 	/// Used for message calls.
 | ||||
| 	Return(BytesRef<'a>), | ||||
| 	/// Init new contract as soon as `RETURN` is called.
 | ||||
| 	InitContract | ||||
| } | ||||
| 
 | ||||
| /// Implementation of evm Externalities.
 | ||||
| pub struct Externalities<'a> { | ||||
| 	#[cfg(test)] | ||||
| 	pub state: &'a mut State, | ||||
| 	#[cfg(not(test))] | ||||
| 	state: &'a mut State, | ||||
| 	info: &'a EnvInfo, | ||||
| 	engine: &'a Engine, | ||||
| 	depth: usize, | ||||
| 	#[cfg(test)] | ||||
| 	pub params: &'a ActionParams, | ||||
| 	#[cfg(not(test))] | ||||
| 	params: &'a ActionParams, | ||||
| 	substate: &'a mut Substate, | ||||
| 	schedule: Schedule, | ||||
| 	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 ActionParams, 
 | ||||
| 			   substate: &'a mut Substate, 
 | ||||
| 			   output: OutputPolicy<'a>) -> Self { | ||||
| 		Externalities { | ||||
| 			state: state, | ||||
| 			info: info, | ||||
| 			engine: engine, | ||||
| 			depth: depth, | ||||
| 			params: params, | ||||
| 			substate: substate, | ||||
| 			schedule: engine.schedule(info), | ||||
| 			output: output | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/// Creates `Externalities` from `Executive`.
 | ||||
| 	fn from_executive(e: &'a mut Executive, params: &'a ActionParams, substate: &'a mut Substate, output: OutputPolicy<'a>) -> Self { | ||||
| 		Self::new(e.state, e.info, e.engine, e.depth, params, substate, output) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<'a> Ext for Externalities<'a> { | ||||
| 	fn sload(&self, key: &H256) -> H256 { | ||||
| 		self.state.storage_at(&self.params.address, key) | ||||
| 	} | ||||
| 
 | ||||
| 	fn sstore(&mut self, key: H256, value: H256) { | ||||
| 		// if SSTORE nonzero -> zero, increment refund count
 | ||||
| 		if value == H256::new() && self.state.storage_at(&self.params.address, &key) != H256::new() { | ||||
| 			self.substate.refunds_count = self.substate.refunds_count + U256::one(); | ||||
| 		} | ||||
| 		self.state.set_storage(&self.params.address, key, value) | ||||
| 	} | ||||
| 
 | ||||
| 	fn balance(&self, address: &Address) -> U256 { | ||||
| 		self.state.balance(address) | ||||
| 	} | ||||
| 
 | ||||
| 	fn blockhash(&self, number: &U256) -> H256 { | ||||
| 		match *number < U256::from(self.info.number) && number.low_u64() >= cmp::max(256, self.info.number) - 256 { | ||||
| 			true => { | ||||
| 				let index = self.info.number - number.low_u64() - 1; | ||||
| 				self.info.last_hashes[index as usize].clone() | ||||
| 			}, | ||||
| 			false => H256::from(&U256::zero()), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> (U256, Option<Address>) { | ||||
| 		// 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 (*gas, None); | ||||
| 		} | ||||
| 
 | ||||
| 		// create new contract address
 | ||||
| 		let address = contract_address(&self.params.address, &self.state.nonce(&self.params.address)); | ||||
| 
 | ||||
| 		// prepare the params
 | ||||
| 		let params = ActionParams { | ||||
| 			address: address.clone(), | ||||
| 			sender: self.params.address.clone(), | ||||
| 			origin: self.params.origin.clone(), | ||||
| 			gas: *gas, | ||||
| 			gas_price: self.params.gas_price.clone(), | ||||
| 			value: value.clone(), | ||||
| 			code: code.to_vec(), | ||||
| 			data: vec![], | ||||
| 		}; | ||||
| 
 | ||||
| 		let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); | ||||
| 		ex.state.inc_nonce(&self.params.address); | ||||
| 		match ex.create(¶ms, self.substate) { | ||||
| 			Ok(gas_left) => (gas_left, Some(address)), | ||||
| 			_ => (U256::zero(), None) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn call(&mut self, 
 | ||||
| 			gas: &U256, 
 | ||||
| 			call_gas: &U256, 
 | ||||
| 			receive_address: &Address, 
 | ||||
| 			value: &U256, 
 | ||||
| 			data: &[u8], 
 | ||||
| 			code_address: &Address, 
 | ||||
| 			output: &mut [u8]) -> Result<(U256, bool), evm::Error> { | ||||
| 		let mut gas_cost = *call_gas; | ||||
| 		let mut call_gas = *call_gas; | ||||
| 
 | ||||
| 		let is_call = receive_address == code_address; | ||||
| 		if is_call && !self.state.exists(&code_address) { | ||||
| 			gas_cost = gas_cost + U256::from(self.schedule.call_new_account_gas); | ||||
| 		} | ||||
| 
 | ||||
| 		if *value > U256::zero() { | ||||
| 			assert!(self.schedule.call_value_transfer_gas > self.schedule.call_stipend, "overflow possible"); | ||||
| 			gas_cost = gas_cost + U256::from(self.schedule.call_value_transfer_gas); | ||||
| 			call_gas = call_gas + U256::from(self.schedule.call_stipend); | ||||
| 		} | ||||
| 
 | ||||
| 		if gas_cost > *gas { | ||||
| 			return Err(evm::Error::OutOfGas); | ||||
| 		} | ||||
| 
 | ||||
| 		let gas = *gas - gas_cost; | ||||
| 
 | ||||
| 		// if balance is insufficient or we are too deep, return
 | ||||
| 		if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth { | ||||
| 			return Ok((gas + call_gas, true)); | ||||
| 		} | ||||
| 
 | ||||
| 		let params = ActionParams { | ||||
| 			address: receive_address.clone(), 
 | ||||
| 			sender: self.params.address.clone(), | ||||
| 			origin: self.params.origin.clone(), | ||||
| 			gas: call_gas, | ||||
| 			gas_price: self.params.gas_price.clone(), | ||||
| 			value: value.clone(), | ||||
| 			code: self.state.code(code_address).unwrap_or(vec![]), | ||||
| 			data: data.to_vec(), | ||||
| 		}; | ||||
| 
 | ||||
| 		let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); | ||||
| 		match ex.call(¶ms, self.substate, BytesRef::Fixed(output)) { | ||||
| 			Ok(gas_left) => Ok((gas + gas_left, true)), | ||||
| 			_ => Ok((gas, false)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn extcode(&self, address: &Address) -> Vec<u8> { | ||||
| 		self.state.code(address).unwrap_or(vec![]) | ||||
| 	} | ||||
| 
 | ||||
| 	fn ret(&mut self, gas: &U256, data: &[u8]) -> Result<U256, evm::Error> { | ||||
| 		match &mut self.output { | ||||
| 			&mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe { | ||||
| 				let len = cmp::min(slice.len(), data.len()); | ||||
| 				ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len); | ||||
| 				Ok(*gas) | ||||
| 			}, | ||||
| 			&mut OutputPolicy::Return(BytesRef::Flexible(ref mut vec)) => unsafe { | ||||
| 				vec.clear(); | ||||
| 				vec.reserve(data.len()); | ||||
| 				ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len()); | ||||
| 				vec.set_len(data.len()); | ||||
| 				Ok(*gas) | ||||
| 			}, | ||||
| 			&mut OutputPolicy::InitContract => { | ||||
| 				let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas); | ||||
| 				if return_cost > *gas { | ||||
| 					return match self.schedule.exceptional_failed_code_deposit { | ||||
| 						true => Err(evm::Error::OutOfGas), | ||||
| 						false => Ok(*gas) | ||||
| 					} | ||||
| 				} | ||||
| 				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); | ||||
| 				self.substate.contracts_created.push(address.clone()); | ||||
| 				Ok(*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, refund_address: &Address) { | ||||
| 		let address = self.params.address.clone(); | ||||
| 		let balance = self.balance(&address); | ||||
| 		self.state.transfer_balance(&address, refund_address, &balance); | ||||
| 		self.substate.suicides.insert(address); | ||||
| 	} | ||||
| 
 | ||||
| 	fn schedule(&self) -> &Schedule { | ||||
| 		&self.schedule | ||||
| 	} | ||||
| 
 | ||||
| 	fn env_info(&self) -> &EnvInfo { | ||||
| 		&self.info | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
| 	use super::*; | ||||
| @ -550,6 +303,7 @@ mod tests { | ||||
| 	use engine::*; | ||||
| 	use spec::*; | ||||
| 	use evm::Schedule; | ||||
| 	use substate::*; | ||||
| 
 | ||||
| 	struct TestEngine { | ||||
| 		spec: Spec, | ||||
|  | ||||
							
								
								
									
										228
									
								
								src/externalities.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								src/externalities.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,228 @@ | ||||
| //! Transaction Execution environment.
 | ||||
| use common::*; | ||||
| use state::*; | ||||
| use engine::*; | ||||
| use executive::*; | ||||
| use evm::{self, Schedule, Ext}; | ||||
| use substate::*; | ||||
| 
 | ||||
| /// Policy for handling output data on `RETURN` opcode.
 | ||||
| pub enum OutputPolicy<'a> { | ||||
| 	/// Return reference to fixed sized output.
 | ||||
| 	/// Used for message calls.
 | ||||
| 	Return(BytesRef<'a>), | ||||
| 	/// Init new contract as soon as `RETURN` is called.
 | ||||
| 	InitContract | ||||
| } | ||||
| 
 | ||||
| /// Implementation of evm Externalities.
 | ||||
| pub struct Externalities<'a> { | ||||
| 	
 | ||||
| 	#[cfg(test)] | ||||
| 	pub state: &'a mut State, | ||||
| 	#[cfg(not(test))] | ||||
| 	state: &'a mut State, | ||||
| 
 | ||||
| 	info: &'a EnvInfo, | ||||
| 	engine: &'a Engine, | ||||
| 	depth: usize, | ||||
| 	
 | ||||
| 	#[cfg(test)] | ||||
| 	pub params: &'a ActionParams, | ||||
| 	#[cfg(not(test))] | ||||
| 	params: &'a ActionParams, | ||||
| 	
 | ||||
| 	substate: &'a mut Substate, | ||||
| 	schedule: Schedule, | ||||
| 	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 ActionParams, 
 | ||||
| 			   substate: &'a mut Substate, 
 | ||||
| 			   output: OutputPolicy<'a>) -> Self { | ||||
| 		Externalities { | ||||
| 			state: state, | ||||
| 			info: info, | ||||
| 			engine: engine, | ||||
| 			depth: depth, | ||||
| 			params: params, | ||||
| 			substate: substate, | ||||
| 			schedule: engine.schedule(info), | ||||
| 			output: output | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<'a> Ext for Externalities<'a> { | ||||
| 	fn sload(&self, key: &H256) -> H256 { | ||||
| 		self.state.storage_at(&self.params.address, key) | ||||
| 	} | ||||
| 
 | ||||
| 	fn sstore(&mut self, key: H256, value: H256) { | ||||
| 		// if SSTORE nonzero -> zero, increment refund count
 | ||||
| 		if value == H256::new() && self.state.storage_at(&self.params.address, &key) != H256::new() { | ||||
| 			self.substate.refunds_count = self.substate.refunds_count + U256::one(); | ||||
| 		} | ||||
| 		self.state.set_storage(&self.params.address, key, value) | ||||
| 	} | ||||
| 
 | ||||
| 	fn balance(&self, address: &Address) -> U256 { | ||||
| 		self.state.balance(address) | ||||
| 	} | ||||
| 
 | ||||
| 	fn blockhash(&self, number: &U256) -> H256 { | ||||
| 		match *number < U256::from(self.info.number) && number.low_u64() >= cmp::max(256, self.info.number) - 256 { | ||||
| 			true => { | ||||
| 				let index = self.info.number - number.low_u64() - 1; | ||||
| 				self.info.last_hashes[index as usize].clone() | ||||
| 			}, | ||||
| 			false => H256::from(&U256::zero()), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> (U256, Option<Address>) { | ||||
| 		// 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 (*gas, None); | ||||
| 		} | ||||
| 
 | ||||
| 		// create new contract address
 | ||||
| 		let address = contract_address(&self.params.address, &self.state.nonce(&self.params.address)); | ||||
| 
 | ||||
| 		// prepare the params
 | ||||
| 		let params = ActionParams { | ||||
| 			address: address.clone(), | ||||
| 			sender: self.params.address.clone(), | ||||
| 			origin: self.params.origin.clone(), | ||||
| 			gas: *gas, | ||||
| 			gas_price: self.params.gas_price.clone(), | ||||
| 			value: value.clone(), | ||||
| 			code: code.to_vec(), | ||||
| 			data: vec![], | ||||
| 		}; | ||||
| 
 | ||||
| 		self.state.inc_nonce(&self.params.address); | ||||
| 		let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); | ||||
| 		match ex.create(¶ms, self.substate) { | ||||
| 			Ok(gas_left) => (gas_left, Some(address)), | ||||
| 			_ => (U256::zero(), None) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn call(&mut self, 
 | ||||
| 			gas: &U256, 
 | ||||
| 			call_gas: &U256, 
 | ||||
| 			receive_address: &Address, 
 | ||||
| 			value: &U256, 
 | ||||
| 			data: &[u8], 
 | ||||
| 			code_address: &Address, 
 | ||||
| 			output: &mut [u8]) -> Result<(U256, bool), evm::Error> { | ||||
| 		let mut gas_cost = *call_gas; | ||||
| 		let mut call_gas = *call_gas; | ||||
| 
 | ||||
| 		let is_call = receive_address == code_address; | ||||
| 		if is_call && !self.state.exists(&code_address) { | ||||
| 			gas_cost = gas_cost + U256::from(self.schedule.call_new_account_gas); | ||||
| 		} | ||||
| 
 | ||||
| 		if *value > U256::zero() { | ||||
| 			assert!(self.schedule.call_value_transfer_gas > self.schedule.call_stipend, "overflow possible"); | ||||
| 			gas_cost = gas_cost + U256::from(self.schedule.call_value_transfer_gas); | ||||
| 			call_gas = call_gas + U256::from(self.schedule.call_stipend); | ||||
| 		} | ||||
| 
 | ||||
| 		if gas_cost > *gas { | ||||
| 			return Err(evm::Error::OutOfGas); | ||||
| 		} | ||||
| 
 | ||||
| 		let gas = *gas - gas_cost; | ||||
| 
 | ||||
| 		// if balance is insufficient or we are too deep, return
 | ||||
| 		if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth { | ||||
| 			return Ok((gas + call_gas, true)); | ||||
| 		} | ||||
| 
 | ||||
| 		let params = ActionParams { | ||||
| 			address: receive_address.clone(), 
 | ||||
| 			sender: self.params.address.clone(), | ||||
| 			origin: self.params.origin.clone(), | ||||
| 			gas: call_gas, | ||||
| 			gas_price: self.params.gas_price.clone(), | ||||
| 			value: value.clone(), | ||||
| 			code: self.state.code(code_address).unwrap_or(vec![]), | ||||
| 			data: data.to_vec(), | ||||
| 		}; | ||||
| 
 | ||||
| 		let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); | ||||
| 		match ex.call(¶ms, self.substate, BytesRef::Fixed(output)) { | ||||
| 			Ok(gas_left) => Ok((gas + gas_left, true)), | ||||
| 			_ => Ok((gas, false)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn extcode(&self, address: &Address) -> Vec<u8> { | ||||
| 		self.state.code(address).unwrap_or(vec![]) | ||||
| 	} | ||||
| 
 | ||||
| 	fn ret(&mut self, gas: &U256, data: &[u8]) -> Result<U256, evm::Error> { | ||||
| 		match &mut self.output { | ||||
| 			&mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe { | ||||
| 				let len = cmp::min(slice.len(), data.len()); | ||||
| 				ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len); | ||||
| 				Ok(*gas) | ||||
| 			}, | ||||
| 			&mut OutputPolicy::Return(BytesRef::Flexible(ref mut vec)) => unsafe { | ||||
| 				vec.clear(); | ||||
| 				vec.reserve(data.len()); | ||||
| 				ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len()); | ||||
| 				vec.set_len(data.len()); | ||||
| 				Ok(*gas) | ||||
| 			}, | ||||
| 			&mut OutputPolicy::InitContract => { | ||||
| 				let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas); | ||||
| 				if return_cost > *gas { | ||||
| 					return match self.schedule.exceptional_failed_code_deposit { | ||||
| 						true => Err(evm::Error::OutOfGas), | ||||
| 						false => Ok(*gas) | ||||
| 					} | ||||
| 				} | ||||
| 				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); | ||||
| 				self.substate.contracts_created.push(address.clone()); | ||||
| 				Ok(*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, refund_address: &Address) { | ||||
| 		let address = self.params.address.clone(); | ||||
| 		let balance = self.balance(&address); | ||||
| 		self.state.transfer_balance(&address, refund_address, &balance); | ||||
| 		self.substate.suicides.insert(address); | ||||
| 	} | ||||
| 
 | ||||
| 	fn schedule(&self) -> &Schedule { | ||||
| 		&self.schedule | ||||
| 	} | ||||
| 
 | ||||
| 	fn env_info(&self) -> &EnvInfo { | ||||
| 		&self.info | ||||
| 	} | ||||
| } | ||||
| @ -89,7 +89,6 @@ extern crate ethcore_util as util; | ||||
| 
 | ||||
| pub mod common; | ||||
| pub mod basic_types; | ||||
| pub mod executive; | ||||
| pub mod error; | ||||
| pub mod log_entry; | ||||
| pub mod env_info; | ||||
| @ -110,8 +109,11 @@ pub mod spec; | ||||
| pub mod views; | ||||
| pub mod blockchain; | ||||
| pub mod extras; | ||||
| pub mod substate; | ||||
| pub mod evm; | ||||
| pub mod service; | ||||
| pub mod executive; | ||||
| pub mod externalities; | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests; | ||||
|  | ||||
							
								
								
									
										33
									
								
								src/substate.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/substate.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| use common::*; | ||||
| 
 | ||||
| /// State changes which should be applied in finalize,
 | ||||
| /// after transaction is fully executed.
 | ||||
| pub struct Substate { | ||||
| 	/// Any accounts that have suicided.
 | ||||
| 	pub suicides: HashSet<Address>, | ||||
| 	/// Any logs.
 | ||||
| 	pub logs: Vec<LogEntry>, | ||||
| 	/// Refund counter of SSTORE nonzero->zero.
 | ||||
| 	pub refunds_count: U256, | ||||
| 	/// Created contracts.
 | ||||
| 	pub contracts_created: Vec<Address> | ||||
| } | ||||
| 
 | ||||
| impl Substate { | ||||
| 	/// Creates new substate.
 | ||||
| 	pub fn new() -> Self { | ||||
| 		Substate { | ||||
| 			suicides: HashSet::new(), | ||||
| 			logs: vec![], | ||||
| 			refunds_count: U256::zero(), | ||||
| 			contracts_created: vec![] | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	pub fn accrue(&mut self, s: Substate) { | ||||
| 		self.suicides.extend(s.suicides.into_iter()); | ||||
| 		self.logs.extend(s.logs.into_iter()); | ||||
| 		self.refunds_count = self.refunds_count + s.refunds_count; | ||||
| 		self.contracts_created.extend(s.contracts_created.into_iter()); | ||||
| 	} | ||||
| } | ||||
| @ -6,6 +6,8 @@ use engine::*; | ||||
| use evm; | ||||
| use evm::{Schedule, Ext, Factory}; | ||||
| use ethereum; | ||||
| use externalities::*; | ||||
| use substate::*; | ||||
| 
 | ||||
| struct TestEngine { | ||||
| 	spec: Spec, | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user