Skip to content

Commit

Permalink
feature: add balance fetch retry logic (#2028)
Browse files Browse the repository at this point in the history
* Adds RPC retry logic

* small refactor in balancesActions.js
  • Loading branch information
comountainclimber committed Nov 29, 2020
1 parent 930dfe8 commit b3c7a27
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 50 deletions.
112 changes: 66 additions & 46 deletions app/actions/balancesActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ const MAX_SCRIPT_HASH_CHUNK_SIZE = 3
type Props = {
net: string,
address: string,
tokens: Array<TokenItemType>,
tokens?: Array<TokenItemType>,
isRetry?: boolean,
}

let inMemoryBalances = {}
Expand Down Expand Up @@ -72,14 +73,16 @@ function determineIfBalanceUpdated(
})
}

async function getBalances({ net, address }: Props) {
let RETRY_COUNT = 0

async function getBalances({ net, address, isRetry = false }: Props) {
const { soundEnabled, tokens } = (await getSettings()) || {
tokens: [],
soundEnabled: true,
}
const network = findNetworkByDeprecatedLabel(net)

let endpoint = await getNode(net)
let endpoint = await getNode(net, isRetry)
if (!endpoint) {
endpoint = await getRPCEndpoint(net)
}
Expand Down Expand Up @@ -113,48 +116,63 @@ async function getBalances({ net, address }: Props) {
return accum
}, [])

const promiseMap = chunks.map(async chunk => {
// NOTE: because the RPC nodes will respond with the contract
// symbol name, we need to use our original token list
// in case two tokens have the same symbol (SWTH vs SWTH OLD)
const balanceResults = await api.nep5.getTokenBalances(
endpoint,
chunk.map(({ scriptHash }) => scriptHash),
address,
)
const hashBasedBalance = {}
let shouldRetry = false
const results = await Promise.all(
chunks.map(async chunk => {
// NOTE: because the RPC nodes will respond with the contract
// symbol name, we need to use our original token list
// in case two tokens have the same symbol (SWTH vs SWTH OLD)
const balanceResults = await api.nep5
.getTokenBalances(
endpoint,
chunk.map(({ scriptHash }) => scriptHash),
address,
)
.catch(e => Promise.reject(e))

chunk.forEach((token, i) => {
hashBasedBalance[token.symbol] = Object.values(balanceResults)[i]
})
return hashBasedBalance
})
const hashBasedBalance = {}

const results = await Promise.all(promiseMap)
chunk.forEach((token, i) => {
hashBasedBalance[token.symbol] = Object.values(balanceResults)[i]
})
return hashBasedBalance
}),
).catch(() => {
console.error(
`An error occurred fetching token balances using: ${endpoint} attempting to use a new RPC node.`,
)
shouldRetry = true
})
if (shouldRetry && RETRY_COUNT < 4) {
RETRY_COUNT += 1
return getBalances({ net, address, isRetry: true })
}

const parsedTokenBalances = results.reduce((accum, currBalance) => {
Object.keys(currBalance).forEach(key => {
const foundToken = tokens.find(token => token.symbol === key)
if (foundToken && currBalance[key]) {
determineIfBalanceUpdated(
const parsedTokenBalances =
results &&
results.reduce((accum, currBalance) => {
Object.keys(currBalance).forEach(key => {
const foundToken = tokens.find(token => token.symbol === key)
if (foundToken && currBalance[key]) {
determineIfBalanceUpdated(
// $FlowFixMe
{ [foundToken.symbol]: currBalance[key] },
soundEnabled,
networkHasChanged,
adressHasChanged,
)
// $FlowFixMe
{ [foundToken.symbol]: currBalance[key] },
soundEnabled,
networkHasChanged,
adressHasChanged,
)
// $FlowFixMe
inMemoryBalances[foundToken.symbol] = currBalance[key]
accum.push({
[foundToken.scriptHash]: {
...foundToken,
balance: currBalance[key],
},
})
}
})
return accum
}, [])
inMemoryBalances[foundToken.symbol] = currBalance[key]
accum.push({
[foundToken.scriptHash]: {
...foundToken,
balance: currBalance[key],
},
})
}
})
return accum
}, [])

// Handle manually added script hashses here
const userGeneratedTokenInfo = []
Expand Down Expand Up @@ -185,11 +203,13 @@ async function getBalances({ net, address }: Props) {
adressHasChanged,
)
inMemoryBalances[token.symbol] = token.balance
parsedTokenBalances.push({
[token.scriptHash]: {
...token,
},
})
if (parsedTokenBalances) {
parsedTokenBalances.push({
[token.scriptHash]: {
...token,
},
})
}
})

// asset balances
Expand Down
16 changes: 12 additions & 4 deletions app/actions/nodeStorageActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,18 @@ export const getRPCEndpoint = async (
}
}

export const getNode = async (net: Net): Promise<string> => {
const setNode = async (node: string, net: Net): Promise<string> =>
setStorage(`${STORAGE_KEY}-${net}`, { node, timestamp: new Date().getTime() })

export const getNode = async (
net: Net,
errorOccurred?: boolean,
): Promise<string> => {
if (errorOccurred) {
delete cachedRPCUrl[net]
await setNode('', net)
return ''
}
const storage = await getStorage(`${STORAGE_KEY}-${net}`).catch(console.error)
const nodeInStorage = get(storage, 'node')
const expiration = get(storage, 'timestamp')
Expand All @@ -132,9 +143,6 @@ export const getNode = async (net: Net): Promise<string> => {
return nodeInStorage
}
const setNode = async (node: string, net: Net): Promise<string> =>
setStorage(`${STORAGE_KEY}-${net}`, { node, timestamp: new Date().getTime() })
export default createActions(
ID,
({ url, net }: Props = {}) => async (): Promise<string> => {
Expand Down

0 comments on commit b3c7a27

Please sign in to comment.