feat(governance): validator tables refocused on stake (#3780)

This commit is contained in:
Sam Keen 2023-05-17 14:14:23 +01:00 committed by GitHub
parent c0320c2468
commit 7b8d9dc94b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 67 deletions

View File

@ -131,20 +131,25 @@ export const ConsensusValidatorsTable = ({
const gridRef = useRef<AgGridReact | null>(null); const gridRef = useRef<AgGridReact | null>(null);
const thirdOfTotalStake = useMemo(
() => new BigNumber(totalStake).dividedBy(3),
[totalStake]
);
const nodes = useMemo(() => { const nodes = useMemo(() => {
if (!data) return []; if (!data) return [];
let canonisedNodes = data let canonisedNodes = data
.sort((a, b) => { .sort((a, b) => {
const aVotingPower = new BigNumber(a.rankingScore.votingPower); const aStakedTotal = new BigNumber(a.stakedTotal);
const bVotingPower = new BigNumber(b.rankingScore.votingPower); const bStakedTotal = new BigNumber(b.stakedTotal);
return bVotingPower.minus(aVotingPower).toNumber(); return bStakedTotal.minus(aStakedTotal).toNumber();
}) })
.map((node, index) => { .map((node, index) => {
const votingPowerRanking = index + 1; const stakedTotalRanking = index + 1;
return { return {
...node, ...node,
votingPowerRanking, stakedTotalRanking,
}; };
}) })
.map( .map(
@ -157,7 +162,7 @@ export const ConsensusValidatorsTable = ({
stakedTotal, stakedTotal,
rankingScore: { stakeScore, votingPower }, rankingScore: { stakeScore, votingPower },
pendingStake, pendingStake,
votingPowerRanking, stakedTotalRanking,
stakedByUser, stakedByUser,
pendingUserStake, pendingUserStake,
userStakeShare, userStakeShare,
@ -175,7 +180,7 @@ export const ConsensusValidatorsTable = ({
return { return {
id, id,
[ValidatorFields.RANKING_INDEX]: votingPowerRanking, [ValidatorFields.RANKING_INDEX]: stakedTotalRanking,
[ValidatorFields.VALIDATOR]: { [ValidatorFields.VALIDATOR]: {
avatarUrl: logo, avatarUrl: logo,
name, name,
@ -236,16 +241,12 @@ export const ConsensusValidatorsTable = ({
return canonisedNodes; return canonisedNodes;
} }
// The point of identifying and hiding the group that could halt the network
// is that we assume the top 1/3 of stake is held by considerably less than
// 1/3 of the validators and we really want people not to stake any more to
// that group, because we want to make it require as many difference
// validators to collude as possible to halt the network, so we hide them.
const { topThird, remaining } = canonisedNodes.reduce( const { topThird, remaining } = canonisedNodes.reduce(
(acc, node) => { (acc, node) => {
if (acc.cumulativeScore < 100 / 3) { if (acc.cumulativeScore.isLessThan(thirdOfTotalStake)) {
acc.cumulativeScore += parseFloat( const prev = acc.cumulativeScore;
node[ValidatorFields.NORMALISED_VOTING_POWER] acc.cumulativeScore = prev.plus(
new BigNumber(node[ValidatorFields.STAKE])
); );
acc.topThird.push(node); acc.topThird.push(node);
return acc; return acc;
@ -253,17 +254,18 @@ export const ConsensusValidatorsTable = ({
acc.remaining.push(node); acc.remaining.push(node);
return acc; return acc;
}, },
{ topThird: [], remaining: [], cumulativeScore: 0 } as { { topThird: [], remaining: [], cumulativeScore: new BigNumber(0) } as {
topThird: CanonisedConsensusNodeProps[]; topThird: CanonisedConsensusNodeProps[];
remaining: CanonisedConsensusNodeProps[]; remaining: CanonisedConsensusNodeProps[];
cumulativeScore: number; cumulativeScore: BigNumber;
} }
); );
// We need to combine the top third of validators into a single node, this // We need to combine the top third of validators into a single node, this
// way the combined values can be passed to AG grid so that the combined cell's // way the combined values can be passed to AG grid so that the combined cell's
// values are correct for ordering. // values are correct for ordering.
const combinedTopThird = topThird.reduce((acc, node) => { const combinedTopThird = topThird.reduce(
(acc, node) => {
const { const {
[ValidatorFields.STAKE]: stake, [ValidatorFields.STAKE]: stake,
[ValidatorFields.STAKE_SHARE]: stakeShare, [ValidatorFields.STAKE_SHARE]: stakeShare,
@ -282,8 +284,8 @@ export const ConsensusValidatorsTable = ({
return { return {
...acc, ...acc,
[ValidatorFields.STAKE]: toBigNum(accStake, decimals) [ValidatorFields.STAKE]: new BigNumber(accStake)
.plus(toBigNum(stake, decimals)) .plus(new BigNumber(stake))
.toString(), .toString(),
[ValidatorFields.STAKE_SHARE]: formatNumberPercentage( [ValidatorFields.STAKE_SHARE]: formatNumberPercentage(
new BigNumber(parseFloat(accStakeShare)).plus( new BigNumber(parseFloat(accStakeShare)).plus(
@ -307,7 +309,15 @@ export const ConsensusValidatorsTable = ({
2 2
), ),
}; };
}); },
{
[ValidatorFields.STAKE]: '0',
[ValidatorFields.STAKE_SHARE]: '0',
[ValidatorFields.PENDING_STAKE]: '0',
[ValidatorFields.NORMALISED_VOTING_POWER]: '0',
[ValidatorFields.TOTAL_PENALTIES]: '0',
}
);
return [ return [
{ {
@ -322,6 +332,7 @@ export const ConsensusValidatorsTable = ({
decimals, decimals,
hideTopThird, hideTopThird,
previousEpochData, previousEpochData,
thirdOfTotalStake,
totalStake, totalStake,
validatorsView, validatorsView,
]); ]);
@ -352,6 +363,7 @@ export const ConsensusValidatorsTable = ({
headerTooltip: t('StakeDescription').toString(), headerTooltip: t('StakeDescription').toString(),
cellRenderer: TotalStakeRenderer, cellRenderer: TotalStakeRenderer,
width: 120, width: 120,
sort: 'desc',
}, },
{ {
field: ValidatorFields.PENDING_STAKE, field: ValidatorFields.PENDING_STAKE,
@ -373,7 +385,6 @@ export const ConsensusValidatorsTable = ({
headerTooltip: t('NormalisedVotingPowerDescription').toString(), headerTooltip: t('NormalisedVotingPowerDescription').toString(),
cellRenderer: VotingPowerRenderer, cellRenderer: VotingPowerRenderer,
width: 200, width: 200,
sort: 'desc',
}, },
{ {
field: ValidatorFields.TOTAL_PENALTIES, field: ValidatorFields.TOTAL_PENALTIES,

View File

@ -57,16 +57,16 @@ export const StandbyPendingValidatorsTable = ({
return data return data
.sort((a, b) => { .sort((a, b) => {
const aVotingPower = new BigNumber(a.rankingScore.votingPower); const aStakedTotal = new BigNumber(a.stakedTotal);
const bVotingPower = new BigNumber(b.rankingScore.votingPower); const bStakedTotal = new BigNumber(b.stakedTotal);
return bVotingPower.minus(aVotingPower).toNumber(); return bStakedTotal.minus(aStakedTotal).toNumber();
}) })
.map((node, index) => { .map((node, index) => {
const votingPowerRanking = index + 1; const stakedTotalRanking = index + 1;
return { return {
...node, ...node,
votingPowerRanking, stakedTotalRanking,
}; };
}) })
.map( .map(
@ -79,7 +79,7 @@ export const StandbyPendingValidatorsTable = ({
stakedTotal, stakedTotal,
rankingScore: { stakeScore }, rankingScore: { stakeScore },
pendingStake, pendingStake,
votingPowerRanking, stakedTotalRanking,
stakedByUser, stakedByUser,
pendingUserStake, pendingUserStake,
userStakeShare, userStakeShare,
@ -125,7 +125,7 @@ export const StandbyPendingValidatorsTable = ({
return { return {
id, id,
[ValidatorFields.RANKING_INDEX]: votingPowerRanking, [ValidatorFields.RANKING_INDEX]: stakedTotalRanking,
[ValidatorFields.VALIDATOR]: { [ValidatorFields.VALIDATOR]: {
avatarUrl, avatarUrl,
name, name,
@ -166,7 +166,7 @@ export const StandbyPendingValidatorsTable = ({
: undefined, : undefined,
[ValidatorFields.PENDING_USER_STAKE]: pendingUserStake, [ValidatorFields.PENDING_USER_STAKE]: pendingUserStake,
[ValidatorFields.USER_STAKE_SHARE]: userStakeShare [ValidatorFields.USER_STAKE_SHARE]: userStakeShare
? formatNumberPercentage(new BigNumber(userStakeShare)) ? formatNumberPercentage(new BigNumber(userStakeShare), 2)
: undefined, : undefined,
}; };
} }
@ -210,6 +210,7 @@ export const StandbyPendingValidatorsTable = ({
headerTooltip: t('StakeDescription').toString(), headerTooltip: t('StakeDescription').toString(),
cellRenderer: TotalStakeRenderer, cellRenderer: TotalStakeRenderer,
width: 120, width: 120,
sort: 'desc',
}, },
{ {
field: ValidatorFields.PENDING_STAKE, field: ValidatorFields.PENDING_STAKE,
@ -233,7 +234,6 @@ export const StandbyPendingValidatorsTable = ({
}), }),
cellRenderer: StakeNeededForPromotionRenderer, cellRenderer: StakeNeededForPromotionRenderer,
width: 210, width: 210,
sort: 'asc',
}, },
{ {
field: ValidatorFields.TOTAL_PENALTIES, field: ValidatorFields.TOTAL_PENALTIES,