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