Skip to content

Commit 14927eb

Browse files
committed
backend/btc: do not panic when retrieving balance
Similar to 52da637, where the same as done for the transactions list. Fixes one panic TODO. All call sites deal with the error now. An error here is usually a database access for a database that was already closed (e.g. transactions endpoint called at the same time as a bitbox02 is unplugged or the account is closed for some other reason).
1 parent 4fbb3b3 commit 14927eb

File tree

12 files changed

+85
-58
lines changed

12 files changed

+85
-58
lines changed

backend/coins/btc/account.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -544,12 +544,7 @@ func (account *Account) Balance() (*accounts.Balance, error) {
544544
if account.fatalError.Load() {
545545
return nil, errp.New("can't call Balance() after a fatal error")
546546
}
547-
balance, err := account.transactions.Balance()
548-
if err != nil {
549-
// TODO
550-
panic(err)
551-
}
552-
return balance, nil
547+
return account.transactions.Balance()
553548
}
554549

555550
func (account *Account) incAndEmitSyncCounter() {

backend/coins/btc/handlers/handlers.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -326,16 +326,24 @@ func (handlers *Handlers) getUTXOs(_ *http.Request) (interface{}, error) {
326326
}
327327

328328
func (handlers *Handlers) getAccountBalance(_ *http.Request) (interface{}, error) {
329+
var result struct {
330+
Success bool `json:"success"`
331+
HasAvailable bool `json:"hasAvailable"`
332+
Available FormattedAmount `json:"available"`
333+
HasIncoming bool `json:"hasIncoming"`
334+
Incoming FormattedAmount `json:"incoming"`
335+
}
329336
balance, err := handlers.account.Balance()
330337
if err != nil {
331-
return nil, err
338+
handlers.log.WithError(err).Error("Error getting account balance")
339+
return result, nil
332340
}
333-
return map[string]interface{}{
334-
"hasAvailable": balance.Available().BigInt().Sign() > 0,
335-
"available": handlers.formatAmountAsJSON(balance.Available(), false),
336-
"hasIncoming": balance.Incoming().BigInt().Sign() > 0,
337-
"incoming": handlers.formatAmountAsJSON(balance.Incoming(), false),
338-
}, nil
341+
result.Success = true
342+
result.HasAvailable = balance.Available().BigInt().Sign() > 0
343+
result.Available = handlers.formatAmountAsJSON(balance.Available(), false)
344+
result.HasIncoming = balance.Incoming().BigInt().Sign() > 0
345+
result.Incoming = handlers.formatAmountAsJSON(balance.Incoming(), false)
346+
return result, nil
339347
}
340348

341349
type sendTxInput struct {

frontends/web/src/api/account.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
import { apiGet, apiPost } from '../utils/request';
18+
import { SuccessResponse } from './response';
1819
import { ChartData } from '../routes/account/summary/chart';
1920

2021
export type CoinCode = 'btc' | 'tbtc' | 'ltc' | 'tltc' | 'eth' | 'goeth';
@@ -151,7 +152,9 @@ export interface IBalance {
151152
incoming: IAmount;
152153
}
153154

154-
export const getBalance = (code: AccountCode): Promise<IBalance> => {
155+
export type TBalanceResult = { success: false } | (SuccessResponse & IBalance);
156+
157+
export const getBalance = (code: AccountCode): Promise<TBalanceResult> => {
155158
return apiGet(`account/${code}/balance`);
156159
};
157160

frontends/web/src/components/balance/balance.test.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
*/
1616

1717
import { render } from '@testing-library/react';
18-
import { IBalance } from '../../api/account';
18+
import { TBalanceResult } from '../../api/account';
1919
import I18NWrapper from '../../i18n/forTests/i18nwrapper';
2020
import { Balance } from './balance';
2121

2222
describe('components/balance/balance', () => {
2323
it('renders balance properly', () => {
24-
const MOCK_BALANCE: IBalance = {
24+
const MOCK_BALANCE: TBalanceResult = {
25+
success: true,
2526
hasAvailable: true,
2627
hasIncoming: true,
2728
available: {

frontends/web/src/components/balance/balance.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
*/
1717

1818
import { useTranslation } from 'react-i18next';
19-
import { IBalance } from '../../api/account';
19+
import { TBalanceResult } from '../../api/account';
2020
import { FiatConversion } from '../../components/rates/rates';
2121
import { bitcoinRemoveTrailingZeroes } from '../../utils/trailing-zeroes';
2222
import style from './balance.module.css';
2323

2424
type TProps = {
25-
balance?: IBalance;
25+
balance?: TBalanceResult;
2626
noRotateFiat?: boolean;
2727
}
2828

@@ -36,6 +36,11 @@ export const Balance = ({
3636
<header className={style.balance}></header>
3737
);
3838
}
39+
if (!balance.success) {
40+
return (
41+
<header className={style.balance}>{t('account.balanceError')}</header>
42+
);
43+
}
3944

4045
// remove trailing zeroes from Bitcoin balance
4146
const availableBalance = bitcoinRemoveTrailingZeroes(balance.available.amount, balance.available.unit);

frontends/web/src/locales/en/app.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"initializing": "Getting information from the blockchain…",
99
"maybeProxyError": "Tor proxy enabled. Ensure that your Tor proxy is running properly, or disable the proxy setting.",
1010
"reconnecting": "Lost connection, trying to reconnect…",
11-
"syncedAddressesCount": "Scanned {{count}} addresses"
11+
"syncedAddressesCount": "Scanned {{count}} addresses",
12+
"balanceError": "Error retrieving balance"
1213
},
1314
"accountInfo": {
1415
"address": "Address",
@@ -1446,4 +1447,4 @@
14461447
"insertDevice": "Please connect your device to get started",
14471448
"title": "Welcome"
14481449
}
1449-
}
1450+
}

frontends/web/src/routes/account/account.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export function Account({
5454
}: Props) {
5555
const { t } = useTranslation();
5656

57-
const [balance, setBalance] = useState<accountApi.IBalance>();
57+
const [balance, setBalance] = useState<accountApi.TBalanceResult>();
5858
const [status, setStatus] = useState<accountApi.IStatus>();
5959
const [syncedAddressesCount, setSyncedAddressesCount] = useState<number>();
6060
const [transactions, setTransactions] = useState<accountApi.TTransactions>();
@@ -166,7 +166,7 @@ export function Account({
166166
return null;
167167
}
168168

169-
const canSend = balance && balance.hasAvailable;
169+
const canSend = balance && balance.success && balance.hasAvailable;
170170

171171
const initializingSpinnerText =
172172
(syncedAddressesCount !== undefined && syncedAddressesCount > 1) ? (
@@ -188,6 +188,7 @@ export function Account({
188188
const exchangeBuySupported = supportedExchanges && supportedExchanges.exchanges.length > 0;
189189

190190
const isAccountEmpty = balance
191+
&& balance.success
191192
&& !balance.hasAvailable
192193
&& !balance.hasIncoming
193194
&& transactions
@@ -265,10 +266,10 @@ export function Account({
265266
</div>
266267
<AccountGuide
267268
account={account}
268-
unit={balance?.available.unit}
269-
hasIncomingBalance={balance && balance.hasIncoming}
269+
unit={balance?.success ? balance?.available.unit : undefined}
270+
hasIncomingBalance={balance && balance.success && balance.hasIncoming}
270271
hasTransactions={transactions !== undefined && transactions.success && transactions.list.length > 0}
271-
hasNoBalance={balance && balance.available.amount === '0'} />
272+
hasNoBalance={balance && balance.success && balance.available.amount === '0'} />
272273
</div>
273274
);
274275
}

frontends/web/src/routes/account/info/buyReceiveCTA.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616

1717
import { useTranslation } from 'react-i18next';
1818
import { route } from '../../../utils/route';
19-
import { CoinWithSAT, IBalance } from '../../../api/account';
19+
import { CoinWithSAT, TBalanceResult } from '../../../api/account';
2020
import { Button } from '../../../components/forms';
2121
import { Balances } from '../summary/accountssummary';
2222
import styles from './buyReceiveCTA.module.css';
2323
import { isBitcoinCoin } from '../utils';
2424

2525
type TBuyReceiveCTAProps = {
26-
balanceList?: [string, IBalance][];
26+
balanceList?: [string, TBalanceResult][];
2727
code?: string;
2828
unit?: string;
2929
};
@@ -59,10 +59,10 @@ export const AddBuyReceiveOnEmptyBalances = ({ balances }: {balances?: Balances}
5959
return null;
6060
}
6161
const balanceList = Object.entries(balances);
62-
if (balanceList.some(entry => entry[1].hasAvailable)) {
62+
if (balanceList.some(entry => entry[1].success && entry[1].hasAvailable)) {
6363
return null;
6464
}
65-
if (balanceList.map(entry => entry[1].available.unit).every(isBitcoinCoin)) {
65+
if (balanceList.every(entry => entry[1].success && isBitcoinCoin(entry[1].available.unit))) {
6666
return <BuyReceiveCTA code={balanceList[0][0]} unit={'BTC'} balanceList={balanceList} />;
6767
}
6868
return <BuyReceiveCTA balanceList={balanceList} />;

frontends/web/src/routes/account/send/send.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ type Props = SendProps & TranslateProps;
6262

6363
interface State {
6464
account?: accountApi.IAccount;
65-
balance?: accountApi.IBalance;
65+
balance?: accountApi.TBalanceResult;
6666
proposedFee?: accountApi.IAmount;
6767
proposedTotal?: accountApi.IAmount;
6868
recipientAddress: string;
@@ -680,7 +680,7 @@ class Send extends Component<Props, State> {
680680
type="number"
681681
step="any"
682682
min="0"
683-
label={balance ? balance.available.unit : t('send.amount.label')}
683+
label={balance && balance.success ? balance.available.unit : t('send.amount.label')}
684684
id="amount"
685685
onInput={this.handleFormChange}
686686
disabled={sendAll}

frontends/web/src/routes/account/summary/accountssummary.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ interface AccountSummaryProps {
4040
}
4141

4242
export interface Balances {
43-
[code: string]: accountApi.IBalance;
43+
[code: string]: accountApi.TBalanceResult;
4444
}
4545

4646
interface SyncStatus {
@@ -214,12 +214,17 @@ class AccountsSummary extends Component<Props, State> {
214214
{ nameCol }
215215
<td data-label={t('accountSummary.balance')}>
216216
<span className={style.summaryTableBalance}>
217-
{balance.available.amount}{' '}
218-
<span className={style.coinUnit}>{balance.available.unit}</span>
217+
{ balance.success ? (
218+
<>
219+
{balance.available.amount}{' '}
220+
<span className={style.coinUnit}>{balance.available.unit}</span>
221+
</>
222+
) : <>{t('account.balanceError')}</>
223+
}
219224
</span>
220225
</td>
221226
<td data-label={t('accountSummary.fiatBalance')}>
222-
<FiatConversion amount={balance.available} noAction={true} />
227+
{ balance.success && <FiatConversion amount={balance.available} noAction={true} /> }
223228
</td>
224229
</tr>
225230
);

0 commit comments

Comments
 (0)