Skip to content
This repository was archived by the owner on Feb 23, 2021. It is now read-only.

Commit b097170

Browse files
authored
Merge pull request #565 from lightninglabs/poll-wallet-balance
Poll wallet balance
2 parents 191d2d5 + 5b04c6e commit b097170

File tree

19 files changed

+209
-138
lines changed

19 files changed

+209
-138
lines changed

src/action/channel.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ import { toSatoshis, parseSat } from '../helper';
77
import * as log from './log';
88

99
class ChannelAction {
10-
constructor(store, grpc, transaction, nav, notification) {
10+
constructor(store, grpc, nav, notification) {
1111
this._store = store;
1212
this._grpc = grpc;
13-
this._transaction = transaction;
1413
this._nav = nav;
1514
this._notification = notification;
1615
}
@@ -84,7 +83,6 @@ class ChannelAction {
8483
this.getPeers(),
8584
this.getChannels(),
8685
this.getPendingChannels(),
87-
this._transaction.update(),
8886
]);
8987
}
9088

src/action/index.js

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,10 @@ export const grpc = new GrpcAction(store, ipc);
3636
export const notify = new NotificationAction(store, nav);
3737
export const wallet = new WalletAction(store, grpc, db, nav, notify);
3838
export const info = new InfoAction(store, grpc, nav, notify);
39-
export const transaction = new TransactionAction(store, grpc, wallet, nav);
40-
export const channel = new ChannelAction(store, grpc, transaction, nav, notify);
41-
export const invoice = new InvoiceAction(
42-
store,
43-
grpc,
44-
transaction,
45-
nav,
46-
notify,
47-
Clipboard
48-
);
49-
export const payment = new PaymentAction(store, grpc, transaction, nav, notify);
39+
export const transaction = new TransactionAction(store, grpc, nav);
40+
export const channel = new ChannelAction(store, grpc, nav, notify);
41+
export const invoice = new InvoiceAction(store, grpc, nav, notify, Clipboard);
42+
export const payment = new PaymentAction(store, grpc, nav, notify);
5043
export const setting = new SettingAction(store, wallet, db, ipc);
5144

5245
payment.listenForUrl(ipc); // enable incoming url handler
@@ -94,11 +87,22 @@ observe(store, 'walletUnlocked', async () => {
9487
* to and from lnd can be done. The display the current state of the
9588
* lnd node all balances, channels and transactions are fetched.
9689
*/
97-
observe(store, 'lndReady', () => {
98-
info.getInfo();
99-
wallet.update();
90+
observe(store, 'lndReady', async () => {
91+
// TODO: this is a workaround the deadlock bug in lnd that blocks
92+
// calling NewAddress while netrino is syncing.
93+
if (store.firstStart) {
94+
// only fetch address before neutrino sync on first start
95+
wallet.getNewAddress();
96+
}
97+
wallet.pollBalances();
98+
wallet.pollExchangeRate();
10099
channel.update();
101100
transaction.update();
102101
transaction.subscribeTransactions();
103102
transaction.subscribeInvoices();
103+
await info.pollInfo();
104+
if (!store.firstStart) {
105+
// wait until neutrino is synced on second start
106+
wallet.getNewAddress();
107+
}
104108
});

src/action/info.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
* the current block height.
55
*/
66

7-
import { RETRY_DELAY } from '../config';
87
import { observe } from 'mobx';
8+
import { poll } from '../helper';
99
import * as log from './log';
1010

1111
class InfoAction {
@@ -35,14 +35,21 @@ class InfoAction {
3535
this._notification.display({ msg: 'Syncing to chain', wait: true });
3636
log.info(`Syncing to chain ... block height: ${response.block_height}`);
3737
this._store.percentSynced = this.calcPercentSynced(response);
38-
clearTimeout(this.t3);
39-
this.t3 = setTimeout(() => this.getInfo(), RETRY_DELAY);
4038
}
39+
return response.synced_to_chain;
4140
} catch (err) {
4241
log.error('Getting node info failed', err);
4342
}
4443
}
4544

45+
/**
46+
* Poll the getInfo api until synced_to_chain is true.
47+
* @return {Promise<undefined>}
48+
*/
49+
async pollInfo() {
50+
await poll(() => this.getInfo());
51+
}
52+
4653
/**
4754
* A navigation helper called during the app onboarding process. The loader
4855
* screen indicating the syncing progress in displayed until syncing has

src/action/invoice.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ import { PREFIX_URI } from '../config';
77
import { toSatoshis } from '../helper';
88

99
class InvoiceAction {
10-
constructor(store, grpc, transaction, nav, notification, clipboard) {
10+
constructor(store, grpc, nav, notification, clipboard) {
1111
this._store = store;
1212
this._grpc = grpc;
13-
this._transaction = transaction;
1413
this._nav = nav;
1514
this._notification = notification;
1615
this._clipboard = clipboard;
@@ -70,7 +69,6 @@ class InvoiceAction {
7069
} catch (err) {
7170
this._notification.display({ msg: 'Creating invoice failed!', err });
7271
}
73-
await this._transaction.update();
7472
}
7573

7674
/**

src/action/payment.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ import {
1515
import * as log from './log';
1616

1717
class PaymentAction {
18-
constructor(store, grpc, transaction, nav, notification) {
18+
constructor(store, grpc, nav, notification) {
1919
this._store = store;
2020
this._grpc = grpc;
21-
this._transaction = transaction;
2221
this._nav = nav;
2322
this._notification = notification;
2423
}
@@ -161,7 +160,6 @@ class PaymentAction {
161160
} catch (err) {
162161
this._notification.display({ msg: 'Sending transaction failed!', err });
163162
}
164-
await this._transaction.update();
165163
}
166164

167165
/**
@@ -192,7 +190,6 @@ class PaymentAction {
192190
this._nav.goPayLightningConfirm();
193191
this._notification.display({ msg: 'Lightning payment failed!', err });
194192
}
195-
await this._transaction.update();
196193
}
197194
}
198195

src/action/transaction.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ import * as log from './log';
77
import { parseDate, parseSat, toHex } from '../helper';
88

99
class TransactionAction {
10-
constructor(store, grpc, wallet, nav) {
10+
constructor(store, grpc, nav) {
1111
this._store = store;
1212
this._grpc = grpc;
13-
this._wallet = wallet;
1413
this._nav = nav;
1514
}
1615

@@ -37,17 +36,15 @@ class TransactionAction {
3736
}
3837

3938
/**
40-
* Update the on-chain transactions, invoice, lighting payments, and wallet
41-
* balances in the app state by querying all required grpc apis.
39+
* Update the on-chain transactions, invoice, and lighting payments in the
40+
* app state by querying all required grpc apis.
4241
* @return {Promise<undefined>}
4342
*/
4443
async update() {
4544
await Promise.all([
4645
this.getTransactions(),
4746
this.getInvoices(),
4847
this.getPayments(),
49-
this._wallet.getBalance(),
50-
this._wallet.getChannelBalance(),
5148
]);
5249
}
5350

src/action/wallet.js

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { observe, when } from 'mobx';
7-
import { toBuffer, parseSat, checkHttpStatus, nap } from '../helper';
7+
import { toBuffer, parseSat, checkHttpStatus, nap, poll } from '../helper';
88
import { MIN_PASSWORD_LENGTH, NOTIFICATION_DELAY, RATE_DELAY } from '../config';
99
import * as log from './log';
1010

@@ -105,17 +105,20 @@ class WalletAction {
105105
}
106106

107107
/**
108-
* Update the wallet on-chain balance, channel balance, wallet address
109-
* and fiat/btc exchange rate.
108+
* Update the wallet on-chain and channel balances.
110109
* @return {Promise<undefined>}
111110
*/
112111
async update() {
113-
await Promise.all([
114-
this.getBalance(),
115-
this.getChannelBalance(),
116-
this.getNewAddress(),
117-
this.pollExchangeRate(),
118-
]);
112+
await Promise.all([this.getBalance(), this.getChannelBalance()]);
113+
}
114+
115+
/**
116+
* Poll the wallet balances in the background since there is no streaming
117+
* grpc api yet
118+
* @return {Promise<undefined>}
119+
*/
120+
async pollBalances() {
121+
await poll(() => this.update());
119122
}
120123

121124
/**
@@ -306,9 +309,7 @@ class WalletAction {
306309
* @return {Promise<undefined>}
307310
*/
308311
async pollExchangeRate() {
309-
await this.getExchangeRate();
310-
clearTimeout(this.tPollRate);
311-
this.tPollRate = setTimeout(() => this.pollExchangeRate(), RATE_DELAY);
312+
await poll(() => this.getExchangeRate(), RATE_DELAY);
312313
}
313314

314315
/**

src/config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @fileOverview this file is used to hardcode default settings for the app.
33
*/
44

5-
module.exports.RETRY_DELAY = 3000;
5+
module.exports.RETRY_DELAY = 1000;
66
module.exports.LND_INIT_DELAY = 5000;
77
module.exports.NOTIFICATION_DELAY = 5000;
88
module.exports.RATE_DELAY = 15 * 60 * 1000;

src/helper.js

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @fileOverview helper and utility functions that can be reused go here.
33
*/
44

5-
import { UNITS, LND_INIT_DELAY } from './config';
5+
import { UNITS, LND_INIT_DELAY, RETRY_DELAY } from './config';
66

77
/**
88
* Format a number value in locale format with either . or ,
@@ -252,3 +252,42 @@ export const checkHttpStatus = response => {
252252
export const nap = (ms = LND_INIT_DELAY) => {
253253
return new Promise(resolve => setTimeout(resolve, ms));
254254
};
255+
256+
/**
257+
* A polling utility that can be used to poll apis. If the api returns
258+
* a truthy value this utility will stop polling. Errors thrown by the
259+
* api are just thrown up to the caller to handle.
260+
* @param {Function} api The api wrapped in an asynchronous function
261+
* @param {number} interval The time interval to wait between polls
262+
* @param {number} retries The number of retries to poll the api
263+
* @return {Promise<Object>} The return value of the api
264+
*/
265+
export const poll = async (api, interval = RETRY_DELAY, retries = Infinity) => {
266+
while (retries--) {
267+
const response = await api();
268+
if (response) return response;
269+
await nap(interval);
270+
}
271+
throw new Error('Maximum retries for polling reached');
272+
};
273+
274+
/**
275+
* A retry utility that can be used to try multiple requests to an api. This
276+
* utility will resolve with the return value if the api resolves. Errors
277+
* thrown by the api are swallowed by this utility and another retry is triggered.
278+
* @param {Function} api The api wrapped in an asynchronous function
279+
* @param {number} interval The time interval to wait between retries
280+
* @param {number} retries The number of retries to be sent to the api
281+
* @return {Promise<Object>} The return value of the api
282+
*/
283+
export const retry = async (api, interval = 100, retries = 1000) => {
284+
while (retries--) {
285+
try {
286+
return await api();
287+
} catch (err) {
288+
if (!retries) throw err;
289+
}
290+
await nap(interval);
291+
}
292+
return null;
293+
};

stories/screen-story.js

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,15 @@ sinon.stub(wallet, 'checkSeed');
6565
sinon.stub(wallet, 'checkNewPassword');
6666
sinon.stub(wallet, 'checkPassword');
6767
sinon.stub(wallet, 'getExchangeRate');
68-
const transaction = new TransactionAction(store, grpc, wallet, nav);
68+
const transaction = new TransactionAction(store, grpc, nav);
6969
sinon.stub(transaction, 'update');
70-
const invoice = new InvoiceAction(
71-
store,
72-
grpc,
73-
transaction,
74-
nav,
75-
notify,
76-
Clipboard
77-
);
70+
const invoice = new InvoiceAction(store, grpc, nav, notify, Clipboard);
7871
sinon.stub(invoice, 'generateUri');
79-
const payment = new PaymentAction(store, grpc, transaction, nav, notify);
72+
const payment = new PaymentAction(store, grpc, nav, notify);
8073
sinon.stub(payment, 'checkType');
8174
sinon.stub(payment, 'payBitcoin');
8275
sinon.stub(payment, 'payLightning');
83-
const channel = new ChannelAction(store, grpc, transaction, nav, notify);
76+
const channel = new ChannelAction(store, grpc, nav, notify);
8477
sinon.stub(channel, 'update');
8578
sinon.stub(channel, 'connectAndOpen');
8679
sinon.stub(channel, 'closeSelectedChannel');

0 commit comments

Comments
 (0)