diff --git a/packages/api/src/base/Init.ts b/packages/api/src/base/Init.ts index 36aedd9a9772..c1297d406daa 100644 --- a/packages/api/src/base/Init.ts +++ b/packages/api/src/base/Init.ts @@ -64,6 +64,8 @@ export abstract class Init extends Decorate { this._rpcCore.setRegistrySwap((blockHash: Uint8Array) => this.getBlockRegistry(blockHash)); + this._rpcCore.setResolveBlockHash((blockNumber) => firstValueFrom(this._rpcCore.chain.getBlockHash(blockNumber))); + if (this.hasSubscriptions) { this._rpcCore.provider.on('disconnected', () => this.#onProviderDisconnect()); this._rpcCore.provider.on('error', (e: Error) => this.#onProviderError(e)); diff --git a/packages/rpc-core/src/bundle.ts b/packages/rpc-core/src/bundle.ts index 812468b66832..d20644f98d7b 100644 --- a/packages/rpc-core/src/bundle.ts +++ b/packages/rpc-core/src/bundle.ts @@ -5,7 +5,7 @@ import type { Observer } from 'rxjs'; import type { ProviderInterface, ProviderInterfaceCallback } from '@polkadot/rpc-provider/types'; import type { StorageKey, Vec } from '@polkadot/types'; import type { Hash } from '@polkadot/types/interfaces'; -import type { AnyJson, Codec, DefinitionRpc, DefinitionRpcExt, DefinitionRpcSub, Registry } from '@polkadot/types/types'; +import type { AnyJson, AnyNumber, Codec, DefinitionRpc, DefinitionRpcExt, DefinitionRpcSub, Registry } from '@polkadot/types/types'; import type { Memoized } from '@polkadot/util/types'; import type { RpcInterfaceMethod } from './types'; @@ -85,6 +85,7 @@ export class RpcCore { #registryDefault: Registry; #getBlockRegistry?: (blockHash: Uint8Array) => Promise<{ registry: Registry }>; + #getBlockHash?: (blockNumber: AnyNumber) => Promise; readonly #storageCache = new Map(); @@ -146,6 +147,15 @@ export class RpcCore { }); } + /** + * @description Sets a function to resolve block hash from block number + */ + public setResolveBlockHash (resolveBlockHash: (blockNumber: AnyNumber) => Promise): void { + this.#getBlockHash = memoize(resolveBlockHash, { + getInstanceId: () => this.#instanceId + }); + } + public addUserInterfaces (userRpc: Record>): void { // add any extra user-defined sections this.sections.push(...Object.keys(userRpc).filter((k) => !this.sections.includes(k))); @@ -202,12 +212,18 @@ export class RpcCore { // execute the RPC call, doing a registry swap for historic as applicable const callWithRegistry = async (isScale: boolean, values: unknown[]): Promise => { - const blockHash = hashIndex === -1 + const blockId = hashIndex === -1 ? null - : values[hashIndex] as (Uint8Array | string | null | undefined); + : values[hashIndex]; + + const blockHash = blockId && def.params[hashIndex].type === 'BlockNumber' + ? await this.#getBlockHash?.(blockId as AnyNumber) + : blockId as (Uint8Array | string | null | undefined); + const { registry } = isScale && blockHash && this.#getBlockRegistry ? await this.#getBlockRegistry(u8aToU8a(blockHash)) : { registry: this.#registryDefault }; + const params = this._formatInputs(registry, null, def, values); // only cache .at() queries, e.g. where valid blockHash was supplied diff --git a/packages/types/src/interfaces/eth/rpc.ts b/packages/types/src/interfaces/eth/rpc.ts index a9a00fed3efe..f3df79275326 100644 --- a/packages/types/src/interfaces/eth/rpc.ts +++ b/packages/types/src/interfaces/eth/rpc.ts @@ -62,6 +62,7 @@ export const rpc: DefinitionsRpc = objectSpread({}, netRpc, web3Rpc, { type: 'EthCallRequest' }, { + isHistoric: true, isOptional: true, name: 'number', type: 'BlockNumber' @@ -87,6 +88,7 @@ export const rpc: DefinitionsRpc = objectSpread({}, netRpc, web3Rpc, { type: 'EthCallRequest' }, { + isHistoric: true, isOptional: true, name: 'number', type: 'BlockNumber' @@ -107,6 +109,7 @@ export const rpc: DefinitionsRpc = objectSpread({}, netRpc, web3Rpc, { type: 'H160' }, { + isHistoric: true, isOptional: true, name: 'number', type: 'BlockNumber' @@ -167,6 +170,7 @@ export const rpc: DefinitionsRpc = objectSpread({}, netRpc, web3Rpc, { type: 'H160' }, { + isHistoric: true, isOptional: true, name: 'number', type: 'BlockNumber' @@ -234,6 +238,7 @@ export const rpc: DefinitionsRpc = objectSpread({}, netRpc, web3Rpc, { type: 'U256' }, { + isHistoric: true, isOptional: true, name: 'number', type: 'BlockNumber' @@ -287,6 +292,7 @@ export const rpc: DefinitionsRpc = objectSpread({}, netRpc, web3Rpc, { type: 'H256' }, { + isHistoric: true, isOptional: true, name: 'number', type: 'BlockNumber'