Merge branch 'master' into unlock
This commit is contained in:
		
						commit
						f5d0fa2c21
					
				| @ -104,7 +104,7 @@ impl EvmTestClient { | ||||
| 		let mut tracer = trace::NoopTracer; | ||||
| 		let mut output = vec![]; | ||||
| 		let mut executive = executive::Executive::new(&mut state, &info, &*self.spec.engine); | ||||
| 		let gas_left = executive.call( | ||||
| 		let (gas_left, _) = executive.call( | ||||
| 			params, | ||||
| 			&mut substate, | ||||
| 			util::BytesRef::Flexible(&mut output), | ||||
|  | ||||
| @ -97,10 +97,45 @@ impl fmt::Display for Error { | ||||
| /// A specialized version of Result over EVM errors.
 | ||||
| pub type Result<T> = ::std::result::Result<T, Error>; | ||||
| 
 | ||||
| 
 | ||||
| /// Return data buffer. Holds memory from a previous call and a slice into that memory.
 | ||||
| #[derive(Debug)] | ||||
| pub struct ReturnData { | ||||
| 	mem: Vec<u8>, | ||||
| 	offset: usize, | ||||
| 	size: usize, | ||||
| } | ||||
| 
 | ||||
| impl ::std::ops::Deref for ReturnData { | ||||
| 	type Target = [u8]; | ||||
| 	fn deref(&self) -> &[u8] { | ||||
| 		&self.mem[self.offset..self.offset + self.size] | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl ReturnData { | ||||
| 	/// Create empty `ReturnData`.
 | ||||
| 	pub fn empty() -> Self { | ||||
| 		ReturnData { | ||||
| 			mem: Vec::new(), | ||||
| 			offset: 0, | ||||
| 			size: 0, | ||||
| 		} | ||||
| 	} | ||||
| 	/// Create `ReturnData` from give buffer and slice.
 | ||||
| 	pub fn new(mem: Vec<u8>, offset: usize, size: usize) -> Self { | ||||
| 		ReturnData { | ||||
| 			mem: mem, | ||||
| 			offset: offset, | ||||
| 			size: size, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /// Gas Left: either it is a known value, or it needs to be computed by processing
 | ||||
| /// a return instruction.
 | ||||
| #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub enum GasLeft<'a> { | ||||
| #[derive(Debug)] | ||||
| pub enum GasLeft { | ||||
| 	/// Known gas left
 | ||||
| 	Known(U256), | ||||
| 	/// Return or Revert instruction must be processed.
 | ||||
| @ -108,7 +143,7 @@ pub enum GasLeft<'a> { | ||||
| 		/// Amount of gas left.
 | ||||
| 		gas_left: U256, | ||||
| 		/// Return data buffer.
 | ||||
| 		data: &'a [u8], | ||||
| 		data: ReturnData, | ||||
| 		/// Apply or revert state changes on revert.
 | ||||
| 		apply_state: bool | ||||
| 	}, | ||||
| @ -122,6 +157,8 @@ pub struct FinalizationResult { | ||||
| 	pub gas_left: U256, | ||||
| 	/// Apply execution state changes or revert them.
 | ||||
| 	pub apply_state: bool, | ||||
| 	/// Return data buffer.
 | ||||
| 	pub return_data: ReturnData, | ||||
| } | ||||
| 
 | ||||
| /// Types that can be "finalized" using an EVM.
 | ||||
| @ -133,13 +170,14 @@ pub trait Finalize { | ||||
| 	fn finalize<E: Ext>(self, ext: E) -> Result<FinalizationResult>; | ||||
| } | ||||
| 
 | ||||
| impl<'a> Finalize for Result<GasLeft<'a>> { | ||||
| impl Finalize for Result<GasLeft> { | ||||
| 	fn finalize<E: Ext>(self, ext: E) -> Result<FinalizationResult> { | ||||
| 		match self { | ||||
| 			Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { gas_left: gas_left, apply_state: true }), | ||||
| 			Ok(GasLeft::NeedsReturn {gas_left, data, apply_state}) => ext.ret(&gas_left, data).map(|gas_left| FinalizationResult { | ||||
| 			Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { gas_left: gas_left, apply_state: true, return_data: ReturnData::empty() }), | ||||
| 			Ok(GasLeft::NeedsReturn {gas_left, data, apply_state}) => ext.ret(&gas_left, &data).map(|gas_left| FinalizationResult { | ||||
| 				gas_left: gas_left, | ||||
| 				apply_state: apply_state, | ||||
| 				return_data: data, | ||||
| 			}), | ||||
| 			Err(err) => Err(err), | ||||
| 		} | ||||
|  | ||||
| @ -17,7 +17,7 @@ | ||||
| //! Interface for Evm externalities.
 | ||||
| 
 | ||||
| use util::*; | ||||
| use evm::{self, Schedule}; | ||||
| use evm::{self, Schedule, ReturnData}; | ||||
| use env_info::*; | ||||
| use types::executed::CallType; | ||||
| 
 | ||||
| @ -34,8 +34,8 @@ pub enum ContractCreateResult { | ||||
| /// Result of externalities call function.
 | ||||
| pub enum MessageCallResult { | ||||
| 	/// Returned when message call was successfull.
 | ||||
| 	/// Contains gas left.
 | ||||
| 	Success(U256), | ||||
| 	/// Contains gas left and output data.
 | ||||
| 	Success(U256, ReturnData), | ||||
| 	/// Returned when message call failed.
 | ||||
| 	/// VM doesn't have to know the reason.
 | ||||
| 	Failed | ||||
| @ -109,7 +109,7 @@ pub trait Ext { | ||||
| 
 | ||||
| 	/// Should be called when transaction calls `RETURN` opcode.
 | ||||
| 	/// Returns gas_left if cost of returning the data is not too high.
 | ||||
| 	fn ret(self, gas: &U256, data: &[u8]) -> evm::Result<U256> where Self: Sized; | ||||
| 	fn ret(self, gas: &U256, data: &ReturnData) -> evm::Result<U256>; | ||||
| 
 | ||||
| 	/// Should be called when contract commits suicide.
 | ||||
| 	/// Address to which funds should be refunded.
 | ||||
|  | ||||
| @ -178,6 +178,8 @@ lazy_static! { | ||||
| 		arr[ADDMOD as usize] =			InstructionInfo::new("ADDMOD",			0, 3, 1, false, GasPriceTier::Mid); | ||||
| 		arr[MULMOD as usize] =			InstructionInfo::new("MULMOD",			0, 3, 1, false, GasPriceTier::Mid); | ||||
| 		arr[SIGNEXTEND as usize] =		InstructionInfo::new("SIGNEXTEND",		0, 2, 1, false, GasPriceTier::Low); | ||||
| 		arr[RETURNDATASIZE as usize] =	InstructionInfo::new("RETURNDATASIZE",	0, 0, 1, false, GasPriceTier::Base); | ||||
| 		arr[RETURNDATACOPY as usize] =	InstructionInfo::new("RETURNDATACOPY",	0, 3, 0, true, GasPriceTier::VeryLow); | ||||
| 		arr[SHA3 as usize] =			InstructionInfo::new("SHA3",			0, 2, 1, false, GasPriceTier::Special); | ||||
| 		arr[ADDRESS as usize] = 		InstructionInfo::new("ADDRESS",			0, 0, 1, false, GasPriceTier::Base); | ||||
| 		arr[BALANCE as usize] = 		InstructionInfo::new("BALANCE",			0, 1, 1, false, GasPriceTier::Special); | ||||
| @ -369,6 +371,10 @@ pub const GASPRICE: Instruction = 0x3a; | ||||
| pub const EXTCODESIZE: Instruction = 0x3b; | ||||
| /// copy external code (from another contract)
 | ||||
| pub const EXTCODECOPY: Instruction = 0x3c; | ||||
| /// get the size of the return data buffer for the last call
 | ||||
| pub const RETURNDATASIZE: Instruction = 0x3d; | ||||
| /// copy return data buffer to memory
 | ||||
| pub const RETURNDATACOPY: Instruction = 0x3e; | ||||
| 
 | ||||
| /// get hash of most recent complete block
 | ||||
| pub const BLOCKHASH: Instruction = 0x40; | ||||
|  | ||||
| @ -173,7 +173,7 @@ impl<Gas: CostType> Gasometer<Gas> { | ||||
| 				let gas = Gas::from(schedule.sha3_gas) + (Gas::from(schedule.sha3_word_gas) * words); | ||||
| 				Request::GasMem(gas, mem_needed(stack.peek(0), stack.peek(1))?) | ||||
| 			}, | ||||
| 			instructions::CALLDATACOPY | instructions::CODECOPY => { | ||||
| 			instructions::CALLDATACOPY | instructions::CODECOPY | instructions::RETURNDATACOPY => { | ||||
| 				Request::GasMemCopy(default_gas, mem_needed(stack.peek(0), stack.peek(2))?, Gas::from_u256(*stack.peek(2))?) | ||||
| 			}, | ||||
| 			instructions::EXTCODECOPY => { | ||||
|  | ||||
| @ -15,6 +15,9 @@ | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| use util::U256; | ||||
| use evm::ReturnData; | ||||
| 
 | ||||
| const MAX_RETURN_WASTE_BYTES: usize = 16384; | ||||
| 
 | ||||
| pub trait Memory { | ||||
| 	/// Retrieve current size of the memory
 | ||||
| @ -36,6 +39,8 @@ pub trait Memory { | ||||
| 	/// Retrieve writeable part of memory
 | ||||
| 	fn writeable_slice(&mut self, offset: U256, size: U256) -> &mut[u8]; | ||||
| 	fn dump(&self); | ||||
| 	/// Convert memory into return data.
 | ||||
| 	fn into_return_data(self, offset: U256, size: U256) -> ReturnData; | ||||
| } | ||||
| 
 | ||||
| /// Checks whether offset and size is valid memory range
 | ||||
| @ -109,6 +114,21 @@ impl Memory for Vec<u8> { | ||||
| 			Memory::resize(self, size) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn into_return_data(mut self, offset: U256, size: U256) -> ReturnData { | ||||
| 		let mut offset = offset.low_u64() as usize; | ||||
| 		let size = size.low_u64() as usize; | ||||
| 		if !is_valid_range(offset, size) { | ||||
| 			return ReturnData::empty() | ||||
| 		} | ||||
| 		if self.len() - size > MAX_RETURN_WASTE_BYTES { | ||||
| 			{ let _ =  self.drain(..offset); } | ||||
| 			self.truncate(size); | ||||
| 			self.shrink_to_fit(); | ||||
| 			offset = 0; | ||||
| 		} | ||||
| 		ReturnData::new(self, offset, size) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| @ -164,4 +184,4 @@ mod tests { | ||||
| 			assert_eq!(mem.read_slice(U256::from(0), U256::from(7)), "a67890g".as_bytes()); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -32,7 +32,7 @@ use std::marker::PhantomData; | ||||
| use action_params::{ActionParams, ActionValue}; | ||||
| use types::executed::CallType; | ||||
| use evm::instructions::{self, Instruction, InstructionInfo}; | ||||
| use evm::{self, MessageCallResult, ContractCreateResult, GasLeft, CostType, CreateContractAddress}; | ||||
| use evm::{self, MessageCallResult, ContractCreateResult, GasLeft, CostType, CreateContractAddress, ReturnData}; | ||||
| use bit_set::BitSet; | ||||
| 
 | ||||
| use util::*; | ||||
| @ -102,6 +102,7 @@ enum InstructionResult<Gas> { | ||||
| pub struct Interpreter<Cost: CostType> { | ||||
| 	mem: Vec<u8>, | ||||
| 	cache: Arc<SharedCache>, | ||||
| 	return_data: ReturnData, | ||||
| 	_type: PhantomData<Cost>, | ||||
| } | ||||
| 
 | ||||
| @ -166,9 +167,10 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> { | ||||
| 				}, | ||||
| 				InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => { | ||||
| 					informant.done(); | ||||
| 					let mem = mem::replace(&mut self.mem, Vec::new()); | ||||
| 					return Ok(GasLeft::NeedsReturn { | ||||
| 						gas_left: gas.as_u256(), | ||||
| 						data: self.mem.read_slice(init_off, init_size), | ||||
| 						data: mem.into_return_data(init_off, init_size), | ||||
| 						apply_state: apply | ||||
| 					}); | ||||
| 				}, | ||||
| @ -187,6 +189,7 @@ impl<Cost: CostType> Interpreter<Cost> { | ||||
| 		Interpreter { | ||||
| 			mem: Vec::new(), | ||||
| 			cache: cache, | ||||
| 			return_data: ReturnData::empty(), | ||||
| 			_type: PhantomData::default(), | ||||
| 		} | ||||
| 	} | ||||
| @ -233,7 +236,7 @@ impl<Cost: CostType> Interpreter<Cost> { | ||||
| 		match instruction { | ||||
| 			instructions::MSTORE | instructions::MLOAD => Some((stack.peek(0).low_u64() as usize, 32)), | ||||
| 			instructions::MSTORE8 => Some((stack.peek(0).low_u64() as usize, 1)), | ||||
| 			instructions::CALLDATACOPY | instructions::CODECOPY => Some((stack.peek(0).low_u64() as usize, stack.peek(2).low_u64() as usize)), | ||||
| 			instructions::CALLDATACOPY | instructions::CODECOPY | instructions::RETURNDATACOPY => Some((stack.peek(0).low_u64() as usize, stack.peek(2).low_u64() as usize)), | ||||
| 			instructions::EXTCODECOPY => Some((stack.peek(1).low_u64() as usize, stack.peek(3).low_u64() as usize)), | ||||
| 			instructions::CALL | instructions::CALLCODE => Some((stack.peek(5).low_u64() as usize, stack.peek(6).low_u64() as usize)), | ||||
| 			instructions::DELEGATECALL => Some((stack.peek(4).low_u64() as usize, stack.peek(5).low_u64() as usize)), | ||||
| @ -362,8 +365,9 @@ impl<Cost: CostType> Interpreter<Cost> { | ||||
| 				}; | ||||
| 
 | ||||
| 				return match call_result { | ||||
| 					MessageCallResult::Success(gas_left) => { | ||||
| 					MessageCallResult::Success(gas_left, data) => { | ||||
| 						stack.push(U256::one()); | ||||
| 						self.return_data = data; | ||||
| 						Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater then current one"))) | ||||
| 					}, | ||||
| 					MessageCallResult::Failed  => { | ||||
| @ -495,21 +499,27 @@ impl<Cost: CostType> Interpreter<Cost> { | ||||
| 			instructions::CODESIZE => { | ||||
| 				stack.push(U256::from(code.len())); | ||||
| 			}, | ||||
| 			instructions::RETURNDATASIZE => { | ||||
| 				stack.push(U256::from(self.return_data.len())) | ||||
| 			}, | ||||
| 			instructions::EXTCODESIZE => { | ||||
| 				let address = u256_to_address(&stack.pop_back()); | ||||
| 				let len = ext.extcodesize(&address)?; | ||||
| 				stack.push(U256::from(len)); | ||||
| 			}, | ||||
| 			instructions::CALLDATACOPY => { | ||||
| 				self.copy_data_to_memory(stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8])); | ||||
| 				Self::copy_data_to_memory(&mut self.mem, stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8])); | ||||
| 			}, | ||||
| 			instructions::RETURNDATACOPY => { | ||||
| 				Self::copy_data_to_memory(&mut self.mem, stack, &*self.return_data); | ||||
| 			}, | ||||
| 			instructions::CODECOPY => { | ||||
| 				self.copy_data_to_memory(stack, params.code.as_ref().map_or_else(|| &[] as &[u8], |c| &**c as &[u8])); | ||||
| 				Self::copy_data_to_memory(&mut self.mem, stack, params.code.as_ref().map_or_else(|| &[] as &[u8], |c| &**c as &[u8])); | ||||
| 			}, | ||||
| 			instructions::EXTCODECOPY => { | ||||
| 				let address = u256_to_address(&stack.pop_back()); | ||||
| 				let code = ext.extcode(&address)?; | ||||
| 				self.copy_data_to_memory(stack, &code); | ||||
| 				Self::copy_data_to_memory(&mut self.mem, stack, &code); | ||||
| 			}, | ||||
| 			instructions::GASPRICE => { | ||||
| 				stack.push(params.gas_price.clone()); | ||||
| @ -541,7 +551,7 @@ impl<Cost: CostType> Interpreter<Cost> { | ||||
| 		Ok(InstructionResult::Ok) | ||||
| 	} | ||||
| 
 | ||||
| 	fn copy_data_to_memory(&mut self, stack: &mut Stack<U256>, source: &[u8]) { | ||||
| 	fn copy_data_to_memory(mem: &mut Vec<u8>, stack: &mut Stack<U256>, source: &[u8]) { | ||||
| 		let dest_offset = stack.pop_back(); | ||||
| 		let source_offset = stack.pop_back(); | ||||
| 		let size = stack.pop_back(); | ||||
| @ -550,9 +560,9 @@ impl<Cost: CostType> Interpreter<Cost> { | ||||
| 		let output_end = match source_offset > source_size || size > source_size || source_offset + size > source_size { | ||||
| 			true => { | ||||
| 				let zero_slice = if source_offset > source_size { | ||||
| 					self.mem.writeable_slice(dest_offset, size) | ||||
| 					mem.writeable_slice(dest_offset, size) | ||||
| 				} else { | ||||
| 					self.mem.writeable_slice(dest_offset + source_size - source_offset, source_offset + size - source_size) | ||||
| 					mem.writeable_slice(dest_offset + source_size - source_offset, source_offset + size - source_size) | ||||
| 				}; | ||||
| 				for i in zero_slice.iter_mut() { | ||||
| 					*i = 0; | ||||
| @ -564,7 +574,7 @@ impl<Cost: CostType> Interpreter<Cost> { | ||||
| 
 | ||||
| 		if source_offset < source_size { | ||||
| 			let output_begin = source_offset.low_u64() as usize; | ||||
| 			self.mem.write_slice(dest_offset, &source[output_begin..output_end]); | ||||
| 			mem.write_slice(dest_offset, &source[output_begin..output_end]); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -33,7 +33,7 @@ mod tests; | ||||
| #[cfg(all(feature="benches", test))] | ||||
| mod benches; | ||||
| 
 | ||||
| pub use self::evm::{Evm, Error, Finalize, FinalizationResult, GasLeft, Result, CostType}; | ||||
| pub use self::evm::{Evm, Error, Finalize, FinalizationResult, GasLeft, Result, CostType, ReturnData}; | ||||
| pub use self::ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress}; | ||||
| pub use self::vmtype::VMType; | ||||
| pub use self::factory::Factory; | ||||
|  | ||||
| @ -18,7 +18,7 @@ use util::*; | ||||
| use action_params::{ActionParams, ActionValue}; | ||||
| use env_info::EnvInfo; | ||||
| use types::executed::CallType; | ||||
| use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress}; | ||||
| use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData}; | ||||
| use std::fmt::Debug; | ||||
| use tests::helpers::*; | ||||
| use types::transaction::SYSTEM_ADDRESS; | ||||
| @ -149,7 +149,7 @@ impl Ext for FakeExt { | ||||
| 			data: data.to_vec(), | ||||
| 			code_address: Some(code_address.clone()) | ||||
| 		}); | ||||
| 		MessageCallResult::Success(*gas) | ||||
| 		MessageCallResult::Success(*gas, ReturnData::empty()) | ||||
| 	} | ||||
| 
 | ||||
| 	fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>> { | ||||
| @ -167,7 +167,7 @@ impl Ext for FakeExt { | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	fn ret(self, _gas: &U256, _data: &[u8]) -> evm::Result<U256> { | ||||
| 	fn ret(self, _gas: &U256, _data: &ReturnData) -> evm::Result<U256> { | ||||
| 		unimplemented!(); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -22,7 +22,7 @@ use engines::Engine; | ||||
| use types::executed::CallType; | ||||
| use env_info::EnvInfo; | ||||
| use error::ExecutionError; | ||||
| use evm::{self, Ext, Finalize, CreateContractAddress, FinalizationResult}; | ||||
| use evm::{self, Ext, Finalize, CreateContractAddress, FinalizationResult, ReturnData}; | ||||
| use externalities::*; | ||||
| use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer}; | ||||
| use transaction::{Action, SignedTransaction}; | ||||
| @ -194,7 +194,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { | ||||
| 
 | ||||
| 		let mut substate = Substate::new(); | ||||
| 
 | ||||
| 		let (gas_left, output) = match t.action { | ||||
| 		let (result, output) = match t.action { | ||||
| 			Action::Create => { | ||||
| 				let code_hash = t.data.sha3(); | ||||
| 				let new_address = contract_address(self.engine.create_address_scheme(self.info.number), &sender, &nonce, &code_hash); | ||||
| @ -233,7 +233,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { | ||||
| 		}; | ||||
| 
 | ||||
| 		// finalize here!
 | ||||
| 		Ok(self.finalize(t, substate, gas_left, output, tracer.traces(), vm_tracer.drain())?) | ||||
| 		Ok(self.finalize(t, substate, result, output, tracer.traces(), vm_tracer.drain())?) | ||||
| 	} | ||||
| 
 | ||||
| 	fn exec_vm<T, V>( | ||||
| @ -279,7 +279,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { | ||||
| 		mut output: BytesRef, | ||||
| 		tracer: &mut T, | ||||
| 		vm_tracer: &mut V | ||||
| 	) -> evm::Result<U256> where T: Tracer, V: VMTracer { | ||||
| 	) -> evm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer { | ||||
| 		// backup used in case of running out of gas
 | ||||
| 		self.state.checkpoint(); | ||||
| 
 | ||||
| @ -329,7 +329,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { | ||||
| 						); | ||||
| 					} | ||||
| 
 | ||||
| 					Ok(params.gas - cost) | ||||
| 					Ok((params.gas - cost, ReturnData::empty())) | ||||
| 				} | ||||
| 			} else { | ||||
| 				// just drain the whole gas
 | ||||
| @ -376,13 +376,13 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { | ||||
| 
 | ||||
| 				self.enact_result(&res, substate, unconfirmed_substate); | ||||
| 				trace!(target: "executive", "enacted: substate={:?}\n", substate); | ||||
| 				res.map(|r| r.gas_left) | ||||
| 				res.map(|r| (r.gas_left, r.return_data)) | ||||
| 			} else { | ||||
| 				// otherwise it's just a basic transaction, only do tracing, if necessary.
 | ||||
| 				self.state.discard_checkpoint(); | ||||
| 
 | ||||
| 				tracer.trace_call(trace_info, U256::zero(), trace_output, vec![]); | ||||
| 				Ok(params.gas) | ||||
| 				Ok((params.gas, ReturnData::empty())) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @ -396,7 +396,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { | ||||
| 		substate: &mut Substate, | ||||
| 		tracer: &mut T, | ||||
| 		vm_tracer: &mut V, | ||||
| 	) -> evm::Result<U256> where T: Tracer, V: VMTracer { | ||||
| 	) -> evm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer { | ||||
| 
 | ||||
| 		let scheme = self.engine.create_address_scheme(self.info.number); | ||||
| 		if scheme != CreateContractAddress::FromSenderAndNonce && self.state.exists_and_has_code(¶ms.address)? { | ||||
| @ -446,7 +446,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { | ||||
| 		}; | ||||
| 
 | ||||
| 		self.enact_result(&res, substate, unconfirmed_substate); | ||||
| 		res.map(|r| r.gas_left) | ||||
| 		res.map(|r| (r.gas_left, r.return_data)) | ||||
| 	} | ||||
| 
 | ||||
| 	/// Finalizes the transaction (does refunds and suicides).
 | ||||
| @ -454,7 +454,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { | ||||
| 		&mut self, | ||||
| 		t: &SignedTransaction, | ||||
| 		mut substate: Substate, | ||||
| 		result: evm::Result<U256>, | ||||
| 		result: evm::Result<(U256, ReturnData)>, | ||||
| 		output: Bytes, | ||||
| 		trace: Vec<FlatTrace>, | ||||
| 		vm_trace: Option<VMTrace> | ||||
| @ -468,7 +468,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { | ||||
| 		let refunds_bound = sstore_refunds + suicide_refunds; | ||||
| 
 | ||||
| 		// real ammount to refund
 | ||||
| 		let gas_left_prerefund = match result { Ok(x) => x, _ => 0.into() }; | ||||
| 		let gas_left_prerefund = match result { Ok((x, _)) => x, _ => 0.into() }; | ||||
| 		let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) >> 1); | ||||
| 		let gas_left = gas_left_prerefund + refunded; | ||||
| 
 | ||||
| @ -597,7 +597,7 @@ mod tests { | ||||
| 		let engine = TestEngine::new(0); | ||||
| 		let mut substate = Substate::new(); | ||||
| 
 | ||||
| 		let gas_left = { | ||||
| 		let (gas_left, _) = { | ||||
| 			let mut ex = Executive::new(&mut state, &info, &engine); | ||||
| 			ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() | ||||
| 		}; | ||||
| @ -655,7 +655,7 @@ mod tests { | ||||
| 		let engine = TestEngine::new(0); | ||||
| 		let mut substate = Substate::new(); | ||||
| 
 | ||||
| 		let gas_left = { | ||||
| 		let (gas_left, _) = { | ||||
| 			let mut ex = Executive::new(&mut state, &info, &engine); | ||||
| 			ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() | ||||
| 		}; | ||||
| @ -713,7 +713,7 @@ mod tests { | ||||
| 		let mut tracer = ExecutiveTracer::default(); | ||||
| 		let mut vm_tracer = ExecutiveVMTracer::toplevel(); | ||||
| 
 | ||||
| 		let gas_left = { | ||||
| 		let (gas_left, _) = { | ||||
| 			let mut ex = Executive::new(&mut state, &info, &engine); | ||||
| 			let output = BytesRef::Fixed(&mut[0u8;0]); | ||||
| 			ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap() | ||||
| @ -822,7 +822,7 @@ mod tests { | ||||
| 		let mut tracer = ExecutiveTracer::default(); | ||||
| 		let mut vm_tracer = ExecutiveVMTracer::toplevel(); | ||||
| 
 | ||||
| 		let gas_left = { | ||||
| 		let (gas_left, _) = { | ||||
| 			let mut ex = Executive::new(&mut state, &info, &engine); | ||||
| 			ex.create(params.clone(), &mut substate, &mut tracer, &mut vm_tracer).unwrap() | ||||
| 		}; | ||||
| @ -907,7 +907,7 @@ mod tests { | ||||
| 		let engine = TestEngine::new(0); | ||||
| 		let mut substate = Substate::new(); | ||||
| 
 | ||||
| 		let gas_left = { | ||||
| 		let (gas_left, _) = { | ||||
| 			let mut ex = Executive::new(&mut state, &info, &engine); | ||||
| 			ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() | ||||
| 		}; | ||||
| @ -1018,7 +1018,7 @@ mod tests { | ||||
| 		let engine = TestEngine::new(0); | ||||
| 		let mut substate = Substate::new(); | ||||
| 
 | ||||
| 		let gas_left = { | ||||
| 		let (gas_left, _) = { | ||||
| 			let mut ex = Executive::new(&mut state, &info, &engine); | ||||
| 			ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() | ||||
| 		}; | ||||
| @ -1062,7 +1062,7 @@ mod tests { | ||||
| 		let engine = TestEngine::new(0); | ||||
| 		let mut substate = Substate::new(); | ||||
| 
 | ||||
| 		let gas_left = { | ||||
| 		let (gas_left, _) = { | ||||
| 			let mut ex = Executive::new(&mut state, &info, &engine); | ||||
| 			ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() | ||||
| 		}; | ||||
| @ -1267,7 +1267,7 @@ mod tests { | ||||
| 		let mut substate = Substate::new(); | ||||
| 
 | ||||
| 		let mut output = [0u8; 14]; | ||||
| 		let result = { | ||||
| 		let (result, _) = { | ||||
| 			let mut ex = Executive::new(&mut state, &info, &engine); | ||||
| 			ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() | ||||
| 		}; | ||||
|  | ||||
| @ -21,7 +21,7 @@ use state::{Backend as StateBackend, State, Substate}; | ||||
| use engines::Engine; | ||||
| use env_info::EnvInfo; | ||||
| use executive::*; | ||||
| use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress}; | ||||
| use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData}; | ||||
| use types::executed::CallType; | ||||
| use types::transaction::UNSIGNED_SENDER; | ||||
| use trace::{Tracer, VMTracer}; | ||||
| @ -212,7 +212,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> | ||||
| 
 | ||||
| 		// TODO: handle internal error separately
 | ||||
| 		match ex.create(params, self.substate, self.tracer, self.vm_tracer) { | ||||
| 			Ok(gas_left) => { | ||||
| 			Ok((gas_left, _)) => { | ||||
| 				self.substate.contracts_created.push(address.clone()); | ||||
| 				ContractCreateResult::Created(address, gas_left) | ||||
| 			}, | ||||
| @ -261,7 +261,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> | ||||
| 		let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); | ||||
| 
 | ||||
| 		match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer, self.vm_tracer) { | ||||
| 			Ok(gas_left) => MessageCallResult::Success(gas_left), | ||||
| 			Ok((gas_left, return_data)) => MessageCallResult::Success(gas_left, return_data), | ||||
| 			_ => MessageCallResult::Failed | ||||
| 		} | ||||
| 	} | ||||
| @ -275,10 +275,10 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> | ||||
| 	} | ||||
| 
 | ||||
| 	#[cfg_attr(feature="dev", allow(match_ref_pats))] | ||||
| 	fn ret(mut self, gas: &U256, data: &[u8]) -> evm::Result<U256> | ||||
| 	fn ret(mut self, gas: &U256, data: &ReturnData) -> evm::Result<U256> | ||||
| 		where Self: Sized { | ||||
| 		let handle_copy = |to: &mut Option<&mut Bytes>| { | ||||
| 			to.as_mut().map(|b| **b = data.to_owned()); | ||||
| 			to.as_mut().map(|b| **b = data.to_vec()); | ||||
| 		}; | ||||
| 		match self.output { | ||||
| 			OutputPolicy::Return(BytesRef::Fixed(ref mut slice), ref mut copy) => { | ||||
| @ -292,7 +292,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> | ||||
| 				handle_copy(copy); | ||||
| 
 | ||||
| 				vec.clear(); | ||||
| 				vec.extend_from_slice(data); | ||||
| 				vec.extend_from_slice(&*data); | ||||
| 				Ok(*gas) | ||||
| 			}, | ||||
| 			OutputPolicy::InitContract(ref mut copy) => { | ||||
|  | ||||
| @ -21,7 +21,7 @@ use executive::*; | ||||
| use engines::Engine; | ||||
| use env_info::EnvInfo; | ||||
| use evm; | ||||
| use evm::{Schedule, Ext, Finalize, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress}; | ||||
| use evm::{Schedule, Ext, Finalize, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData}; | ||||
| use externalities::*; | ||||
| use types::executed::CallType; | ||||
| use tests::helpers::*; | ||||
| @ -142,7 +142,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E> | ||||
| 			gas_limit: *gas, | ||||
| 			value: value.unwrap() | ||||
| 		}); | ||||
| 		MessageCallResult::Success(*gas) | ||||
| 		MessageCallResult::Success(*gas, ReturnData::empty()) | ||||
| 	} | ||||
| 
 | ||||
| 	fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>>  { | ||||
| @ -157,7 +157,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E> | ||||
| 		self.ext.log(topics, data) | ||||
| 	} | ||||
| 
 | ||||
| 	fn ret(self, gas: &U256, data: &[u8]) -> Result<U256, evm::Error> { | ||||
| 	fn ret(self, gas: &U256, data: &ReturnData) -> Result<U256, evm::Error> { | ||||
| 		self.ext.ret(gas, data) | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -72,6 +72,8 @@ pub struct CommonParams { | ||||
| 	pub eip210_contract_code: Bytes, | ||||
| 	/// Gas allocated for EIP-210 blockhash update.
 | ||||
| 	pub eip210_contract_gas: U256, | ||||
| 	/// Number of first block where EIP-211 (Metropolis: RETURNDATASIZE/RETURNDATACOPY) rules begin.
 | ||||
| 	pub eip211_transition: BlockNumber, | ||||
| } | ||||
| 
 | ||||
| impl From<ethjson::spec::Params> for CommonParams { | ||||
| @ -94,6 +96,7 @@ impl From<ethjson::spec::Params> for CommonParams { | ||||
| 				|| DEFAULT_BLOCKHASH_CONTRACT.from_hex().expect("Default BLOCKHASH contract is valid"), | ||||
| 				Into::into), | ||||
| 			eip210_contract_gas: p.eip210_contract_gas.map_or(1000000.into(), Into::into), | ||||
| 			eip211_transition: p.eip211_transition.map_or(BlockNumber::max_value(), Into::into), | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -75,6 +75,9 @@ pub struct Params { | ||||
| 	/// See `CommonParams` docs.
 | ||||
| 	#[serde(rename="eip210ContractGas")] | ||||
| 	pub eip210_contract_gas: Option<Uint>, | ||||
| 	/// See `CommonParams` docs.
 | ||||
| 	#[serde(rename="eip211Transition")] | ||||
| 	pub eip211_transition: Option<Uint>, | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user