Skip to content

Commit

Permalink
feat: add status endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelcr committed Mar 3, 2023
1 parent a2ff106 commit e42b351
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 5 deletions.
2 changes: 1 addition & 1 deletion migrations/1677360299810_chain-tip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function up(pgm: MigrationBuilder): void {
block_height: {
type: 'int',
notNull: true,
default: 1,
default: 0,
},
});
// Ensure only a single row can exist
Expand Down
2 changes: 2 additions & 0 deletions src/api/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import { PINO_CONFIG } from '../logger';
import { InscriptionsRoutes } from './routes/inscriptions';
import { PgStore } from '../pg/pg-store';
import { SatRoutes } from './routes/sats';
import { StatusRoutes } from './routes/status';

export const Api: FastifyPluginAsync<
Record<never, never>,
Server,
TypeBoxTypeProvider
> = async fastify => {
await fastify.register(StatusRoutes);
await fastify.register(InscriptionsRoutes);
await fastify.register(SatRoutes);
};
Expand Down
39 changes: 39 additions & 0 deletions src/api/routes/status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox';
import { FastifyPluginCallback } from 'fastify';
import { Server } from 'http';
import { SERVER_VERSION } from '../../server-version';
import { ApiStatusResponse } from '../schemas';

export const StatusRoutes: FastifyPluginCallback<
Record<never, never>,
Server,
TypeBoxTypeProvider
> = (fastify, options, done) => {
fastify.get(
'/',
{
schema: {
summary: 'API Status',
description: 'Displays the status of the API',
tags: ['Status'],
response: {
200: ApiStatusResponse,
},
},
},
async (request, reply) => {
const result = await fastify.db.sqlTransaction(async sql => {
const block_height = await fastify.db.getChainTipBlockHeight();
const max_inscription_number = await fastify.db.getMaxInscriptionNumber();
return {
server_version: `ordinals-api ${SERVER_VERSION.tag} (${SERVER_VERSION.branch}:${SERVER_VERSION.commit})`,
status: 'ready',
block_height,
max_inscription_number,
};
});
await reply.send(result);
}
);
done();
};
7 changes: 7 additions & 0 deletions src/api/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,13 @@ export const SatoshiResponse = Type.Object({
rarity: Type.Enum(SatoshiRarity, { examples: ['common'] }),
});

export const ApiStatusResponse = Type.Object({
server_version: Type.String({ examples: [''] }),
status: Type.String(),
block_height: Type.Optional(Type.Integer()),
max_inscription_number: Type.Optional(Type.Integer()),
});

export const NotFoundResponse = Type.Object({
error: Type.Literal('Not found'),
});
17 changes: 16 additions & 1 deletion src/pg/pg-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,21 @@ export class PgStore extends BasePgStore {
}

async updateChainTipBlockHeight(args: { blockHeight: number }): Promise<void> {
await this.sql`UPDATE chain_tip SET block_height = ${args.blockHeight}`;
await this.sql`
UPDATE chain_tip SET block_height = GREATEST(${args.blockHeight}, block_height)
`;
}

async getChainTipBlockHeight(): Promise<number> {
const result = await this.sql<{ block_height: number }[]>`SELECT block_height FROM chain_tip`;
return result[0].block_height;
}

async getMaxInscriptionNumber(): Promise<number | undefined> {
const result = await this.sql<{ max: number }[]>`SELECT MAX(number) FROM inscriptions`;
if (result[0].max) {
return result[0].max;
}
}

async getInscriptionTransfersETag(): Promise<string> {
Expand Down Expand Up @@ -85,6 +99,7 @@ export class PgStore extends BasePgStore {
RETURNING ${this.sql(LOCATIONS_COLUMNS)}
`;
}
await this.updateChainTipBlockHeight({ blockHeight: args.location.block_height });
});
}

Expand Down
21 changes: 21 additions & 0 deletions src/server-version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { readFileSync } from 'fs';

interface ServerVersion {
branch: string;
commit: string;
tag: string;
}

function getServerVersion(): ServerVersion {
if (process.env.NODE_ENV === 'test') {
return {
branch: 'test',
commit: '123456',
tag: 'v0.0.1',
};
}
const [branch, commit, tag] = readFileSync('.git-info', 'utf-8').split('\n');
return { branch, commit, tag };
}

export const SERVER_VERSION = getServerVersion();
1 change: 0 additions & 1 deletion tests/cache.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildApiServer } from '../src/api/init';
import { ENV } from '../src/env';
import { cycleMigrations } from '../src/pg/migrations';
import { PgStore } from '../src/pg/pg-store';
import { TestFastifyServer } from './helpers';
Expand Down
1 change: 0 additions & 1 deletion tests/inscriptions.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildApiServer } from '../src/api/init';
import { ENV } from '../src/env';
import { cycleMigrations } from '../src/pg/migrations';
import { PgStore } from '../src/pg/pg-store';
import { TestFastifyServer } from './helpers';
Expand Down
1 change: 0 additions & 1 deletion tests/sats.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildApiServer } from '../src/api/init';
import { ENV } from '../src/env';
import { cycleMigrations } from '../src/pg/migrations';
import { PgStore } from '../src/pg/pg-store';
import { TestFastifyServer } from './helpers';
Expand Down
72 changes: 72 additions & 0 deletions tests/status.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { buildApiServer } from '../src/api/init';
import { cycleMigrations } from '../src/pg/migrations';
import { PgStore } from '../src/pg/pg-store';
import { TestFastifyServer } from './helpers';

describe('Status', () => {
let db: PgStore;
let fastify: TestFastifyServer;

beforeEach(async () => {
db = await PgStore.connect({ skipMigrations: true });
fastify = await buildApiServer({ db });
await cycleMigrations();
});

afterEach(async () => {
await fastify.close();
await db.close();
});

test('returns status when db is empty', async () => {
const response = await fastify.inject({ method: 'GET', url: '/ordinals/v1/' });
const json = response.json();
expect(json).toStrictEqual({
server_version: 'ordinals-api v0.0.1 (test:123456)',
status: 'ready',
block_height: 0,
});
const noVersionResponse = await fastify.inject({ method: 'GET', url: '/ordinals/' });
expect(response.statusCode).toEqual(noVersionResponse.statusCode);
expect(json).toStrictEqual(noVersionResponse.json());
});

test('returns inscriptions total', async () => {
await db.insertInscriptionGenesis({
inscription: {
genesis_id: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dci0',
mime_type: 'image/png',
content_type: 'image/png',
content_length: 5,
number: 7,
content: '0x48656C6C6F',
fee: 2805n,
},
location: {
inscription_id: 0,
block_height: 775617,
block_hash: '00000000000000000002a90330a99f67e3f01eb2ce070b45930581e82fb7a91d',
tx_id: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc',
address: 'bc1p3cyx5e2hgh53w7kpxcvm8s4kkega9gv5wfw7c4qxsvxl0u8x834qf0u2td',
output: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dc:0',
offset: 0n,
value: 10000n,
timestamp: 1676913207,
sat_ordinal: 257418248345364n,
sat_rarity: 'common',
sat_coinbase_height: 650000,
genesis: true,
current: true,
},
});

const response = await fastify.inject({ method: 'GET', url: '/ordinals/v1/' });
const json = response.json();
expect(json).toStrictEqual({
server_version: 'ordinals-api v0.0.1 (test:123456)',
status: 'ready',
block_height: 775617,
max_inscription_number: 7,
});
});
});

0 comments on commit e42b351

Please sign in to comment.