From 88c9b02711f2ca17220945b83ad341e8aa8b3999 Mon Sep 17 00:00:00 2001 From: Enzo Cioppettini Date: Tue, 30 Jan 2024 01:15:38 -0300 Subject: [PATCH] make input addresses and metadata optional (as an arg) --- .../TransactionHistoryController.ts | 1 + .../sqlHistoryForAddresses.queries.ts | 73 +++++++++++++------ .../transaction/sqlHistoryForAddresses.sql | 66 +++++++++++------ .../sqlHistoryForCredentials.queries.ts | 66 +++++++++++------ .../transaction/sqlHistoryForCredentials.sql | 59 ++++++++++----- .../app/services/TransactionHistoryService.ts | 36 ++++++--- webserver/shared/models/TransactionHistory.ts | 5 +- 7 files changed, 206 insertions(+), 100 deletions(-) diff --git a/webserver/server/app/controllers/TransactionHistoryController.ts b/webserver/server/app/controllers/TransactionHistoryController.ts index a136be13..9c9a1c0a 100644 --- a/webserver/server/app/controllers/TransactionHistoryController.ts +++ b/webserver/server/app/controllers/TransactionHistoryController.ts @@ -125,6 +125,7 @@ export class TransactionHistoryController extends Controller { limit: requestBody.limit ?? ADDRESS_LIMIT.RESPONSE, until, dbTx, + withInputContext: !!requestBody.withInputContext }; const result = await Promise.all([ historyForCredentials({ diff --git a/webserver/server/app/models/transaction/sqlHistoryForAddresses.queries.ts b/webserver/server/app/models/transaction/sqlHistoryForAddresses.queries.ts index c9b8f040..53899d00 100644 --- a/webserver/server/app/models/transaction/sqlHistoryForAddresses.queries.ts +++ b/webserver/server/app/models/transaction/sqlHistoryForAddresses.queries.ts @@ -13,6 +13,7 @@ export interface ISqlHistoryForAddressesParams { after_tx_id?: NumberOrString | null | void; limit?: NumberOrString | null | void; until_tx_id?: NumberOrString | null | void; + with_input_context: boolean; } /** 'SqlHistoryForAddresses' return type */ @@ -22,10 +23,10 @@ export interface ISqlHistoryForAddressesResult { era: number; hash: Buffer; height: number; - id: string; + id: string | null; input_addresses: Json | null; is_valid: boolean; - metadata: Buffer; + metadata: Buffer | null; payload: Buffer; slot: number; tx_index: number; @@ -37,7 +38,7 @@ export interface ISqlHistoryForAddressesQuery { result: ISqlHistoryForAddressesResult; } -const sqlHistoryForAddressesIR: any = {"usedParamSet":{"addresses":true,"until_tx_id":true,"after_tx_id":true,"limit":true},"params":[{"name":"addresses","required":false,"transform":{"type":"scalar"},"locs":[{"a":91,"b":100}]},{"name":"until_tx_id","required":false,"transform":{"type":"scalar"},"locs":[{"a":373,"b":384},{"a":788,"b":799},{"a":1250,"b":1261}]},{"name":"after_tx_id","required":false,"transform":{"type":"scalar"},"locs":[{"a":440,"b":451},{"a":854,"b":865},{"a":1325,"b":1336}]},{"name":"limit","required":false,"transform":{"type":"scalar"},"locs":[{"a":516,"b":521},{"a":929,"b":934},{"a":1409,"b":1414},{"a":2329,"b":2334}]}],"statement":"WITH\n address_row AS (\n SELECT *\n FROM \"Address\"\n WHERE \"Address\".payload = ANY (:addresses)\n ),\n outputs AS (\n SELECT DISTINCT ON (\"TransactionOutput\".tx_id) \"TransactionOutput\".tx_id\n FROM \"TransactionOutput\"\n INNER JOIN address_row ON \"TransactionOutput\".address_id = address_row.id\n WHERE\n \"TransactionOutput\".tx_id <= (:until_tx_id)\n AND\n \"TransactionOutput\".tx_id > (:after_tx_id)\n ORDER BY \"TransactionOutput\".tx_id ASC\n LIMIT (:limit)\n ),\n inputs AS (\n SELECT DISTINCT ON (\"TransactionInput\".tx_id) \"TransactionInput\".tx_id\n FROM \"TransactionInput\"\n INNER JOIN address_row ON \"TransactionInput\".address_id = address_row.id\n WHERE\n \"TransactionInput\".tx_id <= (:until_tx_id)\n AND\n \"TransactionInput\".tx_id > (:after_tx_id)\n ORDER BY \"TransactionInput\".tx_id ASC\n LIMIT (:limit)\n ),\n ref_inputs AS (\n SELECT DISTINCT ON (\"TransactionReferenceInput\".tx_id) \"TransactionReferenceInput\".tx_id\n FROM \"TransactionReferenceInput\"\n INNER JOIN address_row ON \"TransactionReferenceInput\".address_id = address_row.id\n WHERE\n \"TransactionReferenceInput\".tx_id <= (:until_tx_id)\n AND\n \"TransactionReferenceInput\".tx_id > (:after_tx_id)\n ORDER BY \"TransactionReferenceInput\".tx_id ASC\n LIMIT (:limit)\n )\nSELECT \"Transaction\".id,\n \"Transaction\".payload,\n \"Transaction\".hash,\n \"Transaction\".tx_index,\n \"Transaction\".is_valid,\n \"Block\".hash AS block_hash,\n \"Block\".epoch,\n \"Block\".slot,\n \"Block\".era,\n \"Block\".height,\n \"TransactionMetadata\".payload AS metadata,\n json_agg(DISTINCT \"Address\".PAYLOAD) input_addresses\nFROM \"Transaction\"\nINNER JOIN \"Block\" ON \"Transaction\".block_id = \"Block\".id\nINNER JOIN \"TransactionInput\" ON \"TransactionInput\".tx_id = \"Transaction\".id\nINNER JOIN \"Address\" ON \"Address\".id = \"TransactionInput\".address_id\nLEFT JOIN \"TransactionMetadata\" ON \"Transaction\".id = \"TransactionMetadata\".tx_id\nWHERE \"Transaction\".id IN (SELECT * FROM inputs UNION ALL SELECT * from ref_inputs UNION ALL SELECT * from outputs)\nGROUP BY \"Transaction\".id, \"Block\".id, \"TransactionMetadata\".id\nORDER BY \"Transaction\".id ASC\nLIMIT (:limit)"}; +const sqlHistoryForAddressesIR: any = {"usedParamSet":{"addresses":true,"until_tx_id":true,"after_tx_id":true,"limit":true,"with_input_context":true},"params":[{"name":"addresses","required":false,"transform":{"type":"scalar"},"locs":[{"a":91,"b":100}]},{"name":"until_tx_id","required":false,"transform":{"type":"scalar"},"locs":[{"a":373,"b":384},{"a":788,"b":799},{"a":1250,"b":1261}]},{"name":"after_tx_id","required":false,"transform":{"type":"scalar"},"locs":[{"a":440,"b":451},{"a":854,"b":865},{"a":1325,"b":1336}]},{"name":"limit","required":false,"transform":{"type":"scalar"},"locs":[{"a":516,"b":521},{"a":929,"b":934},{"a":1409,"b":1414},{"a":2215,"b":2220},{"a":3446,"b":3451}]},{"name":"with_input_context","required":true,"transform":{"type":"scalar"},"locs":[{"a":3493,"b":3512},{"a":3576,"b":3595}]}],"statement":"WITH\n address_row AS (\n SELECT *\n FROM \"Address\"\n WHERE \"Address\".payload = ANY (:addresses)\n ),\n outputs AS (\n SELECT DISTINCT ON (\"TransactionOutput\".tx_id) \"TransactionOutput\".tx_id\n FROM \"TransactionOutput\"\n INNER JOIN address_row ON \"TransactionOutput\".address_id = address_row.id\n WHERE\n \"TransactionOutput\".tx_id <= (:until_tx_id)\n AND\n \"TransactionOutput\".tx_id > (:after_tx_id)\n ORDER BY \"TransactionOutput\".tx_id ASC\n LIMIT (:limit)\n ),\n inputs AS (\n SELECT DISTINCT ON (\"TransactionInput\".tx_id) \"TransactionInput\".tx_id\n FROM \"TransactionInput\"\n INNER JOIN address_row ON \"TransactionInput\".address_id = address_row.id\n WHERE\n \"TransactionInput\".tx_id <= (:until_tx_id)\n AND\n \"TransactionInput\".tx_id > (:after_tx_id)\n ORDER BY \"TransactionInput\".tx_id ASC\n LIMIT (:limit)\n ),\n ref_inputs AS (\n SELECT DISTINCT ON (\"TransactionReferenceInput\".tx_id) \"TransactionReferenceInput\".tx_id\n FROM \"TransactionReferenceInput\"\n INNER JOIN address_row ON \"TransactionReferenceInput\".address_id = address_row.id\n WHERE\n \"TransactionReferenceInput\".tx_id <= (:until_tx_id)\n AND\n \"TransactionReferenceInput\".tx_id > (:after_tx_id)\n ORDER BY \"TransactionReferenceInput\".tx_id ASC\n LIMIT (:limit)\n ),\n base_query AS (\n SELECT \"Transaction\".id,\n \"Transaction\".payload as \"payload!\",\n \"Transaction\".hash as \"hash!\",\n \"Transaction\".tx_index as \"tx_index!\",\n \"Transaction\".is_valid as \"is_valid!\",\n \"Block\".hash AS \"block_hash!\",\n \"Block\".epoch as \"epoch!\",\n \"Block\".slot as \"slot!\",\n \"Block\".era as \"era!\",\n \"Block\".height as \"height!\",\n NULL :: bytea as metadata,\n NULL :: json as input_addresses\n FROM \"Transaction\"\n INNER JOIN \"Block\" ON \"Transaction\".block_id = \"Block\".id\n WHERE \"Transaction\".id IN (SELECT * FROM inputs UNION ALL SELECT * from ref_inputs UNION ALL SELECT * from outputs)\n ORDER BY \"Transaction\".id ASC\n LIMIT (:limit)\n ),\n query_with_inputs_and_metadata AS (\n SELECT \"Transaction\".id,\n \"Transaction\".payload as \"payload!\",\n \"Transaction\".hash as \"hash!\",\n \"Transaction\".tx_index as \"tx_index!\",\n \"Transaction\".is_valid as \"is_valid!\",\n \"Block\".hash AS \"block_hash!\",\n \"Block\".epoch as \"epoch!\",\n \"Block\".slot as \"slot!\",\n \"Block\".era as \"era!\",\n \"Block\".height as \"height!\",\n \"TransactionMetadata\".payload AS metadata,\n json_agg(DISTINCT \"Address\".PAYLOAD) input_addresses\n FROM \"Transaction\"\n INNER JOIN \"Block\" ON \"Transaction\".block_id = \"Block\".id\n INNER JOIN \"TransactionInput\" ON \"TransactionInput\".tx_id = \"Transaction\".id\n INNER JOIN \"Address\" ON \"Address\".id = \"TransactionInput\".address_id\n LEFT JOIN \"TransactionMetadata\" ON \"Transaction\".id = \"TransactionMetadata\".tx_id\n WHERE \"Transaction\".id IN (SELECT * FROM inputs UNION ALL SELECT * from ref_inputs UNION ALL SELECT * from outputs)\n GROUP BY \"Transaction\".id, \"Block\".id, \"TransactionMetadata\".id\n ORDER BY \"Transaction\".id ASC\n LIMIT (:limit)\n )\nSELECT * FROM base_query WHERE NOT :with_input_context!\nUNION ALL\n(SELECT * from query_with_inputs_and_metadata WHERE :with_input_context!)"}; /** * Query generated from SQL: @@ -80,28 +81,52 @@ const sqlHistoryForAddressesIR: any = {"usedParamSet":{"addresses":true,"until_t * "TransactionReferenceInput".tx_id > (:after_tx_id) * ORDER BY "TransactionReferenceInput".tx_id ASC * LIMIT (:limit) + * ), + * base_query AS ( + * SELECT "Transaction".id, + * "Transaction".payload as "payload!", + * "Transaction".hash as "hash!", + * "Transaction".tx_index as "tx_index!", + * "Transaction".is_valid as "is_valid!", + * "Block".hash AS "block_hash!", + * "Block".epoch as "epoch!", + * "Block".slot as "slot!", + * "Block".era as "era!", + * "Block".height as "height!", + * NULL :: bytea as metadata, + * NULL :: json as input_addresses + * FROM "Transaction" + * INNER JOIN "Block" ON "Transaction".block_id = "Block".id + * WHERE "Transaction".id IN (SELECT * FROM inputs UNION ALL SELECT * from ref_inputs UNION ALL SELECT * from outputs) + * ORDER BY "Transaction".id ASC + * LIMIT (:limit) + * ), + * query_with_inputs_and_metadata AS ( + * SELECT "Transaction".id, + * "Transaction".payload as "payload!", + * "Transaction".hash as "hash!", + * "Transaction".tx_index as "tx_index!", + * "Transaction".is_valid as "is_valid!", + * "Block".hash AS "block_hash!", + * "Block".epoch as "epoch!", + * "Block".slot as "slot!", + * "Block".era as "era!", + * "Block".height as "height!", + * "TransactionMetadata".payload AS metadata, + * json_agg(DISTINCT "Address".PAYLOAD) input_addresses + * FROM "Transaction" + * INNER JOIN "Block" ON "Transaction".block_id = "Block".id + * INNER JOIN "TransactionInput" ON "TransactionInput".tx_id = "Transaction".id + * INNER JOIN "Address" ON "Address".id = "TransactionInput".address_id + * LEFT JOIN "TransactionMetadata" ON "Transaction".id = "TransactionMetadata".tx_id + * WHERE "Transaction".id IN (SELECT * FROM inputs UNION ALL SELECT * from ref_inputs UNION ALL SELECT * from outputs) + * GROUP BY "Transaction".id, "Block".id, "TransactionMetadata".id + * ORDER BY "Transaction".id ASC + * LIMIT (:limit) * ) - * SELECT "Transaction".id, - * "Transaction".payload, - * "Transaction".hash, - * "Transaction".tx_index, - * "Transaction".is_valid, - * "Block".hash AS block_hash, - * "Block".epoch, - * "Block".slot, - * "Block".era, - * "Block".height, - * "TransactionMetadata".payload AS metadata, - * json_agg(DISTINCT "Address".PAYLOAD) input_addresses - * FROM "Transaction" - * INNER JOIN "Block" ON "Transaction".block_id = "Block".id - * INNER JOIN "TransactionInput" ON "TransactionInput".tx_id = "Transaction".id - * INNER JOIN "Address" ON "Address".id = "TransactionInput".address_id - * LEFT JOIN "TransactionMetadata" ON "Transaction".id = "TransactionMetadata".tx_id - * WHERE "Transaction".id IN (SELECT * FROM inputs UNION ALL SELECT * from ref_inputs UNION ALL SELECT * from outputs) - * GROUP BY "Transaction".id, "Block".id, "TransactionMetadata".id - * ORDER BY "Transaction".id ASC - * LIMIT (:limit) + * SELECT * FROM base_query WHERE NOT :with_input_context! + * UNION ALL + * (SELECT * from query_with_inputs_and_metadata WHERE :with_input_context!) * ``` */ export const sqlHistoryForAddresses = new PreparedQuery(sqlHistoryForAddressesIR); diff --git a/webserver/server/app/models/transaction/sqlHistoryForAddresses.sql b/webserver/server/app/models/transaction/sqlHistoryForAddresses.sql index ac3d7d51..34658c77 100644 --- a/webserver/server/app/models/transaction/sqlHistoryForAddresses.sql +++ b/webserver/server/app/models/transaction/sqlHistoryForAddresses.sql @@ -37,25 +37,49 @@ WITH "TransactionReferenceInput".tx_id > (:after_tx_id) ORDER BY "TransactionReferenceInput".tx_id ASC LIMIT (:limit) + ), + base_query AS ( + SELECT "Transaction".id, + "Transaction".payload as "payload!", + "Transaction".hash as "hash!", + "Transaction".tx_index as "tx_index!", + "Transaction".is_valid as "is_valid!", + "Block".hash AS "block_hash!", + "Block".epoch as "epoch!", + "Block".slot as "slot!", + "Block".era as "era!", + "Block".height as "height!", + NULL :: bytea as metadata, + NULL :: json as input_addresses + FROM "Transaction" + INNER JOIN "Block" ON "Transaction".block_id = "Block".id + WHERE "Transaction".id IN (SELECT * FROM inputs UNION ALL SELECT * from ref_inputs UNION ALL SELECT * from outputs) + ORDER BY "Transaction".id ASC + LIMIT (:limit) + ), + query_with_inputs_and_metadata AS ( + SELECT "Transaction".id, + "Transaction".payload as "payload!", + "Transaction".hash as "hash!", + "Transaction".tx_index as "tx_index!", + "Transaction".is_valid as "is_valid!", + "Block".hash AS "block_hash!", + "Block".epoch as "epoch!", + "Block".slot as "slot!", + "Block".era as "era!", + "Block".height as "height!", + "TransactionMetadata".payload AS metadata, + json_agg(DISTINCT "Address".PAYLOAD) input_addresses + FROM "Transaction" + INNER JOIN "Block" ON "Transaction".block_id = "Block".id + INNER JOIN "TransactionInput" ON "TransactionInput".tx_id = "Transaction".id + INNER JOIN "Address" ON "Address".id = "TransactionInput".address_id + LEFT JOIN "TransactionMetadata" ON "Transaction".id = "TransactionMetadata".tx_id + WHERE "Transaction".id IN (SELECT * FROM inputs UNION ALL SELECT * from ref_inputs UNION ALL SELECT * from outputs) + GROUP BY "Transaction".id, "Block".id, "TransactionMetadata".id + ORDER BY "Transaction".id ASC + LIMIT (:limit) ) -SELECT "Transaction".id, - "Transaction".payload, - "Transaction".hash, - "Transaction".tx_index, - "Transaction".is_valid, - "Block".hash AS block_hash, - "Block".epoch, - "Block".slot, - "Block".era, - "Block".height, - "TransactionMetadata".payload AS metadata, - json_agg(DISTINCT "Address".PAYLOAD) input_addresses -FROM "Transaction" -INNER JOIN "Block" ON "Transaction".block_id = "Block".id -INNER JOIN "TransactionInput" ON "TransactionInput".tx_id = "Transaction".id -INNER JOIN "Address" ON "Address".id = "TransactionInput".address_id -LEFT JOIN "TransactionMetadata" ON "Transaction".id = "TransactionMetadata".tx_id -WHERE "Transaction".id IN (SELECT * FROM inputs UNION ALL SELECT * from ref_inputs UNION ALL SELECT * from outputs) -GROUP BY "Transaction".id, "Block".id, "TransactionMetadata".id -ORDER BY "Transaction".id ASC -LIMIT (:limit); \ No newline at end of file +SELECT * FROM base_query WHERE NOT :with_input_context! +UNION ALL +(SELECT * from query_with_inputs_and_metadata WHERE :with_input_context!); \ No newline at end of file diff --git a/webserver/server/app/models/transaction/sqlHistoryForCredentials.queries.ts b/webserver/server/app/models/transaction/sqlHistoryForCredentials.queries.ts index 50c042d1..e02270de 100644 --- a/webserver/server/app/models/transaction/sqlHistoryForCredentials.queries.ts +++ b/webserver/server/app/models/transaction/sqlHistoryForCredentials.queries.ts @@ -14,6 +14,7 @@ export interface ISqlHistoryForCredentialsParams { limit?: NumberOrString | null | void; relation?: number | null | void; until_tx_id?: NumberOrString | null | void; + with_input_context: boolean; } /** 'SqlHistoryForCredentials' return type */ @@ -23,10 +24,10 @@ export interface ISqlHistoryForCredentialsResult { era: number; hash: Buffer; height: number; - id: string; + id: string | null; input_addresses: Json | null; is_valid: boolean; - metadata: Buffer; + metadata: Buffer | null; payload: Buffer; slot: number; tx_index: number; @@ -38,7 +39,7 @@ export interface ISqlHistoryForCredentialsQuery { result: ISqlHistoryForCredentialsResult; } -const sqlHistoryForCredentialsIR: any = {"usedParamSet":{"credentials":true,"relation":true,"until_tx_id":true,"after_tx_id":true,"limit":true},"params":[{"name":"credentials","required":false,"transform":{"type":"scalar"},"locs":[{"a":288,"b":299}]},{"name":"relation","required":false,"transform":{"type":"scalar"},"locs":[{"a":354,"b":362}]},{"name":"until_tx_id","required":false,"transform":{"type":"scalar"},"locs":[{"a":464,"b":475}]},{"name":"after_tx_id","required":false,"transform":{"type":"scalar"},"locs":[{"a":527,"b":538}]},{"name":"limit","required":false,"transform":{"type":"scalar"},"locs":[{"a":598,"b":603}]}],"statement":"WITH\n tx_relations AS (\n SELECT DISTINCT ON (\"TxCredentialRelation\".tx_id) \"TxCredentialRelation\".tx_id\n FROM \"StakeCredential\"\n INNER JOIN \"TxCredentialRelation\" ON \"TxCredentialRelation\".credential_id = \"StakeCredential\".id\n WHERE\n \"StakeCredential\".credential = ANY (:credentials)\n AND\n (\"TxCredentialRelation\".relation & (:relation)) > 0\n AND\n \n \"TxCredentialRelation\".tx_id <= (:until_tx_id)\n AND \n \"TxCredentialRelation\".tx_id > (:after_tx_id)\n ORDER BY \"TxCredentialRelation\".tx_id ASC\n LIMIT (:limit)\n )\nSELECT \"Transaction\".id,\n \"Transaction\".payload,\n \"Transaction\".hash,\n \"Transaction\".tx_index,\n \"Transaction\".is_valid,\n \"Block\".hash AS block_hash,\n \"Block\".epoch,\n \"Block\".slot,\n \"Block\".era,\n \"Block\".height,\n \"TransactionMetadata\".payload AS metadata,\n json_agg(DISTINCT \"Address\".PAYLOAD) input_addresses\nFROM tx_relations\nINNER JOIN \"Transaction\" ON tx_relations.tx_id = \"Transaction\".id\nINNER JOIN \"TransactionInput\" ON \"TransactionInput\".tx_id = \"Transaction\".id\nINNER JOIN \"Address\" ON \"Address\".id = \"TransactionInput\".address_id\nLEFT JOIN \"TransactionMetadata\" ON \"Transaction\".id = \"TransactionMetadata\".tx_id\nINNER JOIN \"Block\" ON \"Transaction\".block_id = \"Block\".id\nGROUP BY \"Transaction\".id, \"Block\".id, \"TransactionMetadata\".id"}; +const sqlHistoryForCredentialsIR: any = {"usedParamSet":{"credentials":true,"relation":true,"until_tx_id":true,"after_tx_id":true,"limit":true,"with_input_context":true},"params":[{"name":"credentials","required":false,"transform":{"type":"scalar"},"locs":[{"a":288,"b":299}]},{"name":"relation","required":false,"transform":{"type":"scalar"},"locs":[{"a":354,"b":362}]},{"name":"until_tx_id","required":false,"transform":{"type":"scalar"},"locs":[{"a":464,"b":475}]},{"name":"after_tx_id","required":false,"transform":{"type":"scalar"},"locs":[{"a":527,"b":538}]},{"name":"limit","required":false,"transform":{"type":"scalar"},"locs":[{"a":598,"b":603}]},{"name":"with_input_context","required":true,"transform":{"type":"scalar"},"locs":[{"a":2446,"b":2465},{"a":2529,"b":2548}]}],"statement":"WITH\n tx_relations AS (\n SELECT DISTINCT ON (\"TxCredentialRelation\".tx_id) \"TxCredentialRelation\".tx_id\n FROM \"StakeCredential\"\n INNER JOIN \"TxCredentialRelation\" ON \"TxCredentialRelation\".credential_id = \"StakeCredential\".id\n WHERE\n \"StakeCredential\".credential = ANY (:credentials)\n AND\n (\"TxCredentialRelation\".relation & (:relation)) > 0\n AND\n \n \"TxCredentialRelation\".tx_id <= (:until_tx_id)\n AND \n \"TxCredentialRelation\".tx_id > (:after_tx_id)\n ORDER BY \"TxCredentialRelation\".tx_id ASC\n LIMIT (:limit)\n ),\n base_query AS (\n SELECT \"Transaction\".id,\n \"Transaction\".payload as \"payload!\",\n \"Transaction\".hash as \"hash!\",\n \"Transaction\".tx_index as \"tx_index!\",\n \"Transaction\".is_valid as \"is_valid!\",\n \"Block\".hash AS \"block_hash!\",\n \"Block\".epoch as \"epoch!\",\n \"Block\".slot as \"slot!\",\n \"Block\".era as \"era!\",\n \"Block\".height as \"height!\",\n NULL :: bytea as metadata,\n NULL :: json as input_addresses\n FROM tx_relations\n INNER JOIN \"Transaction\" ON tx_relations.tx_id = \"Transaction\".id\n INNER JOIN \"Block\" ON \"Transaction\".block_id = \"Block\".id\n ),\n query_with_inputs_and_metadata AS (\n SELECT \"Transaction\".id,\n \"Transaction\".payload as \"payload!\",\n \"Transaction\".hash as \"hash!\",\n \"Transaction\".tx_index as \"tx_index!\",\n \"Transaction\".is_valid as \"is_valid!\",\n \"Block\".hash as \"block_hash!\",\n \"Block\".epoch as \"epoch!\",\n \"Block\".slot as \"slot!\",\n \"Block\".era as \"era!\",\n \"Block\".height as \"height!\",\n \"TransactionMetadata\".payload AS metadata,\n json_agg(DISTINCT \"Address\".PAYLOAD) input_addresses\n FROM tx_relations\n INNER JOIN \"Transaction\" ON tx_relations.tx_id = \"Transaction\".id\n INNER JOIN \"TransactionInput\" ON \"TransactionInput\".tx_id = \"Transaction\".id\n INNER JOIN \"Address\" ON \"Address\".id = \"TransactionInput\".address_id\n LEFT JOIN \"TransactionMetadata\" ON \"Transaction\".id = \"TransactionMetadata\".tx_id\n INNER JOIN \"Block\" ON \"Transaction\".block_id = \"Block\".id\n GROUP BY \"Transaction\".id, \"Block\".id, \"TransactionMetadata\".id\n )\nSELECT * FROM base_query WHERE NOT :with_input_context!\nUNION ALL (SELECT * FROM query_with_inputs_and_metadata WHERE :with_input_context!)"}; /** * Query generated from SQL: @@ -59,26 +60,47 @@ const sqlHistoryForCredentialsIR: any = {"usedParamSet":{"credentials":true,"rel * "TxCredentialRelation".tx_id > (:after_tx_id) * ORDER BY "TxCredentialRelation".tx_id ASC * LIMIT (:limit) + * ), + * base_query AS ( + * SELECT "Transaction".id, + * "Transaction".payload as "payload!", + * "Transaction".hash as "hash!", + * "Transaction".tx_index as "tx_index!", + * "Transaction".is_valid as "is_valid!", + * "Block".hash AS "block_hash!", + * "Block".epoch as "epoch!", + * "Block".slot as "slot!", + * "Block".era as "era!", + * "Block".height as "height!", + * NULL :: bytea as metadata, + * NULL :: json as input_addresses + * FROM tx_relations + * INNER JOIN "Transaction" ON tx_relations.tx_id = "Transaction".id + * INNER JOIN "Block" ON "Transaction".block_id = "Block".id + * ), + * query_with_inputs_and_metadata AS ( + * SELECT "Transaction".id, + * "Transaction".payload as "payload!", + * "Transaction".hash as "hash!", + * "Transaction".tx_index as "tx_index!", + * "Transaction".is_valid as "is_valid!", + * "Block".hash as "block_hash!", + * "Block".epoch as "epoch!", + * "Block".slot as "slot!", + * "Block".era as "era!", + * "Block".height as "height!", + * "TransactionMetadata".payload AS metadata, + * json_agg(DISTINCT "Address".PAYLOAD) input_addresses + * FROM tx_relations + * INNER JOIN "Transaction" ON tx_relations.tx_id = "Transaction".id + * INNER JOIN "TransactionInput" ON "TransactionInput".tx_id = "Transaction".id + * INNER JOIN "Address" ON "Address".id = "TransactionInput".address_id + * LEFT JOIN "TransactionMetadata" ON "Transaction".id = "TransactionMetadata".tx_id + * INNER JOIN "Block" ON "Transaction".block_id = "Block".id + * GROUP BY "Transaction".id, "Block".id, "TransactionMetadata".id * ) - * SELECT "Transaction".id, - * "Transaction".payload, - * "Transaction".hash, - * "Transaction".tx_index, - * "Transaction".is_valid, - * "Block".hash AS block_hash, - * "Block".epoch, - * "Block".slot, - * "Block".era, - * "Block".height, - * "TransactionMetadata".payload AS metadata, - * json_agg(DISTINCT "Address".PAYLOAD) input_addresses - * FROM tx_relations - * INNER JOIN "Transaction" ON tx_relations.tx_id = "Transaction".id - * INNER JOIN "TransactionInput" ON "TransactionInput".tx_id = "Transaction".id - * INNER JOIN "Address" ON "Address".id = "TransactionInput".address_id - * LEFT JOIN "TransactionMetadata" ON "Transaction".id = "TransactionMetadata".tx_id - * INNER JOIN "Block" ON "Transaction".block_id = "Block".id - * GROUP BY "Transaction".id, "Block".id, "TransactionMetadata".id + * SELECT * FROM base_query WHERE NOT :with_input_context! + * UNION ALL (SELECT * FROM query_with_inputs_and_metadata WHERE :with_input_context!) * ``` */ export const sqlHistoryForCredentials = new PreparedQuery(sqlHistoryForCredentialsIR); diff --git a/webserver/server/app/models/transaction/sqlHistoryForCredentials.sql b/webserver/server/app/models/transaction/sqlHistoryForCredentials.sql index 78558ada..fc2b1c3f 100644 --- a/webserver/server/app/models/transaction/sqlHistoryForCredentials.sql +++ b/webserver/server/app/models/transaction/sqlHistoryForCredentials.sql @@ -15,24 +15,45 @@ WITH "TxCredentialRelation".tx_id > (:after_tx_id) ORDER BY "TxCredentialRelation".tx_id ASC LIMIT (:limit) + ), + base_query AS ( + SELECT "Transaction".id, + "Transaction".payload as "payload!", + "Transaction".hash as "hash!", + "Transaction".tx_index as "tx_index!", + "Transaction".is_valid as "is_valid!", + "Block".hash AS "block_hash!", + "Block".epoch as "epoch!", + "Block".slot as "slot!", + "Block".era as "era!", + "Block".height as "height!", + NULL :: bytea as metadata, + NULL :: json as input_addresses + FROM tx_relations + INNER JOIN "Transaction" ON tx_relations.tx_id = "Transaction".id + INNER JOIN "Block" ON "Transaction".block_id = "Block".id + ), + query_with_inputs_and_metadata AS ( + SELECT "Transaction".id, + "Transaction".payload as "payload!", + "Transaction".hash as "hash!", + "Transaction".tx_index as "tx_index!", + "Transaction".is_valid as "is_valid!", + "Block".hash as "block_hash!", + "Block".epoch as "epoch!", + "Block".slot as "slot!", + "Block".era as "era!", + "Block".height as "height!", + "TransactionMetadata".payload AS metadata, + json_agg(DISTINCT "Address".PAYLOAD) input_addresses + FROM tx_relations + INNER JOIN "Transaction" ON tx_relations.tx_id = "Transaction".id + INNER JOIN "TransactionInput" ON "TransactionInput".tx_id = "Transaction".id + INNER JOIN "Address" ON "Address".id = "TransactionInput".address_id + LEFT JOIN "TransactionMetadata" ON "Transaction".id = "TransactionMetadata".tx_id + INNER JOIN "Block" ON "Transaction".block_id = "Block".id + GROUP BY "Transaction".id, "Block".id, "TransactionMetadata".id ) -SELECT "Transaction".id, - "Transaction".payload, - "Transaction".hash, - "Transaction".tx_index, - "Transaction".is_valid, - "Block".hash AS block_hash, - "Block".epoch, - "Block".slot, - "Block".era, - "Block".height, - "TransactionMetadata".payload AS metadata, - json_agg(DISTINCT "Address".PAYLOAD) input_addresses -FROM tx_relations -INNER JOIN "Transaction" ON tx_relations.tx_id = "Transaction".id -INNER JOIN "TransactionInput" ON "TransactionInput".tx_id = "Transaction".id -INNER JOIN "Address" ON "Address".id = "TransactionInput".address_id -LEFT JOIN "TransactionMetadata" ON "Transaction".id = "TransactionMetadata".tx_id -INNER JOIN "Block" ON "Transaction".block_id = "Block".id -GROUP BY "Transaction".id, "Block".id, "TransactionMetadata".id; +SELECT * FROM base_query WHERE NOT :with_input_context! +UNION ALL (SELECT * FROM query_with_inputs_and_metadata WHERE :with_input_context!); diff --git a/webserver/server/app/services/TransactionHistoryService.ts b/webserver/server/app/services/TransactionHistoryService.ts index eef02778..417bf6b1 100644 --- a/webserver/server/app/services/TransactionHistoryService.ts +++ b/webserver/server/app/services/TransactionHistoryService.ts @@ -12,6 +12,7 @@ export async function historyForCredentials( stakeCredentials: Buffer[]; relationFilter: RelationFilter; limit: number; + withInputContext?: boolean; } ): Promise { if (request.stakeCredentials.length === 0) return { transactions: [] }; @@ -22,6 +23,7 @@ export async function historyForCredentials( limit: request.limit.toString(), until_tx_id: request.until.tx_id.toString(), relation: request.relationFilter, + with_input_context: !!request.withInputContext, }, request.dbTx ); @@ -38,12 +40,16 @@ export async function historyForCredentials( }, transaction: { - hash: entry.hash.toString('hex'), - payload: entry.payload.toString('hex'), - metadata: entry.metadata && entry.metadata.toString('hex'), - inputCredentials: entry.input_addresses - ? (entry.input_addresses as string[]).map(getPaymentCred) - : [], + ...{ + hash: entry.hash.toString('hex'), + payload: entry.payload.toString('hex'), + }, + ...(request.withInputContext && { + metadata: entry.metadata && entry.metadata.toString('hex'), + inputCredentials: entry.input_addresses + ? (entry.input_addresses as string[]).map(getPaymentCred) + : [], + }), }, })), }; @@ -54,6 +60,7 @@ export async function historyForAddresses( addresses: Buffer[]; dbTx: PoolClient; limit: number; + withInputContext?: boolean; } ): Promise { if (request.addresses?.length === 0) return { transactions: [] }; @@ -63,6 +70,7 @@ export async function historyForAddresses( after_tx_id: (request.after?.tx_id ?? -1)?.toString(), limit: request.limit.toString(), until_tx_id: request.until.tx_id.toString(), + with_input_context: !!request.withInputContext, }, request.dbTx ); @@ -79,12 +87,16 @@ export async function historyForAddresses( }, transaction: { - hash: entry.hash.toString('hex'), - payload: entry.payload.toString('hex'), - metadata: entry.metadata && entry.metadata.toString('hex'), - inputCredentials: entry.input_addresses - ? (entry.input_addresses as string[]).map(getPaymentCred) - : [], + ...{ + hash: entry.hash.toString('hex'), + payload: entry.payload.toString('hex'), + }, + ...(request.withInputContext && { + metadata: entry.metadata && entry.metadata.toString('hex'), + inputCredentials: entry.input_addresses + ? (entry.input_addresses as string[]).map(getPaymentCred) + : [], + }), }, })), }; diff --git a/webserver/shared/models/TransactionHistory.ts b/webserver/shared/models/TransactionHistory.ts index e5b1de3d..39a3e863 100644 --- a/webserver/shared/models/TransactionHistory.ts +++ b/webserver/shared/models/TransactionHistory.ts @@ -11,6 +11,7 @@ export type TransactionHistoryRequest = { limit?: number; slotLimits?: SlotLimits; + withInputContext?: boolean; } & Pagination; export type BlockInfo = BlockSubset & { @@ -37,9 +38,9 @@ export type TransactionInfo = { */ payload: string; - metadata: string | null; + metadata?: string | null; - inputCredentials: string[]; + inputCredentials?: string[]; }; export type TxAndBlockInfo = {