Skip to content

Commit 0203d36

Browse files
BLuEScioNzone117xsemantic-release-bot
authored
feat(agg-paging-limits): aggregated all paging query limits (#1401)
* fix: log PoisonMicroblock tx instead rather than throwing (#1379) * chore(release): 6.1.1 [skip ci] ## [6.1.1](v6.1.0...v6.1.1) (2022-10-24) ### Bug Fixes * log PoisonMicroblock tx instead rather than throwing ([#1379](#1379)) ([cee6352](cee6352)) * feat(agg-paging-limits): aggregated all paging query limits * feat(agg-query-limits): fixed query limit calls and tests * feat(agg-query-limits): fixed tests * feat(agg-query-limits): clean pr * feat(limit-pagesize): addressed pr feedback * feat(agg-pagesize-limits): work in progress * feat(agg-query-limits): cleaning pr * feat(agg-query-limits): cleaning pr * feat(agg-query-limits): cleaning pr * feat(agg-query-limits): cleaning pr * feat(agg-query-limits): fixing tests * fix(add-query-limit): cleaning pr * feat(agg-query-limits): fixing tests Co-authored-by: Matthew Little <[email protected]> Co-authored-by: semantic-release-bot <[email protected]> Co-authored-by: Nick Barnett <[email protected]>
1 parent 7add12c commit 0203d36

File tree

15 files changed

+133
-167
lines changed

15 files changed

+133
-167
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## [6.1.1](https://github.com/hirosystems/stacks-blockchain-api/compare/v6.1.0...v6.1.1) (2022-10-24)
2+
3+
4+
### Bug Fixes
5+
6+
* log PoisonMicroblock tx instead rather than throwing ([#1379](https://github.com/hirosystems/stacks-blockchain-api/issues/1379)) ([cee6352](https://github.com/hirosystems/stacks-blockchain-api/commit/cee63529b4785d9bedc8fcfd568a27aedef0914d))
7+
18
## [6.1.0](https://github.com/hirosystems/stacks-blockchain-api/compare/v6.0.4...v6.1.0) (2022-10-13)
29

310

src/api/pagination.ts

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,58 @@ export function parsePagingQueryInput(val: any) {
2525
return parsedInput;
2626
}
2727

28-
interface ParseLimitQueryParams {
29-
maxItems: number;
30-
errorMsg: string;
28+
export enum ResourceType {
29+
Block,
30+
Tx,
31+
Event,
32+
Burnchain,
33+
Contract,
34+
Microblock,
35+
Token,
3136
}
3237

33-
export function parseLimitQuery({ maxItems, errorMsg }: ParseLimitQueryParams) {
34-
return (val: any) => {
35-
const limit = parsePagingQueryInput(val);
36-
if (limit > maxItems)
37-
throw new InvalidRequestError(errorMsg, InvalidRequestErrorType.invalid_query);
38-
return limit;
39-
};
38+
const pagingQueryLimits: Record<ResourceType, { defaultLimit: number; maxLimit: number }> = {
39+
[ResourceType.Block]: {
40+
defaultLimit: 20,
41+
maxLimit: 30,
42+
},
43+
[ResourceType.Tx]: {
44+
defaultLimit: 20,
45+
maxLimit: 50,
46+
},
47+
[ResourceType.Event]: {
48+
defaultLimit: 20,
49+
maxLimit: 50,
50+
},
51+
[ResourceType.Burnchain]: {
52+
defaultLimit: 96,
53+
maxLimit: 250,
54+
},
55+
[ResourceType.Contract]: {
56+
defaultLimit: 20,
57+
maxLimit: 50,
58+
},
59+
[ResourceType.Microblock]: {
60+
defaultLimit: 20,
61+
maxLimit: 200,
62+
},
63+
[ResourceType.Token]: {
64+
defaultLimit: 50,
65+
maxLimit: 200,
66+
},
67+
};
68+
69+
export function getPagingQueryLimit(resourceType: ResourceType, limitOverride?: any) {
70+
const pagingQueryLimit = pagingQueryLimits[resourceType];
71+
if (!limitOverride) {
72+
return pagingQueryLimit.defaultLimit;
73+
}
74+
const newLimit = parsePagingQueryInput(limitOverride);
75+
if (newLimit > pagingQueryLimit.maxLimit) {
76+
throw new InvalidRequestError(
77+
`'limit' must be equal to or less than ${pagingQueryLimit.maxLimit}`,
78+
InvalidRequestErrorType.invalid_query
79+
);
80+
}
81+
return newLimit;
4082
}

src/api/routes/address.ts

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@ import * as express from 'express';
22
import { asyncHandler } from '../async-handler';
33
import * as Bluebird from 'bluebird';
44
import { BlockIdentifier } from '../../datastore/common';
5-
import { parseLimitQuery, parsePagingQueryInput } from '../pagination';
5+
import { getPagingQueryLimit, parsePagingQueryInput, ResourceType } from '../pagination';
66
import {
77
isUnanchoredRequest,
88
getBlockParams,
99
parseUntilBlockQuery,
1010
validatePrincipal,
1111
} from '../query-helpers';
1212
import {
13-
bufferToHexPrefixString,
1413
formatMapToObject,
1514
getSendManyContract,
1615
has0xPrefix,
@@ -52,25 +51,6 @@ import {
5251
} from '../controllers/cache-controller';
5352
import { PgStore } from '../../datastore/pg-store';
5453

55-
const MAX_TX_PER_REQUEST = 50;
56-
const MAX_ASSETS_PER_REQUEST = 50;
57-
const MAX_STX_INBOUND_PER_REQUEST = 500;
58-
59-
const parseTxQueryLimit = parseLimitQuery({
60-
maxItems: MAX_TX_PER_REQUEST,
61-
errorMsg: '`limit` must be equal to or less than ' + MAX_TX_PER_REQUEST,
62-
});
63-
64-
const parseAssetsQueryLimit = parseLimitQuery({
65-
maxItems: MAX_ASSETS_PER_REQUEST,
66-
errorMsg: '`limit` must be equal to or less than ' + MAX_ASSETS_PER_REQUEST,
67-
});
68-
69-
const parseStxInboundLimit = parseLimitQuery({
70-
maxItems: MAX_STX_INBOUND_PER_REQUEST,
71-
errorMsg: '`limit` must be equal to or less than ' + MAX_STX_INBOUND_PER_REQUEST,
72-
});
73-
7454
async function getBlockHeight(
7555
untilBlock: number | string | undefined,
7656
req: Request,
@@ -246,7 +226,7 @@ export function createAddressRouter(db: PgStore, chainId: ChainID): express.Rout
246226
} else {
247227
blockHeight = await getBlockHeight(untilBlock, req, res, next, db);
248228
}
249-
const limit = parseTxQueryLimit(req.query.limit ?? 20);
229+
const limit = getPagingQueryLimit(ResourceType.Tx, req.query.limit);
250230
const offset = parsePagingQueryInput(req.query.offset ?? 0);
251231

252232
const { results: txResults, total } = await db.getAddressTxs({
@@ -322,7 +302,7 @@ export function createAddressRouter(db: PgStore, chainId: ChainID): express.Rout
322302
} else {
323303
blockHeight = await getBlockHeight(untilBlock, req, res, next, db);
324304
}
325-
const limit = parseTxQueryLimit(req.query.limit ?? 20);
305+
const limit = getPagingQueryLimit(ResourceType.Tx, req.query.limit);
326306
const offset = parsePagingQueryInput(req.query.offset ?? 0);
327307
const { results: txResults, total } = await db.getAddressTxsWithAssetTransfers({
328308
stxAddress: stxAddress,
@@ -395,7 +375,7 @@ export function createAddressRouter(db: PgStore, chainId: ChainID): express.Rout
395375
const untilBlock = parseUntilBlockQuery(req, res, next);
396376
const blockHeight = await getBlockHeight(untilBlock, req, res, next, db);
397377

398-
const limit = parseAssetsQueryLimit(req.query.limit ?? 20);
378+
const limit = getPagingQueryLimit(ResourceType.Event, req.query.limit);
399379
const offset = parsePagingQueryInput(req.query.offset ?? 0);
400380
const { results: assetEvents, total } = await db.getAddressAssetEvents({
401381
stxAddress,
@@ -442,7 +422,7 @@ export function createAddressRouter(db: PgStore, chainId: ChainID): express.Rout
442422
blockHeight = await getBlockHeight(untilBlock, req, res, next, db);
443423
}
444424

445-
const limit = parseStxInboundLimit(req.query.limit ?? 20);
425+
const limit = getPagingQueryLimit(ResourceType.Tx, req.query.limit);
446426
const offset = parsePagingQueryInput(req.query.offset ?? 0);
447427
const { results, total } = await db.getInboundTransfers({
448428
stxAddress,
@@ -489,7 +469,7 @@ export function createAddressRouter(db: PgStore, chainId: ChainID): express.Rout
489469

490470
const untilBlock = parseUntilBlockQuery(req, res, next);
491471
const blockHeight = await getBlockHeight(untilBlock, req, res, next, db);
492-
const limit = parseAssetsQueryLimit(req.query.limit ?? 20);
472+
const limit = getPagingQueryLimit(ResourceType.Event, req.query.limit);
493473
const offset = parsePagingQueryInput(req.query.offset ?? 0);
494474
const includeUnanchored = isUnanchoredRequest(req, res, next);
495475

@@ -533,7 +513,7 @@ export function createAddressRouter(db: PgStore, chainId: ChainID): express.Rout
533513
'/:address/mempool',
534514
mempoolCacheHandler,
535515
asyncHandler(async (req, res, next) => {
536-
const limit = parseTxQueryLimit(req.query.limit ?? MAX_TX_PER_REQUEST);
516+
const limit = getPagingQueryLimit(ResourceType.Tx, req.query.limit);
537517
const offset = parsePagingQueryInput(req.query.offset ?? 0);
538518

539519
const address = req.params['address'];

src/api/routes/block.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,22 @@
11
import * as express from 'express';
2-
import * as Bluebird from 'bluebird';
32
import { BlockListResponse } from '@stacks/stacks-blockchain-api-types';
4-
53
import { getBlockFromDataStore, getBlocksWithMetadata } from '../controllers/db-controller';
6-
import { timeout, waiter, has0xPrefix } from '../../helpers';
4+
import { has0xPrefix } from '../../helpers';
75
import { InvalidRequestError, InvalidRequestErrorType } from '../../errors';
8-
import { parseLimitQuery, parsePagingQueryInput } from '../pagination';
6+
import { getPagingQueryLimit, parsePagingQueryInput, ResourceType } from '../pagination';
97
import { getBlockHeightPathParam, validateRequestHexInput } from '../query-helpers';
108
import { getETagCacheHandler, setETagCacheHeaders } from '../controllers/cache-controller';
119
import { asyncHandler } from '../async-handler';
1210
import { PgStore } from '../../datastore/pg-store';
1311

14-
const MAX_BLOCKS_PER_REQUEST = 30;
15-
16-
const parseBlockQueryLimit = parseLimitQuery({
17-
maxItems: MAX_BLOCKS_PER_REQUEST,
18-
errorMsg: '`limit` must be equal to or less than ' + MAX_BLOCKS_PER_REQUEST,
19-
});
20-
2112
export function createBlockRouter(db: PgStore): express.Router {
2213
const router = express.Router();
2314
const cacheHandler = getETagCacheHandler(db);
2415
router.get(
2516
'/',
2617
cacheHandler,
2718
asyncHandler(async (req, res) => {
28-
const limit = parseBlockQueryLimit(req.query.limit ?? 20);
19+
const limit = getPagingQueryLimit(ResourceType.Block, req.query.limit);
2920
const offset = parsePagingQueryInput(req.query.offset ?? 0);
3021

3122
const { results, total } = await getBlocksWithMetadata({ offset, limit, db });

src/api/routes/burnchain.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,16 @@ import {
1010

1111
import { isValidBitcoinAddress, tryConvertC32ToBtc } from '../../helpers';
1212
import { InvalidRequestError, InvalidRequestErrorType } from '../../errors';
13-
import { parseLimitQuery, parsePagingQueryInput } from '../pagination';
13+
import { getPagingQueryLimit, parsePagingQueryInput, ResourceType } from '../pagination';
1414
import { PgStore } from '../../datastore/pg-store';
1515

16-
const MAX_BLOCKS_PER_REQUEST = 250;
17-
18-
const parseQueryLimit = parseLimitQuery({
19-
maxItems: MAX_BLOCKS_PER_REQUEST,
20-
errorMsg: '`limit` must be equal to or less than ' + MAX_BLOCKS_PER_REQUEST,
21-
});
22-
2316
export function createBurnchainRouter(db: PgStore): express.Router {
2417
const router = express.Router();
2518

2619
router.get(
2720
'/reward_slot_holders',
2821
asyncHandler(async (req, res) => {
29-
const limit = parseQueryLimit(req.query.limit ?? 96);
22+
const limit = getPagingQueryLimit(ResourceType.Burnchain, req.query.limit);
3023
const offset = parsePagingQueryInput(req.query.offset ?? 0);
3124

3225
const queryResults = await db.getBurnchainRewardSlotHolders({ offset, limit });
@@ -53,7 +46,7 @@ export function createBurnchainRouter(db: PgStore): express.Router {
5346
router.get(
5447
'/reward_slot_holders/:address',
5548
asyncHandler(async (req, res) => {
56-
const limit = parseQueryLimit(req.query.limit ?? 96);
49+
const limit = getPagingQueryLimit(ResourceType.Burnchain, req.query.limit);
5750
const offset = parsePagingQueryInput(req.query.offset ?? 0);
5851
const { address } = req.params;
5952

@@ -102,7 +95,7 @@ export function createBurnchainRouter(db: PgStore): express.Router {
10295
router.get(
10396
'/rewards',
10497
asyncHandler(async (req, res) => {
105-
const limit = parseQueryLimit(req.query.limit ?? 96);
98+
const limit = getPagingQueryLimit(ResourceType.Burnchain, req.query.limit);
10699
const offset = parsePagingQueryInput(req.query.offset ?? 0);
107100

108101
const queryResults = await db.getBurnchainRewards({ offset, limit });
@@ -127,7 +120,7 @@ export function createBurnchainRouter(db: PgStore): express.Router {
127120
router.get(
128121
'/rewards/:address',
129122
asyncHandler(async (req, res) => {
130-
const limit = parseQueryLimit(req.query.limit ?? 96);
123+
const limit = getPagingQueryLimit(ResourceType.Burnchain, req.query.limit);
131124
const offset = parsePagingQueryInput(req.query.offset ?? 0);
132125
const { address } = req.params;
133126

src/api/routes/contract.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,18 @@
11
import * as express from 'express';
22
import { asyncHandler } from '../async-handler';
3-
import { parseLimitQuery, parsePagingQueryInput } from '../pagination';
3+
import { getPagingQueryLimit, parsePagingQueryInput, ResourceType } from '../pagination';
44
import { parseDbEvent } from '../controllers/db-controller';
55
import { parseTraitAbi } from '../query-helpers';
66
import { PgStore } from '../../datastore/pg-store';
77

8-
const MAX_EVENTS_PER_REQUEST = 50;
9-
const parseContractEventsQueryLimit = parseLimitQuery({
10-
maxItems: MAX_EVENTS_PER_REQUEST,
11-
errorMsg: '`limit` must be equal to or less than ' + MAX_EVENTS_PER_REQUEST,
12-
});
13-
148
export function createContractRouter(db: PgStore): express.Router {
159
const router = express.Router();
1610

1711
router.get(
1812
'/by_trait',
1913
asyncHandler(async (req, res, next) => {
2014
const trait_abi = parseTraitAbi(req, res, next);
21-
const limit = parseContractEventsQueryLimit(req.query.limit ?? 20);
15+
const limit = getPagingQueryLimit(ResourceType.Contract, req.query.limit);
2216
const offset = parsePagingQueryInput(req.query.offset ?? 0);
2317
const smartContracts = await db.getSmartContractByTrait({
2418
trait: trait_abi,
@@ -58,7 +52,7 @@ export function createContractRouter(db: PgStore): express.Router {
5852
'/:contract_id/events',
5953
asyncHandler(async (req, res) => {
6054
const { contract_id } = req.params;
61-
const limit = parseContractEventsQueryLimit(req.query.limit ?? 20);
55+
const limit = getPagingQueryLimit(ResourceType.Contract, req.query.limit);
6256
const offset = parsePagingQueryInput(req.query.offset ?? 0);
6357
const eventsQuery = await db.getSmartContractEvents({
6458
contractId: contract_id,

src/api/routes/microblock.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,17 @@ import {
1111
getUnanchoredTxsFromDataStore,
1212
} from '../controllers/db-controller';
1313
import { has0xPrefix } from '../../helpers';
14-
import { parseLimitQuery, parsePagingQueryInput } from '../pagination';
14+
import { getPagingQueryLimit, parsePagingQueryInput, ResourceType } from '../pagination';
1515
import { validateRequestHexInput } from '../query-helpers';
1616
import { PgStore } from '../../datastore/pg-store';
1717

18-
const MAX_MICROBLOCKS_PER_REQUEST = 200;
19-
20-
const parseMicroblockQueryLimit = parseLimitQuery({
21-
maxItems: MAX_MICROBLOCKS_PER_REQUEST,
22-
errorMsg: '`limit` must be equal to or less than ' + MAX_MICROBLOCKS_PER_REQUEST,
23-
});
24-
2518
export function createMicroblockRouter(db: PgStore): express.Router {
2619
const router = express.Router();
2720

2821
router.get(
2922
'/',
3023
asyncHandler(async (req, res) => {
31-
const limit = parseMicroblockQueryLimit(req.query.limit ?? 20);
24+
const limit = getPagingQueryLimit(ResourceType.Microblock, req.query.limit);
3225
const offset = parsePagingQueryInput(req.query.offset ?? 0);
3326
const query = await getMicroblocksFromDataStore({ db, offset, limit });
3427
const response: MicroblockListResponse = {

src/api/routes/rosetta/mempool.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import * as express from 'express';
22
import { asyncHandler } from '../../async-handler';
33
import { PgStore } from '../../../datastore/pg-store';
44
import { has0xPrefix } from '../../../helpers';
5-
import { parseLimitQuery } from '../../pagination';
65
import { rosettaValidateRequest, ValidSchema, makeRosettaError } from '../../rosetta-validate';
76
import {
87
RosettaMempoolResponse,
@@ -13,12 +12,6 @@ import { getOperations, parseTransactionMemo } from '../../../rosetta-helpers';
1312
import { RosettaErrors, RosettaErrorsTypes } from '../../rosetta-constants';
1413
import { ChainID } from '@stacks/transactions';
1514

16-
const MAX_MEMPOOL_TXS_PER_REQUEST = 200;
17-
const parseMempoolTxQueryLimit = parseLimitQuery({
18-
maxItems: MAX_MEMPOOL_TXS_PER_REQUEST,
19-
errorMsg: `'limit' must be equal to or less than ${MAX_MEMPOOL_TXS_PER_REQUEST}`,
20-
});
21-
2215
export function createRosettaMempoolRouter(db: PgStore, chainId: ChainID): express.Router {
2316
const router = express.Router();
2417
router.use(express.json());

0 commit comments

Comments
 (0)