Add a local stack for ERC721 watcher (#81)

* Add a stack for erc721 watcher

* Add a demo

* Avoid watcher db service and volume name conflicts across watchers

* Avoid host port conflicts across watchers

* Avoid watcher-db port conflicts
This commit is contained in:
prathamesh0 2022-12-22 13:13:59 +05:30 committed by GitHub
parent a7221ddc24
commit 27c3efabe2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 369 additions and 10 deletions

View File

@ -14,6 +14,7 @@ cerc/fixturenet-eth-geth
cerc/fixturenet-eth-lighthouse cerc/fixturenet-eth-lighthouse
cerc/watcher-mobymask cerc/watcher-mobymask
cerc/watcher-erc20 cerc/watcher-erc20
cerc/watcher-erc721
cerc/test-container cerc/test-container
cerc/eth-probe cerc/eth-probe
cerc/builder-js cerc/builder-js

View File

@ -12,6 +12,7 @@ fixturenet-laconicd
fixturenet-eth fixturenet-eth
watcher-mobymask watcher-mobymask
watcher-erc20 watcher-erc20
watcher-erc721
test test
eth-probe eth-probe
keycloak keycloak

View File

@ -2,7 +2,7 @@ version: '3.2'
services: services:
watcher-db: erc20-watcher-db:
restart: unless-stopped restart: unless-stopped
image: postgres:14-alpine image: postgres:14-alpine
environment: environment:
@ -12,9 +12,9 @@ services:
- POSTGRES_PASSWORD=password - POSTGRES_PASSWORD=password
volumes: volumes:
- ../config/postgresql/multiple-postgressql-databases.sh:/docker-entrypoint-initdb.d/multiple-postgressql-databases.sh - ../config/postgresql/multiple-postgressql-databases.sh:/docker-entrypoint-initdb.d/multiple-postgressql-databases.sh
- watcher_db_data:/var/lib/postgresql/data - erc20_watcher_db_data:/var/lib/postgresql/data
ports: ports:
- "0.0.0.0:15432:5432" - "0.0.0.0:15433:5432"
healthcheck: healthcheck:
test: ["CMD", "nc", "-v", "localhost", "5432"] test: ["CMD", "nc", "-v", "localhost", "5432"]
interval: 20s interval: 20s
@ -27,7 +27,7 @@ services:
depends_on: depends_on:
ipld-eth-server: ipld-eth-server:
condition: service_healthy condition: service_healthy
watcher-db: erc20-watcher-db:
condition: service_healthy condition: service_healthy
image: cerc/watcher-erc20:local image: cerc/watcher-erc20:local
environment: environment:
@ -36,14 +36,14 @@ services:
volumes: volumes:
- ../config/watcher-erc20/erc20-watcher.toml:/app/packages/erc20-watcher/environments/local.toml - ../config/watcher-erc20/erc20-watcher.toml:/app/packages/erc20-watcher/environments/local.toml
ports: ports:
- "0.0.0.0:3001:3001" - "0.0.0.0:3002:3001"
- "0.0.0.0:9001:9001" - "0.0.0.0:9002:9001"
healthcheck: healthcheck:
test: ["CMD", "nc", "-v", "localhost", "3001"] test: ["CMD", "nc", "-v", "localhost", "3002"]
interval: 20s interval: 20s
timeout: 5s timeout: 5s
retries: 15 retries: 15
start_period: 5s start_period: 5s
volumes: volumes:
watcher_db_data: erc20_watcher_db_data:

View File

@ -0,0 +1,49 @@
version: '3.2'
services:
erc721-watcher-db:
restart: unless-stopped
image: postgres:14-alpine
environment:
- POSTGRES_USER=vdbm
- POSTGRES_MULTIPLE_DATABASES=erc721-watcher,erc721-watcher-job-queue
- POSTGRES_EXTENSION=erc721-watcher-job-queue:pgcrypto
- POSTGRES_PASSWORD=password
volumes:
- ../config/postgresql/multiple-postgressql-databases.sh:/docker-entrypoint-initdb.d/multiple-postgressql-databases.sh
- erc721_watcher_db_data:/var/lib/postgresql/data
ports:
- "0.0.0.0:15434:5432"
healthcheck:
test: ["CMD", "nc", "-v", "localhost", "5432"]
interval: 20s
timeout: 5s
retries: 15
start_period: 10s
erc721-watcher:
restart: unless-stopped
depends_on:
ipld-eth-server:
condition: service_healthy
erc721-watcher-db:
condition: service_healthy
image: cerc/watcher-erc721:local
environment:
- ETH_RPC_URL=http://go-ethereum:8545
command: ["sh", "-c", "yarn server"]
volumes:
- ../config/watcher-erc721/erc721-watcher.toml:/app/packages/erc721-watcher/environments/local.toml
ports:
- "0.0.0.0:3009:3009"
- "0.0.0.0:9003:9001"
healthcheck:
test: ["CMD", "nc", "-v", "localhost", "3009"]
interval: 20s
timeout: 5s
retries: 15
start_period: 5s
volumes:
erc721_watcher_db_data:

View File

@ -12,7 +12,7 @@
[database] [database]
type = "postgres" type = "postgres"
host = "watcher-db" host = "erc20-watcher-db"
port = 5432 port = 5432
database = "erc20-watcher" database = "erc20-watcher"
username = "vdbm" username = "vdbm"
@ -32,7 +32,7 @@
deleteOnStart = false deleteOnStart = false
[jobQueue] [jobQueue]
dbConnectionString = "postgres://vdbm:password@watcher-db:5432/erc20-watcher-job-queue" dbConnectionString = "postgres://vdbm:password@erc20-watcher-db:5432/erc20-watcher-job-queue"
maxCompletionLagInSecs = 300 maxCompletionLagInSecs = 300
jobDelayInMilliSecs = 100 jobDelayInMilliSecs = 100
eventsInBatch = 50 eventsInBatch = 50

View File

@ -0,0 +1,56 @@
[server]
host = "0.0.0.0"
port = 3009
kind = "lazy"
# Checkpointing state.
checkpointing = true
# Checkpoint interval in number of blocks.
checkpointInterval = 2000
# Enable state creation
enableState = true
# Boolean to filter logs by contract.
filterLogs = false
# Max block range for which to return events in eventsInRange GQL query.
# Use -1 for skipping check on block range.
maxEventsBlockRange = 1000
[metrics]
host = "127.0.0.1"
port = 9000
[metrics.gql]
port = 9001
[database]
type = "postgres"
host = "erc721-watcher-db"
port = 5432
database = "erc721-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@erc721-watcher-db:5432/erc721-watcher-job-queue"
maxCompletionLagInSecs = 300
jobDelayInMilliSecs = 100
eventsInBatch = 50
blockDelayInMilliSecs = 2000
prefetchBlocksInMem = true
prefetchBlockCount = 10

View File

@ -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/erc721-watcher

View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
# Build cerc/watcher-erc721
# See: https://stackoverflow.com/a/246128/1701505
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
docker build -t cerc/watcher-erc721:local -f ${SCRIPT_DIR}/Dockerfile ${CERC_REPO_BASE_DIR}/watcher-ts

214
stacks/erc721/README.md Normal file
View File

@ -0,0 +1,214 @@
# ERC721 Watcher
Instructions to deploy a local ERC721 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-erc721
```
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-erc721 up
```
## Demo
* Find the watcher container's id using `docker ps` and export it for later use:
```bash
$ export CONTAINER_ID=<CONTAINER_ID>
```
* Deploy an ERC721 token:
```bash
$ docker exec $CONTAINER_ID yarn nft:deploy:docker
```
Export the address of the deployed token to a shell variable for later use:
```bash
$ export NFT_ADDRESS=<NFT_ADDRESS>
```
* Open `http://localhost:3009/graphql` (GraphQL Playground) in a browser window
* Connect MetaMask to `http://localhost:8545` (with chain ID `99`)
* Export your MetaMask account (second account) address to a shell variable for later use:
```bash
$ export RECIPIENT_ADDRESS=<RECIPIENT_ADDRESS>
```
* To get the primary account's address, run:
```bash
$ docker exec $CONTAINER_ID yarn account:docker
```
Export it to shell variable for later use:
```bash
$ export PRIMARY_ADDRESS=<PRIMARY_ADDRESS>
```
* To get the current block hash at any time, run:
```bash
$ docker exec $CONTAINER_ID yarn block:latest:docker
```
* Fire the following GQL query (uses `eth_call`) in the playground:
```graphql
query {
name(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
) {
value
proof {
data
}
}
symbol(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
) {
value
proof {
data
}
}
balanceOf(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
owner: "PRIMARY_ADDRESS"
) {
value
proof {
data
}
}
}
```
Balance for the `PRIMARY_ADDRESS` should be `0` as the token is yet to be minted.
* Fire the following GQL query (uses `storage` calls) in the playground:
```graphql
query {
_name(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
) {
value
proof {
data
}
}
_symbol(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
) {
value
proof {
data
}
}
_balances(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
key0: "PRIMARY_ADDRESS"
) {
value
proof {
data
}
}
}
```
* Mint the token:
```bash
$ docker exec $CONTAINER_ID yarn nft:mint:docker --nft $NFT_ADDRESS --to $PRIMARY_ADDRESS --token-id 1
```
Fire the GQL query above again with latest block hash. The balance should increase to `1`.
* Get the latest block hash and run the following GQL query in the playground for `balanceOf` and `ownerOf` (`eth_call`):
```graphql
query {
fromBalanceOf: balanceOf(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
owner: "PRIMARY_ADDRESS"
) {
value
proof {
data
}
}
toBalanceOf: balanceOf(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
owner: "RECIPIENT_ADDRESS"
) {
value
proof {
data
}
}
ownerOf(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
tokenId: 1
) {
value
proof {
data
}
}
}
```
Balance should be `1` for the `PRIMARY_ADDRESS`, `0` for the `RECIPIENT_ADDRESS` and owner value of the token should be equal to the `PRIMARY_ADDRESS`.
* Transfer the token:
```bash
$ docker exec $CONTAINER_ID yarn nft:transfer:docker --nft $NFT_ADDRESS --from $PRIMARY_ADDRESS --to $RECIPIENT_ADDRESS --token-id 1
```
Fire the GQL query above again with the latest block hash. The token should be transferred to the recipient.
## Clean up
* To stop all the services running in background:
```bash
$ laconic-so deploy-system --include db,go-ethereum-foundry,ipld-eth-server,watcher-erc721 down
```

18
stacks/erc721/stack.yml Normal file
View File

@ -0,0 +1,18 @@
version: "1.0"
name: erc721-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-erc721
pods:
- go-ethereum-foundry
- db
- ipld-eth-server
- watcher-erc721