Skip to content

Commit

Permalink
feat(api-evm): implement eth_getBlockByNumber (#779)
Browse files Browse the repository at this point in the history
* Add missing packages

* Remove unused options from app.json

* Add basic eth_getBlockByNumber

* Use block resource

* Return hashes or object

* gasLimit from milestones

* Allow latest tags
  • Loading branch information
sebastijankuzner authored Nov 27, 2024
1 parent f454817 commit 805425a
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 14 deletions.
45 changes: 45 additions & 0 deletions packages/api-evm/source/actions/eth-get-block-by-number.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { inject, injectable } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";

import { BlockResource } from "../resources/index.js";

@injectable()
export class EthGetBlockByNumberAction implements Contracts.Api.RPC.Action {
public readonly name: string = "eth_getBlockByNumber";

@inject(Identifiers.Application.Instance)
private readonly app!: Contracts.Kernel.Application;

@inject(Identifiers.State.Store)
private readonly stateStore!: Contracts.State.Store;

@inject(Identifiers.Database.Service)
private readonly databaseService!: Contracts.Database.DatabaseService;

public readonly schema = {
$id: `jsonRpc_${this.name}`,

maxItems: 2,
minItems: 2,

prefixItems: [
{ oneOf: [{ $ref: "prefixedHex" }, { enum: ["latest", "finalized", "safe"], type: "string" }] }, // TODO: Extract block tag
{ type: "boolean" },
],
type: "array",
};

public async handle(parameters: [string, boolean]): Promise<object | null> {
const height = parameters[0].startsWith("0x") ? Number.parseInt(parameters[0]) : this.stateStore.getHeight();
const transactionObject = parameters[1];

const commit = await this.databaseService.getCommit(height);

if (!commit) {
// eslint-disable-next-line unicorn/no-null
return null;
}

return this.app.resolve(BlockResource).transform(commit.block, transactionObject);
}
}
1 change: 1 addition & 0 deletions packages/api-evm/source/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from "./eth-block-number.js";
export * from "./eth-call.js";
export * from "./eth-get-balance.js";
export * from "./eth-get-block-by-number.js";
export * from "./eth-get-code.js";
export * from "./eth-get-storage-at.js";
export * from "./eth-get-transaction-count.js";
Expand Down
40 changes: 40 additions & 0 deletions packages/api-evm/source/resources/block.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { inject, injectable } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";

@injectable()
export class BlockResource {
@inject(Identifiers.Cryptography.Configuration)
private readonly configuration!: Contracts.Crypto.Configuration;

public async transform(block: Contracts.Crypto.Block, transactionObject: boolean): Promise<object> {
const blockData: Contracts.Crypto.BlockData = block.data;

const milestone = this.configuration.getMilestone(blockData.height);

/* eslint-disable sort-keys-fix/sort-keys-fix */
return {
number: `0x${blockData.height.toString(16)}`,
hash: `0x${blockData.id}`,
parentHash: `0x${blockData.previousBlock}`,
nonce: "0x0",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad4e2a311b82e5872087ed76f0f1ccf8f", // No uncles in ARK, this is hash of empty list
logsBloom: "", // TODO: Implement logs bloom,
transactionsRoot: `0x${blockData.stateHash}`,
stateRoot: `0x${blockData.stateHash}`,
receiptsRoot: `0x${blockData.stateHash}`,
miner: blockData.generatorAddress,
difficulty: "0x0",
totalDifficulty: "0x0",
extraData: "0x",
size: `0x${blockData.payloadLength.toString(16)}`, // TODO: Implement block size
gasLimit: `0x${milestone.block.maxGasLimit.toString(16)}`,
gasUsed: `0x${blockData.totalGasUsed.toString(16)}`,
timestamp: `0x${blockData.timestamp.toString(16)}`,
transactions: transactionObject
? block.transactions.map((transaction) => transaction.data)
: block.transactions.map((transaction) => transaction.id),
uncles: [],
};
/* eslint-enable sort-keys-fix/sort-keys-fix */
}
}
1 change: 1 addition & 0 deletions packages/api-evm/source/resources/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./block.js";
2 changes: 2 additions & 0 deletions packages/api-evm/source/service-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
CallAction,
EthBlockNumberAction,
EthGetBalanceAction,
EthGetBlockByNumberAction,
EthGetCodeAction,
EthGetStorageAtAction,
EthGetTransactionCount,
Expand Down Expand Up @@ -65,6 +66,7 @@ export class ServiceProvider extends AbstractServiceProvider<Server> {
this.app.resolve(CallAction),
this.app.resolve(EthBlockNumberAction),
this.app.resolve(EthGetBalanceAction),
this.app.resolve(EthGetBlockByNumberAction),
this.app.resolve(EthGetCodeAction),
this.app.resolve(EthGetStorageAtAction),
this.app.resolve(EthGetTransactionCount),
Expand Down
25 changes: 11 additions & 14 deletions packages/core/bin/config/testnet/core/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,7 @@
"package": "@mainsail/transactions"
},
{
"package": "@mainsail/state",
"options": {
"snapshots": {
"enabled": false,
"skipUnknownAttributes": true
}
}
"package": "@mainsail/state"
},
{
"package": "@mainsail/transaction-pool-service"
Expand Down Expand Up @@ -258,6 +252,12 @@
{
"package": "@mainsail/crypto-block"
},
{
"package": "@mainsail/crypto-messages"
},
{
"package": "@mainsail/crypto-commit"
},
{
"package": "@mainsail/crypto-transaction"
},
Expand All @@ -268,13 +268,10 @@
"package": "@mainsail/transactions"
},
{
"package": "@mainsail/state",
"options": {
"snapshots": {
"enabled": false,
"skipUnknownAttributes": true
}
}
"package": "@mainsail/state"
},
{
"package": "@mainsail/database"
},
{
"package": "@mainsail/evm-service"
Expand Down

0 comments on commit 805425a

Please sign in to comment.