I have a function that inserts wasm blob into stable memory as shown below:
async fn start_upgrades_for_individual_canisters(version: String, individual_user_wasm: Vec<u8>) -> String {
if !is_controller(&caller()) {
panic!("Unauthorized caller");
}
CANISTER_DATA.with_borrow_mut(|canister_data| {
canister_data.allow_upgrades_for_individual_canisters = true;
canister_data.last_run_upgrade_status.version = version.clone();
let canister_wasm = CanisterWasm {
version: version.clone(),
wasm_blob: individual_user_wasm.clone()
};
canister_data.wasms.insert(WasmType::IndividualUserWasm, canister_wasm);
});
ic_cdk::spawn(update_user_index_upgrade_user_canisters_with_latest_wasm::upgrade_user_canisters_with_latest_wasm(version, individual_user_wasm));
"Success".to_string()
}
thread_local! {
static CANISTER_DATA: RefCell<CanisterData> = RefCell::default();
}
#[derive(Serialize, Deserialize)]
pub struct CanisterData {
pub configuration: Configuration,
pub last_run_upgrade_status: UpgradeStatus,
pub allow_upgrades_for_individual_canisters: bool,
pub available_canisters: HashSet<Principal>,
pub user_principal_id_to_canister_id_map: BTreeMap<Principal, Principal>,
pub unique_user_name_to_user_principal_id_map: BTreeMap<String, Principal>,
#[serde(skip, default = "_empty_wasms")]
pub wasms: StableBTreeMap<WasmType,CanisterWasm, Memory>
}
impl Default for CanisterData {
fn default() -> Self {
Self { configuration: Default::default(), last_run_upgrade_status: Default::default(), allow_upgrades_for_individual_canisters: Default::default(), available_canisters: Default::default(), user_principal_id_to_canister_id_map: Default::default(), unique_user_name_to_user_principal_id_map: Default::default(), wasms: _empty_wasms() }
}
}
fn _empty_wasms() -> StableBTreeMap<WasmType, CanisterWasm, Memory> {
StableBTreeMap::init(get_wasm_memory())
}
Stable memory initialisation
use ic_stable_structures::{DefaultMemoryImpl, memory_manager::{MemoryId, VirtualMemory, MemoryManager}};
use std::cell::RefCell;
// A memory for upgrades, where data from the heap can be serialized/deserialized.
const UPGRADES: MemoryId = MemoryId::new(0);
// A memory for the StableVec for individual_user wasm.
const INDIVIDUAL_USER_WASM_MEMORY: MemoryId = MemoryId::new(1);
pub type Memory = VirtualMemory<DefaultMemoryImpl>;
thread_local! {
// The memory manager is used for simulating multiple memories. Given a `MemoryId` it can
// return a memory that can be used by stable structures.
static MEMORY_MANAGER: RefCell<MemoryManager<DefaultMemoryImpl>> =
RefCell::new(MemoryManager::init(DefaultMemoryImpl::default()));
}
pub fn get_upgrades_memory() -> Memory {
MEMORY_MANAGER.with(|m| m.borrow_mut().get(UPGRADES))
}
pub fn get_wasm_memory() -> Memory {
MEMORY_MANAGER.with_borrow_mut(|m| m.get(INDIVIDUAL_USER_WASM_MEMORY))
}
I am calling this function from another canister and it fails saying Canister trapped: MemoryId(1): grow failed
. Interesting part is I have two such canisters in one of them the call passes and in other it fails. Both the canisters have same module hash