Compare commits

...
30 Commits
Author SHA1 Message Date
nabarun bed5e262cc Add missing notes and steps in mobymask-v2 stack readme (#241)
* Add missing notes and steps in readme

* Mention clearing of browser cache before opening invite link

Former-commit-id: 1aeb44d5ad
2023-03-27 11:17:12 +05:30
dboreham 97da39c68b Update version
Former-commit-id: 3706dfd7db
2023-03-26 21:35:01 -06:00
dboreham e7c5d5157e Fix missing container name change
Former-commit-id: e70dca7687
2023-03-25 18:57:36 -06:00
dboreham 9adf48f6c8 Merge pull request #240 from cerc-io/dboreham/fix-act-container-names
Use dashes not underscore to match docker-compose file

Former-commit-id: 685ebdfb15
2023-03-25 18:27:38 -06:00
dboreham 16ff576413 Use dashes not underscore to match docker-compose file in hosting repo and convention
Former-commit-id: 022afdc352
2023-03-25 18:26:21 -06:00
dboreham f4e9837ed2 Merge pull request #238 from cerc-io/telackey/act_runner
Add Gitea action support via act_runner.

Former-commit-id: 7af7f654f6
2023-03-25 11:35:07 -06:00
dboreham 0eb890edaf Merge pull request #230 from cerc-io/dboreham/update-node-version
Update to Node 18

Former-commit-id: ece01730fd
2023-03-25 11:34:07 -06:00
telackey 788b214116 Add Gitea action support via act_runner.
Former-commit-id: 74077d7704
2023-03-24 22:24:40 -05:00
dboreham 8e056c1b0c Merge pull request #237 from cerc-io/dboreham/use-local-foundry
Use our locally built foundry container

Former-commit-id: b2cef16462
2023-03-24 18:27:48 -06:00
David Boreham 5767b93e6a Use our locally built foundry container
Former-commit-id: da24a4edf6
2023-03-24 18:23:35 -06:00
dboreham 38feddb266 Update version file
Former-commit-id: 07de83e6d7
2023-03-24 10:26:48 -06:00
Zach 862b75de1e Merge pull request #235 from cerc-io/zramsay-patch-1
doc jq requirement

Former-commit-id: 3d03b1099a
2023-03-24 08:57:38 -04:00
Zach af44d005c3 doc jq requirement
Former-commit-id: a5dd62e457
2023-03-24 08:56:01 -04:00
nabarunandprathamesh 1951a5d398 Add web-apps and laconicd in MobyMask v2 watcher stack (#226)
* Rename .env file

* Add web app services to docker compose file

* Add laconicd to deploy contract and send txs

* Add demo with steps for running mobymask app with L2 chain

* Add fix for yarn install on M1 platform in react-peer

* Update multiaddrs to use websockets

* Add notes in readmes

---------

Co-authored-by: prathamesh0 <prathamesh.musale0@gmail.com>
Former-commit-id: cacd306b22
2023-03-24 15:53:54 +04:00
dboreham 8a4f189286 Merge pull request #234 from cerc-io/dboreham/lirewine-builds
Add support for lirewine npm package build and consumption

Former-commit-id: ebe1dfa4bf
2023-03-24 02:54:21 -06:00
dboreham aa01feb98a Fix up script and npm list
Former-commit-id: e6b91acdea
2023-03-24 02:52:37 -06:00
dboreham c4e3aa54f1 Remove trailing whitespace
Former-commit-id: 2e7ef1e52e
2023-03-24 02:31:19 -06:00
dboreham 364a71d694 Support the @lirewine npm scope
Former-commit-id: 9e322203e9
2023-03-24 02:30:04 -06:00
dboreham d96a6def14 Add lirewine repos and npms
Former-commit-id: 870a987760
2023-03-24 02:08:56 -06:00
dboreham 1a75a270f5 Merge pull request #232 from cerc-io/dboreham/foundry-debian-container
Foundry debian-based container

Former-commit-id: 76029d24de
2023-03-23 17:46:42 -06:00
David Boreham 23fab04ec8 Fix filename
Former-commit-id: 06288fd9e1
2023-03-23 16:09:27 -06:00
David Boreham 4420f45924 Build foundry with Debian base container
Former-commit-id: 21e9f96771
2023-03-23 16:03:35 -06:00
David Boreham 653f4c7d0a Update to Node 18
Former-commit-id: 56ff7d210b
2023-03-23 14:04:31 -06:00
dboreham dac22b19b7 Update version
Former-commit-id: d5fd880bba
2023-03-22 21:35:48 -06:00
dboreham 08ed69e4cd Merge pull request #227 from cerc-io/dboreham/fix-fixturenet-laconicd
Update fixturenet create script

Former-commit-id: 5fca9bdac7
2023-03-22 15:01:59 -06:00
David Boreham 84bad13934 Update fixturenet create script
Former-commit-id: 01c6999027
2023-03-22 14:52:39 -06:00
dboreham c537d787c2 Update version
Former-commit-id: 91ba0ae011
2023-03-21 09:55:40 -06:00
Zach 538bccd19a Merge pull request #225 from cerc-io/dboreham/update-readme
Update README to reflect user experience and to use --stack

Former-commit-id: 8fb93758ee
2023-03-21 09:25:53 -04:00
David Boreham d5f5ecceda Update README to reflect user experience and to use --stack directive in examples
Former-commit-id: 2c151cb8ce
2023-03-20 19:36:05 -06:00
dboreham 39741b2e8f Add Gitea note
Former-commit-id: 74be51b892
2023-03-20 10:14:58 -06:00
38 changed files with 533 additions and 96 deletions
+17 -29
View File
@@ -8,11 +8,11 @@ Stack Orchestrator allows building and deployment of a Laconic Stack on a single
Ensure that the following are already installed:
- [Python3](https://wiki.python.org/moin/BeginnersGuide/Download): `python3 --version` >= `3.10.8`
- [Python3](https://wiki.python.org/moin/BeginnersGuide/Download): `python3 --version` >= `3.8.10` (the Python3 shipped in Ubuntu 20+ is good to go)
- [Docker](https://docs.docker.com/get-docker/): `docker --version` >= `20.10.21`
- [Docker Compose](https://docs.docker.com/compose/install/): `docker-compose --version` >= `2.13.0`
- [jq](https://stedolan.github.io/jq/download/): `jq --version` >= `1.5`
Note: if installing docker-compose via package manager (as opposed to Docker Desktop), you must [install the plugin](https://docs.docker.com/compose/install/linux/#install-the-plugin-manually), e.g., on Linux:
Note: if installing docker-compose via package manager on Linux (as opposed to Docker Desktop), you must [install the plugin](https://docs.docker.com/compose/install/linux/#install-the-plugin-manually), e.g. :
```bash
mkdir -p ~/.docker/cli-plugins
@@ -20,39 +20,27 @@ curl -SL https://github.com/docker/compose/releases/download/v2.11.2/docker-comp
chmod +x ~/.docker/cli-plugins/docker-compose
```
Next, download the latest release from [this page](https://github.com/cerc-io/stack-orchestrator/tags), into a suitable directory (e.g. `~/bin`):
Next decide on a directory where you would like to put the stack-orchestrator program. Typically this would be
a "user" binary directory such as `~/bin` or perhaps `/usr/local/laconic` or possibly just the current working directory.
Now, having selected that directory, download the latest release from [this page](https://github.com/cerc-io/stack-orchestrator/tags) into it (we're using `~/bin` below for concreteness but edit to suit if you selected a different directory). Also be sure that the destination directory exists and is writable:
```bash
curl -L -o ~/bin/laconic-so https://github.com/cerc-io/stack-orchestrator/releases/latest/download/laconic-so
```
Give it permissions:
Give it execute permissions:
```bash
chmod +x ~/bin/laconic-so
```
Ensure `laconic-so` is on the [`PATH`](https://unix.stackexchange.com/a/26059)
Verify operation:
Verify operation (your version will probably be different, just check here that you see some version outut and not an error):
```
laconic-so --help
Usage: python -m laconic-so [OPTIONS] COMMAND [ARGS]...
Laconic Stack Orchestrator
Options:
--quiet
--verbose
--dry-run
--local-stack
-h, --help Show this message and exit.
Commands:
build-containers build the set of containers required for a complete...
build-npms build the set of npm packages required for a...
deploy-system deploy a stack
setup-repositories git clone the set of repositories required to build...
laconic-so version
Version: v1.0.27-7831078
```
## Usage
@@ -64,25 +52,25 @@ Three sub-commands: `setup-repositories`, `build-containers` and `deploy-system`
Clone the set of git repositories necessary to build a system:
```bash
laconic-so --verbose setup-repositories --include cerc-io/go-ethereum,cerc-io/ipld-eth-db,cerc-io/ipld-eth-server,cerc-io/watcher-ts
laconic-so --stack erc20 setup-repositories
```
This will default to `~/cerc` or - if set - the environment variable `CERC_REPO_BASE_DIR`
This will default to cloning git reposiories into: `~/cerc` or - if set - the environment variable `CERC_REPO_BASE_DIR`
### Build Containers
Build the set of docker container images required to run a system. It takes around 10 minutes to build all the containers from scratch.
```bash
laconic-so --verbose build-containers --include cerc/go-ethereum,cerc/go-ethereum-foundry,cerc/ipld-eth-db,cerc/ipld-eth-server,cerc/watcher-erc20
laconic-so --stack erc20 build-containers
```
### Deploy System
Uses `docker-compose` to deploy a system (with most recently built container images).
Uses `docker compose` to deploy a system (with most recently built container images).
```bash
laconic-so --verbose deploy-system --include ipld-eth-db,go-ethereum-foundry,ipld-eth-server,watcher-erc20 up
laconic-so --stack erc20 deploy-system up
```
Check out he GraphQL playground here: [http://localhost:3002/graphql](http://localhost:3002/graphql)
@@ -92,7 +80,7 @@ See the [erc20 watcher demo](/app/data/stacks/erc20) to continue further.
### Cleanup
```bash
laconic-so --verbose deploy-system --include ipld-eth-db,go-ethereum-foundry,ipld-eth-server,watcher-erc20 down
laconic-so --stack erc20 deploy-system down
```
## Contributing
@@ -0,0 +1,25 @@
version: "3.2"
services:
laconicd:
restart: unless-stopped
image: cerc/laconicd:local
command: ["sh", "/docker-entrypoint-scripts.d/create-fixturenet.sh"]
volumes:
- ../config/fixturenet-laconicd/create-fixturenet.sh:/docker-entrypoint-scripts.d/create-fixturenet.sh
ports:
- "9473"
- "8545"
- "8546"
- "1317"
healthcheck:
test: ["CMD", "nc", "-v", "localhost", "8545"]
interval: 20s
timeout: 5s
retries: 15
start_period: 10s
networks:
# https://docs.docker.com/compose/networking/#configure-the-default-network
default:
name: mobymask-v2-network
@@ -21,6 +21,26 @@ services:
retries: 15
start_period: 10s
mobymask:
restart: unless-stopped
depends_on:
mobymask-watcher-db:
condition: service_healthy
image: cerc/mobymask:local
working_dir: /app/packages/server
environment:
- ENV=PROD
command: ["sh", "-c", "npm start"]
volumes:
- ../config/watcher-mobymask-v2/secrets.json:/app/packages/server/secrets.json
- moby_data_server:/app/packages/server
healthcheck:
test: ["CMD", "nc", "-v", "localhost", "3330"]
interval: 20s
timeout: 5s
retries: 15
start_period: 10s
mobymask-watcher-server:
restart: unless-stopped
depends_on:
@@ -30,18 +50,81 @@ services:
command: ["sh", "-c", "yarn server"]
volumes:
- ../config/watcher-mobymask-v2/watcher.toml:/app/packages/mobymask-v2-watcher/environments/local.toml
- ../config/watcher-mobymask-v2/.env:/app/packages/peer/.env
- ../config/watcher-mobymask-v2/peer.env:/app/packages/peer/.env
- ../config/watcher-mobymask-v2/relay-id.json:/app/packages/mobymask-v2-watcher/relay-id.json
ports:
- "0.0.0.0:3001:3001"
- "0.0.0.0:9001:9001"
- "0.0.0.0:9090:9090"
healthcheck:
test: ["CMD", "nc", "-v", "localhost", "9090"]
test: ["CMD", "busybox", "nc", "localhost", "9090"]
interval: 20s
timeout: 5s
retries: 15
start_period: 5s
mobymask-watcher-peer:
restart: unless-stopped
depends_on:
mobymask:
condition: service_healthy
image: cerc/watcher-mobymask-v2:local
command: ["sh", "peer-start.sh"]
volumes:
- ../config/watcher-mobymask-v2/watcher.toml:/app/packages/mobymask-v2-watcher/environments/local.toml
- ../config/watcher-mobymask-v2/peer-id.json:/app/packages/mobymask-v2-watcher/peer-id.json
- ../config/watcher-mobymask-v2/peer-start.sh:/app/packages/mobymask-v2-watcher/peer-start.sh
- moby_data_server:/server
mobymask-app:
depends_on:
mobymask-watcher-server:
condition: service_healthy
mobymask:
condition: service_healthy
image: cerc/mobymask-ui:local
command: ["sh", "mobymask-app-start.sh"]
volumes:
- ../config/watcher-mobymask-v2/mobymask-app.env:/app/.env
- ../config/watcher-mobymask-v2/mobymask-app-config.json:/app/src/mobymask-app-config.json
- ../config/watcher-mobymask-v2/mobymask-app-start.sh:/app/mobymask-app-start.sh
- moby_data_server:/server
ports:
- "0.0.0.0:3002:3000"
healthcheck:
test: ["CMD", "nc", "-v", "localhost", "3000"]
interval: 20s
timeout: 5s
retries: 15
start_period: 10s
shm_size: '1GB'
peer-test-app:
depends_on:
mobymask-watcher-server:
condition: service_healthy
image: cerc/react-peer:local
working_dir: /app/packages/test-app
command: ["sh", "-c", "yarn build && serve -s build"]
volumes:
- ../config/watcher-mobymask-v2/test-app-config.json:/app/packages/test-app/src/config.json
ports:
- "0.0.0.0:3003:3000"
healthcheck:
test: ["CMD", "nc", "-v", "localhost", "3000"]
interval: 20s
timeout: 5s
retries: 15
start_period: 10s
volumes:
mobymask_watcher_db_data:
moby_data_server:
networks:
# https://docs.docker.com/compose/networking/#configure-the-default-network
default:
# https://docs.docker.com/compose/networking/#use-a-pre-existing-network
name: mobymask-v2-network
external: true
@@ -1,8 +1,8 @@
#!/bin/sh
# Originally from: https://github.com/cerc-io/laconicd/blob/main/init.sh
# TODO: fold this back into the laconicd repo
#!/bin/bash
# TODO: this file is now an unmodified copy of cerc-io/laconicd/init.sh
# so we should have a mechanism to bundle it inside the container rather than link from here
# at deploy time.
KEY="mykey"
CHAINID="laconic_9000-1"
@@ -10,7 +10,7 @@ MONIKER="localtestnet"
KEYRING="test"
KEYALGO="eth_secp256k1"
LOGLEVEL="info"
# to trace evm
# trace evm
TRACE="--trace"
# TRACE=""
@@ -28,7 +28,7 @@ laconicd config chain-id $CHAINID
# if $KEY exists it should be deleted
laconicd keys add $KEY --keyring-backend $KEYRING --algo $KEYALGO
# Set moniker and chain-id for laconic (Moniker can be anything, chain-id must be an integer)
# Set moniker and chain-id for Ethermint (Moniker can be anything, chain-id must be an integer)
laconicd init $MONIKER --chain-id $CHAINID
# Change parameter token denominations to aphoton
@@ -37,28 +37,28 @@ cat $HOME/.laconicd/config/genesis.json | jq '.app_state["crisis"]["constant_fee
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
# Custom modules
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["nameservice"]["params"]["record_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_auction_commit_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_auction_reveal_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_auction_minimum_bid"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["record_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_commit_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_reveal_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_minimum_bid"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
if [[ "$TEST_NAMESERVICE_EXPIRY" == "true" ]]; then
if [[ "$TEST_REGISTRY_EXPIRY" == "true" ]]; then
echo "Setting timers for expiry tests."
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["nameservice"]["params"]["record_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_grace_period"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["record_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_grace_period"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
fi
if [[ "$TEST_AUCTION_ENABLED" == "true" ]]; then
echo "Enabling auction and setting timers."
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_auction_enabled"]=true' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_grace_period"]="300s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_auction_commits_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_auction_reveals_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_enabled"]=true' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_grace_period"]="300s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_commits_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_reveals_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
fi
# increase block time (?)
-1
View File
@@ -1 +0,0 @@
RELAY="/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/12D3KooWSPCsVkHVyLQoCqhu2YRPvvM7o6r6NRYyLM5zeA6Uig5t"
@@ -1,8 +0,0 @@
{
"relayNodes": [
"/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/12D3KooWSPCsVkHVyLQoCqhu2YRPvvM7o6r6NRYyLM5zeA6Uig5t"
],
"peer": {
"enableDebugInfo": true
}
}
@@ -0,0 +1,8 @@
{
"relayNodes": [
"/ip4/127.0.0.1/tcp/9090/ws/p2p/12D3KooWSPCsVkHVyLQoCqhu2YRPvvM7o6r6NRYyLM5zeA6Uig5t"
],
"peer": {
"enableDebugInfo": true
}
}
@@ -0,0 +1,9 @@
#!/bin/sh
set -e
# Merging config files to get deployed contract address
jq -s '.[0] * .[1]' /app/src/mobymask-app-config.json /server/config.json > /app/src/config.json
npm run build
serve -s build
@@ -0,0 +1 @@
REACT_APP_WATCHER_URI=http://localhost:3001/graphql
@@ -0,0 +1,5 @@
{
"id": "12D3KooWK6myjc8r1KBnfP9igp31qJkPaVfsKDjKrjoSefV5SDEo",
"privKey": "CAESQJMHbMaH+UEOtjGOzXYtoPO/cdHakCtN1hcnknIWzx/6ie1lxb+8kfzBjwt7apfj8fHlTCYSIVK8Q2AWu9a2h3g=",
"pubKey": "CAESIIntZcW/vJH8wY8Le2qX4/Hx5UwmEiFSvENgFrvWtod4"
}
+10
View File
@@ -0,0 +1,10 @@
#!/bin/sh
# Private key of account with balance
PRIVATE_KEY=
# Assign deployed contract address from server config
CONTRACT_ADDRESS=`jq '.address' /server/config.json`
echo 'yarn peer-listener --contract-address <CONTRACT_ADDRESS> --private-key <PRIVATE_KEY>'
yarn peer-listener --contract-address $CONTRACT_ADDRESS --private-key $PRIVATE_KEY
@@ -0,0 +1 @@
RELAY="/ip4/127.0.0.1/tcp/9090/ws/p2p/12D3KooWSPCsVkHVyLQoCqhu2YRPvvM7o6r6NRYyLM5zeA6Uig5t"
@@ -0,0 +1,5 @@
{
"rpcUrl": "http://laconicd:8545",
"privateKey": "GENESIS_ACCOUNT_PRIVATE_KEY",
"baseURI": "http://127.0.0.1:3002/#"
}
@@ -0,0 +1,8 @@
{
"relayNodes": [
"/ip4/127.0.0.1/tcp/9090/ws/p2p/12D3KooWSPCsVkHVyLQoCqhu2YRPvvM7o6r6NRYyLM5zeA6Uig5t"
],
"peer": {
"enableDebugInfo": true
}
}
@@ -31,7 +31,7 @@
enableDebugInfo = true
[server.p2p.peer]
relayMultiaddr = '/ip4/mobymask-watcher-server/tcp/9090/http/p2p-webrtc-direct/p2p/12D3KooWSPCsVkHVyLQoCqhu2YRPvvM7o6r6NRYyLM5zeA6Uig5t'
relayMultiaddr = '/dns4/mobymask-watcher-server/tcp/9090/ws/p2p/12D3KooWSPCsVkHVyLQoCqhu2YRPvvM7o6r6NRYyLM5zeA6Uig5t'
pubSubTopic = 'mobymask'
peerIdFile = './peer-id.json'
enableDebugInfo = true
@@ -55,7 +55,7 @@
[upstream]
[upstream.ethServer]
gqlApiEndpoint = "http://ipld-eth-server:8083/graphql"
rpcProviderEndpoint = "http://ipld-eth-server:8082"
rpcProviderEndpoint = "http://laconicd:8545"
blockDelayInMilliSecs = 60000
[upstream.cache]
@@ -0,0 +1,3 @@
#!/usr/bin/env bash
# Build a local version of the task executor for act-runner
docker build -t cerc/act-runner-task-executor:local -f ${CERC_REPO_BASE_DIR}/act_runner/Dockerfile.task-executor ${CERC_REPO_BASE_DIR}/act_runner
+3
View File
@@ -0,0 +1,3 @@
#!/usr/bin/env bash
# Build a local version of the act-runner image
docker build -t cerc/act-runner:local -f ${CERC_REPO_BASE_DIR}/act_runner/Dockerfile ${CERC_REPO_BASE_DIR}/act_runner
@@ -1,7 +1,7 @@
# Originally from: https://github.com/devcontainers/images/blob/main/src/javascript-node/.devcontainer/Dockerfile
# Which depends on: https://github.com/nodejs/docker-node/blob/main/Dockerfile-debian.template
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
ARG VARIANT=16-bullseye
ARG VARIANT=18-bullseye
FROM node:${VARIANT}
# Set these args to change the uid/gid for the base container's "node" user to match that of the host user (so bind mounts work as expected).
@@ -1,7 +1,7 @@
#!/bin/bash
# Usage: build-npm-package-local-dependencies.sh <registry-url> <publish-with-this-version>
# Runs build-npm-package.sh after first fixing up yarn.lock to use a local
# npm registry for all packages in a spcific scope (currently @cerc-io)
# npm registry for all packages in a spcific scope (currently @cerc-io and @lirewine)
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
@@ -17,18 +17,21 @@ fi
set -e
local_npm_registry_url=$1
package_publish_version=$2
# TODO: make this a paramater and allow a list of scopes
npm_scope_for_local="@cerc-io"
# We need to configure the local registry
npm config set ${npm_scope_for_local}:registry ${local_npm_registry_url}
npm config set -- ${local_npm_registry_url}:_authToken ${CERC_NPM_AUTH_TOKEN}
# Find the set of dependencies from the specified scope
mapfile -t dependencies_from_scope < <(cat package.json | jq -r '.dependencies | with_entries(if (.key|test("^'${npm_scope_for_local}'/.*$")) then ( {key: .key, value: .value } ) else empty end ) | keys[]')
echo "Fixing up dependencies"
for package in "${dependencies_from_scope[@]}"
# If we need to handle an additional scope, add it to the list below:
npm_scopes_to_handle=("@cerc-io" "@lirewine")
for npm_scope_for_local in ${npm_scopes_to_handle[@]}
do
echo "Fixing up package ${package}"
yarn-local-registry-fixup.sh $package ${local_npm_registry_url}
# We need to configure the local registry
npm config set ${npm_scope_for_local}:registry ${local_npm_registry_url}
npm config set -- ${local_npm_registry_url}:_authToken ${CERC_NPM_AUTH_TOKEN}
# Find the set of dependencies from the specified scope
mapfile -t dependencies_from_scope < <(cat package.json | jq -r '.dependencies | with_entries(if (.key|test("^'${npm_scope_for_local}'/.*$")) then ( {key: .key, value: .value } ) else empty end ) | keys[]')
echo "Fixing up dependencies in scope ${npm_scope_for_local}"
for package in "${dependencies_from_scope[@]}"
do
echo "Fixing up package ${package}"
yarn-local-registry-fixup.sh $package ${local_npm_registry_url}
done
done
echo "Running build"
build-npm-package.sh ${local_npm_registry_url} ${package_publish_version}
@@ -22,8 +22,8 @@ set -e
# Get the name of this package from package.json since we weren't passed that
package_name=$( cat package.json | jq -r .name )
local_npm_registry_url=$1
npm config set @lirewine:registry ${local_npm_registry_url}
npm config set @cerc-io:registry ${local_npm_registry_url}
npm config set @lirewine:registry ${local_npm_registry_url}
npm config set -- ${local_npm_registry_url}:_authToken ${CERC_NPM_AUTH_TOKEN}
# First check if the version of this package we're trying to build already exists in the registry
package_exists=$( yarn info --json ${package_name}@${package_publish_version} 2>/dev/null | jq -r .data.dist.tarball )
@@ -1,3 +1,3 @@
#!/usr/bin/env bash
# Build a local version of the foundry-rs/foundry image
docker build -t cerc/foundry:local ${CERC_REPO_BASE_DIR}/foundry
docker build -t cerc/foundry:local -f ${CERC_REPO_BASE_DIR}/foundry/Dockerfile-debian ${CERC_REPO_BASE_DIR}/foundry
@@ -1,4 +1,4 @@
FROM ghcr.io/foundry-rs/foundry
FROM cerc/foundry:local
RUN apk update ; apk add --no-cache --allow-untrusted ca-certificates curl bash git jq
RUN apk add --no-cache --upgrade grep
@@ -1,6 +1,6 @@
# Originally from: https://github.com/devcontainers/images/blob/main/src/javascript-node/.devcontainer/Dockerfile
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
ARG VARIANT=16-bullseye
ARG VARIANT=18-bullseye
FROM node:${VARIANT}
ARG USERNAME=node
@@ -40,8 +40,7 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# RUN su node -c "npm install -g <your-package-list-here>"
# Configure the local npm registry
RUN npm config set @lirewine:registry ${CERC_NPM_URL} \
&& npm config set @cerc-io:registry ${CERC_NPM_URL} \
RUN npm config set @cerc-io:registry ${CERC_NPM_URL} \
&& npm config set @lirewine:registry ${CERC_NPM_URL} \
&& npm config set -- ${CERC_NPM_URL}:_authToken ${CERC_NPM_AUTH_TOKEN}
@@ -1,11 +1,13 @@
FROM node:18.15.0-alpine3.16
RUN apk --update --no-cache add make git
RUN apk --update --no-cache add make git jq
WORKDIR /app
COPY . .
RUN npm install -g serve
RUN echo "Building mobymask-ui" && \
npm install
@@ -0,0 +1,13 @@
FROM node:16.17.1-alpine3.16
RUN apk --update --no-cache add python3 alpine-sdk
WORKDIR /app
COPY . .
RUN yarn
# Add scripts
RUN mkdir /scripts
ENV PATH="${PATH}:/scripts"
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
# Build cerc/mobymask
# See: https://stackoverflow.com/a/246128/1701505
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
docker build -t cerc/mobymask:local -f ${SCRIPT_DIR}/Dockerfile ${CERC_REPO_BASE_DIR}/MobyMask
@@ -1,12 +1,14 @@
FROM node:18.15.0-alpine3.16
RUN apk --update --no-cache add make git
RUN apk --update --no-cache add make git python3
WORKDIR /app
COPY . .
RUN yarn global add serve
RUN echo "Building react-peer" && \
yarn && yarn workspace @cerc-io/react-peer build
yarn install --ignore-scripts && yarn build --ignore @cerc-io/test-app
WORKDIR /app
@@ -4,7 +4,7 @@ RUN apt-get update \
&& apt-get install -y curl gnupg build-essential \
&& curl --silent --location https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get update \
&& apt-get install -y nodejs git \
&& apt-get install -y nodejs git busybox jq \
&& node -v
RUN corepack enable \
+3
View File
@@ -21,9 +21,12 @@ cerc/uniswap-v3-info
cerc/watcher-mobymask-v2
cerc/react-peer
cerc/mobymask-ui
cerc/mobymask
cerc/test-container
cerc/eth-probe
cerc/builder-js
cerc/keycloak
cerc/tx-spammer
cerc/builder-gerbil
cerc/act-runner
cerc/act-runner-task-executor
+3 -2
View File
@@ -1,4 +1,5 @@
gem
laconic-sdk
debug
laconic-registry-cli
gem
debug
crypto
+1
View File
@@ -15,6 +15,7 @@ watcher-erc20
watcher-erc721
watcher-uniswap-v3
watcher-mobymask-v2
mobymask-laconicd
test
eth-probe
keycloak
+5
View File
@@ -13,9 +13,14 @@ cerc-io/mobymask-watcher
cerc-io/watcher-ts
cerc-io/react-peer
cerc-io/mobymask-ui
cerc-io/MobyMask
vulcanize/uniswap-watcher-ts
vulcanize/uniswap-v3-info
vulcanize/assemblyscript
cerc-io/eth-probe
cerc-io/tx-spammer
dboreham/foundry
lirewine/gem
lirewine/debug
lirewine/crypto
telackey/act_runner
+1
View File
@@ -48,6 +48,7 @@ PING gitea.local (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.147 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.033 ms
```
Although not necessary in order to build and publish packages, you can now access the Gitea web interface at: [http://gitea.local:3000](http://gitea.local:3000) using these credentials: gitea_admin/admin1234 (Note: please properly secure Gitea if public internet access is allowed).
Now npm packages can be built:
### Build npm Packages
+126 -8
View File
@@ -10,6 +10,33 @@ Clone required repositories:
laconic-so --stack mobymask-v2 setup-repositories
```
NOTE: If repositories already exist and are checked out to different versions, `setup-repositories` command will throw an error.
For getting around this, the repositories mentioned below can be removed and then run the command.
Checkout to the required versions and branches in repos
```bash
# watcher-ts
cd ~/cerc/watcher-ts
git checkout v0.2.31
# react-peer
cd ~/cerc/react-peer
git checkout v0.2.29
# mobymask-ui
cd ~/cerc/mobymask-ui
git checkout laconic
# laconicd
cd ~/cerc/laconicd
git checkout v0.8.0
# MobyMask
cd ~/cerc/MobyMask
git checkout v0.1.1
```
Build the container images:
```bash
@@ -20,25 +47,75 @@ This should create the required docker images in the local image registry.
Deploy the stack:
```bash
laconic-so --stack mobymask-v2 deploy-system up
```
* Deploy the laconic chain
```bash
laconic-so --stack mobymask-v2 deploy-system --include mobymask-laconicd up
```
* Check that laconic chain status is healthy
```bash
docker ps
```
* Export the private key from laconicd
```bash
laconic-so --stack mobymask-v2 deploy-system --include mobymask-laconicd exec laconicd "echo y | laconicd keys export mykey --unarmored-hex --unsafe"
```
* Set the private key in [secrets.json](../../config/watcher-mobymask-v2/secrets.json) file that will be used by mobymask container to deploy contract
* Create a new account
```bash
laconic-so --stack mobymask-v2 deploy-system --include mobymask-laconicd exec laconicd "laconicd keys add alice"
```
* Transfer balance to new account
```bash
laconic-so --stack mobymask-v2 deploy-system --include mobymask-laconicd exec laconicd 'laconicd tx bank send $(laconicd keys show mykey -a) $(laconicd keys show alice -a) 1000000000000000000000000aphoton --fees 2000aphoton'
```
* Export the private key of new account from laconicd
```bash
laconic-so --stack mobymask-v2 deploy-system --include mobymask-laconicd exec laconicd "echo y | laconicd keys export alice --unarmored-hex --unsafe"
```
* Set the private key (`PRIVATE_KEY`) in [peer-start.sh](../../config/watcher-mobymask-v2/peer-start.sh) file that will be used to start the peer that sends txs to L2 chain
* Deploy the other containers
```bash
laconic-so --stack mobymask-v2 deploy-system --include watcher-mobymask-v2 up
```
* Check that all containers are healthy using `docker ps`
NOTE: The `mobymask-ui` container might not start. If mobymask-app is not running at http://localhost:3002, run command again to start the container
```bash
laconic-so --stack mobymask-v2 deploy-system --include watcher-mobymask-v2 up
```
## Tests
Find the watcher container's id:
```bash
docker ps | grep "cerc/watcher-mobymask-v2:local"
laconic-so --stack mobymask-v2 deploy-system --include watcher-mobymask-v2 ps | grep "mobymask-watcher-server"
```
Example output
```
8b38e9a64d7e cerc/watcher-mobymask-v2:local "sh -c 'yarn server'" 35 seconds ago Up 14 seconds (health: starting) 0.0.0.0:3001->3001/tcp, 0.0.0.0:9001->9001/tcp, 0.0.0.0:9090->9090/tcp laconic-aeb84676de2b0a7671ae90d537fc7d26-mobymask-watcher-server-1
id: 5d3aae4b22039fcd1c9b18feeb91318ede1100581e75bb5ac54f9e436066b02c, name: laconic-bfb01caf98b1b8f7c8db4d33f11b905a-mobymask-watcher-server-1, ports: 0.0.0.0:3001->3001/tcp, 0.0.0.0:9001->9001/tcp, 0.0.0.0:9090->9090/tcp
```
In above output the container ID is `8b38e9a64d7e`
In above output the container ID is `5d3aae4b22039fcd1c9b18feeb91318ede1100581e75bb5ac54f9e436066b02c`
Export it for later use:
@@ -52,10 +129,51 @@ Run the peer tests:
docker exec -w /app/packages/peer $CONTAINER_ID yarn test
```
## Web Apps
Check that the status for web-app containers are healthy by using `docker ps`
### mobymask-app
The mobymask-app should be running at http://localhost:3002
### peer-test-app
The peer-test-app should be running at http://localhost:3003
## Details
* The relay node for p2p network is running at http://localhost:9090
* The [peer package](https://github.com/cerc-io/watcher-ts/tree/main/packages/peer) (published in [gitea](https://git.vdb.to/cerc-io/-/packages/npm/@cerc-io%2Fpeer)) can be used in client code for connecting to the network
* The [react-peer package](https://github.com/cerc-io/react-peer/tree/main/packages/react-peer) (published in [gitea](https://git.vdb.to/cerc-io/-/packages/npm/@cerc-io%2Freact-peer)) which uses the peer package can be used in react app for connecting to the network
## Demo
Follow the [demo](./demo.md) to try out the MobyMask app with L2 chain
## Clean up
To stop all the services running in background run:
Stop all the services running in background run:
```bash
laconic-so --stack mobymask-v2 deploy-system down
laconic-so --stack mobymask-v2 deploy-system --include watcher-mobymask-v2 down
laconic-so --stack mobymask-v2 deploy-system --include mobymask-laconicd down
```
Clear volumes:
* List all volumes
```bash
docker volume ls
```
* Remove volumes created by this stack
Example:
```bash
docker volume rm laconic-bfb01caf98b1b8f7c8db4d33f11b905a_moby_data_server
```
+132
View File
@@ -0,0 +1,132 @@
# Demo
* Get the root invite link URL for mobymask-app
```
laconic-so --stack mobymask-v2 deploy-system --include watcher-mobymask-v2 logs mobymask
```
The invite link is seen at the end of the logs
Example:
```
laconic-bfb01caf98b1b8f7c8db4d33f11b905a-mobymask-1 | http://127.0.0.1:3002/#/members?invitation=%7B%22v%22%3A1%2C%22signedDelegations%22%3A%5B%7B%22signature%22%3A%220x7559bd412f02677d60820e38243acf61547f79339395a34f7d4e1630e645aeb30535fc219f79b6fbd3af0ce3bd05132ad46d2b274a9fbc4c36bc71edd09850891b%22%2C%22delegation%22%3A%7B%22delegate%22%3A%220xc0838c92B2b71756E0eAD5B3C1e1F186baeEAAac%22%2C%22authority%22%3A%220x0000000000000000000000000000000000000000000000000000000000000000%22%2C%22caveats%22%3A%5B%7B%22enforcer%22%3A%220x558024C7d593B840E1BfD83E9B287a5CDad4db15%22%2C%22terms%22%3A%220x0000000000000000000000000000000000000000000000000000000000000000%22%7D%5D%7D%7D%5D%2C%22key%22%3A%220x98da9805821f1802196443e578fd32af567bababa0a249c07c82df01ecaa7d8d%22%7D
```
* Open the invite link in browser to use the mobymask-app.
NOTE: Before opening the invite link, clear the browser cache (local storage) for http://127.0.0.1:3002 to remove old invitations
* In the debug panel, check if it is connected to the p2p network (It should be connected to atleast one other peer for pubsub to work).
* Create an invite link in the app by clicking on `Create new invite link` button.
* Switch to the `MESSAGES` tab in debug panel for viewing incoming messages later.
* Open the invite link in a new browser with different profile (to simulate remote browser)
* Check that it is connected to any other peer in the network.
* In `Report a phishing attempt` section, report multiple phishers using the `submit` button. Click on the `Submit batch to p2p network` button. This broadcasts signed invocations to the connected peers.
* In the `MESSAGES` tab of other browsers, a message can be seen with the signed invocations.
* In a terminal check logs from the watcher peer container.
* Get the container id
```bash
laconic-so --stack mobymask-v2 deploy-system --include watcher-mobymask-v2 ps | grep mobymask-watcher-peer
```
* Check logs
```bash
docker logs -f CONTAINER_ID
```
* It should have received the message, sent transaction to L2 chain and received a transaction receipt with block details.
Example log:
```
2023-03-23T10:25:19.771Z vulcanize:peer-listener [10:25:19] Received a message on mobymask P2P network from peer: PeerId(12D3KooWAVNswtcrX12iDYukEoxdQwD34kJyRWcQTfZ4unGg2xjd)
2023-03-23T10:25:24.143Z laconic:libp2p-utils Transaction receipt for invoke message {
to: '0x558024C7d593B840E1BfD83E9B287a5CDad4db15',
blockNumber: 1996,
blockHash: '0xebef19c21269654804b2ef2d4bb5cb6c88743b37ed77e82222dc5671debf3afb',
transactionHash: '0xf8c5a093a93f793012196073a7d0cb3ed6fbd2846126c066cb31c72100960cb1',
effectiveGasPrice: '1500000007',
gasUsed: '250000'
}
```
* Check the phisher in watcher GQL: http://localhost:3001/graphql
* Use the blockHash from transaction receipt details or query for latest block
```gql
query {
latestBlock {
hash
number
}
}
```
* Get the deployed contract address
```bash
laconic-so --stack mobymask-v2 deploy-system --include watcher-mobymask-v2 exec mobymask-app "cat src/config.json"
```
The value of `address` field is the deployed contract address
* Check for phisher value
```gql
query {
isPhisher(
blockHash: "TX_OR_LATEST_BLOCK_HASH",
contractAddress: "CONTRACT_ADDRESS",
# If reported phisher name was "test" then key0 value is "TWT:test"
key0: "TWT:PHISHER_NAME"
) {
value
}
}
```
It should return true for reported phisher names.
* Watcher internally is using L2 chain `eth_getStorageAt` method.
* Check the phisher name in mobymask app in `Check Phisher Status` section.
* Watcher GQL API is used for checking phisher.
* Manage the invitations by clicking on the `Outstanding Invitations in p2p network`.
* Revoke the created invitation by clicking on `Revoke (p2p network)`
* Revocation messages can be seen in the debug panel `MESSAGES` tab of other browsers.
* Check the watcher peer logs. It should receive a message and log the transaction receipt for revoke message.
* Try reporting a phisher from the revoked invitee's browser.
* The invocation message for reporting phisher would be broadcasted to all peers.
* Check the watcher peer logs. A transaction failed error should be logged.
* Check the reported phisher in [watcher GQL](https://localhost:3001/graphql)
```gql
query {
isPhisher(
blockHash: "LATEST_BLOCK_HASH",
contractAddress: "CONTRACT_ADDRESS",
key0: "TWT:PHISHER_NAME"
) {
value
}
}
```
It should return false as the invitation/delegation used for reporting phishers has been revoked.
+6
View File
@@ -4,8 +4,14 @@ repos:
- cerc-io/watcher-ts
- cerc-io/react-peer
- cerc-io/mobymask-ui
- cerc-io/laconicd
- cerc-io/MobyMask
containers:
- cerc/watcher-mobymask-v2
- cerc/react-peer
- cerc/mobymask-ui
- cerc/laconicd
- cerc/mobymask
pods:
- mobymask-laconicd
- watcher-mobymask-v2
@@ -3,6 +3,10 @@ name: package-registry
decription: "Local Package Registry"
repos:
- cerc-io/hosting
- telackey/act_runner
containers:
- cerc/act-runner
- cerc/act-runner-task-executor
pods:
- name: gitea
repository: cerc-io/hosting
+1 -1
View File
@@ -1,2 +1,2 @@
# This file should be re-generated running: scripts/update-version-file.sh script
v1.0.27-7831078
v1.0.31-e70dca7