Skip to content

Commit

Permalink
feat: chain tip cache for index
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelcr committed Feb 28, 2023
1 parent b9370d8 commit 7019f98
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 2 deletions.
3 changes: 2 additions & 1 deletion src/api/routes/inscriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
Order,
InscriptionIdParam,
} from '../types';
import { handleInscriptionCache } from '../util/cache';
import { handleChainTipCache, handleInscriptionCache } from '../util/cache';
import {
DEFAULT_API_LIMIT,
hexToBuffer,
Expand All @@ -38,6 +38,7 @@ const IndexRoutes: FastifyPluginCallback<Record<never, never>, Server, TypeBoxTy
options,
done
) => {
fastify.addHook('preHandler', handleChainTipCache);
fastify.get(
'/inscriptions',
{
Expand Down
26 changes: 25 additions & 1 deletion src/api/util/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,20 @@ export async function handleInscriptionCache(request: FastifyRequest, reply: Fas
return handleCache(ETagType.inscription, request, reply);
}

export async function handleChainTipCache(request: FastifyRequest, reply: FastifyReply) {
return handleCache(ETagType.chainTip, request, reply);
}

async function handleCache(type: ETagType, request: FastifyRequest, reply: FastifyReply) {
const ifNoneMatch = parseIfNoneMatchHeader(request.headers['if-none-match']);
let etag: string | undefined;
switch (type) {
case ETagType.inscription:
etag = await getInscriptionLocationEtag(request);
break;
case ETagType.chainTip:
etag = await getChainTipEtag(request);
break;
}
if (etag) {
if (ifNoneMatch && ifNoneMatch.includes(etag)) {
Expand All @@ -44,6 +51,7 @@ export function setReplyNonCacheable(reply: FastifyReply) {
/**
* Retrieve the inscriptions's location timestamp as a UNIX epoch so we can use it as the response
* ETag.
* @param request - Fastify request
* @returns Etag string
*/
async function getInscriptionLocationEtag(request: FastifyRequest): Promise<string | undefined> {
Expand All @@ -62,7 +70,23 @@ async function getInscriptionLocationEtag(request: FastifyRequest): Promise<stri
if (!inscription_id) return;
return await request.server.db.getInscriptionETag({ inscription_id });
} catch (error) {
return undefined;
return;
}
}

/**
* Get an ETag based on the last observed chain tip.
* @param request - Fastify request
* @returns ETag string
*/
async function getChainTipEtag(request: FastifyRequest): Promise<string | undefined> {
try {
const blockHeight = await request.server.db.getChainTipBlockHeight();
if (blockHeight) {
return blockHeight.toString();
}
} catch (error) {
return;
}
}

Expand Down
79 changes: 79 additions & 0 deletions tests/cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,83 @@ describe('ETag cache', () => {
});
expect(cached2.statusCode).toBe(200);
});

test('inscriptions index cache control', async () => {
await db.insertInscriptionGenesis({
inscription: {
genesis_id: '9f4a9b73b0713c5da01c0a47f97c6c001af9028d6bdd9e264dfacbc4e6790201i0',
mime_type: 'text/plain',
content_type: 'text/plain;charset=utf-8',
content_length: 5,
content: '0x48656C6C6F',
fee: 705n,
},
location: {
inscription_id: 0,
block_height: 778575,
block_hash: '00000000000000000002a90330a99f67e3f01eb2ce070b45930581e82fb7a91d',
tx_id: '9f4a9b73b0713c5da01c0a47f97c6c001af9028d6bdd9e264dfacbc4e6790201',
address: 'bc1pscktlmn99gyzlvymvrezh6vwd0l4kg06tg5rvssw0czg8873gz5sdkteqj',
output: '9f4a9b73b0713c5da01c0a47f97c6c001af9028d6bdd9e264dfacbc4e6790201:0',
offset: 0n,
value: 10000n,
timestamp: 1676913207,
sat_ordinal: 257418248345364n,
sat_rarity: 'common',
genesis: true,
current: true,
},
});
await db.insertInscriptionGenesis({
inscription: {
genesis_id: '38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dci0',
mime_type: 'image/png',
content_type: 'image/png',
content_length: 5,
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',
genesis: true,
current: true,
},
});

// ETag response
const response = await fastify.inject({
method: 'GET',
url: '/inscriptions',
});
expect(response.statusCode).toBe(200);
expect(response.headers.etag).not.toBeUndefined();
const etag = response.headers.etag;

// Cached
const cached = await fastify.inject({
method: 'GET',
url: '/inscriptions',
headers: { 'if-none-match': etag },
});
expect(cached.statusCode).toBe(304);

// Simulate new chain tip
await db.updateChainTipBlockHeight({ blockHeight: 5 });
const cached2 = await fastify.inject({
method: 'GET',
url: '/inscriptions',
headers: { 'if-none-match': etag },
});
expect(cached2.statusCode).toBe(200);
});
});

0 comments on commit 7019f98

Please sign in to comment.