Skip to content

Commit 122b033

Browse files
refactor: fetchHistory on sagas/nanoContract to avoid iteration suspension (#569)
* refactor: fetchHistory on sagas/nanoContract to avoid iteration suspension * docs: improve docstring
1 parent 2a972d2 commit 122b033

File tree

2 files changed

+40
-39
lines changed

2 files changed

+40
-39
lines changed

src/sagas/nanoContract.js

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import {
2020
} from 'redux-saga/effects';
2121
import { t } from 'ttag';
2222
import { NanoRequest404Error } from '@hathor/wallet-lib/lib/errors';
23+
import { getRegisteredNanoContracts, safeEffect } from './helpers';
24+
import { isWalletServiceEnabled } from './wallet';
2325
import {
2426
nanoContractBlueprintInfoFailure,
2527
nanoContractBlueprintInfoSuccess,
@@ -35,9 +37,7 @@ import {
3537
} from '../actions';
3638
import { logger } from '../logger';
3739
import { NANO_CONTRACT_TX_HISTORY_SIZE } from '../constants';
38-
import { consumeGenerator, getNanoContractFeatureToggle } from '../utils';
39-
import { getRegisteredNanoContracts, safeEffect } from './helpers';
40-
import { isWalletServiceEnabled } from './wallet';
40+
import { getNanoContractFeatureToggle } from '../utils';
4141

4242
const log = logger('nano-contract-saga');
4343

@@ -54,6 +54,25 @@ export const failureMessage = {
5454
nanoContractHistoryFailure: t`Error while trying to download Nano Contract transactions history.`,
5555
};
5656

57+
/**
58+
* Call the async wallet method `isAddressMine` considering the type of wallet.
59+
*
60+
* @param {Object} wallet A wallet instance
61+
* @param {string} address A wallet address to check
62+
* @param {boolean} useWalletService A flag that determines if wallet service is in use
63+
*/
64+
export const isAddressMine = async (wallet, address, useWalletService) => {
65+
// XXX: Wallet Service doesn't implement isAddressMine.
66+
// See issue: https://github.com/HathorNetwork/hathor-wallet-lib/issues/732
67+
// Default to `false` if using Wallet Service.
68+
if (useWalletService) {
69+
return false;
70+
}
71+
72+
const isMine = await wallet.isAddressMine(address);
73+
return isMine;
74+
};
75+
5776
export function* init() {
5877
const isEnabled = yield select(getNanoContractFeatureToggle);
5978
if (!isEnabled) {
@@ -101,13 +120,13 @@ export function* registerNanoContract({ payload }) {
101120
// XXX: Wallet Service doesn't implement isAddressMine.
102121
// See issue: https://github.com/HathorNetwork/hathor-wallet-lib/issues/732
103122
// Default to `false` if using Wallet Service.
104-
let isAddressMine = false;
123+
let isAddrMine = false;
105124
const useWalletService = yield call(isWalletServiceEnabled);
106125
if (!useWalletService) {
107-
isAddressMine = yield call([wallet, wallet.isAddressMine], address);
126+
isAddrMine = yield call([wallet, wallet.isAddressMine], address);
108127
}
109128

110-
if (!isAddressMine) {
129+
if (!isAddrMine) {
111130
log.debug('Fail registering Nano Contract because address do not belongs to this wallet.');
112131
yield put(nanoContractRegisterFailure(failureMessage.addressNotMine));
113132
return;
@@ -158,6 +177,7 @@ export function* registerNanoContract({ payload }) {
158177
// emit action NANOCONTRACT_REGISTER_SUCCESS with feedback to user
159178
yield put(nanoContractRegisterSuccess({ entryKey: ncId, entryValue: nc, hasFeedback: true }));
160179
}
180+
161181
/**
162182
* Effect invoked by safeEffect if an unexpected error occurs.
163183
*
@@ -215,16 +235,18 @@ function* registerNanoContractOnError(error) {
215235
* @param {string} req.before Transaction hash to start to get newer items
216236
* @param {string} req.after Transaction hash to start to get older items
217237
* @param {Object} req.wallet Wallet instance from redux state
238+
* @param {boolean} req.useWalletService A flag that determines if wallet service is in use
218239
*
219240
* @returns {{
220-
* history: {};
241+
* history: NcTxHistory;
221242
* }}
222243
*
223244
* @throws {Error} when request code is greater then 399 or when response's success is false
224245
*/
225246
export async function fetchHistory(req) {
226247
const {
227248
wallet,
249+
useWalletService,
228250
ncId,
229251
count,
230252
after,
@@ -245,28 +267,17 @@ export async function fetchHistory(req) {
245267
throw new Error('Failed to fetch nano contract history');
246268
}
247269

248-
/* TODO: Make it run concurrently while guaranting the order.
249-
/* see https://github.com/HathorNetwork/hathor-wallet-mobile/issues/514
250-
*/
251-
const historyNewestToOldest = new Array(rawHistory.length)
252-
for (let idx = 0; idx < rawHistory.length; idx += 1) {
253-
const rawTx = rawHistory[idx];
254-
const network = wallet.getNetworkObject();
270+
const network = wallet.getNetworkObject();
271+
// Translate rawNcTxHistory to NcTxHistory
272+
// Prouce a list ordered from newest to oldest
273+
const transformedTxHistory = rawHistory.map(async (rawTx) => {
255274
const caller = addressUtils.getAddressFromPubkey(rawTx.nc_pubkey, network).base58;
256-
// XXX: Wallet Service doesn't implement isAddressMine.
257-
// See issue: https://github.com/HathorNetwork/hathor-wallet-lib/issues/732
258-
// Default to `false` if using Wallet Service.
259-
let isMine = false;
260-
const useWalletService = consumeGenerator(isWalletServiceEnabled());
261-
if (!useWalletService) {
262-
// eslint-disable-next-line no-await-in-loop
263-
isMine = await wallet.isAddressMine(caller);
264-
}
265275
const actions = rawTx.nc_context.actions.map((each) => ({
266276
type: each.type, // 'deposit' or 'withdrawal'
267277
uid: each.token_uid,
268278
amount: each.amount,
269279
}));
280+
const isMine = await isAddressMine(wallet, caller, useWalletService);
270281

271282
const tx = {
272283
txId: rawTx.hash,
@@ -278,13 +289,13 @@ export async function fetchHistory(req) {
278289
blueprintId: rawTx.nc_blueprint_id,
279290
firstBlock: rawTx.first_block,
280291
caller,
281-
isMine,
282292
actions,
293+
isMine,
283294
};
284-
historyNewestToOldest[idx] = tx;
285-
}
295+
return tx;
296+
});
286297

287-
return { history: historyNewestToOldest };
298+
return { history: await Promise.all(transformedTxHistory) };
288299
}
289300

290301
/**
@@ -332,9 +343,11 @@ export function* requestHistoryNanoContract({ payload }) {
332343
yield put(nanoContractHistoryClean({ ncId }));
333344
}
334345

346+
const useWalletService = yield select((state) => state.useWalletService);
335347
try {
336348
const req = {
337349
wallet,
350+
useWalletService,
338351
ncId,
339352
before,
340353
after,

src/utils.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -428,18 +428,6 @@ export const getNanoContractFeatureToggle = (state) => (
428428
*/
429429
export const getTimestampFormat = (timestamp) => moment.unix(timestamp).format(t`DD MMM YYYY [•] HH:mm`)
430430

431-
/**
432-
* Extract the result of a generator function when it is done.
433-
*/
434-
export const consumeGenerator = (generator) => {
435-
for (;;) {
436-
const { value, done } = generator.next();
437-
if (done) {
438-
return value;
439-
}
440-
}
441-
}
442-
443431
/**
444432
* Extract all the items of an async iterator/generator.
445433
*

0 commit comments

Comments
 (0)