Merge branch 'master' into ipc-doc-effort
This commit is contained in:
		
						commit
						dab16af018
					
				
							
								
								
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -22,6 +22,7 @@ dependencies = [
 | 
			
		||||
 "rpassword 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -29,7 +29,7 @@ ethminer = { path = "miner" }
 | 
			
		||||
ethcore-devtools = { path = "devtools" }
 | 
			
		||||
ethcore-rpc = { path = "rpc", optional = true }
 | 
			
		||||
ethcore-webapp = { path = "webapp", optional = true }
 | 
			
		||||
 | 
			
		||||
semver = "0.2"
 | 
			
		||||
 | 
			
		||||
[dependencies.hyper]
 | 
			
		||||
version = "0.8"
 | 
			
		||||
 | 
			
		||||
@ -113,12 +113,20 @@ impl<'a> Executive<'a> {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Creates `Externalities` from `Executive`.
 | 
			
		||||
	pub fn as_externalities<'_>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_, '_>) -> Externalities {
 | 
			
		||||
		Externalities::new(self.state, self.info, self.engine, self.depth, origin_info, substate, output)
 | 
			
		||||
	pub fn as_externalities<'_, T>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_, '_>, tracer: &'_ mut T) -> Externalities<'_, T> where T: Tracer {
 | 
			
		||||
		Externalities::new(self.state, self.info, self.engine, self.depth, origin_info, substate, output, tracer)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// This funtion should be used to execute transaction.
 | 
			
		||||
	pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result<Executed, Error> {
 | 
			
		||||
		let check = options.check_nonce;
 | 
			
		||||
		match options.tracing {
 | 
			
		||||
			true => self.transact_with_tracer(t, check, ExecutiveTracer::default()),
 | 
			
		||||
			false => self.transact_with_tracer(t, check, NoopTracer),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pub fn transact_with_tracer<T>(&'a mut self, t: &SignedTransaction, check_nonce: bool, mut tracer: T) -> Result<Executed, Error> where T: Tracer {
 | 
			
		||||
		let sender = try!(t.sender());
 | 
			
		||||
		let nonce = self.state.nonce(&sender);
 | 
			
		||||
 | 
			
		||||
@ -132,7 +140,7 @@ impl<'a> Executive<'a> {
 | 
			
		||||
		let init_gas = t.gas - base_gas_required;
 | 
			
		||||
 | 
			
		||||
		// validate transaction nonce
 | 
			
		||||
		if options.check_nonce {
 | 
			
		||||
		if check_nonce {
 | 
			
		||||
			if t.nonce != nonce {
 | 
			
		||||
				return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce }));
 | 
			
		||||
			}
 | 
			
		||||
@ -161,7 +169,7 @@ impl<'a> Executive<'a> {
 | 
			
		||||
		self.state.inc_nonce(&sender);
 | 
			
		||||
		self.state.sub_balance(&sender, &U256::from(gas_cost));
 | 
			
		||||
 | 
			
		||||
		let mut substate = Substate::new(options.tracing);
 | 
			
		||||
		let mut substate = Substate::new();
 | 
			
		||||
 | 
			
		||||
		let (gas_left, output) = match t.action {
 | 
			
		||||
			Action::Create => {
 | 
			
		||||
@ -177,7 +185,7 @@ impl<'a> Executive<'a> {
 | 
			
		||||
					code: Some(t.data.clone()),
 | 
			
		||||
					data: None,
 | 
			
		||||
				};
 | 
			
		||||
				(self.create(params, &mut substate), vec![])
 | 
			
		||||
				(self.create(params, &mut substate, &mut tracer), vec![])
 | 
			
		||||
			},
 | 
			
		||||
			Action::Call(ref address) => {
 | 
			
		||||
				let params = ActionParams {
 | 
			
		||||
@ -193,18 +201,19 @@ impl<'a> Executive<'a> {
 | 
			
		||||
				};
 | 
			
		||||
				// TODO: move output upstream
 | 
			
		||||
				let mut out = vec![];
 | 
			
		||||
				(self.call(params, &mut substate, BytesRef::Flexible(&mut out)), out)
 | 
			
		||||
				(self.call(params, &mut substate, BytesRef::Flexible(&mut out), &mut tracer), out)
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		// finalize here!
 | 
			
		||||
		Ok(try!(self.finalize(t, substate, gas_left, output)))
 | 
			
		||||
		Ok(try!(self.finalize(t, substate, gas_left, output, tracer.traces().pop())))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn exec_vm(&mut self, params: ActionParams, unconfirmed_substate: &mut Substate, output_policy: OutputPolicy) -> evm::Result {
 | 
			
		||||
	fn exec_vm<T>(&mut self, params: ActionParams, unconfirmed_substate: &mut Substate, output_policy: OutputPolicy, tracer: &mut T)
 | 
			
		||||
		-> evm::Result where T: Tracer {
 | 
			
		||||
		// Ordinary execution - keep VM in same thread
 | 
			
		||||
		if (self.depth + 1) % MAX_VM_DEPTH_FOR_THREAD != 0 {
 | 
			
		||||
			let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy);
 | 
			
		||||
			let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer);
 | 
			
		||||
			let vm_factory = self.engine.vm_factory();
 | 
			
		||||
			trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call);
 | 
			
		||||
			return vm_factory.create().exec(params, &mut ext);
 | 
			
		||||
@ -214,7 +223,7 @@ impl<'a> Executive<'a> {
 | 
			
		||||
		// TODO [todr] No thread builder yet, so we need to reset once for a while
 | 
			
		||||
		// https://github.com/aturon/crossbeam/issues/16
 | 
			
		||||
		crossbeam::scope(|scope| {
 | 
			
		||||
			let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy);
 | 
			
		||||
			let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer);
 | 
			
		||||
			let vm_factory = self.engine.vm_factory();
 | 
			
		||||
 | 
			
		||||
			scope.spawn(move || {
 | 
			
		||||
@ -227,7 +236,8 @@ impl<'a> Executive<'a> {
 | 
			
		||||
	/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
 | 
			
		||||
	/// Modifies the substate and the output.
 | 
			
		||||
	/// Returns either gas_left or `evm::Error`.
 | 
			
		||||
	pub fn call(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef) -> evm::Result {
 | 
			
		||||
	pub fn call<T>(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef, tracer: &mut T)
 | 
			
		||||
		-> evm::Result where T: Tracer {
 | 
			
		||||
		// backup used in case of running out of gas
 | 
			
		||||
		self.state.snapshot();
 | 
			
		||||
 | 
			
		||||
@ -257,46 +267,45 @@ impl<'a> Executive<'a> {
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			// if destination is a contract, do normal message call
 | 
			
		||||
			
 | 
			
		||||
			// don't trace if it's DELEGATECALL or CALLCODE.
 | 
			
		||||
			let should_trace = if let ActionValue::Transfer(_) = params.value {
 | 
			
		||||
				params.code_address == params.address && substate.subtraces.is_some()
 | 
			
		||||
			} else { false };
 | 
			
		||||
 | 
			
		||||
			// transaction tracing stuff. None if there's no tracing.
 | 
			
		||||
			let (mut trace_info, mut trace_output) = if should_trace {
 | 
			
		||||
				(Some((TraceAction::from_call(¶ms), self.depth)), Some(vec![]))
 | 
			
		||||
			} else { (None, None) };
 | 
			
		||||
			let trace_info = tracer.prepare_trace_call(¶ms);
 | 
			
		||||
			let mut trace_output = tracer.prepare_trace_output();
 | 
			
		||||
			let mut subtracer = tracer.subtracer();
 | 
			
		||||
			let delegate_call = params.code_address != params.address;
 | 
			
		||||
			let gas = params.gas;
 | 
			
		||||
 | 
			
		||||
			if params.code.is_some() {
 | 
			
		||||
				// part of substate that may be reverted
 | 
			
		||||
				let mut unconfirmed_substate = Substate::new(should_trace);
 | 
			
		||||
				let mut unconfirmed_substate = Substate::new();
 | 
			
		||||
 | 
			
		||||
				let res = {
 | 
			
		||||
					self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()))
 | 
			
		||||
					self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer)
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				trace!(target: "executive", "res={:?}", res);
 | 
			
		||||
 | 
			
		||||
				// if there's tracing, make up trace_info's result with trace_output and some arithmetic.
 | 
			
		||||
				if let Some((TraceAction::Call(ref mut c), _)) = trace_info {
 | 
			
		||||
					c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, trace_output.expect("trace_info is Some: so should_trace: qed")));
 | 
			
		||||
				}
 | 
			
		||||
				let traces = subtracer.traces();
 | 
			
		||||
				match res {
 | 
			
		||||
					Ok(gas_left) => tracer.trace_call(
 | 
			
		||||
						trace_info,
 | 
			
		||||
						gas - gas_left,
 | 
			
		||||
						trace_output,
 | 
			
		||||
						self.depth,
 | 
			
		||||
						traces,
 | 
			
		||||
						delegate_call
 | 
			
		||||
					),
 | 
			
		||||
					_ => tracer.trace_failed_call(trace_info, self.depth, traces, delegate_call),
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
 | 
			
		||||
 | 
			
		||||
				self.enact_result(&res, substate, unconfirmed_substate, trace_info);
 | 
			
		||||
				self.enact_result(&res, substate, unconfirmed_substate);
 | 
			
		||||
				trace!(target: "executive", "enacted: substate={:?}\n", substate);
 | 
			
		||||
				res
 | 
			
		||||
			} else {
 | 
			
		||||
				// otherwise it's just a basic transaction, only do tracing, if necessary.
 | 
			
		||||
				trace!(target: "executive", "Basic message (send funds) should_trace={}", should_trace);
 | 
			
		||||
				self.state.clear_snapshot();
 | 
			
		||||
				if let Some((TraceAction::Call(ref mut c), _)) = trace_info {
 | 
			
		||||
					c.result = Some((x!(0), vec![]));
 | 
			
		||||
				}
 | 
			
		||||
				substate.accrue_trace(if should_trace {Some(vec![])} else {None}, trace_info);
 | 
			
		||||
 | 
			
		||||
				tracer.trace_call(trace_info, U256::zero(), trace_output, self.depth, vec![], delegate_call);
 | 
			
		||||
				Ok(params.gas)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@ -305,12 +314,13 @@ 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.
 | 
			
		||||
	pub fn create(&mut self, params: ActionParams, substate: &mut Substate) -> evm::Result {
 | 
			
		||||
	pub fn create<T>(&mut self, params: ActionParams, substate: &mut Substate, tracer: &mut T) -> evm::Result where T:
 | 
			
		||||
		Tracer {
 | 
			
		||||
		// backup used in case of running out of gas
 | 
			
		||||
		self.state.snapshot();
 | 
			
		||||
 | 
			
		||||
		// part of substate that may be reverted
 | 
			
		||||
		let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some());
 | 
			
		||||
		let mut unconfirmed_substate = Substate::new();
 | 
			
		||||
 | 
			
		||||
		// create contract and transfer value to it if necessary
 | 
			
		||||
		let prev_bal = self.state.balance(¶ms.address);
 | 
			
		||||
@ -321,26 +331,34 @@ impl<'a> Executive<'a> {
 | 
			
		||||
			self.state.new_contract(¶ms.address, prev_bal);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		let mut trace_info = substate.subtraces.as_ref().map(|_| (TraceAction::from_create(¶ms), self.depth));
 | 
			
		||||
		let mut trace_output = trace_info.as_ref().map(|_| vec![]);
 | 
			
		||||
		let trace_info = tracer.prepare_trace_create(¶ms);
 | 
			
		||||
		let mut trace_output = tracer.prepare_trace_output();
 | 
			
		||||
		let mut subtracer = tracer.subtracer();
 | 
			
		||||
		let gas = params.gas;
 | 
			
		||||
		let created = params.address.clone();
 | 
			
		||||
 | 
			
		||||
		let res = {
 | 
			
		||||
			self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut()))
 | 
			
		||||
			self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut()), &mut subtracer)
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		if let Some((TraceAction::Create(ref mut c), _)) = trace_info {
 | 
			
		||||
			c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created, trace_output.expect("trace_info is Some: qed")));
 | 
			
		||||
		}
 | 
			
		||||
		match res {
 | 
			
		||||
			Ok(gas_left) => tracer.trace_create(
 | 
			
		||||
				trace_info,
 | 
			
		||||
				gas - gas_left,
 | 
			
		||||
				trace_output,
 | 
			
		||||
				created,
 | 
			
		||||
				self.depth,
 | 
			
		||||
				subtracer.traces()
 | 
			
		||||
			),
 | 
			
		||||
			_ => tracer.trace_failed_create(trace_info, self.depth, subtracer.traces())
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		trace!(target: "executive", "trace_info={:?}", trace_info);
 | 
			
		||||
 | 
			
		||||
		self.enact_result(&res, substate, unconfirmed_substate, trace_info);
 | 
			
		||||
		self.enact_result(&res, substate, unconfirmed_substate);
 | 
			
		||||
		res
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Finalizes the transaction (does refunds and suicides).
 | 
			
		||||
	fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result, output: Bytes) -> ExecutionResult {
 | 
			
		||||
	fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result, output: Bytes, trace: Option<Trace>) -> ExecutionResult {
 | 
			
		||||
		let schedule = self.engine.schedule(self.info);
 | 
			
		||||
 | 
			
		||||
		// refunds from SSTORE nonzero -> zero
 | 
			
		||||
@ -371,8 +389,6 @@ impl<'a> Executive<'a> {
 | 
			
		||||
			self.state.kill_account(address);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		let trace = substate.subtraces.and_then(|mut v| v.pop());
 | 
			
		||||
 | 
			
		||||
		match result {
 | 
			
		||||
			Err(evm::Error::Internal) => Err(ExecutionError::Internal),
 | 
			
		||||
			Err(_) => {
 | 
			
		||||
@ -402,7 +418,7 @@ impl<'a> Executive<'a> {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, maybe_info: Option<(TraceAction, usize)>) {
 | 
			
		||||
	fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate) {
 | 
			
		||||
		match *result {
 | 
			
		||||
			Err(evm::Error::OutOfGas)
 | 
			
		||||
				| Err(evm::Error::BadJumpDestination {..})
 | 
			
		||||
@ -410,11 +426,10 @@ impl<'a> Executive<'a> {
 | 
			
		||||
				| Err(evm::Error::StackUnderflow {..})
 | 
			
		||||
				| Err(evm::Error::OutOfStack {..}) => {
 | 
			
		||||
					self.state.revert_snapshot();
 | 
			
		||||
				substate.accrue_trace(un_substate.subtraces, maybe_info)
 | 
			
		||||
			},
 | 
			
		||||
			Ok(_) | Err(evm::Error::Internal) => {
 | 
			
		||||
				self.state.clear_snapshot();
 | 
			
		||||
				substate.accrue(un_substate, maybe_info)
 | 
			
		||||
				substate.accrue(un_substate);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@ -452,11 +467,11 @@ mod tests {
 | 
			
		||||
		state.add_balance(&sender, &U256::from(0x100u64));
 | 
			
		||||
		let info = EnvInfo::default();
 | 
			
		||||
		let engine = TestEngine::new(0, factory);
 | 
			
		||||
		let mut substate = Substate::new(false);
 | 
			
		||||
		let mut substate = Substate::new();
 | 
			
		||||
 | 
			
		||||
		let gas_left = {
 | 
			
		||||
			let mut ex = Executive::new(&mut state, &info, &engine);
 | 
			
		||||
			ex.create(params, &mut substate).unwrap()
 | 
			
		||||
			ex.create(params, &mut substate, &mut NoopTracer).unwrap()
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		assert_eq!(gas_left, U256::from(79_975));
 | 
			
		||||
@ -511,11 +526,11 @@ mod tests {
 | 
			
		||||
		state.add_balance(&sender, &U256::from(100));
 | 
			
		||||
		let info = EnvInfo::default();
 | 
			
		||||
		let engine = TestEngine::new(0, factory);
 | 
			
		||||
		let mut substate = Substate::new(false);
 | 
			
		||||
		let mut substate = Substate::new();
 | 
			
		||||
 | 
			
		||||
		let gas_left = {
 | 
			
		||||
			let mut ex = Executive::new(&mut state, &info, &engine);
 | 
			
		||||
			ex.create(params, &mut substate).unwrap()
 | 
			
		||||
			ex.create(params, &mut substate, &mut NoopTracer).unwrap()
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		assert_eq!(gas_left, U256::from(62_976));
 | 
			
		||||
@ -566,16 +581,16 @@ mod tests {
 | 
			
		||||
		state.add_balance(&sender, &U256::from(100));
 | 
			
		||||
		let info = EnvInfo::default();
 | 
			
		||||
		let engine = TestEngine::new(5, factory);
 | 
			
		||||
		let mut substate = Substate::new(true);
 | 
			
		||||
		let mut substate = Substate::new();
 | 
			
		||||
		let mut tracer = ExecutiveTracer::default();
 | 
			
		||||
 | 
			
		||||
		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).unwrap()
 | 
			
		||||
			ex.call(params, &mut substate, output, &mut tracer).unwrap()
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		println!("trace: {:?}", substate.subtraces);
 | 
			
		||||
		let expected_trace = Some(vec![ Trace {
 | 
			
		||||
		let expected_trace = vec![ Trace {
 | 
			
		||||
			depth: 0,
 | 
			
		||||
			action: TraceAction::Call(TraceCall {
 | 
			
		||||
				from: x!("cd1722f3947def4cf144679da39c4c32bdc35681"),
 | 
			
		||||
@ -583,7 +598,10 @@ mod tests {
 | 
			
		||||
				value: x!(100),
 | 
			
		||||
				gas: x!(100000),
 | 
			
		||||
				input: vec![],
 | 
			
		||||
				result: Some((x!(55248), vec![]))
 | 
			
		||||
			}),
 | 
			
		||||
			result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
				gas_used: U256::from(55_248),
 | 
			
		||||
				output: vec![],
 | 
			
		||||
			}),
 | 
			
		||||
			subs: vec![Trace {
 | 
			
		||||
				depth: 1,
 | 
			
		||||
@ -591,13 +609,17 @@ mod tests {
 | 
			
		||||
					from: x!("b010143a42d5980c7e5ef0e4a4416dc098a4fed3"),
 | 
			
		||||
					value: x!(23),
 | 
			
		||||
					gas: x!(67979),
 | 
			
		||||
					init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85],
 | 
			
		||||
					result: Some((x!(3224), x!("c6d80f262ae5e0f164e5fde365044d7ada2bfa34"), vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53])),
 | 
			
		||||
					init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85]
 | 
			
		||||
				}),
 | 
			
		||||
				result: TraceResult::Create(TraceCreateResult {
 | 
			
		||||
					gas_used: U256::from(3224),
 | 
			
		||||
					address: Address::from_str("c6d80f262ae5e0f164e5fde365044d7ada2bfa34").unwrap(),
 | 
			
		||||
					code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53]
 | 
			
		||||
				}),
 | 
			
		||||
				subs: vec![]
 | 
			
		||||
			}]
 | 
			
		||||
		} ]);
 | 
			
		||||
		assert_eq!(substate.subtraces, expected_trace);
 | 
			
		||||
		}];
 | 
			
		||||
		assert_eq!(tracer.traces(), expected_trace);
 | 
			
		||||
		assert_eq!(gas_left, U256::from(44_752));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -631,26 +653,31 @@ mod tests {
 | 
			
		||||
		state.add_balance(&sender, &U256::from(100));
 | 
			
		||||
		let info = EnvInfo::default();
 | 
			
		||||
		let engine = TestEngine::new(5, factory);
 | 
			
		||||
		let mut substate = Substate::new(true);
 | 
			
		||||
		let mut substate = Substate::new();
 | 
			
		||||
		let mut tracer = ExecutiveTracer::default();
 | 
			
		||||
 | 
			
		||||
		let gas_left = {
 | 
			
		||||
			let mut ex = Executive::new(&mut state, &info, &engine);
 | 
			
		||||
			ex.create(params.clone(), &mut substate).unwrap()
 | 
			
		||||
			ex.create(params.clone(), &mut substate, &mut tracer).unwrap()
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		println!("trace: {:?}", substate.subtraces);
 | 
			
		||||
		let expected_trace = Some(vec![Trace {
 | 
			
		||||
		let expected_trace = vec![Trace {
 | 
			
		||||
			depth: 0,
 | 
			
		||||
			action: TraceAction::Create(TraceCreate {
 | 
			
		||||
				from: params.sender,
 | 
			
		||||
				value: x!(100),
 | 
			
		||||
				gas: params.gas,
 | 
			
		||||
				init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85],
 | 
			
		||||
				result: Some((x!(3224), params.address, vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53])),
 | 
			
		||||
			}),
 | 
			
		||||
			result: TraceResult::Create(TraceCreateResult {
 | 
			
		||||
				gas_used: U256::from(3224),
 | 
			
		||||
				address: params.address,
 | 
			
		||||
				code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53]
 | 
			
		||||
			}),
 | 
			
		||||
			subs: vec![]
 | 
			
		||||
		} ]);
 | 
			
		||||
		assert_eq!(substate.subtraces, expected_trace);
 | 
			
		||||
		}];
 | 
			
		||||
 | 
			
		||||
		assert_eq!(tracer.traces(), expected_trace);
 | 
			
		||||
		assert_eq!(gas_left, U256::from(96_776));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -696,11 +723,11 @@ mod tests {
 | 
			
		||||
		state.add_balance(&sender, &U256::from(100));
 | 
			
		||||
		let info = EnvInfo::default();
 | 
			
		||||
		let engine = TestEngine::new(0, factory);
 | 
			
		||||
		let mut substate = Substate::new(false);
 | 
			
		||||
		let mut substate = Substate::new();
 | 
			
		||||
 | 
			
		||||
		let gas_left = {
 | 
			
		||||
			let mut ex = Executive::new(&mut state, &info, &engine);
 | 
			
		||||
			ex.create(params, &mut substate).unwrap()
 | 
			
		||||
			ex.create(params, &mut substate, &mut NoopTracer).unwrap()
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		assert_eq!(gas_left, U256::from(62_976));
 | 
			
		||||
@ -748,11 +775,11 @@ mod tests {
 | 
			
		||||
		state.add_balance(&sender, &U256::from(100));
 | 
			
		||||
		let info = EnvInfo::default();
 | 
			
		||||
		let engine = TestEngine::new(1024, factory);
 | 
			
		||||
		let mut substate = Substate::new(false);
 | 
			
		||||
		let mut substate = Substate::new();
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			let mut ex = Executive::new(&mut state, &info, &engine);
 | 
			
		||||
			ex.create(params, &mut substate).unwrap();
 | 
			
		||||
			ex.create(params, &mut substate, &mut NoopTracer).unwrap();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		assert_eq!(substate.contracts_created.len(), 1);
 | 
			
		||||
@ -809,11 +836,11 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
		let info = EnvInfo::default();
 | 
			
		||||
		let engine = TestEngine::new(0, factory);
 | 
			
		||||
		let mut substate = Substate::new(false);
 | 
			
		||||
		let mut substate = Substate::new();
 | 
			
		||||
 | 
			
		||||
		let gas_left = {
 | 
			
		||||
			let mut ex = Executive::new(&mut state, &info, &engine);
 | 
			
		||||
			ex.call(params, &mut substate, BytesRef::Fixed(&mut [])).unwrap()
 | 
			
		||||
			ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer).unwrap()
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		assert_eq!(gas_left, U256::from(73_237));
 | 
			
		||||
@ -854,11 +881,11 @@ mod tests {
 | 
			
		||||
		state.init_code(&address, code.clone());
 | 
			
		||||
		let info = EnvInfo::default();
 | 
			
		||||
		let engine = TestEngine::new(0, factory);
 | 
			
		||||
		let mut substate = Substate::new(false);
 | 
			
		||||
		let mut substate = Substate::new();
 | 
			
		||||
 | 
			
		||||
		let gas_left = {
 | 
			
		||||
			let mut ex = Executive::new(&mut state, &info, &engine);
 | 
			
		||||
			ex.call(params, &mut substate, BytesRef::Fixed(&mut [])).unwrap()
 | 
			
		||||
			ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer).unwrap()
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		assert_eq!(gas_left, U256::from(59_870));
 | 
			
		||||
@ -1056,11 +1083,11 @@ mod tests {
 | 
			
		||||
		state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap());
 | 
			
		||||
		let info = EnvInfo::default();
 | 
			
		||||
		let engine = TestEngine::new(0, factory);
 | 
			
		||||
		let mut substate = Substate::new(false);
 | 
			
		||||
		let mut substate = Substate::new();
 | 
			
		||||
 | 
			
		||||
		let result = {
 | 
			
		||||
			let mut ex = Executive::new(&mut state, &info, &engine);
 | 
			
		||||
			ex.create(params, &mut substate)
 | 
			
		||||
			ex.create(params, &mut substate, &mut NoopTracer)
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		match result {
 | 
			
		||||
 | 
			
		||||
@ -54,7 +54,7 @@ impl OriginInfo {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Implementation of evm Externalities.
 | 
			
		||||
pub struct Externalities<'a> {
 | 
			
		||||
pub struct Externalities<'a, T> where T: 'a + Tracer {
 | 
			
		||||
	state: &'a mut State,
 | 
			
		||||
	env_info: &'a EnvInfo,
 | 
			
		||||
	engine: &'a Engine,
 | 
			
		||||
@ -62,10 +62,11 @@ pub struct Externalities<'a> {
 | 
			
		||||
	origin_info: OriginInfo,
 | 
			
		||||
	substate: &'a mut Substate,
 | 
			
		||||
	schedule: Schedule,
 | 
			
		||||
	output: OutputPolicy<'a, 'a>
 | 
			
		||||
	output: OutputPolicy<'a, 'a>,
 | 
			
		||||
	tracer: &'a mut T,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> Externalities<'a> {
 | 
			
		||||
impl<'a, T> Externalities<'a, T> where T: 'a + Tracer {
 | 
			
		||||
	/// Basic `Externalities` constructor.
 | 
			
		||||
	pub fn new(state: &'a mut State,
 | 
			
		||||
		env_info: &'a EnvInfo,
 | 
			
		||||
@ -73,7 +74,8 @@ impl<'a> Externalities<'a> {
 | 
			
		||||
		depth: usize,
 | 
			
		||||
		origin_info: OriginInfo,
 | 
			
		||||
		substate: &'a mut Substate,
 | 
			
		||||
		output: OutputPolicy<'a, 'a>
 | 
			
		||||
		output: OutputPolicy<'a, 'a>,
 | 
			
		||||
		tracer: &'a mut T,
 | 
			
		||||
	) -> Self {
 | 
			
		||||
		Externalities {
 | 
			
		||||
			state: state,
 | 
			
		||||
@ -83,12 +85,13 @@ impl<'a> Externalities<'a> {
 | 
			
		||||
			origin_info: origin_info,
 | 
			
		||||
			substate: substate,
 | 
			
		||||
			schedule: engine.schedule(env_info),
 | 
			
		||||
			output: output
 | 
			
		||||
			output: output,
 | 
			
		||||
			tracer: tracer,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> Ext for Externalities<'a> {
 | 
			
		||||
impl<'a, T> Ext for Externalities<'a, T> where T: 'a + Tracer {
 | 
			
		||||
	fn storage_at(&self, key: &H256) -> H256 {
 | 
			
		||||
		self.state.storage_at(&self.origin_info.address, key)
 | 
			
		||||
	}
 | 
			
		||||
@ -143,7 +146,7 @@ impl<'a> Ext for Externalities<'a> {
 | 
			
		||||
		let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth);
 | 
			
		||||
 | 
			
		||||
		// TODO: handle internal error separately
 | 
			
		||||
		match ex.create(params, self.substate) {
 | 
			
		||||
		match ex.create(params, self.substate, self.tracer) {
 | 
			
		||||
			Ok(gas_left) => {
 | 
			
		||||
				self.substate.contracts_created.push(address.clone());
 | 
			
		||||
				ContractCreateResult::Created(address, gas_left)
 | 
			
		||||
@ -181,7 +184,7 @@ impl<'a> Ext for Externalities<'a> {
 | 
			
		||||
 | 
			
		||||
		let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth);
 | 
			
		||||
 | 
			
		||||
		match ex.call(params, self.substate, BytesRef::Fixed(output)) {
 | 
			
		||||
		match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer) {
 | 
			
		||||
			Ok(gas_left) => MessageCallResult::Success(gas_left),
 | 
			
		||||
			_ => MessageCallResult::Failed
 | 
			
		||||
		}
 | 
			
		||||
@ -328,7 +331,7 @@ mod tests {
 | 
			
		||||
			TestSetup {
 | 
			
		||||
				state: get_temp_state(),
 | 
			
		||||
				engine: get_test_spec().engine,
 | 
			
		||||
				sub_state: Substate::new(false),
 | 
			
		||||
				sub_state: Substate::new(),
 | 
			
		||||
				env_info: get_test_env_info()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@ -338,8 +341,9 @@ mod tests {
 | 
			
		||||
	fn can_be_created() {
 | 
			
		||||
		let mut setup = TestSetup::new();
 | 
			
		||||
		let state = setup.state.reference_mut();
 | 
			
		||||
		let mut tracer = NoopTracer;
 | 
			
		||||
 | 
			
		||||
		let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None));
 | 
			
		||||
		let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer);
 | 
			
		||||
 | 
			
		||||
		assert_eq!(ext.env_info().number, 100);
 | 
			
		||||
	}
 | 
			
		||||
@ -348,7 +352,9 @@ mod tests {
 | 
			
		||||
	fn can_return_block_hash_no_env() {
 | 
			
		||||
		let mut setup = TestSetup::new();
 | 
			
		||||
		let state = setup.state.reference_mut();
 | 
			
		||||
		let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None));
 | 
			
		||||
		let mut tracer = NoopTracer;
 | 
			
		||||
 | 
			
		||||
		let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer);
 | 
			
		||||
 | 
			
		||||
		let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
 | 
			
		||||
 | 
			
		||||
@ -367,7 +373,9 @@ mod tests {
 | 
			
		||||
			env_info.last_hashes.push(test_hash.clone());
 | 
			
		||||
		}
 | 
			
		||||
		let state = setup.state.reference_mut();
 | 
			
		||||
		let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None));
 | 
			
		||||
		let mut tracer = NoopTracer;
 | 
			
		||||
 | 
			
		||||
		let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer);
 | 
			
		||||
 | 
			
		||||
		let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
 | 
			
		||||
 | 
			
		||||
@ -379,7 +387,9 @@ mod tests {
 | 
			
		||||
	fn can_call_fail_empty() {
 | 
			
		||||
		let mut setup = TestSetup::new();
 | 
			
		||||
		let state = setup.state.reference_mut();
 | 
			
		||||
		let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None));
 | 
			
		||||
		let mut tracer = NoopTracer;
 | 
			
		||||
 | 
			
		||||
		let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer);
 | 
			
		||||
 | 
			
		||||
		let mut output = vec![];
 | 
			
		||||
 | 
			
		||||
@ -401,9 +411,10 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
		let mut setup = TestSetup::new();
 | 
			
		||||
		let state = setup.state.reference_mut();
 | 
			
		||||
		let mut tracer = NoopTracer;
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None));
 | 
			
		||||
			let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer);
 | 
			
		||||
			ext.log(log_topics, &log_data);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -416,9 +427,10 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
		let mut setup = TestSetup::new();
 | 
			
		||||
		let state = setup.state.reference_mut();
 | 
			
		||||
		let mut tracer = NoopTracer;
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None));
 | 
			
		||||
			let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer);
 | 
			
		||||
			ext.suicide(&refund_account);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -49,13 +49,13 @@ impl From<ethjson::vm::Call> for CallCreate {
 | 
			
		||||
 | 
			
		||||
/// Tiny wrapper around executive externalities.
 | 
			
		||||
/// Stores callcreates.
 | 
			
		||||
struct TestExt<'a> {
 | 
			
		||||
	ext: Externalities<'a>,
 | 
			
		||||
struct TestExt<'a, T> where T: 'a + Tracer {
 | 
			
		||||
	ext: Externalities<'a, T>,
 | 
			
		||||
	callcreates: Vec<CallCreate>,
 | 
			
		||||
	contract_address: Address
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> TestExt<'a> {
 | 
			
		||||
impl<'a, T> TestExt<'a, T> where T: 'a + Tracer {
 | 
			
		||||
	fn new(state: &'a mut State,
 | 
			
		||||
			   info: &'a EnvInfo,
 | 
			
		||||
			   engine: &'a Engine,
 | 
			
		||||
@ -63,16 +63,17 @@ impl<'a> TestExt<'a> {
 | 
			
		||||
			   origin_info: OriginInfo,
 | 
			
		||||
			   substate: &'a mut Substate,
 | 
			
		||||
			   output: OutputPolicy<'a, 'a>,
 | 
			
		||||
			   address: Address) -> Self {
 | 
			
		||||
			   address: Address,
 | 
			
		||||
			   tracer: &'a mut T) -> Self {
 | 
			
		||||
		TestExt {
 | 
			
		||||
			contract_address: contract_address(&address, &state.nonce(&address)),
 | 
			
		||||
			ext: Externalities::new(state, info, engine, depth, origin_info, substate, output),
 | 
			
		||||
			ext: Externalities::new(state, info, engine, depth, origin_info, substate, output, tracer),
 | 
			
		||||
			callcreates: vec![]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> Ext for TestExt<'a> {
 | 
			
		||||
impl<'a, T> Ext for TestExt<'a, T> where T: Tracer {
 | 
			
		||||
	fn storage_at(&self, key: &H256) -> H256 {
 | 
			
		||||
		self.ext.storage_at(key)
 | 
			
		||||
	}
 | 
			
		||||
@ -182,7 +183,8 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
 | 
			
		||||
		let engine = TestEngine::new(1, Factory::new(vm_type.clone()));
 | 
			
		||||
		let params = ActionParams::from(vm.transaction);
 | 
			
		||||
 | 
			
		||||
		let mut substate = Substate::new(false);
 | 
			
		||||
		let mut substate = Substate::new();
 | 
			
		||||
		let mut tracer = NoopTracer;
 | 
			
		||||
		let mut output = vec![];
 | 
			
		||||
 | 
			
		||||
		// execute
 | 
			
		||||
@ -195,7 +197,8 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
 | 
			
		||||
				OriginInfo::from(¶ms),
 | 
			
		||||
				&mut substate,
 | 
			
		||||
				OutputPolicy::Return(BytesRef::Flexible(&mut output), None),
 | 
			
		||||
				params.address.clone()
 | 
			
		||||
				params.address.clone(),
 | 
			
		||||
				&mut tracer,
 | 
			
		||||
			);
 | 
			
		||||
			let evm = engine.vm_factory().create();
 | 
			
		||||
			let res = evm.exec(params, &mut ex);
 | 
			
		||||
 | 
			
		||||
@ -398,7 +398,11 @@ fn should_apply_create_transaction() {
 | 
			
		||||
			value: x!(100),
 | 
			
		||||
			gas: x!(77412),
 | 
			
		||||
			init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85],
 | 
			
		||||
			result: Some((x!(3224), x!("8988167e088c87cd314df6d3c2b83da5acb93ace"), vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53]))
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::Create(TraceCreateResult {
 | 
			
		||||
			gas_used: U256::from(3224),
 | 
			
		||||
			address: Address::from_str("8988167e088c87cd314df6d3c2b83da5acb93ace").unwrap(),
 | 
			
		||||
			code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53]
 | 
			
		||||
		}),
 | 
			
		||||
		subs: vec![]
 | 
			
		||||
	});
 | 
			
		||||
@ -454,8 +458,8 @@ fn should_trace_failed_create_transaction() {
 | 
			
		||||
			value: x!(100),
 | 
			
		||||
			gas: x!(78792),
 | 
			
		||||
			init: vec![91, 96, 0, 86],
 | 
			
		||||
			result: None
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::FailedCreate,
 | 
			
		||||
		subs: vec![]
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
@ -493,7 +497,10 @@ fn should_trace_call_transaction() {
 | 
			
		||||
			value: x!(100),
 | 
			
		||||
			gas: x!(79000),
 | 
			
		||||
			input: vec![],
 | 
			
		||||
			result: Some((x!(3), vec![]))
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
			gas_used: U256::from(3),
 | 
			
		||||
			output: vec![]
 | 
			
		||||
		}),
 | 
			
		||||
		subs: vec![]
 | 
			
		||||
	});
 | 
			
		||||
@ -531,7 +538,10 @@ fn should_trace_basic_call_transaction() {
 | 
			
		||||
			value: x!(100),
 | 
			
		||||
			gas: x!(79000),
 | 
			
		||||
			input: vec![],
 | 
			
		||||
			result: Some((x!(0), vec![]))
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
			gas_used: U256::from(0),
 | 
			
		||||
			output: vec![]
 | 
			
		||||
		}),
 | 
			
		||||
		subs: vec![]
 | 
			
		||||
	});
 | 
			
		||||
@ -595,7 +605,10 @@ fn should_not_trace_subcall_transaction_to_builtin() {
 | 
			
		||||
			value: x!(0),
 | 
			
		||||
			gas: x!(79000),
 | 
			
		||||
			input: vec![],
 | 
			
		||||
			result: Some((x!(28061), vec![]))
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
			gas_used: U256::from(28_061),
 | 
			
		||||
			output: vec![]
 | 
			
		||||
		}),
 | 
			
		||||
		subs: vec![]
 | 
			
		||||
	});
 | 
			
		||||
@ -634,7 +647,10 @@ fn should_not_trace_callcode() {
 | 
			
		||||
			value: x!(0),
 | 
			
		||||
			gas: x!(79000),
 | 
			
		||||
			input: vec![],
 | 
			
		||||
			result: Some((x!(64), vec![]))
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
			gas_used: U256::from(64),
 | 
			
		||||
			output: vec![]
 | 
			
		||||
		}),
 | 
			
		||||
		subs: vec![]
 | 
			
		||||
	});
 | 
			
		||||
@ -676,7 +692,10 @@ fn should_not_trace_delegatecall() {
 | 
			
		||||
			value: x!(0),
 | 
			
		||||
			gas: x!(79000),
 | 
			
		||||
			input: vec![],
 | 
			
		||||
			result: Some((x!(61), vec![]))
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
			gas_used: U256::from(61),
 | 
			
		||||
			output: vec![]
 | 
			
		||||
		}),
 | 
			
		||||
		subs: vec![]
 | 
			
		||||
	});
 | 
			
		||||
@ -714,8 +733,8 @@ fn should_trace_failed_call_transaction() {
 | 
			
		||||
			value: x!(100),
 | 
			
		||||
			gas: x!(79000),
 | 
			
		||||
			input: vec![],
 | 
			
		||||
			result: None
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::FailedCall,
 | 
			
		||||
		subs: vec![]
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
@ -756,7 +775,10 @@ fn should_trace_call_with_subcall_transaction() {
 | 
			
		||||
			value: x!(100),
 | 
			
		||||
			gas: x!(79000),
 | 
			
		||||
			input: vec![],
 | 
			
		||||
			result: Some((x!(69), vec![]))
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
			gas_used: U256::from(69),
 | 
			
		||||
			output: vec![]
 | 
			
		||||
		}),
 | 
			
		||||
		subs: vec![Trace {
 | 
			
		||||
			depth: 1,
 | 
			
		||||
@ -766,7 +788,10 @@ fn should_trace_call_with_subcall_transaction() {
 | 
			
		||||
				value: x!(0),
 | 
			
		||||
				gas: x!(78934),
 | 
			
		||||
				input: vec![],
 | 
			
		||||
				result: Some((x!(3), vec![]))
 | 
			
		||||
			}),
 | 
			
		||||
			result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
				gas_used: U256::from(3),
 | 
			
		||||
				output: vec![]
 | 
			
		||||
			}),
 | 
			
		||||
			subs: vec![]
 | 
			
		||||
		}]
 | 
			
		||||
@ -806,7 +831,10 @@ fn should_trace_call_with_basic_subcall_transaction() {
 | 
			
		||||
			value: x!(100),
 | 
			
		||||
			gas: x!(79000),
 | 
			
		||||
			input: vec![],
 | 
			
		||||
			result: Some((x!(31761), vec![]))
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
			gas_used: U256::from(31761),
 | 
			
		||||
			output: vec![]
 | 
			
		||||
		}),
 | 
			
		||||
		subs: vec![Trace {
 | 
			
		||||
			depth: 1,
 | 
			
		||||
@ -816,8 +844,8 @@ fn should_trace_call_with_basic_subcall_transaction() {
 | 
			
		||||
				value: x!(69),
 | 
			
		||||
				gas: x!(2300),
 | 
			
		||||
				input: vec![],
 | 
			
		||||
				result: Some((x!(0), vec![]))
 | 
			
		||||
			}),
 | 
			
		||||
			result: TraceResult::Call(TraceCallResult::default()),
 | 
			
		||||
			subs: vec![]
 | 
			
		||||
		}]
 | 
			
		||||
	});
 | 
			
		||||
@ -856,7 +884,10 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() {
 | 
			
		||||
			value: x!(100),
 | 
			
		||||
			gas: x!(79000),
 | 
			
		||||
			input: vec![],
 | 
			
		||||
			result: Some((x!(31761), vec![]))
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
			gas_used: U256::from(31761),
 | 
			
		||||
			output: vec![]
 | 
			
		||||
		}),
 | 
			
		||||
		subs: vec![]
 | 
			
		||||
	});
 | 
			
		||||
@ -896,7 +927,10 @@ fn should_trace_failed_subcall_transaction() {
 | 
			
		||||
			value: x!(100),
 | 
			
		||||
			gas: x!(79000),
 | 
			
		||||
			input: vec![],
 | 
			
		||||
			result: Some((x!(79000), vec![]))
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
			gas_used: U256::from(79_000),
 | 
			
		||||
			output: vec![]
 | 
			
		||||
		}),
 | 
			
		||||
		subs: vec![Trace {
 | 
			
		||||
			depth: 1,
 | 
			
		||||
@ -906,8 +940,8 @@ fn should_trace_failed_subcall_transaction() {
 | 
			
		||||
				value: x!(0),
 | 
			
		||||
				gas: x!(78934),
 | 
			
		||||
				input: vec![],
 | 
			
		||||
				result: None
 | 
			
		||||
			}),
 | 
			
		||||
			result: TraceResult::FailedCall,
 | 
			
		||||
			subs: vec![]
 | 
			
		||||
		}]
 | 
			
		||||
	});
 | 
			
		||||
@ -948,7 +982,10 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
 | 
			
		||||
			value: x!(100),
 | 
			
		||||
			gas: x!(79000),
 | 
			
		||||
			input: vec![],
 | 
			
		||||
			result: Some((x!(135), vec![]))
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
			gas_used: U256::from(135),
 | 
			
		||||
			output: vec![]
 | 
			
		||||
		}),
 | 
			
		||||
		subs: vec![Trace {
 | 
			
		||||
			depth: 1,
 | 
			
		||||
@ -958,7 +995,10 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
 | 
			
		||||
				value: x!(0),
 | 
			
		||||
				gas: x!(78934),
 | 
			
		||||
				input: vec![],
 | 
			
		||||
				result: Some((x!(69), vec![]))
 | 
			
		||||
			}),
 | 
			
		||||
			result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
				gas_used: U256::from(69),
 | 
			
		||||
				output: vec![]
 | 
			
		||||
			}),
 | 
			
		||||
			subs: vec![Trace {
 | 
			
		||||
				depth: 2,
 | 
			
		||||
@ -968,7 +1008,10 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
 | 
			
		||||
					value: x!(0),
 | 
			
		||||
					gas: x!(78868),
 | 
			
		||||
					input: vec![],
 | 
			
		||||
					result: Some((x!(3), vec![]))
 | 
			
		||||
				}),
 | 
			
		||||
				result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
					gas_used: U256::from(3),
 | 
			
		||||
					output: vec![]
 | 
			
		||||
				}),
 | 
			
		||||
				subs: vec![]
 | 
			
		||||
			}]
 | 
			
		||||
@ -1011,7 +1054,10 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
 | 
			
		||||
			value: x!(100),
 | 
			
		||||
			gas: x!(79000),
 | 
			
		||||
			input: vec![],
 | 
			
		||||
			result: Some((x!(79000), vec![]))
 | 
			
		||||
		}),
 | 
			
		||||
		result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
			gas_used: U256::from(79_000),
 | 
			
		||||
			output: vec![]
 | 
			
		||||
		}),
 | 
			
		||||
		subs: vec![Trace {
 | 
			
		||||
			depth: 1,
 | 
			
		||||
@ -1021,8 +1067,8 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
 | 
			
		||||
				value: x!(0),
 | 
			
		||||
				gas: x!(78934),
 | 
			
		||||
				input: vec![],
 | 
			
		||||
				result: None
 | 
			
		||||
			}),
 | 
			
		||||
			result: TraceResult::FailedCall,
 | 
			
		||||
			subs: vec![Trace {
 | 
			
		||||
				depth: 2,
 | 
			
		||||
				action: TraceAction::Call(TraceCall {
 | 
			
		||||
@ -1031,7 +1077,10 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
 | 
			
		||||
					value: x!(0),
 | 
			
		||||
					gas: x!(78868),
 | 
			
		||||
					input: vec![],
 | 
			
		||||
					result: Some((x!(3), vec![])),
 | 
			
		||||
				}),
 | 
			
		||||
				result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
					gas_used: U256::from(3),
 | 
			
		||||
					output: vec![]
 | 
			
		||||
				}),
 | 
			
		||||
				subs: vec![]
 | 
			
		||||
			}]
 | 
			
		||||
 | 
			
		||||
@ -32,44 +32,25 @@ pub struct Substate {
 | 
			
		||||
 | 
			
		||||
	/// Created contracts.
 | 
			
		||||
	pub contracts_created: Vec<Address>,
 | 
			
		||||
 | 
			
		||||
	/// The trace during this execution or `None` if we're not tracing.
 | 
			
		||||
	pub subtraces: Option<Vec<Trace>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Substate {
 | 
			
		||||
	/// Creates new substate.
 | 
			
		||||
	pub fn new(tracing: bool) -> Self {
 | 
			
		||||
	pub fn new() -> Self {
 | 
			
		||||
		Substate {
 | 
			
		||||
			suicides: Default::default(),
 | 
			
		||||
			logs: Default::default(),
 | 
			
		||||
			sstore_clears_count: Default::default(),
 | 
			
		||||
			contracts_created: Default::default(),
 | 
			
		||||
			subtraces: if tracing {Some(vec![])} else {None},
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Merge tracing information from substate `s` if enabled.
 | 
			
		||||
	pub fn accrue_trace(&mut self, subs: Option<Vec<Trace>>, maybe_info: Option<(TraceAction, usize)>) {
 | 
			
		||||
		// it failed, so we don't bother accrueing any protocol-level stuff, only the
 | 
			
		||||
		// trace info.
 | 
			
		||||
		if let Some(info) = maybe_info {
 | 
			
		||||
			self.subtraces.as_mut().expect("maybe_action is Some: so we must be tracing: qed").push(Trace {
 | 
			
		||||
				action: info.0,
 | 
			
		||||
				depth: info.1,
 | 
			
		||||
				subs: subs.expect("maybe_action is Some: so we must be tracing: qed"),
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Merge secondary substate `s` into self, accruing each element correspondingly; will merge
 | 
			
		||||
	/// tracing information too, if enabled.
 | 
			
		||||
	pub fn accrue(&mut self, s: Substate, maybe_info: Option<(TraceAction, usize)>) {
 | 
			
		||||
	/// Merge secondary substate `s` into self, accruing each element correspondingly.
 | 
			
		||||
	pub fn accrue(&mut self, s: Substate) {
 | 
			
		||||
		self.suicides.extend(s.suicides.into_iter());
 | 
			
		||||
		self.logs.extend(s.logs.into_iter());
 | 
			
		||||
		self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count;
 | 
			
		||||
		self.contracts_created.extend(s.contracts_created.into_iter());
 | 
			
		||||
		self.accrue_trace(s.subtraces, maybe_info);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -80,13 +61,13 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn created() {
 | 
			
		||||
		let sub_state = Substate::new(false);
 | 
			
		||||
		let sub_state = Substate::new();
 | 
			
		||||
		assert_eq!(sub_state.suicides.len(), 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn accrue() {
 | 
			
		||||
		let mut sub_state = Substate::new(false);
 | 
			
		||||
		let mut sub_state = Substate::new();
 | 
			
		||||
		sub_state.contracts_created.push(address_from_u64(1u64));
 | 
			
		||||
		sub_state.logs.push(LogEntry {
 | 
			
		||||
			address: address_from_u64(1u64),
 | 
			
		||||
@ -96,7 +77,7 @@ mod tests {
 | 
			
		||||
		sub_state.sstore_clears_count = x!(5);
 | 
			
		||||
		sub_state.suicides.insert(address_from_u64(10u64));
 | 
			
		||||
 | 
			
		||||
		let mut sub_state_2 = Substate::new(false);
 | 
			
		||||
		let mut sub_state_2 = Substate::new();
 | 
			
		||||
		sub_state_2.contracts_created.push(address_from_u64(2u64));
 | 
			
		||||
		sub_state_2.logs.push(LogEntry {
 | 
			
		||||
			address: address_from_u64(1u64),
 | 
			
		||||
@ -105,7 +86,7 @@ mod tests {
 | 
			
		||||
		});
 | 
			
		||||
		sub_state_2.sstore_clears_count = x!(7);
 | 
			
		||||
 | 
			
		||||
		sub_state.accrue(sub_state_2, None);
 | 
			
		||||
		sub_state.accrue(sub_state_2);
 | 
			
		||||
		assert_eq!(sub_state.contracts_created.len(), 2);
 | 
			
		||||
		assert_eq!(sub_state.sstore_clears_count, x!(12));
 | 
			
		||||
		assert_eq!(sub_state.suicides.len(), 1);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										201
									
								
								ethcore/src/trace/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								ethcore/src/trace/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,201 @@
 | 
			
		||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
//! Tracing
 | 
			
		||||
 | 
			
		||||
mod trace;
 | 
			
		||||
 | 
			
		||||
pub use self::trace::*;
 | 
			
		||||
use util::bytes::Bytes;
 | 
			
		||||
use util::hash::Address;
 | 
			
		||||
use util::numbers::U256;
 | 
			
		||||
use action_params::ActionParams;
 | 
			
		||||
 | 
			
		||||
/// This trait is used by executive to build traces.
 | 
			
		||||
pub trait Tracer: Send {
 | 
			
		||||
	/// Prepares call trace for given params. Noop tracer should return None.
 | 
			
		||||
	fn prepare_trace_call(&self, params: &ActionParams) -> Option<TraceCall>;
 | 
			
		||||
 | 
			
		||||
	/// Prepares create trace for given params. Noop tracer should return None.
 | 
			
		||||
	fn prepare_trace_create(&self, params: &ActionParams) -> Option<TraceCreate>;
 | 
			
		||||
 | 
			
		||||
	/// Prepare trace output. Noop tracer should return None.
 | 
			
		||||
	fn prepare_trace_output(&self) -> Option<Bytes>;
 | 
			
		||||
 | 
			
		||||
	/// Stores trace call info.
 | 
			
		||||
	fn trace_call(
 | 
			
		||||
		&mut self,
 | 
			
		||||
		call: Option<TraceCall>,
 | 
			
		||||
		gas_used: U256,
 | 
			
		||||
		output: Option<Bytes>,
 | 
			
		||||
		depth: usize,
 | 
			
		||||
		subs: Vec<Trace>,
 | 
			
		||||
		delegate_call: bool
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	/// Stores trace create info.
 | 
			
		||||
	fn trace_create(
 | 
			
		||||
		&mut self,
 | 
			
		||||
		create: Option<TraceCreate>,
 | 
			
		||||
		gas_used: U256,
 | 
			
		||||
		code: Option<Bytes>,
 | 
			
		||||
		address: Address,
 | 
			
		||||
		depth: usize,
 | 
			
		||||
		subs: Vec<Trace>
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	/// Stores failed call trace.
 | 
			
		||||
	fn trace_failed_call(&mut self, call: Option<TraceCall>, depth: usize, subs: Vec<Trace>, delegate_call: bool);
 | 
			
		||||
 | 
			
		||||
	/// Stores failed create trace.
 | 
			
		||||
	fn trace_failed_create(&mut self, create: Option<TraceCreate>, depth: usize, subs: Vec<Trace>);
 | 
			
		||||
 | 
			
		||||
	/// Spawn subracer which will be used to trace deeper levels of execution.
 | 
			
		||||
	fn subtracer(&self) -> Self where Self: Sized;
 | 
			
		||||
 | 
			
		||||
	/// Consumes self and returns all traces.
 | 
			
		||||
	fn traces(self) -> Vec<Trace>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Nonoperative tracer. Does not trace anything.
 | 
			
		||||
pub struct NoopTracer;
 | 
			
		||||
 | 
			
		||||
impl Tracer for NoopTracer {
 | 
			
		||||
	fn prepare_trace_call(&self, _: &ActionParams) -> Option<TraceCall> {
 | 
			
		||||
		None
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn prepare_trace_create(&self, _: &ActionParams) -> Option<TraceCreate> {
 | 
			
		||||
		None
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn prepare_trace_output(&self) -> Option<Bytes> {
 | 
			
		||||
		None
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn trace_call(&mut self, call: Option<TraceCall>, _: U256, output: Option<Bytes>, _: usize, _: Vec<Trace>,
 | 
			
		||||
				  _: bool) {
 | 
			
		||||
		assert!(call.is_none());
 | 
			
		||||
		assert!(output.is_none());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn trace_create(&mut self, create: Option<TraceCreate>, _: U256, code: Option<Bytes>, _: Address, _: usize, _: Vec<Trace>) {
 | 
			
		||||
		assert!(create.is_none());
 | 
			
		||||
		assert!(code.is_none());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn trace_failed_call(&mut self, call: Option<TraceCall>, _: usize, _: Vec<Trace>, _: bool) {
 | 
			
		||||
		assert!(call.is_none());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn trace_failed_create(&mut self, create: Option<TraceCreate>, _: usize, _: Vec<Trace>) {
 | 
			
		||||
		assert!(create.is_none());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn subtracer(&self) -> Self {
 | 
			
		||||
		NoopTracer
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn traces(self) -> Vec<Trace> {
 | 
			
		||||
		vec![]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls.
 | 
			
		||||
#[derive(Default)]
 | 
			
		||||
pub struct ExecutiveTracer {
 | 
			
		||||
	traces: Vec<Trace>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Tracer for ExecutiveTracer {
 | 
			
		||||
	fn prepare_trace_call(&self, params: &ActionParams) -> Option<TraceCall> {
 | 
			
		||||
		Some(TraceCall::from(params.clone()))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn prepare_trace_create(&self, params: &ActionParams) -> Option<TraceCreate> {
 | 
			
		||||
		Some(TraceCreate::from(params.clone()))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn prepare_trace_output(&self) -> Option<Bytes> {
 | 
			
		||||
		Some(vec![])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn trace_call(&mut self, call: Option<TraceCall>, gas_used: U256, output: Option<Bytes>, depth: usize, subs:
 | 
			
		||||
				  Vec<Trace>, delegate_call: bool) {
 | 
			
		||||
		// don't trace if it's DELEGATECALL or CALLCODE.
 | 
			
		||||
		if delegate_call {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		let trace = Trace {
 | 
			
		||||
			depth: depth,
 | 
			
		||||
			subs: subs,
 | 
			
		||||
			action: TraceAction::Call(call.expect("Trace call expected to be Some.")),
 | 
			
		||||
			result: TraceResult::Call(TraceCallResult {
 | 
			
		||||
				gas_used: gas_used,
 | 
			
		||||
				output: output.expect("Trace call output expected to be Some.")
 | 
			
		||||
			})
 | 
			
		||||
		};
 | 
			
		||||
		self.traces.push(trace);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn trace_create(&mut self, create: Option<TraceCreate>, gas_used: U256, code: Option<Bytes>, address: Address, depth: usize, subs: Vec<Trace>) {
 | 
			
		||||
		let trace = Trace {
 | 
			
		||||
			depth: depth,
 | 
			
		||||
			subs: subs,
 | 
			
		||||
			action: TraceAction::Create(create.expect("Trace create expected to be Some.")),
 | 
			
		||||
			result: TraceResult::Create(TraceCreateResult {
 | 
			
		||||
				gas_used: gas_used,
 | 
			
		||||
				code: code.expect("Trace create code expected to be Some."),
 | 
			
		||||
				address: address
 | 
			
		||||
			})
 | 
			
		||||
		};
 | 
			
		||||
		self.traces.push(trace);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn trace_failed_call(&mut self, call: Option<TraceCall>, depth: usize, subs: Vec<Trace>, delegate_call: bool) {
 | 
			
		||||
		// don't trace if it's DELEGATECALL or CALLCODE.
 | 
			
		||||
		if delegate_call {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		let trace = Trace {
 | 
			
		||||
			depth: depth,
 | 
			
		||||
			subs: subs,
 | 
			
		||||
			action: TraceAction::Call(call.expect("Trace call expected to be Some.")),
 | 
			
		||||
			result: TraceResult::FailedCall,
 | 
			
		||||
		};
 | 
			
		||||
		self.traces.push(trace);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn trace_failed_create(&mut self, create: Option<TraceCreate>, depth: usize, subs: Vec<Trace>) {
 | 
			
		||||
		let trace = Trace {
 | 
			
		||||
			depth: depth,
 | 
			
		||||
			subs: subs,
 | 
			
		||||
			action: TraceAction::Create(create.expect("Trace create expected to be Some.")),
 | 
			
		||||
			result: TraceResult::FailedCreate,
 | 
			
		||||
		};
 | 
			
		||||
		self.traces.push(trace);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn subtracer(&self) -> Self {
 | 
			
		||||
		ExecutiveTracer::default()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn traces(self) -> Vec<Trace> {
 | 
			
		||||
		self.traces
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -17,6 +17,26 @@
 | 
			
		||||
//! Tracing datatypes.
 | 
			
		||||
use common::*;
 | 
			
		||||
 | 
			
		||||
/// TraceCall result.
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Default)]
 | 
			
		||||
pub struct TraceCallResult {
 | 
			
		||||
	/// Gas used by call.
 | 
			
		||||
	pub gas_used: U256,
 | 
			
		||||
	/// Call Output.
 | 
			
		||||
	pub output: Bytes,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// TraceCreate result.
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
pub struct TraceCreateResult {
 | 
			
		||||
	/// Gas used by create.
 | 
			
		||||
	pub gas_used: U256,
 | 
			
		||||
	/// Code of the newly created contract.
 | 
			
		||||
	pub code: Bytes,
 | 
			
		||||
	/// Address of the newly created contract.
 | 
			
		||||
	pub address: Address,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Description of a _call_ action, either a `CALL` operation or a message transction.
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
pub struct TraceCall {
 | 
			
		||||
@ -30,8 +50,18 @@ pub struct TraceCall {
 | 
			
		||||
	pub gas: U256,
 | 
			
		||||
	/// The input data provided to the call.
 | 
			
		||||
	pub input: Bytes,
 | 
			
		||||
	/// The result of the operation; the gas used and the output data of the call.
 | 
			
		||||
	pub result: Option<(U256, Bytes)>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ActionParams> for TraceCall {
 | 
			
		||||
	fn from(p: ActionParams) -> Self {
 | 
			
		||||
		TraceCall {
 | 
			
		||||
			from: p.sender,
 | 
			
		||||
			to: p.address,
 | 
			
		||||
			value: p.value.value(),
 | 
			
		||||
			gas: p.gas,
 | 
			
		||||
			input: p.data.unwrap_or_else(Vec::new),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Description of a _create_ action, either a `CREATE` operation or a create transction.
 | 
			
		||||
@ -45,23 +75,41 @@ pub struct TraceCreate {
 | 
			
		||||
	pub gas: U256,
 | 
			
		||||
	/// The init code.
 | 
			
		||||
	pub init: Bytes,
 | 
			
		||||
	/// The result of the operation; tuple of the gas used, the address of the newly created account and its code.
 | 
			
		||||
	/// NOTE: Presently failed operations are not reported so this will always be `Some`.
 | 
			
		||||
	pub result: Option<(U256, Address, Bytes)>,
 | 
			
		||||
//	pub output: Bytes,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ActionParams> for TraceCreate {
 | 
			
		||||
	fn from(p: ActionParams) -> Self {
 | 
			
		||||
		TraceCreate {
 | 
			
		||||
			from: p.sender,
 | 
			
		||||
			value: p.value.value(),
 | 
			
		||||
			gas: p.gas,
 | 
			
		||||
			init: p.code.unwrap_or_else(Vec::new),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Description of an action that we trace; will be either a call or a create.
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
pub enum TraceAction {
 | 
			
		||||
	/// Action isn't yet known.
 | 
			
		||||
	Unknown,
 | 
			
		||||
	/// It's a call action.
 | 
			
		||||
	Call(TraceCall),
 | 
			
		||||
	/// It's a create action.
 | 
			
		||||
	Create(TraceCreate),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The result of the performed action.
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
pub enum TraceResult {
 | 
			
		||||
	/// Successful call action result.
 | 
			
		||||
	Call(TraceCallResult),
 | 
			
		||||
	/// Successful create action result.
 | 
			
		||||
	Create(TraceCreateResult),
 | 
			
		||||
	/// Failed call.
 | 
			
		||||
	FailedCall,
 | 
			
		||||
	/// Failed create.
 | 
			
		||||
	FailedCreate,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, PartialEq)]
 | 
			
		||||
/// A trace; includes a description of the action being traced and sub traces of each interior action.
 | 
			
		||||
pub struct Trace {
 | 
			
		||||
@ -72,40 +120,6 @@ pub struct Trace {
 | 
			
		||||
	pub action: TraceAction,
 | 
			
		||||
	/// The sub traces for each interior action performed as part of this call.
 | 
			
		||||
	pub subs: Vec<Trace>,
 | 
			
		||||
	/// The result of the performed action.
 | 
			
		||||
	pub result: TraceResult,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for Trace {
 | 
			
		||||
	fn default() -> Trace {
 | 
			
		||||
		Trace {
 | 
			
		||||
			depth: 0,
 | 
			
		||||
			action: TraceAction::Unknown,
 | 
			
		||||
			subs: vec![],
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TraceAction {
 | 
			
		||||
	/// Compose a `TraceAction` from an `ActionParams`, knowing that the action is a call.
 | 
			
		||||
	pub fn from_call(p: &ActionParams) -> TraceAction {
 | 
			
		||||
		TraceAction::Call(TraceCall {
 | 
			
		||||
			from: p.sender.clone(),
 | 
			
		||||
			to: p.address.clone(),
 | 
			
		||||
			value: p.value.value(),
 | 
			
		||||
			gas: p.gas,
 | 
			
		||||
			input: p.data.clone().unwrap_or_else(Vec::new),
 | 
			
		||||
			result: None,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Compose a `TraceAction` from an `ActionParams`, knowing that the action is a create.
 | 
			
		||||
	pub fn from_create(p: &ActionParams) -> TraceAction {
 | 
			
		||||
		TraceAction::Create(TraceCreate {
 | 
			
		||||
			from: p.sender.clone(),
 | 
			
		||||
			value: p.value.value(),
 | 
			
		||||
			gas: p.gas,
 | 
			
		||||
			init: p.code.clone().unwrap_or_else(Vec::new),
 | 
			
		||||
			result: None,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -34,11 +34,13 @@ pub trait IpcConfig {
 | 
			
		||||
	fn api_version() -> Version {
 | 
			
		||||
		Version::parse("1.0.0").unwrap()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Current ipc protocol version
 | 
			
		||||
	/// Should be increased only if signature of system methods changes
 | 
			
		||||
	fn protocol_version() -> Version {
 | 
			
		||||
		Version::parse("1.0.0").unwrap()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Default handshake requires exact versions match
 | 
			
		||||
	fn handshake(handshake: &Handshake) -> bool {
 | 
			
		||||
		handshake.protocol_version == Self::protocol_version() &&
 | 
			
		||||
 | 
			
		||||
@ -36,6 +36,7 @@ extern crate daemonize;
 | 
			
		||||
extern crate time;
 | 
			
		||||
extern crate number_prefix;
 | 
			
		||||
extern crate rpassword;
 | 
			
		||||
extern crate semver;
 | 
			
		||||
 | 
			
		||||
// for price_info.rs
 | 
			
		||||
#[macro_use] extern crate hyper;
 | 
			
		||||
@ -71,6 +72,7 @@ use rpc::Server as RpcServer;
 | 
			
		||||
use webapp::Listening as WebappServer;
 | 
			
		||||
 | 
			
		||||
mod price_info;
 | 
			
		||||
mod upgrade;
 | 
			
		||||
 | 
			
		||||
fn die_with_message(msg: &str) -> ! {
 | 
			
		||||
	println!("ERROR: {}", msg);
 | 
			
		||||
@ -785,6 +787,17 @@ fn die_with_io_error(e: std::io::Error) -> ! {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
	match ::upgrade::upgrade() {
 | 
			
		||||
		Ok(upgrades_applied) => {
 | 
			
		||||
			if upgrades_applied > 0 {
 | 
			
		||||
				println!("Executed {} upgrade scripts - ok", upgrades_applied);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		Err(e) => {
 | 
			
		||||
			die!("Error upgrading parity data: {:?}", e);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Configuration::parse().execute();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										126
									
								
								parity/upgrade.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								parity/upgrade.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,126 @@
 | 
			
		||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
//! Parity upgrade logic
 | 
			
		||||
 | 
			
		||||
use semver::Version;
 | 
			
		||||
use std::collections::*;
 | 
			
		||||
use std::fs::File;
 | 
			
		||||
use std::env;
 | 
			
		||||
use std::io::{Read, Write};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum Error {
 | 
			
		||||
	CannotLockVersionFile,
 | 
			
		||||
	CannotUpdateVersionFile,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const CURRENT_VERSION: &'static str = env!("CARGO_PKG_VERSION");
 | 
			
		||||
 | 
			
		||||
#[derive(Hash, PartialEq, Eq)]
 | 
			
		||||
struct UpgradeKey {
 | 
			
		||||
	pub old_version: Version,
 | 
			
		||||
	pub new_version: Version,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UpgradeList = HashMap<UpgradeKey, fn() -> Result<(), Error>>;
 | 
			
		||||
 | 
			
		||||
impl UpgradeKey {
 | 
			
		||||
	// given the following config exist
 | 
			
		||||
	// ver.lock 1.1 (`previous_version`)
 | 
			
		||||
	//
 | 
			
		||||
	//  current_version 1.4 (`current_version`)
 | 
			
		||||
	//
 | 
			
		||||
	//
 | 
			
		||||
	//upgrades (set of `UpgradeKey`)
 | 
			
		||||
	//	1.0 -> 1.1 (u1)
 | 
			
		||||
	//	1.1 -> 1.2 (u2)
 | 
			
		||||
	//	1.2 -> 1.3 (u3)
 | 
			
		||||
	//	1.3 -> 1.4 (u4)
 | 
			
		||||
	//	1.4 -> 1.5 (u5)
 | 
			
		||||
	//
 | 
			
		||||
	// then the following upgrades should be applied:
 | 
			
		||||
	// u2, u3, u4
 | 
			
		||||
	fn is_applicable(&self, previous_version: &Version, current_version: &Version) -> bool {
 | 
			
		||||
		self.old_version >= *previous_version && self.new_version <= *current_version
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// dummy upgrade (remove when the first one is in)
 | 
			
		||||
fn dummy_upgrade() -> Result<(), Error> {
 | 
			
		||||
	println!("Adding ver.lock");
 | 
			
		||||
	Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn push_updrades(upgrades: &mut UpgradeList)
 | 
			
		||||
{
 | 
			
		||||
	// dummy upgrade (remove when the first one is in)
 | 
			
		||||
	upgrades.insert(
 | 
			
		||||
		UpgradeKey { old_version: Version::parse("0.9.0").unwrap(), new_version: Version::parse("1.0.0").unwrap() },
 | 
			
		||||
		dummy_upgrade);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn upgrade_from_version(previous_version: &Version) -> Result<usize, Error> {
 | 
			
		||||
	let mut upgrades = HashMap::new();
 | 
			
		||||
	push_updrades(&mut upgrades);
 | 
			
		||||
 | 
			
		||||
	let current_version = Version::parse(CURRENT_VERSION).unwrap();
 | 
			
		||||
 | 
			
		||||
	let mut count = 0;
 | 
			
		||||
	for upgrade_key in upgrades.keys() {
 | 
			
		||||
		if upgrade_key.is_applicable(previous_version, ¤t_version) {
 | 
			
		||||
			let upgrade_script = upgrades[upgrade_key];
 | 
			
		||||
			try!(upgrade_script());
 | 
			
		||||
			count = count + 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	Ok(count)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn with_locked_version<F>(script: F) -> Result<usize, Error>
 | 
			
		||||
	where F: Fn(&Version) -> Result<usize, Error>
 | 
			
		||||
{
 | 
			
		||||
	let mut path = env::home_dir().expect("Applications should have a home dir");
 | 
			
		||||
	path.push(".parity");
 | 
			
		||||
	path.push("ver.lock");
 | 
			
		||||
 | 
			
		||||
	let version =
 | 
			
		||||
		File::open(&path).ok().and_then(|ref mut file|
 | 
			
		||||
			{
 | 
			
		||||
				let mut version_string = String::new();
 | 
			
		||||
				file.read_to_string(&mut version_string)
 | 
			
		||||
					.ok()
 | 
			
		||||
					.and_then(|_| Version::parse(&version_string).ok())
 | 
			
		||||
			})
 | 
			
		||||
			.unwrap_or_else(|| Version::parse("0.9.0").unwrap());
 | 
			
		||||
 | 
			
		||||
	let script_result = {
 | 
			
		||||
		let mut lock = try!(File::create(&path).map_err(|_| Error::CannotLockVersionFile));
 | 
			
		||||
		let result = script(&version);
 | 
			
		||||
 | 
			
		||||
		let written_version = Version::parse(CURRENT_VERSION).unwrap();
 | 
			
		||||
		try!(lock.write_all(written_version.to_string().as_bytes()).map_err(|_| Error::CannotUpdateVersionFile));
 | 
			
		||||
		result
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	script_result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn upgrade() -> Result<usize, Error> {
 | 
			
		||||
	with_locked_version(|ver| {
 | 
			
		||||
		upgrade_from_version(ver)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user