Skip to content

Commit

Permalink
Add blocktable.findBlockByCreatedOnOrAfter, and use in `aggregate-tra…
Browse files Browse the repository at this point in the history
…ding-rewards
  • Loading branch information
teddyding committed Mar 10, 2025
1 parent cd8a246 commit 4ca78d7
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 12 deletions.
42 changes: 42 additions & 0 deletions indexer/packages/postgres/__tests__/stores/block-table.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
teardown,
} from '../../src/helpers/db-helpers';
import { defaultBlock, defaultBlock2 } from '../helpers/constants';
import { DateTime } from 'luxon';

describe('Block store', () => {
beforeAll(async () => {
Expand Down Expand Up @@ -91,4 +92,45 @@ describe('Block store', () => {
it('Unable to find latest Block', async () => {
await expect(BlockTable.getLatest()).rejects.toEqual(new Error('Unable to find latest block'));
});

it('Successfully finds first block created on or after timestamp', async () => {
await Promise.all([
BlockTable.create(defaultBlock),
BlockTable.create(defaultBlock2),
]);

const block: BlockFromDatabase | undefined = await BlockTable.findBlockByCreatedOnOrAfter(
DateTime.utc(2022, 6, 1).toISO(),
);

expect(block).toBeDefined();
expect(block).toEqual(expect.objectContaining(defaultBlock));
});

it('Successfully finds first block when querying with later timestamp', async () => {
await Promise.all([
BlockTable.create(defaultBlock),
BlockTable.create(defaultBlock2),
]);

const block: BlockFromDatabase | undefined = await BlockTable.findBlockByCreatedOnOrAfter(
DateTime.utc(2022, 6, 2).toISO(),
);

expect(block).toBeDefined();
expect(block).toEqual(expect.objectContaining(defaultBlock2));
});

it('Returns undefined when no blocks found after timestamp', async () => {
await Promise.all([
BlockTable.create(defaultBlock),
BlockTable.create(defaultBlock2),
]);

const block: BlockFromDatabase | undefined = await BlockTable.findBlockByCreatedOnOrAfter(
DateTime.utc(2022, 6, 3).toISO(),
);

expect(block).toBeUndefined();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as Knex from 'knex';

export async function up(knex: Knex): Promise<void> {
await knex.raw(`
CREATE INDEX CONCURRENTLY IF NOT EXISTS "blocks_time_since_feb2025_idx"
ON "blocks" ("time")
WHERE "time" >= '2025-02-10 00:00:00+00';
`);
}

export async function down(knex: Knex): Promise<void> {
await knex.raw(`
DROP INDEX CONCURRENTLY IF EXISTS
"blocks_time_since_feb2025_idx";
`);
}

export const config = {
transaction: false,
};
49 changes: 43 additions & 6 deletions indexer/packages/postgres/src/stores/block-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,52 @@ import {
QueryConfig,
} from '../types';

/**
* Find blocks by their block heights.
*/
export async function findByBlockHeights(
blockHeights: string[],
options: Options = DEFAULT_POSTGRES_OPTIONS,
): Promise<BlockFromDatabase[]> {
const baseQuery: QueryBuilder<BlockModel> = setupBaseQuery<BlockModel>(
BlockModel,
options,
);

return baseQuery
.whereIn(BlockColumns.blockHeight, blockHeights)
.orderBy(BlockColumns.blockHeight, Ordering.ASC)
.returning('*');
}

/**
* Find the first block created on or after the given timestamp.
* Uses the blocks_time_since_feb2025_idx index for efficient querying.
*/
export async function findBlockByCreatedOnOrAfter(
createdOnOrAfter: string,
options: Options = DEFAULT_POSTGRES_OPTIONS,
): Promise<BlockFromDatabase | undefined> {
const baseQuery: QueryBuilder<BlockModel> = setupBaseQuery<BlockModel>(
BlockModel,
options,
);

const blocks = await baseQuery
.where(BlockColumns.time, '>=', createdOnOrAfter)
.orderBy(BlockColumns.time, Ordering.ASC)
.limit(1)
.returning('*');
return blocks.length > 0 ? blocks[0] : undefined;
}

// Mark as deprecated to encourage migration to more specific methods
/**
* @deprecated Use findByBlockHeights or findByCreatedOnOrAfter instead
*/
export async function findAll(
{
blockHeight,
createdOnOrAfter,
limit,
}: BlockQueryConfig,
requiredFields: QueryableField[],
Expand All @@ -28,7 +70,6 @@ export async function findAll(
verifyAllRequiredFields(
{
blockHeight,
createdOnOrAfter,
limit,
} as QueryConfig,
requiredFields,
Expand All @@ -43,10 +84,6 @@ export async function findAll(
baseQuery = baseQuery.whereIn(BlockColumns.blockHeight, blockHeight);
}

if (createdOnOrAfter !== undefined) {
baseQuery = baseQuery.where(BlockColumns.time, '>=', createdOnOrAfter);
}

if (options.orderBy !== undefined) {
for (const [column, order] of options.orderBy) {
baseQuery = baseQuery.orderBy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,12 +381,12 @@ export class AggregateTradingReward {
}

private async getNextBlock(time: IsoString): Promise<string> {
const blocks: BlockFromDatabase[] = await BlockTable.findAll({
createdOnOrAfter: time,
limit: 1,
}, [], { readReplica: true });
const block: BlockFromDatabase | undefined = await BlockTable.findBlockByCreatedOnOrAfter(
time,
{ readReplica: true },
);

if (blocks.length === 0) {
if (block === undefined) {
logger.error({
at: 'aggregate-trading-rewards#getStartedAtHeight',
message: 'No blocks found after time, this should never happen',
Expand All @@ -395,7 +395,7 @@ export class AggregateTradingReward {
});
throw new Error(`No blocks found after ${time}`);
}
return blocks[0].blockHeight;
return block.blockHeight;
}

private isEndofPeriod(endTime: DateTime): boolean {
Expand Down

0 comments on commit 4ca78d7

Please sign in to comment.