aboutsummaryrefslogtreecommitdiff
path: root/src/wallet-impl/refresh.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet-impl/refresh.ts')
-rw-r--r--src/wallet-impl/refresh.ts103
1 files changed, 71 insertions, 32 deletions
diff --git a/src/wallet-impl/refresh.ts b/src/wallet-impl/refresh.ts
index 7e7270ed3..a3b48919d 100644
--- a/src/wallet-impl/refresh.ts
+++ b/src/wallet-impl/refresh.ts
@@ -23,6 +23,8 @@ import {
RefreshPlanchetRecord,
CoinRecord,
RefreshSessionRecord,
+ initRetryInfo,
+ updateRetryInfoTimeout,
} from "../dbTypes";
import { amountToPretty } from "../util/helpers";
import {
@@ -36,6 +38,8 @@ import { InternalWalletState } from "./state";
import { Logger } from "../util/logging";
import { getWithdrawDenomList } from "./withdraw";
import { updateExchangeFromUrl } from "./exchanges";
+import { getTimestampNow, OperationError, NotificationType } from "../walletTypes";
+import { guardOperationException } from "./errors";
const logger = new Logger("refresh.ts");
@@ -132,14 +136,16 @@ async function refreshMelt(
if (rs.norevealIndex !== undefined) {
return;
}
- if (rs.finished) {
+ if (rs.finishedTimestamp) {
return;
}
rs.norevealIndex = norevealIndex;
return rs;
});
- ws.notifier.notify();
+ ws.notify({
+ type: NotificationType.RefreshMelted,
+ });
}
async function refreshReveal(
@@ -225,16 +231,6 @@ async function refreshReveal(
return;
}
- const exchange = oneShotGet(
- ws.db,
- Stores.exchanges,
- refreshSession.exchangeBaseUrl,
- );
- if (!exchange) {
- console.error(`exchange ${refreshSession.exchangeBaseUrl} not found`);
- return;
- }
-
const coins: CoinRecord[] = [];
for (let i = 0; i < respJson.ev_sigs.length; i++) {
@@ -271,32 +267,72 @@ async function refreshReveal(
coins.push(coin);
}
- refreshSession.finished = true;
-
await runWithWriteTransaction(
ws.db,
[Stores.coins, Stores.refresh],
async tx => {
const rs = await tx.get(Stores.refresh, refreshSessionId);
if (!rs) {
+ console.log("no refresh session found");
return;
}
- if (rs.finished) {
+ if (rs.finishedTimestamp) {
+ console.log("refresh session already finished");
return;
}
+ rs.finishedTimestamp = getTimestampNow();
+ rs.retryInfo = initRetryInfo(false);
for (let coin of coins) {
await tx.put(Stores.coins, coin);
}
- await tx.put(Stores.refresh, refreshSession);
+ await tx.put(Stores.refresh, rs);
},
);
- ws.notifier.notify();
+ console.log("refresh finished (end of reveal)");
+ ws.notify({
+ type: NotificationType.RefreshRevealed,
+ });
}
+async function incrementRefreshRetry(
+ ws: InternalWalletState,
+ refreshSessionId: string,
+ err: OperationError | undefined,
+): Promise<void> {
+ await runWithWriteTransaction(ws.db, [Stores.refresh], async tx => {
+ const r = await tx.get(Stores.refresh, refreshSessionId);
+ if (!r) {
+ return;
+ }
+ if (!r.retryInfo) {
+ return;
+ }
+ r.retryInfo.retryCounter++;
+ updateRetryInfoTimeout(r.retryInfo);
+ r.lastError = err;
+ await tx.put(Stores.refresh, r);
+ });
+}
+
+
export async function processRefreshSession(
ws: InternalWalletState,
refreshSessionId: string,
) {
+ return ws.memoProcessRefresh.memo(refreshSessionId, async () => {
+ const onOpErr = (e: OperationError) =>
+ incrementRefreshRetry(ws, refreshSessionId, e);
+ return guardOperationException(
+ () => processRefreshSessionImpl(ws, refreshSessionId),
+ onOpErr,
+ );
+ });
+}
+
+async function processRefreshSessionImpl(
+ ws: InternalWalletState,
+ refreshSessionId: string,
+) {
const refreshSession = await oneShotGet(
ws.db,
Stores.refresh,
@@ -305,7 +341,7 @@ export async function processRefreshSession(
if (!refreshSession) {
return;
}
- if (refreshSession.finished) {
+ if (refreshSession.finishedTimestamp) {
return;
}
if (typeof refreshSession.norevealIndex !== "number") {
@@ -376,7 +412,7 @@ export async function refresh(
x.status = CoinStatus.Dormant;
return x;
});
- ws.notifier.notify();
+ ws.notify( { type: NotificationType.RefreshRefused });
return;
}
@@ -388,29 +424,32 @@ export async function refresh(
oldDenom.feeRefresh,
);
- function mutateCoin(c: CoinRecord): CoinRecord {
- const r = Amounts.sub(c.currentAmount, refreshSession.valueWithFee);
- if (r.saturated) {
- // Something else must have written the coin value
- throw TransactionAbort;
- }
- c.currentAmount = r.amount;
- c.status = CoinStatus.Dormant;
- return c;
- }
-
// Store refresh session and subtract refreshed amount from
// coin in the same transaction.
await runWithWriteTransaction(
ws.db,
[Stores.refresh, Stores.coins],
async tx => {
+ const c = await tx.get(Stores.coins, coin.coinPub);
+ if (!c) {
+ return;
+ }
+ if (c.status !== CoinStatus.Dirty) {
+ return;
+ }
+ const r = Amounts.sub(c.currentAmount, refreshSession.valueWithFee);
+ if (r.saturated) {
+ console.log("can't refresh coin, no amount left");
+ return;
+ }
+ c.currentAmount = r.amount;
+ c.status = CoinStatus.Dormant;
await tx.put(Stores.refresh, refreshSession);
- await tx.mutate(Stores.coins, coin.coinPub, mutateCoin);
+ await tx.put(Stores.coins, c);
},
);
logger.info(`created refresh session ${refreshSession.refreshSessionId}`);
- ws.notifier.notify();
+ ws.notify( { type: NotificationType.RefreshStarted });
await processRefreshSession(ws, refreshSession.refreshSessionId);
}