Skip to content

Commit

Permalink
feat: add pallets/on-going-referenda endpoint (#1471)
Browse files Browse the repository at this point in the history
* feat: add pallets/on-going-referenda endpoint

* updated docs

* error handling when call not available
- added also a test for that case

* added test that returns referenda (call available)

* replaced unnecessary Promise.all

* small but nice improvements
- added block height in the error msg (Tarik's review)
- added a Promise.all (Filippo's review)
  • Loading branch information
Imod7 committed Aug 14, 2024
1 parent 250b613 commit 386fbb3
Show file tree
Hide file tree
Showing 18 changed files with 611 additions and 8 deletions.
2 changes: 1 addition & 1 deletion docs/dist/app.bundle.js

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions docs/src/openapi-v1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,31 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/PalletsNominationPool'
/pallets/on-going-referenda:
get:
tags:
- pallets
summary: Get a list of all on-going referenda that have track `root (0)` and `whitelisted (1)`,
along with their associated information.
description: Returns information associated with on-going referenda which includes
the referendum's `enactment`, `submitted` and `deciding` fields.
operationId: getPalletOnGoingReferenda
parameters:
- name: at
in: query
description: Block at which to retrieve the on-going referenda.
required: false
schema:
type: string
description: Block identifier, as the block height or block hash.
format: unsignedInteger or $hex
responses:
"200":
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/PalletsOnGoingReferenda'
/pallets/{palletId}/consts:
get:
tags:
Expand Down Expand Up @@ -3796,6 +3821,55 @@ components:
type: number
minJoinBond:
type: number
PalletsOnGoingReferenda:
type: object
properties:
at:
$ref: '#/components/schemas/BlockIdentifiers'
referenda:
type: array
items:
type: object
properties:
id:
type: string
description: Referendum's id.
decisionDeposit:
type: object
properties:
who:
type: string
description: The account who placed the referendum's decision deposit.
amount:
type: string
format: unsignedInteger
description: The amount of the decision deposit.
description: A deposit which is required for a referendum to progress to the decision phase.
enactment:
type: string
enum:
- at
- after
description: The enactment period of the referendum. It can be defined using either the `at` option,
which specifies the exact block height when the referendum will be enacted, or the `after` option,
which indicates the number of blocks after which the enactment will occur.
submitted:
type: string
format: unsignedInteger
description: The block number at which the referendum was submitted.
deciding:
type: object
properties:
since:
type: string
format: unsignedInteger
description: The block number at which the referendum started being `decided`.
confirming:
type: string
format: unsignedInteger
description: The block number at which the referendum's confirmation stage will end at as long as
it doesn't lose its approval in the meantime.
description: A list of ongoing referenda and their details.
PalletsPoolAssetsInfo:
type: object
properties:
Expand Down
3 changes: 2 additions & 1 deletion src/chains-config/defaultControllers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2022 Parity Technologies (UK) Ltd.
// Copyright 2017-2024 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -43,6 +43,7 @@ export const defaultControllers: ControllerConfig = {
'PalletsErrors',
'PalletsEvents',
'PalletsForeignAssets',
'PalletsOnGoingReferenda',
'PalletsStakingProgress',
'PalletsStorage',
'Paras',
Expand Down
3 changes: 2 additions & 1 deletion src/chains-config/kusamaControllers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2022 Parity Technologies (UK) Ltd.
// Copyright 2017-2024 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -41,6 +41,7 @@ export const kusamaControllers: ControllerConfig = {
'PalletsErrors',
'PalletsEvents',
'PalletsNominationPools',
'PalletsOnGoingReferenda',
'PalletsStakingProgress',
'PalletsStakingValidators',
'PalletsStorage',
Expand Down
3 changes: 2 additions & 1 deletion src/chains-config/polkadotControllers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2022 Parity Technologies (UK) Ltd.
// Copyright 2017-2024 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -41,6 +41,7 @@ export const polkadotControllers: ControllerConfig = {
'PalletsErrors',
'PalletsEvents',
'PalletsNominationPools',
'PalletsOnGoingReferenda',
'PalletsStakingProgress',
'PalletsStakingValidators',
'PalletsStorage',
Expand Down
4 changes: 3 additions & 1 deletion src/controllers/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2023 Parity Technologies (UK) Ltd.
// Copyright 2017-2024 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -37,6 +37,7 @@ import {
PalletsEvents,
PalletsForeignAssets,
PalletsNominationPools,
PalletsOnGoingReferenda,
PalletsPoolAssets,
PalletsStakingProgress,
PalletsStakingValidators,
Expand Down Expand Up @@ -72,6 +73,7 @@ export const controllers = {
PalletsEvents,
PalletsForeignAssets,
PalletsNominationPools,
PalletsOnGoingReferenda,
PalletsPoolAssets,
PalletsStakingProgress,
PalletsStakingValidators,
Expand Down
44 changes: 44 additions & 0 deletions src/controllers/pallets/PalletsOnGoingReferendaController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2017-2024 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

import { ApiPromise } from '@polkadot/api';
import { RequestHandler } from 'express';

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

export default class PalletsOnGoingReferendaController extends AbstractController<PalletsOnGoingReferendaService> {
constructor(api: ApiPromise) {
super(api, '/pallets/on-going-referenda', new PalletsOnGoingReferendaService(api));
this.initRoutes();
}

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

/**
* Get the on-going referenda.
*
* @param _req Express Request
* @param res Express Response
*/
private getPalletOnGoingReferenda: RequestHandler = async ({ query: { at } }, res): Promise<void> => {
const hash = await this.getHashFromAt(at);

PalletsOnGoingReferendaController.sanitizedSend(res, await this.service.derivePalletOnGoingReferenda(hash));
};
}
3 changes: 2 additions & 1 deletion src/controllers/pallets/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2023 Parity Technologies (UK) Ltd.
// Copyright 2017-2024 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
Expand All @@ -22,6 +22,7 @@ export { default as PalletsErrors } from './PalletsErrorsController';
export { default as PalletsEvents } from './PalletsEventsController';
export { default as PalletsForeignAssets } from './PalletsForeignAssetsController';
export { default as PalletsNominationPools } from './PalletsNominationPoolsController';
export { default as PalletsOnGoingReferenda } from './PalletsOnGoingReferendaController';
export { default as PalletsPoolAssets } from './PalletsPoolAssetsController';
export { default as PalletsStakingProgress } from './PalletsStakingProgressController';
export { default as PalletsStakingValidators } from './PalletsStakingValidatorsController';
Expand Down
91 changes: 91 additions & 0 deletions src/services/pallets/PalletsOnGoingReferendaService.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright 2017-2024 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

import type { ApiPromise } from '@polkadot/api';
import type { ApiDecoration } from '@polkadot/api/types';
import type { Hash } from '@polkadot/types/interfaces';

import { sanitizeNumbers } from '../../sanitize/sanitizeNumbers';
import { polkadotRegistryV9300 } from '../../test-helpers/registries';
import { polkadotRegistryV1000001 } from '../../test-helpers/registries';
import { blockHash13641102, blockHash21275366, mockBlock13641102, mockBlock21275366 } from '../test-helpers/mock';
import { referendaEntries } from '../test-helpers/mock/data/referendaEntries';
import fetchOnGoingReferenda21275366Response from '../test-helpers/responses/pallets/fetchOnGoingReferenda21275366.json';
import { PalletsOnGoingReferendaService } from './PalletsOnGoingReferendaService';

// Mocking APIs for block #13641102
const getHeader13641102 = (_hash: Hash) => Promise.resolve().then(() => mockBlock13641102.header);

const mockHistoricApi13641102 = {
query: {},
registry: polkadotRegistryV9300,
} as unknown as ApiDecoration<'promise'>;

const mockApi13641102 = {
rpc: {
chain: {
getHeader: getHeader13641102,
},
},
at: (_hash: Hash) => mockHistoricApi13641102,
} as unknown as ApiPromise;

// Mock PalletsOnGoingReferendaService instance for block #13641102
const palletsOnGoingReferendaService13641102 = new PalletsOnGoingReferendaService(mockApi13641102);

// Mocking APIs for block #21275366
const getHeader21275366 = (_hash: Hash) => Promise.resolve().then(() => mockBlock21275366.header);
const referendaEntriesAt21275366 = () => Promise.resolve().then(() => referendaEntries());

const mockHistoricApi21275366 = {
registry: polkadotRegistryV1000001,
query: {
referenda: {
referendumInfoFor: {
entries: referendaEntriesAt21275366,
},
},
},
} as unknown as ApiDecoration<'promise'>;

const mockApi21275366 = {
rpc: {
chain: {
getHeader: getHeader21275366,
},
},
at: (_hash: Hash) => mockHistoricApi21275366,
} as unknown as ApiPromise;

// Mock PalletsOnGoingReferendaService instance for block #21275366
const palletsOnGoingReferendaService21275366 = new PalletsOnGoingReferendaService(mockApi21275366);

describe('PalletOnGoingReferendaService', () => {
describe('derivePalletOnGoingReferenda', () => {
it('throws error for block 13641102', async () => {
await expect(
palletsOnGoingReferendaService13641102.derivePalletOnGoingReferenda(blockHash13641102),
).rejects.toStrictEqual(
new Error(`The runtime does not include the module 'api.query.referenda' at this block height: 13641102`),
);
});
it('works for block 21275366 (Polkadot) & returns 7 referendas, 2 of which are runtime upgrades', async () => {
expect(
sanitizeNumbers(await palletsOnGoingReferendaService21275366.derivePalletOnGoingReferenda(blockHash21275366)),
).toStrictEqual(fetchOnGoingReferenda21275366Response);
});
});
});
73 changes: 73 additions & 0 deletions src/services/pallets/PalletsOnGoingReferendaService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2017-2024 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import { BlockHash } from '@polkadot/types/interfaces';

import { IPalletOnGoingReferenda, IReferendaInfo } from '../../types/responses';
import { AbstractService } from '../AbstractService';

export class PalletsOnGoingReferendaService extends AbstractService {
/**
* Fetch all on-going referenda that have track: root (0) and whitelisted (1), along
* with their associated information.
*
* @param hash `BlockHash` to make call at
*/
async derivePalletOnGoingReferenda(hash: BlockHash): Promise<IPalletOnGoingReferenda> {
const { api } = this;
const [historicApi, { number }] = await Promise.all([api.at(hash), api.rpc.chain.getHeader(hash)]);
const referenda: IReferendaInfo[] = [];
if (historicApi.query.referenda) {
const referendaEntries = await historicApi.query.referenda.referendumInfoFor.entries();
for (const referendum of referendaEntries) {
const referendumInfo = referendum[1];
if (referendumInfo.isSome) {
const refUnwrapped = referendumInfo.unwrap();
const refId = referendum[0].toHuman() as string[];
if (
refUnwrapped.type == 'Ongoing' &&
(refUnwrapped.asOngoing.track.toHuman() == '0' || refUnwrapped.asOngoing.track.toHuman() == '1')
) {
const decisionDeposit = refUnwrapped.asOngoing.decisionDeposit.isSome
? refUnwrapped.asOngoing.decisionDeposit.unwrap()
: null;
const enactment = refUnwrapped.asOngoing.enactment;
const submitted = refUnwrapped.asOngoing.submitted;
const deciding = refUnwrapped.asOngoing.deciding.isSome ? refUnwrapped.asOngoing.deciding.unwrap() : null;

const refInfo = { id: refId[0], decisionDeposit, enactment, submitted, deciding };
referenda.push(refInfo);
}
}
}
} else {
throw new Error(
`The runtime does not include the module 'api.query.referenda' at this block height: ${number
.unwrap()
.toString(10)}`,
);
}

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

return {
at,
referenda,
};
}
}
3 changes: 2 additions & 1 deletion src/services/pallets/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2023 Parity Technologies (UK) Ltd.
// Copyright 2017-2024 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
Expand All @@ -22,6 +22,7 @@ export * from './PalletsConstantsService';
export * from './PalletsDispatchablesService';
export * from './PalletsForeignAssetsService';
export * from './PalletsNominationPoolsService';
export * from './PalletsOnGoingReferendaService';
export * from './PalletsPoolAssetsService';
export * from './PalletsStakingProgressService';
export * from './PalletsStakingValidatorsService';
Expand Down
Loading

0 comments on commit 386fbb3

Please sign in to comment.