diff --git a/Cargo.lock b/Cargo.lock index ed6c78d48d..34d63ca273 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -303,6 +303,12 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "argon2" version = "0.4.1" @@ -351,6 +357,17 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + [[package]] name = "async-io" version = "1.13.0" @@ -402,6 +419,15 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "async-watch" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a078faf4e27c0c6cc0efb20e5da59dcccc04968ebf2801d8e0b2195124cdcdb2" +dependencies = [ + "event-listener 2.5.3", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -1582,7 +1608,7 @@ dependencies = [ "ic-asset", "ic-cdk", "ic-identity-hsm", - "ic-utils 0.39.0", + "ic-utils 0.39.2", "ic-wasm", "icrc-ledger-types", "idl2json", @@ -1657,7 +1683,7 @@ dependencies = [ "humantime-serde", "ic-agent", "ic-identity-hsm", - "ic-utils 0.39.0", + "ic-utils 0.39.2", "itertools 0.10.5", "k256 0.11.6", "keyring", @@ -2732,12 +2758,14 @@ dependencies = [ [[package]] name = "ic-agent" -version = "0.39.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158138fcb769fe6288e63d5db221c904e472cfb7d376aba13a38c060f2984e63" +version = "0.39.2" +source = "git+https://github.com/dfinity/agent-rs?rev=0a51f2a65dde7d9e1790c378bd60e1768e3be257#0a51f2a65dde7d9e1790c378bd60e1768e3be257" dependencies = [ + "arc-swap", + "async-channel", "async-lock 3.4.0", "async-trait", + "async-watch", "backoff", "cached 0.52.0", "candid", @@ -2749,8 +2777,8 @@ dependencies = [ "hex", "http 1.2.0", "http-body 1.0.1", - "ic-certification 2.6.0", - "ic-transport-types 0.39.1", + "ic-certification 3.0.2", + "ic-transport-types 0.39.2", "ic-verify-bls-signature", "k256 0.13.4", "leb128", @@ -2767,7 +2795,8 @@ dependencies = [ "serde_repr", "sha2 0.10.8", "simple_asn1", - "thiserror 1.0.69", + "stop-token", + "thiserror 2.0.6", "time", "tokio", "tower-service", @@ -2789,7 +2818,7 @@ dependencies = [ "globset", "hex", "ic-agent", - "ic-utils 0.39.0", + "ic-utils 0.39.2", "itertools 0.10.5", "json5", "mime", @@ -2933,6 +2962,18 @@ dependencies = [ "sha2 0.10.8", ] +[[package]] +name = "ic-certification" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eae40f26fcac9c141cad54d9aa5f423efffde78ac371057c53d275ebbcad443" +dependencies = [ + "hex", + "serde", + "serde_bytes", + "sha2 0.10.8", +] + [[package]] name = "ic-certification-testing" version = "2.3.0" @@ -3176,16 +3217,15 @@ dependencies = [ [[package]] name = "ic-identity-hsm" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8722411845f0a4b2c526b906049d45f87c62c78ddf1c38ecdc03ecbd34ffc1d6" +version = "0.39.2" +source = "git+https://github.com/dfinity/agent-rs?rev=0a51f2a65dde7d9e1790c378bd60e1768e3be257#0a51f2a65dde7d9e1790c378bd60e1768e3be257" dependencies = [ "hex", "ic-agent", "pkcs11", "sha2 0.10.8", "simple_asn1", - "thiserror 1.0.69", + "thiserror 2.0.6", ] [[package]] @@ -3294,20 +3334,19 @@ dependencies = [ [[package]] name = "ic-transport-types" -version = "0.39.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d8789a5c176bb1b925fa58ca97c651a3995d504e76101e93d2a17f558bdcf66" +version = "0.39.2" +source = "git+https://github.com/dfinity/agent-rs?rev=0a51f2a65dde7d9e1790c378bd60e1768e3be257#0a51f2a65dde7d9e1790c378bd60e1768e3be257" dependencies = [ "candid", "hex", - "ic-certification 2.6.0", + "ic-certification 3.0.2", "leb128", "serde", "serde_bytes", "serde_cbor", "serde_repr", "sha2 0.10.8", - "thiserror 1.0.69", + "thiserror 2.0.6", ] [[package]] @@ -3365,9 +3404,8 @@ dependencies = [ [[package]] name = "ic-utils" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb1da4a68c45146018b8496c157ad94126b9c202ab4400c6c0a9030c1ef0f0ba" +version = "0.39.2" +source = "git+https://github.com/dfinity/agent-rs?rev=0a51f2a65dde7d9e1790c378bd60e1768e3be257#0a51f2a65dde7d9e1790c378bd60e1768e3be257" dependencies = [ "async-trait", "candid", @@ -3380,7 +3418,7 @@ dependencies = [ "sha2 0.10.8", "strum 0.26.3", "strum_macros 0.26.4", - "thiserror 1.0.69", + "thiserror 2.0.6", "time", "tokio", ] @@ -3617,7 +3655,7 @@ dependencies = [ "humantime", "ic-agent", "ic-asset", - "ic-utils 0.39.0", + "ic-utils 0.39.2", "libflate 1.4.0", "num-traits", "pem 1.1.1", @@ -6081,6 +6119,18 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "stop-token" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af91f480ee899ab2d9f8435bfdfc14d08a5754bd9d3fef1f1a1c23336aad6c8b" +dependencies = [ + "async-channel", + "cfg-if", + "futures-core", + "pin-project-lite", +] + [[package]] name = "string_cache" version = "0.8.7" diff --git a/Cargo.toml b/Cargo.toml index 6b3e137c27..58bbde2814 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,11 +22,11 @@ license = "Apache-2.0" candid = "0.10.11" candid_parser = "0.1.4" dfx-core = { path = "src/dfx-core", version = "0.1.0" } -ic-agent = "0.39" +ic-agent = { version = "0.39", git = "https://github.com/dfinity/agent-rs", rev = "0a51f2a65dde7d9e1790c378bd60e1768e3be257" } ic-asset = { path = "src/canisters/frontend/ic-asset", version = "0.21.0" } ic-cdk = "0.13.1" -ic-identity-hsm = "0.39" -ic-utils = "0.39" +ic-identity-hsm = { version = "0.39", git = "https://github.com/dfinity/agent-rs", rev = "0a51f2a65dde7d9e1790c378bd60e1768e3be257" } +ic-utils = { version = "0.39", git = "https://github.com/dfinity/agent-rs", rev = "0a51f2a65dde7d9e1790c378bd60e1768e3be257" } aes-gcm = "0.10.3" anyhow = "1.0.56" diff --git a/e2e/assets/allocate_memory/src/e2e_project_backend/src/lib.rs b/e2e/assets/allocate_memory/src/e2e_project_backend/src/lib.rs index 7ea906db17..3d9a93c679 100644 --- a/e2e/assets/allocate_memory/src/e2e_project_backend/src/lib.rs +++ b/e2e/assets/allocate_memory/src/e2e_project_backend/src/lib.rs @@ -7,3 +7,8 @@ fn greet(s: String) -> String { fn greet_update(s: String) -> String { format!("Hello, {s}!") } + +#[ic_cdk::on_low_wasm_memory] +fn on_low_wasm_memory() { + ic_cdk::println!("Low memory!"); +} diff --git a/e2e/tests-dfx/update_settings.bash b/e2e/tests-dfx/update_settings.bash index 74d668cf61..399baeca50 100644 --- a/e2e/tests-dfx/update_settings.bash +++ b/e2e/tests-dfx/update_settings.bash @@ -61,6 +61,23 @@ teardown() { assert_contains "Canister exceeded its current Wasm memory limit of 8 bytes" } +@test "set wasm memory threshold" { + dfx_new_rust + install_asset allocate_memory + dfx_start + assert_command dfx canister create e2e_project_backend --no-wallet --wasm-memory-threshold 2MiB --wasm-memory-limit 2MiB + assert_command dfx deploy e2e_project_backend + assert_command dfx canister status e2e_project_backend + assert_contains "Wasm memory threshold: 2_097_152 Bytes" + assert_command dfx canister update-settings e2e_project_backend --wasm-memory-threshold 1MiB + assert_command dfx canister status e2e_project_backend + assert_contains "Wasm memory threshold: 1_048_576 Bytes" + assert_command dfx canister call e2e_project_backend greet_update '("alice")' + sleep 10ms + assert_command dfx canister logs e2e_project_backend + assert_contains "Low memory!" +} + @test "set log visibility" { dfx_new dfx_start diff --git a/src/dfx-core/src/config/model/dfinity.rs b/src/dfx-core/src/config/model/dfinity.rs index e26edada97..e05b1ecfd5 100644 --- a/src/dfx-core/src/config/model/dfinity.rs +++ b/src/dfx-core/src/config/model/dfinity.rs @@ -16,11 +16,13 @@ use crate::error::dfx_config::GetRemoteCanisterIdError::GetRemoteCanisterIdFaile use crate::error::dfx_config::GetReservedCyclesLimitError::GetReservedCyclesLimitFailed; use crate::error::dfx_config::GetSpecifiedIdError::GetSpecifiedIdFailed; use crate::error::dfx_config::GetWasmMemoryLimitError::GetWasmMemoryLimitFailed; +use crate::error::dfx_config::GetWasmMemoryThresholdError::GetWasmMemoryThresholdFailed; use crate::error::dfx_config::{ AddDependenciesError, GetCanisterConfigError, GetCanisterNamesWithDependenciesError, GetComputeAllocationError, GetFreezingThresholdError, GetLogVisibilityError, GetMemoryAllocationError, GetPullCanistersError, GetRemoteCanisterIdError, GetReservedCyclesLimitError, GetSpecifiedIdError, GetWasmMemoryLimitError, + GetWasmMemoryThresholdError, }; use crate::error::fs::CanonicalizePathError; use crate::error::load_dfx_config::LoadDfxConfigError; @@ -477,6 +479,21 @@ pub struct InitializationValues { #[schemars(with = "Option")] pub wasm_memory_limit: Option, + /// # Wasm Memory Threshold + /// + /// Specifies a threshold (in bytes) on the Wasm memory usage of the canister, + /// as a distance from `wasm_memory_limit`. + /// + /// When the remaining memory before the limit drops below this threshold, its + /// `on_low_wasm_memory` hook will be invoked. This enables it to self-optimize, + /// or raise an alert, or otherwise attempt to prevent itself from reaching + /// `wasm_memory_limit`. + /// + /// Must be a number of bytes between 0 and 2^48 (i.e. 256 TiB), inclusive. + /// Can be specified as an integer, or as an SI unit string (e.g. "4KB", "2 MiB") + #[schemars(with = "Option")] + pub wasm_memory_threshold: Option, + /// # Log Visibility /// Specifies who is allowed to read the canister's logs. /// @@ -1004,6 +1021,17 @@ impl ConfigInterface { .wasm_memory_limit) } + pub fn get_wasm_memory_threshold( + &self, + canister_name: &str, + ) -> Result, GetWasmMemoryThresholdError> { + Ok(self + .get_canister_config(canister_name) + .map_err(|e| GetWasmMemoryThresholdFailed(canister_name.to_string(), e))? + .initialization_values + .wasm_memory_threshold) + } + pub fn get_log_visibility( &self, canister_name: &str, diff --git a/src/dfx-core/src/error/dfx_config.rs b/src/dfx-core/src/error/dfx_config.rs index fa2e59c051..dabd5aea76 100644 --- a/src/dfx-core/src/error/dfx_config.rs +++ b/src/dfx-core/src/error/dfx_config.rs @@ -58,6 +58,12 @@ pub enum GetWasmMemoryLimitError { GetWasmMemoryLimitFailed(String, #[source] GetCanisterConfigError), } +#[derive(Error, Debug)] +pub enum GetWasmMemoryThresholdError { + #[error("Failed to get Wasm memory threshold for canister '{0}'")] + GetWasmMemoryThresholdFailed(String, #[source] GetCanisterConfigError), +} + #[derive(Error, Debug)] pub enum GetLogVisibilityError { #[error("Failed to get log visibility for canister '{0}'")] diff --git a/src/dfx/assets/project_templates/rust/src/__backend_name__/Cargo.toml b/src/dfx/assets/project_templates/rust/src/__backend_name__/Cargo.toml index 413f5fa468..f0a6ce3715 100644 --- a/src/dfx/assets/project_templates/rust/src/__backend_name__/Cargo.toml +++ b/src/dfx/assets/project_templates/rust/src/__backend_name__/Cargo.toml @@ -10,5 +10,5 @@ crate-type = ["cdylib"] [dependencies] candid = "0.10" -ic-cdk = "0.16" -ic-cdk-timers = "0.10" # Feel free to remove this dependency if you don't need timers +ic-cdk = "0.17" +ic-cdk-timers = "0.11" # Feel free to remove this dependency if you don't need timers diff --git a/src/dfx/src/commands/canister/call.rs b/src/dfx/src/commands/canister/call.rs index 1a740f7307..aecf4d9a56 100644 --- a/src/dfx/src/commands/canister/call.rs +++ b/src/dfx/src/commands/canister/call.rs @@ -145,6 +145,7 @@ pub fn get_effective_canister_id( | MgmtMethod::BitcoinGetUtxos | MgmtMethod::BitcoinSendTransaction | MgmtMethod::BitcoinGetCurrentFeePercentiles + | MgmtMethod::BitcoinGetBlockHeaders | MgmtMethod::EcdsaPublicKey | MgmtMethod::SignWithEcdsa | MgmtMethod::NodeMetricsHistory => Ok(CanisterId::management_canister()), diff --git a/src/dfx/src/commands/canister/create.rs b/src/dfx/src/commands/canister/create.rs index 368ee604f5..a0e5a610c1 100644 --- a/src/dfx/src/commands/canister/create.rs +++ b/src/dfx/src/commands/canister/create.rs @@ -4,7 +4,7 @@ use crate::lib::environment::Environment; use crate::lib::error::{DfxError, DfxResult}; use crate::lib::ic_attributes::{ get_compute_allocation, get_freezing_threshold, get_log_visibility, get_memory_allocation, - get_reserved_cycles_limit, get_wasm_memory_limit, CanisterSettings, + get_reserved_cycles_limit, get_wasm_memory_limit, get_wasm_memory_threshold, CanisterSettings, }; use crate::lib::operations::canister::{create_canister, skip_remote_canister}; use crate::lib::root_key::fetch_root_key_if_needed; @@ -92,6 +92,18 @@ pub struct CanisterCreateOpts { #[arg(long, value_parser = wasm_memory_limit_parser, hide = true)] wasm_memory_limit: Option, + /// Specifies a threshold (in bytes) on the Wasm memory usage of the canister, + /// as a distance from `wasm_memory_limit`. + /// + /// When the remaining memory before the limit drops below this threshold, its + /// `on_low_wasm_memory` hook will be invoked. This enables it to self-optimize, + /// or raise an alert, or otherwise attempt to prevent itself from reaching + /// `wasm_memory_limit`. + /// + /// Must be a number between 0 B and 256 TiB, inclusive. Can include units, e.g. "4KiB". + #[arg(long, value_parser = wasm_memory_limit_parser)] + wasm_memory_threshold: Option, + /// Specifies who is allowed to read the canister's logs. /// Can be either "controllers" or "public". #[arg(long, value_parser = log_visibility_parser, conflicts_with("log_viewer"))] @@ -208,6 +220,12 @@ pub async fn exec( Some(canister_name), ) .with_context(|| format!("Failed to read Wasm memory limit of {canister_name}."))?; + let wasm_memory_threshold = get_wasm_memory_threshold( + opts.wasm_memory_threshold, + Some(config_interface), + Some(canister_name), + ) + .with_context(|| format!("Failed to read Wasm memory threshold of {canister_name}."))?; let log_visibility = get_log_visibility( env, LogVisibilityOpt::from(&opts.log_visibility, &opts.log_viewer).as_ref(), @@ -231,6 +249,7 @@ pub async fn exec( freezing_threshold, reserved_cycles_limit, wasm_memory_limit, + wasm_memory_threshold, log_visibility, }, opts.created_at_time, @@ -285,6 +304,14 @@ pub async fn exec( Some(canister_name), ) .with_context(|| format!("Failed to read Wasm memory limit of {canister_name}."))?; + let wasm_memory_threshold = get_wasm_memory_threshold( + opts.wasm_memory_threshold, + Some(config_interface), + Some(canister_name), + ) + .with_context(|| { + format!("Failed to read Wasm memory threshold of {canister_name}.") + })?; let log_visibility = get_log_visibility( env, LogVisibilityOpt::from(&opts.log_visibility, &opts.log_viewer).as_ref(), @@ -308,6 +335,7 @@ pub async fn exec( freezing_threshold, reserved_cycles_limit, wasm_memory_limit, + wasm_memory_threshold, log_visibility, }, opts.created_at_time, diff --git a/src/dfx/src/commands/canister/delete.rs b/src/dfx/src/commands/canister/delete.rs index 02d3dcb30f..c99c5df90d 100644 --- a/src/dfx/src/commands/canister/delete.rs +++ b/src/dfx/src/commands/canister/delete.rs @@ -189,6 +189,7 @@ async fn delete_canister( freezing_threshold: Some(FreezingThreshold::try_from(0u8).unwrap()), reserved_cycles_limit: None, wasm_memory_limit: None, + wasm_memory_threshold: None, log_visibility: None, }; info!(log, "Setting the controller to identity principal."); diff --git a/src/dfx/src/commands/canister/status.rs b/src/dfx/src/commands/canister/status.rs index ecd8d7773d..9218774219 100644 --- a/src/dfx/src/commands/canister/status.rs +++ b/src/dfx/src/commands/canister/status.rs @@ -52,6 +52,11 @@ async fn canister_status( } else { "Not Set".to_string() }; + let wasm_memory_threshold = if let Some(threshold) = status.settings.wasm_memory_threshold { + format!("{} Bytes", threshold) + } else { + "Not Set".to_string() + }; let log_visibility = match status.settings.log_visibility { LogVisibility::Controllers => "controllers".to_string(), LogVisibility::Public => "public".to_string(), @@ -66,7 +71,27 @@ async fn canister_status( } }; - println!("Canister status call result for {canister}.\nStatus: {status}\nControllers: {controllers}\nMemory allocation: {memory_allocation}\nCompute allocation: {compute_allocation}\nFreezing threshold: {freezing_threshold}\nIdle cycles burned per day: {idle_cycles_burned_per_day}\nMemory Size: {memory_size:?}\nBalance: {balance} Cycles\nReserved: {reserved} Cycles\nReserved cycles limit: {reserved_cycles_limit}\nWasm memory limit: {wasm_memory_limit}\nModule hash: {module_hash}\nNumber of queries: {queries_total}\nInstructions spent in queries: {query_instructions_total}\nTotal query request payload size (bytes): {query_req_payload_total}\nTotal query response payload size (bytes): {query_resp_payload_total}\nLog visibility: {log_visibility}", + println!( + "\ +Canister status call result for {canister}. +Status: {status} +Controllers: {controllers} +Memory allocation: {memory_allocation} +Compute allocation: {compute_allocation} +Freezing threshold: {freezing_threshold} +Idle cycles burned per day: {idle_cycles_burned_per_day} +Memory Size: {memory_size:?} +Balance: {balance} Cycles +Reserved: {reserved} Cycles +Reserved cycles limit: {reserved_cycles_limit} +Wasm memory limit: {wasm_memory_limit} +Wasm memory threshold: {wasm_memory_threshold} +Module hash: {module_hash} +Number of queries: {queries_total} +Instructions spent in queries: {query_instructions_total} +Total query request payload size (bytes): {query_req_payload_total} +Total query response payload size (bytes): {query_resp_payload_total} +Log visibility: {log_visibility}", status = status.status, controllers = controllers.join(" "), memory_allocation = status.settings.memory_allocation, @@ -76,7 +101,9 @@ async fn canister_status( memory_size = status.memory_size, balance = status.cycles, reserved = status.reserved_cycles, - module_hash = status.module_hash.map_or_else(|| "None".to_string(), |v| format!("0x{}", hex::encode(v))), + module_hash = status + .module_hash + .map_or_else(|| "None".to_string(), |v| format!("0x{}", hex::encode(v))), queries_total = status.query_stats.num_calls_total, query_instructions_total = status.query_stats.num_instructions_total, query_req_payload_total = status.query_stats.request_payload_bytes_total, diff --git a/src/dfx/src/commands/canister/update_settings.rs b/src/dfx/src/commands/canister/update_settings.rs index db3a3184eb..1d18cb1555 100644 --- a/src/dfx/src/commands/canister/update_settings.rs +++ b/src/dfx/src/commands/canister/update_settings.rs @@ -4,7 +4,7 @@ use crate::lib::environment::Environment; use crate::lib::error::{DfxError, DfxResult}; use crate::lib::ic_attributes::{ get_compute_allocation, get_freezing_threshold, get_log_visibility, get_memory_allocation, - get_reserved_cycles_limit, get_wasm_memory_limit, CanisterSettings, + get_reserved_cycles_limit, get_wasm_memory_limit, get_wasm_memory_threshold, CanisterSettings, }; use crate::lib::operations::canister::{ get_canister_status, skip_remote_canister, update_settings, @@ -91,6 +91,18 @@ pub struct UpdateSettingsOpts { #[arg(long, value_parser = wasm_memory_limit_parser)] wasm_memory_limit: Option, + /// Specifies a threshold (in bytes) on the Wasm memory usage of the canister, + /// as a distance from `wasm_memory_limit`. + /// + /// When the remaining memory before the limit drops below this threshold, its + /// `on_low_wasm_memory` hook will be invoked. This enables it to self-optimize, + /// or raise an alert, or otherwise attempt to prevent itself from reaching + /// `wasm_memory_limit`. + /// + /// Must be a number between 0 B and 256 TiB, inclusive. Can include units, e.g. "4KiB". + #[arg(long, value_parser = wasm_memory_limit_parser)] + wasm_memory_threshold: Option, + #[command(flatten)] log_visibility_opt: Option, @@ -158,6 +170,8 @@ pub async fn exec( get_reserved_cycles_limit(opts.reserved_cycles_limit, config_interface, canister_name)?; let wasm_memory_limit = get_wasm_memory_limit(opts.wasm_memory_limit, config_interface, canister_name)?; + let wasm_memory_threshold = + get_wasm_memory_threshold(opts.wasm_memory_threshold, config_interface, canister_name)?; let mut current_status: Option = None; if let Some(log_visibility) = &opts.log_visibility_opt { if log_visibility.require_current_settings() { @@ -214,6 +228,7 @@ pub async fn exec( freezing_threshold, reserved_cycles_limit, wasm_memory_limit, + wasm_memory_threshold, log_visibility, }; update_settings(env, canister_id, settings, call_sender).await?; @@ -266,6 +281,14 @@ pub async fn exec( Some(canister_name), ) .with_context(|| format!("Failed to get Wasm memory limit for {canister_name}."))?; + let wasm_memory_threshold = get_wasm_memory_threshold( + opts.wasm_memory_threshold, + Some(config_interface), + Some(canister_name), + ) + .with_context(|| { + format!("Failed to get Wasm memory threshold for {canister_name}.") + })?; let mut current_status: Option = None; if let Some(log_visibility) = &opts.log_visibility_opt { if log_visibility.require_current_settings() { @@ -325,6 +348,7 @@ pub async fn exec( freezing_threshold, reserved_cycles_limit, wasm_memory_limit, + wasm_memory_threshold, log_visibility, }; update_settings(env, canister_id, settings, call_sender).await?; diff --git a/src/dfx/src/lib/ic_attributes/mod.rs b/src/dfx/src/lib/ic_attributes/mod.rs index a7cf379a02..f287132866 100644 --- a/src/dfx/src/lib/ic_attributes/mod.rs +++ b/src/dfx/src/lib/ic_attributes/mod.rs @@ -22,6 +22,7 @@ pub struct CanisterSettings { pub freezing_threshold: Option, pub reserved_cycles_limit: Option, pub wasm_memory_limit: Option, + pub wasm_memory_threshold: Option, pub log_visibility: Option, } @@ -51,6 +52,10 @@ impl From .wasm_memory_limit .map(u64::from) .map(candid::Nat::from), + wasm_memory_threshold: value + .wasm_memory_threshold + .map(u64::from) + .map(candid::Nat::from), log_visibility: value.log_visibility, } } @@ -107,6 +112,14 @@ impl TryFrom, + config_interface: Option<&ConfigInterface>, + canister_name: Option<&str>, +) -> DfxResult> { + let wasm_memory_threshold = match (wasm_memory_threshold, config_interface, canister_name) { + (Some(memory_threshold), _, _) => Some(memory_threshold), + (None, Some(config_interface), Some(canister_name)) => { + config_interface.get_wasm_memory_threshold(canister_name)? + } + _ => None, + }; + wasm_memory_threshold + .map(|arg| { + u64::try_from(arg.get_bytes()) + .map_err(|e| anyhow!(e)) + .and_then(|n| Ok(WasmMemoryLimit::try_from(n)?)) + .context("Wasm memory limit must be between 0 and 2^48 (i.e 256TB), inclusively.") + }) + .transpose() +} pub fn get_log_visibility( env: &dyn Environment, diff --git a/src/dfx/src/lib/migrate.rs b/src/dfx/src/lib/migrate.rs index f9ceda72a4..5a3c584952 100644 --- a/src/dfx/src/lib/migrate.rs +++ b/src/dfx/src/lib/migrate.rs @@ -120,6 +120,7 @@ async fn migrate_canister( memory_allocation: None, reserved_cycles_limit: None, wasm_memory_limit: None, + wasm_memory_threshold: None, log_visibility: None, }, },)), diff --git a/src/dfx/src/lib/operations/canister/create_canister.rs b/src/dfx/src/lib/operations/canister/create_canister.rs index 8c4952afc7..03c1e3928f 100644 --- a/src/dfx/src/lib/operations/canister/create_canister.rs +++ b/src/dfx/src/lib/operations/canister/create_canister.rs @@ -216,6 +216,7 @@ async fn create_with_management_canister( .with_optional_freezing_threshold(settings.freezing_threshold) .with_optional_reserved_cycles_limit(settings.reserved_cycles_limit) .with_optional_wasm_memory_limit(settings.wasm_memory_limit) + .with_optional_wasm_memory_threshold(settings.wasm_memory_threshold) .with_optional_log_visibility(settings.log_visibility) .await; const NEEDS_WALLET: &str = "In order to create a canister on this network, you must use a wallet in order to allocate cycles to the new canister. \ diff --git a/src/dfx/src/lib/operations/canister/deploy_canisters.rs b/src/dfx/src/lib/operations/canister/deploy_canisters.rs index b1bdff2a3a..b3689e7722 100644 --- a/src/dfx/src/lib/operations/canister/deploy_canisters.rs +++ b/src/dfx/src/lib/operations/canister/deploy_canisters.rs @@ -277,6 +277,7 @@ async fn register_canisters( freezing_threshold, reserved_cycles_limit, wasm_memory_limit, + wasm_memory_threshold: None, log_visibility, }, created_at_time, diff --git a/src/dfx/src/lib/operations/cmc.rs b/src/dfx/src/lib/operations/cmc.rs index 947a08649e..9194177eb4 100644 --- a/src/dfx/src/lib/operations/cmc.rs +++ b/src/dfx/src/lib/operations/cmc.rs @@ -75,6 +75,7 @@ pub async fn notify_create( freezing_threshold: None, reserved_cycles_limit: None, wasm_memory_limit: None, + wasm_memory_threshold: None, log_visibility: None, }) })