aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2023-06-05 18:38:17 +0200
committerFlorian Dold <florian@dold.me>2023-06-05 18:38:17 +0200
commitda927b5e48453b5bddb56944f7073619f693f526 (patch)
tree1aa84cfad016bbe665715e1ef7171dd9a3d586b5 /packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
parentbdb67c83a9d0244ba58e22f4811736722bbcb659 (diff)
downloadwallet-core-da927b5e48453b5bddb56944f7073619f693f526.tar.xz
wallet-core: handle Gone in peer-pull-debit
Diffstat (limited to 'packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts')
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts149
1 files changed, 131 insertions, 18 deletions
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
index 212d69eea..2be21c68d 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
@@ -17,8 +17,10 @@
import {
AcceptPeerPullPaymentResponse,
Amounts,
+ CoinRefreshRequest,
ConfirmPeerPullDebitRequest,
ExchangePurseDeposits,
+ HttpStatusCode,
Logger,
PeerContractTerms,
PreparePeerPullDebitRequest,
@@ -48,6 +50,8 @@ import {
PeerPullDebitRecordStatus,
PeerPullPaymentIncomingRecord,
PendingTaskType,
+ RefreshOperationStatus,
+ createRefreshGroup,
} from "../index.js";
import { assertUnreachable } from "../util/assertUnreachable.js";
import {
@@ -68,6 +72,7 @@ import {
notifyTransition,
stopLongpolling,
} from "./transactions.js";
+import { checkLogicInvariant } from "../util/invariants.js";
const logger = new Logger("pay-peer-pull-debit.ts");
@@ -104,24 +109,89 @@ async function processPeerPullDebitPendingDeposit(
logger.trace(`purse deposit payload: ${j2s(depositPayload)}`);
}
- const httpResp = await ws.http.postJson(purseDepositUrl.href, depositPayload);
- const resp = await readSuccessResponseJsonOrThrow(httpResp, codecForAny());
- logger.trace(`purse deposit response: ${j2s(resp)}`);
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.PeerPullDebit,
+ peerPullPaymentIncomingId,
+ });
- await ws.db
- .mktx((x) => [x.peerPullPaymentIncoming])
- .runReadWrite(async (tx) => {
- const pi = await tx.peerPullPaymentIncoming.get(
- peerPullPaymentIncomingId,
- );
- if (!pi) {
- throw Error("peer pull payment not found anymore");
- }
- if (pi.status === PeerPullDebitRecordStatus.PendingDeposit) {
+ const httpResp = await ws.http.fetch(purseDepositUrl.href, {
+ method: "POST",
+ body: depositPayload,
+ });
+ if (httpResp.status === HttpStatusCode.Gone) {
+ const transitionInfo = await ws.db
+ .mktx((x) => [
+ x.peerPullPaymentIncoming,
+ x.refreshGroups,
+ x.denominations,
+ x.coinAvailability,
+ x.coins,
+ ])
+ .runReadWrite(async (tx) => {
+ const pi = await tx.peerPullPaymentIncoming.get(
+ peerPullPaymentIncomingId,
+ );
+ if (!pi) {
+ throw Error("peer pull payment not found anymore");
+ }
+ if (pi.status !== PeerPullDebitRecordStatus.PendingDeposit) {
+ return;
+ }
+ const oldTxState = computePeerPullDebitTransactionState(pi);
+
+ const currency = Amounts.currencyOf(pi.totalCostEstimated);
+ const coinPubs: CoinRefreshRequest[] = [];
+
+ if (!pi.coinSel) {
+ throw Error("invalid db state");
+ }
+
+ for (let i = 0; i < pi.coinSel.coinPubs.length; i++) {
+ coinPubs.push({
+ amount: pi.coinSel.contributions[i],
+ coinPub: pi.coinSel.coinPubs[i],
+ });
+ }
+
+ const refresh = await createRefreshGroup(
+ ws,
+ tx,
+ currency,
+ coinPubs,
+ RefreshReason.AbortPeerPushDebit,
+ );
+
+ pi.status = PeerPullDebitRecordStatus.AbortingRefresh;
+ pi.abortRefreshGroupId = refresh.refreshGroupId;
+ const newTxState = computePeerPullDebitTransactionState(pi);
+ await tx.peerPullPaymentIncoming.put(pi);
+ return { oldTxState, newTxState };
+ });
+ notifyTransition(ws, transactionId, transitionInfo);
+ } else {
+ const resp = await readSuccessResponseJsonOrThrow(httpResp, codecForAny());
+ logger.trace(`purse deposit response: ${j2s(resp)}`);
+
+ const transitionInfo = await ws.db
+ .mktx((x) => [x.peerPullPaymentIncoming])
+ .runReadWrite(async (tx) => {
+ const pi = await tx.peerPullPaymentIncoming.get(
+ peerPullPaymentIncomingId,
+ );
+ if (!pi) {
+ throw Error("peer pull payment not found anymore");
+ }
+ if (pi.status !== PeerPullDebitRecordStatus.PendingDeposit) {
+ return;
+ }
+ const oldTxState = computePeerPullDebitTransactionState(pi);
pi.status = PeerPullDebitRecordStatus.DonePaid;
- }
- await tx.peerPullPaymentIncoming.put(pi);
- });
+ const newTxState = computePeerPullDebitTransactionState(pi);
+ await tx.peerPullPaymentIncoming.put(pi);
+ return { oldTxState, newTxState };
+ });
+ notifyTransition(ws, transactionId, transitionInfo);
+ }
return {
type: OperationAttemptResultType.Finished,
@@ -133,7 +203,50 @@ async function processPeerPullDebitAbortingRefresh(
ws: InternalWalletState,
peerPullInc: PeerPullPaymentIncomingRecord,
): Promise<OperationAttemptResult> {
- throw Error("not implemented");
+ const peerPullPaymentIncomingId = peerPullInc.peerPullPaymentIncomingId;
+ const abortRefreshGroupId = peerPullInc.abortRefreshGroupId;
+ checkLogicInvariant(!!abortRefreshGroupId);
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.PeerPullDebit,
+ peerPullPaymentIncomingId,
+ });
+ const transitionInfo = await ws.db
+ .mktx((x) => [x.refreshGroups, x.peerPullPaymentIncoming])
+ .runReadWrite(async (tx) => {
+ const refreshGroup = await tx.refreshGroups.get(abortRefreshGroupId);
+ let newOpState: PeerPullDebitRecordStatus | undefined;
+ if (!refreshGroup) {
+ // Maybe it got manually deleted? Means that we should
+ // just go into failed.
+ logger.warn("no aborting refresh group found for deposit group");
+ newOpState = PeerPullDebitRecordStatus.Failed;
+ } else {
+ if (refreshGroup.operationStatus === RefreshOperationStatus.Finished) {
+ newOpState = PeerPullDebitRecordStatus.Aborted;
+ } else if (
+ refreshGroup.operationStatus === RefreshOperationStatus.Failed
+ ) {
+ newOpState = PeerPullDebitRecordStatus.Failed;
+ }
+ }
+ if (newOpState) {
+ const newDg = await tx.peerPullPaymentIncoming.get(
+ peerPullPaymentIncomingId,
+ );
+ if (!newDg) {
+ return;
+ }
+ const oldTxState = computePeerPullDebitTransactionState(newDg);
+ newDg.status = newOpState;
+ const newTxState = computePeerPullDebitTransactionState(newDg);
+ await tx.peerPullPaymentIncoming.put(newDg);
+ return { oldTxState, newTxState };
+ }
+ return undefined;
+ });
+ notifyTransition(ws, transactionId, transitionInfo);
+ // FIXME: Shouldn't this be finished in some cases?!
+ return OperationAttemptResult.pendingEmpty();
}
export async function processPeerPullDebit(
@@ -158,7 +271,7 @@ export async function processPeerPullDebit(
return {
type: OperationAttemptResultType.Finished,
result: undefined,
- }
+ };
}
export async function confirmPeerPullDebit(