How to spawn other canister from canister

I’m testing out the bucket example from tutorial, which dynamically spawn another child canister from within a parent canister.

import Array "mo:base/Array";
import Buckets "Buckets";

actor Map {
  let n = 8; // number of buckets

  type Key = Nat;
  type Value = Text;

  type Bucket = Buckets.Bucket;

  let buckets : [var ?Bucket] = Array.init(n, null);
  
  public func put(k : Key, v : Value) : async () {
    let i = k % n;
    let bucket = switch (buckets[i]) {
      case null {
        let b = await Buckets.Bucket(n, i); // dynamically install a new Bucket
        buckets[i] := ?b;
        b;
      };
      case (?bucket) bucket;
    };
    await bucket.put(k, v);
  };
};

When I call from terminal:

An error happened during the call: 4: Creating a canister requires a fee of 1000000000000 that is deducted from the canister's initial balance but only 0 cycles were received with the create_canister request.

What is the right way to make such call?

2 Likes

@kpeacock Hi Kyle! Hope I call the right person for this one. Can you guide me through this step? It’s currently a blocking issue to me😫

(BTW, great demo! And thx for the frontend lib!)

Thanks, and good question! I think this requires a call that’s initiated by a wallet, using a with_cycles argument. @prithvi would know best, and I’ll make a note that we need to get the docs updated

1 Like

Yeah you guys should definitely update those docs!

I could only make guesses currently. I tried —with-cycles too. I even tried wallet_call. Each gave different errors (forgot to note them down):sweat:

Can you identify the tutorial you are using here? I don’t recognize it offhand. Is it in the Motoko documentation?

We are in the process of updating all tyitorials, so pointers to where you find issues are much appreciated.

I did post the link at the beginning, but there you go:

Cool. That was what I suspected. We will get this fixed

Lisa Gunn
Technical Writer

Sorry, I totally missed this question. The example was written way before we added imperative Cycle accounting via library ExperimentalCycles and never updated.

I’ll try to add it as a working example in the examples repo, but a working solution should look something like this (untested) code:

import Array "mo:base/Array";
import Buckets "Buckets";
import Cycles "mo:base/ExperimentalCycles"; // reference lib


actor Map {
  let n = 8; // number of buckets

  type Key = Nat;
  type Value = Text;

  type Bucket = Buckets.Bucket;

  let buckets : [var ?Bucket] = Array.init(n, null);
  
  public func put(k : Key, v : Value) : async () {
    let i = k % n;
    let bucket = switch (buckets[i]) {
      case null {
        Cycles.add(1000_000_000_000); // provision cycles for next call (might need some more)
        let b = await Buckets.Bucket(n, i); // dynamically install a new Bucket
        buckets[i] := ?b;
        b;
      };
      case (?bucket) bucket;
    };
    await bucket.put(k, v);
  };
};

It’s also possible that the Bucket code needs to call Cycles.accept(Cycles.available()) in it’s constructor… I’ll need to check that. (Seems to be unnecessary when running on a local replica - not sure about the real deal though)

1 Like

Claudio/classes by crusso · Pull Request #95 · dfinity/examples · GitHub contains an example that builds and runs, with cycles. Will hopefully be merged soon.

2 Likes