Skip to content

Commit

Permalink
feat: add stats endpoint for inscription counts
Browse files Browse the repository at this point in the history
  • Loading branch information
janniks committed May 15, 2023
1 parent 4eb53cc commit 55126a6
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 4 deletions.
25 changes: 25 additions & 0 deletions migrations/1683909884000_inscriptions_per_block.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { MigrationBuilder, ColumnDefinitions } from 'node-pg-migrate';

export const shorthands: ColumnDefinitions | undefined = undefined;

export function up(pgm: MigrationBuilder): void {
pgm.createTable('inscriptions_per_block', {
block_height: {
type: 'int',
primaryKey: true,
},
inscriptions: {
type: 'int',
notNull: true,
},
inscriptions_total: {
type: 'int',
notNull: true,
},
});
}

export function down(pgm: MigrationBuilder): void {
pgm.dropTable('inscriptions_per_block');
}
25 changes: 25 additions & 0 deletions src/api/routes/stats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox';
import { FastifyPluginAsync, FastifyPluginCallback } from 'fastify';
import { Server } from 'http';

const IndexRoutes: FastifyPluginCallback<Record<never, never>, Server, TypeBoxTypeProvider> = (
fastify,
options,
done
) => {
fastify.get('/stats/inscriptions', async (request, reply) => {
const inscriptions = await fastify.db.getInscriptionCountPerBlock();
await reply.send({
results: inscriptions,
});
});
done();
};

export const StatsRoutes: FastifyPluginAsync<
Record<never, never>,
Server,
TypeBoxTypeProvider
> = async fastify => {
await fastify.register(IndexRoutes);
};
43 changes: 39 additions & 4 deletions src/pg/pg-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { BasePgStore } from './postgres-tools/base-pg-store';
import {
DbFullyLocatedInscriptionResult,
DbInscriptionContent,
DbInscriptionCountPerBlock,
DbInscriptionIndexFilters,
DbInscriptionIndexOrder,
DbInscriptionIndexPaging,
Expand Down Expand Up @@ -77,6 +78,9 @@ export class PgStore extends BasePgStore {
}
}
}
const block_height = event.block_identifier.index;
await this.rollBackInscriptionCount({ block_height });
logger.info(`PgStore rollback inscription counts for block ${block_height}`);
}
for (const event of payload.apply) {
const block_hash = normalizedHexString(event.block_identifier.hash);
Expand Down Expand Up @@ -130,10 +134,8 @@ export class PgStore extends BasePgStore {
block_height: event.block_identifier.index,
address: transfer.updated_address,
output: output,
offset: offset ?? null,
value: transfer.post_transfer_output_value
? transfer.post_transfer_output_value.toString()
: null,
offset: offset,
value: transfer.post_transfer_output_value?.toString() ?? null,
timestamp: event.timestamp,
sat_ordinal: transfer.ordinal_number.toString(),
sat_rarity: satoshi.rarity,
Expand All @@ -147,6 +149,9 @@ export class PgStore extends BasePgStore {
}
}
}
const block_height = event.block_identifier.index;
await this.insertInscriptionCount({ block_height });
logger.info(`PgStore apply inscription counts at block ${block_height}`);
}
});
await this.normalizeInscriptionLocations({ inscription_id: Array.from(updatedInscriptionIds) });
Expand Down Expand Up @@ -474,6 +479,10 @@ export class PgStore extends BasePgStore {
}
}

async getInscriptionCountPerBlock(): Promise<DbInscriptionCountPerBlock[]> {
return this.sql<DbInscriptionCountPerBlock[]>`SELECT * FROM inscriptions_per_block`;
}

async refreshMaterializedView(viewName: string) {
const isProd = process.env.NODE_ENV === 'production';
await this.sql`REFRESH MATERIALIZED VIEW ${
Expand Down Expand Up @@ -621,6 +630,32 @@ export class PgStore extends BasePgStore {
return inscription_id;
}

private async insertInscriptionCount(args: { block_height: number }): Promise<void> {
await this.sql`
WITH previous AS (
SELECT COALESCE(p.inscriptions_total, 0) as previous_total
FROM inscriptions_per_block p
WHERE p.block_height = ${args.block_height - 1}
LIMIT 1
), current AS (
SELECT block_height, COUNT(*) as inscriptions, COUNT(*) + (SELECT previous_total FROM previous) as inscriptions_total
FROM locations
WHERE block_height = ${args.block_height} AND genesis = true
GROUP BY block_height
LIMIT 1
)
INSERT INTO inscriptions_per_block
SELECT * FROM current
ON CONFLICT (block_height) DO UPDATE SET
inscriptions = EXCLUDED.inscriptions,
inscriptions_total = EXCLUDED.inscriptions_total;
`;
}

private async rollBackInscriptionCount(args: { block_height: number }): Promise<void> {
await this.sql`DELETE FROM inscriptions_per_block WHERE block_height = ${args.block_height}`;
}

private async rollBackInscriptionGenesis(args: { genesis_id: string }): Promise<void> {
// This will cascade into dependent tables.
await this.sql`DELETE FROM inscriptions WHERE genesis_id = ${args.genesis_id}`;
Expand Down
6 changes: 6 additions & 0 deletions src/pg/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,9 @@ export enum DbInscriptionIndexResultCountType {
/** Filtered by custom arguments */
custom,
}

export type DbInscriptionCountPerBlock = {
block_height: number;
inscriptions: number;
inscriptions_total: number;
};

0 comments on commit 55126a6

Please sign in to comment.