Skip to content
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
0675a45
*WIP* add `delegate_dependency` env api calls
ascjones Jan 26, 2024
6d491b4
Merge branch 'master' into aj/delegate-dependency
ascjones Feb 5, 2024
8a0d4b5
Merge branch 'master' into aj/delegate-dependency
ascjones Feb 7, 2024
37370be
Merge branch 'master' into aj/delegate-dependency
ascjones Feb 8, 2024
f441c6a
Merge branch 'master' into aj/delegate-dependency
ascjones Feb 8, 2024
a4bb790
Updated return types and moved docs
ascjones Feb 8, 2024
64afb16
Merge branch 'master' into aj/delegate-dependency
ascjones Feb 9, 2024
c0084dd
unused imports
ascjones Feb 9, 2024
9fc6820
Lazy delegate to
ascjones Feb 9, 2024
5086e0a
Allow deprecated
ascjones Feb 9, 2024
6e358da
Initialise delegate_to hash in constructor
ascjones Feb 9, 2024
b5bede6
Test example, adding `remove_code` extrinsic to e2e
ascjones Feb 9, 2024
d864abb
Docs
ascjones Feb 9, 2024
60b7662
CHANGELOG.md
ascjones Feb 9, 2024
e928284
drink unimplemented
ascjones Feb 9, 2024
82fcc91
Send it
ascjones Feb 9, 2024
e1f7a9f
Fix comment
ascjones Feb 9, 2024
be62c50
Fix comment
ascjones Feb 9, 2024
56a3bbf
Fix comment
ascjones Feb 9, 2024
8b21039
Fix comment
ascjones Feb 9, 2024
c72676d
Fix comment
ascjones Feb 9, 2024
864dcf4
Merge branch 'master' into aj/delegate-dependency
ascjones Feb 19, 2024
785db39
Update integration-tests/upgradeable-contracts/delegator/delegatee2/C…
ascjones Feb 21, 2024
82d720e
Update crates/e2e/src/backend.rs
ascjones Feb 21, 2024
22b01d0
update to `lock/unlock` host fns
ascjones Feb 22, 2024
f0c99e8
#[allow(deprecated)] for _v1 calls
ascjones Feb 22, 2024
4d975b8
Add link to lock up deposit
ascjones Feb 22, 2024
430a831
doc comment as per review
ascjones Feb 22, 2024
1442530
Merge branch 'master' into aj/delegate-dependency
ascjones Feb 23, 2024
eb36349
Update crates/e2e/src/backend.rs
ascjones Feb 23, 2024
c5581dc
Update crates/e2e/src/backend.rs
ascjones Feb 23, 2024
e9b39c9
Update crates/env/src/api.rs
ascjones Feb 23, 2024
d20cd52
Apply suggestions from code review
ascjones Feb 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [Linter] Publish the linting crates on crates.io - [#2060](https://github.com/paritytech/ink/pull/2060)
- [E2E] Added `create_call_builder` for testing existing contracts - [#2075](https://github.com/paritytech/ink/pull/2075)
- `call_v2` cross-contract calls with additional limit parameters - [#2077](https://github.com/paritytech/ink/pull/2077)
- `delegate_dependency` api calls - [#2076](https://github.com/paritytech/ink/pull/2076)

### Changed
- `Mapping`: Reflect all possible failure cases in comments ‒ [#2079](https://github.com/paritytech/ink/pull/2079)
Expand Down
32 changes: 31 additions & 1 deletion crates/e2e/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use super::Keypair;
use crate::{
backend_calls::{
InstantiateBuilder,
RemoveCodeBuilder,
UploadBuilder,
},
builders::CreateBuilderPartial,
Expand Down Expand Up @@ -159,6 +160,28 @@ pub trait ContractsBackend<E: Environment> {
UploadBuilder::new(self, contract_name, caller)
}

/// Start building a remove code call.
/// # Example
///
/// ```ignore
/// let contract = client
/// .remove_code(&ink_e2e::alice(), code_hash)
/// // Submit the call for on-chain execution.
/// .submit()
/// .await
/// .expect("upload failed");
/// ```
fn remove_code<'a>(
&'a mut self,
caller: &'a Keypair,
code_hash: E::Hash,
) -> RemoveCodeBuilder<E, Self>
where
Self: Sized + BuilderClient<E>,
{
RemoveCodeBuilder::new(self, caller, code_hash)
}

/// Start building a call using a builder pattern.
///
/// # Example
Expand Down Expand Up @@ -193,7 +216,7 @@ pub trait ContractsBackend<E: Environment> {

#[async_trait]
pub trait BuilderClient<E: Environment>: ContractsBackend<E> {
/// Executes a bare `call` for the contract at `account_id`. This function does
/// Executes a bare `call` for the contract at `account_id`. This function does not
/// perform a dry-run, and user is expected to provide the gas limit.
///
/// Use it when you want to have a more precise control over submitting extrinsic.
Expand Down Expand Up @@ -239,6 +262,13 @@ pub trait BuilderClient<E: Environment>: ContractsBackend<E> {
storage_deposit_limit: Option<E::Balance>,
) -> Result<UploadResult<E, Self::EventLog>, Self::Error>;

/// Removes the code of the contract at `code_hash`.
async fn bare_remove_code(
&mut self,
caller: &Keypair,
code_hash: E::Hash,
) -> Result<Self::EventLog, Self::Error>;

/// Bare instantiate call. This function does not perform a dry-run,
/// and user is expected to provide the gas limit.
///
Expand Down
31 changes: 31 additions & 0 deletions crates/e2e/src/backend_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,37 @@ where
}
}

/// Allows to build an end-to-end remove code call using a builder pattern.
pub struct RemoveCodeBuilder<'a, E, B>
where
E: Environment,
B: BuilderClient<E>,
{
client: &'a mut B,
caller: &'a Keypair,
code_hash: E::Hash,
}

impl<'a, E, B> RemoveCodeBuilder<'a, E, B>
where
E: Environment,
B: BuilderClient<E>,
{
/// Initialize a remove code builder with essential values.
pub fn new(client: &'a mut B, caller: &'a Keypair, code_hash: E::Hash) -> Self {
Self {
client,
caller,
code_hash,
}
}

/// Submit the remove code extrinsic.
pub async fn submit(&mut self) -> Result<B::EventLog, B::Error> {
B::bare_remove_code(self.client, self.caller, self.code_hash).await
}
}

fn calculate_weight(
mut proof_size: u64,
mut ref_time: u64,
Expand Down
12 changes: 10 additions & 2 deletions crates/e2e/src/drink_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ where
#[async_trait]
impl<
AccountId: Clone + Send + Sync + From<[u8; 32]> + AsRef<[u8; 32]>,
Hash: Copy + From<[u8; 32]>,
Hash: Copy + Send + From<[u8; 32]>,
Config: SandboxConfig,
E: Environment<
AccountId = AccountId,
Expand Down Expand Up @@ -341,6 +341,14 @@ where
})
}

async fn bare_remove_code(
&mut self,
_caller: &Keypair,
_code_hash: E::Hash,
) -> Result<Self::EventLog, Self::Error> {
unimplemented!("drink! sandbox does not yet support remove_code")
}

async fn bare_call<Args: Sync + Encode + Clone, RetType: Send + Decode>(
&mut self,
caller: &Keypair,
Expand Down Expand Up @@ -420,7 +428,7 @@ where

impl<
AccountId: Clone + Send + Sync + From<[u8; 32]> + AsRef<[u8; 32]>,
Hash: Copy + From<[u8; 32]>,
Hash: Copy + Send + From<[u8; 32]>,
Config: SandboxConfig,
E: Environment<
AccountId = AccountId,
Expand Down
3 changes: 3 additions & 0 deletions crates/e2e/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ pub enum Error<DispatchError: fmt::Debug + fmt::Display> {
/// The `call` extrinsic failed.
#[error("Call extrinsic error: {0}")]
CallExtrinsic(DispatchError),
/// The `remove_code` extrinsic failed.
#[error("Remove code extrinsic error: {0}")]
RemoveCodeExtrinsic(DispatchError),
/// Error fetching account balance.
#[error("Fetching account Balance error: {0}")]
Balance(String),
Expand Down
33 changes: 29 additions & 4 deletions crates/e2e/src/subxt_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ where
E::AccountId: Debug + Send + Sync,
E::Balance:
Clone + Debug + Send + Sync + From<u128> + scale::HasCompact + serde::Serialize,
E::Hash: Debug + Send + scale::Encode,
E::Hash: Debug + Send + Sync + scale::Encode,
{
async fn bare_instantiate<Contract: Clone, Args: Send + Sync + Encode + Clone, R>(
&mut self,
Expand Down Expand Up @@ -536,6 +536,30 @@ where
Ok(ret)
}

async fn bare_remove_code(
&mut self,
caller: &Keypair,
code_hash: E::Hash,
) -> Result<Self::EventLog, Self::Error> {
let tx_events = self.api.remove_code(caller, code_hash).await;

for evt in tx_events.iter() {
let evt = evt.unwrap_or_else(|err| {
panic!("unable to unwrap event: {err:?}");
});

if is_extrinsic_failed_event(&evt) {
let metadata = self.api.client.metadata();
let dispatch_error =
DispatchError::decode_from(evt.field_bytes(), metadata)
.map_err(|e| Error::Decoding(e.to_string()))?;
return Err(Error::RemoveCodeExtrinsic(dispatch_error))
}
}

Ok(tx_events)
}

async fn bare_call<Args: Sync + Encode + Clone, RetType: Send + Decode>(
&mut self,
caller: &Keypair,
Expand Down Expand Up @@ -571,7 +595,7 @@ where
if is_extrinsic_failed_event(&evt) {
let metadata = self.api.client.metadata();
let dispatch_error =
subxt::error::DispatchError::decode_from(evt.field_bytes(), metadata)
DispatchError::decode_from(evt.field_bytes(), metadata)
.map_err(|e| Error::Decoding(e.to_string()))?;
log_error(&format!("extrinsic for call failed: {dispatch_error}"));
return Err(Error::CallExtrinsic(dispatch_error))
Expand Down Expand Up @@ -660,13 +684,14 @@ where
C::Address: From<sr25519::PublicKey>,
C::Signature: From<sr25519::Signature>,
C::Address: Send + Sync,
<<C as subxt::Config>::ExtrinsicParams as subxt::config::ExtrinsicParams<C>>::OtherParams: Default + Send + Sync,
<<C as subxt::Config>::ExtrinsicParams as ExtrinsicParams<C>>::OtherParams:
Default + Send + Sync,

E: Environment,
E::AccountId: Debug + Send + Sync,
E::Balance:
Clone + Debug + Send + Sync + From<u128> + scale::HasCompact + serde::Serialize,
E::Hash: Debug + Send + scale::Encode,
E::Hash: Debug + Send + Sync + scale::Encode,
{
}

Expand Down
26 changes: 26 additions & 0 deletions crates/e2e/src/xts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ pub enum Determinism {
Relaxed,
}

/// A raw call to `pallet-contracts`'s `remove_code`.
#[derive(Debug, scale::Encode, scale::Decode, scale_encode::EncodeAsType)]
#[encode_as_type(trait_bounds = "", crate_path = "subxt::ext::scale_encode")]
pub struct RemoveCode<E: Environment> {
code_hash: E::Hash,
}

/// A raw call to `pallet-contracts`'s `upload`.
#[derive(Debug, scale::Encode, scale::Decode, scale_encode::EncodeAsType)]
#[encode_as_type(trait_bounds = "", crate_path = "subxt::ext::scale_encode")]
Expand Down Expand Up @@ -471,6 +478,25 @@ where
self.submit_extrinsic(&call, signer).await
}

/// Submits an extrinsic to remove the code at the given hash.
///
/// Returns when the transaction is included in a block. The return value
/// contains all events that are associated with this transaction.
pub async fn remove_code(
&self,
signer: &Keypair,
code_hash: E::Hash,
) -> ExtrinsicEvents<C> {
let call = subxt::tx::Payload::new(
"Contracts",
"remove_code",
RemoveCode::<E> { code_hash },
)
.unvalidated();

self.submit_extrinsic(&call, signer).await
}

/// Dry runs a call of the contract at `contract` with the given parameters.
pub async fn call_dry_run(
&self,
Expand Down
39 changes: 39 additions & 0 deletions crates/env/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -823,3 +823,42 @@ where
TypedEnvBackend::call_runtime::<E, _>(instance, call)
})
}

/// Adds a new delegate dependency to the contract.
///
/// This guarantees that the code of the dependency cannot be removed without first
/// calling [`remove_delegate_dependency`]. It charges a fraction of the code
/// deposit.
///
/// # Errors
///
/// - If the supplied `code_hash` cannot be found on-chain.
/// - If the `code_hash` is the same as the calling contract.
/// - If the maximum number of delegate dependencies is reached
/// - If the delegate dependency already exists.
pub fn add_delegate_dependency<E>(code_hash: &E::Hash)
where
E: Environment,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
instance.add_delegate_dependency::<E>(code_hash)
})
}

/// Removes the delegate dependency from the contract.
///
/// This removes the lock and refunds the deposit from the call to
/// [`add_delegate_dependency`]. The code of the dependency can be removed if the
/// reference count for the code hash is now zero.
///
/// # Errors
///
/// - If the delegate dependency does not exist.
pub fn remove_delegate_dependency<E>(code_hash: &E::Hash)
where
E: Environment,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
instance.remove_delegate_dependency::<E>(code_hash)
})
}
20 changes: 20 additions & 0 deletions crates/env/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,4 +418,24 @@ pub trait TypedEnvBackend: EnvBackend {
where
E: Environment,
Call: scale::Encode;

/// Adds a new delegate dependency to the contract.
///
/// # Note
///
/// For more details visit:
/// [`add_delegate_dependency`][`crate::add_delegate_dependency`]
fn add_delegate_dependency<E>(&mut self, code_hash: &E::Hash)
where
E: Environment;

/// Removes the delegate dependency from the contract.
///
/// # Note
///
/// For more details visit:
/// [`remove_delegate_dependency`][`crate::remove_delegate_dependency`]
fn remove_delegate_dependency<E>(&mut self, code_hash: &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 @@ -560,4 +560,18 @@ impl TypedEnvBackend for EnvInstance {
{
unimplemented!("off-chain environment does not support `call_runtime`")
}

fn add_delegate_dependency<E>(&mut self, _code_hash: &E::Hash)
where
E: Environment,
{
unimplemented!("off-chain environment does not support delegate dependencies")
}

fn remove_delegate_dependency<E>(&mut self, _code_hash: &E::Hash)
where
E: Environment,
{
unimplemented!("off-chain environment does not support delegate dependencies")
}
}
20 changes: 20 additions & 0 deletions crates/env/src/engine/on_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -660,4 +660,24 @@ impl TypedEnvBackend for EnvInstance {
let enc_call = scope.take_encoded(call);
ext::call_runtime(enc_call).map_err(Into::into)
}

fn add_delegate_dependency<E>(&mut self, code_hash: &E::Hash)
where
E: Environment,
{
let mut scope = self.scoped_buffer();
let enc_code_hash = scope.take_encoded(code_hash);
#[allow(deprecated)]
ext::add_delegate_dependency(enc_code_hash)
}

fn remove_delegate_dependency<E>(&mut self, code_hash: &E::Hash)
where
E: Environment,
{
let mut scope = self.scoped_buffer();
let enc_code_hash = scope.take_encoded(code_hash);
#[allow(deprecated)]
ext::remove_delegate_dependency(enc_code_hash)
}
}
Loading