Canister does not consume cycles (local)

Hi! Please help, I don’t know why, but my canister stopped consuming cycles. With what it can be connected?

let status = await ic.canister_status({ canister_id = canisterId });
let freezingThresholdInCycles = status.memory_size * status.settings.freezing_threshold * 127000 / 1073741824;
let availableCycles = Nat.sub(status.cycles, freezingThresholdInCycles);

cycles is created with 0.5T. When availableCycles is less than 0.25T, the canister is topped up. I don’t understand at what point everything broke, I recently installed nns.

Update:

When I installed nns I had to change networks.json in part local.replica.subnet_type to “system”, so according to the documentation canisters in the local subnet no longer consume cycles for calculations.

I found post from Severin. @Severin does this mean that in order for my canisters to consume cycles for calculating and using CMC and Ledger canisters, I have to abandon nns and deploy wasm modules of the necessary canisters myself? And the second question, how can I set the canisterIds myself so that the canisterIds for the canisters from nns match the canisterIds from the mainnet?

Yes, that is right. I wish we had a better way, but it’s the best we have right now.

You can define canisters as ‘remote’. It’s probably easiest if you do dfx nns import, which will add the NNS canister definitions with the right remote field to your dfx.json.

i have problems with deploying NNS canisters and I realized that I was wasting my time… How can I get 2 subnets locally - application and system? Can I proxy requests for certain canisters to external addresses? For example, install NNS on another computer and send requests to NNS canisters to another host.

That is not possible for now, and would be a huge effort. It’s probably easiest to use a staging environment for multi-subnet tests.

No, if you run a separate IC instance then their root keys won’t match and they do not accept each other’s signatures.

1 Like

Will my canisters become available to everyone? I will spend the real cycles and can not fabricate them, since this is not the local environment?

Yes, they will be public, but discoverability is so bad for random canisters, I (personally) wouldn’t worry about it as long as you don’t supply it with more than 2-3T cycles

Since I’m going to implement important functionality related to cycles, I’ll have to give up subnet_type="system" and a very convenient set of nns canisters. Directly from the application I use 3 types of canisters - ledger, cmc and internet identity. I replaced the lines in my deploy.sh script

dfx extension install nns
dfx nns install

with

source ./scripts/ledger.sh
source ./scripts/cmc.sh
ledger.sh
#!/usr/bin/env bash

SRC_DIR="src/backend/ledger"

# Install ledger locally as documented in:
# https://internetcomputer.org/docs/current/developer-docs/integrations/ledger/ledger-local-setup

IC_VERSION=a17247bd86c7aa4e87742bf74d108614580f216d
mkdir -p $SRC_DIR
curl -kLo $SRC_DIR/ledger.wasm.gz https://download.dfinity.systems/ic/$IC_VERSION/canisters/ledger-canister.wasm.gzhttps://raw.githubusercontent.com/dfinity/ic/$IC_VERSION/rs/rosetta-api/ledger.did
curl -kLo $SRC_DIR/ledger.did https://raw.githubusercontent.com/dfinity/ic/$IC_VERSION/rs/rosetta-api/icp_ledger/ledger.did
mkdir .dfx/local/canisters/ledger
cp $SRC_DIR/ledger.wasm.gz .dfx/local/canisters/ledger/ledger.wasm.gz
dfx identity new --storage-mode=plaintext minter
dfx identity use minter
MINT_ACC=$(dfx identity get-principal)

dfx identity use default
ARCHIVE_CONTROLLER=$(dfx identity get-principal)
LEDGER_ACC=$(dfx identity get-principal)
ACCOUNT_ID=$(dfx ledger account-id)

dfx deploy ledger --specified-id ryjl3-tyaaa-aaaaa-aaaba-cai --argument "(variant {
    Init = record {
        send_whitelist = vec {
            principal \"$LEDGER_ACC\";
        };
        token_symbol = opt \"ICP\";
        transfer_fee = opt record { e8s = 10000 : nat64 };
        minting_account = \"$ACCOUNT_ID\";
        transaction_window = opt record {
            secs = 10 : nat64;
            nanos = 0 : nat32;
        };
        max_message_size_bytes = opt(2560000 : nat64);
        icrc1_minting_account = opt record {
            owner = principal \"$MINT_ACC\";
            subaccount = null;
        };
        archive_options = opt record {
            num_blocks_to_archive = 1000000 : nat64;
            max_transactions_per_response = null;
            trigger_threshold = 1000000 : nat64;
            max_message_size_bytes = null;
            cycles_for_archive_creation = null;
            node_max_memory_size_bytes = null;
            controller_id = principal \"$ARCHIVE_CONTROLLER\";
        };
        initial_values = vec {
            record {
                \"$ACCOUNT_ID\";
                record {
                    e8s = 10000000000 : nat64;
                };
            };
        };
        token_name = opt \"Internet Computer\";
    }
})" --yes -qq --upgrade-unchanged
cmc.sh
#!/usr/bin/env bash

SRC_DIR="src/backend/cmc"
IC_VERSION=a17247bd86c7aa4e87742bf74d108614580f216d
mkdir -p $SRC_DIR
curl -kLo $SRC_DIR/cmc.wasm.gz https://download.dfinity.systems/ic/$IC_VERSION/canisters/cycles-minting-canister.wasm.gz
mkdir .dfx/local/canisters/cmc
cp $SRC_DIR/cmc.wasm .dfx/local/canisters/cmc/cmc.wasm.gz
curl -kLo $SRC_DIR/cmc.did https://raw.githubusercontent.com/dfinity/ic/$IC_VERSION/rs/nns/cmc/cmc.did

didc bind $SRC_DIR/cmc.did -t mo > $SRC_DIR/cmc.mo

dfx identity new --storage-mode=plaintext minter
dfx identity use minter
MINT_ACC=$(dfx identity get-principal)
MINT_ACC_ID=$(node ./scripts/ledger.account-id.mjs --to did --principal $MINT_ACC)
# MINT_ACC_ID=record { bytes = vec { ... } };
dfx identity use default
LEDGER_ID=$(dfx canister id ledger)

dfx deploy cmc --specified-id rkp4c-7iaaa-aaaaa-aaaca-cai --argument "(opt record {
    minting_account_id = opt ${MINT_ACC_ID};
    ledger_canister_id = opt principal \"${LEDGER_ID}\";
    governance_canister_id = opt principal \"aaaaa-aa\";
    last_purged_notification = opt 0;
    exchange_rate_canister = null;
})" --yes -qq --upgrade-unchanged
dfx.json canisters section
"ledger": {
    "type": "custom",
    "candid": "src/backend/ledger/ledger.did",
    "wasm": "src/backend/ledger/ledger.wasm.gz",
    "remote": {
        "id": {
            "ic": "ryjl3-tyaaa-aaaaa-aaaba-cai"
        }
    },
    "declarations": {
        "node_compatibility": true
    }
},
"cmc": {
    "type": "custom",
    "candid": "src/backend/cmc/cmc.did",
    "wasm": "src/backend/cmc/cmc.wasm.gz",
    "remote": {
        "id": {
            "ic": "rkp4c-7iaaa-aaaaa-aaaca-cai"
        }
    },
    "declarations": {
        "node_compatibility": true
    }
}

Ledger seems to work correctly at first glance, I initialize it with 100 ICP on balance. In an actor I’m trying to create a canister

let result = await Ledger.transfer({
    to = account;
    fee = { e8s = FEE };
    memo = MEMO_CREATE_CANISTER;
    from_subaccount = ?fromSubaccount;
    amount;
    created_at_time = ?{ timestamp_nanos = Nat64.fromNat(Int.abs(Time.now())) };
});

and after that I notify CMC

let notifyResult = await CMC.notify_create_canister({ block_index = height; controller = self; subnet_type = null });

And at this step I get an error

Refunded({block_index = ?3; reason = "No subnets in which to create a canister."})

@Severin what am I doing wrong? How to create a subnet?

Honestly: no clue. For the last couple weeks I’ve encountered the same error in one of the tests I wanted to write and I couldn’t find anyone who knows how to fix that.

It turns out that developers do not have the ability to work with cycles locally and dynamically create canisters using Ledger and CMC :thinking:

Perhaps @peterparker can help, I found part of the code for deploying canisters in Juno. You created a topic on the forum, were you able to deploy a WORKING Cycles Minting Canister locally?

@mbeekman can your product ICPipeline help?

1 Like

Thanks for pinging me @rabbithole, I forgot to answe and close the topic your are mentionning.

To answer your question, yes I’m able to deploy the Cycles Minting Canister. It was pain to figure out how, but, yes I managed to do so.

  1. It needs an entry in dfx.json
"cmc": {
			"type": "custom",
			"candid": "candid/cmc.did",
			"wasm": "cmc.wasm",
			"remote": {
				"id": {
					"ic": "rkp4c-7iaaa-aaaaa-aaaca-cai"
				}
			}
		}
  1. It might not need necessary anymore but, at least in my setup, I use a custom build and custom did file because the cmc need some init parameters. Maybe it was fixed in the IC repo but, anyway I use a custom did file:

https://github.com/buildwithjuno/juno/blob/main/candid/cmc.did

  1. Finally, to effectivelly deploy the Cmc, it requires a ledger and minting account so I automated the deployment process with a script. It gather these information and proceed to execute dfx deploy with the appropriate parameters.

https://github.com/buildwithjuno/juno/blob/main/scripts/cmc.sh

Everything is available in Juno’s GitHub repo. :star: starring it is greatly appreciated.

1 Like

I did it too, but the problem is that it doesn’t function as expected. I can’t create a canister dynamically and notify the CMC about it. Please look at the description of the problem here at the end of the post.

Done :slightly_smiling_face:

1 Like

Gotcha! I “only” use the CMC for topup, I don’t use it to create canister, that’s probably the difference and why I cannot answer. I’ll forward your question to the team!

P.S.: thx :smiley:

1 Like

I believe I am right in saying that a local dfx start replica does not support multiple subnets. You get just one to test on.

In particular, that means that if you configure that one subnet to be say an app subnet, you can deploy only canisters that can run on an app subnet.

I understood this point and therefore decided to change my subnet from a system subnet to an application subnet. In this subnet I deployed the canisters I needed - ledger, cmc and internet identity. But when creating a canister via CMC I get an error.

I am still digging through the logic. :slight_smile:

The error message comes from the cmc create_canister function, here: https://github.com/dfinity/ic/blob/master/rs/nns/cmc/src/main.rs#L1661

According to your command above, you do not specify subet type (you set it to null). So according to this line, any subnet that the controller may use is fine. https://github.com/dfinity/ic/blob/master/rs/nns/cmc/src/main.rs#L1606

So the question is who is the controller and how can we authorize the controller to use the one and only subnet?

1 Like

Looking back at the one place where I set up the CMC, I configure the CMC by proposal, like this:

NNS_URL="$(http://localhost:$(dfx info replica-port))"

ic-admin --nns-url "$NNS_URL" \
  propose-to-set-authorized-subnetworks \
  --test-neuron-proposer \
  --proposal-title "Authorize CMC to create canisters in subnets" \
  --proposal-url https://forum.dfinity.org/somepost \
  --summary "Some summary" \
  --subnets $(ic-admin --nns-url "$NNS_URL" get-subnet-list | jq -r '. | join(" --subnets ")')

But in your case there is no governance canister, so we need to whitelist without a proposal. So, whatever function call that proposal makes, you presumably need to make directly.

Looking through that code, I also had to set the sdr exchange rate. Not that it is relevant to the canister whitelisting but it might become relevant later.

ic-admin --nns-url "$NNS_URL" propose-xdr-icp-conversion-rate --test-neuron-proposer --summary "Please set the conversion rate between ICP and cycles" --xdr-permyriad-per-icp 123456789

The CMC has an set_authorized_subnetwork_list method that you would have to call to authorize a given principal to create canisters on a given subnet:

So it looks as if now we just need to make sure we know what principal is trying to create that canister and get the subnet ID. Then call that method and then everything should work.

It’s only an internal method. You can’t call it from the outside :frowning_face:

Given that this is a test environment, I feel rather tempted to add whatever methods are needed to whitelist this call to the CMC canister and call the result a test build. :smiley:

Or delete checks, if that is what it takes.