Skip to content

Commit

Permalink
fix: add recursion backfill and temporary skip (#198)
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelcr authored Aug 28, 2023
1 parent ab2f7bf commit 63571ee
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 25 deletions.
51 changes: 51 additions & 0 deletions migrations/1693235147508_recursion-backfills.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* 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.addColumn('inscription_recursions', {
ref_inscription_genesis_id: {
type: 'text',
},
});
pgm.sql(`
UPDATE inscription_recursions AS ir
SET ref_inscription_genesis_id = (
SELECT genesis_id FROM inscriptions WHERE id = ir.ref_inscription_id
)
`);
pgm.alterColumn('inscription_recursions', 'ref_inscription_genesis_id', { notNull: true });
pgm.alterColumn('inscription_recursions', 'ref_inscription_id', { allowNull: true });

pgm.createIndex('inscription_recursions', ['ref_inscription_genesis_id']);
pgm.createIndex('inscription_recursions', ['ref_inscription_id'], {
where: 'ref_inscription_id IS NULL',
name: 'inscription_recursions_ref_inscription_id_null_index',
});
pgm.dropConstraint(
'inscription_recursions',
'inscriptions_inscription_id_ref_inscription_id_unique'
);
pgm.createConstraint(
'inscription_recursions',
'inscription_recursions_unique',
'UNIQUE(inscription_id, ref_inscription_genesis_id)'
);
}

export function down(pgm: MigrationBuilder): void {
pgm.dropConstraint('inscription_recursions', 'inscription_recursions_unique');
pgm.dropIndex('inscription_recursions', ['ref_inscription_genesis_id']);
pgm.dropColumn('inscription_recursions', 'ref_inscription_genesis_id');
pgm.dropIndex('inscription_recursions', ['ref_inscription_id'], {
name: 'inscription_recursions_ref_inscription_id_null_index',
});
pgm.sql(`DELETE FROM inscription_recursions WHERE ref_inscription_id IS NULL`);
pgm.alterColumn('inscription_recursions', 'ref_inscription_id', { notNull: true });
pgm.createConstraint(
'inscription_recursions',
'inscriptions_inscription_id_ref_inscription_id_unique',
'UNIQUE(inscription_id, ref_inscription_id)'
);
}
59 changes: 34 additions & 25 deletions src/pg/pg-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -645,10 +645,13 @@ export class PgStore extends BasePgStore {
SET updated_at = NOW()
WHERE genesis_id IN ${sql([...transferGenesisIds])}
`;
await this.updateInscriptionLocationPointers(locations);
await this.updateInscriptionRecursions(writes);
await this.backfillOrphanLocations();
await this.counts.applyInscriptions(inscriptions);
if (ENV.BRC20_BLOCK_SCAN_ENABLED) {
// TODO: Temporary
await this.backfillOrphanLocations();
await this.updateInscriptionLocationPointers(locations);
await this.counts.applyInscriptions(inscriptions);
}
for (const reveal of writes) {
const action = reveal.inscription ? `reveal #${reveal.inscription.number}` : `transfer`;
logger.info(
Expand Down Expand Up @@ -819,11 +822,18 @@ export class PgStore extends BasePgStore {
}

private async backfillOrphanLocations(): Promise<void> {
await this.sql`
UPDATE locations AS l
SET inscription_id = (SELECT id FROM inscriptions WHERE genesis_id = l.genesis_id)
WHERE l.inscription_id IS NULL
`;
await this.sqlWriteTransaction(async sql => {
await sql`
UPDATE locations AS l
SET inscription_id = (SELECT id FROM inscriptions WHERE genesis_id = l.genesis_id)
WHERE l.inscription_id IS NULL
`;
await sql`
UPDATE inscription_recursions AS l
SET ref_inscription_id = (SELECT id FROM inscriptions WHERE genesis_id = l.ref_inscription_genesis_id)
WHERE l.ref_inscription_id IS NULL
`;
});
}

private async recalculateCurrentLocationPointerFromLocationRollBack(args: {
Expand Down Expand Up @@ -859,22 +869,21 @@ export class PgStore extends BasePgStore {

private async updateInscriptionRecursions(reveals: DbRevealInsert[]): Promise<void> {
if (reveals.length === 0) return;
await this.sqlWriteTransaction(async sql => {
// TODO: Gap fills may make us miss some recursion refs because they will not appear in this
// query.
for (const i of reveals)
if (i.inscription && i.recursive_refs?.length)
await sql`
WITH from_i AS (
SELECT id FROM inscriptions WHERE genesis_id = ${i.inscription.genesis_id}
),
to_i AS (
SELECT id FROM inscriptions WHERE genesis_id IN ${sql(i.recursive_refs)}
)
INSERT INTO inscription_recursions (inscription_id, ref_inscription_id)
(SELECT from_i.id, to_i.id FROM from_i, to_i WHERE to_i IS NOT NULL)
ON CONFLICT ON CONSTRAINT inscriptions_inscription_id_ref_inscription_id_unique DO NOTHING
`;
});
const inserts = [];
for (const i of reveals)
if (i.inscription && i.recursive_refs?.length)
for (const ref of i.recursive_refs)
inserts.push({
inscription_id: this
.sql`(SELECT id FROM inscriptions WHERE genesis_id = ${i.inscription.genesis_id})`,
ref_inscription_id: this.sql`(SELECT id FROM inscriptions WHERE genesis_id = ${ref})`,
ref_inscription_genesis_id: ref,
});
if (inserts.length === 0) return;
await this.sql`
INSERT INTO inscription_recursions ${this.sql(inserts)}
ON CONFLICT ON CONSTRAINT inscription_recursions_unique DO UPDATE SET
ref_inscription_id = EXCLUDED.ref_inscription_id
`;
}
}
43 changes: 43 additions & 0 deletions tests/inscriptions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,49 @@ describe('/inscriptions', () => {
});
expect(response2.statusCode).toBe(200);
expect(response2.json()).toStrictEqual(expected);

// Backfill new inscription
await db.updateInscriptions(
new TestChainhookPayloadBuilder()
.apply()
.block({
height: 778600,
hash: '000000000000000000043b10697970720b44c79f6ca2dd604cc83cc015e0c459',
timestamp: 1676913207,
})
.transaction({
hash: 'b4b27b9a15f928b95a8ce4b418946553b7b313a345254cd9b23d79489175fa5a',
})
.inscriptionRevealed({
content_bytes: `0x${Buffer.from('World').toString('hex')}`,
content_type: 'text/plain;charset=utf-8',
content_length: 5,
inscription_number: 200,
inscription_fee: 705,
inscription_id: 'b4b27b9a15f928b95a8ce4b418946553b7b313a345254cd9b23d79489175fa5ai0',
inscription_output_value: 10000,
inscriber_address: 'bc1pscktlmn99gyzlvymvrezh6vwd0l4kg06tg5rvssw0czg8873gz5sdkteqj',
ordinal_number: 257418248345364,
ordinal_block_height: 650000,
ordinal_offset: 0,
satpoint_post_inscription:
'b4b27b9a15f928b95a8ce4b418946553b7b313a345254cd9b23d79489175fa5a:0:0',
tx_index: 0,
inscription_input_index: 0,
transfers_pre_inscription: 0,
})
.build()
);
const response3 = await fastify.inject({
method: 'GET',
url: '/ordinals/v1/inscriptions/38c46a8bf7ec90bc7f6b797e7dc84baa97f4e5fd4286b92fe1b50176d03b18dci0',
});
expect(response3.statusCode).toBe(200);
expect(response3.json().recursion_refs).toStrictEqual([
'9f4a9b73b0713c5da01c0a47f97c6c001af9028d6bdd9e264dfacbc4e6790201i0',
'f351d86c6e6cae3c64e297e7463095732f216875bcc1f3c03f950a492bb25421i0',
'b4b27b9a15f928b95a8ce4b418946553b7b313a345254cd9b23d79489175fa5ai0',
]);
});

test('shows inscription with null genesis address', async () => {
Expand Down

0 comments on commit 63571ee

Please sign in to comment.