mirror of
https://github.com/alexgo-io/stacks-blockchain-api.git
synced 2026-01-12 16:53:19 +08:00
fix: guard against empty lists before querying postgres (#1345)
This commit is contained in:
@@ -417,6 +417,12 @@ export class PgStore {
|
||||
indexBlockHashValues.push(indexBytea, parentBytea);
|
||||
blockHashValues.push(indexBytea);
|
||||
});
|
||||
if (blockHashValues.length === 0) {
|
||||
return {
|
||||
results: [],
|
||||
total: 0,
|
||||
};
|
||||
}
|
||||
|
||||
// get txs in those blocks
|
||||
const txs = await sql<{ tx_id: string; index_block_hash: string }[]>`
|
||||
@@ -942,6 +948,9 @@ export class PgStore {
|
||||
includeUnanchored: boolean;
|
||||
includePruned?: boolean;
|
||||
}): Promise<DbMempoolTx[]> {
|
||||
if (args.txIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
return this.sql.begin(async client => {
|
||||
const result = await this.sql<MempoolTxQueryResult[]>`
|
||||
SELECT ${unsafeCols(this.sql, [...MEMPOOL_TX_COLUMNS, abiColumn('mempool_txs')])}
|
||||
@@ -1818,28 +1827,6 @@ export class PgStore {
|
||||
return entries;
|
||||
}
|
||||
|
||||
async getSmartContractList(contractIds: string[]) {
|
||||
const result = await this.sql<
|
||||
{
|
||||
contract_id: string;
|
||||
canonical: boolean;
|
||||
tx_id: string;
|
||||
block_height: number;
|
||||
source_code: string;
|
||||
abi: unknown | null;
|
||||
}[]
|
||||
>`
|
||||
SELECT DISTINCT ON (contract_id) contract_id, canonical, tx_id, block_height, source_code, abi
|
||||
FROM smart_contracts
|
||||
WHERE contract_id IN ${contractIds}
|
||||
ORDER BY contract_id DESC, abi != 'null' DESC, canonical DESC, microblock_canonical DESC, block_height DESC
|
||||
`;
|
||||
if (result.length === 0) {
|
||||
[];
|
||||
}
|
||||
return result.map(r => parseQueryResultToSmartContract(r)).map(res => res.result);
|
||||
}
|
||||
|
||||
async getSmartContract(contractId: string) {
|
||||
const result = await this.sql<
|
||||
{
|
||||
@@ -2879,9 +2866,10 @@ export class PgStore {
|
||||
const nftCustody = args.includeUnanchored
|
||||
? this.sql(`nft_custody_unanchored`)
|
||||
: this.sql(`nft_custody`);
|
||||
const assetIdFilter = args.assetIdentifiers
|
||||
? this.sql`AND nft.asset_identifier IN ${this.sql(args.assetIdentifiers)}`
|
||||
: this.sql``;
|
||||
const assetIdFilter =
|
||||
args.assetIdentifiers && args.assetIdentifiers.length > 0
|
||||
? this.sql`AND nft.asset_identifier IN ${this.sql(args.assetIdentifiers)}`
|
||||
: this.sql``;
|
||||
const nftTxResults = await this.sql<
|
||||
(NftHoldingInfo & ContractTxQueryResult & { count: number })[]
|
||||
>`
|
||||
@@ -3122,7 +3110,10 @@ export class PgStore {
|
||||
}: {
|
||||
txIds: string[];
|
||||
includeUnanchored: boolean;
|
||||
}) {
|
||||
}): Promise<DbTx[]> {
|
||||
if (txIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
return this.sql.begin(async sql => {
|
||||
const maxBlockHeight = await this.getMaxBlockHeight(sql, { includeUnanchored });
|
||||
const result = await sql<ContractTxQueryResult[]>`
|
||||
|
||||
@@ -21,13 +21,14 @@ import {
|
||||
DbNonFungibleTokenMetadata,
|
||||
DbFungibleTokenMetadata,
|
||||
} from '../datastore/common';
|
||||
import { parseDbEvent } from '../api/controllers/db-controller';
|
||||
import { getBlocksWithMetadata, parseDbEvent } from '../api/controllers/db-controller';
|
||||
import * as assert from 'assert';
|
||||
import { PgWriteStore } from '../datastore/pg-write-store';
|
||||
import { cycleMigrations, runMigrations } from '../datastore/migrations';
|
||||
import { getPostgres, PgSqlClient } from '../datastore/connection';
|
||||
import { bnsNameCV, bufferToHexPrefixString, I32_MAX } from '../helpers';
|
||||
import { ChainID, intCV, serializeCV } from '@stacks/transactions';
|
||||
import { ChainID } from '@stacks/transactions';
|
||||
import { TestBlockBuilder } from '../test-utils/test-builders';
|
||||
|
||||
function testEnvVars(
|
||||
envVars: Record<string, string | undefined>,
|
||||
@@ -4960,6 +4961,31 @@ describe('postgres datastore', () => {
|
||||
if (query.found) expect(query.result).toStrictEqual(ftMetadata);
|
||||
});
|
||||
|
||||
test('empty parameter lists are handled correctly', async () => {
|
||||
const block = new TestBlockBuilder({ block_height: 1 }).addTx().build();
|
||||
await db.update(block);
|
||||
|
||||
// Blocks with limit=0
|
||||
await expect(getBlocksWithMetadata({ limit: 0, offset: 0, db: db })).resolves.not.toThrow();
|
||||
// Mempool search with empty txIds
|
||||
await expect(db.getMempoolTxs({ txIds: [], includeUnanchored: true })).resolves.not.toThrow();
|
||||
// NFT holdings with empty asset identifier list
|
||||
await expect(
|
||||
db.getNftHoldings({
|
||||
principal: 'S',
|
||||
assetIdentifiers: [],
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
includeTxMetadata: false,
|
||||
includeUnanchored: true,
|
||||
})
|
||||
).resolves.not.toThrow();
|
||||
// Tx list details with empty txIds
|
||||
await expect(
|
||||
db.getTxListDetails({ txIds: [], includeUnanchored: true })
|
||||
).resolves.not.toThrow();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await db?.close();
|
||||
await runMigrations(undefined, 'down');
|
||||
|
||||
Reference in New Issue
Block a user