wallet-core: implement cancelAbortingTransaction for deposit groups
This commit is contained in:
parent
8624d798b7
commit
fe8749c3f8
@ -1713,6 +1713,16 @@ export const codecForAcceptTipRequest = (): Codec<AcceptTipRequest> =>
|
|||||||
.property("walletTipId", codecForString())
|
.property("walletTipId", codecForString())
|
||||||
.build("AcceptTipRequest");
|
.build("AcceptTipRequest");
|
||||||
|
|
||||||
|
export interface CancelAbortingTransactionRequest {
|
||||||
|
transactionId: TransactionIdStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const codecForCancelAbortingTransactionRequest =
|
||||||
|
(): Codec<CancelAbortingTransactionRequest> =>
|
||||||
|
buildCodecForObject<CancelAbortingTransactionRequest>()
|
||||||
|
.property("transactionId", codecForTransactionIdStr())
|
||||||
|
.build("CancelAbortingTransactionRequest");
|
||||||
|
|
||||||
export interface SuspendTransactionRequest {
|
export interface SuspendTransactionRequest {
|
||||||
transactionId: TransactionIdStr;
|
transactionId: TransactionIdStr;
|
||||||
}
|
}
|
||||||
|
@ -1628,11 +1628,15 @@ export interface BackupProviderRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum DepositOperationStatus {
|
export enum DepositOperationStatus {
|
||||||
Finished = 50 /* OperationStatusRange.DORMANT_START */,
|
Pending = 10,
|
||||||
Suspended = 51 /* OperationStatusRange.DORMANT_START + 1 */,
|
Aborting = 11,
|
||||||
Aborted = 52 /* OperationStatusRange.DORMANT_START + 2 */,
|
|
||||||
Pending = 10 /* OperationStatusRange.ACTIVE_START */,
|
Suspended = 20,
|
||||||
Aborting = 11 /* OperationStatusRange.ACTIVE_START + 1 */,
|
SuspendedAborting = 21,
|
||||||
|
|
||||||
|
Finished = 50,
|
||||||
|
Failed = 51,
|
||||||
|
Aborted = 52,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DepositTrackingInfo {
|
export interface DepositTrackingInfo {
|
||||||
|
@ -167,6 +167,14 @@ export function computeDepositTransactionStatus(
|
|||||||
return {
|
return {
|
||||||
major: TransactionMajorState.Aborted,
|
major: TransactionMajorState.Aborted,
|
||||||
}
|
}
|
||||||
|
case DepositOperationStatus.Failed:
|
||||||
|
return {
|
||||||
|
major: TransactionMajorState.Failed,
|
||||||
|
}
|
||||||
|
case DepositOperationStatus.SuspendedAborting:
|
||||||
|
return {
|
||||||
|
major: TransactionMajorState.SuspendedAborting,
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw Error(`unexpected deposit group state (${dg.operationStatus})`);
|
throw Error(`unexpected deposit group state (${dg.operationStatus})`);
|
||||||
}
|
}
|
||||||
@ -184,7 +192,7 @@ export async function suspendDepositGroup(
|
|||||||
tag: PendingTaskType.Deposit,
|
tag: PendingTaskType.Deposit,
|
||||||
depositGroupId,
|
depositGroupId,
|
||||||
});
|
});
|
||||||
let res = await ws.db
|
const transitionInfo = await ws.db
|
||||||
.mktx((x) => [x.depositGroups])
|
.mktx((x) => [x.depositGroups])
|
||||||
.runReadWrite(async (tx) => {
|
.runReadWrite(async (tx) => {
|
||||||
const dg = await tx.depositGroups.get(depositGroupId);
|
const dg = await tx.depositGroups.get(depositGroupId);
|
||||||
@ -212,14 +220,7 @@ export async function suspendDepositGroup(
|
|||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
stopLongpolling(ws, retryTag);
|
stopLongpolling(ws, retryTag);
|
||||||
if (res) {
|
notifyTransition(ws, transactionId, transitionInfo);
|
||||||
ws.notify({
|
|
||||||
type: NotificationType.TransactionStateTransition,
|
|
||||||
transactionId,
|
|
||||||
oldTxState: res.oldTxState,
|
|
||||||
newTxState: res.newTxState,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resumeDepositGroup(
|
export async function resumeDepositGroup(
|
||||||
@ -230,7 +231,7 @@ export async function resumeDepositGroup(
|
|||||||
tag: TransactionType.Deposit,
|
tag: TransactionType.Deposit,
|
||||||
depositGroupId,
|
depositGroupId,
|
||||||
});
|
});
|
||||||
let res = await ws.db
|
const transitionInfo = await ws.db
|
||||||
.mktx((x) => [x.depositGroups])
|
.mktx((x) => [x.depositGroups])
|
||||||
.runReadWrite(async (tx) => {
|
.runReadWrite(async (tx) => {
|
||||||
const dg = await tx.depositGroups.get(depositGroupId);
|
const dg = await tx.depositGroups.get(depositGroupId);
|
||||||
@ -258,14 +259,7 @@ export async function resumeDepositGroup(
|
|||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
ws.workAvailable.trigger();
|
ws.workAvailable.trigger();
|
||||||
if (res) {
|
notifyTransition(ws, transactionId, transitionInfo);
|
||||||
ws.notify({
|
|
||||||
type: NotificationType.TransactionStateTransition,
|
|
||||||
transactionId,
|
|
||||||
oldTxState: res.oldTxState,
|
|
||||||
newTxState: res.newTxState,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function abortDepositGroup(
|
export async function abortDepositGroup(
|
||||||
@ -280,7 +274,7 @@ export async function abortDepositGroup(
|
|||||||
tag: PendingTaskType.Deposit,
|
tag: PendingTaskType.Deposit,
|
||||||
depositGroupId,
|
depositGroupId,
|
||||||
});
|
});
|
||||||
let res = await ws.db
|
const transitionInfo = await ws.db
|
||||||
.mktx((x) => [x.depositGroups])
|
.mktx((x) => [x.depositGroups])
|
||||||
.runReadWrite(async (tx) => {
|
.runReadWrite(async (tx) => {
|
||||||
const dg = await tx.depositGroups.get(depositGroupId);
|
const dg = await tx.depositGroups.get(depositGroupId);
|
||||||
@ -311,14 +305,48 @@ export async function abortDepositGroup(
|
|||||||
stopLongpolling(ws, retryTag);
|
stopLongpolling(ws, retryTag);
|
||||||
// Need to process the operation again.
|
// Need to process the operation again.
|
||||||
ws.workAvailable.trigger();
|
ws.workAvailable.trigger();
|
||||||
if (res) {
|
notifyTransition(ws, transactionId, transitionInfo);
|
||||||
ws.notify({
|
|
||||||
type: NotificationType.TransactionStateTransition,
|
|
||||||
transactionId,
|
|
||||||
oldTxState: res.oldTxState,
|
|
||||||
newTxState: res.newTxState,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function cancelAbortingDepositGroup(
|
||||||
|
ws: InternalWalletState,
|
||||||
|
depositGroupId: string,
|
||||||
|
): Promise<void> {
|
||||||
|
const transactionId = constructTransactionIdentifier({
|
||||||
|
tag: TransactionType.Deposit,
|
||||||
|
depositGroupId,
|
||||||
|
});
|
||||||
|
const retryTag = constructTaskIdentifier({
|
||||||
|
tag: PendingTaskType.Deposit,
|
||||||
|
depositGroupId,
|
||||||
|
});
|
||||||
|
const transitionInfo = await ws.db
|
||||||
|
.mktx((x) => [x.depositGroups])
|
||||||
|
.runReadWrite(async (tx) => {
|
||||||
|
const dg = await tx.depositGroups.get(depositGroupId);
|
||||||
|
if (!dg) {
|
||||||
|
logger.warn(
|
||||||
|
`can't cancel aborting deposit group, depositGroupId=${depositGroupId} not found`,
|
||||||
|
);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const oldState = computeDepositTransactionStatus(dg);
|
||||||
|
switch (dg.operationStatus) {
|
||||||
|
case DepositOperationStatus.SuspendedAborting:
|
||||||
|
case DepositOperationStatus.Aborting: {
|
||||||
|
dg.operationStatus = DepositOperationStatus.Failed;
|
||||||
|
await tx.depositGroups.put(dg);
|
||||||
|
return {
|
||||||
|
oldTxState: oldState,
|
||||||
|
newTxState: computeDepositTransactionStatus(dg),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
// FIXME: Also cancel ongoing work (via cancellation token, once implemented)
|
||||||
|
stopLongpolling(ws, retryTag);
|
||||||
|
notifyTransition(ws, transactionId, transitionInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteDepositGroup(
|
export async function deleteDepositGroup(
|
||||||
|
@ -75,6 +75,7 @@ import {
|
|||||||
} from "./common.js";
|
} from "./common.js";
|
||||||
import {
|
import {
|
||||||
abortDepositGroup,
|
abortDepositGroup,
|
||||||
|
cancelAbortingDepositGroup,
|
||||||
computeDepositTransactionStatus,
|
computeDepositTransactionStatus,
|
||||||
processDepositGroup,
|
processDepositGroup,
|
||||||
resumeDepositGroup,
|
resumeDepositGroup,
|
||||||
@ -1401,6 +1402,23 @@ export async function suspendTransaction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function cancelAbortingTransaction(
|
||||||
|
ws: InternalWalletState,
|
||||||
|
transactionId: string,
|
||||||
|
): Promise<void> {
|
||||||
|
const tx = parseTransactionIdentifier(transactionId);
|
||||||
|
if (!tx) {
|
||||||
|
throw Error("invalid transaction ID");
|
||||||
|
}
|
||||||
|
switch (tx.tag) {
|
||||||
|
case TransactionType.Deposit:
|
||||||
|
await cancelAbortingDepositGroup(ws, tx.depositGroupId);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
logger.warn(`unable to suspend transaction of type '${tx.tag}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resume a suspended transaction.
|
* Resume a suspended transaction.
|
||||||
*/
|
*/
|
||||||
|
@ -65,6 +65,7 @@ import {
|
|||||||
codecForApplyDevExperiment,
|
codecForApplyDevExperiment,
|
||||||
codecForApplyRefundFromPurchaseIdRequest,
|
codecForApplyRefundFromPurchaseIdRequest,
|
||||||
codecForApplyRefundRequest,
|
codecForApplyRefundRequest,
|
||||||
|
codecForCancelAbortingTransactionRequest,
|
||||||
codecForCheckPeerPullPaymentRequest,
|
codecForCheckPeerPullPaymentRequest,
|
||||||
codecForCheckPeerPushDebitRequest,
|
codecForCheckPeerPushDebitRequest,
|
||||||
codecForConfirmPayRequest,
|
codecForConfirmPayRequest,
|
||||||
@ -231,6 +232,7 @@ import {
|
|||||||
import { acceptTip, prepareTip, processTip } from "./operations/tip.js";
|
import { acceptTip, prepareTip, processTip } from "./operations/tip.js";
|
||||||
import {
|
import {
|
||||||
abortTransaction,
|
abortTransaction,
|
||||||
|
cancelAbortingTransaction,
|
||||||
deleteTransaction,
|
deleteTransaction,
|
||||||
getTransactionById,
|
getTransactionById,
|
||||||
getTransactions,
|
getTransactions,
|
||||||
@ -1229,6 +1231,11 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
|
|||||||
await suspendTransaction(ws, req.transactionId);
|
await suspendTransaction(ws, req.transactionId);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
case WalletApiOperation.CancelAbortingTransaction: {
|
||||||
|
const req = codecForCancelAbortingTransactionRequest().decode(payload);
|
||||||
|
await cancelAbortingTransaction(ws, req.transactionId);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
case WalletApiOperation.ResumeTransaction: {
|
case WalletApiOperation.ResumeTransaction: {
|
||||||
const req = codecForResumeTransaction().decode(payload);
|
const req = codecForResumeTransaction().decode(payload);
|
||||||
await resumeTransaction(ws, req.transactionId);
|
await resumeTransaction(ws, req.transactionId);
|
||||||
|
Loading…
Reference in New Issue
Block a user