Skip to content

Commit b9dee2a

Browse files
authored
fix: identify mempool transactions separately when calculating principal etag (#2126)
1 parent 4f5f582 commit b9dee2a

File tree

2 files changed

+75
-5
lines changed

2 files changed

+75
-5
lines changed

src/datastore/pg-store.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4444,15 +4444,15 @@ export class PgStore extends BasePgStore {
44444444
const result = await this.sql<{ tx_id: string }[]>`
44454445
WITH activity AS (
44464446
(
4447-
SELECT tx_id
4447+
SELECT '0x' || encode(tx_id, 'hex') AS tx_id
44484448
FROM principal_stx_txs
44494449
WHERE principal = ${principal} AND canonical = true AND microblock_canonical = true
44504450
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
44514451
LIMIT 1
44524452
)
44534453
UNION
44544454
(
4455-
SELECT tx_id
4455+
SELECT '0x' || encode(tx_id, 'hex') AS tx_id
44564456
FROM ft_events
44574457
WHERE (sender = ${principal} OR recipient = ${principal})
44584458
AND canonical = true
@@ -4462,7 +4462,7 @@ export class PgStore extends BasePgStore {
44624462
)
44634463
UNION
44644464
(
4465-
SELECT tx_id
4465+
SELECT '0x' || encode(tx_id, 'hex') AS tx_id
44664466
FROM nft_events
44674467
WHERE (sender = ${principal} OR recipient = ${principal})
44684468
AND canonical = true
@@ -4474,7 +4474,7 @@ export class PgStore extends BasePgStore {
44744474
includeMempool
44754475
? this.sql`UNION
44764476
(
4477-
SELECT tx_id
4477+
SELECT 'mempool-' || '0x' || encode(tx_id, 'hex') AS tx_id
44784478
FROM mempool_txs
44794479
WHERE pruned = false AND
44804480
(sender_address = ${principal}
@@ -4486,7 +4486,7 @@ export class PgStore extends BasePgStore {
44864486
: this.sql``
44874487
}
44884488
)
4489-
SELECT DISTINCT tx_id FROM activity WHERE tx_id IS NOT NULL
4489+
SELECT tx_id FROM activity WHERE tx_id IS NOT NULL
44904490
`;
44914491
return result.map(r => r.tx_id);
44924492
}

tests/api/cache-control.test.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,76 @@ describe('cache-control tests', () => {
817817
expect(request8.text).toBe('');
818818
});
819819

820+
test('principal mempool cache on received tx balance confirmation', async () => {
821+
const address = 'SP3FXEKSA6D4BW3TFP2BWTSREV6FY863Y90YY7D8G';
822+
const url = `/extended/v1/address/${address}/balances`;
823+
await db.update(
824+
new TestBlockBuilder({
825+
block_height: 1,
826+
index_block_hash: '0x01',
827+
parent_index_block_hash: '0x00',
828+
}).build()
829+
);
830+
831+
// ETag zero.
832+
const request1 = await supertest(api.server).get(url);
833+
expect(request1.status).toBe(200);
834+
expect(request1.type).toBe('application/json');
835+
const etag0 = request1.headers['etag'];
836+
837+
// Add receiving STX tx.
838+
await db.updateMempoolTxs({
839+
mempoolTxs: [
840+
testMempoolTx({
841+
tx_id: '0x0001',
842+
token_transfer_amount: 2000n,
843+
token_transfer_recipient_address: address,
844+
}),
845+
],
846+
});
847+
848+
// Valid ETag.
849+
const request2 = await supertest(api.server).get(url);
850+
expect(request2.status).toBe(200);
851+
expect(request2.type).toBe('application/json');
852+
expect(request2.headers['etag']).toBeTruthy();
853+
const json2 = JSON.parse(request2.text);
854+
expect(json2.stx.balance).toBe('0');
855+
expect(json2.stx.estimated_balance).toBe('2000');
856+
const etag1 = request2.headers['etag'];
857+
expect(etag1).not.toEqual(etag0);
858+
859+
// Cache works with valid ETag.
860+
const request3 = await supertest(api.server).get(url).set('If-None-Match', etag1);
861+
expect(request3.status).toBe(304);
862+
expect(request3.text).toBe('');
863+
864+
// Confirm mempool tx.
865+
await db.update(
866+
new TestBlockBuilder({
867+
block_height: 2,
868+
index_block_hash: '0x02',
869+
parent_index_block_hash: '0x01',
870+
})
871+
.addTx({
872+
tx_id: '0x0001',
873+
token_transfer_amount: 2000n,
874+
token_transfer_recipient_address: address,
875+
})
876+
.addTxStxEvent({ amount: 2000n, recipient: address })
877+
.build()
878+
);
879+
880+
// Cache is now a miss.
881+
const request4 = await supertest(api.server).get(url).set('If-None-Match', etag1);
882+
expect(request4.status).toBe(200);
883+
expect(request4.type).toBe('application/json');
884+
expect(request4.headers['etag']).not.toEqual(etag1);
885+
const json4 = JSON.parse(request4.text);
886+
expect(json4.stx.balance).toBe('2000');
887+
expect(json4.stx.estimated_balance).toBe('2000');
888+
});
889+
820890
test('block cache control', async () => {
821891
await db.update(
822892
new TestBlockBuilder({

0 commit comments

Comments
 (0)