Skip to content

Commit

Permalink
refactor(api-http): expose full tx receipt via ?fullReceipt flag (#859
Browse files Browse the repository at this point in the history
)

* add `?fullReceipt` query param to omit verbose output

* add `?fullReceipt` to receipts controller

* update integration tests

* style: resolve style guide violations

* fix fixture

* style: resolve style guide violations

* deduplicate column selection
  • Loading branch information
oXtxNt9U authored Feb 13, 2025
1 parent 1fd3832 commit 08b60df
Show file tree
Hide file tree
Showing 16 changed files with 115 additions and 29 deletions.
23 changes: 13 additions & 10 deletions packages/api-http/integration/routes/receipts.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, Sandbox } from "../../../test-framework/source";
import receipts from "../../test/fixtures/receipts.json";
import receiptsResult from "../../test/fixtures/receipts_result.json";
import receiptTransactions from "../../test/fixtures/receipt_transactions.json";
import receiptWallets from "../../test/fixtures/receipt_wallets.json";
import { ApiContext, prepareSandbox } from "../../test/helpers/prepare-sandbox";
Expand All @@ -10,7 +11,9 @@ describe<{
}>("Receipts", ({ it, afterAll, assert, afterEach, beforeAll, beforeEach, nock }) => {
let apiContext: ApiContext;

const options = {};
const options = {
fullReceipt: true,
};

beforeAll(async (context) => {
nock.enableNetConnect();
Expand Down Expand Up @@ -42,23 +45,23 @@ describe<{
const testCases = [
{
query: "",
result: receipts,
result: receiptsResult,
},
{
query: `?txHash=${receipts[0].id}`,
result: [receipts[0]],
result: [receiptsResult[0]],
},
{
query: "?txHash=0000000000000000000000000000000000000000000000000000000000000001",
result: [],
},
{
query: `?sender=${receiptTransactions[0].senderPublicKey}`,
result: receipts,
result: receiptsResult,
},
{
query: `?recipient=${receipts[1].deployedContractAddress}`,
result: [receipts[0]],
result: [receiptsResult[0]],
},
];

Expand Down Expand Up @@ -86,11 +89,11 @@ describe<{
},
{
id: receipts[0].id,
result: receipts[0],
result: receiptsResult[0],
},
{
id: receipts[receipts.length - 1].id,
result: receipts[receipts.length - 1],
id: receipts[receiptsResult.length - 1].id,
result: receiptsResult[receiptsResult.length - 1],
},
];

Expand Down Expand Up @@ -119,11 +122,11 @@ describe<{
const testCases = [
{
query: "",
result: [receipts[1]],
result: [receiptsResult[1]],
},
{
query: `?sender=${receiptTransactions[0].senderPublicKey}`,
result: [receipts[1]],
result: [receiptsResult[1]],
},
{
query: `?sender=asdfgfg`,
Expand Down
2 changes: 1 addition & 1 deletion packages/api-http/source/controllers/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class BlocksController extends Controller {
);

return this.toPagination(
await this.enrichTransactionResult(transactions),
await this.enrichTransactionResult(transactions, { fullReceipt: request.query.fullReceipt }),
TransactionResource,
request.query.transform,
);
Expand Down
36 changes: 29 additions & 7 deletions packages/api-http/source/controllers/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,12 @@ export class Controller extends AbstractController {
return configuration ?? ({} as Models.Configuration);
}

protected async getReceipts(ids: string[]): Promise<Record<string, Models.Receipt>> {
protected async getReceipts(ids: string[], full = false): Promise<Record<string, Models.Receipt>> {
const receiptRepository = this.receiptRepositoryFactory();

const receipts = await receiptRepository
.createQueryBuilder()
.select(["Receipt.id", "Receipt.success", "Receipt.gasUsed", "Receipt.deployedContractAddress"])
.createQueryBuilder("receipt")
.select(this.getReceiptColumns(full))
.whereInIds(ids)
.getMany();

Expand Down Expand Up @@ -122,17 +123,22 @@ export class Controller extends AbstractController {

protected async enrichTransactionResult(
resultPage: Search.ResultsPage<Models.Transaction>,
context?: { state?: Models.State },
context?: { state?: Models.State; fullReceipt?: boolean },
): Promise<Search.ResultsPage<EnrichedTransaction>> {
const [state, receipts] = await Promise.all([
context?.state ?? this.getState(),
this.getReceipts(resultPage.results.map((tx) => tx.id)),
this.getReceipts(
resultPage.results.map((tx) => tx.id),
context?.fullReceipt ?? false,
),
]);

return {
...resultPage,
results: await Promise.all(
resultPage.results.map((tx) => this.enrichTransaction(tx, state, receipts[tx.id] ?? null)),
resultPage.results.map((tx) =>
this.enrichTransaction(tx, state, receipts[tx.id] ?? null, context?.fullReceipt),
),
),
};
}
Expand All @@ -141,10 +147,11 @@ export class Controller extends AbstractController {
transaction: Models.Transaction,
state?: Models.State,
receipt?: Models.Receipt | null,
fullReceipt?: boolean,
): Promise<EnrichedTransaction> {
const [_state, receipts] = await Promise.all([
state ? state : this.getState(),
receipt !== undefined ? receipt : this.getReceipts([transaction.id]),
receipt !== undefined ? receipt : this.getReceipts([transaction.id], fullReceipt),
]);

return { ...transaction, receipt: receipt ?? receipts?.[transaction.id] ?? undefined, state: _state };
Expand All @@ -155,4 +162,19 @@ export class Controller extends AbstractController {
// NOTE: This assumes all block ids are sha256 and never a valid number below this threshold.
return !isNaN(asHeight) && asHeight <= Number.MAX_SAFE_INTEGER ? { height: asHeight } : { id: idOrHeight };
}

protected getReceiptColumns(fullReceipt?: boolean): string[] {
let columns = [
"receipt.id",
"receipt.success",
"receipt.gasUsed",
"receipt.gasRefunded",
"receipt.deployedContractAddress",
];
if (fullReceipt) {
columns = [...columns, "receipt.output", "receipt.logs"];
}

return columns;
}
}
6 changes: 4 additions & 2 deletions packages/api-http/source/controllers/receipts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export class ReceiptsController extends Controller {

const query = this.receiptRepositoryFactory()
.createQueryBuilder("receipt")
.select(this.getReceiptColumns(request.query.fullReceipt))
.innerJoin(Models.Transaction, "transaction", "receipt.id = transaction.id");

if (criteria.txHash) {
Expand Down Expand Up @@ -58,8 +59,8 @@ export class ReceiptsController extends Controller {

public async show(request: Hapi.Request) {
const receipt = await this.receiptRepositoryFactory()
.createQueryBuilder()
.select()
.createQueryBuilder("receipt")
.select(this.getReceiptColumns(request.query.fullReceipt))
.where("id = :id", { id: request.params.id })
.getOne();

Expand All @@ -76,6 +77,7 @@ export class ReceiptsController extends Controller {

const query = this.receiptRepositoryFactory()
.createQueryBuilder("receipt")
.select(this.getReceiptColumns(request.query.fullReceipt))
.innerJoin(Models.Transaction, "transaction", "receipt.id = transaction.id")
.where("receipt.deployedContractAddress IS NOT NULL");

Expand Down
4 changes: 2 additions & 2 deletions packages/api-http/source/controllers/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export class TransactionsController extends Controller {
);

return this.toPagination(
await this.enrichTransactionResult(transactions),
await this.enrichTransactionResult(transactions, { fullReceipt: request.query.fullReceipt }),
TransactionResource,
request.query.transform,
);
Expand Down Expand Up @@ -73,7 +73,7 @@ export class TransactionsController extends Controller {
}

return this.respondWithResource(
await this.enrichTransaction(transaction),
await this.enrichTransaction(transaction, undefined, undefined, request.query.fullReceipt),
TransactionResource,
request.query.transform,
);
Expand Down
4 changes: 2 additions & 2 deletions packages/api-http/source/controllers/votes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class VotesController extends Controller {
);

return this.toPagination(
await this.enrichTransactionResult(transactions),
await this.enrichTransactionResult(transactions, { fullReceipt: request.query.fullReceipt }),
TransactionResource,
request.query.transform,
);
Expand All @@ -55,7 +55,7 @@ export class VotesController extends Controller {
}

return this.respondWithResource(
await this.enrichTransaction(transaction),
await this.enrichTransaction(transaction, undefined, undefined, request.query.fullReceipt),
TransactionResource,
request.query.transform,
);
Expand Down
2 changes: 1 addition & 1 deletion packages/api-http/source/controllers/wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export class WalletsController extends Controller {
);

return this.toPagination(
await this.enrichTransactionResult(transactions),
await this.enrichTransactionResult(transactions, { fullReceipt: request.query.fullReceipt }),
TransactionResource,
request.query.transform,
);
Expand Down
11 changes: 8 additions & 3 deletions packages/api-http/source/resources/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,14 @@ export class TransactionResource implements Contracts.Api.Resource {

...(resource.receipt
? {
deployedContractAddress: resource.receipt.deployedContractAddress ?? undefined,
gasUsed: resource.receipt.gasUsed,
success: resource.receipt.success,
receipt: {
deployedContractAddress: resource.receipt.deployedContractAddress ?? undefined,
gasRefunded: resource.receipt.gasRefunded,
gasUsed: resource.receipt.gasUsed,
logs: resource.receipt.logs,
output: resource.receipt.output,
success: resource.receipt.success,
},
}
: {}),
};
Expand Down
1 change: 1 addition & 0 deletions packages/api-http/source/routes/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export const register = (server: Contracts.Api.ApiServer): void => {
}),
query: Joi.object({
...server.app.schemas.transactionCriteriaSchemas,
fullReceipt: Joi.bool().default(false),
orderBy: server.app.schemas.transactionsOrderBy,
transform: Joi.bool().default(true),
})
Expand Down
5 changes: 5 additions & 0 deletions packages/api-http/source/routes/receipts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const register = (server: Contracts.Api.ApiServer): void => {
},
validate: {
query: Joi.object({
fullReceipt: Joi.bool().default(true),
recipient: address,
sender: walletId,
txHash: transactionCriteriaSchemaObject.id,
Expand All @@ -40,6 +41,9 @@ export const register = (server: Contracts.Api.ApiServer): void => {
params: Joi.object({
id: Joi.string().hex().length(64),
}),
query: Joi.object({
fullReceipt: Joi.bool().default(true),
}),
},
},
path: "/receipts/{id}",
Expand All @@ -56,6 +60,7 @@ export const register = (server: Contracts.Api.ApiServer): void => {
},
validate: {
query: Joi.object({
fullReceipt: Joi.bool().default(false),
sender: walletId,
}).concat(Schemas.pagination),
},
Expand Down
2 changes: 2 additions & 0 deletions packages/api-http/source/routes/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const register = (server: Contracts.Api.ApiServer): void => {
validate: {
query: Joi.object({
...server.app.schemas.transactionCriteriaSchemas,
fullReceipt: Joi.bool().default(false),
orderBy: server.app.schemas.transactionsOrderBy,
transform: Joi.bool().default(true),
})
Expand All @@ -41,6 +42,7 @@ export const register = (server: Contracts.Api.ApiServer): void => {
id: Joi.string().hex().length(64),
}),
query: Joi.object({
fullReceipt: Joi.bool().default(false),
transform: Joi.bool().default(true),
}),
},
Expand Down
2 changes: 2 additions & 0 deletions packages/api-http/source/routes/votes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const register = (server: Contracts.Api.ApiServer): void => {
validate: {
query: Joi.object({
...server.app.schemas.transactionCriteriaSchemas,
fullReceipt: Joi.bool().default(false),
orderBy: server.app.schemas.transactionsOrderBy,
transform: Joi.bool().default(true),
})
Expand All @@ -42,6 +43,7 @@ export const register = (server: Contracts.Api.ApiServer): void => {
id: transactionIdSchema,
}),
query: Joi.object({
fullReceipt: Joi.bool().default(false),
transform: Joi.bool().default(true),
}),
},
Expand Down
4 changes: 4 additions & 0 deletions packages/api-http/source/routes/wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export const register = (server: Contracts.Api.ApiServer): void => {
}),
query: Joi.object({
...server.app.schemas.transactionCriteriaSchemas,
fullReceipt: Joi.bool().default(false),
orderBy: server.app.schemas.transactionsOrderBy,
transform: Joi.bool().default(true),
})
Expand All @@ -111,6 +112,7 @@ export const register = (server: Contracts.Api.ApiServer): void => {
}),
query: Joi.object({
...server.app.schemas.transactionCriteriaSchemas,
fullReceipt: Joi.bool().default(false),
orderBy: server.app.schemas.transactionsOrderBy,
transform: Joi.bool().default(true),
})
Expand All @@ -136,6 +138,7 @@ export const register = (server: Contracts.Api.ApiServer): void => {
}),
query: Joi.object({
...server.app.schemas.transactionCriteriaSchemas,
fullReceipt: Joi.bool().default(false),
orderBy: server.app.schemas.transactionsOrderBy,
transform: Joi.bool().default(true),
})
Expand All @@ -161,6 +164,7 @@ export const register = (server: Contracts.Api.ApiServer): void => {
}),
query: Joi.object({
...server.app.schemas.transactionCriteriaSchemas,
fullReceipt: Joi.bool().default(false),
orderBy: server.app.schemas.transactionsOrderBy,
transform: Joi.bool().default(true),
})
Expand Down
2 changes: 2 additions & 0 deletions packages/api-http/test/fixtures/receipt_transactions.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"id": "d76eface634cab46ccc57f373a03e83cfbdaa7bedb84228ed8ce30bea128649a",
"success": true,
"gasUsed": 116802,
"gasRefunded": 0,
"deployedContractAddress": null
}
},
Expand All @@ -42,6 +43,7 @@
"id": "29c12f5fc3c25323eec3bae1ddbe72a1113cba634e0079735a34074d4dc8ac0b",
"success": true,
"gasUsed": 116802,
"gasRefunded": 0,
"deployedContractAddress": "0x0a26D3630D5EC868767d7F4563Fab98D31601A6e"
}
}
Expand Down
32 changes: 32 additions & 0 deletions packages/api-http/test/fixtures/receipts_result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[
{
"id": "d76eface634cab46ccc57f373a03e83cfbdaa7bedb84228ed8ce30bea128649a",
"success": true,
"gasUsed": 116802,
"gasRefunded": 0,
"deployedContractAddress": null,
"logs": [
{
"data": "0x000000000000000000000000db1a9acdd71eb5f846059034ef6d2cb144ccd1a9000000000000000000000000db1a9acdd71eb5f846059034ef6d2cb144ccd1a9",
"topics": ["0xce0c7a2a940807f7dc2ce7a615c2532e915e6c0ac9a08bc4ed9d515a710a53e2"],
"address": "0x522B3294E6d06aA25Ad0f1B8891242E335D3B459"
}
],
"output": "0x"
},
{
"id": "29c12f5fc3c25323eec3bae1ddbe72a1113cba634e0079735a34074d4dc8ac0b",
"success": true,
"gasUsed": 116802,
"gasRefunded": 0,
"deployedContractAddress": "0x0a26D3630D5EC868767d7F4563Fab98D31601A6e",
"logs": [
{
"data": "0x0000000000000000000000007b962da995bf5e0a7b10351b7a4381f7826504320000000000000000000000007b962da995bf5e0a7b10351b7a4381f782650432",
"topics": ["0xce0c7a2a940807f7dc2ce7a615c2532e915e6c0ac9a08bc4ed9d515a710a53e2"],
"address": "0x522B3294E6d06aA25Ad0f1B8891242E335D3B459"
}
],
"output": "0x"
}
]
Loading

0 comments on commit 08b60df

Please sign in to comment.