Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify ink_env::{eval_contract, invoke_contract} #1165

Merged
merged 12 commits into from
Mar 7, 2022
33 changes: 3 additions & 30 deletions crates/env/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use crate::{
TypedEnvBackend,
},
call::{
utils::ReturnType,
CallParams,
CreateParams,
},
Expand Down Expand Up @@ -216,33 +215,7 @@ pub fn clear_contract_storage(key: &Key) {
})
}

/// Invokes a contract message.
///
/// # Note
///
/// - Prefer using this over [`eval_contract`] if possible. [`invoke_contract`]
/// will generally have a better performance since it won't try to fetch any results.
/// - This is a low level way to invoke another smart contract.
/// Prefer to use the ink! guided and type safe approach to using this.
///
/// # Errors
///
/// - If the called account does not exist.
/// - If the called account is not a contract.
/// - If arguments passed to the called contract message are invalid.
/// - If the called contract execution has trapped.
/// - If the called contract ran out of gas upon execution.
pub fn invoke_contract<T, Args>(params: &CallParams<T, Args, ()>) -> Result<()>
where
T: Environment,
Args: scale::Encode,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::invoke_contract::<T, Args>(instance, params)
})
}

/// Evaluates a contract message and returns its result.
/// Invokes a contract message and returns its result.
///
/// # Note
///
Expand All @@ -257,14 +230,14 @@ where
/// - If the called contract execution has trapped.
/// - If the called contract ran out of gas upon execution.
/// - If the returned value failed to decode properly.
pub fn eval_contract<T, Args, R>(params: &CallParams<T, Args, ReturnType<R>>) -> Result<R>
pub fn invoke_contract<T, Args, R>(params: &CallParams<T, Args, R>) -> Result<R>
where
T: Environment,
Args: scale::Encode,
R: scale::Decode,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::eval_contract::<T, Args, R>(instance, params)
TypedEnvBackend::invoke_contract::<T, Args, R>(instance, params)
})
}

Expand Down
20 changes: 3 additions & 17 deletions crates/env/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

use crate::{
call::{
utils::ReturnType,
CallParams,
CreateParams,
},
Expand Down Expand Up @@ -359,27 +358,14 @@ pub trait TypedEnvBackend: EnvBackend {
T: Environment,
Event: Topics + scale::Encode;

/// Invokes a contract message.
/// Invokes a contract message and returns its result.
///
/// # Note
///
/// For more details visit: [`invoke_contract`][`crate::invoke_contract`]
fn invoke_contract<T, Args>(
fn invoke_contract<T, Args, R>(
&mut self,
call_data: &CallParams<T, Args, ()>,
) -> Result<()>
where
T: Environment,
Args: scale::Encode;

/// Evaluates a contract message and returns its result.
///
/// # Note
///
/// For more details visit: [`eval_contract`][`crate::eval_contract`]
fn eval_contract<T, Args, R>(
&mut self,
call_data: &CallParams<T, Args, ReturnType<R>>,
call_data: &CallParams<T, Args, R>,
) -> Result<R>
where
T: Environment,
Expand Down
77 changes: 10 additions & 67 deletions crates/env/src/call/call_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,38 +84,17 @@ where
}
}

impl<E, Args> CallParams<E, Args, ()>
where
E: Environment,
Args: scale::Encode,
{
/// Invokes the contract with the given built-up call parameters.
///
/// # Note
///
/// Prefer [`invoke`](`Self::invoke`) over [`eval`](`Self::eval`) if the
/// called contract message does not return anything because it is more efficient.
pub fn invoke(&self) -> Result<(), crate::Error> {
crate::invoke_contract(self)
}
}

impl<E, Args, R> CallParams<E, Args, ReturnType<R>>
impl<E, Args, R> CallParams<E, Args, R>
where
E: Environment,
Args: scale::Encode,
R: scale::Decode,
{
/// Evaluates the contract with the given built-up call parameters.
/// Invokes the contract with the given built-up call parameters.
///
/// Returns the result of the contract execution.
///
/// # Note
///
/// Prefer [`invoke`](`Self::invoke`) over [`eval`](`Self::eval`) if the
/// called contract message does not return anything because it is more efficient.
pub fn eval(&self) -> Result<R, crate::Error> {
crate::eval_contract(self)
pub fn invoke(&self) -> Result<R, crate::Error> {
crate::invoke_contract(self)
}
}

Expand Down Expand Up @@ -179,7 +158,7 @@ where
/// # use ::ink_env::{
/// # Environment,
/// # DefaultEnvironment,
/// # call::{build_call, Selector, ExecutionInput, utils::ReturnType},
/// # call::{build_call, Selector, ExecutionInput},
/// # };
/// # type AccountId = <DefaultEnvironment as Environment>::AccountId;
/// let my_return_value: i32 = build_call::<DefaultEnvironment>()
Expand All @@ -192,7 +171,7 @@ where
/// .push_arg(true)
/// .push_arg(&[0x10; 32])
/// )
/// .returns::<ReturnType<i32>>()
/// .returns::<i32>()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ that users aren't exposed to ReturnType<T> anymore

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the PR description you mention that "the user can either omit the call to returns::<R>()". Doesn't looks like this is the case, if I remove this line the example fails to compile

Copy link
Collaborator Author

@ascjones ascjones Mar 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh it appears that is only the case if the arg list is not set (which in this example it is) see https://github.com/paritytech/ink/blob/c0cccb74270f4ef9b92ea3dbde7a06b25f1bf091/crates/env/src/call/call_builder.rs#L438-L439.

Here is an example which calls explcitily but with no args so that compiles: https://github.com/paritytech/ink/blob/378d83f3fc204e18dce6f3946e6a0f27e333d7d6/examples/proxy/lib.rs#L80

I'm not sure why it was already this way, it would make sense to either allow it to be Unset either way and default to (), or require it to be set in all cases. What do you think?

/// .fire()
/// .unwrap();
/// ```
Expand Down Expand Up @@ -328,18 +307,6 @@ where
}
}

mod seal {
/// Used to prevent users from implementing `IndicateReturnType` for their own types.
pub trait Sealed {}
impl Sealed for () {}
impl<T> Sealed for super::ReturnType<T> {}
}

/// Types that can be used in [`CallBuilder::returns`] to signal return type.
pub trait IndicateReturnType: Default + self::seal::Sealed {}
impl IndicateReturnType for () {}
impl<T> IndicateReturnType for ReturnType<T> {}

impl<E, Callee, GasLimit, TransferredValue, Args>
CallBuilder<E, Callee, GasLimit, TransferredValue, Args, Unset<ReturnType<()>>>
where
Expand All @@ -350,14 +317,11 @@ where
/// # Note
///
/// Either use `.returns::<()>` to signal that the call does not return a value
/// or use `.returns::<ReturnType<T>>` to signal that the call returns a value of
/// type `T`.
/// or use `.returns::<T>` to signal that the call returns a value of type `T`.
#[inline]
pub fn returns<R>(
self,
) -> CallBuilder<E, Callee, GasLimit, TransferredValue, Args, Set<R>>
where
R: IndicateReturnType,
) -> CallBuilder<E, Callee, GasLimit, TransferredValue, Args, Set<ReturnType<R>>>
{
CallBuilder {
env: Default::default(),
Expand Down Expand Up @@ -414,7 +378,7 @@ impl<E, GasLimit, TransferredValue, Args, RetType>
GasLimit,
TransferredValue,
Set<ExecutionInput<Args>>,
Set<RetType>,
Set<ReturnType<RetType>>,
>
where
E: Environment,
Expand Down Expand Up @@ -465,27 +429,6 @@ where
}
}

impl<E, GasLimit, TransferredValue, Args>
CallBuilder<
E,
Set<E::AccountId>,
GasLimit,
TransferredValue,
Set<ExecutionInput<Args>>,
Set<()>,
>
where
E: Environment,
GasLimit: Unwrap<Output = u64>,
Args: scale::Encode,
TransferredValue: Unwrap<Output = E::Balance>,
{
/// Invokes the cross-chain function call.
pub fn fire(self) -> Result<(), Error> {
self.params().invoke()
}
}

impl<E, GasLimit, TransferredValue>
CallBuilder<
E,
Expand Down Expand Up @@ -524,6 +467,6 @@ where
{
/// Invokes the cross-chain function call and returns the result.
pub fn fire(self) -> Result<R, Error> {
self.params().eval()
self.params().invoke()
}
}
2 changes: 1 addition & 1 deletion crates/env/src/call/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use core::marker::PhantomData;

/// Represents a return type.
///
/// Used as a marker type to differentiate at compile-time between invoke and evaluate.
/// Used as a marker type to define the return type of an ink! message in call builders.
#[derive(Debug)]
pub struct ReturnType<T>(PhantomData<fn() -> T>);

Expand Down
1 change: 0 additions & 1 deletion crates/env/src/call/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ mod selector;
/// Utility types for the cross-contract calling API.
pub mod utils {
pub use super::{
call_builder::IndicateReturnType,
common::{
ReturnType,
Set,
Expand Down
19 changes: 5 additions & 14 deletions crates/env/src/engine/off_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use super::EnvInstance;
use crate::{
call::{
utils::ReturnType,
CallParams,
CreateParams,
},
Expand Down Expand Up @@ -387,10 +386,14 @@ impl TypedEnvBackend for EnvInstance {
self.engine.deposit_event(&enc_topics[..], enc_data);
}

fn invoke_contract<T, Args>(&mut self, params: &CallParams<T, Args, ()>) -> Result<()>
fn invoke_contract<T, Args, R>(
&mut self,
params: &CallParams<T, Args, R>,
) -> Result<R>
where
T: Environment,
Args: scale::Encode,
R: scale::Decode,
{
let _gas_limit = params.gas_limit();
let _callee = params.callee();
Expand All @@ -400,18 +403,6 @@ impl TypedEnvBackend for EnvInstance {
unimplemented!("off-chain environment does not support contract invocation")
}

fn eval_contract<T, Args, R>(
&mut self,
_call_params: &CallParams<T, Args, ReturnType<R>>,
) -> Result<R>
where
T: Environment,
Args: scale::Encode,
R: scale::Decode,
{
unimplemented!("off-chain environment does not support contract evaluation")
}

fn instantiate_contract<T, Args, Salt, C>(
&mut self,
params: &CreateParams<T, Args, Salt, C>,
Expand Down
Loading