wallet-core: properly separate different types of IDs

This commit is contained in:
Florian Dold 2022-10-14 22:47:11 +02:00
parent eec6695be0
commit 0c8e56c324
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
10 changed files with 78 additions and 54 deletions

View File

@ -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.

View File

@ -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;
}

View File

@ -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(":")}`;
}

View File

@ -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),
};
}

View File

@ -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),

View File

@ -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,
),

View File

@ -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),
};
}

View File

@ -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),
});
}
});

View File

@ -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),
};
}

View File

@ -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";