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

Executive supporters batch requests + mobile delegate names #807

Merged
merged 4 commits into from
Jul 21, 2023
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
14 changes: 10 additions & 4 deletions modules/address/components/AddressIconBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { useWeb3 } from 'modules/web3/hooks/useWeb3';
import { useAccount } from 'modules/app/hooks/useAccount';
import { useSingleDelegateInfo } from 'modules/delegates/hooks/useSingleDelegateInfo';
import { useVoteProxyAddress } from 'modules/app/hooks/useVoteProxyAddress';
import { limitString } from 'lib/string';
import EtherscanLink from 'modules/web3/components/EtherscanLink';
import splitDelegateName from 'modules/delegates/helpers/splitDelegateName';

type PropTypes = {
address: string;
Expand Down Expand Up @@ -74,9 +74,15 @@ export default function AddressIconBox({
<Flex sx={{ flexDirection: ['column', 'row'] }}>
<Flex sx={{ alignItems: 'center' }}>
{delegate ? (
<Text>
{limitTextLength ? limitString(delegate.name, limitTextLength, '...') : delegate.name}
</Text>
limitTextLength ? (
<Flex sx={{ flexDirection: 'column' }}>
{splitDelegateName(delegate.name, limitTextLength).map((name, i) => (
<Text key={delegate.name + '-' + i}>{name}</Text>
))}
</Flex>
) : (
<Text>{delegate.name}</Text>
)
) : (
<Text>
<Address address={address} maxLength={limitTextLength} />
Expand Down
15 changes: 15 additions & 0 deletions modules/delegates/helpers/splitDelegateName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*

SPDX-FileCopyrightText: © 2023 Dai Foundation <www.daifoundation.org>

SPDX-License-Identifier: AGPL-3.0-or-later

*/

import { limitString } from 'lib/string';

// Splits an Aligned Delegate name into two strings: one for the AVC name and one
// for the actual delegate name, useful when displaying the name in small screens
export default function splitDelegateName(delegateName: string, limitTextLength: number): string[] {
return delegateName.split(' - ').map(name => limitString(name, limitTextLength, '...'));
}
69 changes: 45 additions & 24 deletions modules/executive/api/fetchExecutiveVoteTally.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ import { getChiefDeposits } from 'modules/web3/api/getChiefDeposits';
import { getSlateAddresses } from '../helpers/getSlateAddresses';
import { formatValue } from 'lib/string';
import { paddedBytes32ToAddress } from 'lib/utils';
import { BigNumber } from 'ethers';

type AddressWithVotes = {
votes: string[];
slate: string;
address: string;
deposits: BigNumber;
};

export async function fetchExecutiveVoteTally(chief: Chief): Promise<any | null> {
const filter = {
Expand All @@ -32,36 +40,49 @@ export async function fetchExecutiveVoteTally(chief: Chief): Promise<any | null>
}
});

const withDeposits = await Promise.all(
voters.map(voter =>
getChiefDeposits(voter, chief).then(deposits => ({
address: voter,
deposits
}))
)
// We need to split the voters array into chunks of 1000 addresses because our
// Alchemy key doesn't support batch requests larger than 1000 queries each
const chunkSize = 1000;
const voterChunks = Array.from({ length: Math.ceil(voters.length / chunkSize) }, (_, i) =>
voters.slice(i * chunkSize, i * chunkSize + chunkSize)
);
Comment on lines +45 to 48

Choose a reason for hiding this comment

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

Nice work, one thing I'm curious about though is how the JsonRpcBatchProvider handles batching on it's end. From what I understand, the provider just continuously adds batched requests to it's internal cache and executes them with a 10ms delay.

If that's the case I wonder how the chunking here is actually working. But maybe it's because each loop of our chunk creates a new pendingBatch in the provider as seen here.

In any case it does seem to be working, so that's great


const withSlates = await Promise.all(
withDeposits.map(addressDeposit =>
chief.votes(addressDeposit.address).then(slate => ({
...addressDeposit,
slate
}))
)
);
const addressesWithVotes: AddressWithVotes[] = [];

const withVotes = await Promise.all(
withSlates.map(withSlate =>
getSlateAddresses(chief, withSlate.slate).then(addresses => ({
...withSlate,
votes: addresses
}))
)
);
for (const chunk of voterChunks) {
const withDeposits = await Promise.all(
chunk.map(voter =>
getChiefDeposits(voter, chief).then(deposits => ({
address: voter,
deposits
}))
)
);

const withSlates = await Promise.all(
withDeposits.map(addressDeposit =>
chief.votes(addressDeposit.address).then(slate => ({
...addressDeposit,
slate
}))
)
);

const withVotes = await Promise.all(
withSlates.map(withSlate =>
getSlateAddresses(chief, withSlate.slate).then(addresses => ({
...withSlate,
votes: addresses
}))
)
);

addressesWithVotes.push(...withVotes);
}

const voteTally = {};

for (const voteObj of withVotes) {
for (const voteObj of addressesWithVotes) {
for (let vote of voteObj.votes) {
vote = vote.toLowerCase();
if (voteTally[vote] === undefined) {
Expand Down