From 37b171ed99ca3f2e937d88dd4b732eab5711880c Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Thu, 17 Aug 2023 12:44:39 +0200 Subject: [PATCH] wip(import): reload recursively till balance is found --- src/components/App.tsx | 56 +++++++++++++++++++++++++++-------- src/context/WalletContext.tsx | 9 +++--- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index f792f80f3..448d6eb34 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -15,6 +15,7 @@ import { routes } from '../constants/routes' import { useServiceInfo, useSessionConnectionError } from '../context/ServiceInfoContext' import { useSettings } from '../context/SettingsContext' import { + WalletInfo, CurrentWallet, useCurrentWallet, useSetCurrentWallet, @@ -46,7 +47,8 @@ export default function App() { const reloadCurrentWalletInfo = useReloadCurrentWalletInfo() const serviceInfo = useServiceInfo() const sessionConnectionError = useSessionConnectionError() - const [isReloadingWalletInfo, setIsReloadingWalletInfo] = useState(false) + const [reloadingWalletInfoCounter, setReloadingWalletInfoCounter] = useState(0) + const isReloadingWalletInfo = useMemo(() => reloadingWalletInfoCounter > 0, [reloadingWalletInfoCounter]) const startWallet = useCallback( (name: Api.WalletName, token: Api.ApiToken) => { @@ -63,18 +65,18 @@ export default function App() { const reloadWalletInfo = useCallback( (delay: Milliseconds) => { - setIsReloadingWalletInfo(true) + setReloadingWalletInfoCounter((current) => current + 1) console.info('Reloading wallet info...') - return new Promise((resolve, reject) => + return new Promise((resolve, reject) => setTimeout(() => { const abortCtrl = new AbortController() reloadCurrentWalletInfo .reloadAll({ signal: abortCtrl.signal }) - .then((_) => resolve()) + .then((result) => resolve(result)) .catch((error) => reject(error)) .finally(() => { console.info('Finished reloading wallet info.') - setIsReloadingWalletInfo(false) + setReloadingWalletInfoCounter((current) => current - 1) }) }, delay) ) @@ -220,9 +222,11 @@ const RELOAD_WALLET_INFO_DELAY: { AFTER_UNLOCK: 0, } +const MAX_RECURSIVE_WALLET_INFO_RELOADS = 10 + interface WalletInfoAutoReloadProps { currentWallet: CurrentWallet | null - reloadWalletInfo: (delay: Milliseconds) => Promise + reloadWalletInfo: (delay: Milliseconds) => Promise } /** @@ -238,7 +242,7 @@ const WalletInfoAutoReload = ({ currentWallet, reloadWalletInfo }: WalletInfoAut const serviceInfo = useServiceInfo() const [previousRescanning, setPreviousRescanning] = useState(serviceInfo?.rescanning || false) const [currentRescanning, setCurrentRescanning] = useState(serviceInfo?.rescanning || false) - const rescaningFinished = useMemo( + const rescanningFinished = useMemo( () => previousRescanning === true && currentRescanning === false, [previousRescanning, currentRescanning] ) @@ -250,20 +254,46 @@ const WalletInfoAutoReload = ({ currentWallet, reloadWalletInfo }: WalletInfoAut useEffect( function reloadAfterUnlock() { - if (currentWallet) { - reloadWalletInfo(RELOAD_WALLET_INFO_DELAY.AFTER_UNLOCK).catch((err) => console.error(err)) - } + if (!currentWallet) return + + reloadWalletInfo(RELOAD_WALLET_INFO_DELAY.AFTER_UNLOCK).catch((err) => console.error(err)) }, [currentWallet, reloadWalletInfo] ) useEffect( function reloadAfterRescan() { - if (currentWallet && rescaningFinished) { - reloadWalletInfo(RELOAD_WALLET_INFO_DELAY.AFTER_RESCAN).catch((err) => console.error(err)) + if (!currentWallet || !rescanningFinished) return + + // Hacky: If the balance changes after a reload, the backend might still not have been fully synchronized - try again! + // Hint 1: Wallet might be empty in the first + // Hint 2: Just because wallet balance did not change, it does not mean everything has been found. + const reloadWhileBalanceChangesRecursively = async ( + currentBalance: Api.AmountSats, + delay: Milliseconds, + callCounter: number, + maxCalls: number + ) => { + if (callCounter >= maxCalls) return + const info = await reloadWalletInfo(delay) + const newBalance = info.balanceSummary.calculatedTotalBalanceInSats + if (newBalance > currentBalance) { + await reloadWhileBalanceChangesRecursively(newBalance, callCounter++, maxCalls, delay) + } } + + reloadWalletInfo(RELOAD_WALLET_INFO_DELAY.AFTER_RESCAN) + .then((info) => + reloadWhileBalanceChangesRecursively( + info.balanceSummary.calculatedTotalBalanceInSats, + RELOAD_WALLET_INFO_DELAY.AFTER_RESCAN, + 0, + MAX_RECURSIVE_WALLET_INFO_RELOADS + ) + ) + .catch((err) => console.error(err)) }, - [currentWallet, rescaningFinished, reloadWalletInfo] + [currentWallet, rescanningFinished, reloadWalletInfo] ) return <> diff --git a/src/context/WalletContext.tsx b/src/context/WalletContext.tsx index 9c7b5af19..52c92ad10 100644 --- a/src/context/WalletContext.tsx +++ b/src/context/WalletContext.tsx @@ -115,7 +115,7 @@ interface WalletContextEntry { setCurrentWallet: React.Dispatch> currentWalletInfo: WalletInfo | undefined reloadCurrentWalletInfo: { - reloadAll: ({ signal }: { signal: AbortSignal }) => Promise + reloadAll: ({ signal }: { signal: AbortSignal }) => Promise reloadUtxos: ({ signal }: { signal: AbortSignal }) => Promise } } @@ -244,9 +244,10 @@ const WalletProvider = ({ children }: PropsWithChildren) => { ) const reloadAll = useCallback( - async ({ signal }: { signal: AbortSignal }): Promise => { - await Promise.all([reloadUtxos({ signal }), reloadDisplay({ signal })]) - }, + ({ signal }: { signal: AbortSignal }): Promise => + Promise.all([reloadUtxos({ signal }), reloadDisplay({ signal })]) + .then((data) => toCombinedRawData(data[0], data[1])) + .then((raw) => toWalletInfo(raw)), [reloadUtxos, reloadDisplay] )