Skip to content

Commit

Permalink
send canisters back on failure of creation of token
Browse files Browse the repository at this point in the history
  • Loading branch information
ravi-sawlani-yral committed Nov 29, 2024
1 parent 34e0178 commit 5c26a88
Show file tree
Hide file tree
Showing 24 changed files with 997 additions and 446 deletions.
1 change: 1 addition & 0 deletions src/canister/individual_user_template/can.did
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ service : (IndividualUserTemplateInitArgs) -> {
) -> ();
clear_snapshot : () -> ();
create_a_namespace : (text) -> (Result_4);
delete_all_creator_token : () -> ();
delete_key_value_pair : (nat64, text) -> (Result_5);
delete_multiple_key_value_pairs : (nat64, vec text) -> (Result_6);
deploy_cdao_sns : (SnsInitPayload, nat64) -> (Result_7);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use ic_cdk::api::management_canister::main::{deposit_cycles, CanisterIdRecord};
use ic_cdk_macros::update;
use shared_utils::{
canister_specific::individual_user_template::types::cdao::DeployedCdaoCanisters,
common::utils::permissions::is_caller_controller,
};

use crate::CANISTER_DATA;

use super::{
request_cycles_from_subnet_orchestrator,
utils::uninstall_code_and_return_empty_canisters_to_subnet_backup_pool, SubnetOrchestrator,
};

#[update(guard = "is_caller_controller")]
pub fn delete_all_creator_token() {
CANISTER_DATA.with_borrow_mut(|canister_data| {
canister_data
.cdao_canisters
.iter()
.for_each(|deployed_cdao_canisters| {
delete_sns_creator_token(deployed_cdao_canisters);
});

canister_data.cdao_canisters = vec![];
})
}

pub fn delete_sns_creator_token(deployed_canisters: &DeployedCdaoCanisters) {
let canister_ids = deployed_canisters.get_canister_ids();

const UNINSTALL_RECHARGE_AMOUNT: u128 = 300_000_000_000;

ic_cdk::spawn(async move {
let _ = request_cycles_from_subnet_orchestrator(5 * UNINSTALL_RECHARGE_AMOUNT).await;
for canister_id in canister_ids.iter() {
deposit_cycles(
CanisterIdRecord {
canister_id: *canister_id,
},
UNINSTALL_RECHARGE_AMOUNT,
)
.await;
}
uninstall_code_and_return_empty_canisters_to_subnet_backup_pool(canister_ids).await;
});
}
116 changes: 92 additions & 24 deletions src/canister/individual_user_template/src/api/cdao/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ use futures::{
use ic_base_types::PrincipalId;
use ic_cdk::{
api::{
call::RejectionCode,
call::{CallResult, RejectionCode},
management_canister::main::{
create_canister, deposit_cycles, install_code, update_settings, CanisterIdRecord,
CanisterInstallMode, CanisterSettings, CreateCanisterArgument, InstallCodeArgument,
UpdateSettingsArgument,
create_canister, deposit_cycles, install_code, uninstall_code, update_settings,
CanisterIdRecord, CanisterInstallMode, CanisterSettings, CreateCanisterArgument,
InstallCodeArgument, UpdateSettingsArgument,
},
},
query, update,
Expand All @@ -33,25 +33,28 @@ use shared_utils::{
error::CdaoDeployError,
session::SessionType,
},
common::types::known_principal::KnownPrincipalType,
common::{types::known_principal::KnownPrincipalType, utils::task::run_task_concurrently},
constant::{
MAX_LIMIT_FOR_CREATOR_DAO_SNS_TOKEN, NNS_LEDGER_CANISTER_ID, SNS_TOKEN_ARCHIVE_MODULE_HASH,
SNS_TOKEN_GOVERNANCE_MODULE_HASH, SNS_TOKEN_INDEX_MODULE_HASH,
SNS_TOKEN_LEDGER_MODULE_HASH, SNS_TOKEN_ROOT_MODULE_HASH, SNS_TOKEN_SWAP_MODULE_HASH,
USER_SNS_CANISTER_INITIAL_CYCLES,
},
};
use utils::uninstall_code_and_return_empty_canisters_to_subnet_backup_pool;

use crate::{
util::{
cycles::{notify_to_recharge_canister, request_cycles_from_subnet_orchestrator},
subnet_orchestrator::SubnetOrchestrator,
subnet_orchestrator::{self, SubnetOrchestrator},
},
CANISTER_DATA,
};

pub mod delete_all_sns_creator_token;
pub mod send_creator_dao_stats_to_subnet_orchestrator;
pub mod upgrade_creator_dao_governance_canisters;
pub mod utils;

#[update]
pub async fn settle_neurons_fund_participation(
Expand Down Expand Up @@ -135,21 +138,48 @@ async fn deploy_cdao_sns(
let subnet_orchestrator = SubnetOrchestrator::new()
.map_err(|e| CdaoDeployError::CallError(RejectionCode::CanisterError, e))?;

let number_of_canisters_required_to_be_alloted =
CANISTER_DATA.with_borrow(|canister_data| 5 - 5.min(canister_data.empty_canisters.len()));
// TODO: handle this bit of code.

(0..number_of_canisters_required_to_be_alloted)
.map(|_| subnet_orchestrator.allot_empty_canister())
.collect::<FuturesOrdered<_>>()
.try_collect()
.await
.map_err(|e| CdaoDeployError::CallError(RejectionCode::CanisterError, e))?;
let canister_ids_futures = (0..5).map(|_| subnet_orchestrator.allot_empty_canister());

let canister_ids = CANISTER_DATA
.with_borrow_mut(|canister_data| canister_data.empty_canisters.get_number_of_canister(5))
.map_err(|e| CdaoDeployError::CallError(RejectionCode::CanisterError, e))?;
let canister_ids_stream = futures::stream::iter(canister_ids_futures)
.boxed()
.buffer_unordered(5);

let canister_ids_results: Vec<Result<Principal, String>> =
canister_ids_stream.collect::<_>().await;

let canister_id_result = canister_ids_results
.iter()
.find(|canister_id_result| canister_id_result.is_err());

let mut canister_ids: Vec<Principal> = vec![];

if let Some(canister_id_error) = canister_id_result {
if let Err(e) = canister_id_error {
let canister_ids: Vec<Principal> = canister_ids_results
.iter()
.filter(|canister_id_result| canister_id_result.is_ok())
.map(|canister_id_result| canister_id_result.clone().unwrap())
.collect();

ic_cdk::spawn(
uninstall_code_and_return_empty_canisters_to_subnet_backup_pool(canister_ids),
);

return Err(CdaoDeployError::CallError(
RejectionCode::CanisterError,
e.clone(),
));
}
} else {
canister_ids = canister_ids_results
.into_iter()
.map(|canister_id_res| canister_id_res.unwrap())
.collect();
}

canister_ids
let deposit_cycles_result: CallResult<()> = canister_ids
.iter()
.map(|canister_id| {
deposit_cycles(
Expand All @@ -161,10 +191,18 @@ async fn deploy_cdao_sns(
})
.collect::<FuturesUnordered<_>>()
.try_collect()
.await?;
.await;

if let Err(e) = deposit_cycles_result {
ic_cdk::spawn(
uninstall_code_and_return_empty_canisters_to_subnet_backup_pool(canister_ids.clone()),
);
return Err(CdaoDeployError::CallError(e.0, e.1));
}

let canisters: Vec<PrincipalId> = canister_ids
.into_iter()
.iter()
.copied()
.map(|canister_id| PrincipalId::from(canister_id))
.collect();

Expand Down Expand Up @@ -219,7 +257,7 @@ async fn deploy_cdao_sns(

ic_cdk::println!("gov_hash: {:?}", gov_hash);

let mut wasm_bins: VecDeque<_> = [gov_hash, ledger_hash, root_hash, swap_hash, index_hash]
let wasm_bins_result: Result<_, _> = [gov_hash, ledger_hash, root_hash, swap_hash, index_hash]
.into_iter()
.map(|hash| async move {
let req = GetWasmRequest { hash };
Expand All @@ -229,7 +267,15 @@ async fn deploy_cdao_sns(
})
.collect::<FuturesOrdered<_>>()
.try_collect()
.await?;
.await;

if let Err(e) = wasm_bins_result {
ic_cdk::spawn(
uninstall_code_and_return_empty_canisters_to_subnet_backup_pool(canister_ids),
);
return Err(e);
}
let mut wasm_bins: VecDeque<_> = wasm_bins_result.unwrap();

let mut sns_install_futs = FuturesUnordered::new();
sns_install_futs.push(install_canister_wasm(
Expand Down Expand Up @@ -258,7 +304,18 @@ async fn deploy_cdao_sns(
Encode!(&payloads.index_ng).unwrap(),
index,
));
while sns_install_futs.try_next().await?.is_some() {}
while sns_install_futs
.try_next()
.await
.inspect_err(|e| {
ic_cdk::spawn(
uninstall_code_and_return_empty_canisters_to_subnet_backup_pool(
canister_ids.clone(),
),
)
})?
.is_some()
{}

let admin_canister = CANISTER_DATA
.with(|cdata| {
Expand Down Expand Up @@ -297,7 +354,18 @@ async fn deploy_cdao_sns(
index,
vec![admin_canister, user_can, root.0],
));
while update_ctrls_futs.try_next().await?.is_some() {}
while update_ctrls_futs
.try_next()
.await
.inspect_err(|_e| {
ic_cdk::spawn(
uninstall_code_and_return_empty_canisters_to_subnet_backup_pool(
canister_ids.clone(),
),
);
})?
.is_some()
{}

let deployed_cans = DeployedCdaoCanisters {
governance: governance.0,
Expand Down
58 changes: 58 additions & 0 deletions src/canister/individual_user_template/src/api/cdao/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use candid::Principal;
use ic_cdk::api::management_canister::main::{uninstall_code, CanisterIdRecord};
use shared_utils::common::utils::task::run_task_concurrently;

use crate::CANISTER_DATA;

use super::SubnetOrchestrator;

pub(crate) async fn uninstall_code_and_return_empty_canisters_to_subnet_backup_pool(
canister_ids: Vec<Principal>,
) {
let mut failed_to_return_canister_ids = vec![];
let subnet_orchestrator_res = SubnetOrchestrator::new().inspect_err(|_e| {
CANISTER_DATA.with_borrow_mut(|canister_data| {
canister_data
.empty_canisters
.append_empty_canisters(canister_ids.clone())
})
});

if let Ok(subnet_orchestrator) = subnet_orchestrator_res {
let uninstall_code_tasks = canister_ids.iter().map(|canister_id| async {
uninstall_code(CanisterIdRecord {
canister_id: *canister_id,
})
.await
.map_err(|e| (*canister_id, e.1))
});

let uninstall_callback = |uninstall_result: Result<(), (Principal, String)>| {
if let Err(e) = uninstall_result {
ic_cdk::println!("Error Uninstall Code from canister {}. Error: {}", e.0, e.1);
failed_to_return_canister_ids.push(e.0);
}
};

run_task_concurrently(uninstall_code_tasks, 10, uninstall_callback, || false);

let inserting_canisters_into_subnet_backup_pool_res = subnet_orchestrator
.insert_into_backup_pool(
canister_ids
.into_iter()
.filter(|canister_id| !failed_to_return_canister_ids.contains(canister_id))
.collect(),
)
.await;

if let Err(e) = inserting_canisters_into_subnet_backup_pool_res {
failed_to_return_canister_ids.extend(e.into_iter());
}

CANISTER_DATA.with_borrow_mut(|canister_data| {
canister_data
.empty_canisters
.append_empty_canisters(failed_to_return_canister_ids);
});
}
}
4 changes: 4 additions & 0 deletions src/canister/individual_user_template/src/data_model/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ impl AllotedEmptyCanister {
self.canister_ids.insert(canister_id)
}

pub fn append_empty_canisters(&mut self, canister_ids: Vec<Principal>) {
self.canister_ids.extend(canister_ids.into_iter());
}

pub fn len(&self) -> usize {
self.canister_ids.len()
}
Expand Down
6 changes: 3 additions & 3 deletions src/canister/individual_user_template/src/util/cycles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::CANISTER_DATA;

use super::subnet_orchestrator::{self, SubnetOrchestrator};

pub async fn request_cycles_from_subnet_orchestrator(amount: u128) -> Result<(), String> {
pub(crate) async fn request_cycles_from_subnet_orchestrator(amount: u128) -> Result<(), String> {
let subnet_orchestrator_canister_id = CANISTER_DATA
.with_borrow(|canister_data| {
canister_data
Expand All @@ -28,7 +28,7 @@ pub async fn request_cycles_from_subnet_orchestrator(amount: u128) -> Result<(),
result
}

pub fn notify_to_recharge_canister() {
pub(crate) fn notify_to_recharge_canister() {
if let Ok(subnet_orchestrator) = SubnetOrchestrator::new() {
let res = subnet_orchestrator.notify_to_receive_cycles_from_subnet_orchestrator();
if let Err(e) = res {
Expand All @@ -39,7 +39,7 @@ pub fn notify_to_recharge_canister() {
}
}

pub async fn recharge_canister() {
pub(crate) async fn recharge_canister() {
if let Ok(subnet_orchestrator) = SubnetOrchestrator::new() {
let res = subnet_orchestrator
.receive_cycles_from_subnet_orchestrator()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub trait Migration {
}

#[derive(Copy, Clone)]
pub struct IndividualUser {
pub(crate) struct IndividualUser {
pub canister_id: Principal,
pub profile_principal: Principal,
pub subnet_type: SubnetType,
Expand Down
Loading

0 comments on commit 5c26a88

Please sign in to comment.