From 4560e7812cc2a856afa4c8b34f678cf07d93e4c5 Mon Sep 17 00:00:00 2001 From: "Sebastijan K." <58827427+sebastijankuzner@users.noreply.github.com> Date: Fri, 10 Jan 2025 12:17:19 +0100 Subject: [PATCH] feat(api-evm): implement `eth_getTransactionByBlockNumberAndIndex` (#816) * Add action * Add database method --- ...t-transaction-by-block-number-and-index.ts | 38 +++++++++++++++++++ packages/api-evm/source/actions/index.ts | 1 + packages/api-evm/source/service-provider.ts | 2 + .../contracts/source/contracts/database.ts | 1 + packages/database/source/database-service.ts | 19 ++++++++++ 5 files changed, 61 insertions(+) create mode 100644 packages/api-evm/source/actions/eth-get-transaction-by-block-number-and-index.ts diff --git a/packages/api-evm/source/actions/eth-get-transaction-by-block-number-and-index.ts b/packages/api-evm/source/actions/eth-get-transaction-by-block-number-and-index.ts new file mode 100644 index 000000000..7d005d013 --- /dev/null +++ b/packages/api-evm/source/actions/eth-get-transaction-by-block-number-and-index.ts @@ -0,0 +1,38 @@ +import { inject, injectable } from "@mainsail/container"; +import { Contracts, Identifiers } from "@mainsail/contracts"; + +import { TransactionResource } from "../resources/index.js"; + +@injectable() +export class EthGetTransactionByBlockNumberAndIndex implements Contracts.Api.RPC.Action { + @inject(Identifiers.Application.Instance) + private readonly app!: Contracts.Kernel.Application; + + @inject(Identifiers.Database.Service) + private readonly databaseService!: Contracts.Database.DatabaseService; + + public readonly name: string = "eth_getTransactionByBlockNumberAndIndex"; + + public readonly schema = { + $id: `jsonRpc_${this.name}`, + + maxItems: 2, + minItems: 2, + + prefixItems: [{ $ref: "prefixedHex" }, { $ref: "prefixedHex" }], // TODO: Limit sequence + type: "array", + }; + + public async handle(parameters: [string, string]): Promise { + const transaction = await this.databaseService.getTransactionByBlockHeightAndIndex( + Number.parseInt(parameters[0]), + Number.parseInt(parameters[1]), + ); + + if (!transaction) { + return null; + } + + return this.app.resolve(TransactionResource).transform(transaction.data); + } +} diff --git a/packages/api-evm/source/actions/index.ts b/packages/api-evm/source/actions/index.ts index 60c862c32..26ce7bc78 100644 --- a/packages/api-evm/source/actions/index.ts +++ b/packages/api-evm/source/actions/index.ts @@ -8,6 +8,7 @@ export * from "./eth-get-block-transaction-count-by-number.js"; export * from "./eth-get-code.js"; export * from "./eth-get-storage-at.js"; export * from "./eth-get-transaction-by-block-hash-and-index.js"; +export * from "./eth-get-transaction-by-block-number-and-index.js"; export * from "./eth-get-transaction-by-hash.js"; export * from "./eth-get-transaction-count.js"; export * from "./eth-get-uncle-by-block-hash-and-index.js"; diff --git a/packages/api-evm/source/service-provider.ts b/packages/api-evm/source/service-provider.ts index cc43ee969..77f59bb08 100644 --- a/packages/api-evm/source/service-provider.ts +++ b/packages/api-evm/source/service-provider.ts @@ -13,6 +13,7 @@ import { EthGetCodeAction, EthGetStorageAtAction, EthGetTransactionByBlockHashAndIndex, + EthGetTransactionByBlockNumberAndIndex, EthGetTransactionByHash, EthGetTransactionCount, EthGetUncleByBlockHashAndIndex, @@ -84,6 +85,7 @@ export class ServiceProvider extends AbstractServiceProvider { this.app.resolve(EthGetCodeAction), this.app.resolve(EthGetStorageAtAction), this.app.resolve(EthGetTransactionByBlockHashAndIndex), + this.app.resolve(EthGetTransactionByBlockNumberAndIndex), this.app.resolve(EthGetTransactionByHash), this.app.resolve(EthGetTransactionCount), this.app.resolve(EthGetUncleByBlockHashAndIndex), diff --git a/packages/contracts/source/contracts/database.ts b/packages/contracts/source/contracts/database.ts index caa7dee70..05c5949ec 100644 --- a/packages/contracts/source/contracts/database.ts +++ b/packages/contracts/source/contracts/database.ts @@ -27,6 +27,7 @@ export interface DatabaseService { getTransactionById(id: string): Promise; getTransactionByBlockIdAndIndex(blockId: string, index: number): Promise; + getTransactionByBlockHeightAndIndex(height: number, index: number): Promise; addCommit(block: Commit): void; persist(): Promise; diff --git a/packages/database/source/database-service.ts b/packages/database/source/database-service.ts index 66c73e5d2..6b7072eef 100644 --- a/packages/database/source/database-service.ts +++ b/packages/database/source/database-service.ts @@ -214,6 +214,25 @@ export class DatabaseService implements Contracts.Database.DatabaseService { return this.#readTransaction(`${height}-${index}`); } + public async getTransactionByBlockHeightAndIndex( + height: number, + index: number, + ): Promise { + // Get TX from cache + if (this.#commitCache.has(height)) { + const block = this.#commitCache.get(height)!.block; + + if (block.transactions.length <= index) { + return undefined; + } + + return block.transactions[index]; + } + + // Get TX from storage + return this.#readTransaction(`${height}-${index}`); + } + public async *readCommits(start: number, end: number): AsyncGenerator { for (let height = start; height <= end; height++) { const data = await this.#readCommitBytes(height);