all retryInfo function in the same namespace, adding missing retryInfo increment

This commit is contained in:
Sebastian 2022-05-18 14:41:51 -03:00
parent d3a857743d
commit c67d0bff1d
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
14 changed files with 213 additions and 311 deletions

View File

@ -120,7 +120,10 @@ export namespace BankApi {
if (respJson.paytoUri) {
paytoUri = respJson.paytoUri;
}
} catch (e) {}
} catch (e) {
logger.error("error trying to parse json from response", e);
throw TalerError.fromException(e);
}
return {
password,
username,

View File

@ -15,54 +15,30 @@
*/
import {
BackupPurchase,
AmountJson,
Amounts,
BackupDenomSel,
WalletBackupContentV1,
BackupCoinSourceType,
BackupProposalStatus,
codecForContractTerms,
BackupRefundState,
RefreshReason,
BackupRefreshReason,
DenomKeyType,
AbsoluteTime,
TalerProtocolTimestamp,
Amounts, BackupCoinSourceType, BackupDenomSel, BackupProposalStatus,
BackupPurchase, BackupRefreshReason, BackupRefundState, codecForContractTerms,
DenomKeyType, j2s, Logger, RefreshReason, TalerProtocolTimestamp,
WalletBackupContentV1
} from "@gnu-taler/taler-util";
import {
WalletContractData,
DenomSelectionState,
DenominationVerificationStatus,
CoinSource,
AbortStatus, CoinSource,
CoinSourceType,
CoinStatus,
ReserveBankInfo,
ReserveRecordStatus,
ProposalDownload,
ProposalStatus,
WalletRefundItem,
RefundState,
AbortStatus,
RefreshSessionRecord,
WireInfo,
WalletStoresV1,
RefreshCoinStatus,
OperationStatus,
CoinStatus, DenominationVerificationStatus, DenomSelectionState, OperationStatus, ProposalDownload,
ProposalStatus, RefreshCoinStatus, RefreshSessionRecord, RefundState, ReserveBankInfo,
ReserveRecordStatus, WalletContractData, WalletRefundItem, WalletStoresV1, WireInfo
} from "../../db.js";
import { InternalWalletState } from "../../internal-wallet-state.js";
import { PayCoinSelection } from "../../util/coinSelection.js";
import { j2s } from "@gnu-taler/taler-util";
import {
checkDbInvariant,
checkLogicInvariant,
checkLogicInvariant
} from "../../util/invariants.js";
import { Logger } from "@gnu-taler/taler-util";
import { resetRetryInfo } from "../../util/retries.js";
import { InternalWalletState } from "../../internal-wallet-state.js";
import { provideBackupState } from "./state.js";
import { makeEventId, TombstoneTag } from "../transactions.js";
import { getExchangeDetails } from "../exchanges.js";
import { GetReadOnlyAccess, GetReadWriteAccess } from "../../util/query.js";
import { RetryInfo } from "../../util/retries.js";
import { getExchangeDetails } from "../exchanges.js";
import { makeEventId, TombstoneTag } from "../transactions.js";
import { provideBackupState } from "./state.js";
const logger = new Logger("operations/backup/import.ts");
@ -276,7 +252,7 @@ export async function importBackup(
protocolVersionRange: backupExchange.protocol_version_range,
},
permanent: true,
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
lastUpdate: undefined,
nextUpdate: TalerProtocolTimestamp.now(),
nextRefreshCheck: TalerProtocolTimestamp.now(),
@ -464,7 +440,7 @@ export async function importBackup(
timestampReserveInfoPosted:
backupReserve.bank_info?.timestamp_reserve_info_posted,
senderWire: backupReserve.sender_wire,
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
lastError: undefined,
initialWithdrawalGroupId:
backupReserve.initial_withdrawal_group_id,
@ -505,7 +481,7 @@ export async function importBackup(
backupWg.raw_withdrawal_amount,
),
reservePub,
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
secretSeed: backupWg.secret_seed,
timestampStart: backupWg.timestamp_created,
timestampFinish: backupWg.timestamp_finish,
@ -618,7 +594,7 @@ export async function importBackup(
cryptoComp.proposalNoncePrivToPub[backupProposal.nonce_priv],
proposalId: backupProposal.proposal_id,
repurchaseProposalId: backupProposal.repurchase_proposal_id,
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
download,
proposalStatus,
});
@ -753,7 +729,7 @@ export async function importBackup(
cryptoComp.proposalNoncePrivToPub[backupPurchase.nonce_priv],
lastPayError: undefined,
autoRefundDeadline: TalerProtocolTimestamp.never(),
refundStatusRetryInfo: resetRetryInfo(),
refundStatusRetryInfo: RetryInfo.reset(),
lastRefundStatusError: undefined,
refundAwaiting: undefined,
timestampAccept: backupPurchase.timestamp_accept,
@ -764,7 +740,7 @@ export async function importBackup(
lastSessionId: undefined,
abortStatus,
// FIXME!
payRetryInfo: resetRetryInfo(),
payRetryInfo: RetryInfo.reset(),
download,
paymentSubmitPending:
!backupPurchase.timestamp_first_successful_pay,
@ -865,7 +841,7 @@ export async function importBackup(
Amounts.parseOrThrow(x.estimated_output_amount),
),
refreshSessionPerCoin,
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
});
}
}
@ -891,7 +867,7 @@ export async function importBackup(
merchantBaseUrl: backupTip.exchange_base_url,
merchantTipId: backupTip.merchant_tip_id,
pickedUpTimestamp: backupTip.timestamp_finished,
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
secretSeed: backupTip.secret_seed,
tipAmountEffective: denomsSel.totalCoinValue,
tipAmountRaw: Amounts.parseOrThrow(backupTip.tip_amount_raw),

View File

@ -25,10 +25,9 @@
* Imports.
*/
import {
AmountString,
AbsoluteTime, AmountString,
BackupRecovery,
buildCodecForObject,
canonicalizeBaseUrl,
buildCodecForObject, bytesToString, canonicalizeBaseUrl,
canonicalJson,
Codec,
codecForAmountString,
@ -37,39 +36,22 @@ import {
codecForNumber,
codecForString,
codecOptional,
ConfirmPayResultType,
DenomKeyType,
durationFromSpec,
hashDenomPub,
HttpStatusCode,
j2s,
Logger,
notEmpty,
PreparePayResultType,
RecoveryLoadRequest,
RecoveryMergeStrategy,
TalerErrorDetail,
AbsoluteTime,
URL,
WalletBackupContentV1,
TalerProtocolTimestamp,
} from "@gnu-taler/taler-util";
import { gunzipSync, gzipSync } from "fflate";
import { InternalWalletState } from "../../internal-wallet-state.js";
import { kdf } from "@gnu-taler/taler-util";
import { secretbox, secretbox_open } from "@gnu-taler/taler-util";
import {
bytesToString,
decodeCrock,
eddsaGetPublic,
ConfirmPayResultType, decodeCrock, DenomKeyType,
durationFromSpec, eddsaGetPublic,
EddsaKeyPair,
encodeCrock,
getRandomBytes,
hash,
rsaBlind,
stringToBytes,
hash, hashDenomPub,
HttpStatusCode,
j2s, kdf, Logger,
notEmpty,
PreparePayResultType,
RecoveryLoadRequest,
RecoveryMergeStrategy, rsaBlind, secretbox, secretbox_open, stringToBytes, TalerErrorDetail, TalerProtocolTimestamp, URL,
WalletBackupContentV1
} from "@gnu-taler/taler-util";
import { CryptoDispatcher } from "../../crypto/workers/cryptoDispatcher.js";
import { gunzipSync, gzipSync } from "fflate";
import { TalerCryptoInterface } from "../../crypto/cryptoImplementation.js";
import {
BackupProviderRecord,
BackupProviderState,
@ -78,28 +60,28 @@ import {
ConfigRecord,
WalletBackupConfState,
WalletStoresV1,
WALLET_BACKUP_STATE_KEY,
WALLET_BACKUP_STATE_KEY
} from "../../db.js";
import { InternalWalletState } from "../../internal-wallet-state.js";
import {
readSuccessResponseJsonOrThrow,
readTalerErrorResponse,
readTalerErrorResponse
} from "../../util/http.js";
import {
checkDbInvariant,
checkLogicInvariant,
checkLogicInvariant
} from "../../util/invariants.js";
import { GetReadWriteAccess } from "../../util/query.js";
import { resetRetryInfo, updateRetryInfoTimeout } from "../../util/retries.js";
import { RetryInfo } from "../../util/retries.js";
import { guardOperationException } from "../common.js";
import {
checkPaymentByProposalId,
confirmPay,
preparePayForUri,
preparePayForUri
} from "../pay.js";
import { exportBackup } from "./export.js";
import { BackupCryptoPrecomputedData, importBackup } from "./import.js";
import { getWalletBackupState, provideBackupState } from "./state.js";
import { guardOperationException } from "../common.js";
import { TalerCryptoInterface } from "../../crypto/cryptoImplementation.js";
const logger = new Logger("operations/backup.ts");
@ -309,8 +291,8 @@ async function runBackupCycleForProvider(
"if-none-match": newHash,
...(provider.lastBackupHash
? {
"if-match": provider.lastBackupHash,
}
"if-match": provider.lastBackupHash,
}
: {}),
},
});
@ -344,7 +326,7 @@ async function runBackupCycleForProvider(
}
const res = await preparePayForUri(ws, talerUri);
let proposalId = res.proposalId;
let doPay: boolean = false;
let doPay = false;
switch (res.status) {
case PreparePayResultType.InsufficientBalance:
// FIXME: record in provider state!
@ -434,7 +416,7 @@ async function runBackupCycleForProvider(
// FIXME: Allocate error code for this situation?
prov.state = {
tag: BackupProviderStateTag.Retrying,
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
};
await tx.backupProvider.put(prov);
});
@ -472,13 +454,12 @@ async function incrementBackupRetryInTx(
return;
}
if (pr.state.tag === BackupProviderStateTag.Retrying) {
pr.state.retryInfo.retryCounter++;
pr.state.lastError = err;
updateRetryInfoTimeout(pr.state.retryInfo);
pr.state.retryInfo = RetryInfo.increment(pr.state.retryInfo);
} else if (pr.state.tag === BackupProviderStateTag.Ready) {
pr.state = {
tag: BackupProviderStateTag.Retrying,
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
lastError: err,
};
}
@ -685,7 +666,9 @@ export async function addBackupProvider(
});
}
export async function restoreFromRecoverySecret(): Promise<void> {}
export async function restoreFromRecoverySecret(): Promise<void> {
return;
}
/**
* Information about one provider.

View File

@ -47,7 +47,7 @@ import { DepositGroupRecord, OperationStatus, WireFee } from "../db.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import { PayCoinSelection, selectPayCoins } from "../util/coinSelection.js";
import { readSuccessResponseJsonOrThrow } from "../util/http.js";
import { resetRetryInfo, RetryInfo } from "../util/retries.js";
import { RetryInfo } from "../util/retries.js";
import { guardOperationException } from "./common.js";
import { getExchangeDetails } from "./exchanges.js";
import {
@ -85,7 +85,7 @@ async function setupDepositGroupRetry(
return;
}
if (options.resetRetry) {
x.retryInfo = resetRetryInfo();
x.retryInfo = RetryInfo.reset();
} else {
x.retryInfo = RetryInfo.increment(x.retryInfo);
}
@ -599,7 +599,7 @@ export async function createDepositGroup(
payto_uri: req.depositPaytoUri,
salt: wireSalt,
},
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
operationStatus: OperationStatus.Pending,
lastError: undefined,
};

View File

@ -63,7 +63,7 @@ import {
readSuccessResponseTextOrThrow,
} from "../util/http.js";
import { DbAccess, GetReadOnlyAccess } from "../util/query.js";
import { resetRetryInfo, RetryInfo } from "../util/retries.js";
import { RetryInfo } from "../util/retries.js";
import {
WALLET_CACHE_BREAKER_CLIENT_VERSION,
WALLET_EXCHANGE_PROTOCOL_VERSION,
@ -116,6 +116,9 @@ async function reportExchangeUpdateError(
if (!exchange) {
return;
}
if (!exchange.retryInfo) {
logger.reportBreak();
}
exchange.lastError = err;
await tx.exchanges.put(exchange);
});
@ -137,7 +140,7 @@ async function setupExchangeUpdateRetry(
return;
}
if (options.reset) {
exchange.retryInfo = resetRetryInfo();
exchange.retryInfo = RetryInfo.reset();
} else {
exchange.retryInfo = RetryInfo.increment(exchange.retryInfo);
}
@ -399,7 +402,7 @@ async function provideExchangeRecord(
const r: ExchangeRecord = {
permanent: true,
baseUrl: baseUrl,
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
detailsPointer: undefined,
lastUpdate: undefined,
nextUpdate: AbsoluteTime.toTimestamp(now),

View File

@ -97,10 +97,7 @@ import {
} from "../util/http.js";
import { GetReadWriteAccess } from "../util/query.js";
import {
getRetryDuration,
resetRetryInfo,
RetryInfo,
updateRetryInfoTimeout,
} from "../util/retries.js";
import { getExchangeDetails } from "./exchanges.js";
import { createRefreshGroup, getTotalRefreshCost } from "./refresh.js";
@ -438,8 +435,8 @@ async function recordConfirmPay(
proposalId: proposal.proposalId,
lastPayError: undefined,
lastRefundStatusError: undefined,
payRetryInfo: resetRetryInfo(),
refundStatusRetryInfo: resetRetryInfo(),
payRetryInfo: RetryInfo.reset(),
refundStatusRetryInfo: RetryInfo.reset(),
refundQueryRequested: false,
timestampFirstSuccessfulPay: undefined,
autoRefundDeadline: undefined,
@ -494,6 +491,7 @@ async function reportProposalError(
logger.error(
`Asked to report an error for a proposal (${proposalId}) that is not active (no retryInfo)`,
);
logger.reportBreak();
return;
}
pr.lastError = err;
@ -517,7 +515,7 @@ async function setupProposalRetry(
return;
}
if (options.reset) {
pr.retryInfo = resetRetryInfo();
pr.retryInfo = RetryInfo.reset();
} else {
pr.retryInfo = RetryInfo.increment(pr.retryInfo);
}
@ -541,7 +539,7 @@ async function setupPurchasePayRetry(
return;
}
if (options.reset) {
p.payRetryInfo = resetRetryInfo();
p.payRetryInfo = RetryInfo.reset();
} else {
p.payRetryInfo = RetryInfo.increment(p.payRetryInfo);
}
@ -610,7 +608,7 @@ async function failProposalPermanently(
function getProposalRequestTimeout(proposal: ProposalRecord): Duration {
return durationMax(
{ d_ms: 60000 },
durationMin({ d_ms: 5000 }, getRetryDuration(proposal.retryInfo)),
durationMin({ d_ms: 5000 }, RetryInfo.getDuration(proposal.retryInfo)),
);
}
@ -938,7 +936,7 @@ async function startDownloadProposal(
proposalId: proposalId,
proposalStatus: ProposalStatus.Downloading,
repurchaseProposalId: undefined,
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
lastError: undefined,
downloadSessionId: sessionId,
};
@ -986,14 +984,14 @@ async function storeFirstPaySuccess(
purchase.paymentSubmitPending = false;
purchase.lastPayError = undefined;
purchase.lastSessionId = sessionId;
purchase.payRetryInfo = resetRetryInfo();
purchase.payRetryInfo = RetryInfo.reset();
purchase.merchantPaySig = paySig;
const protoAr = purchase.download.contractData.autoRefund;
if (protoAr) {
const ar = Duration.fromTalerProtocolDuration(protoAr);
logger.info("auto_refund present");
purchase.refundQueryRequested = true;
purchase.refundStatusRetryInfo = resetRetryInfo();
purchase.refundStatusRetryInfo = RetryInfo.reset();
purchase.lastRefundStatusError = undefined;
purchase.autoRefundDeadline = AbsoluteTime.toTimestamp(
AbsoluteTime.addDuration(AbsoluteTime.now(), ar),
@ -1023,7 +1021,7 @@ async function storePayReplaySuccess(
}
purchase.paymentSubmitPending = false;
purchase.lastPayError = undefined;
purchase.payRetryInfo = resetRetryInfo();
purchase.payRetryInfo = RetryInfo.reset();
purchase.lastSessionId = sessionId;
await tx.purchases.put(purchase);
});

View File

@ -26,38 +26,28 @@
*/
import {
Amounts,
codecForRecoupConfirmation,
j2s,
NotificationType,
codecForRecoupConfirmation, encodeCrock, getRandomBytes, j2s, Logger, NotificationType,
RefreshReason,
TalerErrorDetail,
TalerProtocolTimestamp,
TalerProtocolTimestamp, URL
} from "@gnu-taler/taler-util";
import { encodeCrock, getRandomBytes } from "@gnu-taler/taler-util";
import {
CoinRecord,
CoinSourceType,
CoinStatus,
RecoupGroupRecord,
CoinStatus, OperationStatus, RecoupGroupRecord,
RefreshCoinSource,
ReserveRecordStatus,
WithdrawCoinSource,
WalletStoresV1,
OperationStatus,
ReserveRecordStatus, WalletStoresV1, WithdrawCoinSource
} from "../db.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import { readSuccessResponseJsonOrThrow } from "../util/http.js";
import { Logger, URL } from "@gnu-taler/taler-util";
import { GetReadWriteAccess } from "../util/query.js";
import {
resetRetryInfo,
RetryInfo,
updateRetryInfoTimeout,
RetryInfo
} from "../util/retries.js";
import { guardOperationException } from "./common.js";
import { createRefreshGroup, processRefreshGroup } from "./refresh.js";
import { getReserveRequestTimeout, processReserve } from "./reserves.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import { GetReadWriteAccess } from "../util/query.js";
import { guardOperationException } from "./common.js";
const logger = new Logger("operations/recoup.ts");
@ -78,7 +68,7 @@ async function setupRecoupRetry(
return;
}
if (options.reset) {
r.retryInfo = resetRetryInfo();
r.retryInfo = RetryInfo.reset();
} else {
r.retryInfo = RetryInfo.increment(r.retryInfo);
}
@ -139,7 +129,7 @@ async function putGroupAsFinished(
if (allFinished) {
logger.info("all recoups of recoup group are finished");
recoupGroup.timestampFinished = TalerProtocolTimestamp.now();
recoupGroup.retryInfo = resetRetryInfo();
recoupGroup.retryInfo = RetryInfo.reset();
recoupGroup.lastError = undefined;
if (recoupGroup.scheduleRefreshCoins.length > 0) {
const refreshGroupId = await createRefreshGroup(
@ -278,7 +268,7 @@ async function recoupWithdrawCoin(
const currency = updatedCoin.currentAmount.currency;
updatedCoin.currentAmount = Amounts.getZero(currency);
updatedReserve.reserveStatus = ReserveRecordStatus.QueryingStatus;
updatedReserve.retryInfo = resetRetryInfo();
updatedReserve.retryInfo = RetryInfo.reset();
updatedReserve.operationStatus = OperationStatus.Pending;
await tx.coins.put(updatedCoin);
await tx.reserves.put(updatedReserve);
@ -482,7 +472,7 @@ export async function createRecoupGroup(
lastError: undefined,
timestampFinished: undefined,
timestampStarted: TalerProtocolTimestamp.now(),
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
recoupFinishedPerCoin: coinPubs.map(() => false),
// Will be populated later
oldAmountPerCoin: [],

View File

@ -15,20 +15,28 @@
*/
import {
AgeCommitment,
AgeRestriction,
CoinPublicKeyString,
DenomKeyType,
encodeCrock,
AbsoluteTime, AgeCommitment,
AgeRestriction, AmountJson, Amounts, amountToPretty, codecForExchangeMeltResponse,
codecForExchangeRevealResponse,
CoinPublicKey, CoinPublicKeyString,
DenomKeyType, Duration,
durationFromSpec,
durationMul, encodeCrock,
ExchangeMeltRequest,
ExchangeProtocolVersion,
ExchangeRefreshRevealRequest,
getRandomBytes,
ExchangeProtocolVersion, ExchangeRefreshRevealRequest, fnutil, getRandomBytes,
HashCodeString,
HttpStatusCode,
j2s,
TalerProtocolTimestamp,
j2s, Logger, NotificationType,
RefreshGroupId,
RefreshReason,
TalerErrorDetail, TalerProtocolTimestamp, URL
} from "@gnu-taler/taler-util";
import { TalerCryptoInterface } from "../crypto/cryptoImplementation.js";
import {
DerivedRefreshSession,
RefreshNewDenomInfo
} from "../crypto/cryptoTypes.js";
import { CryptoApiStoppedError } from "../crypto/workers/cryptoDispatcher.js";
import {
CoinRecord,
CoinSourceType,
@ -37,57 +45,29 @@ import {
OperationStatus,
RefreshCoinStatus,
RefreshGroupRecord,
WalletStoresV1,
WalletStoresV1
} from "../db.js";
import {
codecForExchangeMeltResponse,
codecForExchangeRevealResponse,
CoinPublicKey,
fnutil,
NotificationType,
RefreshGroupId,
RefreshReason,
TalerErrorDetail,
} from "@gnu-taler/taler-util";
import { AmountJson, Amounts } from "@gnu-taler/taler-util";
import { amountToPretty } from "@gnu-taler/taler-util";
import {
readSuccessResponseJsonOrThrow,
readUnexpectedResponseDetails,
} from "../util/http.js";
import { checkDbInvariant } from "../util/invariants.js";
import { Logger } from "@gnu-taler/taler-util";
import {
resetRetryInfo,
RetryInfo,
updateRetryInfoTimeout,
} from "../util/retries.js";
import {
Duration,
durationFromSpec,
durationMul,
AbsoluteTime,
URL,
} from "@gnu-taler/taler-util";
import { updateExchangeFromUrl } from "./exchanges.js";
import { TalerError } from "../errors.js";
import {
DenomInfo,
EXCHANGE_COINS_LOCK,
InternalWalletState,
InternalWalletState
} from "../internal-wallet-state.js";
import {
isWithdrawableDenom,
selectWithdrawalDenominations,
} from "./withdraw.js";
import {
DerivedRefreshSession,
RefreshNewDenomInfo,
} from "../crypto/cryptoTypes.js";
readSuccessResponseJsonOrThrow,
readUnexpectedResponseDetails
} from "../util/http.js";
import { checkDbInvariant } from "../util/invariants.js";
import { GetReadWriteAccess } from "../util/query.js";
import {
RetryInfo
} from "../util/retries.js";
import { guardOperationException } from "./common.js";
import { CryptoApiStoppedError } from "../crypto/workers/cryptoDispatcher.js";
import { TalerCryptoInterface } from "../crypto/cryptoImplementation.js";
import { TalerError } from "../errors.js";
import { updateExchangeFromUrl } from "./exchanges.js";
import {
isWithdrawableDenom,
selectWithdrawalDenominations
} from "./withdraw.js";
const logger = new Logger("refresh.ts");
@ -129,22 +109,22 @@ export function getTotalRefreshCost(
}
function updateGroupStatus(rg: RefreshGroupRecord): void {
let allDone = fnutil.all(
const allDone = fnutil.all(
rg.statusPerCoin,
(x) => x === RefreshCoinStatus.Finished || x === RefreshCoinStatus.Frozen,
);
let anyFrozen = fnutil.any(
const anyFrozen = fnutil.any(
rg.statusPerCoin,
(x) => x === RefreshCoinStatus.Frozen,
);
if (allDone) {
if (anyFrozen) {
rg.frozen = true;
rg.retryInfo = resetRetryInfo();
rg.retryInfo = RetryInfo.reset();
} else {
rg.timestampFinished = AbsoluteTime.toTimestamp(AbsoluteTime.now());
rg.operationStatus = OperationStatus.Finished;
rg.retryInfo = resetRetryInfo();
rg.retryInfo = RetryInfo.reset();
}
}
}
@ -753,7 +733,7 @@ async function setupRefreshRetry(
return;
}
if (options.reset) {
r.retryInfo = resetRetryInfo();
r.retryInfo = RetryInfo.reset();
} else {
r.retryInfo = RetryInfo.increment(r.retryInfo);
}
@ -987,7 +967,7 @@ export async function createRefreshGroup(
reason,
refreshGroupId,
refreshSessionPerCoin: oldCoinPubs.map(() => undefined),
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
inputPerCoin,
estimatedOutputPerCoin,
timestampCreated: TalerProtocolTimestamp.now(),

View File

@ -25,29 +25,18 @@
*/
import {
AbortingCoin,
AbortRequest,
AmountJson,
AbortRequest, AbsoluteTime, AmountJson,
Amounts,
ApplyRefundResponse,
codecForAbortResponse,
codecForMerchantOrderRefundPickupResponse,
CoinPublicKey,
Logger,
codecForMerchantOrderRefundPickupResponse, codecForMerchantOrderStatusPaid, CoinPublicKey, Duration, Logger,
MerchantCoinRefundFailureStatus,
MerchantCoinRefundStatus,
MerchantCoinRefundSuccessStatus,
NotificationType,
parseRefundUri,
RefreshReason,
parseRefundUri, PrepareRefundResult, RefreshReason,
TalerErrorCode,
TalerErrorDetail,
URL,
codecForMerchantOrderStatusPaid,
AbsoluteTime,
TalerProtocolTimestamp,
Duration,
PrepareRefundRequest,
PrepareRefundResult,
TalerErrorDetail, TalerProtocolTimestamp, URL
} from "@gnu-taler/taler-util";
import {
AbortStatus,
@ -55,19 +44,17 @@ import {
PurchaseRecord,
RefundReason,
RefundState,
WalletStoresV1,
WalletStoresV1
} from "../db.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import { readSuccessResponseJsonOrThrow } from "../util/http.js";
import { checkDbInvariant } from "../util/invariants.js";
import { GetReadWriteAccess } from "../util/query.js";
import {
resetRetryInfo,
RetryInfo,
updateRetryInfoTimeout,
RetryInfo
} from "../util/retries.js";
import { createRefreshGroup, getTotalRefreshCost } from "./refresh.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import { guardOperationException } from "./common.js";
import { createRefreshGroup, getTotalRefreshCost } from "./refresh.js";
const logger = new Logger("refund.ts");
@ -147,7 +134,7 @@ async function setupPurchaseQueryRefundRetry(
return;
}
if (options.reset) {
pr.refundStatusRetryInfo = resetRetryInfo();
pr.refundStatusRetryInfo = RetryInfo.reset();
} else {
pr.refundStatusRetryInfo = RetryInfo.increment(
pr.refundStatusRetryInfo,
@ -500,7 +487,7 @@ async function acceptRefunds(
if (queryDone) {
p.timestampLastRefundStatus = now;
p.lastRefundStatusError = undefined;
p.refundStatusRetryInfo = resetRetryInfo();
p.refundStatusRetryInfo = RetryInfo.reset();
p.refundQueryRequested = false;
if (p.abortStatus === AbortStatus.AbortRefund) {
p.abortStatus = AbortStatus.AbortFinished;
@ -509,8 +496,7 @@ async function acceptRefunds(
} else {
// No error, but we need to try again!
p.timestampLastRefundStatus = now;
p.refundStatusRetryInfo.retryCounter++;
updateRetryInfoTimeout(p.refundStatusRetryInfo);
p.refundStatusRetryInfo = RetryInfo.increment(p.refundStatusRetryInfo)
p.lastRefundStatusError = undefined;
logger.trace("refund query not done");
}
@ -619,7 +605,7 @@ export async function applyRefund(
}
p.refundQueryRequested = true;
p.lastRefundStatusError = undefined;
p.refundStatusRetryInfo = resetRetryInfo();
p.refundStatusRetryInfo = RetryInfo.reset();
await tx.purchases.put(p);
return true;
});
@ -892,7 +878,7 @@ export async function abortFailedPayWithRefund(
purchase.paymentSubmitPending = false;
purchase.abortStatus = AbortStatus.AbortRefund;
purchase.lastPayError = undefined;
purchase.payRetryInfo = resetRetryInfo();
purchase.payRetryInfo = RetryInfo.reset();
await tx.purchases.put(purchase);
});
processPurchaseQueryRefund(ws, proposalId, {

View File

@ -58,8 +58,6 @@ import {
} from "../util/http.js";
import { GetReadOnlyAccess } from "../util/query.js";
import {
getRetryDuration,
resetRetryInfo,
RetryInfo,
} from "../util/retries.js";
import {
@ -100,7 +98,7 @@ async function setupReserveRetry(
return;
}
if (options.reset) {
r.retryInfo = resetRetryInfo();
r.retryInfo = RetryInfo.reset();
} else {
r.retryInfo = RetryInfo.increment(r.retryInfo);
}
@ -196,7 +194,7 @@ export async function createReserve(
timestampReserveInfoPosted: undefined,
bankInfo,
reserveStatus,
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
lastError: undefined,
currency: req.amount.currency,
operationStatus: OperationStatus.Pending,
@ -297,7 +295,7 @@ export async function forceQueryReserve(
case ReserveRecordStatus.Dormant:
reserve.reserveStatus = ReserveRecordStatus.QueryingStatus;
reserve.operationStatus = OperationStatus.Pending;
reserve.retryInfo = resetRetryInfo();
reserve.retryInfo = RetryInfo.reset();
break;
default:
break;
@ -392,7 +390,7 @@ async function registerReserveWithBank(
if (!r.bankInfo) {
throw Error("invariant failed");
}
r.retryInfo = resetRetryInfo();
r.retryInfo = RetryInfo.reset();
await tx.reserves.put(r);
});
ws.notify({ type: NotificationType.ReserveRegisteredWithBank });
@ -402,7 +400,7 @@ async function registerReserveWithBank(
export function getReserveRequestTimeout(r: ReserveRecord): Duration {
return durationMax(
{ d_ms: 60000 },
durationMin({ d_ms: 5000 }, getRetryDuration(r.retryInfo)),
durationMin({ d_ms: 5000 }, RetryInfo.getDuration(r.retryInfo)),
);
}
@ -459,7 +457,7 @@ async function processReserveBankStatus(
r.timestampBankConfirmed = now;
r.reserveStatus = ReserveRecordStatus.BankAborted;
r.operationStatus = OperationStatus.Finished;
r.retryInfo = resetRetryInfo();
r.retryInfo = RetryInfo.reset();
await tx.reserves.put(r);
});
return;
@ -496,7 +494,7 @@ async function processReserveBankStatus(
r.timestampBankConfirmed = now;
r.reserveStatus = ReserveRecordStatus.QueryingStatus;
r.operationStatus = OperationStatus.Pending;
r.retryInfo = resetRetryInfo();
r.retryInfo = RetryInfo.reset();
} else {
switch (r.reserveStatus) {
case ReserveRecordStatus.WaitConfirmBank:
@ -555,7 +553,7 @@ async function updateReserve(
if (
resp.status === 404 &&
result.talerErrorResponse.code ===
TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN
TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN
) {
ws.notify({
type: NotificationType.ReserveNotYetFound,
@ -662,7 +660,7 @@ async function updateReserve(
reservePub: reserve.reservePub,
rawWithdrawalAmount: remainingAmount,
timestampStart: AbsoluteTime.toTimestamp(AbsoluteTime.now()),
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
lastError: undefined,
denomsSel: denomSel,
secretSeed: encodeCrock(getRandomBytes(64)),
@ -721,12 +719,13 @@ async function processReserveImpl(
case ReserveRecordStatus.RegisteringBank:
await processReserveBankStatus(ws, reservePub);
return await processReserveImpl(ws, reservePub, { forceNow: true });
case ReserveRecordStatus.QueryingStatus:
case ReserveRecordStatus.QueryingStatus: {
const res = await updateReserve(ws, reservePub);
if (res.ready) {
return await processReserveImpl(ws, reservePub, { forceNow: true });
}
break;
}
case ReserveRecordStatus.Dormant:
// nothing to do
break;

View File

@ -18,51 +18,30 @@
* Imports.
*/
import {
PrepareTipResult,
parseTipUri,
codecForTipPickupGetResponse,
Amounts,
TalerErrorDetail,
NotificationType,
TipPlanchetDetail,
TalerErrorCode,
Logger,
URL,
DenomKeyType,
BlindedDenominationSignature,
codecForMerchantTipResponseV2,
TalerProtocolTimestamp,
Amounts, BlindedDenominationSignature,
codecForMerchantTipResponseV2, codecForTipPickupGetResponse, DenomKeyType, encodeCrock, getRandomBytes, j2s, Logger, NotificationType, parseTipUri, PrepareTipResult, TalerErrorCode, TalerErrorDetail, TalerProtocolTimestamp, TipPlanchetDetail, URL
} from "@gnu-taler/taler-util";
import { DerivedTipPlanchet } from "../crypto/cryptoTypes.js";
import {
DenominationRecord,
CoinRecord,
CoinSourceType,
CoinStatus,
TipRecord,
CoinStatus, DenominationRecord, TipRecord
} from "../db.js";
import { j2s } from "@gnu-taler/taler-util";
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
import {
resetRetryInfo,
RetryInfo,
updateRetryInfoTimeout,
} from "../util/retries.js";
import { makeErrorDetail } from "../errors.js";
import { updateExchangeFromUrl } from "./exchanges.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import {
getExchangeWithdrawalInfo,
updateWithdrawalDenoms,
getCandidateWithdrawalDenoms,
selectWithdrawalDenominations,
} from "./withdraw.js";
import {
getHttpResponseErrorDetails,
readSuccessResponseJsonOrThrow,
readSuccessResponseJsonOrThrow
} from "../util/http.js";
import { encodeCrock, getRandomBytes } from "@gnu-taler/taler-util";
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
import {
RetryInfo
} from "../util/retries.js";
import { guardOperationException } from "./common.js";
import { updateExchangeFromUrl } from "./exchanges.js";
import {
getCandidateWithdrawalDenoms, getExchangeWithdrawalInfo, selectWithdrawalDenominations, updateWithdrawalDenoms
} from "./withdraw.js";
const logger = new Logger("operations/tip.ts");
@ -130,7 +109,7 @@ export async function prepareTip(
createdTimestamp: TalerProtocolTimestamp.now(),
merchantTipId: res.merchantTipId,
tipAmountEffective: selectedDenoms.totalCoinValue,
retryInfo: resetRetryInfo(),
retryInfo: RetryInfo.reset(),
lastError: undefined,
denomsSel: selectedDenoms,
pickedUpTimestamp: undefined,
@ -202,7 +181,7 @@ async function setupTipRetry(
return;
}
if (options.reset) {
t.retryInfo = resetRetryInfo();
t.retryInfo = RetryInfo.reset();
} else {
t.retryInfo = RetryInfo.increment(t.retryInfo);
}
@ -237,7 +216,7 @@ async function resetTipRetry(
.runReadWrite(async (tx) => {
const x = await tx.tips.get(tipId);
if (x) {
x.retryInfo = resetRetryInfo();
x.retryInfo = RetryInfo.reset();
await tx.tips.put(x);
}
});
@ -430,7 +409,7 @@ async function processTipImpl(
}
tr.pickedUpTimestamp = TalerProtocolTimestamp.now();
tr.lastError = undefined;
tr.retryInfo = resetRetryInfo();
tr.retryInfo = RetryInfo.reset();
await tx.tips.put(tr);
for (const cr of newCoinRecords) {
await tx.coins.put(cr);

View File

@ -72,7 +72,7 @@ import {
readSuccessResponseJsonOrThrow,
} from "../util/http.js";
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
import { resetRetryInfo, RetryInfo } from "../util/retries.js";
import { RetryInfo } from "../util/retries.js";
import {
WALLET_BANK_INTEGRATION_PROTOCOL_VERSION,
WALLET_EXCHANGE_PROTOCOL_VERSION,
@ -215,7 +215,7 @@ export function selectWithdrawalDenominations(
for (const d of denoms) {
let count = 0;
const cost = Amounts.add(d.value, d.feeWithdraw).amount;
for (;;) {
for (; ;) {
if (Amounts.cmp(remaining, cost) < 0) {
break;
}
@ -875,11 +875,10 @@ export async function updateWithdrawalDenoms(
denom.verificationStatus === DenominationVerificationStatus.Unverified
) {
logger.trace(
`Validating denomination (${current + 1}/${
denominations.length
`Validating denomination (${current + 1}/${denominations.length
}) signature of ${denom.denomPubHash}`,
);
let valid: boolean = false;
let valid = false;
if (ws.insecureTrustExchange) {
valid = true;
} else {
@ -932,7 +931,7 @@ async function setupWithdrawalRetry(
return;
}
if (options.reset) {
wsr.retryInfo = resetRetryInfo();
wsr.retryInfo = RetryInfo.reset();
} else {
wsr.retryInfo = RetryInfo.increment(wsr.retryInfo);
}
@ -1097,7 +1096,7 @@ async function processWithdrawGroupImpl(
wg.timestampFinish = TalerProtocolTimestamp.now();
wg.operationStatus = OperationStatus.Finished;
delete wg.lastError;
wg.retryInfo = resetRetryInfo();
wg.retryInfo = RetryInfo.reset();
}
await tx.withdrawalGroups.put(wg);
@ -1203,7 +1202,7 @@ export async function getExchangeWithdrawalInfo(
) {
console.warn(
`wallet's support for exchange protocol version ${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` +
`(exchange has ${exchangeDetails.protocolVersion}), checking for updates`,
`(exchange has ${exchangeDetails.protocolVersion}), checking for updates`,
);
}
}

View File

@ -41,7 +41,7 @@ const defaultRetryPolicy: RetryPolicy = {
maxTimeout: { d_ms: 6000 },
};
export function updateRetryInfoTimeout(
function updateTimeout(
r: RetryInfo,
p: RetryPolicy = defaultRetryPolicy,
): void {
@ -65,45 +65,46 @@ export function updateRetryInfoTimeout(
r.nextRetry = { t_ms: t };
}
export function getRetryDuration(
r: RetryInfo | undefined,
p: RetryPolicy = defaultRetryPolicy,
): Duration {
if (!r) {
// If we don't have any retry info, run immediately.
return { d_ms: 0 };
}
if (p.backoffDelta.d_ms === "forever") {
return { d_ms: "forever" };
}
const t = p.backoffDelta.d_ms * Math.pow(p.backoffBase, r.retryCounter);
return {
d_ms: p.maxTimeout.d_ms === "forever" ? t : Math.min(p.maxTimeout.d_ms, t),
};
}
export function resetRetryInfo(p: RetryPolicy = defaultRetryPolicy): RetryInfo {
const now = AbsoluteTime.now();
const info = {
firstTry: now,
nextRetry: now,
retryCounter: 0,
};
updateRetryInfoTimeout(info, p);
return info;
}
export namespace RetryInfo {
export function getDuration(
r: RetryInfo | undefined,
p: RetryPolicy = defaultRetryPolicy,
): Duration {
if (!r) {
// If we don't have any retry info, run immediately.
return { d_ms: 0 };
}
if (p.backoffDelta.d_ms === "forever") {
return { d_ms: "forever" };
}
const t = p.backoffDelta.d_ms * Math.pow(p.backoffBase, r.retryCounter);
return {
d_ms: p.maxTimeout.d_ms === "forever" ? t : Math.min(p.maxTimeout.d_ms, t),
};
}
export function reset(p: RetryPolicy = defaultRetryPolicy): RetryInfo {
const now = AbsoluteTime.now();
const info = {
firstTry: now,
nextRetry: now,
retryCounter: 0,
};
updateTimeout(info, p);
return info;
}
export function increment(
r: RetryInfo | undefined,
p: RetryPolicy = defaultRetryPolicy,
) {
): RetryInfo {
if (!r) {
return resetRetryInfo(p);
return reset(p);
}
const r2 = { ...r };
r2.retryCounter++;
updateRetryInfoTimeout(r2, p);
updateTimeout(r2, p);
return r2;
}
}

View File

@ -335,6 +335,7 @@ async function runTaskLoop(
let numGivingLiveness = 0;
let numDue = 0;
let minDue: AbsoluteTime = AbsoluteTime.never();
for (const p of pending.pendingOperations) {
minDue = AbsoluteTime.min(minDue, p.timestampDue);
if (AbsoluteTime.isExpired(p.timestampDue)) {
@ -683,9 +684,13 @@ async function dumpCoins(ws: InternalWalletState): Promise<CoinDumpJson> {
c.exchangeBaseUrl,
c.denomPubHash,
);
if (!denomInfo) {
console.error("no denomination found for coin")
continue;
}
coinsJson.coins.push({
coin_pub: c.coinPub,
denom_pub: denomInfo?.denomPub!,
denom_pub: denomInfo.denomPub,
denom_pub_hash: c.denomPubHash,
denom_value: Amounts.stringify(denom.value),
exchange_base_url: c.exchangeBaseUrl,