Repository: paritytech/substrate
File: primitives/api/proc-macro/src/impl_runtime_apis.rs (Rust)

Code before:
		/// Implements all runtime apis for the client side.
		#crate_::std_enabled! {
			pub struct RuntimeApiImpl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block> + 'static> {
				call: &'static C,
				in_transaction: std::cell::RefCell<bool>,
				changes: std::cell::RefCell<#crate_::OverlayedChanges>,
				storage_transaction_cache: std::cell::RefCell<
					#crate_::StorageTransactionCache<Block, C::StateBackend>
				>,
				recorder: std::option::Option<#crate_::ProofRecorder<Block>>,
			}

			impl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block>> #crate_::ApiExt<Block> for
				RuntimeApiImpl<Block, C>
			{
				type StateBackend = C::StateBackend;

				fn execute_in_transaction<F: FnOnce(&Self) -> #crate_::TransactionOutcome<R>, R>(
					&self,
					call: F,
				) -> R where Self: Sized {
					self.start_transaction();

					let old_value = std::cell::RefCell::replace(&self.in_transaction, true);
					let res = call(self);
					*std::cell::RefCell::borrow_mut(&self.in_transaction) = old_value;

					self.commit_or_rollback_transaction(
						std::matches!(res, #crate_::TransactionOutcome::Commit(_))
					);

					res.into_inner()
				}

				fn has_api<A: #crate_::RuntimeApiInfo + ?Sized>(
					&self,
					at: <Block as #crate_::BlockT>::Hash,
				) -> std::result::Result<bool, #crate_::ApiError> where Self: Sized {
					#crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
					.map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, |v| v == A::VERSION))
				}

				fn has_api_with<A: #crate_::RuntimeApiInfo + ?Sized, P: Fn(u32) -> bool>(
					&self,
					at: <Block as #crate_::BlockT>::Hash,
					pred: P,
				) -> std::result::Result<bool, #crate_::ApiError> where Self: Sized {
					#crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
					.map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, pred))
				}


Review comment (suggestion):
This might not matter in practice (?), but `commit_or_rollback_transaction` can panic, and now we're going to support nested transactions, which means that `call` can panic, which means that if it does then the `in_transaction` won't get restored to the old value.

Code after:
		/// Implements all runtime apis for the client side.
		#crate_::std_enabled! {
			pub struct RuntimeApiImpl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block> + 'static> {
				call: &'static C,
				transaction_depth: std::cell::RefCell<u16>,
				changes: std::cell::RefCell<#crate_::OverlayedChanges>,
				storage_transaction_cache: std::cell::RefCell<
					#crate_::StorageTransactionCache<Block, C::StateBackend>
				>,
				recorder: std::option::Option<#crate_::ProofRecorder<Block>>,
			}

			impl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block>> #crate_::ApiExt<Block> for
				RuntimeApiImpl<Block, C>
			{
				type StateBackend = C::StateBackend;

				fn execute_in_transaction<F: FnOnce(&Self) -> #crate_::TransactionOutcome<R>, R>(
					&self,
					call: F,
				) -> R where Self: Sized {
					self.start_transaction();

					*std::cell::RefCell::borrow_mut(&self.transaction_depth) += 1;
					let res = call(self);
					std::cell::RefCell::borrow_mut(&self.transaction_depth)
						.checked_sub(1)
						.expect("Transactions are opened and closed together; qed");

					self.commit_or_rollback_transaction(
						std::matches!(res, #crate_::TransactionOutcome::Commit(_))
					);

					res.into_inner()
				}

				fn has_api<A: #crate_::RuntimeApiInfo + ?Sized>(
					&self,
					at: <Block as #crate_::BlockT>::Hash,
				) -> std::result::Result<bool, #crate_::ApiError> where Self: Sized {
					#crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
					.map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, |v| v == A::VERSION))
				}

				fn has_api_with<A: #crate_::RuntimeApiInfo + ?Sized, P: Fn(u32) -> bool>(
					&self,
					at: <Block as #crate_::BlockT>::Hash,
					pred: P,
				) -> std::result::Result<bool, #crate_::ApiError> where Self: Sized {
					#crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
					.map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, pred))