Calling arguments from motoko

Hi,

I’ve been playing with actor classes and mainly creating canisters on the fly for storage (cdn).

So basically I want to create a mini big map ish storage solution. I can create as many canisters as I want on the fly but my question is how do I set a canister compute allocation and memory allocation from motoko?

In dfx I can use

-c, --compute-allocation <compute-allocation> Specifies the canister's compute allocation. This should be a percent in the range [0..100]
and
--memory-allocation <memory-allocation> Specifies how much memory the canister is allowed to use in total. This should be a value in the range [0..256 TB]

but can’t seem to find a way to do it in code. Any help would be appreciated.

Thanks

You should be able to call the management canister aaaaa-aa from your deployed canister in order to update the settings


public type CanisterSettings = {
 controller : ?Principal;
 compute_allocation : ?Nat;
 memory_allocation : ?Nat;
 freezing_threshold : ?Nat;
}

public type IC0 = actor {
     update_settings : {canister_id  : Principal; settings : CanisterSettings} -> async ();
}; 

Your canister will need to have its controller set to itself for this to work however. I could have swore canisters supported upto ten controllers :thinking:, but the interface says otherwise.

3 Likes

Try something like this:

type canister_settings = {
    controller : ?Principal;
    compute_allocation: ?Nat;
    memory_allocation: ?Nat;
    freezing_threshold: ?Nat;
  };
};

let IC0 = actor "aaaaa-aa" :
  actor {
    update_settings : {
      settings : { canister_id : Principal; settings : canister_settings } -> async ();
 };

... await (IC0.update_settings( { 
       canister_id = Principal.fromActor( /* bucket */ ); 
       settings = { /*... */} })); ...

2 Likes

Also see related example:

1 Like

Hey @claudio and @Hazel
Just a follow up, based on this example examples/main.mo at master · dfinity/examples · GitHub it creates a new anonymous canister but I can’t find a way to manage a canister created dynamically from an actor class eg: examples/Buckets.mo at master · dfinity/examples · GitHub . So basically I’m looking to create canisters on the fly but tweak them accordingly to my needs ( as in they’re needed for storage only or maybe some computational power as well)

I thought this actor “aaaaa-aa” : actor { will act as a wrapper over my actor class and will allow me to tweak settings accordingly

Actually, you should be able to update_settings easily enough. You’d have to extend the code in here

To also import this method:

What you won’t be able to easily do is reinstall or upgrade the dynamically installed canisters.

I’d like to add more management functionality but the design for this is currently blocked:

1 Like

Hi @claudio

I’m getting 403 so I screenshot the preview and attached as picture :slight_smile:

It’s a little hard to follow from the screenshots, but I think this behaviour might be expected.
Only the controller or the canister itself is allowed to call canister_status
(c.f.:
The Internet Computer Interface Specification :: Internet Computer (dfinity.org)

The controllers of the canister can initiate transitions between these states using stop_canister and start_canister , and query the state using canister_status . The canister itself can also query its state using ic0.canister_status .

)

When your create the canister, you are specifying its controller to be owner, but when you call canister_status, the caller is actually the canister that calls create_canister and canister_status. This may not be the same as owner (how is owner defined? I can’t tell from the code.)

At least I think that is what is happening. Please do correct me if I’m wrong.

(Instead of screenshots, you could also use a GitHub gist to share files.)

Sorry, you’re right. Please see attached. bucket.mo · GitHub

Unfortunately it errors on create_canister and it’s doesn’t get to canister_status. So that’s all the code I have .
Basically I have a container and I want to automatically create as many bucket canisters and change the memory_allocation to max as the only purpose of a bucket is storage only and unfortunately I can’t do that with an actor class yet as you said above.

So rwlgt-iiaaa-aaaaa-aaaaa-cai is my canister wallet and if you look down on results you can see that the container canister controller is the same one. Also from debug on create_canister I pass owner which is [Canister ryjl3-tyaaa-aaaaa-aaaba-cai] "owner" [Canister ryjl3-tyaaa-aaaaa-aaaba-cai] rwlgt-iiaaa-aaaaa-aaaaa-cai

Thanks

Ok, I think I might know the problem.

The controller field is now called controllers and takes a vec (Motoko immutable array) of values. So I expect the call is failing because the interface of “aaaa-aa” is incorrectly asserted and the type of the argument pass by Motoko to the IC management canister is actually incorrect in this code, causing the call to create_canister to fail.

c.f.

and note the type of canister_settings and definite_settings:

type canister_settings = record {
  controllers : opt vec principal; // !
  compute_allocation : opt nat;
  memory_allocation : opt nat;
  freezing_threshold : opt nat;
};

type definite_canister_settings = record {
  controllers : vec principal; // !
  compute_allocation : nat;
  memory_allocation : nat;
  freezing_threshold : nat;
};

I believe the change from single to multiple controllers was fairly recent, so perhaps your source of truth was out of date.

I hope that solves the issue - please note that I’m on PTO tomorrow so may be later responding if not.

2 Likes

My reply has some typos but I can’t fix them because of the dreaded 403 - I hope you get the gist though.

1 Like

Damn, I lost 2 days on this. Oh well next time I should double check the rust docs as well. Ok so after updating my code it worked. Thanks

Even tho the memory_allocation is still 0 for some reason I don’t get an error anymore.

{cycles = 2_000_000_000_000; memory_size = 0; module_hash = null; settings = {compute_allocation = 0; controllers = [ryjl3-tyaaa-aaaaa-aaaba-cai]; freezing_threshold = 2_592_000; memory_allocation = 0}; status = #running}

Thanks

1 Like

I know, no worries, I got the gist.

Last questions.

  • memory_allocation ( nat ) Must be a number between 0 and 2^48 (i.e 256TB). Not sure I get how it can it be 256TB, shouldn’t that be the max canister memory as in 4GB?
  • Also from the 4GB is it true only 2GB can be used? I got that from your comment: Note that Motoko currently uses a 2-space copying collector so the heap will be at most half the memory, and the heap is thus bounded by 2GB Note the only purpose for this canister is storage so I’m trying the make the most of it.
  • public func discard(a : actor) : async () { I tried this but got an error, can you pass an actor as a parameter?

Thanks

1 Like

The spec is too liberal and the replica will either fail or ignore requests above 4GB, I believe.

Motoko has a new compacting gc that you can select to access more than 2 GB, but it might not let you do that yet in practice because the cost of collecting all that memory is too high for a single message. GC needs to be made incremental too. We are working on that.

Your ‘discard’ function had a typo. The empty actor type is ‘actor {}’, not ‘actor’.

Thank you very much for your answers.

This worked: public shared({caller}) func test(a: actor {}) : async () {

Looking forward for the new GC.

2 Likes