From c73b5cafd74aea7a69c5424a892cc81d44722b45 Mon Sep 17 00:00:00 2001 From: andy-thomason Date: Sat, 8 Oct 2022 23:38:18 +0100 Subject: [PATCH 1/3] Mandelbrot rust example. --- rust-mandelbrot-nft/.dockerignore | 1 + rust-mandelbrot-nft/.gitignore | 1 + rust-mandelbrot-nft/Cargo.lock | 417 ++++++++++++++++++ rust-mandelbrot-nft/Cargo.toml | 11 + rust-mandelbrot-nft/Dockerfile | 7 + rust-mandelbrot-nft/README.md | 61 +++ rust-mandelbrot-nft/dapp.json | 8 + rust-mandelbrot-nft/docker-bake.hcl | 1 + rust-mandelbrot-nft/docker-bake.override.hcl | 23 + .../docker-compose.override.yml | 5 + rust-mandelbrot-nft/entrypoint.sh | 15 + rust-mandelbrot-nft/hello_rust.png | Bin 0 -> 66496 bytes .../riscv64ima-cartesi-linux-gnu.json | 35 ++ rust-mandelbrot-nft/src/main.rs | 230 ++++++++++ 14 files changed, 815 insertions(+) create mode 100644 rust-mandelbrot-nft/.dockerignore create mode 100644 rust-mandelbrot-nft/.gitignore create mode 100644 rust-mandelbrot-nft/Cargo.lock create mode 100644 rust-mandelbrot-nft/Cargo.toml create mode 100644 rust-mandelbrot-nft/Dockerfile create mode 100644 rust-mandelbrot-nft/README.md create mode 100644 rust-mandelbrot-nft/dapp.json create mode 120000 rust-mandelbrot-nft/docker-bake.hcl create mode 100644 rust-mandelbrot-nft/docker-bake.override.hcl create mode 100644 rust-mandelbrot-nft/docker-compose.override.yml create mode 100755 rust-mandelbrot-nft/entrypoint.sh create mode 100644 rust-mandelbrot-nft/hello_rust.png create mode 100644 rust-mandelbrot-nft/riscv64ima-cartesi-linux-gnu.json create mode 100644 rust-mandelbrot-nft/src/main.rs diff --git a/rust-mandelbrot-nft/.dockerignore b/rust-mandelbrot-nft/.dockerignore new file mode 100644 index 00000000..eb5a316c --- /dev/null +++ b/rust-mandelbrot-nft/.dockerignore @@ -0,0 +1 @@ +target diff --git a/rust-mandelbrot-nft/.gitignore b/rust-mandelbrot-nft/.gitignore new file mode 100644 index 00000000..eb5a316c --- /dev/null +++ b/rust-mandelbrot-nft/.gitignore @@ -0,0 +1 @@ +target diff --git a/rust-mandelbrot-nft/Cargo.lock b/rust-mandelbrot-nft/Cargo.lock new file mode 100644 index 00000000..9f981e1b --- /dev/null +++ b/rust-mandelbrot-nft/Cargo.lock @@ -0,0 +1,417 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "flate2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "json" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "miniz_oxide" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "wasi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "png" +version = "0.17.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0e7f4c94ec26ff209cee506314212639d6c91b80afb82984819fafce9df01c" +dependencies = [ + "bitflags", + "crc32fast", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "proc-macro2" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rust-mandelbrot-nft" +version = "0.1.0" +dependencies = [ + "hyper", + "json", + "png", + "tokio", +] + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tokio" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce653fb475565de9f6fb0614b28bca8df2c430c0cf84bcd9c843f15de5414cc" +dependencies = [ + "libc", + "mio", + "num_cpus", + "once_cell", + "pin-project-lite", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "unicode-xid" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/rust-mandelbrot-nft/Cargo.toml b/rust-mandelbrot-nft/Cargo.toml new file mode 100644 index 00000000..df8af02c --- /dev/null +++ b/rust-mandelbrot-nft/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rust-mandelbrot-nft" +version = "0.1.0" +edition = "2021" +authors = ["Andy Thomason"] + +[dependencies] +json = "0.12" +hyper = { version = "0.14", features = ["http1", "runtime", "client"] } +tokio = { version = "1.18", features = ["macros", "rt-multi-thread"] } +png = "0.17" diff --git a/rust-mandelbrot-nft/Dockerfile b/rust-mandelbrot-nft/Dockerfile new file mode 100644 index 00000000..bc2e5aaa --- /dev/null +++ b/rust-mandelbrot-nft/Dockerfile @@ -0,0 +1,7 @@ +# syntax=docker.io/docker/dockerfile:1.4 +FROM cartesi/toolchain:0.11.0 as dapp-build + +WORKDIR /opt/cartesi/dapp + +COPY . . +RUN cargo build -Z build-std=std,core,alloc,panic_abort,proc_macro --target riscv64ima-cartesi-linux-gnu.json --release diff --git a/rust-mandelbrot-nft/README.md b/rust-mandelbrot-nft/README.md new file mode 100644 index 00000000..1ded4b41 --- /dev/null +++ b/rust-mandelbrot-nft/README.md @@ -0,0 +1,61 @@ +# Echo Rust DApp + +This example implements the same behavior as the [Echo DApp written in Python](../echo-python), but here the back-end is written in Rust. As the other example, the DApp simply copies (or "echoes") each input received as a corresponding output notice. + +## 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 is written in Rust, so you need to have rust installed in order to recompile it. + +In order to start the echo-rust back-end, run the following commands in a dedicated terminal: + +```shell +cd echo-rust/ +ROLLUP_HTTP_SERVER_URL="http://127.0.0.1:5004" cargo run +``` + +This will run the echo-rust back-end and send the corresponding notices to port `5004`. + +You can also use a tool like [entr](https://eradman.com/entrproject/) to restart it automatically when the code changes. For example: + +```shell +ls src/*.rs | ROLLUP_HTTP_SERVER_URL="http://127.0.0.1:5004" entr -r cargo run +``` + +After the back-end successfully starts, it should print an output like the following: + +```log +Starting echo-dapp: Sending finish +``` + +After that, you can interact with the application normally [as explained above](#interacting-with-the-application). diff --git a/rust-mandelbrot-nft/dapp.json b/rust-mandelbrot-nft/dapp.json new file mode 100644 index 00000000..f40a1caa --- /dev/null +++ b/rust-mandelbrot-nft/dapp.json @@ -0,0 +1,8 @@ +{ + "fs": { + "files": [ + "target/riscv64ima-cartesi-linux-gnu/release/echo-backend", + "entrypoint.sh" + ] + } +} diff --git a/rust-mandelbrot-nft/docker-bake.hcl b/rust-mandelbrot-nft/docker-bake.hcl new file mode 120000 index 00000000..bfe3894d --- /dev/null +++ b/rust-mandelbrot-nft/docker-bake.hcl @@ -0,0 +1 @@ +../base.hcl \ No newline at end of file diff --git a/rust-mandelbrot-nft/docker-bake.override.hcl b/rust-mandelbrot-nft/docker-bake.override.hcl new file mode 100644 index 00000000..2094a337 --- /dev/null +++ b/rust-mandelbrot-nft/docker-bake.override.hcl @@ -0,0 +1,23 @@ + +target "dapp" { +} + +variable "TAG" { + default = "devel" +} + +variable "DOCKER_ORGANIZATION" { + default = "cartesi" +} + +target "server" { + tags = ["${DOCKER_ORGANIZATION}/dapp:echo-rust-${TAG}-server"] +} + +target "console" { + tags = ["${DOCKER_ORGANIZATION}/dapp:echo-rust-${TAG}-console"] +} + +target "machine" { + tags = ["${DOCKER_ORGANIZATION}/dapp:echo-rust-${TAG}-machine"] +} diff --git a/rust-mandelbrot-nft/docker-compose.override.yml b/rust-mandelbrot-nft/docker-compose.override.yml new file mode 100644 index 00000000..a9966937 --- /dev/null +++ b/rust-mandelbrot-nft/docker-compose.override.yml @@ -0,0 +1,5 @@ +version: "3" + +services: + server_manager: + image: ${DAPP_IMAGE:-cartesi/dapp:echo-rust-0.9.1-server} diff --git a/rust-mandelbrot-nft/entrypoint.sh b/rust-mandelbrot-nft/entrypoint.sh new file mode 100755 index 00000000..4c81e9d3 --- /dev/null +++ b/rust-mandelbrot-nft/entrypoint.sh @@ -0,0 +1,15 @@ +#!/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. + +set -e +rollup-init ./target/riscv64ima-cartesi-linux-gnu/release/echo-backend diff --git a/rust-mandelbrot-nft/hello_rust.png b/rust-mandelbrot-nft/hello_rust.png new file mode 100644 index 0000000000000000000000000000000000000000..05ad60c314ac56026b90b4f3b3dc17486356390d GIT binary patch literal 66496 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 yUg$hK=H|XYy}iJ)BM)i+{OFgjLUiNs0(0000 String { + assert!(s.starts_with("0x")); + + s[2..].as_bytes() + .chunks_exact(2) + .map(|c| { + let d0 = if c[0] > b'9' { c[0] + 9 } else { c[0] } & 0x0f; + let d1 = if c[1] > b'9' { c[1] + 9 } else { c[1] } & 0x0f; + (d0 * 16 + d1) as char + }).collect::() +} + +fn to_hex(b: &[u8]) -> String { + let mut res = String::with_capacity(b.len()*2+2); + res.push_str("0x"); + for byte in b { + res.push(b"0123456789abcdef"[(byte>>4) as usize] as char); + res.push(b"0123456789abcdef"[(byte&0x0f) as usize] as char); + } + res +} + +#[test] +fn hex() { + assert_eq!(from_hex("0x48656c6c6f"), "Hello"); + + assert_eq!(to_hex(b"Hello"), "0x48656c6c6f"); +} + +fn escape_time(cx: f64, cy: f64) -> u8 { + let mut zx = cx; + let mut zy = cy; + let mut res = 0; + loop { + (zx, zy) = (zx*zx - zy*zy + cx, 2.0*zy*zx + cy ); + if zx*zx + zy*zy > 4.0 || res == 255 { + return res; + } + res += 1; + } +} + +fn gen_nft(params: &str) -> Vec { + const SIZE : usize = 1024; + + println!("gen_bft: params={}", params); + let params = params.strip_prefix("(").unwrap(); + let params = params.strip_suffix(")").unwrap(); + let mut it = params.split(":").map(|x| x.parse().unwrap()); + + let px : f64 = it.next().unwrap(); + let py : f64 = it.next().unwrap(); + let zoom : f64 = 1.0 / it.next().unwrap() / (SIZE as f64) / 2.0; + + println!("x,y,z={},{},{}", px, py, zoom); + + let mut w = Vec::new(); + { + let mut encoder = png::Encoder::new(& mut w, SIZE as u32, SIZE as u32); // Width is 2 pixels and height is 1. + encoder.set_color(png::ColorType::Rgba); + encoder.set_depth(png::BitDepth::Eight); + + let mut data = [0_u8; SIZE*SIZE*4]; + + for y in 0..SIZE { + let cy = (y as i32 - (SIZE/2) as i32) as f64 * zoom + py; + for x in 0..SIZE { + let cx = (x as i32 - (SIZE/2) as i32) as f64 * zoom + px; + let t = escape_time(cx, cy); + data[(y*SIZE+x)*4+0] = t << 4; + data[(y*SIZE+x)*4+1] = t << 2; + data[(y*SIZE+x)*4+2] = t; + data[(y*SIZE+x)*4+3] = 0xff; + } + } + + let mut writer = encoder.write_header().unwrap(); + writer.write_image_data(&data).unwrap(); + } + + // Write the image + // TODO: write to IPFS. + let filename = format!("/tmp/mandelbrot-{}.png", params); + std::fs::write(&filename, &w).unwrap(); + println!("written {} size={}", filename, w.len()); + filename.into_bytes() +} + +async fn print_response( + response: hyper::Response, +) -> Result<(), Box> +where + ::Error: 'static, + ::Error: std::error::Error, +{ + let response_status = response.status().as_u16(); + let response_body = hyper::body::to_bytes(response).await?; + println!( + "Received notice status {} body {}", + response_status, + std::str::from_utf8(&response_body)? + ); + Ok(()) +} + +fn process_initial(metadata: &JsonValue) -> Option { + let epoch_index = metadata["epoch_index"].as_u64()?; + let input_index = metadata["input_index"].as_u64()?; + + if epoch_index == 0 && input_index == 0 { + let msg_sender = metadata["msg_sender"].as_str()?; + println!("Captured rollup address: {}", msg_sender); + return Some(msg_sender.to_string()); + } + + return None; +} + +pub async fn handle_advance( + client: &hyper::Client, + server_addr: &str, + request: JsonValue, +) -> Result<&'static str, Box> { + println!("Received advance request data {}", &request); + let payload = request["data"]["payload"] + .as_str() + .ok_or("Missing payload")?; + + println!("Adding notice"); + + let res = gen_nft(&from_hex(&payload)); + + let notice = object! {"payload" => to_hex(&res)}; + + let req = hyper::Request::builder() + .method(hyper::Method::POST) + .header(hyper::header::CONTENT_TYPE, "application/json") + .uri(format!("{}/notice", server_addr)) + .body(hyper::Body::from(notice.dump()))?; + let response = client.request(req).await?; + + print_response(response).await?; + + Ok("accept") +} + +pub async fn handle_inspect( + client: &hyper::Client, + server_addr: &str, + request: JsonValue, +) -> Result<&'static str, Box> { + println!("Received inspect request data {}", &request); + let payload = request["data"]["payload"] + .as_str() + .ok_or("Missing payload")?; + println!("Adding report"); + let report = object! {"payload" => format!("{}", payload)}; + let req = hyper::Request::builder() + .method(hyper::Method::POST) + .header(hyper::header::CONTENT_TYPE, "application/json") + .uri(format!("{}/report", server_addr)) + .body(hyper::Body::from(report.dump()))?; + let response = client.request(req).await?; + print_response(response).await?; + Ok("accept") +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = hyper::Client::new(); + let server_addr = env::var("ROLLUP_HTTP_SERVER_URL")?; + + let mut status = "accept"; + let mut _rollup_address = String::new(); + loop { + println!("Sending finish"); + let response = object! {"status" => status.clone()}; + let request = hyper::Request::builder() + .method(hyper::Method::POST) + .header(hyper::header::CONTENT_TYPE, "application/json") + .uri(format!("{}/finish", &server_addr)) + .body(hyper::Body::from(response.dump()))?; + let response = client.request(request).await?; + println!("Received finish status {}", response.status()); + + if response.status() == hyper::StatusCode::ACCEPTED { + println!("No pending rollup request, trying again"); + } else { + let body = hyper::body::to_bytes(response).await?; + let utf = std::str::from_utf8(&body)?; + let req = json::parse(utf)?; + + if let Some(address) = process_initial(&req["data"]["metadata"]) { + _rollup_address = address; + continue; + } + + let request_type = req["request_type"] + .as_str() + .ok_or("request_type is not a string")?; + status = match request_type { + "advance_state" => handle_advance(&client, &server_addr[..], req).await?, + "inspect_state" => handle_inspect(&client, &server_addr[..], req).await?, + &_ => { + eprintln!("Unknown request type"); + "reject" + } + }; + } + } +} From 6248be4943a3b3b63b6337b8d5b01afee7874513 Mon Sep 17 00:00:00 2001 From: andy-thomason Date: Sat, 8 Oct 2022 23:42:01 +0100 Subject: [PATCH 2/3] Replace example submission to colons. --- rust-mandelbrot-nft/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-mandelbrot-nft/src/main.rs b/rust-mandelbrot-nft/src/main.rs index ccba1220..7800b8c9 100644 --- a/rust-mandelbrot-nft/src/main.rs +++ b/rust-mandelbrot-nft/src/main.rs @@ -11,7 +11,8 @@ // specific language governing permissions and limitations under the License. -// yarn start input send --payload "(-0.1,0.9,4.0)" +// Example submission: +// yarn start input send --payload "(-0.1:0.9:4.0)" use json::{object, JsonValue}; From 456350a30fafb851598fc5f128806165041851fa Mon Sep 17 00:00:00 2001 From: andy-thomason Date: Sun, 9 Oct 2022 14:09:27 +0100 Subject: [PATCH 3/3] Add binary params --- rust-mandelbrot-nft/src/main.rs | 51 +++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/rust-mandelbrot-nft/src/main.rs b/rust-mandelbrot-nft/src/main.rs index 7800b8c9..04e11ace 100644 --- a/rust-mandelbrot-nft/src/main.rs +++ b/rust-mandelbrot-nft/src/main.rs @@ -30,6 +30,18 @@ fn from_hex(s: &str) -> String { }).collect::() } +fn from_hex_vec(s: &str) -> Vec { + assert!(s.starts_with("0x")); + + s[2..].as_bytes() + .chunks_exact(2) + .map(|c| { + let d0 = if c[0] > b'9' { c[0] + 9 } else { c[0] } & 0x0f; + let d1 = if c[1] > b'9' { c[1] + 9 } else { c[1] } & 0x0f; + d0 * 16 + d1 + }).collect::>() +} + fn to_hex(b: &[u8]) -> String { let mut res = String::with_capacity(b.len()*2+2); res.push_str("0x"); @@ -62,17 +74,38 @@ fn escape_time(cx: f64, cy: f64) -> u8 { fn gen_nft(params: &str) -> Vec { const SIZE : usize = 1024; + println!("params={}", params); - println!("gen_bft: params={}", params); - let params = params.strip_prefix("(").unwrap(); - let params = params.strip_suffix(")").unwrap(); - let mut it = params.split(":").map(|x| x.parse().unwrap()); + let (px, py, zoom, id) = if params.starts_with("0x28") { + // Command line: use text. + // Question: how do we send hex from the command line tool? + let params = from_hex(params); + println!("gen_bft: params={}", params); + let params = params.strip_prefix("(").unwrap(); + let params = params.strip_suffix(")").unwrap(); + let mut it = params.split(":").map(|x| x.parse().unwrap()); + + let px : f64 = it.next().unwrap(); + let py : f64 = it.next().unwrap(); + let zoom : f64 = it.next().unwrap(); + + (px, py, zoom, 0) + } else { + // In-chain: use binary. 4x256 bit fixed point integers. + let bytes = from_hex_vec(params); + let mut it = bytes + .chunks(32) + .map(|x| u64::from_be_bytes(x[24..32].try_into().unwrap())); + let px = it.next().unwrap() as f64 / 1000000.0; + let py = it.next().unwrap() as f64 / 1000000.0; + let zoom = it.next().unwrap() as f64 / 1000000.0; + let id = it.next().unwrap(); + (px, py, zoom, id) + }; - let px : f64 = it.next().unwrap(); - let py : f64 = it.next().unwrap(); - let zoom : f64 = 1.0 / it.next().unwrap() / (SIZE as f64) / 2.0; + println!("x,y,zoom,id={},{},{},{}", px, py, zoom, id); - println!("x,y,z={},{},{}", px, py, zoom); + let zoom : f64 = 1.0 / zoom / (SIZE as f64) / 2.0; let mut w = Vec::new(); { @@ -148,7 +181,7 @@ pub async fn handle_advance( println!("Adding notice"); - let res = gen_nft(&from_hex(&payload)); + let res = gen_nft(payload); let notice = object! {"payload" => to_hex(&res)};