Skip to main content

Run your first DApp

In this section, we will explain how to run a Simple Echo DApp example that shows how to build and interact with a minimalistic Cartesi Rollups application that simply copies (or "echoes") each input received as a corresponding output notice. The DApp's back-end is written in Python, and its front-end is simply a set of standard Hardhat command line tasks that can be executed from a terminal.

Before getting started, make sure you have installed all the necessary requirements.

Building the environment

To run the echo example, start by cloning the cartesi/rollups-examples Github repository as follows:

$ git clone https://github.com/cartesi/rollups-examples.git

Then, build the back-end for the echo example:

$ cd rollups-examples/echo
$ make machine

Running the environment

In order to start the containers in production mode, simply run:

$ docker-compose up --build

Note: If you decide to use Docker Compose V2, make sure you set the compatibility flag when executing the command (e.g., docker compose --compatibility up).

Allow some time for the infrastructure to be ready. How much will depend on your system, but after some time showing the error "concurrent call in session", eventually the container logs will repeatedly show the following:

server_manager_1      | Received GetVersion
server_manager_1 | Received GetStatus
server_manager_1 | default_rollups_id
server_manager_1 | Received GetSessionStatus for session default_rollups_id
server_manager_1 | 0
server_manager_1 | Received GetEpochStatus for session default_rollups_id epoch 0

To stop the containers, first end the process with Ctrl + C. Then, remove the containers and associated volumes by executing:

$ docker-compose down -v

Interacting with the application

With the infrastructure in place, you can interact with the application using a set of Hardhat tasks.

First, go to a separate terminal window, switch to the echo/contracts directory, and run yarn:

$ cd echo/contracts/
$ yarn

Then, send an input as follows:

$ npx hardhat --network localhost echo:addInput --input "0x63617274657369"

The input will have been accepted when you receive a response similar to the following one:

Added input '0x63617274657369' to epoch '0' (index '0', timestamp: 1640643170, signer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, tx: 0x31d7e9e810d8702196623837b8512097786b544a4b5ffb52f693b9ff7d424147)

In order to verify the notices generated by your inputs, run the command:

$ npx hardhat --network localhost echo:getNotices --epoch 0

The response should be something like this:

{"session_id":"default_rollups_id","epoch_index":"0","input_index":"0","notice_index":"0","payload":"63617274657369"}

You can also send inputs as regular strings. For example:

$ npx hardhat --network localhost echo:addInput --input 'Hello there!'

To retrieve notices interpreting the payload as a UTF-8 string, you can use the --payload string option:

$ npx hardhat --network localhost echo:getNotices --epoch 0 --payload string
{"session_id":"default_rollups_id","epoch_index":"0","input_index":"1","notice_index":"0","payload":"Hello there!"}

Finally, note that you can check the available options for all Hardhat tasks using the --help switch:

$ npx hardhat echo:addInput --help

Advancing time

To advance time, in order to simulate the passing of epochs, run:

$ npx hardhat --network localhost util:advanceTime --seconds 864010

Running the environment in host mode

When developing an application, it is often important to easily test and debug it. For that matter, it is possible to run the Cartesi Rollups environment in host mode, so that the DApp's back-end can be executed directly on the host machine, allowing it to be debugged using regular development tools such as an IDE.

The first step is to run the environment in host mode using the following command:

$ docker-compose -f docker-compose.yml -f docker-compose-host.yml up --build

The next step is to run the echo server in your machine. The application is written in Python, so you need to have python3 installed.

In order to start the echo server, run the following commands in a dedicated terminal:

$ cd echo/server/
$ python3 -m venv .env
$ . .env/bin/activate
$ pip install -r requirements.txt
$ HTTP_DISPATCHER_URL="http://127.0.0.1:5004" gunicorn --reload --workers 1 --bind 0.0.0.0:5003 echo:app

This will run the echo server on port 5003 and send the corresponding notices to port 5004. The server will also automatically reload if there is a change in the source code, enabling fast development iterations.

The final command, which effectively starts the server, can also be configured in an IDE to allow interactive debugging using features like breakpoints. In that case, it may be interesting to add the parameter --timeout 0 to gunicorn, to avoid having it time out when the debugger stops at a breakpoint.

After the server successfully starts, it should print an output like the following:

[2022-01-21 12:38:23,971] INFO in echo: HTTP dispatcher url is http://127.0.0.1:5004
[2022-01-21 12:38:23 -0500] [79032] [INFO] Starting gunicorn 19.9.0
[2022-01-21 12:38:23 -0500] [79032] [INFO] Listening at: http://0.0.0.0:5003 (79032)
[2022-01-21 12:38:23 -0500] [79032] [INFO] Using worker: sync
[2022-01-21 12:38:23 -0500] [79035] [INFO] Booting worker with pid: 79035

After that, you can interact with the application normally as explained above.

When you add an input, you should see it being processed by the echo server as follows:

[2022-01-21 15:58:39,555] INFO in echo: Received advance request body {'metadata': {'msg_sender': '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', 'epoch_index': 0, 'input_index': 0, 'block_number': 11, 'time_stamp': 1642791522}, 'payload': '0x636172746573690d0a'}
[2022-01-21 15:58:39,556] INFO in echo: Adding notice
[2022-01-21 15:58:39,650] INFO in echo: Received notice status 201 body b'{"index":0}'
[2022-01-21 15:58:39,651] INFO in echo: Finishing
[2022-01-21 15:58:39,666] INFO in echo: Received finish status 202

Finally, to stop the containers, removing any associated volumes, execute:

$ docker-compose -f docker-compose.yml -f docker-compose-host.yml down -v