Docs
Developer guides
Quick start

Quick start

This section will quickly introduce the development of Rooch through a counter example.

What is counter

The counter is a small counting program. It contains an initial value. We can increment its value through an increment instruction to achieve the purpose of counting.

We can use any programming language to implement this small program. This tutorial will use the Move language to write it and let it run successfully on Rooch.

Create counter project

Before we create the counter contract program, we can use the CLI command provided by Rooch to initialize an empty project:

rooch move new quick_start_counter

For detailed methods, please refer to Creating a Rooch Move Contract.

Next, create a counter.move file in the sources directory to write our contract code.

Contract writing

module quick_start_counter::quick_start_counter {
    use moveos_std::account_storage;
    use moveos_std::context::Context;

    struct Counter has key {
        count_value: u64
    }

    fun init(ctx: &mut Context, account: &signer) {
        account_storage::global_move_to(ctx, account, Counter { count_value: 0 });
    }

    entry fun increase(ctx: &mut Context) {
        let counter = account_storage::global_borrow_mut<Counter>(ctx, @quick_start_counter);
        counter.count_value = counter.count_value + 1;
    }
}

With a simple 17 lines of code, a simple counter function is implemented on Rooch Move.

What follows is a detailed description of what each line of code does.

Module declaration

In the Move language, contracts are usually written in modules. Simple contracts can be completed through one module, while complex contracts may be composed of multiple modules. Our counter contract is very simple, so there is only one quick_start_counter module.

Modules usually contain data types and functions required to implement the current module functions.

module quick_start_counter::quick_start_counter {

In line 1, we declare a quick_start_counter module using the module keyword.

In the Move-based blockchain system, modules are uniquely identified by address, that is, an address can only have one module of the same type, and modules of the same type cannot be released multiple times. The same contract can be issued by multiple addresses. In order to identify who issued the contract module in the huge blockchain system, it needs to be uniquely identified by the address. In the Move-based blockchain system, modules are uniquely identified by address, that is, an address can only have one module with the same name, and modules with the same name cannot be published multiple times. The same contract can be published by multiple addresses. In order to identify who published the contract module in the blockchain system, it needs to be uniquely identified by the address.

Therefore, the syntax for declaring a Move module is module address::module_name.

Import module

use moveos_std::account_storage;
use moveos_std::context::Context;

In lines 2~3, it is a statement that imports modules. To implement a counter contract on Rooch, we need to use some functional libraries of the Rooch. This contract uses functional modules such as the account_storage and context provided by the MoveOS Standard Library.

Define data structure

struct Counter has key {
    count_value: u64
}

We define a Counter type structure to record the count value. The structure only contains a u64 type field count_value.

We want to record the value of the Counter type into Rooch's global storage, so we need to provide a key ability for this type so that Move can find the data through the key.

Initialization function

fun init(ctx: &mut Context, account: &signer) {
    account_storage::global_move_to(ctx, account, Counter { value: 0 })
}

Move provides a specific initialization function init to automatically initialize the contract to ensure that some necessary operations have been performed after the contract is released.

For example, we hope that once the counter contract is released, the contract will automatically initialize the counter for us so that its count value is 0.

Line 9 is the function signature of the init function, which accepts two parameters ctx and account.

Increasing function

Next, we need to define an incrementing function that will increment the counter value by 1 every time it is executed.

entry fun increase(ctx: &mut Context) {
    let counter = account_storage::global_borrow_mut<Counter>(ctx, @quick_start_counter);
    counter.count_value = counter.count_value + 1;
}

Line 13 is the signature of the increase function, which accepts a context parameter.

In line 14, the global_borrow_mut instruction of the account storage provided by Rooch is called to obtain a mutable reference of type Counter, and the return value of the function is bound to the counter variable. By borrowing a mutable reference from Counter, we can modify its value.

The global_borrow_mut function accepts a context parameter and an address parameter to borrow the Counter resource. For simplicity, we directly use the address of the published counter module as the borrower.

In line 15, we obtain the field value of the Counter structure through member operations and perform an increment operation.

At this point, we have implemented the incrementing logic of the counter.

Entry function

The entry function is a function modified by the entry keyword.

For security reasons, the Move virtual machine prohibits external (command line, etc.) direct calls to functions that operate module data. Instead, a method called an entry function is provided to indirectly call logical functions. The entry function is the contract exposed to the outside what an interface.

Note: In order to simplify the counter contract demonstrated in this example as much as possible, we merged the logical operation and entry function into one increase function. In actual development, it is recommended to encapsulate the logic and entry function separately into different functions.

As you can see, the increase function on line 13 is modified with the entry keyword, so it becomes an entry function. With the entry function, we can perform the counter increment operation in the command line or other clients.

Special note that the context parameters of the increase function are parameters automatically passed by Move VM. They need to be passed explicitly when writing the contract. However, for external calls, they do not need to be passed manually, so when calling the increase function on the command line, they do not need to pass any arguments.

Demo counter program in Rooch's CLI

  1. First check whether the currently activated Rooch network is the dev network:
$ rooch env list
 
       Env Alias         |                     RPC URL                      |                  Websocket URL                   |  Active Env
---------------------------------------------------------------------------------------------------------------------------------------------------------
         local           |               http://0.0.0.0:50051               |                       Null                       |
          dev            |       https://dev-seed.rooch.network:443/        |                       Null                       |     True

Note that if the dev environment of Active Env is not True, use the rooch env switch --alias dev command to switch to the development network.

  1. Open another terminal, switch to the root directory of the counter project, and compile the contract:
$ rooch move build
 
UPDATING GIT DEPENDENCY https://github.com/rooch-network/rooch.git
UPDATING GIT DEPENDENCY https://github.com/rooch-network/rooch.git
UPDATING GIT DEPENDENCY https://github.com/rooch-network/rooch.git
UPDATING GIT DEPENDENCY https://github.com/rooch-network/rooch.git
UPDATING GIT DEPENDENCY https://github.com/rooch-network/rooch.git
UPDATING GIT DEPENDENCY https://github.com/rooch-network/rooch.git
INCLUDING DEPENDENCY MoveStdlib
INCLUDING DEPENDENCY MoveosStdlib
INCLUDING DEPENDENCY RoochFramework
BUILDING quick_start_counter
Success
  1. Publish the counter contract to Rooch:
$ rooch move publish
 
UPDATING GIT DEPENDENCY https://github.com/rooch-network/rooch.git
UPDATING GIT DEPENDENCY https://github.com/rooch-network/rooch.git
UPDATING GIT DEPENDENCY https://github.com/rooch-network/rooch.git
UPDATING GIT DEPENDENCY https://github.com/rooch-network/rooch.git
UPDATING GIT DEPENDENCY https://github.com/rooch-network/rooch.git
UPDATING GIT DEPENDENCY https://github.com/rooch-network/rooch.git
INCLUDING DEPENDENCY MoveStdlib
INCLUDING DEPENDENCY MoveosStdlib
INCLUDING DEPENDENCY RoochFramework
BUILDING quick_start_counter
Publish modules to address: 0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81
{
  "sequence_info": {
    "tx_order": "17128",
    "tx_order_signature": {
      "auth_validator_id": "0",
      "payload": "0x00b5d56a8178299d628e0d341fff4b97904f7ff80f9e3e8aca10f0d1d9ac65e5736757caec9be17aa54b1da860b183a6d1574f1db9ba632910fb308c4d6283d30eca2ecf17ab26b7c32ddba10913e6f74d43b5258905bef0f88b6d744d73bc9ce9"
    },
    "tx_accumulator_root": "0xb408f55b7e003f54fa37a87ccaa25937bedb7d04d3d8a06f745de4e30b25a3cf"
  },
  "execution_info": {
    "tx_hash": "0xa45998b0a7d979597d0ed4021c2ffbe778d2e0889d3151ad29493e3d91f177a6",
    "state_root": "0x0a5f095123b459749938b4fc436c06c429066f6a48a8f014bba6360471b6d03b",
    "event_root": "0x8be169d5a1b2bdace1ff085fae4753e37f69095ec543a83ef34cae23e9ebb747",
    "gas_used": 1644906,
    "status": {
      "type": "executed"
    }
  },
......

When you see executed in the execution_info.status of the output result, it means that the counter contract has been successfully released and the counter has been initialized.

  1. We use the resource search command provided by Rooch to obtain information about Counter resources.

The syntax is rooch resource --address address_of_published_resource --resource resource_type:

$ rooch resource --address 0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81 --resource 0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81::quick_start_counter::Counter
 
{
  "value": "0x0000000000000000",
  "value_type": "0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81::quick_start_counter::Counter",
  "decoded_value": {
    "abilities": 8,
    "type": "0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81::quick_start_counter::Counter",
    "value": {
      "count_value": "0"
    }
  }
}

Pay attention to the value attribute. You can see that in the output information of the Counter resource, the field count_value of Counter is indeed 0.

  1. Then we call the counter’s increment function:

The syntax is rooch move run --function address_published_by_the_module::module_name::entry_function_name --sender-account address_to_send_the_current_transaction.

Note: In the blockchain system, performing certain operations is usually performed by sending a transaction to the blockchain system to perform the corresponding operation.

$ rooch move run --function 0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81::quick_start_counter::increase --sender-account 0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81
 
{
  "sequence_info": {
    "tx_order": "17160",
    "tx_order_signature": {
      "auth_validator_id": "0",
      "payload": "0x00f3809e65ee7aef9d9f4f7f79820ad6a25d44aed583c74300f30a0550f8256e371546e4515125636646acb3e625bb5d02db933656218832103300861b4a2b9d07ca2ecf17ab26b7c32ddba10913e6f74d43b5258905bef0f88b6d744d73bc9ce9"
    },
    "tx_accumulator_root": "0x89ace9f8d15707a008f7237566761e28743a4c73d9f5b19622c65e4a072850bc"
  },
  "execution_info": {
    "tx_hash": "0x19139e0f8779c43e7feb989553d66e41eab2840705417898dee376b3ea2ea3d0",
    "state_root": "0xb876495e3c144700fb315cf2697a990d25578b4b832f9b34bb74e4f233d4faf2",
    "event_root": "0x414343554d554c41544f525f504c414345484f4c4445525f4841534800000000",
    "gas_used": 12769,
    "status": {
      "type": "executed"
    }
  },
......

If you see executed in the status, it proves that the increase function call was successful.

  1. Check again to see if the counter value is what we expected:
$ rooch resource --address 0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81 --resource 0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81::quick_start_counter::Counter
 
{
  "value": "0x0100000000000000",
  "value_type": "0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81::quick_start_counter::Counter",
  "decoded_value": {
    "abilities": 8,
    "type": "0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81::quick_start_counter::Counter",
    "value": {
      "count_value": "1"
    }
  }
}

As you can see, the value of the Counter's value field has indeed been updated to 1.

At this point, you already know how to write contracts in Rooch and how to call contracts from the command line.

Next, let's increase the difficulty a little bit and we will demonstrate how to run and use the counter contract program in the front end.

Quick experience

The source code of this example is stored in the rooch/examples/quick_start_counter directory. To make testing easier, we change the address in the Move.toml file to the wildcard character _.

If you run it directly using the example we provided, the executed Shell command will be a little different:

$ rooch move build --named-addresses quick_start_counter=default
 
$ rooch move publish --named-addresses quick_start_counter=default
 
# 注意 `0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81` 是我演示的地址,当你实际运行时,需要更改为你自己的钱包地址
$ rooch resource --address 0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81 --resource 0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81::quick_start_counter::Counter
 
$ rooch move run --function 0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81::quick_start_counter::increase --sender-account default
 
$ rooch resource --address 0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81 --resource 0xc4a286bef174e126ef24363a0799c069504d0f132f713bf4762ad127c799df81::quick_start_counter::Counter

Note: The default in the command represents the default address in the Rooch configuration. If you want to use another address, you can also directly pass the address starting with 0x.