diff --git a/packages/api-evm/source/actions/eth-get-block-transaction-count-by-number.test.ts b/packages/api-evm/source/actions/eth-get-block-transaction-count-by-number.test.ts new file mode 100644 index 000000000..d5649d6c4 --- /dev/null +++ b/packages/api-evm/source/actions/eth-get-block-transaction-count-by-number.test.ts @@ -0,0 +1,65 @@ +import { Identifiers } from "@mainsail/contracts"; +import { Validator } from "@mainsail/validation"; + +import { describe, Sandbox } from "../../../test-framework/source"; +import { EthGetBlockTransactionCountByNumber } from "./index.js"; + +describe<{ + sandbox: Sandbox; + action: EthGetBlockTransactionCountByNumber; + validator: Validator; + database: any; +}>("EthGetBlockTransactionCountByHash", ({ beforeEach, it, assert, stub }) => { + beforeEach(async (context) => { + context.database = { + getBlockHeader: async () => undefined, + }; + + context.sandbox = new Sandbox(); + + context.sandbox.app.bind(Identifiers.Database.Service).toConstantValue(context.database); + + context.action = context.sandbox.app.resolve(EthGetBlockTransactionCountByNumber); + context.validator = context.sandbox.app.resolve(Validator); + }); + + it("should have a name", ({ action }) => { + assert.equal(action.name, "eth_getBlockTransactionCountByNumber"); + }); + + 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_getBlockTransactionCountByNumber", ["0x0"]).errors); + assert.defined(validator.validate("jsonRpc_eth_getBlockTransactionCountByNumber", ["0x0", ""]).errors); + assert.defined(validator.validate("jsonRpc_eth_getBlockTransactionCountByNumber", [1]).errors); + assert.defined(validator.validate("jsonRpc_eth_getBlockTransactionCountByNumber", {}).errors); + }); + + it("should return null if block not found", async ({ action }) => { + assert.null(await action.handle(["0x10"])); + }); + + it("should return 0x0", async ({ action, database }) => { + const spyGetBlockHeader = stub(database, "getBlockHeader").returnValue({ numberOfTransactions: 0 }); + + assert.equal(await action.handle(["0x0"]), "0x0"); + + spyGetBlockHeader.calledOnce(); + spyGetBlockHeader.calledWith(0); + }); + + it("should return 0x14", async ({ action, database }) => { + const spyGetBlockHeader = stub(database, "getBlockHeader").returnValue({ numberOfTransactions: 20 }); + + assert.equal(await action.handle(["0x14"]), "0x14"); + + spyGetBlockHeader.calledOnce(); + spyGetBlockHeader.calledWith(20); + }); +}); diff --git a/packages/api-evm/source/actions/eth-get-block-transaction-count-by-number.ts b/packages/api-evm/source/actions/eth-get-block-transaction-count-by-number.ts new file mode 100644 index 000000000..bbbb15be0 --- /dev/null +++ b/packages/api-evm/source/actions/eth-get-block-transaction-count-by-number.ts @@ -0,0 +1,31 @@ +import { inject, injectable } from "@mainsail/container"; +import { Contracts, Identifiers } from "@mainsail/contracts"; + +@injectable() +export class EthGetBlockTransactionCountByNumber implements Contracts.Api.RPC.Action { + public readonly name: string = "eth_getBlockTransactionCountByNumber"; + + @inject(Identifiers.Database.Service) + private readonly databaseService!: Contracts.Database.DatabaseService; + + public readonly schema = { + $id: `jsonRpc_${this.name}`, + + maxItems: 1, + minItems: 1, + + prefixItems: [{ $ref: "prefixedHex" }], + type: "array", + }; + + public async handle(parameters: [string]): Promise { + const block = await this.databaseService.getBlockHeader(Number(parameters[0])); + + 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/index.ts b/packages/api-evm/source/actions/index.ts index 47569d53d..6d77943cd 100644 --- a/packages/api-evm/source/actions/index.ts +++ b/packages/api-evm/source/actions/index.ts @@ -4,6 +4,7 @@ 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-block-transaction-count-by-number.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 ee50af4ec..2efceeb67 100644 --- a/packages/api-evm/source/service-provider.ts +++ b/packages/api-evm/source/service-provider.ts @@ -9,6 +9,7 @@ import { EthGetBlockByHashAction, EthGetBlockByNumberAction, EthGetBlockTransactionCountByHash, + EthGetBlockTransactionCountByNumber, EthGetCodeAction, EthGetStorageAtAction, EthGetTransactionCount, @@ -77,6 +78,7 @@ export class ServiceProvider extends AbstractServiceProvider { this.app.resolve(EthGetBlockByHashAction), this.app.resolve(EthGetBlockByNumberAction), this.app.resolve(EthGetBlockTransactionCountByHash), + this.app.resolve(EthGetBlockTransactionCountByNumber), this.app.resolve(EthGetCodeAction), this.app.resolve(EthGetStorageAtAction), this.app.resolve(EthGetTransactionCount),