mirror of
https://github.com/cerc-io/watcher-ts
synced 2025-02-12 20:46:35 +00:00
Get uniswap events in block range (#139)
* Get events in block range. * Get uniswap events in block range.
This commit is contained in:
parent
ecfa3ed386
commit
7151521c3b
@ -6,7 +6,7 @@ export class Account {
|
|||||||
@PrimaryColumn('varchar', { length: 42 })
|
@PrimaryColumn('varchar', { length: 42 })
|
||||||
address!: string;
|
address!: string;
|
||||||
|
|
||||||
@Column('numeric')
|
@Column('integer')
|
||||||
startingBlock!: number;
|
startingBlock!: number;
|
||||||
|
|
||||||
@ManyToMany(() => Trace, trace => trace.accounts)
|
@ManyToMany(() => Trace, trace => trace.accounts)
|
||||||
|
@ -6,13 +6,13 @@ export class BlockProgress {
|
|||||||
@PrimaryColumn('varchar', { length: 66 })
|
@PrimaryColumn('varchar', { length: 66 })
|
||||||
blockHash!: string;
|
blockHash!: string;
|
||||||
|
|
||||||
@Column('numeric')
|
@Column('integer')
|
||||||
blockNumber!: number;
|
blockNumber!: number;
|
||||||
|
|
||||||
@Column('numeric')
|
@Column('integer')
|
||||||
numTx!: number;
|
numTx!: number;
|
||||||
|
|
||||||
@Column('numeric')
|
@Column('integer')
|
||||||
numTracedTx!: number;
|
numTracedTx!: number;
|
||||||
|
|
||||||
@Column('boolean')
|
@Column('boolean')
|
||||||
|
@ -9,7 +9,7 @@ export class Trace {
|
|||||||
@PrimaryColumn('varchar', { length: 66 })
|
@PrimaryColumn('varchar', { length: 66 })
|
||||||
txHash!: string;
|
txHash!: string;
|
||||||
|
|
||||||
@Column('numeric')
|
@Column('integer')
|
||||||
blockNumber!: number;
|
blockNumber!: number;
|
||||||
|
|
||||||
@Column('varchar', { length: 66 })
|
@Column('varchar', { length: 66 })
|
||||||
|
@ -9,6 +9,6 @@ export class Contract {
|
|||||||
@Column('varchar', { length: 42 })
|
@Column('varchar', { length: 42 })
|
||||||
address!: string;
|
address!: string;
|
||||||
|
|
||||||
@Column('numeric')
|
@Column('integer')
|
||||||
startingBlock!: number;
|
startingBlock!: number;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
import _ from 'lodash';
|
||||||
import { Connection, ConnectionOptions, createConnection, DeepPartial } from 'typeorm';
|
import { Connection, ConnectionOptions, createConnection, DeepPartial } from 'typeorm';
|
||||||
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
|
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
|
||||||
|
|
||||||
import { Event } from './entity/Event';
|
import { Event, UNKNOWN_EVENT_NAME } from './entity/Event';
|
||||||
import { Contract } from './entity/Contract';
|
import { Contract } from './entity/Contract';
|
||||||
import { BlockProgress } from './entity/BlockProgress';
|
import { BlockProgress } from './entity/BlockProgress';
|
||||||
|
|
||||||
@ -58,6 +59,35 @@ export class Database {
|
|||||||
.getMany();
|
.getMany();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getProcessedBlockCountForRange (fromBlockNumber: number, toBlockNumber: number): Promise<{ expected: number, actual: number }> {
|
||||||
|
const blockNumbers = _.range(fromBlockNumber, toBlockNumber + 1);
|
||||||
|
const expected = blockNumbers.length;
|
||||||
|
|
||||||
|
const repo = this._conn.getRepository(BlockProgress);
|
||||||
|
const { count: actual } = await repo
|
||||||
|
.createQueryBuilder('block_progress')
|
||||||
|
.select('COUNT(DISTINCT(block_number))', 'count')
|
||||||
|
.where('block_number IN (:...blockNumbers) AND is_complete = :isComplete', { blockNumbers, isComplete: true })
|
||||||
|
.getRawOne();
|
||||||
|
|
||||||
|
return { expected, actual: parseInt(actual) };
|
||||||
|
}
|
||||||
|
|
||||||
|
async getEventsInRange (fromBlockNumber: number, toBlockNumber: number): Promise<Array<Event>> {
|
||||||
|
return this._conn.getRepository(Event)
|
||||||
|
.createQueryBuilder('event')
|
||||||
|
.where('block_number >= :fromBlockNumber AND block_number <= :toBlockNumber AND event_name <> :eventName', {
|
||||||
|
fromBlockNumber,
|
||||||
|
toBlockNumber,
|
||||||
|
eventName: UNKNOWN_EVENT_NAME
|
||||||
|
})
|
||||||
|
.orderBy({
|
||||||
|
block_number: 'ASC',
|
||||||
|
index: 'ASC'
|
||||||
|
})
|
||||||
|
.getMany();
|
||||||
|
}
|
||||||
|
|
||||||
async saveEvents (blockHash: string, blockNumber: number, events: DeepPartial<Event>[]): Promise<void> {
|
async saveEvents (blockHash: string, blockNumber: number, events: DeepPartial<Event>[]): Promise<void> {
|
||||||
// In a transaction:
|
// In a transaction:
|
||||||
// (1) Save all the events in the database.
|
// (1) Save all the events in the database.
|
||||||
|
@ -9,13 +9,13 @@ export class BlockProgress {
|
|||||||
@Column('varchar', { length: 66 })
|
@Column('varchar', { length: 66 })
|
||||||
blockHash!: string;
|
blockHash!: string;
|
||||||
|
|
||||||
@Column('numeric')
|
@Column('integer')
|
||||||
blockNumber!: number;
|
blockNumber!: number;
|
||||||
|
|
||||||
@Column('numeric')
|
@Column('integer')
|
||||||
numEvents!: number;
|
numEvents!: number;
|
||||||
|
|
||||||
@Column('numeric')
|
@Column('integer')
|
||||||
numProcessedEvents!: number;
|
numProcessedEvents!: number;
|
||||||
|
|
||||||
@Column('boolean')
|
@Column('boolean')
|
||||||
|
@ -15,6 +15,6 @@ export class Contract {
|
|||||||
@Column('varchar', { length: 8 })
|
@Column('varchar', { length: 8 })
|
||||||
kind!: string;
|
kind!: string;
|
||||||
|
|
||||||
@Column('numeric')
|
@Column('integer')
|
||||||
startingBlock!: number;
|
startingBlock!: number;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ export const UNKNOWN_EVENT_NAME = '__unknown__';
|
|||||||
@Entity()
|
@Entity()
|
||||||
// Index to query all events for a contract efficiently.
|
// Index to query all events for a contract efficiently.
|
||||||
@Index(['blockHash', 'contract'])
|
@Index(['blockHash', 'contract'])
|
||||||
|
// Index to query block range for uniswap events.
|
||||||
|
@Index(['blockNumber', 'eventName'])
|
||||||
export class Event {
|
export class Event {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
id!: number;
|
id!: number;
|
||||||
|
@ -15,6 +15,9 @@ import { Contract, KIND_FACTORY, KIND_POOL } from './entity/Contract';
|
|||||||
import factoryABI from './artifacts/factory.json';
|
import factoryABI from './artifacts/factory.json';
|
||||||
import poolABI from './artifacts/pool.json';
|
import poolABI from './artifacts/pool.json';
|
||||||
|
|
||||||
|
// TODO: Move to config.
|
||||||
|
const MAX_EVENTS_BLOCK_RANGE = 1000;
|
||||||
|
|
||||||
const log = debug('vulcanize:indexer');
|
const log = debug('vulcanize:indexer');
|
||||||
|
|
||||||
type ResultEvent = {
|
type ResultEvent = {
|
||||||
@ -294,4 +297,20 @@ export class Indexer {
|
|||||||
async updateBlockProgress (blockHash: string): Promise<void> {
|
async updateBlockProgress (blockHash: string): Promise<void> {
|
||||||
return this._db.updateBlockProgress(blockHash);
|
return this._db.updateBlockProgress(blockHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getProcessedBlockCountForRange (fromBlockNumber: number, toBlockNumber: number): Promise<{ expected: number, actual: number }> {
|
||||||
|
return this._db.getProcessedBlockCountForRange(fromBlockNumber, toBlockNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getEventsInRange (fromBlockNumber: number, toBlockNumber: number): Promise<Array<Event>> {
|
||||||
|
if (toBlockNumber <= fromBlockNumber) {
|
||||||
|
throw new Error('toBlockNumber should be greater than fromBlockNumber');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((toBlockNumber - fromBlockNumber) > MAX_EVENTS_BLOCK_RANGE) {
|
||||||
|
throw new Error(`Max range (${MAX_EVENTS_BLOCK_RANGE}) exceeded`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._db.getEventsInRange(fromBlockNumber, toBlockNumber);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,19 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
|
|||||||
|
|
||||||
const events = await indexer.getEventsByFilter(blockHash, contract, name);
|
const events = await indexer.getEventsByFilter(blockHash, contract, name);
|
||||||
return events.map(event => indexer.getResultEvent(event));
|
return events.map(event => indexer.getResultEvent(event));
|
||||||
}
|
},
|
||||||
|
|
||||||
|
eventsInRange: async (_: any, { fromBlockNumber, toBlockNumber }: { fromBlockNumber: number, toBlockNumber: number }) => {
|
||||||
|
log('eventsInRange', fromBlockNumber, toBlockNumber);
|
||||||
|
|
||||||
|
const { expected, actual } = await indexer.getProcessedBlockCountForRange(fromBlockNumber, toBlockNumber);
|
||||||
|
if (expected !== actual) {
|
||||||
|
throw new Error(`Range not available, expected ${expected}, got ${actual} blocks in range`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const events = await indexer.getEventsInRange(fromBlockNumber, toBlockNumber);
|
||||||
|
return events.map(event => indexer.getResultEvent(event));
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user