diff --git a/src/executor/mod.rs b/src/executor/mod.rs
index 8dee8150c..190ec4aa7 100644
--- a/src/executor/mod.rs
+++ b/src/executor/mod.rs
@@ -5,4 +5,7 @@
 
 mod stack;
 
-pub use self::stack::{StackExecutor, MemoryStackState, StackState, StackSubstateMetadata, StackExitKind};
+pub use self::stack::{
+	StackExecutor, MemoryStackState, StackState, StackSubstateMetadata, StackExitKind,
+	HookedStackExecutor, Hook,
+};
diff --git a/src/executor/stack/hooked.rs b/src/executor/stack/hooked.rs
new file mode 100644
index 000000000..3a22c4a43
--- /dev/null
+++ b/src/executor/stack/hooked.rs
@@ -0,0 +1,377 @@
+use core::convert::Infallible;
+use primitive_types::{U256, H256, H160};
+use sha3::{Keccak256, Digest};
+use super::{StackExecutor, StackState, StackExitKind};
+use crate::{
+	ExitReason, Runtime, ExitError, Stack, Opcode, Capture, Handler, Transfer,
+	Context, CreateScheme, ExitSucceed, Config, gasometer,
+};
+
+/// Can be injected in `StackExecutor` to inspect contract execution step by
+/// step.
+pub trait Hook {
+	/// Called before the execution of a context.
+	fn before_loop<'config, S: StackState<'config>>(
+		&mut self,
+		executor: &StackExecutor<'config, S>,
+		runtime: &Runtime,
+	);
+
+	/// Called before each step.
+	fn before_step<'config, S: StackState<'config>>(
+		&mut self,
+		executor: &StackExecutor<'config, S>,
+		runtime: &Runtime,
+	);
+
+	/// Called after each step. Will not be called if runtime exited
+	/// from the loop.
+	fn after_step<'config, S: StackState<'config>>(
+		&mut self,
+		executor: &StackExecutor<'config, S>,
+		runtime: &Runtime,
+	);
+
+	/// Called after the execution of a context.
+	fn after_loop<'config, S: StackState<'config>>(
+		&mut self,
+		executor: &StackExecutor<'config, S>,
+		runtime: &Runtime,
+		reason: &ExitReason,
+	);
+}
+
+impl Hook for () {
+	fn before_loop<'config, S: StackState<'config>>(
+		&mut self,
+		_executor: &StackExecutor<'config, S>,
+		_runtime: &Runtime,
+	) {
+	}
+
+	fn before_step<'config, S: StackState<'config>>(
+		&mut self,
+		_executor: &StackExecutor<'config, S>,
+		_runtime: &Runtime,
+	) {
+	}
+
+	fn after_step<'config, S: StackState<'config>>(
+		&mut self,
+		_executor: &StackExecutor<'config, S>,
+		_runtime: &Runtime,
+	) {
+	}
+
+	fn after_loop<'config, S: StackState<'config>>(
+		&mut self,
+		_executor: &StackExecutor<'config, S>,
+		_runtime: &Runtime,
+		_reason: &ExitReason,
+	) {
+	}
+}
+
+fn hooked_execute<'config, S: StackState<'config>, H: Hook>(
+	executor: &mut StackExecutor<'config, S>,
+	runtime: &mut Runtime,
+	hook: &mut H,
+) -> ExitReason {
+	hook.before_loop(executor, runtime);
+
+	let reason = loop {
+		hook.before_step(executor, runtime);
+
+		match runtime.step(executor) {
+			Ok(_) => {}
+			Err(Capture::Exit(s)) => break s,
+			Err(Capture::Trap(_)) => unreachable!("Trap is Infallible"),
+		}
+
+		hook.after_step(executor, runtime);
+	};
+
+	hook.after_loop(executor, runtime, &reason);
+
+	reason
+}
+
+pub struct HookedStackExecutor<'config, S, H> {
+	executor: StackExecutor<'config, S>,
+	hook: H,
+}
+
+impl<'config, S: StackState<'config>, H: Hook> HookedStackExecutor<'config, S, H> {
+	/// Create a new stack-based executor.
+	pub fn new(state: S, config: &'config Config, hook: H) -> Self {
+		Self {
+			executor: StackExecutor::new(state, config),
+			hook,
+		}
+	}
+
+	/// Create a new stack-based executor with given precompiles.
+	pub fn new_with_precompile(
+		state: S,
+		config: &'config Config,
+		hook: H,
+		precompile: fn(
+			H160,
+			&[u8],
+			Option<u64>,
+			&Context,
+		) -> Option<Result<(ExitSucceed, Vec<u8>, u64), ExitError>>,
+	) -> Self {
+		Self {
+			executor: StackExecutor::new_with_precompile(state, config, precompile),
+			hook,
+		}
+	}
+
+	/// Return a reference of the Config.
+	pub fn config(&self) -> &'config Config {
+		self.executor.config()
+	}
+
+	pub fn state(&self) -> &S {
+		self.executor.state()
+	}
+
+	pub fn state_mut(&mut self) -> &mut S {
+		self.executor.state_mut()
+	}
+
+	pub fn into_state(self) -> S {
+		self.executor.into_state()
+	}
+
+	/// Create a substate executor from the current executor.
+	pub fn enter_substate(&mut self, gas_limit: u64, is_static: bool) {
+		self.executor.enter_substate(gas_limit, is_static)
+	}
+
+	/// Exit a substate. Panic if it results an empty substate stack.
+	pub fn exit_substate(&mut self, kind: StackExitKind) -> Result<(), ExitError> {
+		self.executor.exit_substate(kind)
+	}
+
+	/// Execute the runtime until it returns.
+	pub fn execute(&mut self, runtime: &mut Runtime) -> ExitReason {
+		hooked_execute(&mut self.executor, runtime, &mut self.hook)
+	}
+
+	/// Get remaining gas.
+	pub fn gas(&self) -> u64 {
+		self.executor.gas()
+	}
+
+	/// Execute a `CREATE` transaction.
+	pub fn transact_create(
+		&mut self,
+		caller: H160,
+		value: U256,
+		init_code: Vec<u8>,
+		gas_limit: u64,
+	) -> ExitReason {
+		let transaction_cost = gasometer::create_transaction_cost(&init_code);
+		match self.executor.state.metadata_mut().gasometer.record_transaction(transaction_cost) {
+			Ok(()) => (),
+			Err(e) => return e.into(),
+		}
+
+		let hook = &mut self.hook;
+		match super::create_inner(
+			&mut self.executor,
+			caller,
+			CreateScheme::Legacy { caller },
+			value,
+			init_code,
+			Some(gas_limit),
+			false,
+			|executor, runtime| {
+				hooked_execute(executor, runtime, hook)
+			}
+		) {
+			Capture::Exit((s, _, _)) => s,
+			Capture::Trap(_) => unreachable!(),
+		}
+	}
+
+	/// Execute a `CREATE2` transaction.
+	pub fn transact_create2(
+		&mut self,
+		caller: H160,
+		value: U256,
+		init_code: Vec<u8>,
+		salt: H256,
+		gas_limit: u64,
+	) -> ExitReason {
+		let transaction_cost = gasometer::create_transaction_cost(&init_code);
+		match self.executor.state.metadata_mut().gasometer.record_transaction(transaction_cost) {
+			Ok(()) => (),
+			Err(e) => return e.into(),
+		}
+		let code_hash = H256::from_slice(Keccak256::digest(&init_code).as_slice());
+
+		let hook = &mut self.hook;
+		match super::create_inner(
+			&mut self.executor,
+			caller,
+			CreateScheme::Create2 { caller, code_hash, salt },
+			value,
+			init_code,
+			Some(gas_limit),
+			false,
+			|executor, runtime| {
+				hooked_execute(executor, runtime, hook)
+			}
+		) {
+			Capture::Exit((s, _, _)) => s,
+			Capture::Trap(_) => unreachable!(),
+		}
+	}
+
+	/// Execute a `CALL` transaction.
+	pub fn transact_call(
+		&mut self,
+		caller: H160,
+		address: H160,
+		value: U256,
+		data: Vec<u8>,
+		gas_limit: u64,
+	) -> (ExitReason, Vec<u8>) {
+		let transaction_cost = gasometer::call_transaction_cost(&data);
+		match self.executor.state.metadata_mut().gasometer.record_transaction(transaction_cost) {
+			Ok(()) => (),
+			Err(e) => return (e.into(), Vec::new()),
+		}
+
+		self.executor.state.inc_nonce(caller);
+
+		let context = Context {
+			caller,
+			address,
+			apparent_value: value,
+		};
+
+		let hook = &mut self.hook;
+		match super::call_inner(
+			&mut self.executor,
+			address,
+			Some(Transfer {
+				source: caller,
+				target: address,
+				value
+			}),
+			data,
+			Some(gas_limit),
+			false,
+			false,
+			false,
+			context,
+			|executor, runtime| {
+				hooked_execute(executor, runtime, hook)
+			}
+		) {
+			Capture::Exit((s, v)) => (s, v),
+			Capture::Trap(_) => unreachable!(),
+		}
+	}
+
+	/// Get used gas for the current executor, given the price.
+	pub fn used_gas(&self) -> u64 {
+		self.executor.used_gas()
+	}
+
+	/// Get fee needed for the current executor, given the price.
+	pub fn fee(&self, price: U256) -> U256 {
+		self.executor.fee(price)
+	}
+
+	/// Get account nonce.
+	pub fn nonce(&self, address: H160) -> U256 {
+		self.executor.nonce(address)
+	}
+
+	/// Get the create address from given scheme.
+	pub fn create_address(&self, scheme: CreateScheme) -> H160 {
+		self.executor.create_address(scheme)
+	}
+}
+
+impl<'config, S: StackState<'config>, H: Hook> Handler for HookedStackExecutor<'config, S, H> {
+	type CreateInterrupt = Infallible;
+	type CreateFeedback = Infallible;
+	type CallInterrupt = Infallible;
+	type CallFeedback = Infallible;
+
+	fn balance(&self, address: H160) -> U256 { self.executor.balance(address) }
+	fn code_size(&self, address: H160) -> U256 { self.executor.code_size(address) }
+	fn code_hash(&self, address: H160) -> H256 { self.executor.code_hash(address) }
+	fn code(&self, address: H160) -> Vec<u8> { self.executor.code(address) }
+	fn storage(&self, address: H160, index: H256) -> H256 { self.executor.storage(address, index) }
+	fn original_storage(&self, address: H160, index: H256) -> H256 { self.executor.original_storage(address, index) }
+	fn exists(&self, address: H160) -> bool { self.executor.exists(address) }
+	fn gas_left(&self) -> U256 { self.executor.gas_left() }
+	fn gas_price(&self) -> U256 { self.executor.gas_price() }
+	fn origin(&self) -> H160 { self.executor.origin() }
+	fn block_hash(&self, number: U256) -> H256 { self.executor.block_hash(number) }
+	fn block_number(&self) -> U256 { self.executor.block_number() }
+	fn block_coinbase(&self) -> H160 { self.executor.block_coinbase() }
+	fn block_timestamp(&self) -> U256 { self.executor.block_timestamp() }
+	fn block_difficulty(&self) -> U256 { self.executor.block_difficulty() }
+	fn block_gas_limit(&self) -> U256 { self.executor.block_gas_limit() }
+	fn chain_id(&self) -> U256 { self.executor.chain_id() }
+	fn deleted(&self, address: H160) -> bool { self.executor.deleted(address) }
+
+	fn set_storage(&mut self, address: H160, index: H256, value: H256) -> Result<(), ExitError> {
+		self.executor.set_storage(address, index, value)
+	}
+
+	fn log(&mut self, address: H160, topics: Vec<H256>, data: Vec<u8>) -> Result<(), ExitError> {
+		self.executor.log(address, topics, data)
+	}
+
+	fn mark_delete(&mut self, address: H160, target: H160) -> Result<(), ExitError> {
+		self.executor.mark_delete(address, target)
+	}
+
+	fn create(
+		&mut self,
+		caller: H160,
+		scheme: CreateScheme,
+		value: U256,
+		init_code: Vec<u8>,
+		target_gas: Option<u64>,
+	) -> Capture<(ExitReason, Option<H160>, Vec<u8>), Self::CreateInterrupt> {
+		let hook = &mut self.hook;
+		super::create_inner(&mut self.executor, caller, scheme, value, init_code, target_gas, true, |executor, runtime| {
+			hooked_execute(executor, runtime, hook)
+		})
+	}
+
+	fn call(
+		&mut self,
+		code_address: H160,
+		transfer: Option<Transfer>,
+		input: Vec<u8>,
+		target_gas: Option<u64>,
+		is_static: bool,
+		context: Context,
+	) -> Capture<(ExitReason, Vec<u8>), Self::CallInterrupt> {
+		let hook = &mut self.hook;
+		super::call_inner(&mut self.executor, code_address, transfer, input, target_gas, is_static, true, true, context, |executor, runtime| {
+			hooked_execute(executor, runtime, hook)
+		})
+	}
+
+	#[inline]
+	fn pre_validate(
+		&mut self,
+		context: &Context,
+		opcode: Opcode,
+		stack: &Stack,
+	) -> Result<(), ExitError> {
+		self.executor.pre_validate(context, opcode, stack)
+	}
+}
diff --git a/src/executor/stack/mod.rs b/src/executor/stack/mod.rs
index 8ff7ac508..4af93ad74 100644
--- a/src/executor/stack/mod.rs
+++ b/src/executor/stack/mod.rs
@@ -1,6 +1,8 @@
 mod state;
+mod hooked;
 
 pub use self::state::{MemoryStackSubstate, MemoryStackState, StackState};
+pub use self::hooked::{HookedStackExecutor, Hook};
 
 use core::{convert::Infallible, cmp::min};
 use alloc::{rc::Rc, vec::Vec};
@@ -104,13 +106,6 @@ impl<'config, S: StackState<'config>> StackExecutor<'config, S> {
 		Self::new_with_precompile(state, config, no_precompile)
 	}
 
-	/// Return a reference of the Config.
-	pub fn config(
-		&self
-	) -> &'config Config {
-		self.config
-	}
-
 	/// Create a new stack-based executor with given precompiles.
 	pub fn new_with_precompile(
 		state: S,
@@ -124,6 +119,11 @@ impl<'config, S: StackState<'config>> StackExecutor<'config, S> {
 		}
 	}
 
+	/// Return a reference of the Config.
+	pub fn config(&self) -> &'config Config {
+		self.config
+	}
+
 	pub fn state(&self) -> &S {
 		&self.state
 	}
@@ -184,13 +184,17 @@ impl<'config, S: StackState<'config>> StackExecutor<'config, S> {
 			Err(e) => return e.into(),
 		}
 
-		match self.create_inner(
+		match create_inner(
+			self,
 			caller,
 			CreateScheme::Legacy { caller },
 			value,
 			init_code,
 			Some(gas_limit),
 			false,
+			|executor, runtime| {
+				executor.execute(runtime)
+			}
 		) {
 			Capture::Exit((s, _, _)) => s,
 			Capture::Trap(_) => unreachable!(),
@@ -213,13 +217,17 @@ impl<'config, S: StackState<'config>> StackExecutor<'config, S> {
 		}
 		let code_hash = H256::from_slice(Keccak256::digest(&init_code).as_slice());
 
-		match self.create_inner(
+		match create_inner(
+			self,
 			caller,
 			CreateScheme::Create2 { caller, code_hash, salt },
 			value,
 			init_code,
 			Some(gas_limit),
 			false,
+			|executor, runtime| {
+				executor.execute(runtime)
+			}
 		) {
 			Capture::Exit((s, _, _)) => s,
 			Capture::Trap(_) => unreachable!(),
@@ -249,30 +257,38 @@ impl<'config, S: StackState<'config>> StackExecutor<'config, S> {
 			apparent_value: value,
 		};
 
-		match self.call_inner(address, Some(Transfer {
-			source: caller,
-			target: address,
-			value
-		}), data, Some(gas_limit), false, false, false, context) {
+		match call_inner(
+			self,
+			address,
+			Some(Transfer {
+				source: caller,
+				target: address,
+				value
+			}),
+			data,
+			Some(gas_limit),
+			false,
+			false,
+			false,
+			context,
+			|executor, runtime| {
+				executor.execute(runtime)
+			}
+		) {
 			Capture::Exit((s, v)) => (s, v),
 			Capture::Trap(_) => unreachable!(),
 		}
 	}
 
 	/// Get used gas for the current executor, given the price.
-	pub fn used_gas(
-		&self,
-	) -> u64 {
+	pub fn used_gas(&self) -> u64 {
 		self.state.metadata().gasometer.total_used_gas() -
 			min(self.state.metadata().gasometer.total_used_gas() / 2,
 				self.state.metadata().gasometer.refunded_gas() as u64)
 	}
 
 	/// Get fee needed for the current executor, given the price.
-	pub fn fee(
-		&self,
-		price: U256,
-	) -> U256 {
+	pub fn fee(&self, price: U256) -> U256 {
 		let used_gas = self.used_gas();
 		U256::from(used_gas) * price
 	}
@@ -305,268 +321,274 @@ impl<'config, S: StackState<'config>> StackExecutor<'config, S> {
 			},
 		}
 	}
+}
 
-	fn create_inner(
-		&mut self,
-		caller: H160,
-		scheme: CreateScheme,
-		value: U256,
-		init_code: Vec<u8>,
-		target_gas: Option<u64>,
-		take_l64: bool,
-	) -> Capture<(ExitReason, Option<H160>, Vec<u8>), Infallible> {
-		macro_rules! try_or_fail {
-			( $e:expr ) => {
-				match $e {
-					Ok(v) => v,
-					Err(e) => return Capture::Exit((e.into(), None, Vec::new())),
-				}
+fn create_inner<'config, S: StackState<'config>, FExecute>(
+	executor: &mut StackExecutor<'config, S>,
+	caller: H160,
+	scheme: CreateScheme,
+	value: U256,
+	init_code: Vec<u8>,
+	target_gas: Option<u64>,
+	take_l64: bool,
+	fexecute: FExecute,
+) -> Capture<(ExitReason, Option<H160>, Vec<u8>), Infallible> where
+	FExecute: FnOnce(&mut StackExecutor<'config, S>, &mut Runtime) -> ExitReason,
+{
+	macro_rules! try_or_fail {
+		( $e:expr ) => {
+			match $e {
+				Ok(v) => v,
+				Err(e) => return Capture::Exit((e.into(), None, Vec::new())),
 			}
 		}
+	}
 
-		fn l64(gas: u64) -> u64 {
-			gas - gas / 64
-		}
+	fn l64(gas: u64) -> u64 {
+		gas - gas / 64
+	}
 
-		if let Some(depth) = self.state.metadata().depth {
-			if depth > self.config.call_stack_limit {
-				return Capture::Exit((ExitError::CallTooDeep.into(), None, Vec::new()))
-			}
+	if let Some(depth) = executor.state.metadata().depth {
+		if depth > executor.config.call_stack_limit {
+			return Capture::Exit((ExitError::CallTooDeep.into(), None, Vec::new()))
 		}
+	}
 
-		if self.balance(caller) < value {
-			return Capture::Exit((ExitError::OutOfFund.into(), None, Vec::new()))
-		}
+	if executor.balance(caller) < value {
+		return Capture::Exit((ExitError::OutOfFund.into(), None, Vec::new()))
+	}
 
-		let after_gas = if take_l64 && self.config.call_l64_after_gas {
-			if self.config.estimate {
-				let initial_after_gas = self.state.metadata().gasometer.gas();
-				let diff = initial_after_gas - l64(initial_after_gas);
-				try_or_fail!(self.state.metadata_mut().gasometer.record_cost(diff));
-				self.state.metadata().gasometer.gas()
-			} else {
-				l64(self.state.metadata().gasometer.gas())
-			}
+	let after_gas = if take_l64 && executor.config.call_l64_after_gas {
+		if executor.config.estimate {
+			let initial_after_gas = executor.state.metadata().gasometer.gas();
+			let diff = initial_after_gas - l64(initial_after_gas);
+			try_or_fail!(executor.state.metadata_mut().gasometer.record_cost(diff));
+			executor.state.metadata().gasometer.gas()
 		} else {
-			self.state.metadata().gasometer.gas()
-		};
-
-		let target_gas = target_gas.unwrap_or(after_gas);
+			l64(executor.state.metadata().gasometer.gas())
+		}
+	} else {
+		executor.state.metadata().gasometer.gas()
+	};
 
-		let gas_limit = min(after_gas, target_gas);
-		try_or_fail!(
-			self.state.metadata_mut().gasometer.record_cost(gas_limit)
-		);
+	let target_gas = target_gas.unwrap_or(after_gas);
 
-		let address = self.create_address(scheme);
-		self.state.inc_nonce(caller);
+	let gas_limit = min(after_gas, target_gas);
+	try_or_fail!(
+		executor.state.metadata_mut().gasometer.record_cost(gas_limit)
+	);
 
-		self.enter_substate(gas_limit, false);
+	let address = executor.create_address(scheme);
+	executor.state.inc_nonce(caller);
 
-		{
-			if self.code_size(address) != U256::zero() {
-				let _ = self.exit_substate(StackExitKind::Failed);
-				return Capture::Exit((ExitError::CreateCollision.into(), None, Vec::new()))
-			}
-
-			if self.nonce(address) > U256::zero() {
-				let _ = self.exit_substate(StackExitKind::Failed);
-				return Capture::Exit((ExitError::CreateCollision.into(), None, Vec::new()))
-			}
+	executor.enter_substate(gas_limit, false);
 
-			self.state.reset_storage(address);
+	{
+		if executor.code_size(address) != U256::zero() {
+			let _ = executor.exit_substate(StackExitKind::Failed);
+			return Capture::Exit((ExitError::CreateCollision.into(), None, Vec::new()))
 		}
 
-		let context = Context {
-			address,
-			caller,
-			apparent_value: value,
-		};
-		let transfer = Transfer {
-			source: caller,
-			target: address,
-			value,
-		};
-		match self.state.transfer(transfer) {
-			Ok(()) => (),
-			Err(e) => {
-				let _ = self.exit_substate(StackExitKind::Reverted);
-				return Capture::Exit((ExitReason::Error(e), None, Vec::new()))
-			},
+		if executor.nonce(address) > U256::zero() {
+			let _ = executor.exit_substate(StackExitKind::Failed);
+			return Capture::Exit((ExitError::CreateCollision.into(), None, Vec::new()))
 		}
 
-		if self.config.create_increase_nonce {
-			self.state.inc_nonce(address);
-		}
-
-		let mut runtime = Runtime::new(
-			Rc::new(init_code),
-			Rc::new(Vec::new()),
-			context,
-			self.config,
-		);
-
-		let reason = self.execute(&mut runtime);
-		log::debug!(target: "evm", "Create execution using address {}: {:?}", address, reason);
-
-		match reason {
-			ExitReason::Succeed(s) => {
-				let out = runtime.machine().return_value();
-
-				if let Some(limit) = self.config.create_contract_limit {
-					if out.len() > limit {
-						self.state.metadata_mut().gasometer.fail();
-						let _ = self.exit_substate(StackExitKind::Failed);
-						return Capture::Exit((ExitError::CreateContractLimit.into(), None, Vec::new()))
-					}
+		executor.state.reset_storage(address);
+	}
+
+	let context = Context {
+		address,
+		caller,
+		apparent_value: value,
+	};
+	let transfer = Transfer {
+		source: caller,
+		target: address,
+		value,
+	};
+	match executor.state.transfer(transfer) {
+		Ok(()) => (),
+		Err(e) => {
+			let _ = executor.exit_substate(StackExitKind::Reverted);
+			return Capture::Exit((ExitReason::Error(e), None, Vec::new()))
+		},
+	}
+
+	if executor.config.create_increase_nonce {
+		executor.state.inc_nonce(address);
+	}
+
+	let mut runtime = Runtime::new(
+		Rc::new(init_code),
+		Rc::new(Vec::new()),
+		context,
+		executor.config,
+	);
+
+	let reason = fexecute(executor, &mut runtime);
+	log::debug!(target: "evm", "Create execution using address {}: {:?}", address, reason);
+
+	match reason {
+		ExitReason::Succeed(s) => {
+			let out = runtime.machine().return_value();
+
+			if let Some(limit) = executor.config.create_contract_limit {
+				if out.len() > limit {
+					executor.state.metadata_mut().gasometer.fail();
+					let _ = executor.exit_substate(StackExitKind::Failed);
+					return Capture::Exit((ExitError::CreateContractLimit.into(), None, Vec::new()))
 				}
+			}
 
-				match self.state.metadata_mut().gasometer.record_deposit(out.len()) {
-					Ok(()) => {
-						let e = self.exit_substate(StackExitKind::Succeeded);
-						self.state.set_code(address, out);
-						try_or_fail!(e);
-						Capture::Exit((ExitReason::Succeed(s), Some(address), Vec::new()))
-					},
-					Err(e) => {
-						let _ = self.exit_substate(StackExitKind::Failed);
-						Capture::Exit((ExitReason::Error(e), None, Vec::new()))
-					},
-				}
-			},
-			ExitReason::Error(e) => {
-				self.state.metadata_mut().gasometer.fail();
-				let _ = self.exit_substate(StackExitKind::Failed);
-				Capture::Exit((ExitReason::Error(e), None, Vec::new()))
-			},
-			ExitReason::Revert(e) => {
-				let _ = self.exit_substate(StackExitKind::Reverted);
-				Capture::Exit((ExitReason::Revert(e), None, runtime.machine().return_value()))
-			},
-			ExitReason::Fatal(e) => {
-				self.state.metadata_mut().gasometer.fail();
-				let _ = self.exit_substate(StackExitKind::Failed);
-				Capture::Exit((ExitReason::Fatal(e), None, Vec::new()))
-			},
-		}
+			match executor.state.metadata_mut().gasometer.record_deposit(out.len()) {
+				Ok(()) => {
+					let e = executor.exit_substate(StackExitKind::Succeeded);
+					executor.state.set_code(address, out);
+					try_or_fail!(e);
+					Capture::Exit((ExitReason::Succeed(s), Some(address), Vec::new()))
+				},
+				Err(e) => {
+					let _ = executor.exit_substate(StackExitKind::Failed);
+					Capture::Exit((ExitReason::Error(e), None, Vec::new()))
+				},
+			}
+		},
+		ExitReason::Error(e) => {
+			executor.state.metadata_mut().gasometer.fail();
+			let _ = executor.exit_substate(StackExitKind::Failed);
+			Capture::Exit((ExitReason::Error(e), None, Vec::new()))
+		},
+		ExitReason::Revert(e) => {
+			let _ = executor.exit_substate(StackExitKind::Reverted);
+			Capture::Exit((ExitReason::Revert(e), None, runtime.machine().return_value()))
+		},
+		ExitReason::Fatal(e) => {
+			executor.state.metadata_mut().gasometer.fail();
+			let _ = executor.exit_substate(StackExitKind::Failed);
+			Capture::Exit((ExitReason::Fatal(e), None, Vec::new()))
+		},
 	}
+}
 
-	fn call_inner(
-		&mut self,
-		code_address: H160,
-		transfer: Option<Transfer>,
-		input: Vec<u8>,
-		target_gas: Option<u64>,
-		is_static: bool,
-		take_l64: bool,
-		take_stipend: bool,
-		context: Context,
-	) -> Capture<(ExitReason, Vec<u8>), Infallible> {
-		macro_rules! try_or_fail {
-			( $e:expr ) => {
-				match $e {
-					Ok(v) => v,
-					Err(e) => return Capture::Exit((e.into(), Vec::new())),
-				}
+fn call_inner<'config, S: StackState<'config>, FExecute>(
+	executor: &mut StackExecutor<'config, S>,
+	code_address: H160,
+	transfer: Option<Transfer>,
+	input: Vec<u8>,
+	target_gas: Option<u64>,
+	is_static: bool,
+	take_l64: bool,
+	take_stipend: bool,
+	context: Context,
+	fexecute: FExecute,
+) -> Capture<(ExitReason, Vec<u8>), Infallible> where
+	FExecute: FnOnce(&mut StackExecutor<'config, S>, &mut Runtime) -> ExitReason,
+{
+	macro_rules! try_or_fail {
+		( $e:expr ) => {
+			match $e {
+				Ok(v) => v,
+				Err(e) => return Capture::Exit((e.into(), Vec::new())),
 			}
 		}
+	}
 
-		fn l64(gas: u64) -> u64 {
-			gas - gas / 64
-		}
+	fn l64(gas: u64) -> u64 {
+		gas - gas / 64
+	}
 
-		let after_gas = if take_l64 && self.config.call_l64_after_gas {
-			if self.config.estimate {
-				let initial_after_gas = self.state.metadata().gasometer.gas();
-				let diff = initial_after_gas - l64(initial_after_gas);
-				try_or_fail!(self.state.metadata_mut().gasometer.record_cost(diff));
-				self.state.metadata().gasometer.gas()
-			} else {
-				l64(self.state.metadata().gasometer.gas())
-			}
+	let after_gas = if take_l64 && executor.config.call_l64_after_gas {
+		if executor.config.estimate {
+			let initial_after_gas = executor.state.metadata().gasometer.gas();
+			let diff = initial_after_gas - l64(initial_after_gas);
+			try_or_fail!(executor.state.metadata_mut().gasometer.record_cost(diff));
+			executor.state.metadata().gasometer.gas()
 		} else {
-			self.state.metadata().gasometer.gas()
-		};
+			l64(executor.state.metadata().gasometer.gas())
+		}
+	} else {
+		executor.state.metadata().gasometer.gas()
+	};
 
-		let target_gas = target_gas.unwrap_or(after_gas);
-		let mut gas_limit = min(target_gas, after_gas);
+	let target_gas = target_gas.unwrap_or(after_gas);
+	let mut gas_limit = min(target_gas, after_gas);
 
-		try_or_fail!(
-			self.state.metadata_mut().gasometer.record_cost(gas_limit)
-		);
+	try_or_fail!(
+		executor.state.metadata_mut().gasometer.record_cost(gas_limit)
+	);
 
-		if let Some(transfer) = transfer.as_ref() {
-			if take_stipend && transfer.value != U256::zero() {
-				gas_limit = gas_limit.saturating_add(self.config.call_stipend);
-			}
+	if let Some(transfer) = transfer.as_ref() {
+		if take_stipend && transfer.value != U256::zero() {
+			gas_limit = gas_limit.saturating_add(executor.config.call_stipend);
 		}
+	}
 
-		let code = self.code(code_address);
+	let code = executor.code(code_address);
 
-		self.enter_substate(gas_limit, is_static);
-		self.state.touch(context.address);
+	executor.enter_substate(gas_limit, is_static);
+	executor.state.touch(context.address);
 
-		if let Some(depth) = self.state.metadata().depth {
-			if depth > self.config.call_stack_limit {
-				let _ = self.exit_substate(StackExitKind::Reverted);
-				return Capture::Exit((ExitError::CallTooDeep.into(), Vec::new()))
-			}
-		}
-
-		if let Some(transfer) = transfer {
-			match self.state.transfer(transfer) {
-				Ok(()) => (),
-				Err(e) => {
-					let _ = self.exit_substate(StackExitKind::Reverted);
-					return Capture::Exit((ExitReason::Error(e), Vec::new()))
-				},
-			}
+	if let Some(depth) = executor.state.metadata().depth {
+		if depth > executor.config.call_stack_limit {
+			let _ = executor.exit_substate(StackExitKind::Reverted);
+			return Capture::Exit((ExitError::CallTooDeep.into(), Vec::new()))
 		}
+	}
 
-		if let Some(ret) = (self.precompile)(code_address, &input, Some(gas_limit), &context) {
-			return match ret {
-				Ok((s, out, cost)) => {
-					let _ = self.state.metadata_mut().gasometer.record_cost(cost);
-					let _ = self.exit_substate(StackExitKind::Succeeded);
-					Capture::Exit((ExitReason::Succeed(s), out))
-				},
-				Err(e) => {
-					let _ = self.exit_substate(StackExitKind::Failed);
-					Capture::Exit((ExitReason::Error(e), Vec::new()))
-				},
-			}
+	if let Some(transfer) = transfer {
+		match executor.state.transfer(transfer) {
+			Ok(()) => (),
+			Err(e) => {
+				let _ = executor.exit_substate(StackExitKind::Reverted);
+				return Capture::Exit((ExitReason::Error(e), Vec::new()))
+			},
 		}
+	}
 
-		let mut runtime = Runtime::new(
-			Rc::new(code),
-			Rc::new(input),
-			context,
-			self.config,
-		);
-
-		let reason = self.execute(&mut runtime);
-		log::debug!(target: "evm", "Call execution using address {}: {:?}", code_address, reason);
-
-		match reason {
-			ExitReason::Succeed(s) => {
-				let _ = self.exit_substate(StackExitKind::Succeeded);
-				Capture::Exit((ExitReason::Succeed(s), runtime.machine().return_value()))
+	if let Some(ret) = (executor.precompile)(code_address, &input, Some(gas_limit), &context) {
+		return match ret {
+			Ok((s, out, cost)) => {
+				let _ = executor.state.metadata_mut().gasometer.record_cost(cost);
+				let _ = executor.exit_substate(StackExitKind::Succeeded);
+				Capture::Exit((ExitReason::Succeed(s), out))
 			},
-			ExitReason::Error(e) => {
-				let _ = self.exit_substate(StackExitKind::Failed);
+			Err(e) => {
+				let _ = executor.exit_substate(StackExitKind::Failed);
 				Capture::Exit((ExitReason::Error(e), Vec::new()))
 			},
-			ExitReason::Revert(e) => {
-				let _ = self.exit_substate(StackExitKind::Reverted);
-				Capture::Exit((ExitReason::Revert(e), runtime.machine().return_value()))
-			},
-			ExitReason::Fatal(e) => {
-				self.state.metadata_mut().gasometer.fail();
-				let _ = self.exit_substate(StackExitKind::Failed);
-				Capture::Exit((ExitReason::Fatal(e), Vec::new()))
-			},
 		}
 	}
+
+	let mut runtime = Runtime::new(
+		Rc::new(code),
+		Rc::new(input),
+		context,
+		executor.config,
+	);
+
+	let reason = fexecute(executor, &mut runtime);
+	log::debug!(target: "evm", "Call execution using address {}: {:?}", code_address, reason);
+
+	match reason {
+		ExitReason::Succeed(s) => {
+			let _ = executor.exit_substate(StackExitKind::Succeeded);
+			Capture::Exit((ExitReason::Succeed(s), runtime.machine().return_value()))
+		},
+		ExitReason::Error(e) => {
+			let _ = executor.exit_substate(StackExitKind::Failed);
+			Capture::Exit((ExitReason::Error(e), Vec::new()))
+		},
+		ExitReason::Revert(e) => {
+			let _ = executor.exit_substate(StackExitKind::Reverted);
+			Capture::Exit((ExitReason::Revert(e), runtime.machine().return_value()))
+		},
+		ExitReason::Fatal(e) => {
+			executor.state.metadata_mut().gasometer.fail();
+			let _ = executor.exit_substate(StackExitKind::Failed);
+			Capture::Exit((ExitReason::Fatal(e), Vec::new()))
+		},
+	}
 }
 
 impl<'config, S: StackState<'config>> Handler for StackExecutor<'config, S> {
@@ -661,7 +683,9 @@ impl<'config, S: StackState<'config>> Handler for StackExecutor<'config, S> {
 		init_code: Vec<u8>,
 		target_gas: Option<u64>,
 	) -> Capture<(ExitReason, Option<H160>, Vec<u8>), Self::CreateInterrupt> {
-		self.create_inner(caller, scheme, value, init_code, target_gas, true)
+		create_inner(self, caller, scheme, value, init_code, target_gas, true, |executor, runtime| {
+			executor.execute(runtime)
+		})
 	}
 
 	fn call(
@@ -673,7 +697,9 @@ impl<'config, S: StackState<'config>> Handler for StackExecutor<'config, S> {
 		is_static: bool,
 		context: Context,
 	) -> Capture<(ExitReason, Vec<u8>), Self::CallInterrupt> {
-		self.call_inner(code_address, transfer, input, target_gas, is_static, true, true, context)
+		call_inner(self, code_address, transfer, input, target_gas, is_static, true, true, context, |executor, runtime| {
+			executor.execute(runtime)
+		})
 	}
 
 	#[inline]
@@ -683,8 +709,6 @@ impl<'config, S: StackState<'config>> Handler for StackExecutor<'config, S> {
 		opcode: Opcode,
 		stack: &Stack
 	) -> Result<(), ExitError> {
-		// log::trace!(target: "evm", "Running opcode: {:?}, Pre gas-left: {:?}", opcode, gasometer.gas());
-
 		if let Some(cost) = gasometer::static_opcode_cost(opcode) {
 			self.state.metadata_mut().gasometer.record_cost(cost)?;
 		} else {