as we’re focusing on toko for the time being, I’ve taken all the canister-specific functionality out of dragginz (and mimic) and moved it to ICU, a public utils repository.
Feel free to have a look around and if anything’s useful let me know. The general points are :
- root creates all the canisters at the top of the subnet heirarchy. root has all the WASMs
- each canister has a AppState, SubnetIndex, CanisterState and CanisterChildIndex which keeps track of the state of the application over multiple subnets.
- if any canister wants to create or upgrade a child it sends a request to root
- there are other abstracted pieces of code like authentication, guarding, that are hopefully quite flexible
- the interface/ directory provides an interface to all the inner workings of the code with proper error nesting.
- best practice serialization routines (probably) all in one place
- macros enable shared icu_* endpoints for any canister. ie. icu_canister_cycles_balance
So let’s say you wanted to create a “canister sharder” with custom logic, or an account canister that kept a list of user principals and associated canisters, you could scaffold these in icu and then use them over multiple projects.
Here’s some example code using both icu and mimic in toko…
use actor::canister::{self, ROOT};
use icu::{
interface::state::root::canister_registry::{self, CanisterDef, create_canisters},
prelude::*,
};
use mimic::prelude_actor::*;
//
// ICU
//
icu_start_root!(ROOT);
icu_memory_manager!();
fn _init() {
mimic_init();
register_canisters();
}
async fn _init_async() {
create_canisters().await.unwrap();
}
//
// MIMIC
//
mimic_start!();
// register_canisters
fn register_canisters() {
let canisters: &[(&'static str, CanisterDef, &'static [u8])] = &[
(
canister::ACCOUNT,
CanisterDef { auto_create: true, is_sharded: false },
include_bytes!("../../../../../.dfx/local/canisters/account/account.wasm.gz"),
),
(
canister::ASSET,
CanisterDef { auto_create: false, is_sharded: true },
include_bytes!("../../../../../.dfx/local/canisters/asset/asset.wasm.gz"),
),
(
canister::ASSET_ROUTER,
CanisterDef { auto_create: false, is_sharded: false },
include_bytes!(
"../../../../../.dfx/local/canisters/asset_router/asset_router.wasm.gz"
),
),
(
canister::CONFIG,
CanisterDef { auto_create: true, is_sharded: false },
include_bytes!("../../../../../.dfx/local/canisters/config/config.wasm.gz"),
),
(
canister::LEDGER,
CanisterDef { auto_create: false, is_sharded: true },
include_bytes!("../../../../../.dfx/local/canisters/ledger/ledger.wasm.gz"),
),
(
canister::LEDGER_ARCHIVE,
CanisterDef { auto_create: false, is_sharded: true },
include_bytes!(
"../../../../../.dfx/local/canisters/ledger_archive/ledger_archive.wasm.gz"
),
),
(
canister::LEDGER_INDEX,
CanisterDef { auto_create: false, is_sharded: true },
include_bytes!(
"../../../../../.dfx/local/canisters/ledger_index/ledger_index.wasm.gz"
),
),
(
canister::MARKET,
CanisterDef { auto_create: true, is_sharded: false },
include_bytes!("../../../../../.dfx/local/canisters/market/market.wasm.gz"),
),
(
canister::PROJECT,
CanisterDef { auto_create: false, is_sharded: true },
include_bytes!("../../../../../.dfx/local/canisters/project/project.wasm.gz"),
),
(
canister::WILD,
CanisterDef { auto_create: true, is_sharded: false },
include_bytes!("../../../../../.dfx/local/canisters/wild/wild.wasm.gz"),
),
];
for (path, def, wasm) in canisters {
canister_registry::add_canister(path, def, wasm).unwrap();
}
}
//
// API
//
// end
export_candid!();
Worth bookmarking as it’s definitely going to grow into a proper multi-canister utils thingy over time. We’ve got multiple projects using it so it should be quite battle-tested eventually.
icu/src/memory/counter.rs at main · dragginzgame/icu · GitHub - my question was why doesn’t a pattern like this exist in ic-stable-structures? Is there a reason it doesn’t exist? o.0