From 6cedf66077e9d2148591ddb3cd868623cfaa026c Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 9 Jan 2025 16:01:05 +0100 Subject: [PATCH 1/2] Add action --- ...get-transaction-by-block-hash-and-index.ts | 35 +++++++++++++++++++ packages/api-evm/source/actions/index.ts | 1 + packages/api-evm/source/service-provider.ts | 2 ++ 3 files changed, 38 insertions(+) create mode 100644 packages/api-evm/source/actions/eth-get-transaction-by-block-hash-and-index.ts diff --git a/packages/api-evm/source/actions/eth-get-transaction-by-block-hash-and-index.ts b/packages/api-evm/source/actions/eth-get-transaction-by-block-hash-and-index.ts new file mode 100644 index 000000000..6f26ea725 --- /dev/null +++ b/packages/api-evm/source/actions/eth-get-transaction-by-block-hash-and-index.ts @@ -0,0 +1,35 @@ +import { inject, injectable } from "@mainsail/container"; +import { Contracts, Identifiers } from "@mainsail/contracts"; + +import { TransactionResource } from "../resources/index.js"; + +@injectable() +export class EthGetTransactionByBlockHashAndIndex 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_getTransactionByBlockHashAndIndex"; + + public readonly schema = { + $id: `jsonRpc_${this.name}`, + + maxItems: 1, + minItems: 1, + + prefixItems: [{ $ref: "prefixedHex" }], // TODO: Use transaction id + type: "array", + }; + + public async handle(parameters: [string]): Promise { + const transaction = await this.databaseService.getTransactionById(parameters[0].slice(2)); + + 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 4683b6ec0..60c862c32 100644 --- a/packages/api-evm/source/actions/index.ts +++ b/packages/api-evm/source/actions/index.ts @@ -7,6 +7,7 @@ export * from "./eth-get-block-transaction-count-by-hash.js"; 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-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 d690c78cb..cc43ee969 100644 --- a/packages/api-evm/source/service-provider.ts +++ b/packages/api-evm/source/service-provider.ts @@ -12,6 +12,7 @@ import { EthGetBlockTransactionCountByNumber, EthGetCodeAction, EthGetStorageAtAction, + EthGetTransactionByBlockHashAndIndex, EthGetTransactionByHash, EthGetTransactionCount, EthGetUncleByBlockHashAndIndex, @@ -82,6 +83,7 @@ export class ServiceProvider extends AbstractServiceProvider { this.app.resolve(EthGetBlockTransactionCountByNumber), this.app.resolve(EthGetCodeAction), this.app.resolve(EthGetStorageAtAction), + this.app.resolve(EthGetTransactionByBlockHashAndIndex), this.app.resolve(EthGetTransactionByHash), this.app.resolve(EthGetTransactionCount), this.app.resolve(EthGetUncleByBlockHashAndIndex), From e2d7500e1b66c1256359a18078cc4c6896391e8d Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 9 Jan 2025 16:33:55 +0100 Subject: [PATCH 2/2] Add and use getTransactionByBlockIdAndIndex --- ...get-transaction-by-block-hash-and-index.ts | 13 +++-- .../contracts/source/contracts/database.ts | 1 + packages/database/source/database-service.ts | 55 ++++++++++++++----- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/packages/api-evm/source/actions/eth-get-transaction-by-block-hash-and-index.ts b/packages/api-evm/source/actions/eth-get-transaction-by-block-hash-and-index.ts index 6f26ea725..b40d789ac 100644 --- a/packages/api-evm/source/actions/eth-get-transaction-by-block-hash-and-index.ts +++ b/packages/api-evm/source/actions/eth-get-transaction-by-block-hash-and-index.ts @@ -16,15 +16,18 @@ export class EthGetTransactionByBlockHashAndIndex implements Contracts.Api.RPC.A public readonly schema = { $id: `jsonRpc_${this.name}`, - maxItems: 1, - minItems: 1, + maxItems: 2, + minItems: 2, - prefixItems: [{ $ref: "prefixedHex" }], // TODO: Use transaction id + prefixItems: [{ $ref: "prefixedHex" }, { $ref: "prefixedHex" }], // TODO: Use block id & limit sequence type: "array", }; - public async handle(parameters: [string]): Promise { - const transaction = await this.databaseService.getTransactionById(parameters[0].slice(2)); + public async handle(parameters: [string, string]): Promise { + const transaction = await this.databaseService.getTransactionByBlockIdAndIndex( + parameters[0].slice(2), + Number.parseInt(parameters[1]), + ); if (!transaction) { return null; diff --git a/packages/contracts/source/contracts/database.ts b/packages/contracts/source/contracts/database.ts index fe308701f..caa7dee70 100644 --- a/packages/contracts/source/contracts/database.ts +++ b/packages/contracts/source/contracts/database.ts @@ -26,6 +26,7 @@ export interface DatabaseService { getBlockHeaderById(id: string): Promise; getTransactionById(id: string): Promise; + getTransactionByBlockIdAndIndex(blockId: string, 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 c9731c125..66c73e5d2 100644 --- a/packages/database/source/database-service.ts +++ b/packages/database/source/database-service.ts @@ -186,23 +186,32 @@ export class DatabaseService implements Contracts.Database.DatabaseService { return undefined; } - const transactionBytes: Buffer | undefined = this.transactionStorage.get(key); - Utils.assert.defined(transactionBytes); + return await this.#readTransaction(key); + } - const buffer = ByteBuffer.fromBuffer(transactionBytes); - const height = buffer.readUint32(); - const sequence = buffer.readUint32(); - const transaction = await this.transactionFactory.fromBytes(buffer.getRemainder()); + public async getTransactionByBlockIdAndIndex( + blockId: string, + index: number, + ): Promise { + // Verify if the block exists + const height = this.#getHeightById(blockId); + if (height === undefined) { + return undefined; + } - transaction.data.sequence = sequence; - transaction.data.blockHeight = height; + // Get TX from cache + if (this.#commitCache.has(height)) { + const block = this.#commitCache.get(height)!.block; - const blockBuffer = this.#readBlockHeaderBytes(height); - Utils.assert.defined(blockBuffer); - const block = await this.blockDeserializer.deserializeHeader(blockBuffer); - transaction.data.blockId = block.id; + if (block.transactions.length <= index) { + return undefined; + } - return transaction; + return block.transactions[index]; + } + + // Get TX from storage + return this.#readTransaction(`${height}-${index}`); } public async *readCommits(start: number, end: number): AsyncGenerator { @@ -346,6 +355,26 @@ export class DatabaseService implements Contracts.Database.DatabaseService { return this.blockStorage.get(height); } + async #readTransaction(key): Promise { + const transactionBytes: Buffer | undefined = this.transactionStorage.get(key); + Utils.assert.defined(transactionBytes); + + const buffer = ByteBuffer.fromBuffer(transactionBytes); + const height = buffer.readUint32(); + const sequence = buffer.readUint32(); + const transaction = await this.transactionFactory.fromBytes(buffer.getRemainder()); + + transaction.data.sequence = sequence; + transaction.data.blockHeight = height; + + const blockBuffer = this.#readBlockHeaderBytes(height); + Utils.assert.defined(blockBuffer); + const block = await this.blockDeserializer.deserializeHeader(blockBuffer); + transaction.data.blockId = block.id; + + return transaction; + } + async #map(data: unknown[], callback: (...arguments_: any[]) => Promise): Promise { const result: T[] = []; for (const [index, datum] of data.entries()) {