Repository: paritytech/substrate
File: frame/contracts/src/exec.rs (Rust)

Code before:
		let entry_point = frame.entry_point;
		let delegated_code_hash =
			if frame.delegate_caller.is_some() { Some(*executable.code_hash()) } else { None };
		let do_transaction = || {
			// We need to charge the storage deposit before the initial transfer so that
			// it can create the account in case the initial transfer is < ed.
			if entry_point == ExportedFunction::Constructor {
				// Root origin can't be used to instantiate a contract, so it is safe to assume that
				// if we reached this point the origin has an associated account.
				let origin = &self.origin.account_id()?;
				let frame = top_frame_mut!(self);
				frame.nested_storage.charge_instantiate(
					origin,
					&frame.account_id,
					frame.contract_info.get(&frame.account_id),
					executable.code_info(),
				)?;
			}

			// Every non delegate call or instantiate also optionally transfers the balance.
			self.initial_transfer()?;

			#[cfg(feature = "unsafe-debug")]
			let code_hash = executable.code_hash().clone();
			#[cfg(feature = "unsafe-debug")]
			T::Debug::before_call(&code_hash, entry_point, &input_data);

			// Call into the Wasm blob.
			let output = executable
				.execute(self, &entry_point, input_data.clone())
				.map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee })?;

			#[cfg(feature = "unsafe-debug")]
			T::Debug::after_call(&code_hash, entry_point, &input_data, &output);

			// Avoid useless work that would be reverted anyways.
			if output.did_revert() {
				return Ok(output)
			}

			// Storage limit is normally enforced as late as possible (when the last frame returns)
			// so that the ordering of storage accesses does not matter.
			// (However, if a special limit was set for a sub-call, it should be enforced right
			// after the sub-call returned. See below for this case of enforcement).
			if self.frames.is_empty() {
				let frame = &mut self.first_frame;
				frame.contract_info.load(&frame.account_id);
				let contract = frame.contract_info.as_contract();
				frame.nested_storage.enforce_limit(contract)?;
			}


Review comment (bug):
Only clone when compiled with debugging. We can also think about not cloning the input at all and leave that to the debugger to store the input if needed. We already pass it in `before_call` and it doesn't change in between.

```suggestion
			#[cfg(feature = "unsafe-debug")]
			let (code_hash, input_clone) = {
			    let code_hash = executable.code_hash().clone();
			    T::Debug::before_call(&code_hash, entry_point, &input_data);
			    (code_hash, input_data.clone())
			};
```

Code after:
		let frame = self.top_frame();
		let entry_point = frame.entry_point;
		let delegated_code_hash =
			if frame.delegate_caller.is_some() { Some(*executable.code_hash()) } else { None };
		let do_transaction = || {
			// We need to charge the storage deposit before the initial transfer so that
			// it can create the account in case the initial transfer is < ed.
			if entry_point == ExportedFunction::Constructor {
				// Root origin can't be used to instantiate a contract, so it is safe to assume that
				// if we reached this point the origin has an associated account.
				let origin = &self.origin.account_id()?;
				let frame = top_frame_mut!(self);
				frame.nested_storage.charge_instantiate(
					origin,
					&frame.account_id,
					frame.contract_info.get(&frame.account_id),
					executable.code_info(),
				)?;
			}

			// Every non delegate call or instantiate also optionally transfers the balance.
			self.initial_transfer()?;

			#[cfg(feature = "unsafe-debug")]
			let (code_hash, input_clone) = {
				let code_hash = *executable.code_hash();
				T::Debug::before_call(&code_hash, entry_point, &input_data);
				(code_hash, input_data.clone())
			};

			// Call into the Wasm blob.
			let output = executable
				.execute(self, &entry_point, input_data)
				.map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee })?;

			#[cfg(feature = "unsafe-debug")]
			T::Debug::after_call(&code_hash, entry_point, input_clone, &output);

			// Avoid useless work that would be reverted anyways.
			if output.did_revert() {
				return Ok(output)
			}

			// Storage limit is normally enforced as late as possible (when the last frame returns)
			// so that the ordering of storage accesses does not matter.
			// (However, if a special limit was set for a sub-call, it should be enforced right
			// after the sub-call returned. See below for this case of enforcement).
			if self.frames.is_empty() {
				let frame = &mut self.first_frame;
				frame.contract_info.load(&frame.account_id);
				let contract = frame.contract_info.as_contract();