mirror of
https://github.com/cerc-io/watcher-ts
synced 2024-11-19 12:26:19 +00:00
Accommodate CLI refactoring changes to codegen (#261)
* Use watch-contract CLI from cli package in codegen * Use reset CLIs from cli package in codegen * Use create checkpoint CLI from cli package in codegen * Use inspect-cid CLI from cli package in codegen * Use import state CLI from cli package in codegen * Use export-state and verify-checkpoint CLI from cli package in codegen * Use server CLI from cli package in codegen * Use job-runner CLI from cli package in codegen * Use index-block CLI from cli package in codegen * Use fill CLI from cli package in codegen * Minor codegen fixes * Update watcher instructions to run job-runner before server
This commit is contained in:
parent
590482ee53
commit
63a2c5804e
@ -15,15 +15,15 @@ const VERIFY_TEMPLATE_FILE = './templates/checkpoint-verify-template.handlebars'
|
||||
* Writes the checkpoint file generated from a template to a stream.
|
||||
* @param outStream A writable output stream to write the checkpoint file to.
|
||||
*/
|
||||
export function exportCheckpoint (checkpointOutStream: Writable, checkpointCreateOutStream: Writable, checkpointVerifyOutStream: Writable | undefined, subgraphPath: string): void {
|
||||
export function exportCheckpoint (checkpointOutStream: Writable, checkpointCreateOutStream: Writable, checkpointVerifyOutStream: Writable | undefined): void {
|
||||
const checkpointTemplateString = fs.readFileSync(path.resolve(__dirname, CHECKPOINT_TEMPLATE_FILE)).toString();
|
||||
const checkpointTemplate = Handlebars.compile(checkpointTemplateString);
|
||||
const checkpoint = checkpointTemplate({ subgraphPath });
|
||||
const checkpoint = checkpointTemplate({});
|
||||
checkpointOutStream.write(checkpoint);
|
||||
|
||||
const createCheckpointTemplateString = fs.readFileSync(path.resolve(__dirname, CREATE_TEMPLATE_FILE)).toString();
|
||||
const createCheckpointTemplate = Handlebars.compile(createCheckpointTemplateString);
|
||||
const createCheckpoint = createCheckpointTemplate({ subgraphPath });
|
||||
const createCheckpoint = createCheckpointTemplate({});
|
||||
checkpointCreateOutStream.write(createCheckpoint);
|
||||
|
||||
if (checkpointVerifyOutStream) {
|
||||
|
@ -12,6 +12,9 @@ columns:
|
||||
pgType: integer
|
||||
tsType: number
|
||||
columnType: Column
|
||||
columnOptions:
|
||||
- option: nullable
|
||||
value: true
|
||||
imports:
|
||||
- toImport:
|
||||
- Entity
|
||||
|
@ -13,9 +13,9 @@ const TEMPLATE_FILE = './templates/export-state-template.handlebars';
|
||||
* Writes the export-state file generated from a template to a stream.
|
||||
* @param outStream A writable output stream to write the export-state file to.
|
||||
*/
|
||||
export function exportState (outStream: Writable, subgraphPath: string): void {
|
||||
export function exportState (outStream: Writable): void {
|
||||
const templateString = fs.readFileSync(path.resolve(__dirname, TEMPLATE_FILE)).toString();
|
||||
const template = Handlebars.compile(templateString);
|
||||
const exportState = template({ subgraphPath });
|
||||
const exportState = template({});
|
||||
outStream.write(exportState);
|
||||
}
|
||||
|
@ -8,23 +8,14 @@ import Handlebars from 'handlebars';
|
||||
import { Writable } from 'stream';
|
||||
|
||||
const FILL_TEMPLATE_FILE = './templates/fill-template.handlebars';
|
||||
const FILL_STATE_TEMPLATE_FILE = './templates/fill-state-template.handlebars';
|
||||
|
||||
/**
|
||||
* Writes the fill file generated from a template to a stream.
|
||||
* @param fillOutStream A writable output stream to write the fill file to.
|
||||
* @param fillStateOutStream A writable output stream to write the fill state file to.
|
||||
*/
|
||||
export function exportFill (fillOutStream: Writable, fillStateOutStream: Writable | undefined, subgraphPath: string): void {
|
||||
export function exportFill (fillOutStream: Writable, subgraphPath: string): void {
|
||||
const templateString = fs.readFileSync(path.resolve(__dirname, FILL_TEMPLATE_FILE)).toString();
|
||||
const template = Handlebars.compile(templateString);
|
||||
const fill = template({ subgraphPath });
|
||||
fillOutStream.write(fill);
|
||||
|
||||
if (fillStateOutStream) {
|
||||
const templateString = fs.readFileSync(path.resolve(__dirname, FILL_STATE_TEMPLATE_FILE)).toString();
|
||||
const template = Handlebars.compile(templateString);
|
||||
const fillState = template({});
|
||||
fillStateOutStream.write(fillState);
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import { exportInspectCID } from './inspect-cid';
|
||||
import { getSubgraphConfig } from './utils/subgraph';
|
||||
import { exportIndexBlock } from './index-block';
|
||||
import { exportSubscriber } from './subscriber';
|
||||
import { exportReset } from './reset';
|
||||
|
||||
const main = async (): Promise<void> => {
|
||||
const argv = await yargs(hideBin(process.argv))
|
||||
@ -238,7 +239,14 @@ function generateWatcher (visitor: Visitor, contracts: any[], config: any) {
|
||||
outStream = outputDir
|
||||
? fs.createWriteStream(path.join(outputDir, 'src/cli/watch-contract.ts'))
|
||||
: process.stdout;
|
||||
exportWatchContract(outStream, config.subgraphPath);
|
||||
exportWatchContract(outStream);
|
||||
|
||||
const resetOutStream = fs.createWriteStream(path.join(outputDir, 'src/cli/reset.ts'));
|
||||
const resetJQOutStream = fs.createWriteStream(path.join(outputDir, 'src/cli/reset-cmds/job-queue.ts'));
|
||||
const resetWatcherOutStream = fs.createWriteStream(path.join(outputDir, 'src/cli/reset-cmds/watcher.ts'));
|
||||
const resetStateOutStream = fs.createWriteStream(path.join(outputDir, 'src/cli/reset-cmds/state.ts'));
|
||||
|
||||
exportReset(resetOutStream, resetJQOutStream, resetWatcherOutStream, resetStateOutStream);
|
||||
|
||||
let checkpointOutStream, checkpointCreateOutStream, checkpointVerifyOutStream;
|
||||
|
||||
@ -256,7 +264,7 @@ function generateWatcher (visitor: Visitor, contracts: any[], config: any) {
|
||||
}
|
||||
}
|
||||
|
||||
exportCheckpoint(checkpointOutStream, checkpointCreateOutStream, checkpointVerifyOutStream, config.subgraphPath);
|
||||
exportCheckpoint(checkpointOutStream, checkpointCreateOutStream, checkpointVerifyOutStream);
|
||||
|
||||
outStream = outputDir
|
||||
? fs.createWriteStream(path.join(outputDir, 'src/hooks.ts'))
|
||||
@ -266,15 +274,7 @@ function generateWatcher (visitor: Visitor, contracts: any[], config: any) {
|
||||
const fillOutStream = outputDir
|
||||
? fs.createWriteStream(path.join(outputDir, 'src/fill.ts'))
|
||||
: process.stdout;
|
||||
|
||||
let fillStateOutStream;
|
||||
if (config.subgraphPath) {
|
||||
fillStateOutStream = outputDir
|
||||
? fs.createWriteStream(path.join(outputDir, 'src/fill-state.ts'))
|
||||
: process.stdout;
|
||||
}
|
||||
|
||||
exportFill(fillOutStream, fillStateOutStream, config.subgraphPath);
|
||||
exportFill(fillOutStream, config.subgraphPath);
|
||||
|
||||
outStream = outputDir
|
||||
? fs.createWriteStream(path.join(outputDir, 'src/types.ts'))
|
||||
@ -298,27 +298,20 @@ function generateWatcher (visitor: Visitor, contracts: any[], config: any) {
|
||||
: process.stdout;
|
||||
visitor.exportClient(outStream, schemaContent, path.join(outputDir, 'src/gql'));
|
||||
|
||||
const resetOutStream = fs.createWriteStream(path.join(outputDir, 'src/cli/reset.ts'));
|
||||
const resetJQOutStream = fs.createWriteStream(path.join(outputDir, 'src/cli/reset-cmds/job-queue.ts'));
|
||||
const resetWatcherOutStream = fs.createWriteStream(path.join(outputDir, 'src/cli/reset-cmds/watcher.ts'));
|
||||
const resetStateOutStream = fs.createWriteStream(path.join(outputDir, 'src/cli/reset-cmds/state.ts'));
|
||||
|
||||
visitor.exportReset(resetOutStream, resetJQOutStream, resetWatcherOutStream, resetStateOutStream, config.subgraphPath);
|
||||
|
||||
outStream = outputDir
|
||||
? fs.createWriteStream(path.join(outputDir, 'src/cli/export-state.ts'))
|
||||
: process.stdout;
|
||||
exportState(outStream, config.subgraphPath);
|
||||
exportState(outStream);
|
||||
|
||||
outStream = outputDir
|
||||
? fs.createWriteStream(path.join(outputDir, 'src/cli/import-state.ts'))
|
||||
: process.stdout;
|
||||
importState(outStream, config.subgraphPath);
|
||||
importState(outStream);
|
||||
|
||||
outStream = outputDir
|
||||
? fs.createWriteStream(path.join(outputDir, 'src/cli/inspect-cid.ts'))
|
||||
: process.stdout;
|
||||
exportInspectCID(outStream, config.subgraphPath);
|
||||
exportInspectCID(outStream);
|
||||
|
||||
outStream = outputDir
|
||||
? fs.createWriteStream(path.join(outputDir, 'src/cli/index-block.ts'))
|
||||
|
@ -13,9 +13,9 @@ const TEMPLATE_FILE = './templates/import-state-template.handlebars';
|
||||
* Writes the import-state file generated from a template to a stream.
|
||||
* @param outStream A writable output stream to write the import-state file to.
|
||||
*/
|
||||
export function importState (outStream: Writable, subgraphPath: string): void {
|
||||
export function importState (outStream: Writable): void {
|
||||
const templateString = fs.readFileSync(path.resolve(__dirname, TEMPLATE_FILE)).toString();
|
||||
const template = Handlebars.compile(templateString);
|
||||
const importState = template({ subgraphPath });
|
||||
const importState = template({});
|
||||
outStream.write(importState);
|
||||
}
|
||||
|
@ -13,9 +13,9 @@ const TEMPLATE_FILE = './templates/inspect-cid-template.handlebars';
|
||||
* Writes the inspect-cid file generated from a template to a stream.
|
||||
* @param outStream A writable output stream to write the inspect-cid file to.
|
||||
*/
|
||||
export function exportInspectCID (outStream: Writable, subgraphPath: string): void {
|
||||
export function exportInspectCID (outStream: Writable): void {
|
||||
const templateString = fs.readFileSync(path.resolve(__dirname, TEMPLATE_FILE)).toString();
|
||||
const template = Handlebars.compile(templateString);
|
||||
const inspectCid = template({ subgraphPath });
|
||||
const inspectCid = template({});
|
||||
outStream.write(inspectCid);
|
||||
}
|
||||
|
@ -12,90 +12,31 @@ const RESET_JQ_TEMPLATE_FILE = './templates/reset-job-queue-template.handlebars'
|
||||
const RESET_WATCHER_TEMPLATE_FILE = './templates/reset-watcher-template.handlebars';
|
||||
const RESET_STATE_TEMPLATE_FILE = './templates/reset-state-template.handlebars';
|
||||
|
||||
export class Reset {
|
||||
_queries: Array<any>;
|
||||
_resetTemplateString: string;
|
||||
_resetJQTemplateString: string;
|
||||
_resetWatcherTemplateString: string;
|
||||
_resetStateTemplateString: string;
|
||||
/**
|
||||
* Writes the reset.ts, job-queue.ts, watcher.ts, state.ts files generated from templates to respective streams.
|
||||
* @param resetOutStream A writable output stream to write the reset file to.
|
||||
* @param resetJQOutStream A writable output stream to write the reset job-queue file to.
|
||||
* @param resetWatcherOutStream A writable output stream to write the reset watcher file to.
|
||||
* @param resetStateOutStream A writable output stream to write the reset state file to.
|
||||
*/
|
||||
export function exportReset (resetOutStream: Writable, resetJQOutStream: Writable, resetWatcherOutStream: Writable, resetStateOutStream: Writable): void {
|
||||
const resetTemplateString = fs.readFileSync(path.resolve(__dirname, RESET_TEMPLATE_FILE)).toString();
|
||||
const resetTemplate = Handlebars.compile(resetTemplateString);
|
||||
const resetString = resetTemplate({});
|
||||
resetOutStream.write(resetString);
|
||||
|
||||
constructor () {
|
||||
this._queries = [];
|
||||
this._resetTemplateString = fs.readFileSync(path.resolve(__dirname, RESET_TEMPLATE_FILE)).toString();
|
||||
this._resetJQTemplateString = fs.readFileSync(path.resolve(__dirname, RESET_JQ_TEMPLATE_FILE)).toString();
|
||||
this._resetWatcherTemplateString = fs.readFileSync(path.resolve(__dirname, RESET_WATCHER_TEMPLATE_FILE)).toString();
|
||||
this._resetStateTemplateString = fs.readFileSync(path.resolve(__dirname, RESET_STATE_TEMPLATE_FILE)).toString();
|
||||
}
|
||||
const resetJQTemplateString = fs.readFileSync(path.resolve(__dirname, RESET_JQ_TEMPLATE_FILE)).toString();
|
||||
const resetJQTemplate = Handlebars.compile(resetJQTemplateString);
|
||||
const resetJQString = resetJQTemplate({});
|
||||
resetJQOutStream.write(resetJQString);
|
||||
|
||||
/**
|
||||
* Stores the query to be passed to the template.
|
||||
* @param name Name of the query.
|
||||
*/
|
||||
addQuery (name: string): void {
|
||||
// Check if the query is already added.
|
||||
if (this._queries.some(query => query.name === name)) {
|
||||
return;
|
||||
}
|
||||
const resetWatcherTemplateString = fs.readFileSync(path.resolve(__dirname, RESET_WATCHER_TEMPLATE_FILE)).toString();
|
||||
const resetWatcherTemplate = Handlebars.compile(resetWatcherTemplateString);
|
||||
const resetWatcher = resetWatcherTemplate({});
|
||||
resetWatcherOutStream.write(resetWatcher);
|
||||
|
||||
const queryObject = {
|
||||
name,
|
||||
entityName: ''
|
||||
};
|
||||
|
||||
// eth_call mode: Capitalize first letter of entity name (balanceOf -> BalanceOf).
|
||||
// storage mode: Capiltalize second letter of entity name (_balances -> _Balances).
|
||||
queryObject.entityName = (name.charAt(0) === '_')
|
||||
? `_${name.charAt(1).toUpperCase()}${name.slice(2)}`
|
||||
: `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
|
||||
|
||||
this._queries.push(queryObject);
|
||||
}
|
||||
|
||||
addSubgraphEntities (subgraphSchemaDocument: any): void {
|
||||
const subgraphTypeDefs = subgraphSchemaDocument.definitions;
|
||||
|
||||
subgraphTypeDefs.forEach((def: any) => {
|
||||
if (def.kind !== 'ObjectTypeDefinition') {
|
||||
return;
|
||||
}
|
||||
|
||||
this._queries.push({
|
||||
entityName: def.name.value
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the reset.ts, job-queue.ts, state.ts files generated from templates to respective streams.
|
||||
* @param outStream A writable output stream to write the database file to.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Writes the reset.ts, job-queue.ts, watcher.ts, state.ts files generated from templates to respective streams.
|
||||
* @param resetOutStream A writable output stream to write the reset file to.
|
||||
* @param resetJQOutStream A writable output stream to write the reset job-queue file to.
|
||||
* @param resetWatcherOutStream A writable output stream to write the reset watcher file to.
|
||||
* @param resetStateOutStream A writable output stream to write the reset state file to.
|
||||
*/
|
||||
exportReset (resetOutStream: Writable, resetJQOutStream: Writable, resetWatcherOutStream: Writable, resetStateOutStream: Writable, subgraphPath: string): void {
|
||||
const resetTemplate = Handlebars.compile(this._resetTemplateString);
|
||||
const resetString = resetTemplate({});
|
||||
resetOutStream.write(resetString);
|
||||
|
||||
const resetJQTemplate = Handlebars.compile(this._resetJQTemplateString);
|
||||
const resetJQString = resetJQTemplate({});
|
||||
resetJQOutStream.write(resetJQString);
|
||||
|
||||
const resetWatcherTemplate = Handlebars.compile(this._resetWatcherTemplateString);
|
||||
const obj = {
|
||||
queries: this._queries,
|
||||
subgraphPath
|
||||
};
|
||||
const resetWatcher = resetWatcherTemplate(obj);
|
||||
resetWatcherOutStream.write(resetWatcher);
|
||||
|
||||
const resetStateTemplate = Handlebars.compile(this._resetStateTemplateString);
|
||||
const resetState = resetStateTemplate({});
|
||||
resetStateOutStream.write(resetState);
|
||||
}
|
||||
const resetStateTemplateString = fs.readFileSync(path.resolve(__dirname, RESET_STATE_TEMPLATE_FILE)).toString();
|
||||
const resetStateTemplate = Handlebars.compile(resetStateTemplateString);
|
||||
const resetState = resetStateTemplate({});
|
||||
resetStateOutStream.write(resetState);
|
||||
}
|
||||
|
@ -2,19 +2,11 @@
|
||||
// Copyright 2022 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import debug from 'debug';
|
||||
import assert from 'assert';
|
||||
|
||||
import { getConfig, initClients, JobQueue, Config } from '@cerc-io/util';
|
||||
{{#if (subgraphPath)}}
|
||||
import { GraphWatcher, Database as GraphDatabase } from '@cerc-io/graph-node';
|
||||
{{/if}}
|
||||
import { CreateCheckpointCmd } from '@cerc-io/cli';
|
||||
|
||||
import { Database } from '../../database';
|
||||
import { Indexer } from '../../indexer';
|
||||
|
||||
const log = debug('vulcanize:checkpoint-create');
|
||||
|
||||
export const command = 'create';
|
||||
|
||||
export const desc = 'Create checkpoint';
|
||||
@ -33,39 +25,8 @@ export const builder = {
|
||||
};
|
||||
|
||||
export const handler = async (argv: any): Promise<void> => {
|
||||
const config: Config = await getConfig(argv.configFile);
|
||||
const { ethClient, ethProvider } = await initClients(config);
|
||||
const createCheckpointCmd = new CreateCheckpointCmd();
|
||||
await createCheckpointCmd.init(argv, Database, Indexer);
|
||||
|
||||
const db = new Database(config.database);
|
||||
await db.init();
|
||||
|
||||
{{#if (subgraphPath)}}
|
||||
const graphDb = new GraphDatabase(config.server, db.baseDatabase);
|
||||
await graphDb.init();
|
||||
|
||||
const graphWatcher = new GraphWatcher(graphDb, ethClient, ethProvider, config.server);
|
||||
|
||||
{{/if}}
|
||||
const jobQueueConfig = config.jobQueue;
|
||||
assert(jobQueueConfig, 'Missing job queue config');
|
||||
|
||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
||||
|
||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
||||
await jobQueue.start();
|
||||
|
||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue{{#if (subgraphPath)}}, graphWatcher{{/if}});
|
||||
await indexer.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
graphWatcher.setIndexer(indexer);
|
||||
await graphWatcher.init();
|
||||
{{/if}}
|
||||
|
||||
const blockHash = await indexer.processCLICheckpoint(argv.address, argv.blockHash);
|
||||
|
||||
log(`Created a checkpoint for contract ${argv.address} at block-hash ${blockHash}`);
|
||||
|
||||
await db.close();
|
||||
await createCheckpointCmd.exec();
|
||||
};
|
||||
|
@ -2,65 +2,27 @@
|
||||
// Copyright 2022 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import path from 'path';
|
||||
import debug from 'debug';
|
||||
import assert from 'assert';
|
||||
import { VerifyCheckpointCmd } from '@cerc-io/cli';
|
||||
|
||||
import { getConfig, initClients, JobQueue, Config, verifyCheckpointData } from '@cerc-io/util';
|
||||
import { GraphWatcher, Database as GraphDatabase } from '@cerc-io/graph-node';
|
||||
|
||||
import { Database, ENTITY_TO_LATEST_ENTITY_MAP, ENTITY_QUERY_TYPE_MAP } from '../../database';
|
||||
import { Database } from '../../database';
|
||||
import { Indexer } from '../../indexer';
|
||||
|
||||
const log = debug('vulcanize:checkpoint-verify');
|
||||
|
||||
export const command = 'verify';
|
||||
|
||||
export const desc = 'Verify checkpoint';
|
||||
|
||||
export const builder = {
|
||||
cid: {
|
||||
alias: 'c',
|
||||
type: 'string',
|
||||
alias: 'c',
|
||||
demandOption: true,
|
||||
describe: 'Checkpoint CID to be verified'
|
||||
}
|
||||
};
|
||||
|
||||
export const handler = async (argv: any): Promise<void> => {
|
||||
const config: Config = await getConfig(argv.configFile);
|
||||
const { ethClient, ethProvider } = await initClients(config);
|
||||
const verifyCheckpointCmd = new VerifyCheckpointCmd();
|
||||
await verifyCheckpointCmd.init(argv, Database, Indexer);
|
||||
|
||||
const db = new Database(config.database);
|
||||
await db.init();
|
||||
|
||||
const graphDb = new GraphDatabase(config.server, db.baseDatabase, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP);
|
||||
await graphDb.init();
|
||||
|
||||
const graphWatcher = new GraphWatcher(graphDb, ethClient, ethProvider, config.server);
|
||||
|
||||
const jobQueueConfig = config.jobQueue;
|
||||
assert(jobQueueConfig, 'Missing job queue config');
|
||||
|
||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
||||
|
||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
||||
await jobQueue.start();
|
||||
|
||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue, graphWatcher);
|
||||
await indexer.init();
|
||||
|
||||
graphWatcher.setIndexer(indexer);
|
||||
await graphWatcher.init();
|
||||
|
||||
const state = await indexer.getStateByCID(argv.cid);
|
||||
assert(state, 'State for the provided CID doesn\'t exist.');
|
||||
const data = indexer.getStateData(state);
|
||||
|
||||
log(`Verifying checkpoint data for contract ${state.contractAddress}`);
|
||||
await verifyCheckpointData(graphDb, state.block, data);
|
||||
log('Checkpoint data verified');
|
||||
|
||||
await db.close();
|
||||
await verifyCheckpointCmd.exec();
|
||||
};
|
||||
|
@ -11,7 +11,8 @@ import {
|
||||
EventWatcher as BaseEventWatcher,
|
||||
EventWatcherInterface,
|
||||
QUEUE_BLOCK_PROCESSING,
|
||||
QUEUE_EVENT_PROCESSING
|
||||
QUEUE_EVENT_PROCESSING,
|
||||
IndexerInterface
|
||||
} from '@cerc-io/util';
|
||||
|
||||
import { Indexer } from './indexer';
|
||||
@ -24,12 +25,12 @@ export class EventWatcher implements EventWatcherInterface {
|
||||
_pubsub: PubSub
|
||||
_jobQueue: JobQueue
|
||||
|
||||
constructor (ethClient: EthClient, indexer: Indexer, pubsub: PubSub, jobQueue: JobQueue) {
|
||||
constructor (ethClient: EthClient, indexer: IndexerInterface, pubsub: PubSub, jobQueue: JobQueue) {
|
||||
assert(ethClient);
|
||||
assert(indexer);
|
||||
|
||||
this._ethClient = ethClient;
|
||||
this._indexer = indexer;
|
||||
this._indexer = indexer as Indexer;
|
||||
this._pubsub = pubsub;
|
||||
this._jobQueue = jobQueue;
|
||||
this._baseEventWatcher = new BaseEventWatcher(this._ethClient, this._indexer, this._pubsub, this._jobQueue);
|
||||
|
@ -2,163 +2,21 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import assert from 'assert';
|
||||
import yargs from 'yargs';
|
||||
import 'reflect-metadata';
|
||||
import debug from 'debug';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import {
|
||||
Config,
|
||||
DEFAULT_CONFIG_PATH,
|
||||
getConfig,
|
||||
initClients,
|
||||
JobQueue,
|
||||
{{#if (subgraphPath)}}
|
||||
{{/if}}
|
||||
StateKind
|
||||
} from '@cerc-io/util';
|
||||
{{#if (subgraphPath)}}
|
||||
import { GraphWatcher, Database as GraphDatabase } from '@cerc-io/graph-node';
|
||||
{{/if}}
|
||||
import * as codec from '@ipld/dag-cbor';
|
||||
import { ExportStateCmd } from '@cerc-io/cli';
|
||||
|
||||
import { Database{{#if (subgraphPath)}}, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP{{/if}} } from '../database';
|
||||
import { Database } from '../database';
|
||||
import { Indexer } from '../indexer';
|
||||
|
||||
const log = debug('vulcanize:export-state');
|
||||
|
||||
const main = async (): Promise<void> => {
|
||||
const argv = await yargs.parserConfiguration({
|
||||
'parse-numbers': false
|
||||
}).options({
|
||||
configFile: {
|
||||
alias: 'f',
|
||||
type: 'string',
|
||||
require: true,
|
||||
demandOption: true,
|
||||
describe: 'Configuration file path (toml)',
|
||||
default: DEFAULT_CONFIG_PATH
|
||||
},
|
||||
exportFile: {
|
||||
alias: 'o',
|
||||
type: 'string',
|
||||
describe: 'Export file path'
|
||||
},
|
||||
blockNumber: {
|
||||
type: 'number',
|
||||
describe: 'Block number to create snapshot at'
|
||||
}
|
||||
}).argv;
|
||||
const exportStateCmd = new ExportStateCmd();
|
||||
await exportStateCmd.init(Database, Indexer);
|
||||
|
||||
const config: Config = await getConfig(argv.configFile);
|
||||
const { ethClient, ethProvider } = await initClients(config);
|
||||
|
||||
const db = new Database(config.database);
|
||||
await db.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
const graphDb = new GraphDatabase(config.server, db.baseDatabase, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP);
|
||||
await graphDb.init();
|
||||
|
||||
const graphWatcher = new GraphWatcher(graphDb, ethClient, ethProvider, config.server);
|
||||
{{/if}}
|
||||
|
||||
const jobQueueConfig = config.jobQueue;
|
||||
assert(jobQueueConfig, 'Missing job queue config');
|
||||
|
||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
||||
|
||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
||||
await jobQueue.start();
|
||||
|
||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue{{#if (subgraphPath)}}, graphWatcher{{/if}});
|
||||
await indexer.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
graphWatcher.setIndexer(indexer);
|
||||
await graphWatcher.init();
|
||||
{{/if}}
|
||||
|
||||
const exportData: any = {
|
||||
snapshotBlock: {},
|
||||
contracts: [],
|
||||
stateCheckpoints: []
|
||||
};
|
||||
|
||||
const contracts = await db.getContracts();
|
||||
|
||||
// Get latest block with hooks processed.
|
||||
let block = await indexer.getLatestStateIndexedBlock();
|
||||
assert(block);
|
||||
|
||||
if (argv.blockNumber) {
|
||||
if (argv.blockNumber > block.blockNumber) {
|
||||
throw new Error(`Export snapshot block height ${argv.blockNumber} should be less than latest state indexed block height ${block.blockNumber}`);
|
||||
}
|
||||
|
||||
const blocksAtSnapshotHeight = await indexer.getBlocksAtHeight(argv.blockNumber, false);
|
||||
|
||||
if (!blocksAtSnapshotHeight.length) {
|
||||
throw new Error(`No blocks at snapshot height ${argv.blockNumber}`);
|
||||
}
|
||||
|
||||
block = blocksAtSnapshotHeight[0];
|
||||
}
|
||||
|
||||
log(`Creating export snapshot at block height ${block.blockNumber}`);
|
||||
|
||||
// Export snapshot block.
|
||||
exportData.snapshotBlock = {
|
||||
blockNumber: block.blockNumber,
|
||||
blockHash: block.blockHash
|
||||
};
|
||||
|
||||
// Export contracts and checkpoints.
|
||||
for (const contract of contracts) {
|
||||
if (contract.startingBlock > block.blockNumber) {
|
||||
continue;
|
||||
}
|
||||
|
||||
exportData.contracts.push({
|
||||
address: contract.address,
|
||||
kind: contract.kind,
|
||||
checkpoint: contract.checkpoint,
|
||||
startingBlock: block.blockNumber
|
||||
});
|
||||
|
||||
// Create and export checkpoint if checkpointing is on for the contract.
|
||||
if (contract.checkpoint) {
|
||||
await indexer.createCheckpoint(contract.address, block.blockHash);
|
||||
|
||||
const state = await indexer.getLatestState(contract.address, StateKind.Checkpoint, block.blockNumber);
|
||||
assert(state);
|
||||
|
||||
const data = indexer.getStateData(state);
|
||||
|
||||
exportData.stateCheckpoints.push({
|
||||
contractAddress: state.contractAddress,
|
||||
cid: state.cid,
|
||||
kind: state.kind,
|
||||
data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (argv.exportFile) {
|
||||
const encodedExportData = codec.encode(exportData);
|
||||
|
||||
const filePath = path.resolve(argv.exportFile);
|
||||
const fileDir = path.dirname(filePath);
|
||||
|
||||
if (!fs.existsSync(fileDir)) fs.mkdirSync(fileDir, { recursive: true });
|
||||
|
||||
fs.writeFileSync(filePath, encodedExportData);
|
||||
} else {
|
||||
log(exportData);
|
||||
}
|
||||
await exportStateCmd.exec();
|
||||
};
|
||||
|
||||
main().catch(err => {
|
||||
|
@ -1,104 +0,0 @@
|
||||
//
|
||||
// Copyright 2022 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import 'reflect-metadata';
|
||||
import debug from 'debug';
|
||||
import { Between } from 'typeorm';
|
||||
|
||||
import { Database as GraphDatabase, prepareEntityState } from '@cerc-io/graph-node';
|
||||
|
||||
import { Indexer } from './indexer';
|
||||
|
||||
const log = debug('vulcanize:fill-state');
|
||||
|
||||
export const fillState = async (
|
||||
indexer: Indexer,
|
||||
graphDb: GraphDatabase,
|
||||
dataSources: any[],
|
||||
argv: {
|
||||
startBlock: number,
|
||||
endBlock: number
|
||||
}
|
||||
): Promise<void> => {
|
||||
const { startBlock, endBlock } = argv;
|
||||
if (startBlock > endBlock) {
|
||||
log('endBlock should be greater than or equal to startBlock');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// NOTE: Assuming all blocks in the given range are in the pruned region
|
||||
log(`Filling state for subgraph entities in range: [${startBlock}, ${endBlock}]`);
|
||||
|
||||
// Check that there are no existing diffs in this range
|
||||
const existingStates = await indexer.getStates({ block: { blockNumber: Between(startBlock, endBlock) } });
|
||||
if (existingStates.length > 0) {
|
||||
log('found existing state(s) in the given range');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Map: contractAddress -> entities updated
|
||||
const contractEntitiesMap: Map<string, string[]> = new Map();
|
||||
|
||||
// Populate contractEntitiesMap using data sources from subgraph
|
||||
// NOTE: Assuming each entity type is only mapped to a single contract
|
||||
// This is true for eden subgraph; may not be the case for other subgraphs
|
||||
dataSources.forEach((dataSource: any) => {
|
||||
const { source: { address: contractAddress }, mapping: { entities } } = dataSource;
|
||||
contractEntitiesMap.set(contractAddress, entities as string[]);
|
||||
});
|
||||
|
||||
// Fill state for blocks in the given range
|
||||
for (let blockNumber = startBlock; blockNumber <= endBlock; blockNumber++) {
|
||||
// Get the canonical block hash at current height
|
||||
const blocks = await indexer.getBlocksAtHeight(blockNumber, false);
|
||||
|
||||
if (blocks.length === 0) {
|
||||
log(`block not found at height ${blockNumber}`);
|
||||
process.exit(1);
|
||||
} else if (blocks.length > 1) {
|
||||
log(`found more than one non-pruned block at height ${blockNumber}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const blockHash = blocks[0].blockHash;
|
||||
|
||||
// Create initial state for contracts
|
||||
await indexer.createInit(blockHash, blockNumber);
|
||||
|
||||
// Fill state for each contract in contractEntitiesMap
|
||||
const contractStatePromises = Array.from(contractEntitiesMap.entries())
|
||||
.map(async ([contractAddress, entities]): Promise<void> => {
|
||||
// Get all the updated entities at this block
|
||||
const updatedEntitiesListPromises = entities.map(async (entity): Promise<any[]> => {
|
||||
return graphDb.getEntitiesForBlock(blockHash, entity);
|
||||
});
|
||||
const updatedEntitiesList = await Promise.all(updatedEntitiesListPromises);
|
||||
|
||||
// Populate state with all the updated entities of each entity type
|
||||
updatedEntitiesList.forEach((updatedEntities, index) => {
|
||||
const entityName = entities[index];
|
||||
|
||||
updatedEntities.forEach((updatedEntity) => {
|
||||
// Prepare diff data for the entity update
|
||||
const diffData = prepareEntityState(updatedEntity, entityName, indexer.getRelationsMap());
|
||||
|
||||
// Update the in-memory subgraph state
|
||||
indexer.updateSubgraphState(contractAddress, diffData);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
await Promise.all(contractStatePromises);
|
||||
|
||||
// Persist subgraph state to the DB
|
||||
await indexer.dumpSubgraphState(blockHash, true);
|
||||
await indexer.updateStateSyncStatusIndexedBlock(blockNumber);
|
||||
|
||||
// Create checkpoints
|
||||
await indexer.processCheckpoint(blockHash);
|
||||
await indexer.updateStateSyncStatusCheckpointBlock(blockNumber);
|
||||
}
|
||||
|
||||
log(`Filled state for subgraph entities in range: [${startBlock}, ${endBlock}]`);
|
||||
};
|
@ -2,113 +2,37 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import assert from 'assert';
|
||||
import 'reflect-metadata';
|
||||
import yargs from 'yargs';
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import debug from 'debug';
|
||||
import { PubSub } from 'graphql-subscriptions';
|
||||
|
||||
import { Config, getConfig, fillBlocks, JobQueue, DEFAULT_CONFIG_PATH, initClients } from '@cerc-io/util';
|
||||
{{#if (subgraphPath)}}
|
||||
import { GraphWatcher, Database as GraphDatabase } from '@cerc-io/graph-node';
|
||||
import assert from 'assert';
|
||||
{{/if}}
|
||||
import 'reflect-metadata';
|
||||
import debug from 'debug';
|
||||
|
||||
import { FillCmd } from '@cerc-io/cli';
|
||||
{{#if (subgraphPath)}}
|
||||
import { getContractEntitiesMap } from '@cerc-io/graph-node';
|
||||
{{/if}}
|
||||
|
||||
import { Database{{#if (subgraphPath)}}, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP{{/if}} } from './database';
|
||||
import { Indexer } from './indexer';
|
||||
import { EventWatcher } from './events';
|
||||
{{#if (subgraphPath)}}
|
||||
import { fillState } from './fill-state';
|
||||
{{/if}}
|
||||
|
||||
const log = debug('vulcanize:server');
|
||||
const log = debug('vulcanize:fill');
|
||||
|
||||
export const main = async (): Promise<any> => {
|
||||
const argv = await yargs(hideBin(process.argv)).parserConfiguration({
|
||||
'parse-numbers': false
|
||||
}).env(
|
||||
'FILL'
|
||||
).options({
|
||||
configFile: {
|
||||
alias: 'f',
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
describe: 'configuration file path (toml)',
|
||||
default: DEFAULT_CONFIG_PATH
|
||||
},
|
||||
startBlock: {
|
||||
type: 'number',
|
||||
demandOption: true,
|
||||
describe: 'Block number to start processing at'
|
||||
},
|
||||
{{#if (subgraphPath)}}
|
||||
state: {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
describe: 'Fill state for subgraph entities'
|
||||
},
|
||||
{{/if}}
|
||||
endBlock: {
|
||||
type: 'number',
|
||||
demandOption: true,
|
||||
describe: 'Block number to stop processing at'
|
||||
},
|
||||
prefetch: {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
describe: 'Block and events prefetch mode'
|
||||
},
|
||||
batchBlocks: {
|
||||
type: 'number',
|
||||
default: 10,
|
||||
describe: 'Number of blocks prefetched in batch'
|
||||
}
|
||||
}).argv;
|
||||
const fillCmd = new FillCmd();
|
||||
await fillCmd.init(Database, Indexer, EventWatcher{{#if (subgraphPath)}}, {}, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP{{/if}});
|
||||
|
||||
const config: Config = await getConfig(argv.configFile);
|
||||
const { ethClient, ethProvider } = await initClients(config);
|
||||
|
||||
const db = new Database(config.database);
|
||||
await db.init();
|
||||
{{#if (subgraphPath)}}
|
||||
const indexer = fillCmd.indexer as Indexer;
|
||||
assert(indexer);
|
||||
|
||||
const graphDb = new GraphDatabase(config.server, db.baseDatabase, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP);
|
||||
await graphDb.init();
|
||||
// Get contractEntitiesMap required for fill-state
|
||||
// NOTE: Assuming each entity type is only mapped to a single contract
|
||||
const contractEntitiesMap = getContractEntitiesMap(indexer.graphWatcher.dataSources);
|
||||
|
||||
const graphWatcher = new GraphWatcher(graphDb, ethClient, ethProvider, config.server);
|
||||
{{/if}}
|
||||
|
||||
const jobQueueConfig = config.jobQueue;
|
||||
assert(jobQueueConfig, 'Missing job queue config');
|
||||
|
||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
||||
|
||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
||||
await jobQueue.start();
|
||||
|
||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue{{#if (subgraphPath)}}, graphWatcher{{/if}});
|
||||
await indexer.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
graphWatcher.setIndexer(indexer);
|
||||
await graphWatcher.init();
|
||||
|
||||
if (argv.state) {
|
||||
assert(config.server.enableState, 'State creation disabled');
|
||||
await fillState(indexer, graphDb, graphWatcher.dataSources, argv);
|
||||
|
||||
return;
|
||||
}
|
||||
{{/if}}
|
||||
|
||||
// Note: In-memory pubsub works fine for now, as each watcher is a single process anyway.
|
||||
// Later: https://www.apollographql.com/docs/apollo-server/data/subscriptions/#production-pubsub-libraries
|
||||
const pubsub = new PubSub();
|
||||
|
||||
const eventWatcher = new EventWatcher(ethClient, indexer, pubsub, jobQueue);
|
||||
|
||||
await fillBlocks(jobQueue, indexer, eventWatcher, jobQueueConfig.blockDelayInMilliSecs, argv);
|
||||
await fillCmd.exec({{#if (subgraphPath)}}contractEntitiesMap{{/if}});
|
||||
};
|
||||
|
||||
main().catch(err => {
|
||||
|
@ -37,7 +37,7 @@ export async function createInitialState (indexer: Indexer, contractAddress: str
|
||||
|
||||
/**
|
||||
* Hook function to create state diff.
|
||||
* @param indexer Indexer instance that contains methods to fetch the contract varaiable values.
|
||||
* @param indexer Indexer instance that contains methods to fetch the contract variable values.
|
||||
* @param blockHash Block hash of the concerned block.
|
||||
*/
|
||||
export async function createStateDiff (indexer: Indexer, blockHash: string): Promise<void> {
|
||||
|
@ -2,22 +2,12 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import assert from 'assert';
|
||||
import 'reflect-metadata';
|
||||
import yargs from 'yargs';
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import debug from 'debug';
|
||||
import { PubSub } from 'graphql-subscriptions';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { getConfig, fillBlocks, JobQueue, DEFAULT_CONFIG_PATH, Config, initClients, StateKind } from '@cerc-io/util';
|
||||
{{#if (subgraphPath)}}
|
||||
import { GraphWatcher, Database as GraphDatabase } from '@cerc-io/graph-node';
|
||||
{{/if}}
|
||||
import * as codec from '@ipld/dag-cbor';
|
||||
import { ImportStateCmd } from '@cerc-io/cli';
|
||||
|
||||
import { Database{{#if (subgraphPath)}}, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP{{/if}} } from '../database';
|
||||
import { Database } from '../database';
|
||||
import { Indexer } from '../indexer';
|
||||
import { EventWatcher } from '../events';
|
||||
import { State } from '../entity/State';
|
||||
@ -25,115 +15,10 @@ import { State } from '../entity/State';
|
||||
const log = debug('vulcanize:import-state');
|
||||
|
||||
export const main = async (): Promise<any> => {
|
||||
const argv = await yargs(hideBin(process.argv)).parserConfiguration({
|
||||
'parse-numbers': false
|
||||
}).options({
|
||||
configFile: {
|
||||
alias: 'f',
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
describe: 'configuration file path (toml)',
|
||||
default: DEFAULT_CONFIG_PATH
|
||||
},
|
||||
importFile: {
|
||||
alias: 'i',
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
describe: 'Import file path (JSON)'
|
||||
}
|
||||
}).argv;
|
||||
const importStateCmd = new ImportStateCmd();
|
||||
await importStateCmd.init(Database, Indexer, EventWatcher);
|
||||
|
||||
const config: Config = await getConfig(argv.configFile);
|
||||
const { ethClient, ethProvider } = await initClients(config);
|
||||
|
||||
const db = new Database(config.database);
|
||||
await db.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
const graphDb = new GraphDatabase(config.server, db.baseDatabase, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP);
|
||||
await graphDb.init();
|
||||
|
||||
const graphWatcher = new GraphWatcher(graphDb, ethClient, ethProvider, config.server);
|
||||
{{/if}}
|
||||
|
||||
// Note: In-memory pubsub works fine for now, as each watcher is a single process anyway.
|
||||
// Later: https://www.apollographql.com/docs/apollo-server/data/subscriptions/#production-pubsub-libraries
|
||||
const pubsub = new PubSub();
|
||||
|
||||
const jobQueueConfig = config.jobQueue;
|
||||
assert(jobQueueConfig, 'Missing job queue config');
|
||||
|
||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
||||
|
||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
||||
await jobQueue.start();
|
||||
|
||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue{{#if (subgraphPath)}}, graphWatcher{{/if}});
|
||||
await indexer.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
graphWatcher.setIndexer(indexer);
|
||||
await graphWatcher.init();
|
||||
{{/if}}
|
||||
|
||||
const eventWatcher = new EventWatcher(ethClient, indexer, pubsub, jobQueue);
|
||||
|
||||
// Import data.
|
||||
const importFilePath = path.resolve(argv.importFile);
|
||||
const encodedImportData = fs.readFileSync(importFilePath);
|
||||
const importData = codec.decode(Buffer.from(encodedImportData)) as any;
|
||||
|
||||
// Fill the snapshot block.
|
||||
await fillBlocks(
|
||||
jobQueue,
|
||||
indexer,
|
||||
eventWatcher,
|
||||
jobQueueConfig.blockDelayInMilliSecs,
|
||||
{
|
||||
prefetch: true,
|
||||
startBlock: importData.snapshotBlock.blockNumber,
|
||||
endBlock: importData.snapshotBlock.blockNumber
|
||||
}
|
||||
);
|
||||
|
||||
// Fill the Contracts.
|
||||
for (const contract of importData.contracts) {
|
||||
await indexer.watchContract(contract.address, contract.kind, contract.checkpoint, contract.startingBlock);
|
||||
}
|
||||
|
||||
// Get the snapshot block.
|
||||
const block = await indexer.getBlockProgress(importData.snapshotBlock.blockHash);
|
||||
assert(block);
|
||||
|
||||
// Fill the States.
|
||||
for (const checkpoint of importData.stateCheckpoints) {
|
||||
let state = new State();
|
||||
|
||||
state = Object.assign(state, checkpoint);
|
||||
state.block = block;
|
||||
|
||||
state.data = Buffer.from(codec.encode(state.data));
|
||||
|
||||
state = await indexer.saveOrUpdateState(state);
|
||||
{{#if (subgraphPath)}}
|
||||
await graphWatcher.updateEntitiesFromState(state);
|
||||
{{/if}}
|
||||
}
|
||||
|
||||
// Mark snapshot block as completely processed.
|
||||
block.isComplete = true;
|
||||
await indexer.updateBlockProgress(block, block.lastProcessedEventIndex);
|
||||
await indexer.updateSyncStatusChainHead(block.blockHash, block.blockNumber);
|
||||
await indexer.updateSyncStatusIndexedBlock(block.blockHash, block.blockNumber);
|
||||
await indexer.updateStateSyncStatusIndexedBlock(block.blockNumber);
|
||||
await indexer.updateStateSyncStatusCheckpointBlock(block.blockNumber);
|
||||
|
||||
// The 'diff_staged' and 'init' State entries are unnecessary as checkpoints have been already created for the snapshot block.
|
||||
await indexer.removeStates(block.blockNumber, StateKind.Init);
|
||||
await indexer.removeStates(block.blockNumber, StateKind.DiffStaged);
|
||||
|
||||
log(`Import completed for snapshot block at height ${block.blockNumber}`);
|
||||
await importStateCmd.exec(State);
|
||||
};
|
||||
|
||||
main().catch(err => {
|
||||
|
@ -2,73 +2,21 @@
|
||||
// Copyright 2022 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import yargs from 'yargs';
|
||||
import 'reflect-metadata';
|
||||
import debug from 'debug';
|
||||
import assert from 'assert';
|
||||
|
||||
import { Config, DEFAULT_CONFIG_PATH, getConfig, initClients, JobQueue, indexBlock } from '@cerc-io/util';
|
||||
{{#if (subgraphPath)}}
|
||||
import { GraphWatcher, Database as GraphDatabase } from '@cerc-io/graph-node';
|
||||
{{/if}}
|
||||
import { IndexBlockCmd } from '@cerc-io/cli';
|
||||
|
||||
import { Database{{#if (subgraphPath)}}, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP{{/if}} } from '../database';
|
||||
import { Database } from '../database';
|
||||
import { Indexer } from '../indexer';
|
||||
|
||||
const log = debug('vulcanize:index-block');
|
||||
|
||||
const main = async (): Promise<void> => {
|
||||
const argv = await yargs.parserConfiguration({
|
||||
'parse-numbers': false
|
||||
}).options({
|
||||
configFile: {
|
||||
alias: 'f',
|
||||
type: 'string',
|
||||
require: true,
|
||||
demandOption: true,
|
||||
describe: 'Configuration file path (toml)',
|
||||
default: DEFAULT_CONFIG_PATH
|
||||
},
|
||||
block: {
|
||||
type: 'number',
|
||||
require: true,
|
||||
demandOption: true,
|
||||
describe: 'Block number to index'
|
||||
}
|
||||
}).argv;
|
||||
const indexBlockCmd = new IndexBlockCmd();
|
||||
await indexBlockCmd.init(Database, Indexer);
|
||||
|
||||
const config: Config = await getConfig(argv.configFile);
|
||||
const { ethClient, ethProvider } = await initClients(config);
|
||||
|
||||
const db = new Database(config.database);
|
||||
await db.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
const graphDb = new GraphDatabase(config.server, db.baseDatabase, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP);
|
||||
await graphDb.init();
|
||||
|
||||
const graphWatcher = new GraphWatcher(graphDb, ethClient, ethProvider, config.server);
|
||||
{{/if}}
|
||||
|
||||
const jobQueueConfig = config.jobQueue;
|
||||
assert(jobQueueConfig, 'Missing job queue config');
|
||||
|
||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
||||
|
||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
||||
|
||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue{{#if (subgraphPath)}}, graphWatcher{{/if}});
|
||||
await indexer.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
graphWatcher.setIndexer(indexer);
|
||||
await graphWatcher.init();
|
||||
{{/if}}
|
||||
|
||||
await indexBlock(indexer, jobQueueConfig.eventsInBatch, argv);
|
||||
|
||||
await db.close();
|
||||
await indexBlockCmd.exec();
|
||||
};
|
||||
|
||||
main().catch(err => {
|
||||
|
@ -31,7 +31,9 @@ import {
|
||||
StateKind,
|
||||
StateStatus,
|
||||
ResultEvent,
|
||||
getResultEvent
|
||||
getResultEvent,
|
||||
DatabaseInterface,
|
||||
Clients
|
||||
} from '@cerc-io/util';
|
||||
{{#if (subgraphPath)}}
|
||||
import { GraphWatcher, updateSubgraphState, dumpSubgraphState } from '@cerc-io/graph-node';
|
||||
@ -87,16 +89,17 @@ export class Indexer implements IndexerInterface {
|
||||
_subgraphStateMap: Map<string, any>
|
||||
|
||||
{{/if}}
|
||||
constructor (serverConfig: ServerConfig, db: Database, ethClient: EthClient, ethProvider: BaseProvider, jobQueue: JobQueue{{#if (subgraphPath)}}, graphWatcher: GraphWatcher{{/if}}) {
|
||||
constructor (serverConfig: ServerConfig, db: DatabaseInterface, clients: Clients, ethProvider: BaseProvider, jobQueue: JobQueue{{#if (subgraphPath)}}, graphWatcher?: GraphWatcher{{/if}}) {
|
||||
assert(db);
|
||||
assert(ethClient);
|
||||
assert(clients.ethClient);
|
||||
|
||||
this._db = db;
|
||||
this._ethClient = ethClient;
|
||||
this._db = db as Database;
|
||||
this._ethClient = clients.ethClient;
|
||||
this._ethProvider = ethProvider;
|
||||
this._serverConfig = serverConfig;
|
||||
this._baseIndexer = new BaseIndexer(this._serverConfig, this._db, this._ethClient, this._ethProvider, jobQueue);
|
||||
{{#if (subgraphPath)}}
|
||||
assert(graphWatcher);
|
||||
this._graphWatcher = graphWatcher;
|
||||
{{/if}}
|
||||
|
||||
@ -105,12 +108,7 @@ export class Indexer implements IndexerInterface {
|
||||
this._contractMap = new Map();
|
||||
{{#each contracts as | contract |}}
|
||||
|
||||
const {
|
||||
abi: {{contract.contractName}}ABI,
|
||||
{{#if contract.contractStorageLayout}}
|
||||
storageLayout: {{contract.contractName}}StorageLayout
|
||||
{{/if}}
|
||||
} = {{contract.contractName}}Artifacts;
|
||||
const { abi: {{contract.contractName}}ABI{{#if contract.contractStorageLayout}}, storageLayout: {{contract.contractName}}StorageLayout{{/if}} } = {{contract.contractName}}Artifacts;
|
||||
{{/each}}
|
||||
{{#each contracts as | contract |}}
|
||||
|
||||
|
@ -2,16 +2,10 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import assert from 'assert';
|
||||
import yargs from 'yargs';
|
||||
import 'reflect-metadata';
|
||||
import debug from 'debug';
|
||||
import util from 'util';
|
||||
|
||||
import { Config, DEFAULT_CONFIG_PATH, getConfig, initClients, JobQueue } from '@cerc-io/util';
|
||||
{{#if (subgraphPath)}}
|
||||
import { GraphWatcher, Database as GraphDatabase } from '@cerc-io/graph-node';
|
||||
{{/if}}
|
||||
import { InspectCIDCmd } from '@cerc-io/cli';
|
||||
|
||||
import { Database } from '../database';
|
||||
import { Indexer } from '../indexer';
|
||||
@ -19,61 +13,10 @@ import { Indexer } from '../indexer';
|
||||
const log = debug('vulcanize:inspect-cid');
|
||||
|
||||
const main = async (): Promise<void> => {
|
||||
const argv = await yargs.parserConfiguration({
|
||||
'parse-numbers': false
|
||||
}).options({
|
||||
configFile: {
|
||||
alias: 'f',
|
||||
type: 'string',
|
||||
require: true,
|
||||
demandOption: true,
|
||||
describe: 'Configuration file path (toml)',
|
||||
default: DEFAULT_CONFIG_PATH
|
||||
},
|
||||
cid: {
|
||||
alias: 'c',
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
describe: 'CID to be inspected'
|
||||
}
|
||||
}).argv;
|
||||
const inspectCIDCmd = new InspectCIDCmd();
|
||||
await inspectCIDCmd.init(Database, Indexer);
|
||||
|
||||
const config: Config = await getConfig(argv.configFile);
|
||||
const { ethClient, ethProvider } = await initClients(config);
|
||||
|
||||
const db = new Database(config.database);
|
||||
await db.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
const graphDb = new GraphDatabase(config.server, db.baseDatabase);
|
||||
await graphDb.init();
|
||||
|
||||
const graphWatcher = new GraphWatcher(graphDb, ethClient, ethProvider, config.server);
|
||||
{{/if}}
|
||||
|
||||
const jobQueueConfig = config.jobQueue;
|
||||
assert(jobQueueConfig, 'Missing job queue config');
|
||||
|
||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
||||
|
||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
||||
await jobQueue.start();
|
||||
|
||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue{{#if (subgraphPath)}}, graphWatcher{{/if}});
|
||||
await indexer.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
graphWatcher.setIndexer(indexer);
|
||||
await graphWatcher.init();
|
||||
{{/if}}
|
||||
|
||||
const state = await indexer.getStateByCID(argv.cid);
|
||||
assert(state, 'State for the provided CID doesn\'t exist.');
|
||||
|
||||
const stateData = await indexer.getStateData(state);
|
||||
|
||||
log(util.inspect(stateData, false, null));
|
||||
await inspectCIDCmd.exec();
|
||||
};
|
||||
|
||||
main().catch(err => {
|
||||
|
@ -2,130 +2,26 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import assert from 'assert';
|
||||
import 'reflect-metadata';
|
||||
import yargs from 'yargs';
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import debug from 'debug';
|
||||
|
||||
import {
|
||||
getConfig,
|
||||
Config,
|
||||
JobQueue,
|
||||
JobRunner as BaseJobRunner,
|
||||
QUEUE_BLOCK_PROCESSING,
|
||||
QUEUE_EVENT_PROCESSING,
|
||||
QUEUE_BLOCK_CHECKPOINT,
|
||||
QUEUE_HOOKS,
|
||||
JOB_KIND_PRUNE,
|
||||
JobQueueConfig,
|
||||
DEFAULT_CONFIG_PATH,
|
||||
initClients,
|
||||
startMetricsServer
|
||||
} from '@cerc-io/util';
|
||||
{{#if (subgraphPath)}}
|
||||
import { GraphWatcher, Database as GraphDatabase } from '@cerc-io/graph-node';
|
||||
{{/if}}
|
||||
import { JobRunnerCmd } from '@cerc-io/cli';
|
||||
import { JobRunner } from '@cerc-io/util';
|
||||
|
||||
import { Indexer } from './indexer';
|
||||
import { Database{{#if (subgraphPath)}}, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP{{/if}} } from './database';
|
||||
|
||||
const log = debug('vulcanize:job-runner');
|
||||
|
||||
export class JobRunner {
|
||||
_indexer: Indexer
|
||||
_jobQueue: JobQueue
|
||||
_baseJobRunner: BaseJobRunner
|
||||
_jobQueueConfig: JobQueueConfig
|
||||
|
||||
constructor (jobQueueConfig: JobQueueConfig, indexer: Indexer, jobQueue: JobQueue) {
|
||||
this._jobQueueConfig = jobQueueConfig;
|
||||
this._indexer = indexer;
|
||||
this._jobQueue = jobQueue;
|
||||
this._baseJobRunner = new BaseJobRunner(this._jobQueueConfig, this._indexer, this._jobQueue);
|
||||
}
|
||||
|
||||
async start (): Promise<void> {
|
||||
await this._jobQueue.deleteAllJobs();
|
||||
await this._baseJobRunner.resetToPrevIndexedBlock();
|
||||
await this.subscribeBlockProcessingQueue();
|
||||
await this.subscribeEventProcessingQueue();
|
||||
await this.subscribeBlockCheckpointQueue();
|
||||
await this.subscribeHooksQueue();
|
||||
}
|
||||
|
||||
async subscribeBlockProcessingQueue (): Promise<void> {
|
||||
await this._jobQueue.subscribe(QUEUE_BLOCK_PROCESSING, async (job) => {
|
||||
await this._baseJobRunner.processBlock(job);
|
||||
});
|
||||
}
|
||||
|
||||
async subscribeEventProcessingQueue (): Promise<void> {
|
||||
await this._jobQueue.subscribe(QUEUE_EVENT_PROCESSING, async (job) => {
|
||||
await this._baseJobRunner.processEvent(job);
|
||||
});
|
||||
}
|
||||
|
||||
async subscribeHooksQueue (): Promise<void> {
|
||||
await this._jobQueue.subscribe(QUEUE_HOOKS, async (job) => {
|
||||
await this._baseJobRunner.processHooks(job);
|
||||
});
|
||||
}
|
||||
|
||||
async subscribeBlockCheckpointQueue (): Promise<void> {
|
||||
await this._jobQueue.subscribe(QUEUE_BLOCK_CHECKPOINT, async (job) => {
|
||||
await this._baseJobRunner.processCheckpoint(job);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const main = async (): Promise<any> => {
|
||||
const argv = await yargs(hideBin(process.argv))
|
||||
.option('f', {
|
||||
alias: 'config-file',
|
||||
demandOption: true,
|
||||
describe: 'configuration file path (toml)',
|
||||
type: 'string',
|
||||
default: DEFAULT_CONFIG_PATH
|
||||
})
|
||||
.argv;
|
||||
const jobRunnerCmd = new JobRunnerCmd();
|
||||
await jobRunnerCmd.init(Database, Indexer{{#if (subgraphPath)}}, {}, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP{{/if}});
|
||||
|
||||
const config: Config = await getConfig(argv.f);
|
||||
const { ethClient, ethProvider } = await initClients(config);
|
||||
|
||||
const db = new Database(config.database);
|
||||
await db.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
const graphDb = new GraphDatabase(config.server, db.baseDatabase, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP);
|
||||
await graphDb.init();
|
||||
|
||||
const graphWatcher = new GraphWatcher(graphDb, ethClient, ethProvider, config.server);
|
||||
{{/if}}
|
||||
|
||||
const jobQueueConfig = config.jobQueue;
|
||||
assert(jobQueueConfig, 'Missing job queue config');
|
||||
|
||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
||||
|
||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
||||
await jobQueue.start();
|
||||
|
||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue{{#if (subgraphPath)}}, graphWatcher{{/if}});
|
||||
await indexer.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
graphWatcher.setIndexer(indexer);
|
||||
await graphWatcher.init();
|
||||
|
||||
await indexer.addContracts();
|
||||
{{/if}}
|
||||
|
||||
const jobRunner = new JobRunner(jobQueueConfig, indexer, jobQueue);
|
||||
await jobRunner.start();
|
||||
|
||||
startMetricsServer(config, indexer);
|
||||
await jobRunnerCmd.exec(async (jobRunner: JobRunner): Promise<void> => {
|
||||
await jobRunner.subscribeBlockProcessingQueue();
|
||||
await jobRunner.subscribeEventProcessingQueue();
|
||||
await jobRunner.subscribeBlockCheckpointQueue();
|
||||
await jobRunner.subscribeHooksQueue();
|
||||
});
|
||||
};
|
||||
|
||||
main().then(() => {
|
||||
|
@ -42,18 +42,18 @@
|
||||
"@apollo/client": "^3.3.19",
|
||||
"@ethersproject/providers": "^5.4.4",
|
||||
"@ipld/dag-cbor": "^6.0.12",
|
||||
"@cerc-io/ipld-eth-client": "^0.2.13",
|
||||
"@cerc-io/solidity-mapper": "^0.2.13",
|
||||
"@cerc-io/util": "^0.2.13",
|
||||
"@cerc-io/cli": "^0.2.15",
|
||||
"@cerc-io/ipld-eth-client": "^0.2.15",
|
||||
"@cerc-io/solidity-mapper": "^0.2.15",
|
||||
"@cerc-io/util": "^0.2.15",
|
||||
{{#if (subgraphPath)}}
|
||||
"@cerc-io/graph-node": "^0.2.13",
|
||||
"@cerc-io/graph-node": "^0.2.15",
|
||||
{{/if}}
|
||||
"apollo-type-bigint": "^0.1.3",
|
||||
"debug": "^4.3.1",
|
||||
"ethers": "^5.4.4",
|
||||
"express": "^4.18.2",
|
||||
"graphql": "^15.5.0",
|
||||
"graphql-import-node": "^0.0.4",
|
||||
"graphql-subscriptions": "^2.0.0",
|
||||
"json-bigint": "^1.0.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
|
@ -73,13 +73,15 @@ To enable GQL requests caching:
|
||||
|
||||
## Run
|
||||
|
||||
* Run the watcher:
|
||||
* If the watcher is a `lazy` watcher:
|
||||
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
* Run the server:
|
||||
|
||||
GQL console: http://localhost:{{port}}/graphql
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
|
||||
GQL console: http://localhost:{{port}}/graphql
|
||||
|
||||
* If the watcher is an `active` watcher:
|
||||
|
||||
@ -89,6 +91,14 @@ GQL console: http://localhost:{{port}}/graphql
|
||||
yarn job-runner
|
||||
```
|
||||
|
||||
* Run the server:
|
||||
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
|
||||
GQL console: http://localhost:{{port}}/graphql
|
||||
|
||||
* To watch a contract:
|
||||
|
||||
```bash
|
||||
|
@ -2,14 +2,10 @@
|
||||
// Copyright 2022 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import debug from 'debug';
|
||||
|
||||
import { getConfig, Config } from '@cerc-io/util';
|
||||
import { ResetStateCmd } from '@cerc-io/cli';
|
||||
|
||||
import { Database } from '../../database';
|
||||
|
||||
const log = debug('vulcanize:reset-state');
|
||||
|
||||
export const command = 'state';
|
||||
|
||||
export const desc = 'Reset State to a given block number';
|
||||
@ -21,42 +17,8 @@ export const builder = {
|
||||
};
|
||||
|
||||
export const handler = async (argv: any): Promise<void> => {
|
||||
const { blockNumber } = argv;
|
||||
const config: Config = await getConfig(argv.configFile);
|
||||
const resetStateCmd = new ResetStateCmd();
|
||||
await resetStateCmd.init(argv, Database);
|
||||
|
||||
// Initialize database
|
||||
const db = new Database(config.database);
|
||||
await db.init();
|
||||
|
||||
// Create a DB transaction
|
||||
const dbTx = await db.createTransactionRunner();
|
||||
|
||||
console.time('time:reset-state');
|
||||
try {
|
||||
// Delete all State entries in the given range
|
||||
await db.removeStatesAfterBlock(dbTx, blockNumber);
|
||||
|
||||
// Reset the stateSyncStatus.
|
||||
const stateSyncStatus = await db.getStateSyncStatus();
|
||||
|
||||
if (stateSyncStatus) {
|
||||
if (stateSyncStatus.latestIndexedBlockNumber > blockNumber) {
|
||||
await db.updateStateSyncStatusIndexedBlock(dbTx, blockNumber, true);
|
||||
}
|
||||
|
||||
if (stateSyncStatus.latestCheckpointBlockNumber > blockNumber) {
|
||||
await db.updateStateSyncStatusCheckpointBlock(dbTx, blockNumber, true);
|
||||
}
|
||||
}
|
||||
|
||||
dbTx.commitTransaction();
|
||||
} catch (error) {
|
||||
await dbTx.rollbackTransaction();
|
||||
throw error;
|
||||
} finally {
|
||||
await dbTx.release();
|
||||
}
|
||||
console.timeEnd('time:reset-state');
|
||||
|
||||
log(`Reset State successfully to block ${blockNumber}`);
|
||||
await resetStateCmd.exec();
|
||||
};
|
||||
|
@ -2,24 +2,10 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import debug from 'debug';
|
||||
import { MoreThan } from 'typeorm';
|
||||
import assert from 'assert';
|
||||
|
||||
import { getConfig, initClients, resetJobs, JobQueue, Config } from '@cerc-io/util';
|
||||
{{#if (subgraphPath)}}
|
||||
import { GraphWatcher, Database as GraphDatabase } from '@cerc-io/graph-node';
|
||||
{{/if}}
|
||||
import { ResetWatcherCmd } from '@cerc-io/cli';
|
||||
|
||||
import { Database } from '../../database';
|
||||
import { Indexer } from '../../indexer';
|
||||
import { BlockProgress } from '../../entity/BlockProgress';
|
||||
|
||||
{{#each queries as | query |}}
|
||||
import { {{query.entityName}} } from '../../entity/{{query.entityName}}';
|
||||
{{/each}}
|
||||
|
||||
const log = debug('vulcanize:reset-watcher');
|
||||
|
||||
export const command = 'watcher';
|
||||
|
||||
@ -32,38 +18,8 @@ export const builder = {
|
||||
};
|
||||
|
||||
export const handler = async (argv: any): Promise<void> => {
|
||||
const config: Config = await getConfig(argv.configFile);
|
||||
await resetJobs(config);
|
||||
const { ethClient, ethProvider } = await initClients(config);
|
||||
const resetWatcherCmd = new ResetWatcherCmd();
|
||||
await resetWatcherCmd.init(argv, Database, Indexer);
|
||||
|
||||
// Initialize database.
|
||||
const db = new Database(config.database);
|
||||
await db.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
const graphDb = new GraphDatabase(config.server, db.baseDatabase);
|
||||
await graphDb.init();
|
||||
|
||||
const graphWatcher = new GraphWatcher(graphDb, ethClient, ethProvider, config.server);
|
||||
{{/if}}
|
||||
|
||||
const jobQueueConfig = config.jobQueue;
|
||||
assert(jobQueueConfig, 'Missing job queue config');
|
||||
|
||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
||||
|
||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
||||
await jobQueue.start();
|
||||
|
||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue{{#if (subgraphPath)}}, graphWatcher{{/if}});
|
||||
await indexer.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
graphWatcher.setIndexer(indexer);
|
||||
await graphWatcher.init();
|
||||
{{/if}}
|
||||
|
||||
await indexer.resetWatcherToBlock(argv.blockNumber);
|
||||
log('Reset watcher successfully');
|
||||
await resetWatcherCmd.exec();
|
||||
};
|
||||
|
@ -8,7 +8,17 @@ import debug from 'debug';
|
||||
import Decimal from 'decimal.js';
|
||||
import { GraphQLResolveInfo, GraphQLScalarType } from 'graphql';
|
||||
|
||||
import { ValueResult, BlockHeight, gqlTotalQueryCount, gqlQueryCount, jsonBigIntStringReplacer, getResultState, setGQLCacheHints } from '@cerc-io/util';
|
||||
import {
|
||||
ValueResult,
|
||||
BlockHeight,
|
||||
gqlTotalQueryCount,
|
||||
gqlQueryCount,
|
||||
jsonBigIntStringReplacer,
|
||||
getResultState,
|
||||
setGQLCacheHints,
|
||||
IndexerInterface,
|
||||
EventWatcherInterface
|
||||
} from '@cerc-io/util';
|
||||
|
||||
import { Indexer } from './indexer';
|
||||
import { EventWatcher } from './events';
|
||||
@ -21,8 +31,9 @@ import { {{query.entityName}} } from './entity/{{query.entityName}}';
|
||||
|
||||
const log = debug('vulcanize:resolver');
|
||||
|
||||
export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatcher): Promise<any> => {
|
||||
assert(indexer);
|
||||
export const createResolvers = async (indexerArg: IndexerInterface, eventWatcherArg: EventWatcherInterface): Promise<any> => {
|
||||
const indexer = indexerArg as Indexer;
|
||||
const eventWatcher = eventWatcherArg as EventWatcher;
|
||||
|
||||
const gqlCacheConfig = indexer.serverConfig.gqlCache;
|
||||
|
||||
|
@ -4,19 +4,10 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import assert from 'assert';
|
||||
import 'reflect-metadata';
|
||||
import express, { Application } from 'express';
|
||||
import { PubSub } from 'graphql-subscriptions';
|
||||
import yargs from 'yargs';
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import debug from 'debug';
|
||||
import 'graphql-import-node';
|
||||
|
||||
import { DEFAULT_CONFIG_PATH, getConfig, Config, JobQueue, KIND_ACTIVE, initClients, startGQLMetricsServer, createAndStartServer } from '@cerc-io/util';
|
||||
{{#if (subgraphPath)}}
|
||||
import { GraphWatcher, Database as GraphDatabase } from '@cerc-io/graph-node';
|
||||
{{/if}}
|
||||
import { ServerCmd } from '@cerc-io/cli';
|
||||
|
||||
import { createResolvers } from './resolvers';
|
||||
import { Indexer } from './indexer';
|
||||
@ -26,70 +17,12 @@ import { EventWatcher } from './events';
|
||||
const log = debug('vulcanize:server');
|
||||
|
||||
export const main = async (): Promise<any> => {
|
||||
const argv = await yargs(hideBin(process.argv))
|
||||
.option('f', {
|
||||
alias: 'config-file',
|
||||
demandOption: true,
|
||||
describe: 'configuration file path (toml)',
|
||||
type: 'string',
|
||||
default: DEFAULT_CONFIG_PATH
|
||||
})
|
||||
.argv;
|
||||
const serverCmd = new ServerCmd();
|
||||
await serverCmd.init(Database, Indexer, EventWatcher{{#if (subgraphPath)}}, {}, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP{{/if}});
|
||||
|
||||
const config: Config = await getConfig(argv.f);
|
||||
const { ethClient, ethProvider } = await initClients(config);
|
||||
|
||||
const { kind: watcherKind } = config.server;
|
||||
|
||||
const db = new Database(config.database);
|
||||
await db.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
const graphDb = new GraphDatabase(config.server, db.baseDatabase, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP);
|
||||
await graphDb.init();
|
||||
|
||||
const graphWatcher = new GraphWatcher(graphDb, ethClient, ethProvider, config.server);
|
||||
{{/if}}
|
||||
|
||||
// Note: In-memory pubsub works fine for now, as each watcher is a single process anyway.
|
||||
// Later: https://www.apollographql.com/docs/apollo-server/data/subscriptions/#production-pubsub-libraries
|
||||
const pubsub = new PubSub();
|
||||
|
||||
const jobQueueConfig = config.jobQueue;
|
||||
assert(jobQueueConfig, 'Missing job queue config');
|
||||
|
||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
||||
|
||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
||||
|
||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue{{#if (subgraphPath)}}, graphWatcher{{/if}});
|
||||
await indexer.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
graphWatcher.setIndexer(indexer);
|
||||
await graphWatcher.init();
|
||||
{{/if}}
|
||||
|
||||
const eventWatcher = new EventWatcher(ethClient, indexer, pubsub, jobQueue);
|
||||
|
||||
if (watcherKind === KIND_ACTIVE) {
|
||||
await jobQueue.start();
|
||||
// Delete jobs to prevent creating jobs after completion of processing previous block.
|
||||
await jobQueue.deleteAllJobs();
|
||||
await eventWatcher.start();
|
||||
}
|
||||
|
||||
const resolvers = await createResolvers(indexer, eventWatcher);
|
||||
const typeDefs = fs.readFileSync(path.join(__dirname, 'schema.gql')).toString();
|
||||
|
||||
// Create an Express app
|
||||
const app: Application = express();
|
||||
const server = createAndStartServer(app, typeDefs, resolvers, config.server);
|
||||
|
||||
startGQLMetricsServer(config);
|
||||
|
||||
return { app, server };
|
||||
return serverCmd.exec(createResolvers, typeDefs);
|
||||
};
|
||||
|
||||
main().then(() => {
|
||||
|
@ -2,15 +2,10 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import yargs from 'yargs';
|
||||
import 'reflect-metadata';
|
||||
import debug from 'debug';
|
||||
import assert from 'assert';
|
||||
|
||||
import { Config, DEFAULT_CONFIG_PATH, getConfig, initClients, JobQueue } from '@cerc-io/util';
|
||||
{{#if (subgraphPath)}}
|
||||
import { GraphWatcher, Database as GraphDatabase } from '@cerc-io/graph-node';
|
||||
{{/if}}
|
||||
import { WatchContractCmd } from '@cerc-io/cli';
|
||||
|
||||
import { Database } from '../database';
|
||||
import { Indexer } from '../indexer';
|
||||
@ -18,76 +13,10 @@ import { Indexer } from '../indexer';
|
||||
const log = debug('vulcanize:watch-contract');
|
||||
|
||||
const main = async (): Promise<void> => {
|
||||
const argv = await yargs.parserConfiguration({
|
||||
'parse-numbers': false
|
||||
}).options({
|
||||
configFile: {
|
||||
alias: 'f',
|
||||
type: 'string',
|
||||
require: true,
|
||||
demandOption: true,
|
||||
describe: 'Configuration file path (toml)',
|
||||
default: DEFAULT_CONFIG_PATH
|
||||
},
|
||||
address: {
|
||||
type: 'string',
|
||||
require: true,
|
||||
demandOption: true,
|
||||
describe: 'Address of the deployed contract'
|
||||
},
|
||||
kind: {
|
||||
type: 'string',
|
||||
require: true,
|
||||
demandOption: true,
|
||||
describe: 'Kind of contract'
|
||||
},
|
||||
checkpoint: {
|
||||
type: 'boolean',
|
||||
require: true,
|
||||
demandOption: true,
|
||||
describe: 'Turn checkpointing on'
|
||||
},
|
||||
startingBlock: {
|
||||
type: 'number',
|
||||
default: 1,
|
||||
describe: 'Starting block'
|
||||
}
|
||||
}).argv;
|
||||
const watchContractCmd = new WatchContractCmd();
|
||||
await watchContractCmd.init(Database, Indexer);
|
||||
|
||||
const config: Config = await getConfig(argv.configFile);
|
||||
const { ethClient, ethProvider } = await initClients(config);
|
||||
|
||||
const db = new Database(config.database);
|
||||
await db.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
const graphDb = new GraphDatabase(config.server, db.baseDatabase);
|
||||
await graphDb.init();
|
||||
|
||||
const graphWatcher = new GraphWatcher(graphDb, ethClient, ethProvider, config.server);
|
||||
{{/if}}
|
||||
|
||||
const jobQueueConfig = config.jobQueue;
|
||||
assert(jobQueueConfig, 'Missing job queue config');
|
||||
|
||||
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
|
||||
assert(dbConnectionString, 'Missing job queue db connection string');
|
||||
|
||||
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
|
||||
await jobQueue.start();
|
||||
|
||||
const indexer = new Indexer(config.server, db, ethClient, ethProvider, jobQueue{{#if (subgraphPath)}}, graphWatcher{{/if}});
|
||||
await indexer.init();
|
||||
{{#if (subgraphPath)}}
|
||||
|
||||
graphWatcher.setIndexer(indexer);
|
||||
await graphWatcher.init();
|
||||
{{/if}}
|
||||
|
||||
await indexer.watchContract(argv.address, argv.kind, argv.checkpoint, argv.startingBlock);
|
||||
|
||||
await db.close();
|
||||
await jobQueue.stop();
|
||||
await watchContractCmd.exec();
|
||||
};
|
||||
|
||||
main().catch(err => {
|
||||
|
@ -12,7 +12,6 @@ import { Indexer } from './indexer';
|
||||
import { Resolvers } from './resolvers';
|
||||
import { Schema } from './schema';
|
||||
import { Client } from './client';
|
||||
import { Reset } from './reset';
|
||||
import { Param } from './utils/types';
|
||||
import { MODE_ETH_CALL, MODE_STORAGE } from './utils/constants';
|
||||
import { parseSubgraphSchema } from './utils/subgraph';
|
||||
@ -25,7 +24,6 @@ export class Visitor {
|
||||
_entity: Entity;
|
||||
_database: Database;
|
||||
_client: Client;
|
||||
_reset: Reset;
|
||||
_types: Types;
|
||||
|
||||
_contract?: { name: string, kind: string };
|
||||
@ -37,7 +35,6 @@ export class Visitor {
|
||||
this._entity = new Entity();
|
||||
this._database = new Database();
|
||||
this._client = new Client();
|
||||
this._reset = new Reset();
|
||||
this._types = new Types();
|
||||
}
|
||||
|
||||
@ -75,7 +72,6 @@ export class Visitor {
|
||||
this._entity.addQuery(name, params, returnType);
|
||||
this._database.addQuery(name, params, returnType);
|
||||
this._client.addQuery(name, params, returnType);
|
||||
this._reset.addQuery(name);
|
||||
|
||||
assert(this._contract);
|
||||
this._indexer.addQuery(this._contract.name, MODE_ETH_CALL, name, params, returnType);
|
||||
@ -123,7 +119,6 @@ export class Visitor {
|
||||
this._entity.addQuery(name, params, returnType);
|
||||
this._database.addQuery(name, params, returnType);
|
||||
this._client.addQuery(name, params, returnType);
|
||||
this._reset.addQuery(name);
|
||||
|
||||
assert(this._contract);
|
||||
this._indexer.addQuery(this._contract.name, MODE_STORAGE, name, params, returnType, stateVariableType);
|
||||
@ -153,7 +148,6 @@ export class Visitor {
|
||||
this._types.addSubgraphTypes(subgraphSchemaDocument);
|
||||
this._entity.addSubgraphEntities(subgraphSchemaDocument);
|
||||
this._resolvers.addSubgraphResolvers(subgraphSchemaDocument);
|
||||
this._reset.addSubgraphEntities(subgraphSchemaDocument);
|
||||
this._indexer.addSubgraphEntities(subgraphSchemaDocument);
|
||||
this._database.addSubgraphEntities(subgraphSchemaDocument);
|
||||
}
|
||||
@ -210,17 +204,6 @@ export class Visitor {
|
||||
this._client.exportClient(outStream, schemaContent, gqlDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the reset.ts, job-queue.ts, watcher.ts, state.ts files generated from templates to respective streams.
|
||||
* @param resetOutStream A writable output stream to write the reset file to.
|
||||
* @param resetJQOutStream A writable output stream to write the reset job-queue file to.
|
||||
* @param resetWatcherOutStream A writable output stream to write the reset watcher file to.
|
||||
* @param resetStateOutStream A writable output stream to write the reset state file to.
|
||||
*/
|
||||
exportReset (resetOutStream: Writable, resetJQOutStream: Writable, resetWatcherOutStream: Writable, resetStateOutStream: Writable, subgraphPath: string): void {
|
||||
this._reset.exportReset(resetOutStream, resetJQOutStream, resetWatcherOutStream, resetStateOutStream, subgraphPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the types file generated from a template to a stream.
|
||||
* @param outStream A writable output stream to write the database file to.
|
||||
|
@ -13,9 +13,9 @@ const TEMPLATE_FILE = './templates/watch-contract-template.handlebars';
|
||||
* Writes the watch-contract file generated from a template to a stream.
|
||||
* @param outStream A writable output stream to write the watch-contract file to.
|
||||
*/
|
||||
export function exportWatchContract (outStream: Writable, subgraphPath: string): void {
|
||||
export function exportWatchContract (outStream: Writable): void {
|
||||
const templateString = fs.readFileSync(path.resolve(__dirname, TEMPLATE_FILE)).toString();
|
||||
const template = Handlebars.compile(templateString);
|
||||
const events = template({ subgraphPath });
|
||||
const events = template({});
|
||||
outStream.write(events);
|
||||
}
|
||||
|
@ -61,13 +61,15 @@
|
||||
|
||||
## Run
|
||||
|
||||
* Run the watcher:
|
||||
* If the watcher is a `lazy` watcher:
|
||||
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
* Run the server:
|
||||
|
||||
GQL console: http://localhost:3012/graphql
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
|
||||
GQL console: http://localhost:3012/graphql
|
||||
|
||||
* If the watcher is an `active` watcher:
|
||||
|
||||
@ -77,6 +79,14 @@ GQL console: http://localhost:3012/graphql
|
||||
yarn job-runner
|
||||
```
|
||||
|
||||
* Run the server:
|
||||
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
|
||||
GQL console: http://localhost:3012/graphql
|
||||
|
||||
* To watch a contract:
|
||||
|
||||
```bash
|
||||
|
@ -51,7 +51,6 @@
|
||||
"ethers": "^5.4.4",
|
||||
"express": "^4.18.2",
|
||||
"graphql": "^15.5.0",
|
||||
"graphql-import-node": "^0.0.4",
|
||||
"graphql-subscriptions": "^2.0.0",
|
||||
"json-bigint": "^1.0.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
|
@ -21,8 +21,8 @@ export const builder = {
|
||||
};
|
||||
|
||||
export const handler = async (argv: any): Promise<void> => {
|
||||
const createCheckpointCmd = new VerifyCheckpointCmd();
|
||||
await createCheckpointCmd.init(argv, Database, Indexer);
|
||||
const verifyCheckpointCmd = new VerifyCheckpointCmd();
|
||||
await verifyCheckpointCmd.init(argv, Database, Indexer);
|
||||
|
||||
await createCheckpointCmd.exec();
|
||||
await verifyCheckpointCmd.exec();
|
||||
};
|
||||
|
@ -6,7 +6,6 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import 'reflect-metadata';
|
||||
import debug from 'debug';
|
||||
import 'graphql-import-node';
|
||||
|
||||
import { ServerCmd } from '@cerc-io/cli';
|
||||
|
||||
|
@ -70,16 +70,6 @@ yarn build
|
||||
|
||||
Run the watcher:
|
||||
|
||||
```bash
|
||||
$ yarn server
|
||||
|
||||
# For development.
|
||||
$ yarn server:dev
|
||||
|
||||
# For specifying config file.
|
||||
$ yarn server -f environments/local.toml
|
||||
```
|
||||
|
||||
Start the job runner:
|
||||
|
||||
```bash
|
||||
@ -92,6 +82,18 @@ $ yarn job-runner:dev
|
||||
$ yarn job-runner -f environments/local.toml
|
||||
```
|
||||
|
||||
Start the server:
|
||||
|
||||
```bash
|
||||
$ yarn server
|
||||
|
||||
# For development.
|
||||
$ yarn server:dev
|
||||
|
||||
# For specifying config file.
|
||||
$ yarn server -f environments/local.toml
|
||||
```
|
||||
|
||||
GQL console: http://localhost:3001/graphql
|
||||
|
||||
Deploy an ERC20 token:
|
||||
|
@ -52,7 +52,6 @@
|
||||
"ethers": "^5.4.4",
|
||||
"express": "^4.18.2",
|
||||
"graphql": "^15.5.0",
|
||||
"graphql-import-node": "^0.0.4",
|
||||
"graphql-request": "^3.4.0",
|
||||
"graphql-subscriptions": "^2.0.0",
|
||||
"json-bigint": "^1.0.0",
|
||||
|
@ -3,7 +3,6 @@
|
||||
//
|
||||
|
||||
import debug from 'debug';
|
||||
import 'graphql-import-node';
|
||||
|
||||
import { ServerCmd } from '@cerc-io/cli';
|
||||
|
||||
|
@ -71,11 +71,15 @@ Follow the steps below or follow the [Demo](./demo.md)
|
||||
|
||||
* Run the watcher:
|
||||
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
* If the watcher is a `lazy` watcher:
|
||||
|
||||
GQL console: http://localhost:3006/graphql
|
||||
* Run the server:
|
||||
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
|
||||
GQL console: http://localhost:3006/graphql
|
||||
|
||||
* If the watcher is an `active` watcher:
|
||||
|
||||
@ -85,6 +89,14 @@ GQL console: http://localhost:3006/graphql
|
||||
yarn job-runner
|
||||
```
|
||||
|
||||
* Run the server:
|
||||
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
|
||||
GQL console: http://localhost:3012/graphql
|
||||
|
||||
* To watch a contract:
|
||||
|
||||
```bash
|
||||
|
@ -58,7 +58,6 @@
|
||||
"ethers": "^5.4.4",
|
||||
"express": "^4.18.2",
|
||||
"graphql": "^15.5.0",
|
||||
"graphql-import-node": "^0.0.4",
|
||||
"graphql-subscriptions": "^2.0.0",
|
||||
"json-bigint": "^1.0.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
|
@ -6,7 +6,6 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import 'reflect-metadata';
|
||||
import debug from 'debug';
|
||||
import 'graphql-import-node';
|
||||
|
||||
import { ServerCmd } from '@cerc-io/cli';
|
||||
|
||||
|
@ -194,18 +194,6 @@ export class Database {
|
||||
}
|
||||
}
|
||||
|
||||
async getEntitiesForBlock (blockHash: string, tableName: string): Promise<any[]> {
|
||||
const repo = this._conn.getRepository(tableName);
|
||||
|
||||
const entities = await repo.find({
|
||||
where: {
|
||||
blockHash
|
||||
}
|
||||
});
|
||||
|
||||
return entities;
|
||||
}
|
||||
|
||||
async getEntityIdsAtBlockNumber (blockNumber: number, tableName: string): Promise<string[]> {
|
||||
const repo = this._conn.getRepository(tableName);
|
||||
|
||||
|
@ -12,10 +12,9 @@ import { SelectionNode } from 'graphql';
|
||||
|
||||
import { ResultObject } from '@vulcanize/assemblyscript/lib/loader';
|
||||
import { EthClient } from '@cerc-io/ipld-eth-client';
|
||||
import { getFullBlock, BlockHeight, ServerConfig, getFullTransaction, QueryOptions, StateInterface, IndexerInterface, BlockProgressInterface } from '@cerc-io/util';
|
||||
import { getFullBlock, BlockHeight, ServerConfig, getFullTransaction, QueryOptions, IndexerInterface, BlockProgressInterface } from '@cerc-io/util';
|
||||
|
||||
import { createBlock, createEvent, getSubgraphConfig, resolveEntityFieldConflicts, Transaction } from './utils';
|
||||
import { updateEntitiesFromState } from './state-utils';
|
||||
import { Context, GraphData, instantiate } from './loader';
|
||||
import { Database, DEFAULT_LIMIT } from './database';
|
||||
|
||||
@ -349,12 +348,6 @@ export class GraphWatcher {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Remove after updating codegen CLIs
|
||||
async updateEntitiesFromState (state: StateInterface) {
|
||||
assert(this._indexer);
|
||||
await updateEntitiesFromState(this._database, this._indexer, state);
|
||||
}
|
||||
|
||||
updateEntityCacheFrothyBlocks (blockProgress: BlockProgressInterface): void {
|
||||
assert(this._indexer);
|
||||
this._database.updateEntityCacheFrothyBlocks(blockProgress, this._indexer.serverConfig.clearEntitiesCacheInterval);
|
||||
|
@ -63,13 +63,13 @@
|
||||
|
||||
## Run
|
||||
|
||||
* Run the watcher:
|
||||
* Run the server:
|
||||
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
|
||||
GQL console: http://localhost:3008/graphql
|
||||
GQL console: http://localhost:3008/graphql
|
||||
|
||||
* If the watcher is an `active` watcher:
|
||||
|
||||
@ -79,6 +79,14 @@ GQL console: http://localhost:3008/graphql
|
||||
yarn job-runner
|
||||
```
|
||||
|
||||
* Run the server:
|
||||
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
|
||||
GQL console: http://localhost:3008/graphql
|
||||
|
||||
* To watch a contract:
|
||||
|
||||
```bash
|
||||
|
@ -51,7 +51,6 @@
|
||||
"ethers": "^5.4.4",
|
||||
"express": "^4.18.2",
|
||||
"graphql": "^15.5.0",
|
||||
"graphql-import-node": "^0.0.4",
|
||||
"graphql-subscriptions": "^2.0.0",
|
||||
"json-bigint": "^1.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
|
@ -21,8 +21,8 @@ export const builder = {
|
||||
};
|
||||
|
||||
export const handler = async (argv: any): Promise<void> => {
|
||||
const createCheckpointCmd = new VerifyCheckpointCmd();
|
||||
await createCheckpointCmd.init(argv, Database, Indexer);
|
||||
const verifyCheckpointCmd = new VerifyCheckpointCmd();
|
||||
await verifyCheckpointCmd.init(argv, Database, Indexer);
|
||||
|
||||
await createCheckpointCmd.exec();
|
||||
await verifyCheckpointCmd.exec();
|
||||
};
|
||||
|
@ -6,7 +6,6 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import 'reflect-metadata';
|
||||
import debug from 'debug';
|
||||
import 'graphql-import-node';
|
||||
|
||||
import { ServerCmd } from '@cerc-io/cli';
|
||||
|
||||
|
@ -63,13 +63,13 @@
|
||||
|
||||
Follow the steps below or follow the [Demo](./demo.md)
|
||||
|
||||
* Run the watcher:
|
||||
* Run the server:
|
||||
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
|
||||
GQL console: http://localhost:3010/graphql
|
||||
GQL console: http://localhost:3010/graphql
|
||||
|
||||
* If the watcher is an `active` watcher:
|
||||
|
||||
@ -79,6 +79,14 @@ GQL console: http://localhost:3010/graphql
|
||||
yarn job-runner
|
||||
```
|
||||
|
||||
* Run the server:
|
||||
|
||||
```bash
|
||||
yarn server
|
||||
```
|
||||
|
||||
GQL console: http://localhost:3010/graphql
|
||||
|
||||
* To watch a contract:
|
||||
|
||||
```bash
|
||||
|
@ -49,7 +49,6 @@
|
||||
"ethers": "^5.4.4",
|
||||
"express": "^4.18.2",
|
||||
"graphql": "^15.5.0",
|
||||
"graphql-import-node": "^0.0.4",
|
||||
"graphql-subscriptions": "^2.0.0",
|
||||
"json-bigint": "^1.0.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
|
@ -6,7 +6,6 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import 'reflect-metadata';
|
||||
import debug from 'debug';
|
||||
import 'graphql-import-node';
|
||||
|
||||
import { ServerCmd } from '@cerc-io/cli';
|
||||
|
||||
|
@ -7965,11 +7965,6 @@ graphql-compose@^9.0.3:
|
||||
graphql-type-json "0.3.2"
|
||||
object-path "0.11.7"
|
||||
|
||||
graphql-import-node@^0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/graphql-import-node/-/graphql-import-node-0.0.4.tgz#0522f058978c7e1b99d1e6be1b851ee17007b111"
|
||||
integrity sha512-okpdABQIgIM0qdx9Mfgdu6fTsFEazZmHZdEU34cijkUj9D1db1SyPRGHPxbXmbacamhEF41ckxpCAgHiGliryQ==
|
||||
|
||||
graphql-request@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-3.4.0.tgz#3a400cd5511eb3c064b1873afb059196bbea9c2b"
|
||||
|
Loading…
Reference in New Issue
Block a user