Skip to content

Commit dea1e4f

Browse files
committed
fix: bugs and improvements on transactions query
1 parent 8bdd0eb commit dea1e4f

23 files changed

+6853
-458
lines changed

indexer/src/kadena-server/repository/infra/query-builders/transaction-query-builder.ts

Lines changed: 106 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* This class encapsulates the complex logic for constructing SQL queries
55
* to retrieve transactions from the database with various filtering criteria.
66
*/
7+
import { isNullOrUndefined } from '@/utils/helpers';
78
import {
89
GetTransactionsCountParams,
910
GetTransactionsParams,
@@ -32,47 +33,72 @@ export default class TransactionQueryBuilder {
3233
private createBlockConditions(
3334
params: GetTransactionsParams,
3435
queryParams: Array<string | number | boolean>,
36+
maxHeightFromDb: number,
3537
) {
36-
const { blockHash, chainId, maxHeight, minHeight } = params;
38+
const { blockHash, chainId, maxHeight, minHeight, accountName } = params;
3739
let blocksConditions = '';
3840
const blockParams: (string | number | boolean)[] = [...queryParams];
3941

4042
blockParams.push(true);
4143
blocksConditions += `WHERE b.canonical = $${blockParams.length}`;
4244

43-
// Add block hash condition if specified
4445
if (blockHash) {
4546
blockParams.push(blockHash);
4647
const op = this.operator(blockParams.length);
4748
blocksConditions += `${op} b.hash = $${blockParams.length}`;
4849
}
4950

50-
// Add maximum height condition if specified
51-
if (maxHeight) {
51+
if (isNullOrUndefined(accountName) && maxHeight && !minHeight) {
5252
blockParams.push(maxHeight);
5353
const op = this.operator(blockParams.length);
54-
blocksConditions += `${op} b."height" <= $${blockParams.length}`;
54+
const secondCondition = `LEAST($${blockParams.length}, ${maxHeightFromDb}) - 20`;
55+
blocksConditions += `${op} b."height" <= $${blockParams.length} AND b."height" >= ${secondCondition}`;
56+
}
57+
58+
if (isNullOrUndefined(accountName) && minHeight && !maxHeight) {
59+
if (minHeight < 0) {
60+
throw new Error('minHeight cannot be less than 0');
61+
}
62+
blockParams.push(minHeight);
63+
const op = this.operator(blockParams.length);
64+
blocksConditions += `${op} b."height" >= $${blockParams.length} AND b."height" <= $${blockParams.length} + 20`;
5565
}
5666

57-
// Add minimum height condition if specified
58-
if (minHeight) {
67+
if (isNullOrUndefined(accountName) && minHeight && maxHeight) {
68+
if (minHeight > maxHeight) {
69+
throw new Error('minHeight cannot be greater than maxHeight');
70+
}
71+
72+
blockParams.push(minHeight);
73+
const op = this.operator(blockParams.length);
74+
blockParams.push(maxHeight);
75+
const secondCondition = `LEAST($${blockParams.length - 1} + 20, $${blockParams.length})`;
76+
blocksConditions += `${op} b."height" >= $${blockParams.length - 1} AND b."height" <= ${secondCondition}`;
77+
}
78+
79+
if (!isNullOrUndefined(accountName) && minHeight) {
5980
blockParams.push(minHeight);
6081
const op = this.operator(blockParams.length);
6182
blocksConditions += `${op} b."height" >= $${blockParams.length}`;
6283
}
6384

64-
// Add chain ID condition if specified
65-
if (chainId) {
66-
blockParams.push(chainId);
85+
if (!isNullOrUndefined(accountName) && maxHeight) {
86+
blockParams.push(maxHeight);
6787
const op = this.operator(blockParams.length);
68-
blocksConditions += `${op} b."chainId" = $${blockParams.length}`;
88+
blocksConditions += `${op} b."height" <= $${blockParams.length}`;
6989
}
7090

71-
// Force query to retrieve a smaller set of blocks since only using chainId doesn't filter many rows
72-
if (chainId && !params.after && !params.before && !minHeight && !maxHeight) {
91+
if (!isNullOrUndefined(accountName) && minHeight && maxHeight) {
92+
blockParams.push(minHeight);
93+
const op = this.operator(blockParams.length);
94+
blockParams.push(maxHeight);
95+
blocksConditions += `${op} b."height" >= $${blockParams.length - 1} AND b."height" <= $${blockParams.length}`;
96+
}
97+
98+
if (chainId) {
7399
blockParams.push(chainId);
74100
const op = this.operator(blockParams.length);
75-
blocksConditions += `${op} b."chainId" = $${blockParams.length} AND b."height" > (SELECT max(height) FROM "Blocks") - 1000`;
101+
blocksConditions += `${op} b."chainId" = $${blockParams.length}`;
76102
}
77103

78104
return { blocksConditions, blockParams };
@@ -91,7 +117,15 @@ export default class TransactionQueryBuilder {
91117
params: GetTransactionsParams,
92118
queryParams: Array<string | number | boolean>,
93119
) {
94-
const { accountName, after, before, requestKey, fungibleName, hasTokenId = false } = params;
120+
const {
121+
accountName,
122+
after,
123+
before,
124+
requestKey,
125+
fungibleName,
126+
hasTokenId = false,
127+
isCoinbase,
128+
} = params;
95129
let conditions = '';
96130

97131
const transactionParams: (string | number)[] = [];
@@ -103,6 +137,10 @@ export default class TransactionQueryBuilder {
103137
transactionParams.push(accountName);
104138
const op = localOperator(transactionParams.length);
105139
conditions += `${op} t.sender = $${queryParams.length + transactionParams.length}`;
140+
} else if (!isCoinbase) {
141+
transactionParams.push('coinbase');
142+
const op = localOperator(transactionParams.length);
143+
conditions += `${op} t.sender != $${queryParams.length + transactionParams.length}`;
106144
}
107145

108146
// Add 'after' cursor condition for pagination
@@ -173,10 +211,21 @@ export default class TransactionQueryBuilder {
173211
before?: string | null;
174212
order: string;
175213
limit: number;
214+
maxHeightFromDb: number;
176215
},
177216
) {
178-
const { blockHash, chainId, maxHeight, minHeight, minimumDepth, limit, order, after, before } =
179-
params;
217+
const {
218+
blockHash,
219+
chainId,
220+
maxHeight,
221+
minHeight,
222+
minimumDepth,
223+
limit,
224+
order,
225+
after,
226+
before,
227+
maxHeightFromDb,
228+
} = params;
180229

181230
// Determine if block-based filtering is the primary access pattern
182231
const isBlockQueryFirst = blockHash || minHeight || maxHeight || minimumDepth || chainId;
@@ -189,9 +238,11 @@ export default class TransactionQueryBuilder {
189238
// Build query conditions based on the primary access pattern
190239
if (isBlockQueryFirst) {
191240
// Start with block conditions when block filtering is primary
192-
const { blockParams, blocksConditions: bConditions } = this.createBlockConditions(params, [
193-
limit,
194-
]);
241+
const { blockParams, blocksConditions: bConditions } = this.createBlockConditions(
242+
params,
243+
[limit],
244+
maxHeightFromDb,
245+
);
195246

196247
const { params: txParams, conditions: txConditions } = this.createTransactionConditions(
197248
{ ...params, after, before },
@@ -210,6 +261,7 @@ export default class TransactionQueryBuilder {
210261
const { blocksConditions: bConditions, blockParams } = this.createBlockConditions(
211262
params,
212263
txParams,
264+
maxHeightFromDb,
213265
);
214266

215267
queryParams.push(...blockParams);
@@ -231,27 +283,26 @@ export default class TransactionQueryBuilder {
231283
t.id AS id,
232284
t.creationtime AS "creationTime",
233285
t.hash AS "hashTransaction",
234-
td.nonce AS "nonceTransaction",
235-
td.sigs AS sigs,
236-
td.continuation AS continuation,
286+
NULL AS "nonceTransaction",
287+
NULL AS sigs,
288+
NULL AS continuation,
237289
t.num_events AS "eventCount",
238-
td.pactid AS "pactId",
239-
td.proof AS proof,
240-
td.rollback AS rollback,
290+
NULL AS "pactId",
291+
NULL AS proof,
292+
NULL AS rollback,
241293
t.txid AS txid,
242294
b.height AS "height",
243295
b."hash" AS "blockHash",
244296
b."chainId" AS "chainId",
245-
td.gas AS "gas",
246-
td.step AS step,
247-
td.data AS data,
248-
td.code AS code,
297+
NULL AS "gas",
298+
NULL AS step,
299+
NULL AS data,
300+
NULL AS code,
249301
t.logs AS "logs",
250302
t.result AS "result",
251303
t.requestkey AS "requestKey"
252304
FROM filtered_block b
253305
JOIN "Transactions" t ON b.id = t."blockId"
254-
${params.isCoinbase ? 'LEFT ' : ''} JOIN "TransactionDetails" td ON t.id = td."transactionId"
255306
${transactionsConditions}
256307
ORDER BY t.creationtime ${order}, t.id ${order}
257308
LIMIT $1
@@ -269,29 +320,26 @@ export default class TransactionQueryBuilder {
269320
t.id AS id,
270321
t.creationtime AS "creationTime",
271322
t.hash AS "hashTransaction",
272-
td.nonce AS "nonceTransaction",
273-
td.sigs AS sigs,
274-
td.continuation AS continuation,
323+
NULL AS "nonceTransaction",
324+
NULL AS sigs,
325+
NULL AS continuation,
275326
t.num_events AS "eventCount",
276-
td.pactid AS "pactId",
277-
td.proof AS proof,
278-
td.rollback AS rollback,
327+
NULL AS "pactId",
328+
NULL AS proof,
329+
NULL AS rollback,
279330
t.txid AS txid,
280331
b.height AS "height",
281332
b."hash" AS "blockHash",
282333
b."chainId" AS "chainId",
283-
td.gas AS "gas",
284-
td.step AS step,
285-
td.data AS data,
286-
td.code AS code,
287-
td.nonce,
288-
td.sigs,
334+
NULL AS "gas",
335+
NULL AS step,
336+
NULL AS data,
337+
NULL AS code,
289338
t.logs AS "logs",
290339
t.result AS "result",
291340
t.requestkey AS "requestKey"
292341
FROM filtered_transactions t
293342
JOIN "Blocks" b ON b.id = t."blockId"
294-
${params.isCoinbase ? 'LEFT ' : ''} JOIN "TransactionDetails" td ON t.id = td."transactionId"
295343
${blocksConditions}
296344
LIMIT $1
297345
`;
@@ -327,34 +375,37 @@ export default class TransactionQueryBuilder {
327375
whereCondition = ` WHERE (t.creationtime, t.id) > ($2, $3)`;
328376
}
329377

378+
if (!params.isCoinbase) {
379+
whereCondition += ` AND t.sender != 'coinbase'`;
380+
}
381+
330382
whereCondition += ` AND b.canonical = true`;
331383

332384
let query = `
333385
SELECT
334386
t.id AS id,
335387
t.creationtime AS "creationTime",
336388
t.hash AS "hashTransaction",
337-
td.nonce AS "nonceTransaction",
338-
td.sigs AS sigs,
339-
td.continuation AS continuation,
389+
NULL AS "nonceTransaction",
390+
NULL AS sigs,
391+
NULL AS continuation,
340392
t.num_events AS "eventCount",
341-
td.pactid AS "pactId",
342-
td.proof AS proof,
343-
td.rollback AS rollback,
393+
NULL AS "pactId",
394+
NULL AS proof,
395+
NULL AS rollback,
344396
t.txid AS txid,
345397
b.height AS "height",
346398
b."hash" AS "blockHash",
347399
b."chainId" AS "chainId",
348-
td.gas AS "gas",
349-
td.step AS step,
350-
td.data AS data,
351-
td.code AS code,
400+
NULL AS "gas",
401+
NULL AS step,
402+
NULL AS data,
403+
NULL AS code,
352404
t.logs AS "logs",
353405
t.result AS "result",
354406
t.requestkey AS "requestKey"
355407
FROM "Transactions" t
356408
JOIN "Blocks" b ON b.id = t."blockId"
357-
${params.isCoinbase ? 'LEFT ' : ''} JOIN "TransactionDetails" td ON t.id = td."transactionId"
358409
${whereCondition}
359410
ORDER BY t.creationtime ${params.order}, t.id ${params.order}
360411
LIMIT $1

0 commit comments

Comments
 (0)