diff --git a/packages/api-evm/source/actions/eth-get-block-transaction-count-by-hash.test.ts b/packages/api-evm/source/actions/eth-get-block-transaction-count-by-hash.test.ts new file mode 100644 index 000000000..e4195a6b0 --- /dev/null +++ b/packages/api-evm/source/actions/eth-get-block-transaction-count-by-hash.test.ts @@ -0,0 +1,80 @@ +import { Identifiers } from "@mainsail/contracts"; +import { Validator } from "@mainsail/validation"; + +import { describe, Sandbox } from "../../../test-framework/source"; +import { EthGetBlockTransactionCountByHash } from "./index.js"; + +describe<{ + sandbox: Sandbox; + action: EthGetBlockTransactionCountByHash; + validator: Validator; + database: any; +}>("EthGetBlockTransactionCountByHash", ({ beforeEach, it, assert, stub }) => { + beforeEach(async (context) => { + context.database = { + getBlockHeaderById: async () => undefined, + }; + + context.sandbox = new Sandbox(); + + context.sandbox.app.bind(Identifiers.Database.Service).toConstantValue(context.database); + + context.action = context.sandbox.app.resolve(EthGetBlockTransactionCountByHash); + context.validator = context.sandbox.app.resolve(Validator); + }); + + it("should have a name", ({ action }) => { + assert.equal(action.name, "eth_getBlockTransactionCountByHash"); + }); + + it("schema should be array with 0 parameters", ({ action, validator }) => { + validator.addSchema({ + $id: "prefixedHex", + pattern: "^0x[0-9a-f]+$", + type: "string", + }); + validator.addSchema(action.schema); + + assert.undefined( + validator.validate("jsonRpc_eth_getBlockTransactionCountByHash", [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + ]).errors, + ); + assert.defined( + validator.validate("jsonRpc_eth_getBlockTransactionCountByHash", [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "", + ]).errors, + ); + assert.defined(validator.validate("jsonRpc_eth_getBlockTransactionCountByHash", [1]).errors); + assert.defined(validator.validate("jsonRpc_eth_getBlockTransactionCountByHash", {}).errors); + }); + + it("should return null if block not found", async ({ action }) => { + assert.null(await action.handle(["0x0000000000000000000000000000000000000000000000000000000000000000"])); + }); + + it("should return 0x0", async ({ action, database }) => { + const spyGetBlockHeaderById = stub(database, "getBlockHeaderById").returnValue({ numberOfTransactions: 0 }); + + assert.equal( + await action.handle(["0x0000000000000000000000000000000000000000000000000000000000000000"]), + "0x0", + ); + + spyGetBlockHeaderById.calledOnce(); + spyGetBlockHeaderById.calledWith("0000000000000000000000000000000000000000000000000000000000000000"); + }); + + it("should return 0x14", async ({ action, database }) => { + const spyGetBlockHeaderById = stub(database, "getBlockHeaderById").returnValue({ numberOfTransactions: 20 }); + + assert.equal( + await action.handle(["0x0000000000000000000000000000000000000000000000000000000000000000"]), + "0x14", + ); + + spyGetBlockHeaderById.calledOnce(); + spyGetBlockHeaderById.calledWith("0000000000000000000000000000000000000000000000000000000000000000"); + }); +}); diff --git a/packages/api-evm/source/actions/eth-get-block-transaction-count-by-hash.ts b/packages/api-evm/source/actions/eth-get-block-transaction-count-by-hash.ts new file mode 100644 index 000000000..044761cf1 --- /dev/null +++ b/packages/api-evm/source/actions/eth-get-block-transaction-count-by-hash.ts @@ -0,0 +1,31 @@ +import { inject, injectable } from "@mainsail/container"; +import { Contracts, Identifiers } from "@mainsail/contracts"; + +@injectable() +export class EthGetBlockTransactionCountByHash implements Contracts.Api.RPC.Action { + public readonly name: string = "eth_getBlockTransactionCountByHash"; + + @inject(Identifiers.Database.Service) + private readonly databaseService!: Contracts.Database.DatabaseService; + + public readonly schema = { + $id: `jsonRpc_${this.name}`, + + maxItems: 1, + minItems: 1, + + prefixItems: [{ $ref: "prefixedHex" }], // TODO: Replace prefixedHex with prefixedBlockId + type: "array", + }; + + public async handle(parameters: [string]): Promise { + const block = await this.databaseService.getBlockHeaderById(parameters[0].slice(2)); + + if (!block) { + // eslint-disable-next-line unicorn/no-null + return null; + } + + return `0x${block.numberOfTransactions.toString(16)}`; + } +} diff --git a/packages/api-evm/source/actions/eth-get-transaction-count.test.ts b/packages/api-evm/source/actions/eth-get-transaction-count.test.ts index 82a18b298..6c74bb7e6 100644 --- a/packages/api-evm/source/actions/eth-get-transaction-count.test.ts +++ b/packages/api-evm/source/actions/eth-get-transaction-count.test.ts @@ -1,10 +1,10 @@ import { Identifiers } from "@mainsail/contracts"; import { Validator } from "@mainsail/validation"; -import { describeSkip, Sandbox } from "../../../test-framework/source"; +import { describe, Sandbox } from "../../../test-framework/source"; import { EthGetTransactionCount } from "./index.js"; -describeSkip<{ +describe<{ sandbox: Sandbox; action: EthGetTransactionCount; validator: Validator; diff --git a/packages/api-evm/source/actions/index.ts b/packages/api-evm/source/actions/index.ts index a86021d69..47569d53d 100644 --- a/packages/api-evm/source/actions/index.ts +++ b/packages/api-evm/source/actions/index.ts @@ -3,6 +3,7 @@ export * from "./eth-call.js"; export * from "./eth-get-balance.js"; export * from "./eth-get-block-by-hash.js"; export * from "./eth-get-block-by-number.js"; +export * from "./eth-get-block-transaction-count-by-hash.js"; export * from "./eth-get-code.js"; export * from "./eth-get-storage-at.js"; export * from "./eth-get-transaction-count.js"; diff --git a/packages/api-evm/source/service-provider.ts b/packages/api-evm/source/service-provider.ts index 80b82a218..ee50af4ec 100644 --- a/packages/api-evm/source/service-provider.ts +++ b/packages/api-evm/source/service-provider.ts @@ -8,6 +8,7 @@ import { EthGetBalanceAction, EthGetBlockByHashAction, EthGetBlockByNumberAction, + EthGetBlockTransactionCountByHash, EthGetCodeAction, EthGetStorageAtAction, EthGetTransactionCount, @@ -75,6 +76,7 @@ export class ServiceProvider extends AbstractServiceProvider { this.app.resolve(EthGetBalanceAction), this.app.resolve(EthGetBlockByHashAction), this.app.resolve(EthGetBlockByNumberAction), + this.app.resolve(EthGetBlockTransactionCountByHash), this.app.resolve(EthGetCodeAction), this.app.resolve(EthGetStorageAtAction), this.app.resolve(EthGetTransactionCount),