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 17:58:20 +0200
committerFlorian Dold <florian@dold.me>2023-06-05 17:58:25 +0200
commit9fca44893a6f7fcee5c828da5fc10e7d76592b5d (patch)
tree634830c7a769302d5e107f2aee323c3f705cf113 /packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
parent6e7c88a62073082b28ef563561d08f56acc0b017 (diff)
downloadwallet-core-9fca44893a6f7fcee5c828da5fc10e7d76592b5d.tar.xz
wallet-core: handle more p2p abort cases nicely
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.ts127
1 files changed, 112 insertions, 15 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 fdec42bbd..212d69eea 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
@@ -15,55 +15,152 @@
*/
import {
- ConfirmPeerPullDebitRequest,
AcceptPeerPullPaymentResponse,
Amounts,
- j2s,
- TalerError,
- TalerErrorCode,
- TransactionType,
- RefreshReason,
+ ConfirmPeerPullDebitRequest,
+ ExchangePurseDeposits,
Logger,
PeerContractTerms,
PreparePeerPullDebitRequest,
PreparePeerPullDebitResponse,
+ RefreshReason,
+ TalerError,
+ TalerErrorCode,
TalerPreciseTimestamp,
+ TransactionAction,
+ TransactionMajorState,
+ TransactionMinorState,
+ TransactionState,
+ TransactionType,
+ codecForAny,
codecForExchangeGetContractResponse,
codecForPeerContractTerms,
decodeCrock,
eddsaGetPublic,
encodeCrock,
getRandomBytes,
+ j2s,
parsePayPullUri,
- TransactionAction,
- TransactionMajorState,
- TransactionMinorState,
- TransactionState,
} from "@gnu-taler/taler-util";
+import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
import {
InternalWalletState,
PeerPullDebitRecordStatus,
PeerPullPaymentIncomingRecord,
PendingTaskType,
} from "../index.js";
-import { TaskIdentifiers, constructTaskIdentifier } from "../util/retries.js";
-import { spendCoins, runOperationWithErrorReporting } from "./common.js";
+import { assertUnreachable } from "../util/assertUnreachable.js";
+import {
+ OperationAttemptResult,
+ OperationAttemptResultType,
+ TaskIdentifiers,
+ constructTaskIdentifier,
+} from "../util/retries.js";
+import { runOperationWithErrorReporting, spendCoins } from "./common.js";
import {
codecForExchangePurseStatus,
getTotalPeerPaymentCost,
+ queryCoinInfosForSelection,
selectPeerCoins,
} from "./pay-peer-common.js";
-import { processPeerPullDebit } from "./pay-peer-push-credit.js";
import {
constructTransactionIdentifier,
notifyTransition,
stopLongpolling,
} from "./transactions.js";
-import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
-import { assertUnreachable } from "../util/assertUnreachable.js";
const logger = new Logger("pay-peer-pull-debit.ts");
+async function processPeerPullDebitPendingDeposit(
+ ws: InternalWalletState,
+ peerPullInc: PeerPullPaymentIncomingRecord,
+): Promise<OperationAttemptResult> {
+ const peerPullPaymentIncomingId = peerPullInc.peerPullPaymentIncomingId;
+ const pursePub = peerPullInc.pursePub;
+
+ const coinSel = peerPullInc.coinSel;
+ if (!coinSel) {
+ throw Error("invalid state, no coins selected");
+ }
+
+ const coins = await queryCoinInfosForSelection(ws, coinSel);
+
+ const depositSigsResp = await ws.cryptoApi.signPurseDeposits({
+ exchangeBaseUrl: peerPullInc.exchangeBaseUrl,
+ pursePub: peerPullInc.pursePub,
+ coins,
+ });
+
+ const purseDepositUrl = new URL(
+ `purses/${pursePub}/deposit`,
+ peerPullInc.exchangeBaseUrl,
+ );
+
+ const depositPayload: ExchangePurseDeposits = {
+ deposits: depositSigsResp.deposits,
+ };
+
+ if (logger.shouldLogTrace()) {
+ 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)}`);
+
+ 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) {
+ pi.status = PeerPullDebitRecordStatus.DonePaid;
+ }
+ await tx.peerPullPaymentIncoming.put(pi);
+ });
+
+ return {
+ type: OperationAttemptResultType.Finished,
+ result: undefined,
+ };
+}
+
+async function processPeerPullDebitAbortingRefresh(
+ ws: InternalWalletState,
+ peerPullInc: PeerPullPaymentIncomingRecord,
+): Promise<OperationAttemptResult> {
+ throw Error("not implemented");
+}
+
+export async function processPeerPullDebit(
+ ws: InternalWalletState,
+ peerPullPaymentIncomingId: string,
+): Promise<OperationAttemptResult> {
+ const peerPullInc = await ws.db
+ .mktx((x) => [x.peerPullPaymentIncoming])
+ .runReadOnly(async (tx) => {
+ return tx.peerPullPaymentIncoming.get(peerPullPaymentIncomingId);
+ });
+ if (!peerPullInc) {
+ throw Error("peer pull debit not found");
+ }
+
+ switch (peerPullInc.status) {
+ case PeerPullDebitRecordStatus.PendingDeposit:
+ return await processPeerPullDebitPendingDeposit(ws, peerPullInc);
+ case PeerPullDebitRecordStatus.AbortingRefresh:
+ return await processPeerPullDebitAbortingRefresh(ws, peerPullInc);
+ }
+ return {
+ type: OperationAttemptResultType.Finished,
+ result: undefined,
+ }
+}
+
export async function confirmPeerPullDebit(
ws: InternalWalletState,
req: ConfirmPeerPullDebitRequest,