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

perf: load withdrawal tx history by priority #2128

Merged
merged 28 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 12 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
26 changes: 25 additions & 1 deletion packages/arb-token-bridge-ui/src/token-bridge-sdk/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
getArbitrumNetwork
} from '@arbitrum/sdk'
import { isDepositMode } from '../util/isDepositMode'
import { ConnectionInfo } from 'ethers/lib/utils.js'

export const getAddressFromSigner = async (signer: Signer) => {
const address = await signer.getAddress()
Expand Down Expand Up @@ -104,9 +105,32 @@ const getProviderForChainCache: {
// start with empty cache
}

const THROTTLE_LIMIT = 10

const connection: Omit<ConnectionInfo, 'url'> = {
timeout: 300000,
allowGzip: true,
skipFetchSetup: true,
throttleLimit: THROTTLE_LIMIT,
throttleSlotInterval: 3000,
throttleCallback: async (attempt: number) => {
// Always retry until we hit the THROTTLE_LIMIT
// Otherwise, it only throttles for specific response codes
// Return true to continue retrying, false to stop
return attempt <= THROTTLE_LIMIT
},
headers: {
Accept: '*/*',
'Accept-Encoding': 'gzip, deflate, br'
}
}

function createProviderWithCache(chainId: ChainId) {
const rpcUrl = rpcURLs[chainId]
const provider = new StaticJsonRpcProvider(rpcUrl, chainId)
const provider = new StaticJsonRpcProvider(
{ ...connection, url: rpcUrl! },
chainId
)
getProviderForChainCache[chainId] = provider
return provider
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { Provider, BlockTag } from '@ethersproject/providers'
import { Erc20Bridger, EventArgs } from '@arbitrum/sdk'
import { WithdrawalInitiatedEvent } from '@arbitrum/sdk/dist/lib/abi/L2ArbitrumGateway'

import { getNonce } from '../AddressUtils'

function dedupeEvents(
events: (EventArgs<WithdrawalInitiatedEvent> & {
txHash: string
Expand All @@ -12,6 +10,15 @@ function dedupeEvents(
return [...new Map(events.map(item => [item.txHash, item])).values()]
}

export type FetchTokenWithdrawalsFromEventLogsParams = {
sender?: string
receiver?: string
fromBlock: BlockTag
toBlock: BlockTag
l2Provider: Provider
l2GatewayAddresses?: string[]
}

/**
* Fetches initiated token withdrawals from event logs in range of [fromBlock, toBlock].
*
Expand All @@ -30,22 +37,13 @@ export async function fetchTokenWithdrawalsFromEventLogs({
toBlock,
l2Provider,
l2GatewayAddresses = []
}: {
sender?: string
receiver?: string
fromBlock: BlockTag
toBlock: BlockTag
l2Provider: Provider
l2GatewayAddresses?: string[]
}) {
Comment on lines -33 to -40
Copy link
Member Author

Choose a reason for hiding this comment

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

extracted into type FetchTokenWithdrawalsFromEventLogsParams

}: FetchTokenWithdrawalsFromEventLogsParams) {
const erc20Bridger = await Erc20Bridger.fromProvider(l2Provider)
const promises: ReturnType<Erc20Bridger['getWithdrawalEvents']>[] = []

const senderNonce = await getNonce(sender, { provider: l2Provider })
Copy link
Member Author

Choose a reason for hiding this comment

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

moved to fetchWithdrawals.ts so we do it just once


l2GatewayAddresses.forEach(gatewayAddress => {
// funds sent by this address
if (sender && senderNonce > 0) {
if (sender) {
promises.push(
erc20Bridger.getWithdrawalEvents(
l2Provider,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { constants } from 'ethers'
import { Provider, BlockTag } from '@ethersproject/providers'
import { Erc20Bridger, getArbitrumNetwork } from '@arbitrum/sdk'

import {
fetchTokenWithdrawalsFromEventLogs,
FetchTokenWithdrawalsFromEventLogsParams
} from './fetchTokenWithdrawalsFromEventLogs'
import { getNonce } from '../AddressUtils'

function wait(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms))
}

type WithdrawalQuery = {
params: FetchTokenWithdrawalsFromEventLogsParams
priority: number
}

type UnwrapPromise<T> = T extends Promise<infer U> ? U : T
brtkx marked this conversation as resolved.
Show resolved Hide resolved

type Result = UnwrapPromise<ReturnType<Erc20Bridger['getWithdrawalEvents']>>

export type FetchTokenWithdrawalsFromEventLogsSequentiallyParams = {
sender?: string
receiver?: string
provider: Provider
fromBlock?: BlockTag
toBlock?: BlockTag
}

export async function fetchTokenWithdrawalsFromEventLogsSequentially({
sender,
receiver,
provider,
fromBlock = 0,
toBlock = 'latest'
}: FetchTokenWithdrawalsFromEventLogsSequentiallyParams): Promise<Result> {
await wait(2000)

const network = await getArbitrumNetwork(provider)
const senderNonce = await getNonce(sender, { provider })

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
const standardGateway = network.tokenBridge?.childErc20Gateway!
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
const customGateway = network.tokenBridge?.childCustomGateway!
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
const wethGateway = network.tokenBridge?.childWethGateway!

let prio = 1

const queries: WithdrawalQuery[] = []

if (senderNonce > 0) {
queries.push({
params: {
sender,
fromBlock,
toBlock,
l2Provider: provider,
l2GatewayAddresses: [standardGateway]
},
priority: prio
})
prio++
if (wethGateway !== constants.AddressZero) {
queries.push({
params: {
sender,
fromBlock,
toBlock: 'latest',
l2Provider: provider,
l2GatewayAddresses: [wethGateway]
},
priority: prio
})
prio++
}
queries.push({
params: {
sender,
fromBlock,
toBlock: 'latest',
l2Provider: provider,
l2GatewayAddresses: [customGateway]
},
priority: prio
})
prio++
}

queries.push({
params: {
receiver,
fromBlock,
toBlock: 'latest',
l2Provider: provider,
l2GatewayAddresses: [standardGateway]
},
priority: prio
})
prio++
if (wethGateway !== constants.AddressZero) {
queries.push({
params: {
receiver,
fromBlock,
toBlock: 'latest',
l2Provider: provider,
l2GatewayAddresses: [wethGateway]
},
priority: prio
})
prio++
}
queries.push({
params: {
receiver,
fromBlock,
toBlock: 'latest',
l2Provider: provider,
l2GatewayAddresses: [customGateway]
},
priority: prio
})
prio++

const maxPriority = queries.map(query => query.priority).sort()[
queries.length - 1
]!

const result: Result = []
let currentPriority = 1

while (currentPriority <= maxPriority) {
const filteredQueries = queries.filter(
query => query.priority === currentPriority
)

const results = await Promise.all(
filteredQueries.map(query =>
fetchTokenWithdrawalsFromEventLogs(query.params)
)
)

results.forEach(r => {
result.push(...r)
})

await wait(2000)

currentPriority += 1
}

return result
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import {
fetchWithdrawalsFromSubgraph
} from './fetchWithdrawalsFromSubgraph'
import { fetchLatestSubgraphBlockNumber } from '../SubgraphUtils'
import { fetchTokenWithdrawalsFromEventLogs } from './fetchTokenWithdrawalsFromEventLogs'

import { fetchL2Gateways } from '../fetchL2Gateways'
import { Withdrawal } from '../../hooks/useTransactionHistory'
import { attachTimestampToTokenWithdrawal } from './helpers'
import { WithdrawalInitiated } from '../../hooks/arbTokenBridge.types'
import { fetchTokenWithdrawalsFromEventLogsSequentially } from './fetchTokenWithdrawalsFromEventLogsSequentially'

export type FetchWithdrawalsParams = {
sender?: string
Expand Down Expand Up @@ -43,6 +44,7 @@ export async function fetchWithdrawals({
const l1ChainID = (await l1Provider.getNetwork()).chainId
const l2ChainID = (await l2Provider.getNetwork()).chainId

// todo: use
const l2GatewayAddresses = await fetchL2Gateways(l2Provider)

if (!fromBlock) {
Expand Down Expand Up @@ -93,13 +95,12 @@ export async function fetchWithdrawals({
toBlock: 'latest',
l2Provider: l2Provider
}),
fetchTokenWithdrawalsFromEventLogs({
fetchTokenWithdrawalsFromEventLogsSequentially({
sender,
receiver,
fromBlock: toBlock + 1,
toBlock: 'latest',
l2Provider: l2Provider,
l2GatewayAddresses
provider: l2Provider
})
])

Expand Down
Loading