11个版本
0.1.9 | 2024年3月13日 |
---|---|
0.1.8 | 2024年1月16日 |
0.1.7 | 2023年11月16日 |
0.1.6 | 2023年9月18日 |
0.0.0 | 2017年4月7日 |
#85 in 魔法豆
77KB
1.5K SLoC
Rustic框架
Rustic是一个用于在互联网计算机上开发canister的框架。
设计目标
- 简洁性。在大多数情况下,开发者不需要了解所有实现细节。
- 遵循最佳实践。这个库应该结合最新的canister开发知识。
- OpenZeppelin风格。应该实现其他链(如ETH)的大部分使用模式。
特性
- 访问:访问控制等同于OpenZeppelin Ownable2Step + 管理员列表
- 访问-角色:访问控制等同于OpenZeppelin AccessControl
- 审计事件:审计用事件
- 备份:备份数据
- 缓存:将频繁读取的数据缓存到堆中以提高性能
- 认证:认证查询
- 工厂:canister工厂
- https:具有指标等的canister的https接口
- 检查:更新方法的循环直方图
- 生命周期:canister生命周期管理
- 日志:canister在堆中的日志
- 稳定-日志:在稳定内存中的canister日志
- 暂停:等同于OpenZeppelin Pausable
- 支付:支付辅助工具
- 重入性:等同于OpenZeppelin ReentrancyGuard
- 测试:单元测试辅助工具
- 代币:可替换和非可替换代币
用法
开始之前
设置环境变量 RUSTIC_USER_PAGE_END
。此值不应在升级过程中更改!一旦设置了用户页面范围,就永远不能更改!确保为未来的升级留下足够的空间。要合理,不要设置值过高,因为你即使为空页面范围支付存储费用。
基本用法
查看示例。
稳定内存
互联网计算机的canister有4GB的堆内存,在canister升级期间会被清除,另外还有96GB的稳定内存,可以在canister升级期间保留。出于健壮性和可升级性的原因,我们应该几乎总是优先选择稳定内存。
rustic 框架提供了一个简单的方式来使用稳定内存,通过 ic-stable-structures
包。Rustic 使用以下内存映射
- 前 64 页被 rustic 预留用于使用。
- 用户页从
USER_PAGE_START
开始,即第 64 页。 - 用户可以在页面上存储具有已知有限大小的数据结构(即不能无限增长)直到
RUSTIC_USER_PAGE_END
,它在环境变量中定义。 - 剩余的内存由
MEMORY_MANAGER
管理,可用于存储无界数据结构(例如StableBTreeMap
和StableVec
)。 MEMORY_MANAGER
可以使用MemoryId
动态分配内存。每个数据结构的MemoryId
必须是唯一的。用户可用的MemoryId
范围是 [0,223],而 [224,255] 范围被 rustic 预留。
初始化和升级后钩子
该模块必须在主应用程序的初始化钩子中进行初始化。在所有其他内容之前必须首先初始化 rustic 模块。
# use ic_cdk::init;
#[init]
pub fn init () {
rustic::rustic_init();
// init code for your canister
}
该模块有一个升级后方法,你必须在升级后钩子中调用。
# use ic_cdk::post_upgrade;
#[post_upgrade]
pub fn post_upgrade () {
rustic::rustic_post_upgrade(false, true, false);
// post upgrade code for your canister
}
导出 Candid
export-candid
允许使用在 ic-cdk
v0.11 中引入的机制进行 candid 导出。然而,由于此机制的工作方式,candid 需要导出两次,一次是在你的应用程序中,一次是从 rustic 库中。
要从 rustic 导出 candid,使用带有 export-candid
功能的 rustic,并在你的主 canister 中注释掉 ic_cdk::export_candid!()
以避免冲突。然后生成一次 wasm,并使用 candid-extractor
提取 candid。
然后从你的主应用程序导出 candid,禁用 export-candid
功能,将 ic_cdk::export_candid!()
添加到你的主 canister 中,重新编译并再次提取 candid。
手动合并这两个 candid 文件,以获取你的 canister 的最终 candid。
生命周期
当使用 lifecycle
功能(默认启用)时,在新 canister 的升级后钩子中,通过调用 rustic::rustic_post_upgrade
来调用 lifecycle_on_upgrade
方法。对于 semver,你需要指定你是否想要进行主要/次要/补丁级别版本的提升。如果稳定内存布局发生了变化(确保你测试了兼容性,因为这不是 rustic 检查的),则提升稳定内存版本。如果你提升主要版本,则次要/补丁级别将被忽略,并将从 0 开始。
注意事项
永远不要在你的应用程序中使用预升级钩子。这个特性应该被认为是已弃用的。
注意事项
- 在单元测试期间不执行更新保护(或从 canister 内部的任何调用)。此行为与 Solidity 修改器保护不同。以下代码展开为
# use candid::Principal;
# use rustic::access_control::only_owner;
// This exported function contains the guard
// #[export_name = "canister_update transfer_ownership"]
fn transfer_ownership_0_() {
ic_cdk::setup();
let r: Result<(), String> = only_owner();
if let Err(e) = r {
ic_cdk::api::call::reject(&e);
return;
}
ic_cdk::spawn(async {
let (new_owner,) = ic_cdk::api::call::arg_data(ic_cdk::api::call::ArgDecoderConfig {
decoding_quota: None,
skipping_quota: Some(10000usize),
debug: false,
});
let result = transfer_ownership(new_owner);
ic_cdk::api::call::reply(())
});
}
// This internal function does not contain the guard
pub fn transfer_ownership(new_owner: Option<Principal>) {
// implemantation of transfer_ownership
}
为了使守卫同时适用于内部和外部调用,rustic-macros
包包含一个名为 modifiers
的宏,该宏同时适用于内部和外部调用。
- 访问控制仅在应用级别。请注意,还有一个系统级别的
controller
,它可以执行可以器升级。
已知问题
许可证
MIT
依赖关系
~3.5–5.5MB
~99K SLoC