Increment a natural number

In this tutorial, you are going to write a program that creates a single actor and provides a few basic functions to increment a counter and illustrate persistence of a value.

For this tutorial, the actor is named Counter. The program uses the currentValue variable to contain a natural number that represents the current value of the counter. This program supports the following function calls:

  • The increment function call updates the current value, incrementing by 1 (no return value).

  • The get function call queries and returns the current value.

  • The set function call updates the current value to an arbitrary numeric value you specify as an argument.

This tutorial provides a simple example of how you can increment a counter by calling functions on a deployed canister. By calling the function to increment a value multiple times, you can verify that the variable state—that is, the value of the variable between calls—persists.

Before you begin

Before starting the tutorial, verify the following:

  • You have downloaded and installed the DFINITY Canister SDK package as described in Download and install.

  • You have stopped any Internet Computer network processes running on the local computer.

This tutorial takes approximately 20 minutes to complete.

Create a new project

To create a new project directory for this tutorial:

  1. Open a terminal shell on your local computer, if you don’t already have one open.

  2. Change to the folder you are using for your Internet Computer projects, if you are using one.

  3. Create a new project by running the following command:

    dfx new my_counter

    The command creates a new my_counter project and Git repository for your project.

  4. Change to your project directory by running the following command:

    cd my_counter

Modify the default configuration

You have already seen that creating a new project adds a default dfx.json configuration file to your project directory. In this tutorial, you will modify the default settings to use a different name for the main program in your project.

To modify the default dfx.json configuration file:

  1. Open the dfx.json configuration file in a text editor and change the default main setting from main.mo to increment_counter.mo.

    For example:

    "main": "src/my_counter/increment_counter.mo",

    For this tutorial, changing the name of the source file from main.mo to increment_counter.mo simply illustrates how the setting in the dfx.json configuration file determines the source file to be compiled.

    In a more complex application, you might have multiple source files with dependencies that you need to manage using settings in the dfx.json configuration file. In a scenario like that—with multiple canisters and programs defined in your dfx.json file—having multiple files all named main.mo might be confusing.

    You can leave the rest of the default settings as they are.

  2. Save your change and close the dfx.json file to continue.

  3. Change the name of the main program file in the source code directory to match the name specified in the dfx.json configuration file by running the following command

    mv src/my_counter/main.mo src/my_counter/increment_counter.mo

Modify the default program

So far, you have only changed the name of the main program for your project. The next step is to modify the code in the src/my_counter/increment_counter.mo file to define an actor named Counter and implement the increment, get, and set functions.

To modify the default template source code:

  1. Check that you are still in your project directory, if needed.

  2. Open the src/my_counter/increment_counter.mo file in a text editor and delete the existing content.

  3. Copy and paste the following sample code into the increment_counter.mo file:

    // Create a simple Counter actor.
    actor Counter {
        stable var currentValue : Nat = 0;
    
        // Increment the counter with the increment function.
        public func increment() : async () {
            currentValue += 1;
        };
    
        // Read the counter value with a get function.
        public query func get() : async Nat {
            currentValue
        };
    
        // Write an arbitrary value with a set function.
        public func set(n: Nat) : async () {
            currentValue := n;
        };
    }

    Let’s take a closer look at this sample program:

    • You can see that the currentValue variable declaration in this example includes the stable keyword to indicate the state—the value that can be set, incremented, and retrieved—persists.

      This keyword ensures that the value for the variable is unchanged when the program is upgraded.

    • The declaration for the currentValue variable also specifies that its type is a natural (Nat) number.

    • The program includes two public update methods—the increment and set functions—and one a query method, in this case, the get function.

    For more information about stable and flexible variables, see Stable variables and upgrade methods in the Motoko Programming Language Guide.

    For more information about the differences between a query and an update, see query calls in Canisters include both program and state.

  4. Save your changes and close the file to continue.

Start the local network

Before you can build the my_counter project, you need to connect to the Internet Computer network either running locally in your development environment or running remotely on a sub-network that you can access.

Starting the network locally requires a dfx.json file, so you should be sure you are in your project’s root directory. For this tutorial, you should have two separate terminal shells, so that you can start and see network operations in one terminal and manage your project in another.

To start the network locally:

  1. Open a new terminal window or tab on your local computer.

  2. Navigate to the root directory for your project, if necessary.

    • You should now have two terminals open.

    • You should have the project directory as your current working directory.

  3. Start the Internet Computer network on your local computer by running the following command:

    dfx start

    After you start the local network, the terminal displays messages about network operations.

  4. Leave the terminal that displays network operations open and switch your focus to your original terminal where you created your new project.

Register, build, and deploy the application

After you connect to the Internet Computer network running locally in your development environment, you can register, build, and deploy your application locally.

To deploy the application locally:

  1. Check that you are still in the root directory for your project, if needed.

  2. Register, build, and deploy your application by running the following command:

    dfx deploy

    The dfx deploy command output displays information about the operations it performs.

Invoke methods on the deployed canister

After successfully deploying the canister, you can simulate an end-user invoking the methods provided by the canister. For this tutorial, you invoke a get method to query the value of a counter, an increment method that increments the counter each time it is called, and a set method to pass an argument to update the counter to an arbitrary value you specify.

To test invoking methods on the deployed canister:

  1. Run the following command to invoke the get function, which reads the current value of the currentValue variable on the deployed canister:

    dfx canister call my_counter get

    The command returns the current value of the currentValue variable as zero:

    (0)
  2. Run the following command to invoke the increment function to increment the value of the currentValue variable on the deployed canister by one:

    dfx canister call my_counter increment

    This command increments the value of the variable—changing its state—but does not return the result.

  3. Rerun the following command to get the current value of the currentValue variable on the deployed canister:

    dfx canister call my_counter get

    The command returns the updated value of the currentValue variable as one:

    (1)
  4. Run additional commands to experiment with invoking other methods and using different values.

    For example, try commands similar to the following to set and return the counter value:

    dfx canister call my_counter set '(987)'
    dfx canister call my_counter get

    Returns the current value of 987.

    dfx canister call my_counter increment
    dfx canister call my_counter get

    Returns the incremented value of 988.

Test functions in a browser

The canister interface description language—often referred to as Candid or more generally as the IDL—provides a common language for specifying the signature of a canister service. The language provides a unified way of interacting with canisters in various languages and tools, such as the dfx command-line interface, JavaScript, and Motoko.

Based on the type signature of the actor, Candid also provides a web interface that allows you to call canister functions for testing and debugging.

If you have upgraded to a 0.7.0-beta version of the DFINITY Canister SDK, you cannot yet use the Candid web interface to test functions in a browser. To use the Candid web interface, you can install a previous version of the DFINITY Canister SDK for your project.

After you have deployed your project locally using the dfx deploy or dfx canister install command, you can access the Candid web interface endpoint in a browser. Accessing the Candid web interface endpoint enables you to view and test canister functions without writing any front-end code.

To use the Candid web interface to test canister functions:

  1. Copy the canister identifier associated with the main actor for your application.

  2. Open a browser and navigate to the address and port number specified in the dfx.json configuration file.

    By default, the local network binds to the 127.0.0.1:8000 address and port number.

  3. Add the candid endpoint to access the Candid web interface followed by the required canisterId parameter and canister identifier.

    For example, the full URL should look similar to the following but with the canister_identifier that was returned by the dfx canister install command:

    http://127.0.0.1:8000/candid?canisterId=<YOUR-CANISTER-IDENTIFIER>
  4. Review the list of function calls and types defined in the program.

  5. Type a value of the appropriate type for a function or click Random to generate a value, then click Call or Query to see the result.

    Note that depending on the data type, the Candid interface might display additional configuration settings for testing functions. For example, if a function takes an array, you might need to specify the number of items in the array before entering values.

    Counter functions

Stop the local network

After you finish experimenting with your program, you can stop the local Internet Computer network so that it doesn’t continue running in the background.

To stop the local network:

  1. In the terminal that displays network operations, press Control-C to interrupt the local network process.

  2. Stop the Internet Computer network by running the following command:

    dfx stop