Skip to content

Commit

Permalink
feat: add support for reserved_cycles and reserved_cycles_limit
Browse files Browse the repository at this point in the history
  • Loading branch information
ericswanson-dfinity committed Sep 29, 2023
1 parent 344225d commit df17ef9
Show file tree
Hide file tree
Showing 20 changed files with 239 additions and 38 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

# UNRELEASED

### feat: Added support for reserved_cycles and reserved_cycles_limit

`dfx canister status` will now display the reserved cycles balance and reserved cycles limit for a canister.

Added command-line options:
- `dfx canister create --reserved-cycles-limit <limit>`
- `dfx canister update-settings --reserved-cycles-limit <limit>`

In addition, `dfx deploy` will set `reserved_cycles_limit` when creating canisters if specified in `canisters.<canister>.initialization_values.reserved_cycles_limit` in dfx.json.

### fix: Include remote canisters in canisters_to_generate

Generate frontend declarations for remote canisters too because frontend JS code may want to call them.
Expand Down
32 changes: 16 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 9 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ license = "Apache-2.0"

[workspace.dependencies]
candid = "0.9.0"
ic-agent = "0.28.0"
ic-agent = "0.29.0"
ic-asset = { path = "src/canisters/frontend/ic-asset" }
ic-cdk = "0.10.0"
ic-identity-hsm = "0.28.0"
ic-utils = "0.28.0"
ic-identity-hsm = "0.29.0"
ic-utils = "0.29.0"

aes-gcm = "0.9.4"
anyhow = "1.0.56"
Expand Down Expand Up @@ -69,19 +69,19 @@ url = "2.1.0"
walkdir = "2.3.2"

[patch.crates-io.ic-agent]
version = "0.28.0"
version = "0.29.0"
git = "https://github.com/dfinity/agent-rs.git"
rev = "9c4db330d96938d95eda69bbf5878db91aae0aa1"
rev = "b91b85b7b6ba6bfaf9dfd616b7c7c8f966bf8f68"

[patch.crates-io.ic-identity-hsm]
version = "0.28.0"
version = "0.29.0"
git = "https://github.com/dfinity/agent-rs.git"
rev = "9c4db330d96938d95eda69bbf5878db91aae0aa1"
rev = "b91b85b7b6ba6bfaf9dfd616b7c7c8f966bf8f68"

[patch.crates-io.ic-utils]
version = "0.28.0"
version = "0.29.0"
git = "https://github.com/dfinity/agent-rs.git"
rev = "9c4db330d96938d95eda69bbf5878db91aae0aa1"
rev = "b91b85b7b6ba6bfaf9dfd616b7c7c8f966bf8f68"

[profile.release]
panic = 'abort'
Expand Down
2 changes: 2 additions & 0 deletions docs/cli-reference/dfx-canister.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ You can use the following options with the `dfx canister create` command.
| `-c`, `--compute-allocation <allocation>` | Specifies the canister's compute allocation. This should be a percent in the range [0..100]. |
| `--controller <principal>` | Specifies the identity name or the principal of the new controller. |
| `--memory-allocation <memory>` | Specifies how much memory the canister is allowed to use in total. This should be a value in the range [0..12 GiB]. A setting of 0 means the canister will have access to memory on a “best-effort” basis: It will only be charged for the memory it uses, but at any point in time may stop running if it tries to allocate more memory when there isn’t space available on the subnet. |
| `--reserved-cycles-limit <limit>` | Specifies the upper limit for the canister's reserved cycles. |
| `--no-wallet` | Performs the call with the user Identity as the Sender of messages. Bypasses the Wallet canister. Enabled by default. |
| `--with-cycles <number-of-cycles>` | Specifies the initial cycle balance to deposit into the newly created canister. The specified amount needs to take the canister create fee into account. This amount is deducted from the wallet's cycle balance. |
| `--specified-id <PRINCIPAL>` | Attempts to create the canister with this Canister ID |
Expand Down Expand Up @@ -921,6 +922,7 @@ You can specify the following options for the `dfx canister update-settings` com
| `-c`, `--compute-allocation <allocation>` | Specifies the canister's compute allocation. This should be a percent in the range [0..100]. |
| `--set-controller <principal>` | Specifies the identity name or the principal of the new controller. Can be specified more than once, indicating the canister will have multiple controllers. If any controllers are set with this parameter, any other controllers will be removed. |
| `--memory-allocation <allocation>` | Specifies how much memory the canister is allowed to use in total. This should be a value in the range [0..12 GiB]. A setting of 0 means the canister will have access to memory on a “best-effort” basis: It will only be charged for the memory it uses, but at any point in time may stop running if it tries to allocate more memory when there isn’t space available on the subnet. |
| `--reserved-cycles-limit <limit>` | Specifies the upper limit of the canister's reserved cycles. |
| `--remove-controller <principal>` | Removes a principal from the list of controllers of the canister. |
| `--freezing-threshold <seconds>` | Set the [freezing threshold](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-create_canister) in seconds for a canister. This should be a value in the range [0..2^64^-1]. Very long thresholds require the `--confirm-very-long-freezing-threshold` flag. |
| `-y`, `--yes` | Skips yes/no checks by answering 'yes'. Such checks can result in loss of control, so this is not recommended outside of CI. |
Expand Down
14 changes: 13 additions & 1 deletion docs/dfx-json-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,8 @@
"default": {
"compute_allocation": null,
"freezing_threshold": null,
"memory_allocation": null
"memory_allocation": null,
"reserved_cycles_limit": null
},
"allOf": [
{
Expand Down Expand Up @@ -848,6 +849,17 @@
],
"format": "uint64",
"minimum": 0.0
},
"reserved_cycles_limit": {
"title": "Reserved Cycles Limit",
"description": "Specifies the upper limit of the canister's reserved cycles balance.\n\nReserved cycles are cycles that the system sets aside for future use by the canister. If a subnet's storage exceeds 450 GiB, then every time a canister allocates new storage bytes, the system sets aside some amount of cycles from the main balance of the canister. These reserved cycles will be used to cover future payments for the newly allocated bytes. The reserved cycles are not transferable and the amount of reserved cycles depends on how full the subnet is.\n\nA setting of 0 means that the canister will trap if it tries to allocate new storage while the subnet's memory usage exceeds 450 GiB.",
"default": null,
"type": [
"integer",
"null"
],
"format": "uint128",
"minimum": 0.0
}
}
},
Expand Down
15 changes: 15 additions & 0 deletions e2e/tests-dfx/create.bash
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@ teardown() {
standard_teardown
}

@test "create with reserved cycles limit" {
dfx_start

assert_command_fail dfx canister create e2e_project_backend --reserved-cycles-limit 470000
assert_contains "Cannot create a canister using a wallet if the reserved_cycles_limit is set. Please create with --no-wallet or use dfx canister update-settings instead."

assert_command dfx canister create e2e_project_frontend --no-wallet
assert_command dfx canister status e2e_project_frontend
assert_contains "Reserved Cycles Limit: 5_000_000_000_000 Cycles"

assert_command dfx canister create e2e_project_backend --reserved-cycles-limit 470000 --no-wallet
assert_command dfx canister status e2e_project_backend
assert_contains "Reserved Cycles Limit: 470_000 Cycles"
}

@test "create succeeds on default project" {
dfx_start
assert_command dfx canister create --all
Expand Down
13 changes: 13 additions & 0 deletions e2e/tests-dfx/deploy.bash
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ teardown() {
standard_teardown
}

@test "deploy with reserved cycles limit" {
dfx_start
cat dfx.json
jq '.canisters.hello_backend.initialization_values.reserved_cycles_limit=860000' dfx.json | sponge dfx.json
assert_command_fail dfx deploy
assert_contains "Cannot create a canister using a wallet if the reserved_cycles_limit is set. Please create with --no-wallet or use dfx canister update-settings instead."

assert_command dfx deploy --no-wallet

assert_command dfx canister status hello_backend
assert_contains "Reserved Cycles Limit: 860_000 Cycles"
}

@test "deploy --upgrade-unchanged upgrades even if the .wasm did not change" {
dfx_start
assert_command dfx deploy
Expand Down
11 changes: 11 additions & 0 deletions e2e/tests-dfx/update_settings.bash
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ teardown() {
standard_teardown
}

@test "set reserved cycles limit" {
dfx_start
assert_command dfx deploy hello_backend
assert_command dfx canister status hello_backend
assert_contains "Reserved Cycles Limit: 5_000_000_000_000 Cycles"

assert_command dfx canister update-settings hello_backend --reserved-cycles-limit 650000
assert_command dfx canister status hello_backend
assert_contains "Reserved Cycles Limit: 650_000 Cycles"
}

@test "set freezing threshold" {
dfx_start
assert_command dfx deploy hello_backend
Expand Down
33 changes: 27 additions & 6 deletions src/dfx-core/src/config/model/dfinity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@ use crate::error::dfx_config::AddDependenciesError::CanisterCircularDependency;
use crate::error::dfx_config::GetCanisterNamesWithDependenciesError::AddDependenciesFailed;
use crate::error::dfx_config::GetComputeAllocationError::GetComputeAllocationFailed;
use crate::error::dfx_config::GetFreezingThresholdError::GetFreezingThresholdFailed;
use crate::error::dfx_config::GetMemoryAllocationError::GetMemoryAllocationFailed;
use crate::error::dfx_config::GetPullCanistersError::PullCanistersSameId;
use crate::error::dfx_config::GetRemoteCanisterIdError::GetRemoteCanisterIdFailed;
use crate::error::dfx_config::{
AddDependenciesError, GetCanisterConfigError, GetCanisterNamesWithDependenciesError,
GetComputeAllocationError, GetFreezingThresholdError, GetMemoryAllocationError,
GetPullCanistersError, GetRemoteCanisterIdError,
};
use crate::error::dfx_config::{AddDependenciesError, GetCanisterConfigError, GetCanisterNamesWithDependenciesError, GetComputeAllocationError, GetFreezingThresholdError, GetMemoryAllocationError, GetPullCanistersError, GetRemoteCanisterIdError, GetReservedCyclesLimitError};
use crate::error::load_dfx_config::LoadDfxConfigError;
use crate::error::load_dfx_config::LoadDfxConfigError::{
DetermineCurrentWorkingDirFailed, LoadFromFileFailed, ResolveConfigPathFailed,
Expand Down Expand Up @@ -45,6 +40,8 @@ use std::fmt;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs};
use std::path::{Path, PathBuf};
use std::time::Duration;
use crate::error::dfx_config::GetMemoryAllocationError::GetMemoryAllocationFailed;
use crate::error::dfx_config::GetReservedCyclesLimitError::GetReservedCyclesLimitFailed;

use super::network_descriptor::MOTOKO_PLAYGROUND_CANISTER_TIMEOUT_SECONDS;

Expand Down Expand Up @@ -347,6 +344,19 @@ pub struct InitializationValues {
#[serde(with = "humantime_serde")]
#[schemars(with = "Option<String>")]
pub freezing_threshold: Option<Duration>,

/// # Reserved Cycles Limit
/// Specifies the upper limit of the canister's reserved cycles balance.
///
/// Reserved cycles are cycles that the system sets aside for future use by the canister.
/// If a subnet's storage exceeds 450 GiB, then every time a canister allocates new storage bytes,
/// the system sets aside some amount of cycles from the main balance of the canister.
/// These reserved cycles will be used to cover future payments for the newly allocated bytes.
/// The reserved cycles are not transferable and the amount of reserved cycles depends on how full the subnet is.
///
/// A setting of 0 means that the canister will trap if it tries to allocate new storage while the subnet's memory usage exceeds 450 GiB.
#[schemars(with = "Option<u128>")]
pub reserved_cycles_limit: Option<u128>,
}

/// # Declarations Configuration
Expand Down Expand Up @@ -836,6 +846,17 @@ impl ConfigInterface {
.freezing_threshold)
}

pub fn get_reserved_cycles_limit(
&self,
canister_name: &str,
) -> Result<Option<u128>, GetReservedCyclesLimitError> {
Ok(self
.get_canister_config(canister_name)
.map_err(|e| GetReservedCyclesLimitFailed(canister_name.to_string(), e))?
.initialization_values
.reserved_cycles_limit)
}

fn get_canister_config(
&self,
canister_name: &str,
Expand Down
7 changes: 7 additions & 0 deletions src/dfx-core/src/error/dfx_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,15 @@ pub enum GetFreezingThresholdError {
GetFreezingThresholdFailed(String, GetCanisterConfigError),
}

#[derive(Error, Debug)]
pub enum GetReservedCyclesLimitError {
#[error("Failed to get reserved cycles limit for canister '{0}': {1}")]
GetReservedCyclesLimitFailed(String, GetCanisterConfigError),
}

#[derive(Error, Debug)]
pub enum GetMemoryAllocationError {

#[error("Failed to get memory allocation for canister '{0}': {1}")]
GetMemoryAllocationFailed(String, GetCanisterConfigError),
}
Expand Down
Loading

0 comments on commit df17ef9

Please sign in to comment.