diff --git a/Cargo.lock b/Cargo.lock index 0853bd4f2..9c766da64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,7 +218,7 @@ dependencies = [ [[package]] name = "candid-extractor" -version = "0.1.1" +version = "0.1.2" dependencies = [ "anyhow", "quote", @@ -883,7 +883,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "ic-cdk" -version = "0.11.1" +version = "0.11.2" dependencies = [ "candid", "ic-cdk-macros", @@ -983,7 +983,7 @@ dependencies = [ [[package]] name = "ic0" -version = "0.21.0" +version = "0.21.1" dependencies = [ "quote", "syn 1.0.107", diff --git a/Cargo.toml b/Cargo.toml index dce58e555..d4ce5c0e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,8 +19,8 @@ lto = true opt-level = 'z' [workspace.dependencies] -ic0 = { path = "src/ic0", version = "0.21.0" } -ic-cdk = { path = "src/ic-cdk", version = "0.11.1" } +ic0 = { path = "src/ic0", version = "0.21.1" } +ic-cdk = { path = "src/ic-cdk", version = "0.11.2" } ic-cdk-timers = { path = "src/ic-cdk-timers", version = "0.5.0" } candid = "0.9.6" diff --git a/e2e-tests/canisters/api_call.rs b/e2e-tests/canisters/api_call.rs index 7603147b1..2f8f90002 100644 --- a/e2e-tests/canisters/api_call.rs +++ b/e2e-tests/canisters/api_call.rs @@ -1,4 +1,4 @@ -use ic_cdk::{api::call::ManualReply, query}; +use ic_cdk::{api::call::ManualReply, query, update}; #[query] fn instruction_counter() -> u64 { @@ -10,4 +10,9 @@ fn manual_reject() -> ManualReply { ManualReply::reject("manual reject") } +#[update] +fn cycles_burn(amount: u128) -> u128 { + ic_cdk::api::cycles_burn(amount) +} + fn main() {} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 39f637a95..20f2129e3 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -439,3 +439,36 @@ fn test_canister_info() { } ); } + +#[test] +fn test_cycles_burn() { + let env = env(); + let wasm = cargo_build_canister("api-call"); + let canister_id = env.create_canister(None); + env.add_cycles(canister_id, 1500); + + env.install_canister(canister_id, wasm, vec![], None); + eprintln!("Canister installed."); + let balance1 = env.cycle_balance(canister_id); + eprintln!("Balance 1: {balance1}"); + + let attempted = 1000u128; + + // Scenario 1: burn less than balance + let (burned,): (u128,) = call_candid(&env, canister_id, "cycles_burn", (attempted,)) + .expect("Error calling cycles_burn"); + eprintln!("Attempted to burn {attempted}, actually burned {burned}"); + assert_eq!(burned, attempted); + let balance2 = env.cycle_balance(canister_id); + eprintln!("Balance 2: {balance2}"); + + // Scenario 2: burn more than balance + let (burned,): (u128,) = call_candid(&env, canister_id, "cycles_burn", (attempted,)) + .expect("Error calling cycles_burn"); + eprintln!("Attempted to burn {attempted}, actually burned {burned}"); + assert!(burned < attempted); + assert_eq!(burned, balance2); + let balance3 = env.cycle_balance(canister_id); + eprintln!("Balance 3: {balance3}"); + assert_eq!(balance3, 0); +} diff --git a/ic0.txt b/ic0.txt index eaff356c6..29955e510 100644 --- a/ic0.txt +++ b/ic0.txt @@ -17,6 +17,7 @@ ic0.msg_cycles_refunded128 : (dst : i32) -> (); // R ic0.msg_cycles_accept : (max_amount : i64) -> (amount : i64); // U Rt Ry ic0.msg_cycles_accept128 : (max_amount_high : i64, max_amount_low: i64, dst : i32) -> (); // U Rt Ry +ic0.cycles_burn128 : (amount_high : i64, amount_low : i64, dst : i32) -> ();// I G U Ry Rt C T ic0.canister_self_size : () -> i32; // * ic0.canister_self_copy : (dst : i32, offset : i32, size : i32) -> (); // * diff --git a/scripts/download_state_machine_binary.sh b/scripts/download_state_machine_binary.sh index b44136a01..5b8995d9a 100755 --- a/scripts/download_state_machine_binary.sh +++ b/scripts/download_state_machine_binary.sh @@ -8,7 +8,7 @@ cd "$SCRIPTS_DIR/.." uname_sys=$(uname -s | tr '[:upper:]' '[:lower:]') echo "uname_sys: $uname_sys" -commit_sha="b314222935b7d06c70036b0b54aa80a33252d79c" +commit_sha="15e69667ae983fa92c33794a3954d9ca87518af6" curl -sLO "https://download.dfinity.systems/ic/$commit_sha/binaries/x86_64-$uname_sys/ic-test-state-machine.gz" gzip -d ic-test-state-machine.gz diff --git a/src/candid-extractor/Cargo.toml b/src/candid-extractor/Cargo.toml index de2c44d77..024ba79d2 100644 --- a/src/candid-extractor/Cargo.toml +++ b/src/candid-extractor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid-extractor" -version = "0.1.1" +version = "0.1.2" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/candid-extractor/ic_mock.wat b/src/candid-extractor/ic_mock.wat index da53f6bdc..17e1f5d41 100644 --- a/src/candid-extractor/ic_mock.wat +++ b/src/candid-extractor/ic_mock.wat @@ -17,6 +17,7 @@ (func (export "msg_cycles_refunded128") (param i32) ) (func (export "msg_cycles_accept") (param i64) (result i64) i64.const 0) (func (export "msg_cycles_accept128") (param i64 i64 i32) ) + (func (export "cycles_burn128") (param i64 i64 i32) ) (func (export "canister_self_size") (result i32) i32.const 0) (func (export "canister_self_copy") (param i32 i32 i32) ) (func (export "canister_cycle_balance") (result i64) i64.const 0) diff --git a/src/ic-cdk/CHANGELOG.md b/src/ic-cdk/CHANGELOG.md index 7b93ba3f0..9403d1e0c 100644 --- a/src/ic-cdk/CHANGELOG.md +++ b/src/ic-cdk/CHANGELOG.md @@ -6,6 +6,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.11.2] - 2023-10-11 + +### Added + +- `cycles_burn` corresponding to system API `ic0.cycles_burn128`. (#434) + +### Changed + +- Upgrade `ic0` to `0.21.1`. (#434) + +## [0.11.1] - 2023-10-11 + +### Changed + +- Upgrade `ic0` to `0.21.0`. (#433) + ## [0.11.0] - 2023-09-18 ### Changed diff --git a/src/ic-cdk/Cargo.toml b/src/ic-cdk/Cargo.toml index 5876cd9f5..7a0d80e3d 100644 --- a/src/ic-cdk/Cargo.toml +++ b/src/ic-cdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-cdk" -version = "0.11.1" +version = "0.11.2" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic-cdk/src/api/mod.rs b/src/ic-cdk/src/api/mod.rs index 1ce2f9daa..6aa92d828 100644 --- a/src/ic-cdk/src/api/mod.rs +++ b/src/ic-cdk/src/api/mod.rs @@ -140,3 +140,21 @@ pub fn is_controller(principal: &Principal) -> bool { // SAFETY: `principal.as_bytes()`, being `&[u8]`, is a readable sequence of bytes and therefore safe to pass to `ic0.is_controller`. unsafe { ic0::is_controller(slice.as_ptr() as i32, slice.len() as i32) != 0 } } + +/// Burns cycles from the canister. +/// +/// Returns the amount of cycles that were actually burned. +pub fn cycles_burn(amount: u128) -> u128 { + let amount_high = (amount >> 64) as u64; + let amount_low = (amount & u64::MAX as u128) as u64; + let mut dst = 0u128; + // SAFETY: `dst` is writable and sixteen bytes wide, and therefore safe to pass to ic0.cycles_burn128 + unsafe { + ic0::cycles_burn128( + amount_high as i64, + amount_low as i64, + &mut dst as *mut u128 as i32, + ) + } + dst +} diff --git a/src/ic0/Cargo.toml b/src/ic0/Cargo.toml index 700cf38fb..540cb3d99 100644 --- a/src/ic0/Cargo.toml +++ b/src/ic0/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic0" -version = "0.21.0" +version = "0.21.1" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/src/ic0/src/ic0.rs b/src/ic0/src/ic0.rs index f5c2ba03c..bac51bf5f 100644 --- a/src/ic0/src/ic0.rs +++ b/src/ic0/src/ic0.rs @@ -19,6 +19,7 @@ extern "C" { pub fn msg_cycles_refunded128(dst: i32); pub fn msg_cycles_accept(max_amount: i64) -> i64; pub fn msg_cycles_accept128(max_amount_high: i64, max_amount_low: i64, dst: i32); + pub fn cycles_burn128(amount_high: i64, amount_low: i64, dst: i32); pub fn canister_self_size() -> i32; pub fn canister_self_copy(dst: i32, offset: i32, size: i32); pub fn canister_cycle_balance() -> i64; @@ -116,6 +117,9 @@ mod non_wasm { pub unsafe fn msg_cycles_accept128(max_amount_high: i64, max_amount_low: i64, dst: i32) { panic!("msg_cycles_accept128 should only be called inside canisters."); } + pub unsafe fn cycles_burn128(amount_high: i64, amount_low: i64, dst: i32) { + panic!("cycles_burn128 should only be called inside canisters."); + } pub unsafe fn canister_self_size() -> i32 { panic!("canister_self_size should only be called inside canisters."); }