Skip to content

Commit

Permalink
Update demo for IPLD blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
nikugogoi committed Jun 13, 2022
1 parent baa20de commit f2d299f
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 71 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ jobs:
- name: Docker Login to Registry
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u vulcanize --password-stdin
- name: Docker Pull
run: docker pull ghcr.io/vulcanize/watcher-ts:${{steps.vars.outputs.sha}}
run: docker pull ghcr.io/vulcanize/graph-watcher-ts:${{steps.vars.outputs.sha}}
- name: Tag docker image
run: docker tag ghcr.io/vulcanize/watcher-ts:${{steps.vars.outputs.sha}} ghcr.io/vulcanize/watcher-ts:${{steps.vars.outputs.tag}}
run: docker tag ghcr.io/vulcanize/graph-watcher-ts:${{steps.vars.outputs.sha}} ghcr.io/vulcanize/graph-watcher-ts:${{steps.vars.outputs.tag}}
- name: Docker Push to Github Hub
run: docker push ghcr.io/vulcanize/watcher-ts:${{steps.vars.outputs.tag}}
run: docker push ghcr.io/vulcanize/graph-watcher-ts:${{steps.vars.outputs.tag}}

171 changes: 106 additions & 65 deletions packages/erc721-watcher/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
yarn
```

* Run the IPFS (go-ipfs version 0.12.2) daemon:

```bash
ipfs daemon
```

* Create a postgres12 database for the watcher:

```bash
Expand Down Expand Up @@ -37,18 +43,32 @@

* The following core services should be setup and running on localhost:

* `vulcanize/go-ethereum` [v1.10.18-statediff-3.2.2](https://github.com/vulcanize/go-ethereum/releases/tag/v1.10.18-statediff-3.2.2) on port 8545
* `vulcanize/go-ethereum` [v1.10.18-statediff-4.0.2-alpha](https://github.com/vulcanize/go-ethereum/releases/tag/v1.10.18-statediff-4.0.2-alpha) on port 8545

* `vulcanize/ipld-eth-server` [v3.2.2](https://github.com/vulcanize/ipld-eth-server/releases/tag/v3.2.2) with native GQL API enabled, on port 8082
* `vulcanize/ipld-eth-server` [v4.0.3-alpha](https://github.com/vulcanize/ipld-eth-server/releases/tag/v4.0.3-alpha) with native GQL API enabled, on port 8082

* In the [config file](./environments/local.toml):

* Update the database connection settings.

* Update the `upstream` config and provide the `ipld-eth-server` GQL API endpoint.

* Update the `server` config with state checkpoint settings and provide the IPFS API address.

## Demo

* Run the watcher:

```bash
yarn server
```

* Run the job-runner:

```bash
yarn job-runner
```

* Deploy an ERC721 token:

```bash
Expand All @@ -62,7 +82,17 @@
export NFT_ADDRESS="<NFT_ADDRESS>"
```

* Open `http://localhost:3006/graphql` (GraphQL Playground) in a browser window
* Run the following GQL mutation in generated watcher GraphQL endpoint http://127.0.0.1:3006/graphql

```graphql
mutation {
watchContract(
address: "NFT_ADDRESS"
kind: "ERC721"
checkpoint: true
)
}
```

* Connect MetaMask to `http://localhost:8545` (with chain ID `41337`)

Expand All @@ -72,89 +102,76 @@
export RECIPIENT_ADDRESS="<RECIPIENT_ADDRESS>"
```

* To get the current block hash at any time, run:

```bash
yarn block:latest
```

* Run the following GQL query (`eth_call`) in generated watcher graphql endpoint http://127.0.0.1:3006/graphql
* Run the following GQL subscription in generated watcher GraphQL endpoint:

```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: "0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc"
) {
value
proof {
data
subscription {
onEvent {
event {
__typename
... on TransferEvent {
from
to
tokenId
},
... on ApprovalEvent {
owner
approved
tokenId
}
},
block {
number
hash
}
}
}
```

* Run the following GQL query (`storage`) in generated watcher graphql endpoint http://127.0.0.1:3006/graphql
* Mint token

```bash
yarn nft:mint --nft $NFT_ADDRESS --to 0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc --token-id 1
```

* A Transfer event to 0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc shall be visible in the subscription at endpoint.

* An auto-generated diff_staged IPLDBlock should be added with parent cid pointing to the initial checkpoint IPLDBlock.

* Run the getState query at the endpoint to get the latest IPLDBlock for NFT_ADDRESS:

```graphql
query {
_name(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
) {
value
proof {
data
}
}
_symbol(
blockHash: "LATEST_BLOCK_HASH"
getState (
blockHash: "EVENT_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
# kind: "checkpoint"
# kind: "diff"
kind: "diff_staged"
) {
value
proof {
data
}
}
_balances(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
key0: "0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc"
) {
value
proof {
data
cid
block {
cid
hash
number
timestamp
parentHash
}
contractAddress
data
}
}
```

* Mint token
`diff` IPLDBlocks get created corresponding to the `diff_staged` blocks when their respective eth_blocks reach the pruned region.

* To get the current block hash at any time, run:

```bash
yarn nft:mint --nft $NFT_ADDRESS --to 0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc --token-id 1
yarn block:latest
```

* Get the latest blockHash and run the following query for `balanceOf` and `ownerOf` (`eth_call`):
* Run the following query for `balanceOf` and `ownerOf` (`eth_call`):

```graphql
query {
Expand Down Expand Up @@ -197,8 +214,32 @@
yarn nft:transfer --nft $NFT_ADDRESS --from 0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc --to $RECIPIENT_ADDRESS --token-id 1
```

* An Approval event for ZERO_ADDRESS (0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc) shall be visible in the subscription at endpoint.

* A Transfer event to $RECIPIENT_ADDRESS shall be visible in the subscription at endpoint.

* An auto-generated diff_staged IPLDBlock should be added with parent cid pointing to the previous IPLDBlock.

* Get the latest blockHash and replace the blockHash in the above query. The result should be different and the token should be transferred to the recipient.

* Run the getState query again at the endpoint with the event blockHash.

* After the `diff` block has been created, create a checkpoint using CLI in `packages/erc721-watcher`:

```bash
yarn checkpoint --address $NFT_ADDRESS
```

* Run the getState query again with the output blockHash and kind checkpoint at the endpoint.

* The latest checkpoint should have the aggregate of state diffs since the last checkpoint.

* The IPLDBlock entries can be seen in pg-admin in table ipld_block.

* All the diff and checkpoint IPLDBlocks should pushed to IPFS.

* Open IPFS WebUI http://127.0.0.1:5001/webui and search for IPLDBlocks using their CIDs.

## Customize

* Indexing on an event:
Expand Down
2 changes: 1 addition & 1 deletion packages/erc721-watcher/environments/local.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
checkpointInterval = 2000

# IPFS API address (can be taken from the output on running the IPFS daemon).
# ipfsApiAddr = "/ip4/127.0.0.1/tcp/5001"
ipfsApiAddr = "/ip4/127.0.0.1/tcp/5001"


[database]
Expand Down
42 changes: 40 additions & 2 deletions packages/erc721-watcher/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,44 @@ export async function handleEvent (indexer: Indexer, eventData: ResultEvent): Pr
assert(indexer);
assert(eventData);

// Use indexer methods to index data.
// Pass `diff` parameter to indexer methods as true to save an auto-generated state from the indexed data.
// Perform indexing based on the type of event.
switch (eventData.event.__typename) {
case 'TransferEvent': {
// Get event fields from eventData.
const { from, to, tokenId } = eventData.event;

// Update balance entry for the sender in database.
if (from !== '0x0000000000000000000000000000000000000000') {
await indexer._balances(eventData.block.hash, eventData.contract, from, true);
}

// Update balance entry for the receiver in database.
if (to !== '0x0000000000000000000000000000000000000000') {
await indexer._balances(eventData.block.hash, eventData.contract, to, true);
}

// Update owner for the tokenId in database.
await indexer._owners(eventData.block.hash, eventData.contract, tokenId, true);

break;
}
case 'ApprovalEvent': {
// Get event fields from eventData.
const { tokenId } = eventData.event;

// Update tokenApprovals for the tokenId in database.
await indexer._tokenApprovals(eventData.block.hash, eventData.contract, tokenId, true);

break;
}
case 'ApprovalForAllEvent': {
// Get event fields from eventData.
const { owner, operator } = eventData.event;

// Update operatorApprovals for the tokenId in database.
await indexer._operatorApprovals(eventData.block.hash, eventData.contract, owner, operator, true);

break;
}
}
}

0 comments on commit f2d299f

Please sign in to comment.