Skip to content

Commit

Permalink
fix: transfers for inscriptions created immediately before (#320)
Browse files Browse the repository at this point in the history
* fix: transfers for inscriptions created immediately before

* chore: comment style
  • Loading branch information
rafaelcr authored Mar 4, 2024
1 parent 043eaea commit 66ba744
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 20 deletions.
45 changes: 25 additions & 20 deletions src/pg/pg-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -493,14 +493,32 @@ export class PgStore extends BasePgStore {
): Promise<void> {
if (reveals.length === 0) return;
await this.sqlWriteTransaction(async sql => {
// 1. Write inscription reveals
const inscriptionInserts: InscriptionInsert[] = [];
for (const r of reveals) if ('inscription' in r) inscriptionInserts.push(r.inscription);
if (inscriptionInserts.length)
await sql`
INSERT INTO inscriptions ${sql(inscriptionInserts)}
ON CONFLICT ON CONSTRAINT inscriptions_number_unique DO UPDATE SET
genesis_id = EXCLUDED.genesis_id,
mime_type = EXCLUDED.mime_type,
content_type = EXCLUDED.content_type,
content_length = EXCLUDED.content_length,
content = EXCLUDED.content,
fee = EXCLUDED.fee,
sat_ordinal = EXCLUDED.sat_ordinal,
sat_rarity = EXCLUDED.sat_rarity,
sat_coinbase_height = EXCLUDED.sat_coinbase_height,
updated_at = NOW()
`;

// 2. Write locations and transfers
const locationInserts: LocationInsert[] = [];
const revealOutputs: InscriptionEventData[] = [];
const transferredOrdinalNumbersSet = new Set<string>();
for (const r of reveals)
if ('inscription' in r) {
revealOutputs.push(r);
inscriptionInserts.push(r.inscription);
locationInserts.push({
...r.location,
inscription_id: sql`(SELECT id FROM inscriptions WHERE genesis_id = ${r.location.genesis_id})`,
Expand Down Expand Up @@ -535,22 +553,6 @@ export class PgStore extends BasePgStore {
});
}
}
const transferredOrdinalNumbers = [...transferredOrdinalNumbersSet];
if (inscriptionInserts.length)
await sql`
INSERT INTO inscriptions ${sql(inscriptionInserts)}
ON CONFLICT ON CONSTRAINT inscriptions_number_unique DO UPDATE SET
genesis_id = EXCLUDED.genesis_id,
mime_type = EXCLUDED.mime_type,
content_type = EXCLUDED.content_type,
content_length = EXCLUDED.content_length,
content = EXCLUDED.content,
fee = EXCLUDED.fee,
sat_ordinal = EXCLUDED.sat_ordinal,
sat_rarity = EXCLUDED.sat_rarity,
sat_coinbase_height = EXCLUDED.sat_coinbase_height,
updated_at = NOW()
`;
const pointers: DbLocationPointerInsert[] = [];
for (const batch of batchIterate(locationInserts, INSERT_BATCH_SIZE)) {
const pointerBatch = await sql<DbLocationPointerInsert[]>`
Expand All @@ -569,20 +571,23 @@ export class PgStore extends BasePgStore {
await this.updateInscriptionLocationPointers(pointerBatch);
pointers.push(...pointerBatch);
}
await this.updateInscriptionRecursions(reveals);
if (streamed && transferredOrdinalNumbers.length)
if (streamed && transferredOrdinalNumbersSet.size)
await sql`
UPDATE inscriptions
SET updated_at = NOW()
WHERE sat_ordinal IN ${sql(transferredOrdinalNumbers)}
WHERE sat_ordinal IN ${sql([...transferredOrdinalNumbersSet])}
`;

for (const reveal of reveals) {
const action =
'inscription' in reveal
? `reveal #${reveal.inscription.number} (${reveal.location.genesis_id})`
: `transfer sat ${reveal.location.ordinal_number}`;
logger.info(`PgStore ${action} at block ${reveal.location.block_height}`);
}

// 3. Recursions, Counts and BRC-20
await this.updateInscriptionRecursions(reveals);
await this.counts.applyInscriptions(inscriptionInserts);
if (ENV.BRC20_BLOCK_SCAN_ENABLED)
await this.brc20.insertOperations({ reveals: revealOutputs, pointers });
Expand Down
90 changes: 90 additions & 0 deletions tests/ordhook/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,96 @@ describe('EventServer', () => {
const json = response.json();
expect(json.genesis_address).toBe(address);
});

test('inscriptions revealed and immediately transferred in the same block', async () => {
await db.updateInscriptions(
new TestChainhookPayloadBuilder()
.apply()
.block({
height: 832574,
hash: '000000000000000000020c8145de25b1e1e0a6312e377827a3015e15fdd574cd',
})
.transaction({
hash: '53957f47697096cef4ad24dae6357b3d7ffe1e3eb9216ce0bb01d6b6a2c8cf4a',
})
.inscriptionRevealed({
content_bytes:
'0x7b2270223a226272632d3230222c226f70223a227472616e73666572222c227469636b223a224d544d54222c22616d74223a2231303030227d',
content_length: 57,
content_type: 'text/plain;charset=utf-8',
curse_type: null,
delegate: '',
inscriber_address: 'bc1pgfkgsz2gv8cy42csdfgnuepx5g2sm0y3nsccvehjpjnev8990pms7jp9n5',
inscription_fee: 11322,
inscription_id: '53957f47697096cef4ad24dae6357b3d7ffe1e3eb9216ce0bb01d6b6a2c8cf4ai0',
inscription_input_index: 0,
inscription_number: {
classic: 0,
jubilee: 0,
},
inscription_output_value: 8834,
inscription_pointer: 0,
metadata: null,
metaprotocol: '',
ordinal_block_height: 149412,
ordinal_number: 747064132806533,
ordinal_offset: 4132806533,
parent: '',
satpoint_post_inscription:
'53957f47697096cef4ad24dae6357b3d7ffe1e3eb9216ce0bb01d6b6a2c8cf4a:0:0',
transfers_pre_inscription: 0,
tx_index: 2613,
})
.transaction({
hash: '5252157e270d1d405fa5d58249832ca3aa706b84e4dad2a31e7f52373aec2b7b',
})
.inscriptionTransferred({
destination: {
type: 'transferred',
value: 'bc1p80sw4ug55q7p4ha5gsk40d2tszqy7cendt9yksmf4nswzzrq58msp6t7qe',
},
ordinal_number: 747064132806533,
post_transfer_output_value: 546,
satpoint_post_transfer:
'5252157e270d1d405fa5d58249832ca3aa706b84e4dad2a31e7f52373aec2b7b:0:0',
satpoint_pre_transfer:
'53957f47697096cef4ad24dae6357b3d7ffe1e3eb9216ce0bb01d6b6a2c8cf4a:0:0',
tx_index: 2614,
})
.build()
);
const response = await fastify.inject({
method: 'GET',
url: `/ordinals/inscriptions/53957f47697096cef4ad24dae6357b3d7ffe1e3eb9216ce0bb01d6b6a2c8cf4ai0/transfers`,
});
expect(response.statusCode).toBe(200);
const json = response.json();
expect(json.total).toBe(2);
expect(json.results).toStrictEqual([
{
address: 'bc1p80sw4ug55q7p4ha5gsk40d2tszqy7cendt9yksmf4nswzzrq58msp6t7qe',
block_hash: '000000000000000000020c8145de25b1e1e0a6312e377827a3015e15fdd574cd',
block_height: 832574,
location: '5252157e270d1d405fa5d58249832ca3aa706b84e4dad2a31e7f52373aec2b7b:0:0',
offset: '0',
output: '5252157e270d1d405fa5d58249832ca3aa706b84e4dad2a31e7f52373aec2b7b:0',
timestamp: 1677803510000,
tx_id: '5252157e270d1d405fa5d58249832ca3aa706b84e4dad2a31e7f52373aec2b7b',
value: '546',
},
{
address: 'bc1pgfkgsz2gv8cy42csdfgnuepx5g2sm0y3nsccvehjpjnev8990pms7jp9n5',
block_hash: '000000000000000000020c8145de25b1e1e0a6312e377827a3015e15fdd574cd',
block_height: 832574,
location: '53957f47697096cef4ad24dae6357b3d7ffe1e3eb9216ce0bb01d6b6a2c8cf4a:0:0',
offset: '0',
output: '53957f47697096cef4ad24dae6357b3d7ffe1e3eb9216ce0bb01d6b6a2c8cf4a:0',
timestamp: 1677803510000,
tx_id: '53957f47697096cef4ad24dae6357b3d7ffe1e3eb9216ce0bb01d6b6a2c8cf4a',
value: '8834',
},
]);
});
});

describe('gap detection', () => {
Expand Down

0 comments on commit 66ba744

Please sign in to comment.