wallet-core: fix issues with aborting deposits
This commit is contained in:
parent
485f7d3603
commit
8624d798b7
@ -873,7 +873,7 @@ export function bufferForUint32(n: number): Uint8Array {
|
||||
* which should be true for all Taler protocol messages.
|
||||
*/
|
||||
export function bufferForUint64(n: number): Uint8Array {
|
||||
const arrBuf = new ArrayBuffer(4);
|
||||
const arrBuf = new ArrayBuffer(8);
|
||||
const buf = new Uint8Array(arrBuf);
|
||||
const dv = new DataView(arrBuf);
|
||||
if (n < 0 || !Number.isInteger(n)) {
|
||||
|
@ -232,7 +232,7 @@ export async function resetOperationTimeout(
|
||||
if (retryRecord) {
|
||||
// Note that we don't reset the lastError, it should still be visible
|
||||
// while the retry runs.
|
||||
retryRecord.retryInfo = RetryInfo.increment(retryRecord.retryInfo);
|
||||
retryRecord.retryInfo = RetryInfo.reset();
|
||||
await tx.operationRetries.put(retryRecord);
|
||||
}
|
||||
});
|
||||
|
@ -89,6 +89,7 @@ import {
|
||||
import { selectPayCoinsNew } from "../util/coinSelection.js";
|
||||
import {
|
||||
constructTransactionIdentifier,
|
||||
notifyTransition,
|
||||
parseTransactionIdentifier,
|
||||
stopLongpolling,
|
||||
} from "./transactions.js";
|
||||
@ -158,8 +159,16 @@ export function computeDepositTransactionStatus(
|
||||
return {
|
||||
major: TransactionMajorState.Suspended,
|
||||
};
|
||||
case DepositOperationStatus.Aborting:
|
||||
return {
|
||||
major: TransactionMajorState.Aborting,
|
||||
};
|
||||
case DepositOperationStatus.Aborted:
|
||||
return {
|
||||
major: TransactionMajorState.Aborted,
|
||||
}
|
||||
default:
|
||||
throw Error("unexpected deposit group state");
|
||||
throw Error(`unexpected deposit group state (${dg.operationStatus})`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,8 +388,11 @@ async function waitForRefreshOnDepositGroup(
|
||||
): Promise<OperationAttemptResult> {
|
||||
const abortRefreshGroupId = depositGroup.abortRefreshGroupId;
|
||||
checkLogicInvariant(!!abortRefreshGroupId);
|
||||
// FIXME: Emit notification on state transition!
|
||||
const res = await ws.db
|
||||
const transactionId = constructTransactionIdentifier({
|
||||
tag: TransactionType.Deposit,
|
||||
depositGroupId: depositGroup.depositGroupId,
|
||||
});
|
||||
const transitionInfo = await ws.db
|
||||
.mktx((x) => [x.refreshGroups, x.depositGroups])
|
||||
.runReadWrite(async (tx) => {
|
||||
const refreshGroup = await tx.refreshGroups.get(abortRefreshGroupId);
|
||||
@ -405,30 +417,17 @@ async function waitForRefreshOnDepositGroup(
|
||||
if (!newDg) {
|
||||
return;
|
||||
}
|
||||
const oldDepositTxStatus = computeDepositTransactionStatus(newDg);
|
||||
const oldTxState = computeDepositTransactionStatus(newDg);
|
||||
newDg.operationStatus = newOpState;
|
||||
const newDepositTxStatus = computeDepositTransactionStatus(newDg);
|
||||
const newTxState = computeDepositTransactionStatus(newDg);
|
||||
await tx.depositGroups.put(newDg);
|
||||
return { oldDepositTxStatus, newDepositTxStatus };
|
||||
return { oldTxState, newTxState };
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
if (res) {
|
||||
const transactionId = constructTransactionIdentifier({
|
||||
tag: TransactionType.Deposit,
|
||||
depositGroupId: depositGroup.depositGroupId,
|
||||
});
|
||||
ws.notify({
|
||||
type: NotificationType.TransactionStateTransition,
|
||||
transactionId,
|
||||
oldTxState: res.oldDepositTxStatus,
|
||||
newTxState: res.newDepositTxStatus,
|
||||
});
|
||||
notifyTransition(ws, transactionId, transitionInfo);
|
||||
return OperationAttemptResult.pendingEmpty();
|
||||
} else {
|
||||
return OperationAttemptResult.pendingEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
async function refundDepositGroup(
|
||||
@ -436,6 +435,7 @@ async function refundDepositGroup(
|
||||
depositGroup: DepositGroupRecord,
|
||||
): Promise<OperationAttemptResult> {
|
||||
const newTxPerCoin = [...depositGroup.transactionPerCoin];
|
||||
logger.info(`status per coin: ${j2s(depositGroup.transactionPerCoin)}`);
|
||||
for (let i = 0; i < depositGroup.transactionPerCoin.length; i++) {
|
||||
const st = depositGroup.transactionPerCoin[i];
|
||||
switch (st) {
|
||||
@ -475,6 +475,7 @@ async function refundDepositGroup(
|
||||
method: "POST",
|
||||
body: refundReq,
|
||||
});
|
||||
logger.info(`coin ${i} refund HTTP status for coin: ${httpResp.status}`);
|
||||
let newStatus: DepositElementStatus;
|
||||
if (httpResp.status === 200) {
|
||||
// FIXME: validate response
|
||||
@ -492,7 +493,7 @@ async function refundDepositGroup(
|
||||
let isDone = true;
|
||||
for (let i = 0; i < newTxPerCoin.length; i++) {
|
||||
if (
|
||||
newTxPerCoin[i] != DepositElementStatus.RefundFailed ||
|
||||
newTxPerCoin[i] != DepositElementStatus.RefundFailed &&
|
||||
newTxPerCoin[i] != DepositElementStatus.RefundSuccess
|
||||
) {
|
||||
isDone = false;
|
||||
@ -535,6 +536,7 @@ async function refundDepositGroup(
|
||||
await tx.depositGroups.put(newDg);
|
||||
});
|
||||
|
||||
|
||||
return OperationAttemptResult.pendingEmpty();
|
||||
}
|
||||
|
||||
@ -775,10 +777,13 @@ export async function processDepositGroup(
|
||||
}
|
||||
|
||||
if (depositGroup.operationStatus === DepositOperationStatus.Aborting) {
|
||||
logger.info("processing deposit tx in 'aborting'");
|
||||
const abortRefreshGroupId = depositGroup.abortRefreshGroupId;
|
||||
if (!abortRefreshGroupId) {
|
||||
logger.info("refunding deposit group");
|
||||
return refundDepositGroup(ws, depositGroup);
|
||||
}
|
||||
logger.info("waiting for refresh");
|
||||
return waitForRefreshOnDepositGroup(ws, depositGroup);
|
||||
}
|
||||
return OperationAttemptResult.finishedEmpty();
|
||||
|
@ -198,7 +198,10 @@ async function gatherDepositPending(
|
||||
resp: PendingOperationsResponse,
|
||||
): Promise<void> {
|
||||
const dgs = await tx.depositGroups.indexes.byStatus.getAll(
|
||||
OperationStatus.Pending,
|
||||
GlobalIDB.KeyRange.bound(
|
||||
OperationStatusRange.ACTIVE_START,
|
||||
OperationStatusRange.ACTIVE_END,
|
||||
),
|
||||
);
|
||||
for (const dg of dgs) {
|
||||
if (dg.timestampFinished) {
|
||||
|
@ -1307,7 +1307,7 @@ export async function retryTransaction(
|
||||
ws: InternalWalletState,
|
||||
transactionId: string,
|
||||
): Promise<void> {
|
||||
logger.info(`retrying transaction ${transactionId}`);
|
||||
logger.info(`resetting retry timeout for ${transactionId}`);
|
||||
|
||||
const parsedTx = parseTransactionIdentifier(transactionId);
|
||||
|
||||
@ -1325,9 +1325,6 @@ export async function retryTransaction(
|
||||
});
|
||||
await resetOperationTimeout(ws, taskId);
|
||||
stopLongpolling(ws, taskId);
|
||||
await runOperationWithErrorReporting(ws, taskId, () =>
|
||||
processPeerPullCredit(ws, parsedTx.pursePub),
|
||||
);
|
||||
break;
|
||||
}
|
||||
case TransactionType.Deposit: {
|
||||
@ -1337,9 +1334,6 @@ export async function retryTransaction(
|
||||
});
|
||||
await resetOperationTimeout(ws, taskId);
|
||||
stopLongpolling(ws, taskId);
|
||||
await runOperationWithErrorReporting(ws, taskId, () =>
|
||||
processDepositGroup(ws, parsedTx.depositGroupId),
|
||||
);
|
||||
break;
|
||||
}
|
||||
case TransactionType.Withdrawal: {
|
||||
@ -1350,9 +1344,6 @@ export async function retryTransaction(
|
||||
});
|
||||
await resetOperationTimeout(ws, taskId);
|
||||
stopLongpolling(ws, taskId);
|
||||
await runOperationWithErrorReporting(ws, taskId, () =>
|
||||
processWithdrawalGroup(ws, parsedTx.withdrawalGroupId),
|
||||
);
|
||||
break;
|
||||
}
|
||||
case TransactionType.Payment: {
|
||||
@ -1362,9 +1353,6 @@ export async function retryTransaction(
|
||||
});
|
||||
await resetOperationTimeout(ws, taskId);
|
||||
stopLongpolling(ws, taskId);
|
||||
await runOperationWithErrorReporting(ws, taskId, () =>
|
||||
processPurchasePay(ws, parsedTx.proposalId),
|
||||
);
|
||||
break;
|
||||
}
|
||||
case TransactionType.Tip: {
|
||||
@ -1374,9 +1362,6 @@ export async function retryTransaction(
|
||||
});
|
||||
await resetOperationTimeout(ws, taskId);
|
||||
stopLongpolling(ws, taskId);
|
||||
await runOperationWithErrorReporting(ws, taskId, () =>
|
||||
processTip(ws, parsedTx.walletTipId),
|
||||
);
|
||||
break;
|
||||
}
|
||||
case TransactionType.Refresh: {
|
||||
@ -1386,9 +1371,6 @@ export async function retryTransaction(
|
||||
});
|
||||
await resetOperationTimeout(ws, taskId);
|
||||
stopLongpolling(ws, taskId);
|
||||
await runOperationWithErrorReporting(ws, taskId, () =>
|
||||
processRefreshGroup(ws, parsedTx.refreshGroupId),
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user