Developer Journey: Feedback and discussion

Jessie I noticed in 2.1 that I got the same “already installed” message when you did the upgrade as I did:

dfx canister install counter_backend --mode upgrade
Upgrading code for canister counter_backend, with canister ID bkyz2-fmaaa-aaaaa-qaaaq-cai
Module hash 7020fa1900e17060a542586720a30c0fec19e87670e8a14e0f2891c6a0229e23 is already installed.

Clearly its not a fatal error, but I’m wondering if you could explain what it means. The new code is not installed. So what is already installed? (BTW I did search for this on the forums before posting here and did not find)

Hi @peterkayhi , the code from when you ran the dfx deploy counter_backend command is installed. The dfx deploy command does a few things in the background, such as generate the Candid interface files, compile the canister’s code into a Wasm module, then install that module into the canister.

In the video tutorial, I got this error because I only ran dfx canister install, which didn’t rebuild the Wasm module with the new hash, resulting in that error. But once I ran dfx deploy, since that command includes building the Wasm module as part of the process, you see that the output indicates the canister was upgraded successfully. I could have explained this better in the video, my apologies!

nothing to apologize for! I appreciate you taking the time to reply here.

Hi Jessie - hope my questions are worthy of your time. I’m going through what you’re doing in great detail as I want to completely understand every line of code. I have completed the Motoko Bootcamp so I have some basic familiarity with Motoko and I’m seeing your work as going above and beyond that. I’m really sensitive about wasting people’s time so know that when I’m coming to you it’s because I’ve spent a lot of time to understand every minute detail and exhausted every other avenue (searching, ICP AI, forums etc).

My question centers around understanding 3 lines of code from your 2.2 pub/pub examples (which I copied/pasted from the web page instead of the git versions which have no comments)

Questions on 3 lines of code from 2.2 Advanced canister calls.

Line 16 of pub/main.mo:

callback : shared Counter -> ();  

In the video you said “it’s going to store the result of the shared Counter function” (https://youtu.be/9BfDy3VNxu8?t=1084) but there is no Counter function, right? I can guess this line is related to the intercanister call but I don’t understand exactly how.

Line 31 of pub/main.mo:

subscriber.callback(counter);

This looks like it’s calling a function but there is no such definition. I’m sure it’s related to line 16 but I don’t understand exactly how and what’s going on.

I understand how Sub is importing Pub and using its subscribe function. It’s just those 2 above lines that I cannot fully explain.

Line 22 of sub/main.mo:

callback = updateCount;

I think this one is trivial - it looks like you’re calling updateCount but what’s puzzling is why aren’t you passing a Counter value e.g. updateCount()? how is it you’re able to call updateCount without the ()?

Can you please explain these in detail? I can’t figure out exactly what they are doing and I’ve spent nearly 2 hours and digging through this and articulating my questions (which I hope would have solved it but did not)

@peterkayhi I’m going to defer your questions to @claudio , he may be able to explain the Motoko logic better than I can.

Line 16 is declaring the field ‘callback’ of a record. The field has a shared function type that receives a ‘Counter’ and returns nothing (a one- way or fire-and-forget function that can be called but whose result cannot be awaited).

(In Motoko, functions are first-class values that can be stored in fields, passed as arguments andreturned a results.)

Line 31 access the ‘callback’ field of a ‘subscriber’ record and calls it with an argument.

Line 22 uses the function value ‘updateCount’ as the value of a ‘callback’ field in some larger record.

Hope that helps!

Really appreciate you taking the time to reply - means a lot. Detailed question below and if it’s easier for you to point me to a page that further explains and save you the agony of replying please don’t hesitate.

on the line 22 example (BTW here’s the code and in this version it’s line 17):

it’s making an call to updateCount which is further down (line 21) defined as:

  public func updateCount(counter : Counter) {
    count += counter.value;
  };

my question is why doesn’t

      callback = updateCount;

generate a compile time error? shouldn’t it be

callback = updateCount(someCounterValue);

how is it able to get away with this?

It’s because the type of the callback field is a function type, so it must contain a function value.

  type Subscriber = {
    topic : Text;
    callback : shared Counter -> ();
  };

(examples/motoko/pub-sub/src/pub/Main.mo at 73f624adfca169ed310879bcc88d60963003190f · dfinity/examples · GitHub)

Here, shared Counter -> (); is the type of a (shared) function that takes a Counter value and returns nothing (()).

Note that

  public func updateCount(counter : Counter) {
    count += counter.value;
  };

Is syntactic sugar for

  public shared func updateCount(counter : Counter)   :  () {
    count += counter.value;
  };

(this is because public functions in actors are implicitly shared functions, and omitting the return type is the same as specifying : ())

Given this, updateCount has type shared Counter -> () and can be used as the value of the callback field above.

The reason Motoko gets away with this is that functions are first-class values in Motoko and can be stored in data-structures, variables, fields etc. That’s not a new idea and is present in many modern languages.

(First-class function - Wikipedia)

RESOLVED
Hello,

I am going through the developer journey, and have encountered an issue on 1.5 Deploying Canisters. I have an old identity set up that has an active wallet through dfx wallet, but wanted to follow the tutorial on a fresh identity using the dfx ledger and dfx cycles commands.

My issue:
I’ve sent my own ICP to dfx ledger account-id to add ICP then converted to cycles by command
dfx cycles convert --amount AMOUNT --ic
seen below I call dfx deploy --ic to deploy the poll dapp on 1.5, and get error:
Caused by: No wallet configured for combination of identity 'develop' and network 'ic'

$ dfx deploy --ic 
Please enter the passphrase for your identity: [hidden]
Decryption complete.
Deploying all canisters.
Creating canisters...
Creating canister polling_example_backend...
Error: Failed while trying to deploy canisters.
Caused by: Failed while trying to register all canisters.
Caused by: Failed to create canister 'polling_example_backend'.
Caused by: No wallet configured for combination of identity 'develop' and network 'ic'

In the command below you can see that I have balance, but no wallet configured for ic network.

$ dfx cycles balance --ic
Please enter the passphrase for your identity: [hidden]
Decryption complete.
2.627 TC (trillion cycles).

I ran this command in bash before running the above DFX_CYCLES_LEDGER_SUPPORT_ENABLE=1

Is there a way to use the cycles balance from dfx cycles when using the dfx deploy command?

Sorry if this is somewhere I missed, thanks!

Resolved my issue… was missing export in front of the ledger support command.

I’ve been out for a while and wanted still to thank you for taking the time to explain this to me. It’s much appreciated.

Hello,

I ran into an issue on the example project in 3.4: Introduction to Agents

I get this error when I run dfx generate in the random_maze project

Generating type declarations for canister random_maze_assets:
Error: Failed while trying to generate type declarations for 'random_maze_assets'.
Caused by: Candid file: ../examples/motoko/random_maze/.dfx/local/canisters/random_maze_assets/assetstorage.did doesn't exist.

Afterwards I ran dfx deploy that did not get any errors on the command line, but I do get this in the browser developer console when I press the Generate! button to get the maze
image

I’m using version v16.20.2 of node

Any idea of what could be causing this issue?

Thank you!

Thanks @TDizzle , I was able to recreate both errors locally myself, and I’ve opened an issue in the Examples repo to let the team know this example needs to be looked at.

Hello again Jessie! I looked this over as careully as I could and I can’t seem to resolve it. Can you point me in the right direction?

I’m going through 4.2 and just before 4.2 ICRC-1 tokens | Internet Computer

this command

dfx canister call icrc1_ledger_canister icrc1_transfer "(record { to = record { owner = principal \"sckqo-e2vyl-4rqqu-5g4wf-pqskh-iynjm-46ixm-awluw-ucnqa-4sl6j-mqe\";};  amount = 10_000;})"

returns this message:


(variant { Err = variant { InsufficientFunds = record { balance = 0 : nat } } })

My $DEPLOY_ID is set correctly because this works fine and returns the correct balance:

dfx canister call icrc1_ledger_canister icrc1_balance_of "(record {owner = principal \"${DEPLOY_ID}\"; })"

The only thing I can think of is that it’s not hitting the right Account but since there’s no explicit Account in the command, I’m assuming it’s being pulled from $DEPLOY_ID which is properly set.

I looked at the Candid interface and it confirms that there’s no “from” Account to be set.

Where should I look next?

Hey @peterkayhi , have you followed the video form of the tutorial? https://www.youtube.com/watch?v=RDbt62tXXwk

Mahalo Jessie for the reply. I’m embarrassed (and probably a little ashamed too;) to admit that I did not watch the video tutorial and instead followed the text page itself.

So I went through the video tutorial again this time, followed every command you gave on the video successfully and hit the same problem.

I’m at a loss for what to try next. I don’t understand why i’d get an insufficient funds error when there’s clearly a balance.

I’m assuming the TO owner principal is correct and should not be changed to reflect my local environment.

sckqo-e2vyl-4rqqu-5g4wf-pqskh-iynjm-46ixm-awluw-ucnqa-4sl6j-mqe

Are you using the DEPLOY_ID identity as the current dfx identity, like:

dfx identity use DEPLOY_ID_IDENTITY ?

ah! That was it. Recommend you add that in the web page. If you follow the page and your video, the “dfx identity use archive_controller” is the last one used on deployment. Neither in your video nor in the docs is there a direction to switch back to the DevJourney identity (which is the one holding the DEPLOY_ID principal) to do the icrc1_transfer canister call.

Now that it works, it’s obvious why my previous attempts failed. The token transfer comes from current identity, not the DEPLOY_ID env var.

I don’t understand why it works in your video - there doesn’t seem to be an edit cut - and you too deploy under the archive_controller identity so you should have failed too - yet you did not. Would be interesting to know why.

Regardless, it’s working now for me and thanks so much for taking the time to help me resolve this!

@Jessie You should be aware that the example in 1.3 of the developer journey does not work. Myself and a colleague both (independently) ran into the same problem. I also see that another user @Abundanzini reported the same problem in April in this forum. On clicking the ‘Vote’ button it gives a new page with the error: “Could not find a canister id to forward to.”

It appears that the code in index.js is not being invoked. I suspect that the instructions specify putting it in the wrong place.

The lesson concludes by directing students to a completed solution on GitHub, which works ok, however it is not a good first time user experience to complete the first dapp tutorial only for it not to work.

Can you ask someone to check this out please? Thank you.

Thanks @tommccann , I’ve pushed an update to this page to clarify the instructions. The problem was with the selection of the frontend template in the dfx new command - the one selected in the tutorial used TypeScript and Vite, while the tutorial code used JavaScript and React. The instructions are now correct for JavaScript and React.