From 0c8e56c32457ea9b9229a8a3607fcf8e7618bc17 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 14 Oct 2022 22:47:11 +0200 Subject: wallet-core: properly separate different types of IDs --- packages/taler-util/src/wallet-types.ts | 6 ++- .../src/operations/backup/import.ts | 10 ++--- .../taler-wallet-core/src/operations/common.ts | 19 +++++++-- .../taler-wallet-core/src/operations/deposits.ts | 6 +-- .../src/operations/pay-merchant.ts | 14 +++---- .../taler-wallet-core/src/operations/pay-peer.ts | 14 +++---- packages/taler-wallet-core/src/operations/tip.ts | 4 +- .../src/operations/transactions.ts | 47 +++++++++++++--------- .../taler-wallet-core/src/operations/withdraw.ts | 8 ++-- .../src/wallet/Transaction.stories.tsx | 4 +- 10 files changed, 78 insertions(+), 54 deletions(-) diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts index cd6c2202e..d4de53972 100644 --- a/packages/taler-util/src/wallet-types.ts +++ b/packages/taler-util/src/wallet-types.ts @@ -73,12 +73,14 @@ import { VersionMatchResult } from "./libtool-version.js"; /** * Identifier for a transaction in the wallet. */ -export type TransactionIdStr = `tx:${string}:${string}`; +export type TransactionIdStr = `txn:${string}:${string}`; /** * Identifier for a pending task in the wallet. */ -export type PendingIdStr = `pd:${string}:string`; +export type PendingIdStr = `pnd:${string}:${string}`; + +export type TombstoneIdStr = `tmb:${string}:${string}`; /** * Response for the create reserve request to the wallet. diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts index 775a8ac42..3bbb7d798 100644 --- a/packages/taler-wallet-core/src/operations/backup/import.ts +++ b/packages/taler-wallet-core/src/operations/backup/import.ts @@ -63,7 +63,7 @@ import { InternalWalletState } from "../../internal-wallet-state.js"; import { assertUnreachable } from "../../util/assertUnreachable.js"; import { checkLogicInvariant } from "../../util/invariants.js"; import { GetReadOnlyAccess, GetReadWriteAccess } from "../../util/query.js"; -import { makeCoinAvailable, makeEventId, TombstoneTag } from "../common.js"; +import { makeCoinAvailable, makeTombstoneId, makeTransactionId, TombstoneTag } from "../common.js"; import { getExchangeDetails } from "../exchanges.js"; import { extractContractData } from "../pay-merchant.js"; import { provideBackupState } from "./state.js"; @@ -493,7 +493,7 @@ export async function importBackup( for (const backupWg of backupBlob.withdrawal_groups) { const reservePub = cryptoComp.reservePrivToPub[backupWg.reserve_priv]; checkLogicInvariant(!!reservePub); - const ts = makeEventId(TombstoneTag.DeleteReserve, reservePub); + const ts = makeTombstoneId(TombstoneTag.DeleteReserve, reservePub); if (tombstoneSet.has(ts)) { continue; } @@ -574,7 +574,7 @@ export async function importBackup( } for (const backupPurchase of backupBlob.purchases) { - const ts = makeEventId( + const ts = makeTombstoneId( TombstoneTag.DeletePayment, backupPurchase.proposal_id, ); @@ -705,7 +705,7 @@ export async function importBackup( } for (const backupRefreshGroup of backupBlob.refresh_groups) { - const ts = makeEventId( + const ts = makeTombstoneId( TombstoneTag.DeleteRefreshGroup, backupRefreshGroup.refresh_group_id, ); @@ -791,7 +791,7 @@ export async function importBackup( } for (const backupTip of backupBlob.tips) { - const ts = makeEventId(TombstoneTag.DeleteTip, backupTip.wallet_tip_id); + const ts = makeTombstoneId(TombstoneTag.DeleteTip, backupTip.wallet_tip_id); if (tombstoneSet.has(ts)) { continue; } diff --git a/packages/taler-wallet-core/src/operations/common.ts b/packages/taler-wallet-core/src/operations/common.ts index d69bc09f8..d17530c7f 100644 --- a/packages/taler-wallet-core/src/operations/common.ts +++ b/packages/taler-wallet-core/src/operations/common.ts @@ -25,6 +25,7 @@ import { RefreshReason, TalerErrorCode, TalerErrorDetail, + TombstoneIdStr, TransactionIdStr, TransactionType, } from "@gnu-taler/taler-util"; @@ -280,9 +281,19 @@ export enum TombstoneTag { /** * Create an event ID from the type and the primary key for the event. */ -export function makeEventId( - type: TransactionType | TombstoneTag, +export function makeTransactionId( + type: TransactionType, ...args: string[] -): string { - return type + ":" + args.map((x) => encodeURIComponent(x)).join(":"); +): TransactionIdStr { + return `txn:${type}:${args.map((x) => encodeURIComponent(x)).join(":")}`; +} + +/** + * Create an event ID from the type and the primary key for the event. + */ +export function makeTombstoneId( + type: TombstoneTag, + ...args: string[] +): TombstoneIdStr { + return `tmb:${type}:${args.map((x) => encodeURIComponent(x)).join(":")}`; } diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts index 1f7d05d29..7e87dafb8 100644 --- a/packages/taler-wallet-core/src/operations/deposits.ts +++ b/packages/taler-wallet-core/src/operations/deposits.ts @@ -53,7 +53,7 @@ import { import { InternalWalletState } from "../internal-wallet-state.js"; import { readSuccessResponseJsonOrThrow } from "../util/http.js"; import { OperationAttemptResult } from "../util/retries.js"; -import { makeEventId, spendCoins } from "./common.js"; +import { makeTransactionId, spendCoins } from "./common.js"; import { getExchangeDetails } from "./exchanges.js"; import { extractContractData, @@ -495,7 +495,7 @@ export async function createDepositGroup( ]) .runReadWrite(async (tx) => { await spendCoins(ws, tx, { - allocationId: `deposit-group:${depositGroup.depositGroupId}`, + allocationId: `txn:deposit:${depositGroup.depositGroupId}`, coinPubs: payCoinSel.coinPubs, contributions: payCoinSel.coinContributions, refreshReason: RefreshReason.PayDeposit, @@ -505,7 +505,7 @@ export async function createDepositGroup( return { depositGroupId: depositGroupId, - transactionId: makeEventId(TransactionType.Deposit, depositGroupId), + transactionId: makeTransactionId(TransactionType.Deposit, depositGroupId), }; } diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts index 233038997..6b14b60c6 100644 --- a/packages/taler-wallet-core/src/operations/pay-merchant.ts +++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts @@ -122,7 +122,7 @@ import { scheduleRetry, } from "../util/retries.js"; import { - makeEventId, + makeTransactionId, spendCoins, storeOperationError, storeOperationPending, @@ -858,7 +858,7 @@ async function handleInsufficientFunds( payInfo.payCoinSelectionUid = encodeCrock(getRandomBytes(32)); await tx.purchases.put(p); await spendCoins(ws, tx, { - allocationId: `tx:proposal:${p.proposalId}`, + allocationId: `txn:proposal:${p.proposalId}`, coinPubs: payInfo.payCoinSelection.coinPubs, contributions: payInfo.payCoinSelection.coinContributions, refreshReason: RefreshReason.PayMerchant, @@ -1554,7 +1554,7 @@ export async function runPayForConfirmPay( return { type: ConfirmPayResultType.Done, contractTerms: d.contractTermsRaw, - transactionId: makeEventId(TransactionType.Payment, proposalId), + transactionId: makeTransactionId(TransactionType.Payment, proposalId), }; } case OperationAttemptResultType.Error: { @@ -1580,7 +1580,7 @@ export async function runPayForConfirmPay( return { type: ConfirmPayResultType.Pending, lastError: opRetry?.lastError, - transactionId: makeEventId(TransactionType.Payment, proposalId), + transactionId: makeTransactionId(TransactionType.Payment, proposalId), }; } else { // FIXME: allocate error code! @@ -1599,7 +1599,7 @@ export async function runPayForConfirmPay( ); return { type: ConfirmPayResultType.Pending, - transactionId: makeEventId(TransactionType.Payment, proposalId), + transactionId: makeTransactionId(TransactionType.Payment, proposalId), lastError: undefined, }; case OperationAttemptResultType.Longpoll: @@ -1735,7 +1735,7 @@ export async function confirmPay( p.purchaseStatus = PurchaseStatus.Paying; await tx.purchases.put(p); await spendCoins(ws, tx, { - allocationId: `tx:proposal:${p.proposalId}`, + allocationId: `txn:proposal:${p.proposalId}`, coinPubs: coinSelection.coinPubs, contributions: coinSelection.coinContributions, refreshReason: RefreshReason.PayMerchant, @@ -2549,7 +2549,7 @@ export async function applyRefundFromPurchaseId( return { contractTermsHash: download.contractData.contractTermsHash, proposalId: purchase.proposalId, - transactionId: makeEventId(TransactionType.Payment, proposalId), //FIXME: can we have the tx id of the refund + transactionId: makeTransactionId(TransactionType.Payment, proposalId), //FIXME: can we have the tx id of the refund amountEffectivePaid: Amounts.stringify(summary.amountEffectivePaid), amountRefundGone: Amounts.stringify(summary.amountRefundGone), amountRefundGranted: Amounts.stringify(summary.amountRefundGranted), diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts b/packages/taler-wallet-core/src/operations/pay-peer.ts index e9185a9d4..8bce887c0 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer.ts @@ -73,7 +73,7 @@ import { InternalWalletState } from "../internal-wallet-state.js"; import { readSuccessResponseJsonOrThrow } from "../util/http.js"; import { checkDbInvariant } from "../util/invariants.js"; import { GetReadOnlyAccess } from "../util/query.js"; -import { spendCoins, makeEventId } from "../operations/common.js"; +import { spendCoins, makeTransactionId } from "../operations/common.js"; import { updateExchangeFromUrl } from "./exchanges.js"; import { internalCreateWithdrawalGroup } from "./withdraw.js"; @@ -261,7 +261,7 @@ export async function initiatePeerToPeerPush( } await spendCoins(ws, tx, { - allocationId: `peer-push:${pursePair.pub}`, + allocationId: `txn:peer-push-debit:${pursePair.pub}`, coinPubs: sel.coins.map((x) => x.coinPub), contributions: sel.coins.map((x) => Amounts.parseOrThrow(x.contribution), @@ -340,7 +340,7 @@ export async function initiatePeerToPeerPush( exchangeBaseUrl: coinSelRes.exchangeBaseUrl, contractPriv: econtractResp.contractPriv, }), - transactionId: makeEventId(TransactionType.PeerPushDebit, pursePair.pub), + transactionId: makeTransactionId(TransactionType.PeerPushDebit, pursePair.pub), }; } @@ -551,7 +551,7 @@ export async function acceptPeerPushPayment( }); return { - transactionId: makeEventId( + transactionId: makeTransactionId( TransactionType.PeerPushCredit, wg.withdrawalGroupId, ), @@ -596,7 +596,7 @@ export async function acceptPeerPullPayment( } await spendCoins(ws, tx, { - allocationId: `peer-pull:${req.peerPullPaymentIncomingId}`, + allocationId: `txn:peer-pull-debit:${req.peerPullPaymentIncomingId}`, coinPubs: sel.coins.map((x) => x.coinPub), contributions: sel.coins.map((x) => Amounts.parseOrThrow(x.contribution), @@ -643,7 +643,7 @@ export async function acceptPeerPullPayment( logger.trace(`purse deposit response: ${j2s(resp)}`); return { - transactionId: makeEventId( + transactionId: makeTransactionId( TransactionType.PeerPullDebit, req.peerPullPaymentIncomingId, ), @@ -839,7 +839,7 @@ export async function initiatePeerRequestForPay( exchangeBaseUrl: req.exchangeBaseUrl, contractPriv: econtractResp.contractPriv, }), - transactionId: makeEventId( + transactionId: makeTransactionId( TransactionType.PeerPullCredit, wg.withdrawalGroupId, ), diff --git a/packages/taler-wallet-core/src/operations/tip.ts b/packages/taler-wallet-core/src/operations/tip.ts index a83867f55..b74e1182a 100644 --- a/packages/taler-wallet-core/src/operations/tip.ts +++ b/packages/taler-wallet-core/src/operations/tip.ts @@ -56,7 +56,7 @@ import { OperationAttemptResult, OperationAttemptResultType, } from "../util/retries.js"; -import { makeCoinAvailable, makeEventId } from "./common.js"; +import { makeCoinAvailable, makeTransactionId } from "./common.js"; import { updateExchangeFromUrl } from "./exchanges.js"; import { getCandidateWithdrawalDenoms, @@ -366,6 +366,6 @@ export async function acceptTip( await processTip(ws, tipId); } return { - transactionId: makeEventId(TransactionType.Tip, tipId), + transactionId: makeTransactionId(TransactionType.Tip, tipId), }; } diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts index 6955d7b17..9a34379a9 100644 --- a/packages/taler-wallet-core/src/operations/transactions.ts +++ b/packages/taler-wallet-core/src/operations/transactions.ts @@ -53,7 +53,7 @@ import { import { InternalWalletState } from "../internal-wallet-state.js"; import { checkDbInvariant } from "../util/invariants.js"; import { RetryTags } from "../util/retries.js"; -import { makeEventId, TombstoneTag } from "./common.js"; +import { makeTombstoneId, makeTransactionId, TombstoneTag } from "./common.js"; import { processDepositGroup } from "./deposits.js"; import { getExchangeDetails } from "./exchanges.js"; import { @@ -193,7 +193,7 @@ export async function getTransactionById( const filteredRefunds = await Promise.all( Object.values(purchase.refunds).map(async (r) => { const t = await tx.tombstones.get( - makeEventId( + makeTombstoneId( TombstoneTag.DeleteRefund, purchase.proposalId, `${r.executionTime.t_s}`, @@ -271,7 +271,7 @@ export async function getTransactionById( if (!theRefund) throw Error("not found"); const t = await tx.tombstones.get( - makeEventId( + makeTombstoneId( TombstoneTag.DeleteRefund, purchase.proposalId, executionTimeStr, @@ -338,7 +338,10 @@ function buildTransactionForPushPaymentDebit( exchangeBaseUrl: pi.exchangeBaseUrl, contractPriv: pi.contractPriv, }), - transactionId: makeEventId(TransactionType.PeerPushDebit, pi.pursePub), + transactionId: makeTransactionId( + TransactionType.PeerPushDebit, + pi.pursePub, + ), ...(ort?.lastError ? { error: ort.lastError } : {}), }; } @@ -359,7 +362,7 @@ function buildTransactionForPullPaymentDebit( summary: pi.contractTerms.summary, }, timestamp: pi.timestampCreated, - transactionId: makeEventId( + transactionId: makeTransactionId( TransactionType.PeerPullDebit, pi.peerPullPaymentIncomingId, ), @@ -388,7 +391,7 @@ function buildTransactionForPullPaymentCredit( exchangeBaseUrl: wsr.exchangeBaseUrl, contractPriv: wsr.wgInfo.contractPriv, }), - transactionId: makeEventId( + transactionId: makeTransactionId( TransactionType.PeerPullCredit, wsr.withdrawalGroupId, ), @@ -414,7 +417,7 @@ function buildTransactionForPushPaymentCredit( }, pending: !wsr.timestampFinish, timestamp: wsr.timestampStart, - transactionId: makeEventId( + transactionId: makeTransactionId( TransactionType.PeerPushCredit, wsr.withdrawalGroupId, ), @@ -443,7 +446,7 @@ function buildTransactionForBankIntegratedWithdraw( exchangeBaseUrl: wsr.exchangeBaseUrl, pending: !wsr.timestampFinish, timestamp: wsr.timestampStart, - transactionId: makeEventId( + transactionId: makeTransactionId( TransactionType.Withdrawal, wsr.withdrawalGroupId, ), @@ -483,7 +486,7 @@ function buildTransactionForManualWithdraw( exchangeBaseUrl: withdrawalGroup.exchangeBaseUrl, pending: !withdrawalGroup.timestampFinish, timestamp: withdrawalGroup.timestampStart, - transactionId: makeEventId( + transactionId: makeTransactionId( TransactionType.Withdrawal, withdrawalGroup.withdrawalGroupId, ), @@ -504,7 +507,10 @@ function buildTransactionForDeposit( frozen: false, timestamp: dg.timestampCreated, targetPaytoUri: dg.wire.payto_uri, - transactionId: makeEventId(TransactionType.Deposit, dg.depositGroupId), + transactionId: makeTransactionId( + TransactionType.Deposit, + dg.depositGroupId, + ), depositGroupId: dg.depositGroupId, ...(ort?.lastError ? { error: ort.lastError } : {}), }; @@ -523,7 +529,10 @@ function buildTransactionForTip( pending: !tipRecord.pickedUpTimestamp, frozen: false, timestamp: tipRecord.acceptedTimestamp, - transactionId: makeEventId(TransactionType.Tip, tipRecord.walletTipId), + transactionId: makeTransactionId( + TransactionType.Tip, + tipRecord.walletTipId, + ), merchantBaseUrl: tipRecord.merchantBaseUrl, ...(ort?.lastError ? { error: ort.lastError } : {}), }; @@ -606,11 +615,11 @@ async function buildTransactionForRefund( return { type: TransactionType.Refund, info, - refundedTransactionId: makeEventId( + refundedTransactionId: makeTransactionId( TransactionType.Payment, purchaseRecord.proposalId, ), - transactionId: makeEventId( + transactionId: makeTransactionId( TransactionType.Refund, purchaseRecord.proposalId, `${refundInfo.executionTime.t_s}`, @@ -667,7 +676,7 @@ async function buildTransactionForPurchase( amountEffective: Amounts.stringify(r.amountAppliedEffective), amountRaw: Amounts.stringify(r.amountAppliedRaw), timestamp: r.executionTime, - transactionId: makeEventId( + transactionId: makeTransactionId( TransactionType.Refund, purchaseRecord.proposalId, `${r.executionTime.t_s}`, @@ -694,7 +703,7 @@ async function buildTransactionForPurchase( pending: purchaseRecord.purchaseStatus === PurchaseStatus.Paying, refunds, timestamp, - transactionId: makeEventId( + transactionId: makeTransactionId( TransactionType.Payment, purchaseRecord.proposalId, ), @@ -854,7 +863,7 @@ export async function getTransactions( const filteredRefunds = await Promise.all( Object.values(purchase.refunds).map(async (r) => { const t = await tx.tombstones.get( - makeEventId( + makeTombstoneId( TombstoneTag.DeleteRefund, purchase.proposalId, `${r.executionTime.t_s}`, @@ -1077,7 +1086,7 @@ export async function deleteTransaction( // This should just influence the history view, // but won't delete any actual refund information. await tx.tombstones.put({ - id: makeEventId( + id: makeTombstoneId( TombstoneTag.DeleteRefund, proposalId, executionTimeStr, @@ -1096,7 +1105,7 @@ export async function deleteTransaction( if (debit) { await tx.peerPullPaymentIncoming.delete(peerPullPaymentIncomingId); await tx.tombstones.put({ - id: makeEventId( + id: makeTombstoneId( TombstoneTag.DeletePeerPullDebit, peerPullPaymentIncomingId, ), @@ -1112,7 +1121,7 @@ export async function deleteTransaction( if (debit) { await tx.peerPushPaymentInitiations.delete(pursePub); await tx.tombstones.put({ - id: makeEventId(TombstoneTag.DeletePeerPushDebit, pursePub), + id: makeTombstoneId(TombstoneTag.DeletePeerPushDebit, pursePub), }); } }); diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index 700c4620c..2932cfa5f 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -111,7 +111,7 @@ import { WALLET_EXCHANGE_PROTOCOL_VERSION, } from "../versions.js"; import { - makeEventId, + makeTransactionId, storeOperationError, storeOperationPending, } from "./common.js"; @@ -1797,7 +1797,7 @@ export async function acceptWithdrawalFromUri( return { reservePub: existingWithdrawalGroup.reservePub, confirmTransferUrl: url, - transactionId: makeEventId( + transactionId: makeTransactionId( TransactionType.Withdrawal, existingWithdrawalGroup.withdrawalGroupId, ), @@ -1858,7 +1858,7 @@ export async function acceptWithdrawalFromUri( return { reservePub: withdrawalGroup.reservePub, confirmTransferUrl: withdrawInfo.confirmTransferUrl, - transactionId: makeEventId(TransactionType.Withdrawal, withdrawalGroupId), + transactionId: makeTransactionId(TransactionType.Withdrawal, withdrawalGroupId), }; } @@ -1919,6 +1919,6 @@ export async function createManualWithdrawal( return { reservePub: withdrawalGroup.reservePub, exchangePaytoUris: exchangePaytoUris, - transactionId: makeEventId(TransactionType.Withdrawal, withdrawalGroupId), + transactionId: makeTransactionId(TransactionType.Withdrawal, withdrawalGroupId), }; } diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx index dc8f067a5..812ef93c9 100644 --- a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx @@ -60,7 +60,9 @@ const commonTransaction = { amountEffective: "KUDOS:9.2", pending: false, timestamp: TalerProtocolTimestamp.now(), - transactionId: "12", + transactionId: "txn:deposit:12", + frozen: false, + type: TransactionType.Deposit, } as TransactionCommon; import merchantIcon from "../../static-dev/merchant-icon.jpeg"; -- cgit v1.2.3