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

Fetch transaction arguments for indexed event #137

Merged
merged 1 commit into from
Jun 30, 2022
Merged
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
107 changes: 65 additions & 42 deletions packages/moby-mask-watcher/demo.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@

* Clone the [stack-orchestrator](https://github.com/vulcanize/stack-orchestrator) repo.

* Checkout the `develop` branch in stack-orchestrator repo.

```bash
git checkout develop
```

* Create a `config.sh` file.

```bash
Expand All @@ -25,7 +19,7 @@

```bash
# In go-ethereum repo.
git checkout v1.10.19-statediff-4.0.3-alpha
git checkout v1.10.19-statediff-4.0.4-alpha
```

* To run the stack-orchestrator, the docker-compose version used is:
Expand Down Expand Up @@ -148,6 +142,44 @@
}
```

* Get the latest block

```graphql
query {
latestBlock {
hash
number
}
}
```

* Run the following GQL query in GraphQL endpoint

```graphql
query {
isPhisher(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "MOBY_ADDRESS"
key0: "TWT:phishername"
) {
value
proof {
data
}
}
isMember(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "MOBY_ADDRESS"
key0: "TWT:membername"
) {
value
proof {
data
}
}
}
```

* Run the following GQL subscription in generated watcher GraphQL endpoint:

```graphql
Expand Down Expand Up @@ -182,45 +214,36 @@
yarn claimMember --contract $MOBY_ADDRESS --name memberName
```

* The events should be visible in the subscription at GQL endpoint.
* The events should be visible in the subscription at GQL endpoint. Note down the event blockHash from result.

* Check the names in the watcher GraphQL playground http://localhost:3010/graphql
* The isMember and isPhisher lists should be indexed. Check the database (moby-mask-watcher) tables `is_phisher` and `is_member`, there should be entries at the event blockHash and the value should be true. The data is indexed in `handleEvent` method in the [hooks file](./src/hooks.ts).

* Get the latest block
* Update the the previous query with event blockHash and check isPhisher and isMember in GraphQL playground

```graphql
query {
latestBlock {
hash
number
```graphql
query {
isPhisher(
blockHash: "EVENT_BLOCK_HASH"
contractAddress: "MOBY_ADDRESS",
key0: "TWT:phishername"
) {
value
proof {
data
}
}
```

* Check the `isPhisher` and `isMember` maps

```graphql
query {
isPhisher(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "MOBY_ADDRESS",
key0: "TWT:phishername"
) {
value
proof {
data
}
}

isMember(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "MOBY_ADDRESS",
key0: "TWT:membername"
) {
value
proof {
data
}

isMember(
blockHash: "EVENT_BLOCK_HASH"
contractAddress: "MOBY_ADDRESS",
key0: "TWT:membername"
) {
value
proof {
data
}
}
```
}
```

The data is fetched from watcher database as it is already indexed.
35 changes: 32 additions & 3 deletions packages/moby-mask-watcher/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
//

import assert from 'assert';
import { utils } from 'ethers';

// import { updateStateForMappingType, updateStateForElementaryType } from '@vulcanize/util';

import { Indexer, ResultEvent } from './indexer';
import { Indexer, KIND_PHISHERREGISTRY, ResultEvent } from './indexer';

/**
* Hook function to store an initial state.
Expand Down Expand Up @@ -75,6 +76,34 @@ 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) {
// In case of PhisherRegistry 'PhisherStatusUpdated' event.
case 'PhisherStatusUpdatedEvent': {
const txArgs = await getTxArgs(indexer, KIND_PHISHERREGISTRY, eventData.tx.hash);

// Update isPhisher entry for the identifier in database.
await indexer.isPhisher(eventData.block.hash, eventData.contract, txArgs.identifier, true);

break;
}
// In case of PhisherRegistry 'MemberStatusUpdated' event.
case 'MemberStatusUpdatedEvent': {
const txArgs = await getTxArgs(indexer, KIND_PHISHERREGISTRY, eventData.tx.hash);

// Update isPhisher entry for the identifier in database.
await indexer.isMember(eventData.block.hash, eventData.contract, txArgs.identifier, true);

break;
}
}
}

// Get transaction arguments for specified txHash.
const getTxArgs = async (indexer: Indexer, contractKind: string, txHash: string): Promise<utils.Result> => {
const tx = await indexer.getFullTransaction(txHash);
const contractInterface = await indexer.getContractInterface(contractKind);
assert(contractInterface);
const txDescription = contractInterface.parseTransaction({ data: tx.input });
return txDescription.args;
};
15 changes: 13 additions & 2 deletions packages/moby-mask-watcher/src/indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import {
BlockHeight,
IPFSClient,
StateKind,
IpldStatus as IpldStatusInterface
IpldStatus as IpldStatusInterface,
getFullTransaction
} from '@vulcanize/util';
import { GraphWatcher } from '@vulcanize/graph-node';

Expand All @@ -43,7 +44,7 @@ import { IPLDBlock } from './entity/IPLDBlock';

const log = debug('vulcanize:indexer');

const KIND_PHISHERREGISTRY = 'PhisherRegistry';
export const KIND_PHISHERREGISTRY = 'PhisherRegistry';

const DELEGATIONTRIGGERED_EVENT = 'DelegationTriggered';
const MEMBERSTATUSUPDATED_EVENT = 'MemberStatusUpdated';
Expand Down Expand Up @@ -797,6 +798,16 @@ export class Indexer implements IPLDIndexerInterface {
return block;
}

// Get full transaction data.
async getFullTransaction (txHash: string): Promise<any> {
return getFullTransaction(this._ethClient, txHash);
}

// Get contract interface for specified contract kind.
async getContractInterface (kind: string): Promise<ethers.utils.Interface | undefined> {
return this._contractMap.get(kind);
}

getEntityTypesMap (): Map<string, { [key: string]: string }> {
return this._entityTypesMap;
}
Expand Down