I think we’ve discovered a bug in the Rust CDK. Currently ic_cdk_macros allows guard functions on init, pre_upgrade, and post_upgrade. But the expanded code for the guard function macro results in a call to ic0.msg_reject, which is not allowed from canister_init, canister_post_upgrade, or canister_pre_upgrade according to the current interface spec. We also see this error in our CI tests for guard functions in Azle.
Here’s the expanded code for a guard function:
#[export_name = "canister_pre_upgrade"]
fn pre_upgrade_4_() {
ic_cdk::setup();
let r: Result<(), String> = _cdk_user_defined_preventUpgrades();
if let Err(e) = r {
ic_cdk::api::call::reject(&e);
return;
}
ic_cdk::spawn(async {
let result = pre_upgrade();
});
}
And here’s where the interface spec describes where ic0.msg_reject can be called from:
ic0.msg_reject : (src : i32, size : i32) → (); // U Q CQ Ry Rt CRy CRt
Seems like the Rust CDK is incorrect in allowing guard functions for init, pre_upgrade and post_upgrade.