diff --git a/echo-ruby/.dockerignore b/echo-ruby/.dockerignore new file mode 100644 index 00000000..2235026f --- /dev/null +++ b/echo-ruby/.dockerignore @@ -0,0 +1,4 @@ +.tool-versions +docker-bake.hcl +docker-bake.override.hcl +docker-compose.override.yml \ No newline at end of file diff --git a/echo-ruby/.tool-versions b/echo-ruby/.tool-versions new file mode 100644 index 00000000..a2e77829 --- /dev/null +++ b/echo-ruby/.tool-versions @@ -0,0 +1 @@ +ruby 3.0.2 diff --git a/echo-ruby/Dockerfile b/echo-ruby/Dockerfile new file mode 100644 index 00000000..14e6a05e --- /dev/null +++ b/echo-ruby/Dockerfile @@ -0,0 +1,43 @@ +# syntax=docker.io/docker/dockerfile:1.4 + +# build stage: includes resources necessary for installing dependencies + +# Here the image's platform does not necessarily have to be riscv64. +# If any needed dependencies rely on native binaries, you must use +# a riscv64 image such as riscv64/ubuntu:22.04 for the build stage, +# to ensure that the appropriate binaries will be generated. +FROM --platform=linux/riscv64 riscv64/ubuntu:22.04 as build-stage + +WORKDIR /opt/cartesi/dapp + +COPY Gemfile . +COPY Gemfile.lock . + +ENV GEM_HOME="/opt/cartesi/dapp/bundle" +ENV PATH=$GEM_HOME/bin:$GEM_HOME/gems/bin:$PATH + +RUN apt-get update \ + && apt-get install -y ruby ruby-dev build-essential \ + && gem install bundler \ + && bundle install \ + && rm -rf /opt/cartesi/dapp/bundle/cache/* + +# runtime stage: produces final image that will be executed + +# Here the image's platform must be riscv64. +# Give preference to small base images, which lead to better start-up +# performance when loading the Cartesi Machine. +FROM --platform=linux/riscv64 riscv64/ubuntu:jammy +WORKDIR /opt/cartesi/dapp + +ENV GEM_HOME="/opt/cartesi/dapp/bundle" +ENV PATH=$GEM_HOME/bin:$GEM_HOME/gems/bin:$PATH + +RUN apt-get update \ + && apt-get install -y ruby \ + && rm -rf /var/apt/lists/* \ + && rm -rf /usr/lib/ruby/gems/*/cache/* +COPY --from=build-stage /opt/cartesi/dapp ./ + +COPY echo.rb . +COPY entrypoint.sh . \ No newline at end of file diff --git a/echo-ruby/Gemfile b/echo-ruby/Gemfile new file mode 100644 index 00000000..e2e9250d --- /dev/null +++ b/echo-ruby/Gemfile @@ -0,0 +1,6 @@ +ruby '3.0.2' + +source 'https://rubygems.org' + +gem 'json' +gem 'http' diff --git a/echo-ruby/Gemfile.lock b/echo-ruby/Gemfile.lock new file mode 100644 index 00000000..1281945c --- /dev/null +++ b/echo-ruby/Gemfile.lock @@ -0,0 +1,40 @@ +GEM + remote: https://rubygems.org/ + specs: + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + ffi (1.15.5) + ffi-compiler (1.0.1) + ffi (>= 1.0.0) + rake + http (4.4.1) + addressable (~> 2.3) + http-cookie (~> 1.0) + http-form_data (~> 2.2) + http-parser (~> 1.2.0) + http-cookie (1.0.5) + domain_name (~> 0.5) + http-form_data (2.3.0) + http-parser (1.2.3) + ffi-compiler (>= 1.0, < 2.0) + json (2.6.3) + public_suffix (5.0.1) + rake (13.0.6) + unf (0.1.4) + unf_ext + unf_ext (0.0.8.2) + +PLATFORMS + arm64-darwin-21 + +DEPENDENCIES + http + json + +RUBY VERSION + ruby 3.0.2p107 + +BUNDLED WITH + 2.2.22 diff --git a/echo-ruby/README.md b/echo-ruby/README.md new file mode 100644 index 00000000..b2dec35b --- /dev/null +++ b/echo-ruby/README.md @@ -0,0 +1,63 @@ +# Echo Ruby DApp + +This example represents a minimalistic Cartesi Rollups application that simply copies (or "echoes") each input received as a corresponding output notice. This DApp's back-end is written in Ruby. + +## Interacting with the application + +We can use the [frontend-console](../frontend-console) application to interact with the DApp. +Ensure that the [application has already been built](../frontend-console/README.md#building) before using it. + +First, go to a separate terminal window and switch to the `frontend-console` directory: + +```shell +cd frontend-console +``` + +Then, send an input as follows: + +```shell +yarn start input send --payload "Hello there" +``` + +In order to verify the notices generated by your inputs, run the command: + +```shell +yarn start notice list +``` + +The response should be something like this: + +```json +[{"epoch":"0","input":"1","notice":"0","payload":"Hello there"}] +``` + +## Running the back-end 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](../README.md#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. + +This DApp's back-end is written in Ruby and expects version 2.6.6 or higher to be available in the host machine. + +In order to start the back-end, run the following commands in a dedicated terminal: + +```shell +cd echo-ruby/ +ruby echo.rb +``` + +The final command will effectively run the back-end and send corresponding outputs to port `5004`. +It can optionally be configured in an IDE to allow interactive debugging using features like breakpoints. + +You can also use a tool like [entr](https://eradman.com/entrproject/) to restart the back-end automatically when the code changes. For example: + +```shell +ls *.rb | entr -r ruby echo.rb +``` + +After the back-end successfully starts, it should print an output like the following: + +```log +HTTP rollup_server url is http://127.0.0.1:5004 +Sending finish +``` + +After that, you can interact with the application normally [as explained above](#interacting-with-the-application). diff --git a/echo-ruby/dapp.json b/echo-ruby/dapp.json new file mode 100644 index 00000000..89868f87 --- /dev/null +++ b/echo-ruby/dapp.json @@ -0,0 +1,5 @@ +{ + "fs": { + "files": ["echo.rb", "entrypoint.sh"] + } +} diff --git a/echo-ruby/docker-bake.hcl b/echo-ruby/docker-bake.hcl new file mode 120000 index 00000000..bc81cc07 --- /dev/null +++ b/echo-ruby/docker-bake.hcl @@ -0,0 +1 @@ +../build/docker-riscv/base.hcl \ No newline at end of file diff --git a/echo-ruby/docker-bake.override.hcl b/echo-ruby/docker-bake.override.hcl new file mode 100644 index 00000000..33a5f60c --- /dev/null +++ b/echo-ruby/docker-bake.override.hcl @@ -0,0 +1,23 @@ + +variable "TAG" { + default = "devel" +} + +variable "DOCKER_ORGANIZATION" { + default = "cartesi" +} + +target "dapp" { +} + +target "server" { + tags = ["${DOCKER_ORGANIZATION}/dapp:echo-ruby-${TAG}-server"] +} + +target "console" { + tags = ["${DOCKER_ORGANIZATION}/dapp:echo-ruby-${TAG}-console"] +} + +target "machine" { + tags = ["${DOCKER_ORGANIZATION}/dapp:echo-ruby-${TAG}-machine"] +} diff --git a/echo-ruby/docker-compose.override.yml b/echo-ruby/docker-compose.override.yml new file mode 100644 index 00000000..ae2d01f1 --- /dev/null +++ b/echo-ruby/docker-compose.override.yml @@ -0,0 +1,5 @@ +version: "3" + +services: + server_manager: + image: ${DAPP_IMAGE:-cartesi/dapp:echo-ruby-devel-server} diff --git a/echo-ruby/echo.rb b/echo-ruby/echo.rb new file mode 100644 index 00000000..e39abe96 --- /dev/null +++ b/echo-ruby/echo.rb @@ -0,0 +1,82 @@ +# Copyright 2022 Cartesi Pte. Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +require 'json' +require 'http' + +def log(message) + puts message +end + +def handle_advance(data) + log("Received advance request data #{data}") + payload = data['payload'] + log("Adding notice \"#{payload}\"") + response = HTTP.post(ROLLUP_SERVER + '/notice', { + headers: { + 'Content-Type': 'application/json' + }, + json: { payload: payload } + }) + log("Received notice status #{response.status} with body #{response}") + return "accept"; +end + +def handle_inspect(data) + log("Received inspect request data #{data}"); + payload = data['payload'] + log("Adding report \"#{payload}\"") + response = HTTP.post(ROLLUP_SERVER + '/report', { + headers: { + 'Content-Type': 'application/json' + }, + json: { payload: payload } + }) + log("Received report status #{response.status}") + return "accept" +end + +ROLLUP_SERVER = ENV.fetch('ROLLUP_HTTP_SERVER_URL', 'http://127.0.0.1:5004') +log("HTTP rollup_server url is #{ROLLUP_SERVER}") + +finish = { status: "accept" } + +while (true) do + log("Sending finish") + + response = HTTP.post(ROLLUP_SERVER + '/finish', { + headers: { + 'Content-Type': 'application/json' + }, + json: { status: 'accept' } + }); + + log("Received finish status #{response.status}") + + if response.status == 202 + log("No pending rollup request, trying again") + else + rollup_req = response.parse + metadata = rollup_req['data']['metadata'] + if (metadata && metadata['epoch_index'] == 0 && metadata['input_index'] == 0) + rollup_address = metadata['msg_sender']; + log("Captured rollup address: #{rollup_address}") + else + case rollup_req['request_type'] + when 'advance_state' + finish[:status] = handle_advance(rollup_req['data']) + when 'inspect_state' + finish[:status] = handle_inspect(rollup_req['data']) + end + end + end +end \ No newline at end of file diff --git a/echo-ruby/entrypoint.sh b/echo-ruby/entrypoint.sh new file mode 100755 index 00000000..c5928fed --- /dev/null +++ b/echo-ruby/entrypoint.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# Copyright 2022 Cartesi Pte. Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +export GEM_HOME="/opt/cartesi/dapp/bundle" +export PATH=$GEM_HOME/bin:$GEM_HOME/gems/bin:$PATH + +set -e +rollup-init bundle exec ruby echo.rb