Skip to content

Commit 6c88a16

Browse files
authored
fix: guard against empty lists before querying postgres (#1345)
1 parent 8709ea1 commit 6c88a16

File tree

2 files changed

+45
-28
lines changed

2 files changed

+45
-28
lines changed

src/datastore/pg-store.ts

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,12 @@ export class PgStore {
417417
indexBlockHashValues.push(indexBytea, parentBytea);
418418
blockHashValues.push(indexBytea);
419419
});
420+
if (blockHashValues.length === 0) {
421+
return {
422+
results: [],
423+
total: 0,
424+
};
425+
}
420426

421427
// get txs in those blocks
422428
const txs = await sql<{ tx_id: string; index_block_hash: string }[]>`
@@ -942,6 +948,9 @@ export class PgStore {
942948
includeUnanchored: boolean;
943949
includePruned?: boolean;
944950
}): Promise<DbMempoolTx[]> {
951+
if (args.txIds.length === 0) {
952+
return [];
953+
}
945954
return this.sql.begin(async client => {
946955
const result = await this.sql<MempoolTxQueryResult[]>`
947956
SELECT ${unsafeCols(this.sql, [...MEMPOOL_TX_COLUMNS, abiColumn('mempool_txs')])}
@@ -1818,28 +1827,6 @@ export class PgStore {
18181827
return entries;
18191828
}
18201829

1821-
async getSmartContractList(contractIds: string[]) {
1822-
const result = await this.sql<
1823-
{
1824-
contract_id: string;
1825-
canonical: boolean;
1826-
tx_id: string;
1827-
block_height: number;
1828-
source_code: string;
1829-
abi: unknown | null;
1830-
}[]
1831-
>`
1832-
SELECT DISTINCT ON (contract_id) contract_id, canonical, tx_id, block_height, source_code, abi
1833-
FROM smart_contracts
1834-
WHERE contract_id IN ${contractIds}
1835-
ORDER BY contract_id DESC, abi != 'null' DESC, canonical DESC, microblock_canonical DESC, block_height DESC
1836-
`;
1837-
if (result.length === 0) {
1838-
[];
1839-
}
1840-
return result.map(r => parseQueryResultToSmartContract(r)).map(res => res.result);
1841-
}
1842-
18431830
async getSmartContract(contractId: string) {
18441831
const result = await this.sql<
18451832
{
@@ -2879,9 +2866,10 @@ export class PgStore {
28792866
const nftCustody = args.includeUnanchored
28802867
? this.sql(`nft_custody_unanchored`)
28812868
: this.sql(`nft_custody`);
2882-
const assetIdFilter = args.assetIdentifiers
2883-
? this.sql`AND nft.asset_identifier IN ${this.sql(args.assetIdentifiers)}`
2884-
: this.sql``;
2869+
const assetIdFilter =
2870+
args.assetIdentifiers && args.assetIdentifiers.length > 0
2871+
? this.sql`AND nft.asset_identifier IN ${this.sql(args.assetIdentifiers)}`
2872+
: this.sql``;
28852873
const nftTxResults = await this.sql<
28862874
(NftHoldingInfo & ContractTxQueryResult & { count: number })[]
28872875
>`
@@ -3122,7 +3110,10 @@ export class PgStore {
31223110
}: {
31233111
txIds: string[];
31243112
includeUnanchored: boolean;
3125-
}) {
3113+
}): Promise<DbTx[]> {
3114+
if (txIds.length === 0) {
3115+
return [];
3116+
}
31263117
return this.sql.begin(async sql => {
31273118
const maxBlockHeight = await this.getMaxBlockHeight(sql, { includeUnanchored });
31283119
const result = await sql<ContractTxQueryResult[]>`

src/tests/datastore-tests.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ import {
2121
DbNonFungibleTokenMetadata,
2222
DbFungibleTokenMetadata,
2323
} from '../datastore/common';
24-
import { parseDbEvent } from '../api/controllers/db-controller';
24+
import { getBlocksWithMetadata, parseDbEvent } from '../api/controllers/db-controller';
2525
import * as assert from 'assert';
2626
import { PgWriteStore } from '../datastore/pg-write-store';
2727
import { cycleMigrations, runMigrations } from '../datastore/migrations';
2828
import { getPostgres, PgSqlClient } from '../datastore/connection';
2929
import { bnsNameCV, bufferToHexPrefixString, I32_MAX } from '../helpers';
30-
import { ChainID, intCV, serializeCV } from '@stacks/transactions';
30+
import { ChainID } from '@stacks/transactions';
31+
import { TestBlockBuilder } from '../test-utils/test-builders';
3132

3233
function testEnvVars(
3334
envVars: Record<string, string | undefined>,
@@ -4960,6 +4961,31 @@ describe('postgres datastore', () => {
49604961
if (query.found) expect(query.result).toStrictEqual(ftMetadata);
49614962
});
49624963

4964+
test('empty parameter lists are handled correctly', async () => {
4965+
const block = new TestBlockBuilder({ block_height: 1 }).addTx().build();
4966+
await db.update(block);
4967+
4968+
// Blocks with limit=0
4969+
await expect(getBlocksWithMetadata({ limit: 0, offset: 0, db: db })).resolves.not.toThrow();
4970+
// Mempool search with empty txIds
4971+
await expect(db.getMempoolTxs({ txIds: [], includeUnanchored: true })).resolves.not.toThrow();
4972+
// NFT holdings with empty asset identifier list
4973+
await expect(
4974+
db.getNftHoldings({
4975+
principal: 'S',
4976+
assetIdentifiers: [],
4977+
limit: 10,
4978+
offset: 0,
4979+
includeTxMetadata: false,
4980+
includeUnanchored: true,
4981+
})
4982+
).resolves.not.toThrow();
4983+
// Tx list details with empty txIds
4984+
await expect(
4985+
db.getTxListDetails({ txIds: [], includeUnanchored: true })
4986+
).resolves.not.toThrow();
4987+
});
4988+
49634989
afterEach(async () => {
49644990
await db?.close();
49654991
await runMigrations(undefined, 'down');

0 commit comments

Comments
 (0)