Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add Kusama chain check in historic blocks #1415

Merged
merged 4 commits into from
Mar 20, 2024
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
12 changes: 7 additions & 5 deletions src/controllers/accounts/AccountsStakingPayoutsController.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 @@ -104,17 +104,19 @@ export default class AccountsStakingPayoutsController extends AbstractController
const earlyErasBlockInfo: IEarlyErasBlockInfo = kusamaEarlyErasBlockInfo;
let hash = await this.getHashFromAt(at);
let apiAt = await this.api.at(hash);
const runtimeInfo = await this.api.rpc.state.getRuntimeVersion(hash);
const isKusama = runtimeInfo.specName.toString().toLowerCase() === 'kusama';
Copy link
Member

@TarikGul TarikGul Mar 20, 2024

Choose a reason for hiding this comment

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

Let's right a variable here that is:

const isKusama = runtimeInfo.specName.toString().toLowerCase() === 'kusama';

This should clean the rest up a bit

Copy link
Contributor

Choose a reason for hiding this comment

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

Beat me to it

const { eraArg, currentEra } = await this.getEraAndHash(apiAt, this.verifyAndCastOr('era', era, undefined));
if (currentEra <= 519 && depth !== undefined) {
if (currentEra <= 519 && depth !== undefined && isKusama) {
throw new InternalServerError('The `depth` query parameter is disabled for eras less than 518.');
} else if (currentEra <= 519 && era !== undefined) {
} else if (currentEra <= 519 && era !== undefined && isKusama) {
throw new InternalServerError('The `era` query parameter is disabled for eras less than 518.');
}
let sanitizedDepth: string | undefined;
if (depth) {
if (depth && isKusama) {
sanitizedDepth = Math.min(Number(depth), currentEra - 518).toString();
}
if (currentEra < 518) {
if (currentEra < 518 && isKusama) {
const eraStartBlock: number = earlyErasBlockInfo[currentEra].start;
hash = await this.getHashFromAt(eraStartBlock.toString());
apiAt = await this.api.at(hash);
Expand Down
58 changes: 33 additions & 25 deletions src/services/accounts/AccountsStakingPayoutsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,14 @@ type KeysAndExposures = [StorageKey<[EraIndex, AccountId]>, PalletStakingExposur
type IErasGeneral = [IAdjustedDeriveEraExposure, PalletStakingEraRewardPoints | EraPoints, Option<BalanceOf>];

/**
* Index of the validator for eras previous to 518
* Index of the validator for eras previous to 518 in Kusama chain.
*/
interface ValidatorIndex {
[x: string]: number;
}
/**
* Adapted AdjustedDeriveEraExposure interface for compatibility with eras
* previous to 518
* previous to 518 in Kusama chain.
*/
interface IAdjustedDeriveEraExposure extends DeriveEraExposure {
validatorIndex?: ValidatorIndex;
Expand Down Expand Up @@ -96,7 +96,7 @@ interface IEraData {

/**
* Block information relevant for compatibility with eras previous
* to 518
* to 518 in Kusama chain.
*/
interface IBlockInfo {
height: string;
Expand Down Expand Up @@ -136,6 +136,16 @@ export class AccountsStakingPayoutsService extends AbstractService {

const sanitizedEra = era < 0 ? 0 : era;

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

// User friendly - we don't error if the user specified era & depth combo <= 0, instead just start at 0
const startEra = Math.max(0, sanitizedEra - (depth - 1));
const runtimeInfo = await this.api.rpc.state.getRuntimeVersion(at.hash);
const isKusama = runtimeInfo.specName.toString().toLowerCase() === 'kusama';

/**
* Given https://github.com/polkadot-js/api/issues/5232,
* polkadot-js, and substrate treats historyDepth as a consts. In order
Expand All @@ -147,7 +157,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
historyDepth = historicApi.consts.staking.historyDepth;
} else if (historicApi.query.staking.historyDepth) {
historyDepth = await historicApi.query.staking.historyDepth<u32>();
} else if (currentEra < 518) {
} else if (currentEra < 518 && isKusama) {
historyDepth = api.registry.createType('u32', 0);
}

Expand All @@ -164,16 +174,8 @@ export class AccountsStakingPayoutsService extends AbstractService {
);
}

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

// User friendly - we don't error if the user specified era & depth combo <= 0, instead just start at 0
const startEra = Math.max(0, sanitizedEra - (depth - 1));

// Fetch general data about the era
const allErasGeneral = await this.fetchAllErasGeneral(historicApi, startEra, sanitizedEra, at);
const allErasGeneral = await this.fetchAllErasGeneral(historicApi, startEra, sanitizedEra, at, isKusama);

// With the general data, we can now fetch the commission of each validator `address` nominates
const allErasCommissions = await this.fetchAllErasCommissions(
Expand All @@ -182,6 +184,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
startEra,
// Create an array of `DeriveEraExposure`
allErasGeneral.map((eraGeneral) => eraGeneral[0]),
isKusama,
).catch((err: Error) => {
throw this.createHttpErrorForAddr(address, err);
});
Expand Down Expand Up @@ -214,7 +217,7 @@ export class AccountsStakingPayoutsService extends AbstractService {

return {
at,
erasPayouts: allEraData.map((eraData) => this.deriveEraPayouts(address, unclaimedOnly, eraData)),
erasPayouts: allEraData.map((eraData) => this.deriveEraPayouts(address, unclaimedOnly, eraData, isKusama)),
};
}

Expand All @@ -231,11 +234,11 @@ export class AccountsStakingPayoutsService extends AbstractService {
startEra: number,
era: number,
blockNumber: IBlockInfo,
isKusama: boolean,
): Promise<IErasGeneral[]> {
const allDeriveQuerys: Promise<IErasGeneral>[] = [];
let nextEraStartBlock: number = Number(blockNumber.height);
let eraDurationInBlocks: number = 0;
const runtimeInfo = await this.api.rpc.state.getRuntimeVersion(blockNumber.hash);
const earlyErasBlockInfo: IEarlyErasBlockInfo = kusamaEarlyErasBlockInfo;
for (let e = startEra; e <= era; e += 1) {
const eraIndex = historicApi.registry.createType('EraIndex', e);
Expand All @@ -250,7 +253,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
} else {
// We check if we are in the Kusama chain since currently we have
// the block info for the early eras only for Kusama.
if (runtimeInfo.specName.toString() === 'kusama') {
if (isKusama) {
// Retrieve the first block of the era following the given era in order
// to fetch the `Rewards` event at that block.
nextEraStartBlock = era === 0 ? earlyErasBlockInfo[era + 1].start : earlyErasBlockInfo[era].start;
Expand Down Expand Up @@ -286,7 +289,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
const rewardPromise: Promise<Option<u128>> = new Promise<Option<u128>>((resolve) => {
resolve(reward);
});
if (runtimeInfo.specName.toString() !== 'kusama') {
if (!isKusama) {
nextEraStartBlock = nextEraStartBlock - eraDurationInBlocks;
}

Expand Down Expand Up @@ -316,6 +319,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
address: string,
startEra: number,
deriveErasExposures: IAdjustedDeriveEraExposure[],
isKusama: boolean,
): Promise<ICommissionAndLedger[][]> {
// Cache StakingLedger to reduce redundant queries to node
const validatorLedgerCache: { [id: string]: PalletStakingStakingLedger } = {};
Expand All @@ -330,7 +334,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
}

const singleEraCommissions = nominatedExposures.map(({ validatorId }) =>
this.fetchCommissionAndLedger(historicApi, validatorId, currEra, validatorLedgerCache),
this.fetchCommissionAndLedger(historicApi, validatorId, currEra, validatorLedgerCache, isKusama),
);

return Promise.all(singleEraCommissions);
Expand All @@ -350,6 +354,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
address: string,
unclaimedOnly: boolean,
{ deriveEraExposure, eraRewardPoints, erasValidatorRewardOption, exposuresWithCommission, eraIndex }: IEraData,
isKusama: boolean,
): IEraPayouts | { message: string } {
if (!exposuresWithCommission) {
return {
Expand Down Expand Up @@ -408,7 +413,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
} else {
continue;
}
} else if (eraIndex.toNumber() < 518) {
} else if (eraIndex.toNumber() < 518 && isKusama) {
indexOfEra = eraIndex.toNumber();
} else {
continue;
Expand Down Expand Up @@ -458,6 +463,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
validatorId: string,
era: number,
validatorLedgerCache: { [id: string]: PalletStakingStakingLedger },
isKusama: boolean,
): Promise<ICommissionAndLedger> {
let commission: Perbill;
let validatorLedger;
Expand All @@ -474,18 +480,20 @@ export class AccountsStakingPayoutsService extends AbstractService {
commission = (prefs[0] as PalletStakingValidatorPrefs | ValidatorPrefsWithCommission).commission.unwrap();
}
} else {
commissionPromise = ancient
? historicApi.query.staking.validators(validatorId)
: historicApi.query.staking.erasValidatorPrefs(era, validatorId);
commissionPromise =
ancient && isKusama
? historicApi.query.staking.validators(validatorId)
: historicApi.query.staking.erasValidatorPrefs(era, validatorId);

const [prefs, validatorControllerOption] = await Promise.all([
commissionPromise,
historicApi.query.staking.bonded(validatorId),
]);

commission = ancient
? (prefs[0] as PalletStakingValidatorPrefs | ValidatorPrefsWithCommission).commission.unwrap()
: prefs.commission.unwrap();
commission =
ancient && isKusama
? (prefs[0] as PalletStakingValidatorPrefs | ValidatorPrefsWithCommission).commission.unwrap()
: prefs.commission.unwrap();

if (validatorControllerOption.isNone) {
return {
Expand Down
Loading