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

Add watcher in eth_call mode for Azimuth contract #4

Merged
merged 2 commits into from
Apr 12, 2023
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
2 changes: 2 additions & 0 deletions packages/azimuth-watcher/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Don't lint build output.
dist
28 changes: 28 additions & 0 deletions packages/azimuth-watcher/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"semistandard",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"indent": ["error", 2, { "SwitchCase": 1 }],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": [
"warn",
{
"allowArgumentsExplicitlyTypedAsAny": true
}
]
}
}
227 changes: 227 additions & 0 deletions packages/azimuth-watcher/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
# azimuth-watcher

## Currently unsupported queries

The watcher was generated in `eth_call` mode and does not support the following queries in its current state:

* `getKeys(uint32 _point) returns (bytes32 crypt, bytes32 auth, uint32 suite, uint32 revision)`

* `getSpawned(uint32 _point) returns (uint32[] spawned)`

* `getSponsoring(uint32 _sponsor) returns (uint32[] sponsees)`

* `getEscapeRequests(uint32 _sponsor) returns (uint32[] requests)`

* `getOwnedPoints(address _whose) returns (uint32[] ownedPoints)`

* `getManagerFor(address _proxy) returns (uint32[] mfor)`

* `getSpawningFor(address _proxy) returns (uint32[] sfor)`

* `getVotingFor(address _proxy) returns (uint32[] vfor)`

* `getTransferringFor(address _proxy) returns (uint32[] tfor)`


## Setup

* Run the following command to install required packages:

```bash
yarn
```

* Create a postgres12 database for the watcher:

```bash
sudo su - postgres
createdb azimuth-watcher
```

* If the watcher is an `active` watcher:

Create database for the job queue and enable the `pgcrypto` extension on them (https://github.com/timgit/pg-boss/blob/master/docs/usage.md#intro):

```
createdb azimuth-watcher-job-queue
```

```
postgres@tesla:~$ psql -U postgres -h localhost azimuth-watcher-job-queue
Password for user postgres:
psql (12.7 (Ubuntu 12.7-1.pgdg18.04+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

azimuth-watcher-job-queue=# CREATE EXTENSION pgcrypto;
CREATE EXTENSION
azimuth-watcher-job-queue=# exit
```

* 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.

## Customize

* Indexing on an event:

* Edit the custom hook function `handleEvent` (triggered on an event) in [hooks.ts](./src/hooks.ts) to perform corresponding indexing using the `Indexer` object.

* While using the indexer storage methods for indexing, pass `diff` as true if default state is desired to be generated using the state variables being indexed.

* Generating state:

* Edit the custom hook function `createInitialState` (triggered if the watcher passes the start block, checkpoint: `true`) in [hooks.ts](./src/hooks.ts) to save an initial `State` using the `Indexer` object.

* Edit the custom hook function `createStateDiff` (triggered on a block) in [hooks.ts](./src/hooks.ts) to save the state in a `diff` `State` using the `Indexer` object. The default state (if exists) is updated.

* Edit the custom hook function `createStateCheckpoint` (triggered just before default and CLI checkpoint) in [hooks.ts](./src/hooks.ts) to save the state in a `checkpoint` `State` using the `Indexer` object.

### GQL Caching

To enable GQL requests caching:

* Update the `server.gqlCache` config with required settings.

* In the GQL [schema file](./src/schema.gql), use the `cacheControl` directive to apply cache hints at schema level.

* Eg. Set `inheritMaxAge` to true for non-scalar fields of a type.

* In the GQL [resolvers file](./src/resolvers.ts), uncomment the `setGQLCacheHints()` calls in resolvers for required queries.

## Run

* If the watcher is a `lazy` watcher:

* Run the server:

```bash
yarn server
```

GQL console: http://localhost:3009/graphql

* If the watcher is an `active` watcher:

* Run the job-runner:

```bash
yarn job-runner
```

* Run the server:

```bash
yarn server
```

GQL console: http://localhost:3009/graphql

* To watch a contract:

```bash
yarn watch:contract --address <contract-address> --kind <contract-kind> --checkpoint <true | false> --starting-block [block-number]
```

* `address`: Address or identifier of the contract to be watched.
* `kind`: Kind of the contract.
* `checkpoint`: Turn checkpointing on (`true` | `false`).
* `starting-block`: Starting block for the contract (default: `1`).

Examples:

Watch a contract with its address and checkpointing on:

```bash
yarn watch:contract --address 0x1F78641644feB8b64642e833cE4AFE93DD6e7833 --kind ERC20 --checkpoint true
```

Watch a contract with its identifier and checkpointing on:

```bash
yarn watch:contract --address MyProtocol --kind protocol --checkpoint true
```

* To fill a block range:

```bash
yarn fill --start-block <from-block> --end-block <to-block>
```

* `start-block`: Block number to start filling from.
* `end-block`: Block number till which to fill.

* To create a checkpoint for a contract:

```bash
yarn checkpoint create --address <contract-address> --block-hash [block-hash]
```

* `address`: Address or identifier of the contract for which to create a checkpoint.
* `block-hash`: Hash of a block (in the pruned region) at which to create the checkpoint (default: latest canonical block hash).

* To reset the watcher to a previous block number:

* Reset watcher:

```bash
yarn reset watcher --block-number <previous-block-number>
```

* Reset job-queue:

```bash
yarn reset job-queue
```

* Reset state:

```bash
yarn reset state --block-number <previous-block-number>
```

* `block-number`: Block number to which to reset the watcher.

* To export and import the watcher state:

* In source watcher, export watcher state:

```bash
yarn export-state --export-file [export-file-path] --block-number [snapshot-block-height]
```

* `export-file`: Path of file to which to export the watcher data.
* `block-number`: Block height at which to take snapshot for export.

* In target watcher, run job-runner:

```bash
yarn job-runner
```

* Import watcher state:

```bash
yarn import-state --import-file <import-file-path>
```

* `import-file`: Path of file from which to import the watcher data.

* Run server:

```bash
yarn server
```

* To inspect a CID:

```bash
yarn inspect-cid --cid <cid>
```

* `cid`: CID to be inspected.
66 changes: 66 additions & 0 deletions packages/azimuth-watcher/environments/local.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
[server]
host = "127.0.0.1"
port = 3009
kind = "lazy"

# Checkpointing state.
checkpointing = true

# Checkpoint interval in number of blocks.
checkpointInterval = 2000

# Enable state creation
# CAUTION: Disable only if state creation is not desired or can be filled subsequently
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

# GQL cache settings
[server.gqlCache]
enabled = true

# Max in-memory cache size (in bytes) (default 8 MB)
# maxCacheSize

# GQL cache-control max-age settings (in seconds)
maxAge = 15

[metrics]
host = "127.0.0.1"
port = 9000
[metrics.gql]
port = 9001

[database]
type = "postgres"
host = "localhost"
port = 5432
database = "azimuth-watcher"
username = "postgres"
password = "postgres"
synchronize = true
logging = false

[upstream]
[upstream.ethServer]
gqlApiEndpoint = "http://127.0.0.1:8082/graphql"
rpcProviderEndpoint = "http://127.0.0.1:8081"

[upstream.cache]
name = "requests"
enabled = false
deleteOnStart = false

[jobQueue]
dbConnectionString = "postgres://postgres:postgres@localhost/azimuth-watcher-job-queue"
maxCompletionLagInSecs = 300
jobDelayInMilliSecs = 100
eventsInBatch = 50
blockDelayInMilliSecs = 2000
prefetchBlocksInMem = true
prefetchBlockCount = 10
Loading