implement force-retrying transactions

This commit is contained in:
Florian Dold 2021-06-14 19:37:35 +02:00
parent b4f97f4592
commit ef636c022b
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
4 changed files with 69 additions and 5 deletions

View File

@ -949,7 +949,16 @@ export interface DeleteTransactionRequest {
transactionId: string; transactionId: string;
} }
export interface RetryTransactionRequest {
transactionId: string;
}
export const codecForDeleteTransactionRequest = (): Codec<DeleteTransactionRequest> => export const codecForDeleteTransactionRequest = (): Codec<DeleteTransactionRequest> =>
buildCodecForObject<DeleteTransactionRequest>() buildCodecForObject<DeleteTransactionRequest>()
.property("transactionId", codecForString()) .property("transactionId", codecForString())
.build("DeleteTransactionRequest"); .build("DeleteTransactionRequest");
export const codecForRetryTransactionRequest = (): Codec<RetryTransactionRequest> =>
buildCodecForObject<RetryTransactionRequest>()
.property("transactionId", codecForString())
.build("RetryTransactionRequest");

View File

@ -5,11 +5,15 @@
// Implementation derived from TweetNaCl version 20140427. // Implementation derived from TweetNaCl version 20140427.
// See for details: http://tweetnacl.cr.yp.to/ // See for details: http://tweetnacl.cr.yp.to/
import { createRequire } from "module"; import * as mod from "module";
// We need this require function to synchronously let require: any;
// import the "crypto" module in the CSPRNG initialization.
const require = createRequire(import.meta.url); if (typeof require !== "function" && mod.default && mod.default.createRequire) {
// We need this require function to synchronously
// import the "crypto" module in the CSPRNG initialization.
require = mod.default.createRequire(import.meta.url);
}
const gf = function (init: number[] = []): Float64Array { const gf = function (init: number[] = []): Float64Array {
const r = new Float64Array(16); const r = new Float64Array(16);

View File

@ -38,6 +38,11 @@ import {
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { getFundingPaytoUris } from "./reserves.js"; import { getFundingPaytoUris } from "./reserves.js";
import { getExchangeDetails } from "./exchanges.js"; import { getExchangeDetails } from "./exchanges.js";
import { processWithdrawGroup } from "./withdraw.js";
import { processPurchasePay } from "./pay.js";
import { processDepositGroup } from "./deposits.js";
import { processTip } from "./tip.js";
import { processRefreshGroup } from "./refresh.js";
/** /**
* Create an event ID from the type and the primary key for the event. * Create an event ID from the type and the primary key for the event.
@ -398,6 +403,46 @@ export enum TombstoneTag {
DeleteRefund = "delete-refund", DeleteRefund = "delete-refund",
} }
/**
* Immediately retry the underlying operation
* of a transaction.
*/
export async function retryTransaction(
ws: InternalWalletState,
transactionId: string,
): Promise<void> {
const [type, ...rest] = transactionId.split(":");
switch (type) {
case TransactionType.Deposit:
const depositGroupId = rest[0];
processDepositGroup(ws, depositGroupId, true);
break;
case TransactionType.Withdrawal: {
const withdrawalGroupId = rest[0];
await processWithdrawGroup(ws, withdrawalGroupId, true);
break;
}
case TransactionType.Payment: {
const proposalId = rest[0]
await processPurchasePay(ws, proposalId, true);
break;
}
case TransactionType.Tip: {
const walletTipId = rest[0];
await processTip(ws, walletTipId, true);
break;
}
case TransactionType.Refresh: {
const refreshGroupId = rest[0];
await processRefreshGroup(ws, refreshGroupId, true);
break;
}
default:
break;
}
}
/** /**
* Permanently delete a transaction based on the transaction ID. * Permanently delete a transaction based on the transaction ID.
*/ */

View File

@ -26,6 +26,7 @@ import {
BackupRecovery, BackupRecovery,
codecForAny, codecForAny,
codecForDeleteTransactionRequest, codecForDeleteTransactionRequest,
codecForRetryTransactionRequest,
DeleteTransactionRequest, DeleteTransactionRequest,
durationFromSpec, durationFromSpec,
durationMax, durationMax,
@ -103,7 +104,7 @@ import {
withdrawTestBalance, withdrawTestBalance,
} from "./operations/testing"; } from "./operations/testing";
import { acceptTip, prepareTip, processTip } from "./operations/tip"; import { acceptTip, prepareTip, processTip } from "./operations/tip";
import { deleteTransaction, getTransactions } from "./operations/transactions"; import { deleteTransaction, getTransactions, retryTransaction } from "./operations/transactions";
import { import {
getExchangeWithdrawalInfo, getExchangeWithdrawalInfo,
getWithdrawalDetailsForUri, getWithdrawalDetailsForUri,
@ -1194,6 +1195,11 @@ export class Wallet {
await deleteTransaction(this.ws, req.transactionId); await deleteTransaction(this.ws, req.transactionId);
return {}; return {};
} }
case "retryTransaction": {
const req = codecForRetryTransactionRequest().decode(payload);
await retryTransaction(this.ws, req.transactionId);
return {};
}
} }
throw OperationFailedError.fromCode( throw OperationFailedError.fromCode(
TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN, TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN,