Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ae1de13
feat: chainSpec based controller config; Types from apps-config
emostov Nov 24, 2020
5d254dd
Update mock api to include derive getBlock - specs work
emostov Nov 24, 2020
7072fdc
Update to reflect TS 4.1
emostov Nov 24, 2020
c682665
Clean up comments
emostov Nov 24, 2020
4ab1b2d
Save
emostov Dec 2, 2020
cc9a962
Merge origin master
emostov Dec 2, 2020
ede1787
feat: Token query param for non-native token balance-info
emostov Dec 2, 2020
39e1a1a
Revert package.json
emostov Dec 2, 2020
be66056
Initial reply david review
emostov Dec 2, 2020
e465092
Update src/main.ts
emostov Dec 2, 2020
19a66e7
Remove kulupu controller
emostov Dec 2, 2020
0ac5573
Merge branch 'types-package' of https://github.com/paritytech/substra…
emostov Dec 2, 2020
c5e9284
Add chain builder integration guide
emostov Dec 3, 2020
0c57ecd
Patch CHAIN_INTEGRATION.md
emostov Dec 3, 2020
6692e50
Apply suggestions from code review
emostov Dec 4, 2020
4b4d9a2
Update CHAIN_INTEGRATION.md
emostov Dec 4, 2020
b81c0d1
Bump deps
emostov Dec 8, 2020
46f067d
Merge remote-tracking branch 'origin' into types-package
emostov Dec 8, 2020
92a8856
Use whole options object for controller creation
emostov Dec 8, 2020
8451309
Apply suggestions from code review
emostov Dec 9, 2020
87572a9
Respond to maciej feedback
emostov Dec 9, 2020
c38c105
Merge branch 'types-package' of https://github.com/paritytech/substra…
emostov Dec 9, 2020
a1a988a
Update chain integration guide
emostov Dec 9, 2020
79f9eb8
Remove excessive nullish colescing operators
emostov Dec 9, 2020
cf84d63
Merge origin master
emostov Dec 9, 2020
b34cca2
Fix merge issue
emostov Dec 9, 2020
a16235a
Update CHAIN_INTEGRATION.md
emostov Dec 9, 2020
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
Next Next commit
feat: chainSpec based controller config; Types from apps-config
Clean up
  • Loading branch information
emostov committed Nov 24, 2020
commit ae1de13620ff8a2d21f3a29b2db0173f62aa6b34
18 changes: 10 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"build:calc": "bash ./calc/build.sh",
"build:docker": "docker build -t substrate-api-sidecar .",
"build:docs": "(cd docs && yarn && yarn build)",
"clean": "rm -rf node_modules/ yarn.lock build/",
"main": "node ./build/src/main.js",
"lint": "tsc && eslint . --ext ts",
"deploy": "yarn build && standard-version",
Expand All @@ -36,8 +37,9 @@
"test": "jest --silent"
},
"dependencies": {
"@polkadot/api": "^2.7.1",
"@polkadot/util-crypto": "^4.1.1",
"@polkadot/api": "^2.8.1",
"@polkadot/apps-config": "^0.68.1",
"@polkadot/util-crypto": "^4.2.1",
"@substrate/calc": "^0.1.2",
"confmgr": "^1.0.6",
"express": "^4.17.1",
Expand All @@ -52,19 +54,19 @@
"@types/jest": "^26.0.15",
"@types/morgan": "^1.9.2",
"@types/triple-beam": "^1.3.2",
"@typescript-eslint/eslint-plugin": "^4.7.0",
"@typescript-eslint/parser": "^4.7.0",
"eslint": "^7.13.0",
"@typescript-eslint/eslint-plugin": "^4.8.2",
"@typescript-eslint/parser": "^4.8.2",
"eslint": "^7.14.0",
"eslint-config-prettier": "^6.15.0",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-simple-import-sort": "^6.0.0",
"eslint-plugin-simple-import-sort": "^6.0.1",
"jest": "^26.6.3",
"prettier": "^2.1.2",
"prettier": "^2.2.0",
"rimraf": "^3.0.2",
"standard-version": "^9.0.0",
"ts-jest": "^26.4.4",
"tsc-watch": "^4.2.9",
"typescript": "^4.0.5"
"typescript": "^4.1.2"
},
"resolutions": {
"node-forge": ">=0.10.0",
Expand Down
3 changes: 3 additions & 0 deletions src/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ export default class App {
listen(): void {
this.app.listen(this.port, this.host, () => {
console.log(`Listening on http://${this.host}:${this.port}/`);
console.log(
`Check the root endpoint (http://${this.host}:${this.port}/) to see the available endpoints for the current node`
);
});
}

Expand Down
4 changes: 2 additions & 2 deletions src/Config.ts → src/SidecarConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ConfigManager } from 'confmgr';

import * as configTypes from '../config/types.json';
import { Specs } from './Specs';
import { CONFIG, ISidecarConfig, MODULES } from './types/config';
import { CONFIG, ISidecarConfig, MODULES } from './types/sidecar-config';

function hr(): string {
return Array(80).fill('━').join('');
Expand All @@ -11,7 +11,7 @@ function hr(): string {
/**
* Access a singleton config object that will be intialized on first use.
*/
export class Config {
export class SidecarConfig {
private static _config: ISidecarConfig | undefined;
/**
* Gather env vars for config and make sure they are valid.
Expand Down
2 changes: 1 addition & 1 deletion src/Specs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ConfigSpecs, SpecsFactory } from 'confmgr';

import { CONFIG, MODULES } from './types/config';
import { CONFIG, MODULES } from './types/sidecar-config';

/**
* Access a singleton specification for config enviroment variables that will
Expand Down
26 changes: 26 additions & 0 deletions src/chains-config/defaultControllers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ControllerConfig } from '../types/chains-config';

/**
* Controllers that Sidecar will always default to. This likely will always be
* the optimal controller selection for Polkadot and Kusama.
*/
export const defaultControllers: ControllerConfig = {
Blocks: true,
KulupuBlocks: true,
AccountsStakingPayouts: true,
AccountsBalanceInfo: true,
AccountsStakingInfo: true,
AccountsVestingInfo: true,
NodeNetwork: true,
NodeVersion: true,
NodeTransactionPool: true,
RuntimeCode: true,
RuntimeSpec: true,
RuntimeMetadata: true,
TransactionDryRun: true,
TransactionMaterial: true,
TransactionFeeEstimate: true,
TransactionSubmit: true,
PalletsStakingProgress: true,
PalletsStorageItem: true,
};
48 changes: 48 additions & 0 deletions src/chains-config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { ApiPromise } from '@polkadot/api';
import AbstractController from 'src/controllers/AbstractController';
import { AbstractService } from 'src/services/AbstractService';

import { controllers } from '../controllers';
import { ControllerConfig } from '../types/chains-config';
import { defaultControllers } from './defaultControllers';
import { kulupuControllers } from './kulupuControllers';

/**
*
* @param api ApiPromise to inject into controllers
* @param implName
*/
export function getControllersForSpec(
api: ApiPromise,
specName: string
): AbstractController<AbstractService>[] {
switch (specName) {
case 'kulupu':
return getControllersFromConfig(api, kulupuControllers);
default:
return getControllersFromConfig(api, defaultControllers);
}
}

/**
* Return an array of instantiated controller instances based off of a
* `ControllerConfig`.
*
* @param api ApiPromise to inject into controllers
* @param config controller mount configuration object
*/
function getControllersFromConfig(api: ApiPromise, config: ControllerConfig) {
// If we don't typecast here, tsc thinks its just [string, any][]
const controllersToInclude = Object.entries(config) as [
keyof typeof controllers,
boolean
][];

return controllersToInclude.reduce((acc, [controllerName, shouldMount]) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day JavaScript will get filterMap on arrays, one day... :)

if (shouldMount) {
return acc.concat(new controllers[controllerName](api));
}

return acc;
}, [] as AbstractController<AbstractService>[]);
}
22 changes: 22 additions & 0 deletions src/chains-config/kulupuControllers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ControllerConfig } from '../types/chains-config';

export const kulupuControllers: ControllerConfig = {
Blocks: false,
KulupuBlocks: true,
AccountsStakingPayouts: false,
AccountsBalanceInfo: true,
AccountsStakingInfo: false,
AccountsVestingInfo: false,
NodeNetwork: true,
NodeVersion: true,
NodeTransactionPool: true,
RuntimeCode: true,
RuntimeSpec: true,
RuntimeMetadata: true,
TransactionDryRun: true,
TransactionMaterial: true,
TransactionFeeEstimate: true,
TransactionSubmit: true,
PalletsStakingProgress: false,
PalletsStorageItem: true,
};
4 changes: 1 addition & 3 deletions src/controllers/AbstractControllers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ const api = {
},
};

const MockController = class MockController extends AbstractController<
AbstractService
> {
const MockController = class MockController extends AbstractController<AbstractService> {
protected initRoutes(): void {
throw new Error('Method not implemented.');
}
Expand Down
4 changes: 1 addition & 3 deletions src/controllers/accounts/AccountsBalanceInfoController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ import AbstractController from '../AbstractController';
* - `AccountData`: https://crates.parity.io/pallet_balances/struct.AccountData.html
* - `BalanceLock`: https://crates.parity.io/pallet_balances/struct.BalanceLock.html
*/
export default class AccountsBalanceController extends AbstractController<
AccountsBalanceInfoService
> {
export default class AccountsBalanceController extends AbstractController<AccountsBalanceInfoService> {
constructor(api: ApiPromise) {
super(
api,
Expand Down
4 changes: 1 addition & 3 deletions src/controllers/accounts/AccountsStakingInfoController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ import AbstractController from '../AbstractController';
* - `Bonded`: https://crates.parity.io/pallet_staking/struct.Bonded.html
* - `StakingLedger`: https://crates.parity.io/pallet_staking/struct.StakingLedger.html
*/
export default class AccountsStakingInfoController extends AbstractController<
AccountsStakingInfoService
> {
export default class AccountsStakingInfoController extends AbstractController<AccountsStakingInfoService> {
constructor(api: ApiPromise) {
super(
api,
Expand Down
8 changes: 2 additions & 6 deletions src/controllers/accounts/AccountsStakingPayoutsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ import AbstractController from '../AbstractController';
* aformentioned payouts.
*
*/
export default class AccountsStakingPayoutsController extends AbstractController<
AccountsStakingPayoutsService
> {
export default class AccountsStakingPayoutsController extends AbstractController<AccountsStakingPayoutsService> {
constructor(api: ApiPromise) {
super(
api,
Expand All @@ -86,9 +84,7 @@ export default class AccountsStakingPayoutsController extends AbstractController
* @param req Express Request
* @param res Express Response
*/
private getStakingPayoutsByAccountId: RequestHandler<
IAddressParam
> = async (
private getStakingPayoutsByAccountId: RequestHandler<IAddressParam> = async (
{ params: { address }, query: { depth, era, unclaimedOnly } },
res
): Promise<void> => {
Expand Down
4 changes: 1 addition & 3 deletions src/controllers/accounts/AccountsVestingInfoController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ import AbstractController from '../AbstractController';
* - Vesting Pallet: https://crates.parity.io/pallet_vesting/index.html
* - `VestingInfo`: https://crates.parity.io/pallet_vesting/struct.VestingInfo.html
*/
export default class AccountsVestingInfoController extends AbstractController<
AccountsVestingInfoService
> {
export default class AccountsVestingInfoController extends AbstractController<AccountsVestingInfoService> {
constructor(api: ApiPromise) {
super(
api,
Expand Down
4 changes: 1 addition & 3 deletions src/controllers/blocks/BlocksController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ import AbstractController from '../AbstractController';
* - `OnInitialize`: https://crates.parity.io/frame_support/traits/trait.OnInitialize.html
* - `OnFinalize`: https://crates.parity.io/frame_support/traits/trait.OnFinalize.html
*/
export default class BlocksController extends AbstractController<
BlocksService
> {
export default class BlocksController extends AbstractController<BlocksService> {
constructor(api: ApiPromise) {
super(api, '/blocks', new BlocksService(api));
this.initRoutes();
Expand Down
121 changes: 121 additions & 0 deletions src/controllers/chains/KulupuBlocksController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { ApiPromise } from '@polkadot/api';
import { RequestHandler } from 'express';

import { BlocksService } from '../../services';
import { INumberParam } from '../../types/requests';
import AbstractController from '../AbstractController';

/**
* GET a block.
*
* N.B. this controller assumes the chain does not have a finality
* gadget (e.g. PoW in Kulupu))
*
* Paths:
* - `kulupuBlocks\head`: Get the latest finalized block.
* - (Optional) `kulupuBlocks\number`: Block hash or height at which to query. If not provided, queries
* finalized head.
*
* Query:
* - (Optional) `eventDocs`: When set to `true`, every event will have an extra
* `docs` property with a string of the events documentation.
* - (Optional) `extrinsicDocs`: When set to `true`, every extrinsic will have an extra
* `docs` property with a string of the extrinsics documentation.
*
*
* Returns:
* - `number`: Block height.
* - `hash`: The block's hash.
* - `parentHash`: The hash of the parent block.
* - `stateRoot`: The state root after executing this block.
* - `extrinsicsRoot`: The Merkle root of the extrinsics.
* - `authorId`: The account ID of the block author (may be undefined for some chains).
* - `logs`: Array of `DigestItem`s associated with the block.
* - `onInitialize`: Object with an array of `SanitizedEvent`s that occurred during block
* initialization with the `method` and `data` for each.
* - `extrinsics`: Array of extrinsics (inherents and transactions) within the block. Each
* contains:
* - `method`: Extrinsic method.
* - `signature`: Object with `signature` and `signer`, or `null` if unsigned.
* - `nonce`: Account nonce, if applicable.
* - `args`: Array of arguments.
* - `tip`: Any tip added to the transaction.
* - `hash`: The transaction's hash.
* - `info`: `RuntimeDispatchInfo` for the transaction. Includes the `partialFee`.
* - `events`: An array of `SanitizedEvent`s that occurred during extrinsic execution.
* - `success`: Whether or not the extrinsic succeeded.
* - `paysFee`: Whether the extrinsic requires a fee. Careful! This field relates to whether or
* not the extrinsic requires a fee if called as a transaction. Block authors could insert
* the extrinsic as an inherent in the block and not pay a fee. Always check that `paysFee`
* is `true` and that the extrinsic is signed when reconciling old blocks.
* - `onFinalize`: Object with an array of `SanitizedEvent`s that occurred during block
* finalization with the `method` and `data` for each.
*
*
* Substrate Reference:
* - `DigestItem`: https://crates.parity.io/sp_runtime/enum.DigestItem.html
* - `RawEvent`: https://crates.parity.io/frame_system/enum.RawEvent.html
* - Extrinsics: https://substrate.dev/docs/en/knowledgebase/learn-substrate/extrinsics
* - `Extrinsic`: https://crates.parity.io/sp_runtime/traits/trait.Extrinsic.html
* - `OnInitialize`: https://crates.parity.io/frame_support/traits/trait.OnInitialize.html
* - `OnFinalize`: https://crates.parity.io/frame_support/traits/trait.OnFinalize.html
*/
export default class KulupuBlocksController extends AbstractController<BlocksService> {
constructor(api: ApiPromise) {
super(api, '/kulupuBlocks', new BlocksService(api));
this.initRoutes();
}

protected initRoutes(): void {
this.safeMountAsyncGetHandlers([
['/head', this.getLatestBlock],
['/:number', this.getBlockById],
]);
}

/**
* Get the latest block.
*
* @param _req Express Request
* @param res Express Response
*/
private getLatestBlock: RequestHandler = async (
{ query: { eventDocs, extrinsicDocs } },
res
) => {
const eventDocsArg = eventDocs === 'true';
const extrsinsicDocsArg = extrinsicDocs === 'true';

const hash = (await this.api.rpc.chain.getHeader()).hash;

KulupuBlocksController.sanitizedSend(
res,
await this.service.fetchBlock(hash, eventDocsArg, extrsinsicDocsArg)
);
};

/**
* Get a block by its hash or number identifier.
*
* @param req Express Request
* @param res Express Response
*/
private getBlockById: RequestHandler<INumberParam> = async (
{ params: { number }, query: { eventDocs, extrinsicDocs } },
res
): Promise<void> => {
const hash = await this.getHashForBlock(number);

const eventDocsArg = eventDocs === 'true';
const extrinsinsicDocsArg = extrinsicDocs === 'true';

KulupuBlocksController.sanitizedSend(
res,
await this.service.fetchBlock(
hash,
eventDocsArg,
extrinsinsicDocsArg
)
);
};
}
6 changes: 6 additions & 0 deletions src/controllers/chains/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Chain specific controllers.
//
// These endpoints may be reused for other chains as well, but for now naming them after the chain
// that originally neccesitated it for simplicity.

export { default as KulupuBlocks } from './KulupuBlocksController';
Loading