Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ a 32-byte hex string (`0x` followed by 64 hexadecimal digits) that denotes the b

- [`/node/version` fetch information about the Substrates node's implementation and versioning.](src/controllers/node/NodeVersionController.ts)

- [`/runtime/code` fetch the Wasm code blob of the Substrate runtime.](src/controllers/runtime/RuntimeCodeController.ts)

- [`/runtime/spec` version information of the Substrate runtime.](src/controllers/runtime/RuntimeSpecController.ts)

- [`/claims/ADDRESS` fetch claims data for an Ethereum `ADDRESS`.](src/controllers/claims/ClaimsController.ts)

- [`/claims/ADDRESS/NUMBER` fetch claims data for an Ethereum `ADDRESS` at the block identified by 'NUMBER`.](src/controllers/claims/ClaimsController.ts)
Expand Down
11 changes: 6 additions & 5 deletions openapi/openapi-proposal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -984,7 +984,7 @@ paths:
get:
tags:
- runtime
summary: Get version information of the runtime.
summary: Get version information of the Substrate runtime.
description: Returns version information related to the runtime.
parameters:
- name: at
Expand Down Expand Up @@ -1620,16 +1620,17 @@ components:
- Live
implVersion:
type: string
description: Version of the implementation of the specification. Non-consensus-breaking
description: Version of the implementation specification. Non-consensus-breaking
optimizations are about the only changes that could be made which would
result in only the `impl_version` changing.
result in only the `impl_version` changing. The `impl_version` is set to 0
when `spec_version` is incremented.
specName:
type: string
description: Identifies the different Substrate runtimes.
specVersion:
type: string
description: version of the runtime specification
txVersion:
description: Version of the runtime specification.
transactionVersion:
type: string
description: All existing dispatches are fully compatible when this number
doesn't change. This number must change when an existing dispatchable
Expand Down
51 changes: 51 additions & 0 deletions src/controllers/runtime/RuntimeCodeController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ApiPromise } from '@polkadot/api';
import { RequestHandler } from 'express';

import { RuntimeCodeService } from '../../services';
import AbstractController from '../AbstractController';

/**
* Get the Wasm code blob of the Substrate runtime.
*
* Query:
* - (Optional)`at`: Block at which to retrieve runtime version information at. Block
* identifier, as the block height or block hash. Defaults to most recent block.
*
* Returns:
* - `at`: Block number and hash at which the call was made.
* - `code`: Runtime code Wasm blob.
*/
export default class RuntimeCodeController extends AbstractController<
RuntimeCodeService
> {
constructor(api: ApiPromise) {
super(api, '/runtime/code', new RuntimeCodeService(api));
this.initRoutes();
}

protected initRoutes(): void {
this.safeMountAsyncGetHandlers([['', this.getCodeAtBlock]]);
}

/**
* Get the chain's latest metadata in a decoded, JSON format.
*
* @param _req Express Request
* @param res Express Response
*/

private getCodeAtBlock: RequestHandler = async (
{ query: { at } },
res
): Promise<void> => {
const hash =
typeof at === 'string'
? await this.getHashForBlock(at)
: await this.api.rpc.chain.getFinalizedHead();

RuntimeCodeController.sanitizedSend(
res,
await this.service.fetchCode(hash)
);
};
}
55 changes: 55 additions & 0 deletions src/controllers/runtime/RuntimeSpecController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { ApiPromise } from '@polkadot/api';
import { RequestHandler } from 'express';

import { RuntimeSpecService } from '../../services';
import AbstractController from '../AbstractController';

/**
* Get version information of the Substrate runtime.
*
* Query:
* - (Optional)`at`: Block at which to retrieve runtime version information. Block
* identifier, as the block height or block hash. Defaults to most recent block.
*
* Returns:
* - `at`: Block number and hash at which the call was made.
* - `authoringVersion`: The version of the authorship interface. An authoring node
* will not attempt to author blocks unless this is equal to its native runtime.
* - `chainType`: Type of the chain.
* - `implVersion`: Version of the implementation specification. Non-consensus-breaking
* optimizations are about the only changes that could be made which would
* result in only the `impl_version` changing. The `impl_version` is set to 0
* when `spec_version` is incremented.
* - `specName`: Identifies the spec name for the current runtime.
* - `specVersion`: Version of the runtime specification.
* - `transactionVersion`: All existing dispatches are fully compatible when this
* number doesn't change. This number must change when an existing dispatchable
* (module ID, dispatch ID) is changed, either through an alteration in its
* user-level semantics, a parameter added/removed/changed, a dispatchable
* its index.
* - `properties`: Arbitrary properties defined in the chain spec.
*/
export default class RuntimeSpecController extends AbstractController<
RuntimeSpecService
> {
constructor(api: ApiPromise) {
super(api, '/runtime/spec', new RuntimeSpecService(api));
this.initRoutes();
}

protected initRoutes(): void {
this.safeMountAsyncGetHandlers([['', this.getSpec]]);
}

private getSpec: RequestHandler = async ({ query: { at } }, res) => {
const hash =
typeof at === 'string'
? await this.getHashForBlock(at)
: await this.api.rpc.chain.getFinalizedHead();

RuntimeSpecController.sanitizedSend(
res,
await this.service.fetchSpec(hash)
);
};
}
2 changes: 2 additions & 0 deletions src/controllers/runtime/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export { default as Metadata } from './RuntimeMetadataController';
export { default as RuntimeCode } from './RuntimeCodeController';
export { default as RuntimeSpec } from './RuntimeSpecController';
4 changes: 4 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ async function main() {
const nodeTransactionPoolController = new controllers.NodeTransactionPool(
api
);
const runtimeCodeController = new controllers.RuntimeCode(api);
const runtimeSpecController = new controllers.RuntimeSpec(api);
const claimsController = new controllers.Claims(api);
const txArtifactsController = new controllers.TransactionMaterial(api);
const txFeeEstimateController = new controllers.TransactionFeeEstimate(api);
Expand All @@ -93,6 +95,8 @@ async function main() {
nodeNetworkController,
nodeVersionController,
nodeTransactionPoolController,
runtimeCodeController,
runtimeSpecController,
claimsController,
txArtifactsController,
txFeeEstimateController,
Expand Down
2 changes: 1 addition & 1 deletion src/services/accounts/AccountsStakingInfoService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class AccountsStakingInfoService extends AbstractService {

const at = {
hash,
height: header.number.toNumber().toString(10),
height: header.number.unwrap().toString(10),
};

if (controllerOption.isNone) {
Expand Down
18 changes: 18 additions & 0 deletions src/services/runtime/RuntimeCodeService.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { sanitizeNumbers } from '../../sanitize/sanitizeNumbers';
import { blockHash789629, mockApi } from '../test-helpers/mock';
import * as codeResponse from '../test-helpers/responses/runtime/code789629.json';
import { RuntimeCodeService } from './RuntimeCodeService';

const runtimeCodeService = new RuntimeCodeService(mockApi);

describe('RuntimeCodeService', () => {
describe('fetchCode', () => {
it('works when ApiPromise works', async () => {
expect(
sanitizeNumbers(
await runtimeCodeService.fetchCode(blockHash789629)
)
).toStrictEqual(codeResponse);
});
});
});
32 changes: 32 additions & 0 deletions src/services/runtime/RuntimeCodeService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Option, Raw } from '@polkadot/types';
import { BlockHash } from '@polkadot/types/interfaces';
import { IMetadataCode } from 'src/types/responses';

import { AbstractService } from '../AbstractService';

// https://github.com/shawntabrizi/substrate-graph-benchmarks/blob/ae9b82f/js/extensions/known-keys.js#L21
export const CODE_KEY = '0x3a636f6465';

export class RuntimeCodeService extends AbstractService {
/**
* Fetch `Metadata` in decoded JSON form.
*
* @param hash `BlockHash` to make call at
*/
async fetchCode(hash: BlockHash): Promise<IMetadataCode> {
const api = await this.ensureMeta(hash);

const [code, { number }] = await Promise.all([
api.rpc.state.getStorage(CODE_KEY, hash),
api.rpc.chain.getHeader(hash),
]);

return {
at: {
hash,
height: number.unwrap().toString(10),
},
code: code as Option<Raw>,
};
}
}
18 changes: 18 additions & 0 deletions src/services/runtime/RuntimeSpecService.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { sanitizeNumbers } from '../../sanitize/sanitizeNumbers';
import { blockHash789629, mockApi } from '../test-helpers/mock';
import * as response from '../test-helpers/responses/runtime/spec.json';
import { RuntimeSpecService } from './RuntimeSpecService';

const runtimeSpecService = new RuntimeSpecService(mockApi);

describe('RuntimeSpecService', () => {
describe('fetchSpec', () => {
it('works when ApiPromise works', async () => {
expect(
sanitizeNumbers(
await runtimeSpecService.fetchSpec(blockHash789629)
)
).toStrictEqual(response);
});
});
});
33 changes: 33 additions & 0 deletions src/services/runtime/RuntimeSpecService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { BlockHash } from '@polkadot/types/interfaces';
import { IRuntimeSpec } from 'src/types/responses';

import { AbstractService } from '../AbstractService';
export class RuntimeSpecService extends AbstractService {
async fetchSpec(hash: BlockHash): Promise<IRuntimeSpec> {
const [
{
authoringVersion,
specName,
specVersion,
transactionVersion,
implVersion,
},
chainType,
properties,
] = await Promise.all([
this.api.rpc.state.getRuntimeVersion(hash),
this.api.rpc.system.chainType(),
this.api.rpc.system.properties(),
]);

return {
authoringVersion,
transactionVersion,
implVersion,
specName,
specVersion,
chainType,
properties,
};
}
}
2 changes: 2 additions & 0 deletions src/services/runtime/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './RuntimeMetadataService';
export * from './RuntimeCodeService';
export * from './RuntimeSpecService';
25 changes: 25 additions & 0 deletions src/services/test-helpers/mock/mockApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const getRuntimeVersion = () =>
transactionVersion: polkadotRegistry.createType('u32', 2),
implVersion: polkadotRegistry.createType('u32', 0),
implName: polkadotRegistry.createType('Text', 'parity-polkadot'),
authoringVersion: polkadotRegistry.createType('u32', 0),
};
});

Expand Down Expand Up @@ -202,6 +203,27 @@ export const queryInfoBalancesTransfer = (
export const submitExtrinsic = (_extrinsic: string): Promise<Hash> =>
Promise.resolve().then(() => polkadotRegistry.createType('Hash'));

const getStorage = () =>
Promise.resolve().then(() =>
polkadotRegistry.createType('Option<Raw>', '0x')
);

const chainType = () =>
Promise.resolve().then(() =>
polkadotRegistry.createType('ChainType', {
Live: null,
})
);

const properties = () =>
Promise.resolve().then(() =>
polkadotRegistry.createType('ChainProperties', {
ss58Format: '0',
tokenDecimals: '12',
tokenSymbol: 'DOT',
})
);

const getFinalizedHead = () => Promise.resolve().then(() => blockHash789629);

const health = () =>
Expand Down Expand Up @@ -310,6 +332,7 @@ export const mockApi = ({
state: {
getRuntimeVersion,
getMetadata,
getStorage,
},
system: {
chain,
Expand All @@ -318,6 +341,8 @@ export const mockApi = ({
nodeRoles,
localPeerId,
version,
chainType,
properties,
},
payment: {
queryInfo: queryInfoBalancesTransfer,
Expand Down
7 changes: 7 additions & 0 deletions src/services/test-helpers/responses/runtime/code789629.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"at": {
"hash": "0x7b713de604a99857f6c25eacc115a4f28d2611a23d9ddff99ab0e4f1c17a8578",
"height": "789629"
},
"code": "0x"
}
15 changes: 15 additions & 0 deletions src/services/test-helpers/responses/runtime/spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"authoringVersion": "0",
"transactionVersion": "2",
"implVersion": "0",
"specName": "polkadot",
"specVersion": "16",
"chainType": {
"Live": null
},
"properties": {
"ss58Format": "0",
"tokenDecimals": "12",
"tokenSymbol": "DOT"
}
}
8 changes: 8 additions & 0 deletions src/types/responses/MetadataCode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Option, Raw } from '@polkadot/types';

import { IAt } from '.';

export interface IMetadataCode {
at: IAt;
code: Option<Raw>;
}
12 changes: 12 additions & 0 deletions src/types/responses/RuntimeSpec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ChainProperties, ChainType } from '@polkadot/types/interfaces';
import { Text, u32 } from '@polkadot/types/primitive';

export interface IRuntimeSpec {
authoringVersion: u32;
transactionVersion: u32;
implVersion: u32;
specName: Text;
specVersion: u32;
chainType: ChainType;
properties: ChainProperties;
}
2 changes: 2 additions & 0 deletions src/types/responses/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export * from './AccountStakingInfo';
export * from './AccountVestingInfo';
export * from './TransactionMaterial';
export * from './Extrinsic';
export * from './MetadataCode';
export * from './RuntimeSpec';
export * from './Payout';
export * from './EraPayouts';
export * from './AccountStakingPayouts';
Expand Down