Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/cartesapp separation #19

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
.sunodo
.venv
__pycache__
cartridges
cartridges
cache
data
frontend/app/contracts
!frontend/app/contracts/RivesScoreNFT.sol
9 changes: 7 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ WORKDIR /opt/tools
RUN <<EOF
apt-get update && \
apt-get install -y --no-install-recommends wget=1.21.2-2ubuntu1 ca-certificates=20230311ubuntu0.22.04.1 \
build-essential=12.9ubuntu3 sqlite3=3.37.2-2ubuntu0.3 git=1:2.34.1-1ubuntu1.10 squashfs-tools=1:4.5-3build1&& \
build-essential=12.9ubuntu3 sqlite3=3.37.2-2ubuntu0.3 git=1:2.34.1-1ubuntu1.10 squashfs-tools=1:4.5-3build1 \
libjpeg-dev=8c-2ubuntu10 zlib1g-dev=1:1.2.11.dfsg-2ubuntu9.2 libfreetype6-dev=2.11.1+dfsg-1ubuntu0.2 && \
wget -O machine-emulator-tools.deb https://github.com/cartesi/machine-emulator-tools/releases/download/v${MACHINE_EMULATOR_TOOLS_VERSION}/machine-emulator-tools-v${MACHINE_EMULATOR_TOOLS_VERSION}.deb && \
rm -rf /var/lib/apt/lists/*
EOF
Expand Down Expand Up @@ -74,12 +75,16 @@ RUN ln -s /rivos/usr/bin/bwrap /usr/bin/ && \
WORKDIR /opt/cartesi/dapp

COPY main.py .
COPY cartesapp cartesapp
COPY app app
COPY misc/Rives-Logo.png misc/Rives-Logo.png
COPY misc/snake.sqfs misc/snake.sqfs
COPY misc/2048.sqfs misc/2048.sqfs
COPY misc/freedoom.sqfs misc/freedoom.sqfs
COPY misc/antcopter.sqfs misc/antcopter.sqfs
COPY misc/monky.sqfs misc/monky.sqfs
COPY misc/test.rivlog misc/test.rivlog

COPY misc/font misc/font

FROM base as dapp

Expand Down
49 changes: 22 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ For now, this is not a final product and should not be used as one.
- [Sunodo](https://github.com/sunodo/sunodo) to build and run the DApp backend
- [Metamask](https://metamask.io/) to sign transactions in the frontend
- [json-schema-to-typescript](https://www.npmjs.com/package/json-schema-to-typescript) to generate typescript interfaces`npm install -g json-schema-to-typescript --save`
-[cartesi-client](https://github.com/prototyp3-dev/cartesi-client/), an interface to cartesi rollups framework
- [cartesi-client](https://github.com/prototyp3-dev/cartesi-client/), an interface to cartesi rollups framework

To build the DApp, two images are also required: `riv/toolchain` and `sunodo/sdk:0.2.0-riv`.

Expand All @@ -32,53 +32,48 @@ docker build --tag sunodo/sdk:0.2.0-riv . --target sunodo-riv --progress plain .

## Building

Build with:
Build backend with:

```shell
sunodo build
```

## Running

Run the DApp environment with:
You should also install the frontend dependencies. First install [cartesi client](https://github.com/prototyp3-dev/cartesi-client), then run:

```shell
sunodo run
cd frontend
yarn
npm link cartesi-client
```

## Generating frontend libs

Import cartesapp manager and add module

```python
from cartesapp.manager import Manager
m = Manager()
m.add_module('app')
```
## Running

To create (or merge) the frontend structure:
Run the DApp environment with:

```python
m.create_frontend()
```shell
sunodo run
```

To (re)generate frontend libs based on backend (on a specific path, default is `src`):
Then deploy the Rives Screenshot NFT contract (you should have already installed frontend dependencies)

```python
m.generate_frontend_lib("app/backend-libs")
```shell
cd frontend
MNEMONIC='test test test test test test test test test test test junk'
RPC_URL=http://127.0.0.1:8545
DAPP_ADDRESS=0x70ac08179605AF2D9e75782b8DEcDD3c22aA4D0C
BITMASK_ADDRESS=0xF5B2d8c81cDE4D6238bBf20D3D77DB37df13f735
forge create --constructor-args $DAPP_ADDRESS --rpc-url "$RPC_URL" --mnemonic "$MNEMONIC" --json contracts/RivesScoreNFT.sol:RivesScoreNFT --libraries node_modules/@cartesi/util/contracts/Bitmask.sol:Bitmask:$BITMASK_ADDRESS
```

Then install frontend dependencies:
Finally, run the frontend

```shell
cd frontend
yarn
yarn dev
```

Link cartesi client lib (in `./frontend`), redo this step every time you install or remeve a package:
You will be able to mint the NFTs once the epoch has finished, but you can increase the time of the local dev chain with

```shell
npm link cartesi-client
curl -H "Content-Type: application/json" -X POST --data '{"id":1337,"jsonrpc":"2.0","method":"evm_increaseTime","params":[864000]}' http://localhost:8545
```

Now you can use the generated libs on the frontend. Check examples in `./misc/dry-run.ts`
2 changes: 0 additions & 2 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@
from . import setup, cartridge, replay, scoreboard
# TODO: use settings file instead of init
101 changes: 67 additions & 34 deletions app/cartridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
from cartesi.abi import String, Bytes, Bytes32, UInt

from cartesapp.storage import Entity, helpers, seed
from cartesapp.manager import query, mutation, get_metadata, event, output, add_output, emit_event, contract_call
from cartesapp.context import get_metadata
from cartesapp.input import query, mutation
from cartesapp.output import event, output, add_output, emit_event, contract_call

from .riv import riv_get_cartridge_info, riv_get_cartridge_screenshot, riv_get_cartridges_path, riv_get_cover, riv_get_cartridge_outcard
from .setup import AppSettings
from .riv import riv_get_cartridge_info, riv_get_cartridge_screenshot, riv_get_cartridges_path, riv_get_cover, riv_get_cartridge_outcard, replay_log
from .settings import AppSettings

LOGGER = logging.getLogger(__name__)

Expand All @@ -26,36 +28,57 @@
class Cartridge(Entity):
id = helpers.PrimaryKey(str, 64)
name = helpers.Required(str, index=True, unique=True)
user_address = helpers.Required(str, 66)
user_address = helpers.Required(str, 42)
info = helpers.Optional(helpers.Json, lazy=True)
created_at = helpers.Required(int)
cover = helpers.Optional(bytes, lazy=True)

@seed()
def initialize_data():
cartridge_example_file = open('misc/snake.sqfs','rb')
cartridge_example_data = cartridge_example_file.read()
cartridge_example_file.close()
create_cartridge(cartridge_example_data,msg_sender="0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266")
if AppSettings.rivemu_path is None: os.remove('misc/snake.sqfs')

cartridge_example_file = open('misc/freedoom.sqfs','rb')
cartridge_example_data = cartridge_example_file.read()
cartridge_example_file.close()
create_cartridge(cartridge_example_data,msg_sender="0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266")
if AppSettings.rivemu_path is None: os.remove('misc/freedoom.sqfs')

cartridge_example_file = open('misc/antcopter.sqfs','rb')
cartridge_example_data = cartridge_example_file.read()
cartridge_example_file.close()
create_cartridge(cartridge_example_data,msg_sender="0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266")
if AppSettings.rivemu_path is None: os.remove('misc/antcopter.sqfs')

cartridge_example_file = open('misc/2048.sqfs','rb')
cartridge_example_data = cartridge_example_file.read()
cartridge_example_file.close()
create_cartridge(cartridge_example_data,msg_sender="0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266")
if AppSettings.rivemu_path is None: os.remove('misc/2048.sqfs')
try:
cartridge_example_file = open('misc/snake.sqfs','rb')
cartridge_example_data = cartridge_example_file.read()
cartridge_example_file.close()
create_cartridge(cartridge_example_data,msg_sender="0xAf1577F6A113da0bc671a59D247528811501cF94")
if AppSettings.rivemu_path is None: os.remove('misc/snake.sqfs')
except Exception as e:
LOGGER.warning(e)

try:
cartridge_example_file = open('misc/freedoom.sqfs','rb')
cartridge_example_data = cartridge_example_file.read()
cartridge_example_file.close()
create_cartridge(cartridge_example_data,msg_sender="0xAf1577F6A113da0bc671a59D247528811501cF94")
if AppSettings.rivemu_path is None: os.remove('misc/freedoom.sqfs')
except Exception as e:
LOGGER.warning(e)

try:
cartridge_example_file = open('misc/antcopter.sqfs','rb')
cartridge_example_data = cartridge_example_file.read()
cartridge_example_file.close()
create_cartridge(cartridge_example_data,msg_sender="0xAf1577F6A113da0bc671a59D247528811501cF94")
if AppSettings.rivemu_path is None: os.remove('misc/antcopter.sqfs')
except Exception as e:
LOGGER.warning(e)

try:
cartridge_example_file = open('misc/monky.sqfs','rb')
cartridge_example_data = cartridge_example_file.read()
cartridge_example_file.close()
create_cartridge(cartridge_example_data,msg_sender="0xAf1577F6A113da0bc671a59D247528811501cF94")
if AppSettings.rivemu_path is None: os.remove('misc/monky.sqfs')
except Exception as e:
LOGGER.warning(e)

# try:
# cartridge_example_file = open('misc/2048.sqfs','rb')
# cartridge_example_data = cartridge_example_file.read()
# cartridge_example_file.close()
# create_cartridge(cartridge_example_data,msg_sender="0xAf1577F6A113da0bc671a59D247528811501cF94")
# if AppSettings.rivemu_path is None: os.remove('misc/2048.sqfs')
# except Exception as e:
# LOGGER.warning(e)


# Inputs
Expand Down Expand Up @@ -190,8 +213,6 @@ def cartridge(payload: CartridgePayload) -> bool:
def cartridge_info(payload: CartridgePayload) -> bool:
cartridge = helpers.select(c for c in Cartridge if c.id == payload.id).first()

LOGGER.info(cartridge)

if cartridge is not None:
cartridge_dict = cartridge.to_dict(with_lazy=True)
cartridge_dict['cover'] = base64.b64encode(cartridge_dict['cover'])
Expand Down Expand Up @@ -255,7 +276,10 @@ def create_cartridge(cartridge_data,**metadata):
if helpers.count(c for c in Cartridge if c.id == data_hash) > 0:
raise Exception(f"Cartridge already exists")

cartridge_file = open(f"{riv_get_cartridges_path()}/{data_hash}",'wb')
cartridges_path = riv_get_cartridges_path()
if not os.path.exists(cartridges_path):
os.makedirs(cartridges_path)
cartridge_file = open(f"{cartridges_path}/{data_hash}",'wb')
cartridge_file.write(cartridge_data)
cartridge_file.close()

Expand All @@ -266,16 +290,25 @@ def create_cartridge(cartridge_data,**metadata):
Info(**cartridge_info_json)

# check if cartridge runs
riv_get_cartridge_outcard(data_hash,0,None,None)
test_replay_file = open('misc/test.rivlog','rb')
test_replay = test_replay_file.read()
test_replay_file.close()

# TODO: allow one of theses tests
outcard_raw, outhash, screenshot = replay_log(data_hash,test_replay,'',b'')
# riv_get_cartridge_outcard(data_hash,0,None,None)

cartridge_cover = riv_get_cover(data_hash)
if cartridge_cover is None or len(cartridge_cover) == 0:
cartridge_cover = riv_get_cartridge_screenshot(data_hash,0)
#cartridge_cover = riv_get_cartridge_screenshot(data_hash,0)
cartridge_cover = screenshot

user_address = metadata.get('msg_sender')
if user_address is not None: user_address = user_address.lower()
c = Cartridge(
id = data_hash,
name = cartridge_info_json['name'],
user_address = metadata.get('msg_sender'),
user_address = user_address,
created_at = metadata.get('timestamp') or 0,
info = cartridge_info_json,
cover = cartridge_cover
Expand All @@ -290,7 +323,7 @@ def delete_cartridge(cartridge_id,**metadata):
if cartridge is None:
raise Exception(f"Cartridge doesn't exist")

if cartridge.user_address != metadata['msg_sender']:
if cartridge.user_address != metadata['msg_sender'].lower():
raise Exception(f"Sender not allowed")

cartridge.delete()
Expand Down
Loading