Skip to content

Commit

Permalink
fix: add Kusama chain check in historic blocks (#1415)
Browse files Browse the repository at this point in the history
* fix: add kusama chain check in historic blocks

* run linter

* applied Tarik's suggestion with 'isKusama' variable

* Update src/controllers/accounts/AccountsStakingPayoutsController.ts

Co-authored-by: Alberto Nicolas Penayo <74352651+bee344@users.noreply.github.com>

---------

Co-authored-by: Alberto Nicolas Penayo <74352651+bee344@users.noreply.github.com>
  • Loading branch information
Imod7 and bee344 committed Mar 20, 2024
1 parent e20f782 commit cfbcddd
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 30 deletions.
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';
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

0 comments on commit cfbcddd

Please sign in to comment.