Crate canister_tools

source ·
Expand description

A Rust library for canisters on the internet-computer.

Features

  • Easy simple upgrade strategy.
  • Safe data snapshots management manual upload and download of the canister data.

Each global data structure is set and registered with a MemoryId in the canister_init hook and in the canister_post_upgrade hook. On an upgrade, the library will serialize the registered data structures into the corresponding MemoryId.

For a global data type to be serializable, it must implement the Serializable trait. Types that implement candid’s CandidType and Deserialize traits auto-implement the Serializable trait with the candid binary serialization format.

For the safety and to make sure that your data is always accessible even if something goes wrong in the pre_upgrade hook or elsewhere, this library creates canister methods that can be used in those cases to download and upload the canister data.

This library creates the following canister methods for the state-snapshot management and stable-memory management.

type MemoryId = nat8;
type Offset = nat64;
type Length = nat64;
type StateSnapshotLength = nat64;
type WasmPages = nat64;
 
service : {
    // Takes a snapshot of the data structure registered at the given MemoryId.
    controller_create_state_snapshot : (MemoryId) -> (StateSnapshotLength);
     
    // Download the snapshot of the data corresponding to the given MemoryId.
    // Download the data in chunks.
    controller_download_state_snapshot : (MemoryId, Offset, Length) -> (blob) query;
     
    // Clears the snapshot of the data corresponding to the given MemoryId.
    // When uploading data onto the data structure, call this method first to clear
    // the snapshot before uploading a customized snapshot.
    controller_clear_state_snapshot : (MemoryId) -> ();
     
    // Upload the serialized data structure for the given MemoryId in chunks that can then be deserialized and loaded onto the canister global variable.   
    controller_append_state_snapshot : (MemoryId, blob) -> ();
     
    // Deserializes the snapshot for the data structure corresponding to the given MemoryId
    // and loads it onto the canister's global variable.
    controller_load_state_snapshot : (MemoryId) -> ();
 


    // Common stable memory functions as canister methods.
    // Useful when using a custom stable-memory strategy for one or some of the MemoryIds. 
    controller_stable_memory_read : (MemoryId, Offset, Length) -> (blob) query;
    controller_stable_memory_write : (MemoryId, Offset, blob) -> ();
    controller_stable_memory_size : (MemoryId) -> (nat64) query;
    controller_stable_memory_grow : (MemoryId, WasmPages) -> (int64);
}

§Sample

use core::cell::RefCell;
use ic_cdk::{
    update,
    query,    
    init,
    pre_upgrade,
    post_upgrade
};
use candid::{CandidType, Deserialize};
use canister_tools::{
    MemoryId,
    localkey::refcell::{with, with_mut},
};
 
 
 
const DATA_UPGRADE_SERIALIZATION_MEMORY_ID: MemoryId = MemoryId::new(0);
 
 
#[derive(CandidType, Deserialize)]
struct Data {
    field_one: String,
    field_two: u64,
}
 
 
thread_local! {
    static DATA: RefCell<Data> = RefCell::new(
        Data{
            field_one: String::from("Hi World"),
            field_two: 55
        }
    );
}
 
#[init]
fn init() {
    canister_tools::init(&DATA, DATA_UPGRADE_SERIALIZATION_MEMORY_ID);
}
 
#[pre_upgrade]
fn pre_upgrade() {
    canister_tools::pre_upgrade();
}
 
#[post_upgrade]
fn post_upgrade() {
    canister_tools::post_upgrade(&DATA, DATA_UPGRADE_SERIALIZATION_MEMORY_ID, None::<fn(Data) -> Data>);
}
 
 
 
#[query]
pub fn get_field_two() -> u64 {
    with(&DATA, |data| {
        data.field_two
    })
}
 
#[update]
pub fn set_field_two(value: u64) {
    with_mut(&DATA, |data| {
        data.field_two = value;
    });
}

Modules§

Structs§

Traits§

  • A trait that specifies how the data structure will be serialized for the upgrades and for the snapshots. This trait is implemented with the candid serialization format for any type that implements the CandidType and Deserialize traits.

Functions§

  • Gets the stable memory of the memory_id.
  • Call this function in the canister_init method. This function registers the data structure with the memory_id for the upgrades and snapshots.
  • Call this function in the post_upgrade_hook. Deserializes the data stored at the memory_id and loads it onto the global variable. Then registers the global variable with the memory_id for the next upgrade and for the state-snapshots.
  • Call this function in the pre_upgrade hook. Serializes each registered global variable into the corresponding stable-memory-id that it is registerd with.