diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d577f4a3e..73c05f2284 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Changed - Restrict which `cfg` attributes can be used ‒ [#2313](https://github.com/use-ink/ink/pull/2313) +## Added +- Support for `caller_is_root` - [#2332] (https://github.com/use-ink/ink/pull/2332) + ## Fixed - [E2E] Have port parsing handle comma-separated list ‒ [#2336](https://github.com/use-ink/ink/pull/2336) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 654ea7987d..0b563ad5b2 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -729,6 +729,26 @@ where }) } +/// Checks whether the caller of the current contract is root. +/// +/// Note that only the origin of the call stack can be root. Hence this function returning +/// `true` implies that the contract is being called by the origin. +/// +/// A return value of `true` indicates that this contract is being called by a root +/// origin, and `false` indicates that the caller is a signed origin. +/// +/// # Errors +/// +/// If the returned value cannot be properly decoded. +pub fn caller_is_root() -> bool +where + E: Environment, +{ + ::on_instance(|instance| { + TypedEnvBackend::caller_is_root::(instance) + }) +} + /// Replace the contract code at the specified address with new code. /// /// # Note diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 1ace832dfa..8739bbe73c 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -413,6 +413,15 @@ pub trait TypedEnvBackend: EnvBackend { where E: Environment; + /// Checks whether the caller of the current contract is root. + /// + /// # Note + /// + /// For more details visit: [`caller_is_root`][`crate::caller_is_root`] + fn caller_is_root(&mut self) -> bool + where + E: Environment; + /// Retrieves the code hash of the contract at the given `account` id. /// /// # Note diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 727bee025a..c136d7b9d7 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -567,6 +567,13 @@ impl TypedEnvBackend for EnvInstance { unimplemented!("off-chain environment does not support cross-contract calls") } + fn caller_is_root(&mut self) -> bool + where + E: Environment, + { + unimplemented!("off-chain environment does not support `caller_is_root`") + } + fn code_hash(&mut self, _account: &E::AccountId) -> Result where E: Environment, diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index bf3fea473f..27d465b0da 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -676,6 +676,20 @@ impl TypedEnvBackend for EnvInstance { ext::caller_is_origin() } + fn caller_is_root(&mut self) -> bool + where + E: Environment, + { + // `ext::caller_is_root()` currently returns `u32`. + // See https://github.com/paritytech/polkadot-sdk/issues/6767 for more details. + let ret = ext::caller_is_root(); + match ret { + 0u32 => false, + 1u32 => true, + _ => panic!("Invalid value for bool conversion: {}", ret), + } + } + fn code_hash(&mut self, account_id: &E::AccountId) -> Result where E: Environment, diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index 106a015860..c0229dc1e0 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -1178,6 +1178,37 @@ where ink_env::caller_is_origin::() } + /// Checks whether the caller of the current contract is root. + /// + /// # Example + /// + /// ``` + /// # #[ink::contract] + /// # pub mod my_contract { + /// # #[ink(storage)] + /// # pub struct MyContract { } + /// # + /// # impl MyContract { + /// # #[ink(constructor)] + /// # pub fn new() -> Self { + /// # Self {} + /// # } + /// # + /// #[ink(message)] + /// pub fn caller_is_root(&mut self) -> bool { + /// self.env().caller_is_root() + /// } + /// # } + /// # } + /// ``` + /// + /// # Note + /// + /// For more details visit: [`ink_env::caller_is_root`] + pub fn caller_is_root(self) -> bool { + ink_env::caller_is_root::() + } + /// Returns the code hash of the contract at the given `account` id. /// /// # Example