diff --git a/app/data/container-image-list.txt b/app/data/container-image-list.txt index 12db6164..19ee8da6 100644 --- a/app/data/container-image-list.txt +++ b/app/data/container-image-list.txt @@ -13,6 +13,7 @@ cerc/laconic-cns-cli cerc/fixturenet-eth-geth cerc/fixturenet-eth-lighthouse cerc/watcher-mobymask +cerc/watcher-erc20 cerc/test-container cerc/eth-probe cerc/builder-js diff --git a/app/data/pod-list.txt b/app/data/pod-list.txt index 659eeb10..0e02bc4c 100644 --- a/app/data/pod-list.txt +++ b/app/data/pod-list.txt @@ -11,6 +11,7 @@ laconicd fixturenet-laconicd fixturenet-eth watcher-mobymask +watcher-erc20 test eth-probe keycloak diff --git a/app/deploy_system.py b/app/deploy_system.py index b3fb618a..91232094 100644 --- a/app/deploy_system.py +++ b/app/deploy_system.py @@ -73,7 +73,7 @@ def command(ctx, include, exclude, cluster, command, services): docker = DockerClient(compose_files=compose_files, compose_project_name=cluster) services_list = list(services) or None - + if not dry_run: if command == "up": if verbose: diff --git a/compose/docker-compose-ipld-eth-server.yml b/compose/docker-compose-ipld-eth-server.yml index 21dfd2b2..ee9c8885 100644 --- a/compose/docker-compose-ipld-eth-server.yml +++ b/compose/docker-compose-ipld-eth-server.yml @@ -30,4 +30,9 @@ services: ports: - "127.0.0.1:8081:8081" - "127.0.0.1:8082:8082" - + healthcheck: + test: ["CMD", "nc", "-v", "localhost", "8081"] + interval: 20s + timeout: 5s + retries: 15 + start_period: 5s diff --git a/compose/docker-compose-watcher-erc20.yml b/compose/docker-compose-watcher-erc20.yml new file mode 100644 index 00000000..18beacb0 --- /dev/null +++ b/compose/docker-compose-watcher-erc20.yml @@ -0,0 +1,49 @@ +version: '3.2' + +services: + + watcher-db: + restart: unless-stopped + image: postgres:14-alpine + environment: + - POSTGRES_USER=vdbm + - POSTGRES_MULTIPLE_DATABASES=erc20-watcher,erc20-watcher-job-queue + - POSTGRES_EXTENSION=erc20-watcher-job-queue:pgcrypto + - POSTGRES_PASSWORD=password + volumes: + - ../config/postgresql/multiple-postgressql-databases.sh:/docker-entrypoint-initdb.d/multiple-postgressql-databases.sh + - watcher_db_data:/var/lib/postgresql/data + ports: + - "0.0.0.0:15432:5432" + healthcheck: + test: ["CMD", "nc", "-v", "localhost", "5432"] + interval: 20s + timeout: 5s + retries: 15 + start_period: 10s + + erc20-watcher: + restart: unless-stopped + depends_on: + ipld-eth-server: + condition: service_healthy + watcher-db: + condition: service_healthy + image: cerc/watcher-erc20:local + environment: + - ETH_RPC_URL=http://go-ethereum:8545 + command: ["sh", "-c", "yarn server"] + volumes: + - ../config/watcher-erc20/erc20-watcher.toml:/app/packages/erc20-watcher/environments/local.toml + ports: + - "0.0.0.0:3001:3001" + - "0.0.0.0:9001:9001" + healthcheck: + test: ["CMD", "nc", "-v", "localhost", "3001"] + interval: 20s + timeout: 5s + retries: 15 + start_period: 5s + +volumes: + watcher_db_data: diff --git a/config/watcher-erc20/erc20-watcher.toml b/config/watcher-erc20/erc20-watcher.toml new file mode 100644 index 00000000..5b8b4ce5 --- /dev/null +++ b/config/watcher-erc20/erc20-watcher.toml @@ -0,0 +1,41 @@ +[server] + host = "0.0.0.0" + port = 3001 + mode = "storage" + kind = "lazy" + +[metrics] + host = "127.0.0.1" + port = 9000 + [metrics.gql] + port = 9001 + +[database] + type = "postgres" + host = "watcher-db" + port = 5432 + database = "erc20-watcher" + username = "vdbm" + password = "password" + synchronize = true + logging = false + maxQueryExecutionTime = 100 + +[upstream] + [upstream.ethServer] + gqlApiEndpoint = "http://ipld-eth-server:8082/graphql" + rpcProviderEndpoint = "http://ipld-eth-server:8081" + + [upstream.cache] + name = "requests" + enabled = false + deleteOnStart = false + +[jobQueue] + dbConnectionString = "postgres://vdbm:password@watcher-db:5432/erc20-watcher-job-queue" + maxCompletionLagInSecs = 300 + jobDelayInMilliSecs = 100 + eventsInBatch = 50 + blockDelayInMilliSecs = 2000 + prefetchBlocksInMem = true + prefetchBlockCount = 10 diff --git a/config/watcher-mobymask/mobymask-watcher.toml b/config/watcher-mobymask/mobymask-watcher.toml index 4dba25b9..3e9b2db5 100644 --- a/config/watcher-mobymask/mobymask-watcher.toml +++ b/config/watcher-mobymask/mobymask-watcher.toml @@ -37,8 +37,8 @@ [upstream] [upstream.ethServer] - gqlApiEndpoint = "http://ipld-eth-server:8083/graphql" - rpcProviderEndpoint = "http://ipld-eth-server:8082" + gqlApiEndpoint = "http://ipld-eth-server:8082/graphql" + rpcProviderEndpoint = "http://ipld-eth-server:8081" blockDelayInMilliSecs = 60000 [upstream.cache] diff --git a/container-build/cerc-go-ethereum-foundry/genesis-automine.json b/container-build/cerc-go-ethereum-foundry/genesis-automine.json index a00a614e..6cbf7f26 100644 --- a/container-build/cerc-go-ethereum-foundry/genesis-automine.json +++ b/container-build/cerc-go-ethereum-foundry/genesis-automine.json @@ -10,7 +10,7 @@ "petersburgBlock": 0, "istanbulBlock": 0, "clique": { - "period": 2, + "period": 5, "epoch": 3000 } }, diff --git a/container-build/cerc-watcher-erc20/Dockerfile b/container-build/cerc-watcher-erc20/Dockerfile new file mode 100644 index 00000000..5ec94987 --- /dev/null +++ b/container-build/cerc-watcher-erc20/Dockerfile @@ -0,0 +1,13 @@ +FROM node:16.17.1-alpine3.16 + +RUN apk --update --no-cache add git python3 alpine-sdk + +WORKDIR /app + +COPY . . + +RUN echo "Building watcher-ts" && \ + git checkout v0.2.19 && \ + yarn && yarn build + +WORKDIR /app/packages/erc20-watcher diff --git a/container-build/cerc-watcher-erc20/build.sh b/container-build/cerc-watcher-erc20/build.sh new file mode 100755 index 00000000..b800b73d --- /dev/null +++ b/container-build/cerc-watcher-erc20/build.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# Build cerc/watcher-erc20 + +# See: https://stackoverflow.com/a/246128/1701505 +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +docker build -t cerc/watcher-erc20:local -f ${SCRIPT_DIR}/Dockerfile ${CERC_REPO_BASE_DIR}/watcher-ts diff --git a/stacks/erc20/README.md b/stacks/erc20/README.md new file mode 100644 index 00000000..eec3d9f4 --- /dev/null +++ b/stacks/erc20/README.md @@ -0,0 +1,157 @@ +# ERC20 Watcher + +Instructions to deploy a local ERC20 watcher stack (core + watcher) for demonstration and testing purposes using [laconic-stack-orchestrator](../../README.md#setup) + +## Setup + +* Clone / pull required repositories: + + ```bash + $ laconic-so setup-repositories --include cerc-io/go-ethereum,cerc-io/ipld-eth-db,cerc-io/ipld-eth-server,cerc-io/watcher-ts --pull + ``` + +* Build the core and watcher container images: + + ```bash + $ laconic-so build-containers --include cerc/go-ethereum,cerc/go-ethereum-foundry,cerc/ipld-eth-db,cerc/ipld-eth-server,cerc/watcher-erc20 + ``` + + This should create the required docker images in the local image registry. + +* Deploy the stack: + + ```bash + $ laconic-so deploy-system --include db,go-ethereum-foundry,ipld-eth-server,watcher-erc20 up + ``` + +## Demo + +* Find the watcher container's id using `docker ps` and export it for later use: + + ```bash + $ export CONTAINER_ID= + ``` + +* Deploy an ERC20 token: + + ```bash + $ docker exec $CONTAINER_ID yarn token:deploy:docker + ``` + + Export the address of the deployed token to a shell variable for later use: + + ```bash + $ export TOKEN_ADDRESS= + ``` + +* Open `http://localhost:3001/graphql` (GraphQL Playground) in a browser window + +* Connect MetaMask to `http://localhost:8545` (with chain ID `99`) + +* Add the deployed token as an asset in MetaMask and check that the initial balance is zero + +* Export your MetaMask account (second account) address to a shell variable for later use: + + ```bash + $ export RECIPIENT_ADDRESS= + ``` + +* To get the primary account's address, run: + + ```bash + $ docker exec $CONTAINER_ID yarn account:docker + ``` + +* To get the current block hash at any time, run: + + ```bash + $ docker exec $CONTAINER_ID yarn block:latest:docker + ``` + +* Fire a GQL query in the playground to get the name, symbol and total supply of the deployed token: + + ```graphql + query { + name( + blockHash: "LATEST_BLOCK_HASH" + token: "TOKEN_ADDRESS" + ) { + value + proof { + data + } + } + + symbol( + blockHash: "LATEST_BLOCK_HASH" + token: "TOKEN_ADDRESS" + ) { + value + proof { + data + } + } + + totalSupply( + blockHash: "LATEST_BLOCK_HASH" + token: "TOKEN_ADDRESS" + ) { + value + proof { + data + } + } + } + ``` + +* Fire the following query to get balances for the primary and the recipient account at the latest block hash: + + ```graphql + query { + fromBalanceOf: balanceOf( + blockHash: "LATEST_BLOCK_HASH" + token: "TOKEN_ADDRESS", + # primary account having all the balance initially + owner: "PRIMARY_ADDRESS" + ) { + value + proof { + data + } + } + toBalanceOf: balanceOf( + blockHash: "LATEST_BLOCK_HASH" + token: "TOKEN_ADDRESS", + owner: "RECIPIENT_ADDRESS" + ) { + value + proof { + data + } + } + } + ``` + + * The initial balance for the primary account should be `1000000000000000000000` + * The initial balance for the recipient should be `0` + +* Transfer tokens to the recipient account: + + ```bash + $ docker exec $CONTAINER_ID yarn token:transfer:docker --token $TOKEN_ADDRESS --to $RECIPIENT_ADDRESS --amount 100 + ``` + +* Fire the above GQL query again with the latest block hash to get updated balances for the primary (`from`) and the recipient (`to`) account: + + * The balance for the primary account should be reduced by the transfer amount (`100`) + * The balance for the recipient account should be equal to the transfer amount (`100`) + +* Transfer funds between different accounts using MetaMask and use the playground to query the balance before and after the transfer. + +## Clean up + +* To stop all the services running in background run: + + ```bash + $ laconic-so deploy-system --include db,go-ethereum-foundry,ipld-eth-server,watcher-erc20 down + ``` diff --git a/stacks/erc20/stack.yml b/stacks/erc20/stack.yml new file mode 100644 index 00000000..e9b0eb6d --- /dev/null +++ b/stacks/erc20/stack.yml @@ -0,0 +1,18 @@ +version: "1.0" +name: erc20-watcher +repos: + - cerc-io/go-ethereum + - cerc-io/ipld-eth-db + - cerc-io/ipld-eth-server + - cerc-io/watcher-ts +containers: + - cerc/go-ethereum + - cerc/go-ethereum-foundry + - cerc/ipld-eth-db + - cerc/ipld-eth-server + - cerc/watcher-erc20 +pods: + - go-ethereum-foundry + - db + - ipld-eth-server + - watcher-erc20