diff --git a/rs/cycles_account_manager/src/cycles_account_manager.rs b/rs/cycles_account_manager/src/cycles_account_manager.rs index f2caf8ceb986..8fd1a7fc7d10 100644 --- a/rs/cycles_account_manager/src/cycles_account_manager.rs +++ b/rs/cycles_account_manager/src/cycles_account_manager.rs @@ -34,7 +34,7 @@ const DAY: Duration = Duration::from_secs(SECONDS_PER_DAY as u64); /// Maximum payload size of a management call to update_settings /// overriding the canister's freezing threshold. -const MAX_DELAYED_INGRESS_COST_PAYLOAD_SIZE: usize = 324; +const MAX_DELAYED_INGRESS_COST_PAYLOAD_SIZE: usize = 338; /// Handles any operation related to cycles accounting, such as charging (due to /// using system resources) or refunding unused cycles. diff --git a/rs/execution_environment/src/canister_manager.rs b/rs/execution_environment/src/canister_manager.rs index 24197efacd88..fa111f3f9083 100644 --- a/rs/execution_environment/src/canister_manager.rs +++ b/rs/execution_environment/src/canister_manager.rs @@ -517,6 +517,7 @@ impl CanisterManager { settings.reserved_cycles_limit(), reservation_cycles, settings.log_visibility().cloned(), + settings.snapshot_visibility().cloned(), log_memory_limit, settings.wasm_memory_limit(), settings.environment_variables().cloned(), @@ -591,6 +592,9 @@ impl CanisterManager { if let Some(log_visibility) = settings.log_visibility() { canister.system_state.log_visibility = log_visibility.clone(); } + if let Some(snapshot_visibility) = settings.snapshot_visibility() { + canister.system_state.snapshot_visibility = snapshot_visibility.clone(); + } if let Some(log_memory_limit) = settings.log_memory_limit() { canister .system_state @@ -1130,6 +1134,7 @@ impl CanisterManager { let freeze_threshold = canister.system_state.freeze_threshold; let reserved_cycles_limit = canister.system_state.reserved_balance_limit(); let log_visibility = canister.system_state.log_visibility.clone(); + let snapshot_visibility = canister.system_state.snapshot_visibility.clone(); let log_memory_limit = canister.log_memory_limit().get(); let wasm_memory_limit = canister.system_state.wasm_memory_limit; let wasm_memory_threshold = canister.system_state.wasm_memory_threshold; @@ -1160,6 +1165,7 @@ impl CanisterManager { freeze_threshold.get(), reserved_cycles_limit.map(|x| x.get()), log_visibility, + snapshot_visibility, log_memory_limit, self.cycles_account_manager .idle_cycles_burned_rate( diff --git a/rs/execution_environment/src/canister_settings.rs b/rs/execution_environment/src/canister_settings.rs index 457ec22e2d8f..3bf6b3ecaeb3 100644 --- a/rs/execution_environment/src/canister_settings.rs +++ b/rs/execution_environment/src/canister_settings.rs @@ -1,7 +1,7 @@ use ic_base_types::{EnvironmentVariables, NumBytes, NumSeconds}; use ic_error_types::{ErrorCode, UserError}; use ic_management_canister_types_private::{ - BoundedAllowedViewers, CanisterSettingsArgs, LogVisibilityV2, + BoundedAllowedViewers, CanisterSettingsArgs, LogVisibilityV2, SnapshotVisibility, }; use ic_types::{ ComputeAllocation, Cycles, InvalidComputeAllocationError, MemoryAllocation, PrincipalId, @@ -27,6 +27,7 @@ pub(crate) struct CanisterSettings { pub(crate) freezing_threshold: Option, pub(crate) reserved_cycles_limit: Option, pub(crate) log_visibility: Option, + pub(crate) snapshot_visibility: Option, pub(crate) log_memory_limit: Option, pub(crate) wasm_memory_limit: Option, pub(crate) environment_variables: Option, @@ -41,6 +42,7 @@ impl CanisterSettings { freezing_threshold: Option, reserved_cycles_limit: Option, log_visibility: Option, + snapshot_visibility: Option, log_memory_limit: Option, wasm_memory_limit: Option, environment_variables: Option, @@ -53,6 +55,7 @@ impl CanisterSettings { freezing_threshold, reserved_cycles_limit, log_visibility, + snapshot_visibility, log_memory_limit, wasm_memory_limit, environment_variables, @@ -87,6 +90,10 @@ impl CanisterSettings { self.log_visibility.as_ref() } + pub fn snapshot_visibility(&self) -> Option<&SnapshotVisibility> { + self.snapshot_visibility.as_ref() + } + pub fn log_memory_limit(&self) -> Option { self.log_memory_limit } @@ -193,6 +200,7 @@ impl TryFrom for CanisterSettings { freezing_threshold, reserved_cycles_limit, input.log_visibility, + input.snapshot_visibility, log_memory_limit, wasm_memory_limit, environment_variables, @@ -219,6 +227,7 @@ pub(crate) struct CanisterSettingsBuilder { freezing_threshold: Option, reserved_cycles_limit: Option, log_visibility: Option, + snapshot_visibility: Option, log_memory_limit: Option, wasm_memory_limit: Option, environment_variables: Option, @@ -235,6 +244,7 @@ impl CanisterSettingsBuilder { freezing_threshold: None, reserved_cycles_limit: None, log_visibility: None, + snapshot_visibility: None, log_memory_limit: None, wasm_memory_limit: None, environment_variables: None, @@ -250,6 +260,7 @@ impl CanisterSettingsBuilder { freezing_threshold: self.freezing_threshold, reserved_cycles_limit: self.reserved_cycles_limit, log_visibility: self.log_visibility, + snapshot_visibility: self.snapshot_visibility, log_memory_limit: self.log_memory_limit, wasm_memory_limit: self.wasm_memory_limit, environment_variables: self.environment_variables, @@ -305,6 +316,13 @@ impl CanisterSettingsBuilder { } } + pub fn with_snapshot_visibility(self, snapshot_visibility: SnapshotVisibility) -> Self { + Self { + snapshot_visibility: Some(snapshot_visibility), + ..self + } + } + pub fn with_log_memory_limit(self, log_memory_limit: NumBytes) -> Self { Self { log_memory_limit: Some(log_memory_limit), @@ -407,6 +425,7 @@ pub(crate) struct ValidatedCanisterSettings { reserved_cycles_limit: Option, reservation_cycles: Cycles, log_visibility: Option, + snapshot_visibility: Option, log_memory_limit: Option, wasm_memory_limit: Option, environment_variables: Option, @@ -422,6 +441,7 @@ impl ValidatedCanisterSettings { reserved_cycles_limit: Option, reservation_cycles: Cycles, log_visibility: Option, + snapshot_visibility: Option, log_memory_limit: Option, wasm_memory_limit: Option, environment_variables: Option, @@ -435,6 +455,7 @@ impl ValidatedCanisterSettings { reserved_cycles_limit, reservation_cycles, log_visibility, + snapshot_visibility, log_memory_limit, wasm_memory_limit, environment_variables, @@ -473,6 +494,10 @@ impl ValidatedCanisterSettings { self.log_visibility.as_ref() } + pub fn snapshot_visibility(&self) -> Option<&SnapshotVisibility> { + self.snapshot_visibility.as_ref() + } + pub fn log_memory_limit(&self) -> Option { self.log_memory_limit } @@ -503,6 +528,16 @@ impl<'a> From<&'a LogVisibilityV2> for VisibilitySettings<'a> { } } +impl<'a> From<&'a SnapshotVisibility> for VisibilitySettings<'a> { + fn from(v: &'a SnapshotVisibility) -> Self { + match v { + SnapshotVisibility::Public => Self::Public, + SnapshotVisibility::Controllers => Self::Controllers, + SnapshotVisibility::AllowedViewers(principals) => Self::AllowedViewers(principals), + } + } +} + impl VisibilitySettings<'_> { pub(crate) fn has_access( &self, diff --git a/rs/nns/cmc/cmc.did b/rs/nns/cmc/cmc.did index 9a3fde853393..ccdfe8d161f0 100644 --- a/rs/nns/cmc/cmc.did +++ b/rs/nns/cmc/cmc.did @@ -5,8 +5,13 @@ type log_visibility = variant { public; allowed_viewers : vec principal; }; -type environment_variable = record { - name: text; +type snapshot_visibility = variant { + controllers; + public; + allowed_viewers : vec principal; +}; +type environment_variable = record { + name: text; value: text; }; type CanisterSettings = record { @@ -16,6 +21,7 @@ type CanisterSettings = record { freezing_threshold : opt nat; reserved_cycles_limit : opt nat; log_visibility : opt log_visibility; + snapshot_visibility : opt snapshot_visibility; wasm_memory_limit : opt nat; wasm_memory_threshold : opt nat; environment_variables : opt vec environment_variable; diff --git a/rs/nns/cmc/unreleased_changelog.md b/rs/nns/cmc/unreleased_changelog.md index 94126a0ff421..864ecd9020c9 100644 --- a/rs/nns/cmc/unreleased_changelog.md +++ b/rs/nns/cmc/unreleased_changelog.md @@ -9,6 +9,8 @@ on the process that this file is part of, see ## Added +- Added the optional `snapshot_visibility` field to `CanisterSettings` in the Candid API. This a non-breaking change impacting the type `CreateCanisterArg` and the endpoint `create_canister`. + ## Changed ## Deprecated diff --git a/rs/pocket_ic_server/src/pocket_ic.rs b/rs/pocket_ic_server/src/pocket_ic.rs index ce4baccc811f..675299da2cef 100644 --- a/rs/pocket_ic_server/src/pocket_ic.rs +++ b/rs/pocket_ic_server/src/pocket_ic.rs @@ -69,7 +69,7 @@ use ic_management_canister_types_private::{ CanisterSnapshotDataKind, CanisterSnapshotDataOffset, EcdsaCurve, EcdsaKeyId, LogVisibilityV2, MasterPublicKeyId, Method as Ic00Method, ProvisionalCreateCanisterWithCyclesArgs, ReadCanisterSnapshotDataArgs, ReadCanisterSnapshotMetadataArgs, - ReadCanisterSnapshotMetadataResponse, SchnorrAlgorithm, SchnorrKeyId, + ReadCanisterSnapshotMetadataResponse, SchnorrAlgorithm, SchnorrKeyId, SnapshotVisibility, UploadCanisterSnapshotDataArgs, UploadCanisterSnapshotMetadataArgs, VetKdCurve, VetKdKeyId, }; use ic_metrics::MetricsRegistry; @@ -1146,6 +1146,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(3_221_225_472_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = nns_subnet.state_machine.create_canister_with_cycles( Some(REGISTRY_CANISTER_ID.get()), @@ -1229,6 +1230,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(3_221_225_472_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = nns_subnet.state_machine.create_canister_with_cycles( Some(CYCLES_MINTING_CANISTER_ID.get()), @@ -1399,6 +1401,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(3_221_225_472_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = nns_subnet.state_machine.create_canister_with_cycles( Some(LEDGER_CANISTER_ID.get()), @@ -1480,6 +1483,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(3_221_225_472_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = nns_subnet.state_machine.create_canister_with_cycles( Some(LEDGER_INDEX_CANISTER_ID.get()), @@ -1559,6 +1563,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(3_221_225_472_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = ii_subnet.state_machine.create_canister_with_cycles( Some(CYCLES_LEDGER_CANISTER_ID.get()), @@ -1623,6 +1628,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(3_221_225_472_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = ii_subnet.state_machine.create_canister_with_cycles( Some(CYCLES_LEDGER_INDEX_CANISTER_ID.get()), @@ -1693,6 +1699,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(4_294_967_296_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = nns_subnet.state_machine.create_canister_with_cycles( Some(GOVERNANCE_CANISTER_ID.get()), @@ -1770,6 +1777,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(3_221_225_472_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = nns_subnet.state_machine.create_canister_with_cycles( Some(ROOT_CANISTER_ID.get()), @@ -1837,6 +1845,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(3_221_225_472_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = nns_subnet.state_machine.create_canister_with_cycles( Some(SNS_WASM_CANISTER_ID.get()), @@ -1935,6 +1944,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(3_221_225_472_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = sns_subnet.state_machine.create_canister_with_cycles( Some(SNS_AGGREGATOR_CANISTER_ID.get()), @@ -2008,6 +2018,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(3_221_225_472_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = ii_subnet.state_machine.create_canister_with_cycles( Some(IDENTITY_CANISTER_ID.get()), @@ -2188,6 +2199,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(3_221_225_472_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = nns_subnet.state_machine.create_canister_with_cycles( Some(NNS_UI_CANISTER_ID.get()), @@ -2285,6 +2297,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(2_000_000_000_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = btc_subnet.state_machine.create_canister_with_cycles( Some(BITCOIN_TESTNET_CANISTER_ID.get()), @@ -2359,6 +2372,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(3_221_225_472_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = btc_subnet.state_machine.create_canister_with_cycles( Some(DOGECOIN_CANISTER_ID.get()), @@ -2425,6 +2439,7 @@ impl PocketIcSubnets { wasm_memory_limit: Some(3_221_225_472_u64.into()), wasm_memory_threshold: Some(0_u64.into()), environment_variables: None, + snapshot_visibility: Some(SnapshotVisibility::Controllers), }; let canister_id = nns_subnet.state_machine.create_canister_with_cycles( Some(MIGRATION_CANISTER_ID.get()), diff --git a/rs/protobuf/def/state/canister_state_bits/v1/canister_state_bits.proto b/rs/protobuf/def/state/canister_state_bits/v1/canister_state_bits.proto index e0803fcf57f0..680461b4bce0 100644 --- a/rs/protobuf/def/state/canister_state_bits/v1/canister_state_bits.proto +++ b/rs/protobuf/def/state/canister_state_bits/v1/canister_state_bits.proto @@ -377,6 +377,18 @@ message LogVisibilityV2 { } } +message SnapshotVisibilityAllowedViewers { + repeated types.v1.PrincipalId principals = 1; +} + +message SnapshotVisibility { + oneof snapshot_visibility { + int32 controllers = 1; + int32 public = 2; + SnapshotVisibilityAllowedViewers allowed_viewers = 3; + } +} + message CanisterLogRecord { uint64 idx = 1; uint64 timestamp_nanos = 2; @@ -410,7 +422,7 @@ message TaskQueue { repeated ExecutionTask queue = 3; } -// Next ID: 64 +// Next ID: 65 message CanisterStateBits { reserved 1, 3, 6, 9, 10, 14, 16, 17, 24, 30, 35, 42, 47, 53; @@ -491,4 +503,6 @@ message CanisterStateBits { TaskQueue tasks = 54; // A map of environment variable names to their values map environment_variables = 55; + // Snapshot visibility for the canister. + SnapshotVisibility snapshot_visibility = 64; } diff --git a/rs/protobuf/src/gen/state/state.canister_state_bits.v1.rs b/rs/protobuf/src/gen/state/state.canister_state_bits.v1.rs index 8c6dfeda8d00..486e163730cb 100644 --- a/rs/protobuf/src/gen/state/state.canister_state_bits.v1.rs +++ b/rs/protobuf/src/gen/state/state.canister_state_bits.v1.rs @@ -591,6 +591,28 @@ pub mod log_visibility_v2 { } } #[derive(Clone, PartialEq, ::prost::Message)] +pub struct SnapshotVisibilityAllowedViewers { + #[prost(message, repeated, tag = "1")] + pub principals: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SnapshotVisibility { + #[prost(oneof = "snapshot_visibility::SnapshotVisibility", tags = "1, 2, 3")] + pub snapshot_visibility: ::core::option::Option, +} +/// Nested message and enum types in `SnapshotVisibility`. +pub mod snapshot_visibility { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum SnapshotVisibility { + #[prost(int32, tag = "1")] + Controllers(i32), + #[prost(int32, tag = "2")] + Public(i32), + #[prost(message, tag = "3")] + AllowedViewers(super::SnapshotVisibilityAllowedViewers), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] pub struct CanisterLogRecord { #[prost(uint64, tag = "1")] pub idx: u64, @@ -617,7 +639,7 @@ pub struct TaskQueue { #[prost(message, repeated, tag = "3")] pub queue: ::prost::alloc::vec::Vec, } -/// Next ID: 64 +/// Next ID: 65 #[derive(Clone, PartialEq, ::prost::Message)] pub struct CanisterStateBits { #[prost(uint64, tag = "2")] @@ -740,6 +762,9 @@ pub struct CanisterStateBits { ::prost::alloc::string::String, ::prost::alloc::string::String, >, + /// Snapshot visibility for the canister. + #[prost(message, optional, tag = "64")] + pub snapshot_visibility: ::core::option::Option, #[prost(oneof = "canister_state_bits::CanisterStatus", tags = "11, 12, 13")] pub canister_status: ::core::option::Option, } diff --git a/rs/replica_tests/tests/canister_lifecycle.rs b/rs/replica_tests/tests/canister_lifecycle.rs index 448d0b9a6b7e..f01013d4bdae 100644 --- a/rs/replica_tests/tests/canister_lifecycle.rs +++ b/rs/replica_tests/tests/canister_lifecycle.rs @@ -9,7 +9,7 @@ use ic_error_types::{ErrorCode, RejectCode}; use ic_management_canister_types_private::{ self as ic00, CanisterChange, CanisterIdRecord, CanisterInstallMode, CanisterSettingsArgsBuilder, CanisterStatusResultV2, CanisterStatusType, EmptyBlob, IC_00, - InstallCodeArgs, LogVisibilityV2, Method, Payload, UpdateSettingsArgs, + InstallCodeArgs, LogVisibilityV2, Method, Payload, SnapshotVisibility, UpdateSettingsArgs, }; use ic_registry_provisional_whitelist::ProvisionalWhitelist; use ic_replica_tests as utils; @@ -726,6 +726,7 @@ fn can_get_canister_information() { 2592000, Some(5_000_000_000_000u128), LogVisibilityV2::default(), + SnapshotVisibility::default(), TEST_DEFAULT_LOG_MEMORY_LIMIT, 0u128, 0u128, @@ -796,6 +797,7 @@ fn can_get_canister_information() { 259200, None, LogVisibilityV2::default(), + SnapshotVisibility::default(), TEST_DEFAULT_LOG_MEMORY_LIMIT, 0u128, 0u128, diff --git a/rs/replicated_state/src/canister_state.rs b/rs/replicated_state/src/canister_state.rs index 3fcebbffea64..6fb2d53bdba9 100644 --- a/rs/replicated_state/src/canister_state.rs +++ b/rs/replicated_state/src/canister_state.rs @@ -17,6 +17,7 @@ use ic_interfaces::execution_environment::{ }; use ic_management_canister_types_private::{ CanisterChangeDetails, CanisterChangeOrigin, CanisterStatusType, LogVisibilityV2, + SnapshotVisibility, }; use ic_registry_subnet_type::SubnetType; use ic_types::messages::{CanisterMessage, Ingress, Request, RequestOrResponse, Response}; @@ -100,6 +101,10 @@ impl CanisterState { &self.system_state.log_visibility } + pub fn snapshot_visibility(&self) -> &SnapshotVisibility { + &self.system_state.snapshot_visibility + } + /// Returns the difference in time since the canister was last charged for resource allocations. pub fn duration_since_last_allocation_charge(&self, current_time: Time) -> Duration { debug_assert!( diff --git a/rs/replicated_state/src/canister_state/system_state.rs b/rs/replicated_state/src/canister_state/system_state.rs index 38ff59a5d33a..0d1c5915755f 100644 --- a/rs/replicated_state/src/canister_state/system_state.rs +++ b/rs/replicated_state/src/canister_state/system_state.rs @@ -28,7 +28,7 @@ use ic_interfaces::execution_environment::HypervisorError; use ic_logger::{ReplicaLogger, error}; use ic_management_canister_types_private::{ CanisterChange, CanisterChangeDetails, CanisterChangeOrigin, CanisterStatusType, - LogVisibilityV2, + LogVisibilityV2, SnapshotVisibility, }; use ic_registry_subnet_type::SubnetType; use ic_types::batch::TotalQueryStats; @@ -482,6 +482,9 @@ pub struct SystemState { /// Log visibility of the canister. pub log_visibility: LogVisibilityV2, + /// Snapshot visibility of the canister. + pub snapshot_visibility: SnapshotVisibility, + /// Log records of the canister. #[validate_eq(CompareWithValidateEq)] pub canister_log: CanisterLog, @@ -675,6 +678,7 @@ impl SystemState { canister_history: CanisterHistory::default(), wasm_chunk_store, log_visibility: Default::default(), + snapshot_visibility: Default::default(), // TODO(EXC-2118): CanisterLog does not store log records efficiently, // therefore it should not scale to memory limit from above. // Remove this field after migration is done. @@ -711,6 +715,7 @@ impl SystemState { wasm_chunk_store_data: PageMap, wasm_chunk_store_metadata: WasmChunkStoreMetadata, log_visibility: LogVisibilityV2, + snapshot_visibility: SnapshotVisibility, canister_log: CanisterLog, log_memory_store_data: Option, wasm_memory_limit: Option, @@ -745,6 +750,7 @@ impl SystemState { wasm_chunk_store_metadata, ), log_visibility, + snapshot_visibility, canister_log, log_memory_store: LogMemoryStore::from_checkpoint( LOG_MEMORY_STORE_FEATURE, @@ -2442,6 +2448,7 @@ pub mod testing { canister_history: Default::default(), wasm_chunk_store: WasmChunkStore::new_for_testing(), log_visibility: Default::default(), + snapshot_visibility: Default::default(), // TODO(EXC-2118): CanisterLog does not store log records efficiently, // therefore it should not scale to memory limit from above. // Remove this field after migration is done. diff --git a/rs/state_layout/src/state_layout.rs b/rs/state_layout/src/state_layout.rs index 5110b96d77c0..5a936cba393f 100644 --- a/rs/state_layout/src/state_layout.rs +++ b/rs/state_layout/src/state_layout.rs @@ -1,7 +1,7 @@ use ic_base_types::{NumBytes, NumSeconds}; use ic_logger::{ReplicaLogger, error, info, warn}; use ic_management_canister_types_private::{ - Global, LogVisibilityV2, OnLowWasmMemoryHookStatus, SnapshotSource, + Global, LogVisibilityV2, OnLowWasmMemoryHookStatus, SnapshotSource, SnapshotVisibility, }; use ic_metrics::{MetricsRegistry, buckets::decimal_buckets}; use ic_protobuf::state::{ @@ -206,6 +206,7 @@ pub struct CanisterStateBits { pub wasm_chunk_store_metadata: WasmChunkStoreMetadata, pub total_query_stats: TotalQueryStats, pub log_visibility: LogVisibilityV2, + pub snapshot_visibility: SnapshotVisibility, pub log_memory_limit: NumBytes, pub canister_log: CanisterLog, pub wasm_memory_limit: Option, diff --git a/rs/state_layout/src/state_layout/proto.rs b/rs/state_layout/src/state_layout/proto.rs index 3dbf3e309c83..d1cc51547865 100644 --- a/rs/state_layout/src/state_layout/proto.rs +++ b/rs/state_layout/src/state_layout/proto.rs @@ -59,6 +59,10 @@ impl From for pb_canister_state_bits::CanisterStateBits { total_query_stats: Some((&item.total_query_stats).into()), log_visibility_v2: pb_canister_state_bits::LogVisibilityV2::from(&item.log_visibility) .into(), + snapshot_visibility: pb_canister_state_bits::SnapshotVisibility::from( + &item.snapshot_visibility, + ) + .into(), log_memory_limit: item.log_memory_limit.get(), canister_log_records: item .canister_log @@ -197,6 +201,11 @@ impl TryFrom for CanisterStateBits { "CanisterStateBits::log_visibility_v2", ) .unwrap_or_default(), + snapshot_visibility: try_from_option_field( + value.snapshot_visibility, + "CanisterStateBits::snapshot_visibility", + ) + .unwrap_or_default(), log_memory_limit: NumBytes::from(value.log_memory_limit), canister_log: CanisterLog::new_aggregate( value.next_canister_log_record_idx, diff --git a/rs/state_layout/src/state_layout/tests.rs b/rs/state_layout/src/state_layout/tests.rs index e0c2c3a125ba..41cece8fe0c9 100644 --- a/rs/state_layout/src/state_layout/tests.rs +++ b/rs/state_layout/src/state_layout/tests.rs @@ -59,6 +59,7 @@ fn default_canister_state_bits() -> CanisterStateBits { wasm_chunk_store_metadata: WasmChunkStoreMetadata::default(), total_query_stats: TotalQueryStats::default(), log_visibility: Default::default(), + snapshot_visibility: Default::default(), log_memory_limit: NumBytes::from(0), canister_log: CanisterLog::default_aggregate(), wasm_memory_limit: None, diff --git a/rs/state_manager/src/checkpoint.rs b/rs/state_manager/src/checkpoint.rs index b4c9270299e2..22163a376074 100644 --- a/rs/state_manager/src/checkpoint.rs +++ b/rs/state_manager/src/checkpoint.rs @@ -946,6 +946,7 @@ pub fn load_canister_state( wasm_chunk_store_data, canister_state_bits.wasm_chunk_store_metadata, canister_state_bits.log_visibility, + canister_state_bits.snapshot_visibility, canister_state_bits.canister_log, log_memory_store_data, canister_state_bits.wasm_memory_limit, diff --git a/rs/state_manager/src/tip.rs b/rs/state_manager/src/tip.rs index 5ce35c7a4a34..365352da9ba8 100644 --- a/rs/state_manager/src/tip.rs +++ b/rs/state_manager/src/tip.rs @@ -1385,6 +1385,7 @@ fn serialize_canister_protos_to_checkpoint_readwrite( .clone(), total_query_stats: canister_state.system_state.total_query_stats.clone(), log_visibility: canister_state.system_state.log_visibility.clone(), + snapshot_visibility: canister_state.system_state.snapshot_visibility.clone(), log_memory_limit: canister_state.log_memory_limit(), canister_log: canister_state.system_state.canister_log.clone(), wasm_memory_limit: canister_state.system_state.wasm_memory_limit, diff --git a/rs/types/management_canister_types/src/lib.rs b/rs/types/management_canister_types/src/lib.rs index d0e079d175bf..aa4ac96690f3 100644 --- a/rs/types/management_canister_types/src/lib.rs +++ b/rs/types/management_canister_types/src/lib.rs @@ -1233,8 +1233,7 @@ impl From<&LogVisibilityV2> for pb_canister_state_bits::LogVisibilityV2 { .get() .iter() .map(|c| (*c).into()) - .collect::>() - .clone(), + .collect::>(), }, ), ), @@ -1279,6 +1278,96 @@ impl TryFrom for LogVisibilityV2 { } } +/// Snapshot visibility for a canister. +/// ```text +/// variant { +/// controllers; +/// public; +/// allowed_viewers : vec principal; +/// } +/// ``` +#[derive(Clone, Eq, PartialEq, Debug, Default, CandidType, Deserialize, EnumIter)] +pub enum SnapshotVisibility { + #[default] + #[serde(rename = "controllers")] + Controllers, + #[serde(rename = "public")] + Public, + #[serde(rename = "allowed_viewers")] + AllowedViewers(BoundedAllowedViewers), +} + +impl Payload<'_> for SnapshotVisibility {} + +impl From<&SnapshotVisibility> for pb_canister_state_bits::SnapshotVisibility { + fn from(item: &SnapshotVisibility) -> Self { + match item { + SnapshotVisibility::Controllers => pb_canister_state_bits::SnapshotVisibility { + snapshot_visibility: Some( + pb_canister_state_bits::snapshot_visibility::SnapshotVisibility::Controllers(1), + ), + }, + SnapshotVisibility::Public => pb_canister_state_bits::SnapshotVisibility { + snapshot_visibility: Some( + pb_canister_state_bits::snapshot_visibility::SnapshotVisibility::Public(2), + ), + }, + SnapshotVisibility::AllowedViewers(principals) => { + pb_canister_state_bits::SnapshotVisibility { + snapshot_visibility: Some( + pb_canister_state_bits::snapshot_visibility::SnapshotVisibility::AllowedViewers( + pb_canister_state_bits::SnapshotVisibilityAllowedViewers { + principals: principals + .get() + .iter() + .map(|c| (*c).into()) + .collect::>() + }, + ), + ), + } + } + } + } +} + +impl TryFrom for SnapshotVisibility { + type Error = ProxyDecodeError; + + fn try_from(item: pb_canister_state_bits::SnapshotVisibility) -> Result { + let Some(snapshot_visibility) = item.snapshot_visibility else { + return Err(ProxyDecodeError::MissingField( + "SnapshotVisibility::snapshot_visibility", + )); + }; + match snapshot_visibility { + pb_canister_state_bits::snapshot_visibility::SnapshotVisibility::Controllers(_) => { + Ok(Self::Controllers) + } + pb_canister_state_bits::snapshot_visibility::SnapshotVisibility::Public(_) => { + Ok(Self::Public) + } + pb_canister_state_bits::snapshot_visibility::SnapshotVisibility::AllowedViewers( + data, + ) => { + let principals = data + .principals + .iter() + .map(|p| { + PrincipalId::try_from(p.raw.clone()).map_err(|e| { + ProxyDecodeError::ValueOutOfRange { + typ: "PrincipalId", + err: e.to_string(), + } + }) + }) + .collect::, _>>()?; + Ok(Self::AllowedViewers(BoundedAllowedViewers::new(principals))) + } + } + } +} + /// Struct used for encoding/decoding /// ```text /// record { @@ -1304,6 +1393,7 @@ pub struct DefiniteCanisterSettingsArgs { freezing_threshold: candid::Nat, reserved_cycles_limit: candid::Nat, log_visibility: LogVisibilityV2, + snapshot_visibility: SnapshotVisibility, log_memory_limit: candid::Nat, wasm_memory_limit: candid::Nat, wasm_memory_threshold: candid::Nat, @@ -1319,6 +1409,7 @@ impl DefiniteCanisterSettingsArgs { freezing_threshold: u64, reserved_cycles_limit: Option, log_visibility: LogVisibilityV2, + snapshot_visibility: SnapshotVisibility, log_memory_limit: u64, wasm_memory_limit: Option, wasm_memory_threshold: u64, @@ -1342,6 +1433,7 @@ impl DefiniteCanisterSettingsArgs { freezing_threshold: candid::Nat::from(freezing_threshold), reserved_cycles_limit, log_visibility, + snapshot_visibility, log_memory_limit: candid::Nat::from(log_memory_limit), wasm_memory_limit, wasm_memory_threshold: candid::Nat::from(wasm_memory_threshold), @@ -1361,6 +1453,10 @@ impl DefiniteCanisterSettingsArgs { &self.log_visibility } + pub fn snapshot_visibility(&self) -> &SnapshotVisibility { + &self.snapshot_visibility + } + pub fn log_memory_limit(&self) -> candid::Nat { self.log_memory_limit.clone() } @@ -1490,6 +1586,7 @@ impl CanisterStatusResultV2 { freezing_threshold: u64, reserved_cycles_limit: Option, log_visibility: LogVisibilityV2, + snapshot_visibility: SnapshotVisibility, log_memory_limit: u64, idle_cycles_burned_per_day: u128, reserved_cycles: u128, @@ -1531,6 +1628,7 @@ impl CanisterStatusResultV2 { freezing_threshold, reserved_cycles_limit, log_visibility, + snapshot_visibility, log_memory_limit, wasm_memory_limit, wasm_memory_threshold, @@ -2273,6 +2371,7 @@ pub struct CanisterSettingsArgs { pub freezing_threshold: Option, pub reserved_cycles_limit: Option, pub log_visibility: Option, + pub snapshot_visibility: Option, pub log_memory_limit: Option, pub wasm_memory_limit: Option, pub wasm_memory_threshold: Option, @@ -2292,6 +2391,7 @@ impl CanisterSettingsArgs { freezing_threshold: None, reserved_cycles_limit: None, log_visibility: None, + snapshot_visibility: None, log_memory_limit: None, wasm_memory_limit: None, wasm_memory_threshold: None, @@ -2308,6 +2408,7 @@ pub struct CanisterSettingsArgsBuilder { freezing_threshold: Option, reserved_cycles_limit: Option, log_visibility: Option, + snapshot_visibility: Option, log_memory_limit: Option, wasm_memory_limit: Option, wasm_memory_threshold: Option, @@ -2328,6 +2429,7 @@ impl CanisterSettingsArgsBuilder { freezing_threshold: self.freezing_threshold, reserved_cycles_limit: self.reserved_cycles_limit, log_visibility: self.log_visibility, + snapshot_visibility: self.snapshot_visibility, log_memory_limit: self.log_memory_limit, wasm_memory_limit: self.wasm_memory_limit, wasm_memory_threshold: self.wasm_memory_threshold, @@ -2413,6 +2515,14 @@ impl CanisterSettingsArgsBuilder { } } + /// Sets the snapshot visibility. + pub fn with_snapshot_visibility(self, snapshot_visibility: SnapshotVisibility) -> Self { + Self { + snapshot_visibility: Some(snapshot_visibility), + ..self + } + } + /// Sets the log capacity in bytes. pub fn with_log_memory_limit(self, log_memory_limit: u64) -> Self { Self { diff --git a/rs/types/management_canister_types/tests/ic.did b/rs/types/management_canister_types/tests/ic.did index 343cc0897f2c..dd45e995321f 100644 --- a/rs/types/management_canister_types/tests/ic.did +++ b/rs/types/management_canister_types/tests/ic.did @@ -8,6 +8,12 @@ type log_visibility = variant { allowed_viewers : vec principal; }; +type snapshot_visibility = variant { + controllers; + public; + allowed_viewers : vec principal; +}; + type environment_variable = record { name: text; value: text; @@ -20,6 +26,7 @@ type canister_settings = record { freezing_threshold : opt nat; reserved_cycles_limit : opt nat; log_visibility : opt log_visibility; + snapshot_visibility : opt snapshot_visibility; log_memory_limit : opt nat; wasm_memory_limit : opt nat; wasm_memory_threshold : opt nat; @@ -34,6 +41,7 @@ type definite_canister_settings = record { freezing_threshold : nat; reserved_cycles_limit : nat; log_visibility : log_visibility; + snapshot_visibility : snapshot_visibility; log_memory_limit : nat; wasm_memory_limit : nat; wasm_memory_threshold: nat;