Skip to content

Commit

Permalink
Implement seal_code_hash and seal_own_code_hash (#1205)
Browse files Browse the repository at this point in the history
* seal_code_hash() added

* +docs

* seal_own_code_hash() added

* ci errors fixes

* more ci fixes

* more ci fixes

* refactored on what to return

* Apply suggestions from code review

Co-authored-by: Michael Müller <mich@elmueller.net>

* fix: new funcs are in TypedEnvBackend trait

* errors section to code_hash doc + own_code_hash to return non-wrapped val

* bug caught and fixed: wrong return val for seal_own_code_hash

* Update crates/env/src/api.rs

Co-authored-by: Michael Müller <mich@elmueller.net>

* Apply suggestions from code review

Co-authored-by: Michael Müller <mich@elmueller.net>

* own_code_hash to return Result, as there could be decoding issues

* bugfix (e2e testing caught)

* ci fix

* Apply suggestions from code review

Co-authored-by: Michael Müller <mich@elmueller.net>

* Revert "Apply suggestions from code review"

This reverts commit 5591d95.

Co-authored-by: Michael Müller <mich@elmueller.net>
  • Loading branch information
agryaznov and cmichi committed Apr 8, 2022
1 parent 1aafcb1 commit b65091a
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 0 deletions.
29 changes: 29 additions & 0 deletions crates/env/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,35 @@ where
})
}

/// Retrieves the code hash of the contract at the specified account id.
///
/// # Errors
///
/// - If no code hash was found for the specified account id.
/// - If the returned value cannot be properly decoded.
pub fn code_hash<E>(account: &E::AccountId) -> Result<E::Hash>
where
E: Environment,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::code_hash::<E>(instance, account)
})
}

/// Retrieves the code hash of the currently executing contract.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn own_code_hash<E>() -> Result<E::Hash>
where
E: Environment,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::own_code_hash::<E>(instance)
})
}

/// Checks whether the caller of the current contract is the origin of the whole call stack.
///
/// Prefer this over [`is_contract`] when checking whether your contract is being called by
Expand Down
18 changes: 18 additions & 0 deletions crates/env/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,4 +447,22 @@ pub trait TypedEnvBackend: EnvBackend {
fn caller_is_origin<E>(&mut self) -> bool
where
E: Environment;

/// Retrieves the code hash of the contract at the given `account` id.
///
/// # Note
///
/// For more details visit: [`code_hash`][`crate::code_hash`]
fn code_hash<E>(&mut self, account: &E::AccountId) -> Result<E::Hash>
where
E: Environment;

/// Retrieves the code hash of the currently executing contract.
///
/// # Note
///
/// For more details visit: [`own_code_hash`][`crate::own_code_hash`]
fn own_code_hash<E>(&mut self) -> Result<E::Hash>
where
E: Environment;
}
14 changes: 14 additions & 0 deletions crates/env/src/engine/off_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,4 +486,18 @@ impl TypedEnvBackend for EnvInstance {
{
unimplemented!("off-chain environment does not support cross-contract calls")
}

fn code_hash<E>(&mut self, _account: &E::AccountId) -> Result<E::Hash>
where
E: Environment,
{
unimplemented!("off-chain environment does not support `code_hash`")
}

fn own_code_hash<E>(&mut self) -> Result<E::Hash>
where
E: Environment,
{
unimplemented!("off-chain environment does not support `own_code_hash`")
}
}
33 changes: 33 additions & 0 deletions crates/env/src/engine/on_chain/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,17 @@ mod sys {
message_hash_ptr: Ptr32<[u8]>,
output_ptr: Ptr32Mut<[u8]>,
) -> ReturnCode;

pub fn seal_code_hash(
account_id_ptr: Ptr32<[u8]>,
output_ptr: Ptr32Mut<[u8]>,
output_len_ptr: Ptr32Mut<u32>,
) -> ReturnCode;

pub fn seal_own_code_hash(
output_ptr: Ptr32Mut<[u8]>,
output_len_ptr: Ptr32Mut<u32>,
);
}
}

Expand Down Expand Up @@ -676,3 +687,25 @@ pub fn caller_is_origin() -> bool {
let ret_val = unsafe { sys::seal_caller_is_origin() };
ret_val.into_bool()
}

pub fn code_hash(account_id: &[u8], output: &mut [u8]) -> Result {
let mut output_len = output.len() as u32;
let ret_val = unsafe {
sys::seal_code_hash(
Ptr32::from_slice(account_id),
Ptr32Mut::from_slice(output),
Ptr32Mut::from_ref(&mut output_len),
)
};
ret_val.into()
}

pub fn own_code_hash(output: &mut [u8]) {
let mut output_len = output.len() as u32;
unsafe {
sys::seal_own_code_hash(
Ptr32Mut::from_slice(output),
Ptr32Mut::from_ref(&mut output_len),
)
}
}
24 changes: 24 additions & 0 deletions crates/env/src/engine/on_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,4 +512,28 @@ impl TypedEnvBackend for EnvInstance {
{
ext::caller_is_origin()
}

fn code_hash<E>(&mut self, account_id: &E::AccountId) -> Result<E::Hash>
where
E: Environment,
{
let mut scope = self.scoped_buffer();
let output = scope.take(32);
scope.append_encoded(account_id);
let enc_account_id = scope.take_appended();

ext::code_hash(enc_account_id, output)?;
let hash = scale::Decode::decode(&mut &output[..])?;
Ok(hash)
}

fn own_code_hash<E>(&mut self) -> Result<E::Hash>
where
E: Environment,
{
let output = &mut self.scoped_buffer().take(32);
ext::own_code_hash(output);
let hash = scale::Decode::decode(&mut &output[..])?;
Ok(hash)
}
}
64 changes: 64 additions & 0 deletions crates/lang/src/env_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -901,4 +901,68 @@ where
pub fn caller_is_origin(self) -> bool {
ink_env::caller_is_origin::<E>()
}

/// Returns the code hash of the contract at the given `account` id.
///
/// # Example
///
/// ```
/// # use ink_lang as ink;
/// # #[ink::contract]
/// # pub mod my_contract {
/// # #[ink(storage)]
/// # pub struct MyContract { }
/// #
/// # impl MyContract {
/// # #[ink(constructor)]
/// # pub fn new() -> Self {
/// # Self {}
/// # }
/// #
/// #[ink(message)]
/// pub fn code_hash(&mut self, account_id: AccountId) -> Option<Hash> {
/// self.env().code_hash(&account_id).ok()
/// }
/// # }
/// # }
/// ```
///
/// # Note
///
/// For more details visit: [`ink_env::code_hash`]
pub fn code_hash(self, account_id: &E::AccountId) -> Result<E::Hash> {
ink_env::code_hash::<E>(account_id)
}

/// Returns the code hash of the contract at the given `account` id.
///
/// # Example
///
/// ```
/// # use ink_lang as ink;
/// # #[ink::contract]
/// # pub mod my_contract {
/// # #[ink(storage)]
/// # pub struct MyContract { }
/// #
/// # impl MyContract {
/// # #[ink(constructor)]
/// # pub fn new() -> Self {
/// # Self {}
/// # }
/// #
/// #[ink(message)]
/// pub fn own_code_hash(&mut self) -> Hash {
/// self.env().own_code_hash().expect("contract should have a code hash")
/// }
/// # }
/// # }
/// ```
///
/// # Note
///
/// For more details visit: [`ink_env::own_code_hash`]
pub fn own_code_hash(self) -> Result<E::Hash> {
ink_env::own_code_hash::<E>()
}
}

0 comments on commit b65091a

Please sign in to comment.