wallet-core: remove deprecated txid parsing

This commit is contained in:
Florian Dold 2023-05-24 14:09:25 +02:00
parent 4627c0781c
commit f14c7e5f2a
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
6 changed files with 417 additions and 410 deletions

View File

@ -362,42 +362,6 @@ export enum TombstoneTag {
DeletePeerPushCredit = "delete-peer-push-credit", DeletePeerPushCredit = "delete-peer-push-credit",
} }
/**
* Create an event ID from the type and the primary key for the event.
*
* @deprecated use constructTransactionIdentifier instead
*/
export function makeTransactionId(
type: TransactionType,
...args: string[]
): string {
return `txn:${type}:${args.map((x) => encodeURIComponent(x)).join(":")}`;
}
export function parseId(
idType: "txn" | "tmb" | "any",
txId: string,
): {
type: TransactionType;
args: string[];
} {
const txnParts = txId.split(":");
if (txnParts.length < 3) {
throw Error("id should have al least 3 parts separated by ':'");
}
const [prefix, typeStr, ...args] = txnParts;
const type = typeStr as TransactionType;
if (idType != "any" && prefix !== idType) {
throw Error(`id should start with ${idType}`);
}
if (args.length === 0) {
throw Error("id should have one or more arguments");
}
return { type, args };
}
/** /**
* Create an event ID from the type and the primary key for the event. * Create an event ID from the type and the primary key for the event.

View File

@ -118,7 +118,6 @@ import {
TaskIdentifiers, TaskIdentifiers,
} from "../util/retries.js"; } from "../util/retries.js";
import { import {
makeTransactionId,
runLongpollAsync, runLongpollAsync,
runOperationWithErrorReporting, runOperationWithErrorReporting,
spendCoins, spendCoins,

View File

@ -59,7 +59,7 @@ import {
OperationAttemptResult, OperationAttemptResult,
OperationAttemptResultType, OperationAttemptResultType,
} from "../util/retries.js"; } from "../util/retries.js";
import { makeCoinAvailable, makeTransactionId } from "./common.js"; import { makeCoinAvailable } from "./common.js";
import { updateExchangeFromUrl } from "./exchanges.js"; import { updateExchangeFromUrl } from "./exchanges.js";
import { import {
getCandidateWithdrawalDenoms, getCandidateWithdrawalDenoms,

View File

@ -67,7 +67,6 @@ import {
PeerPushPaymentIncomingStatus, PeerPushPaymentIncomingStatus,
PeerPullPaymentInitiationRecord, PeerPullPaymentInitiationRecord,
RefundGroupRecord, RefundGroupRecord,
ContractTermsRecord,
} from "../db.js"; } from "../db.js";
import { InternalWalletState } from "../internal-wallet-state.js"; import { InternalWalletState } from "../internal-wallet-state.js";
import { PendingTaskType } from "../pending-types.js"; import { PendingTaskType } from "../pending-types.js";
@ -76,8 +75,6 @@ import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
import { constructTaskIdentifier, TaskIdentifiers } from "../util/retries.js"; import { constructTaskIdentifier, TaskIdentifiers } from "../util/retries.js";
import { import {
makeTombstoneId, makeTombstoneId,
makeTransactionId,
parseId,
resetOperationTimeout, resetOperationTimeout,
runOperationWithErrorReporting, runOperationWithErrorReporting,
TombstoneTag, TombstoneTag,
@ -164,9 +161,15 @@ export async function getTransactionById(
ws: InternalWalletState, ws: InternalWalletState,
req: TransactionByIdRequest, req: TransactionByIdRequest,
): Promise<Transaction> { ): Promise<Transaction> {
const { type, args: rest } = parseId("txn", req.transactionId); const parsedTx = parseTransactionIdentifier(req.transactionId);
if (type === TransactionType.Withdrawal) {
const withdrawalGroupId = rest[0]; if (!parsedTx) {
throw Error("invalid transaction ID");
}
switch (parsedTx.tag) {
case TransactionType.Withdrawal: {
const withdrawalGroupId = parsedTx.withdrawalGroupId;
return await ws.db return await ws.db
.mktx((x) => [ .mktx((x) => [
x.withdrawalGroups, x.withdrawalGroups,
@ -205,8 +208,10 @@ export async function getTransactionById(
ort, ort,
); );
}); });
} else if (type === TransactionType.Payment) { }
const proposalId = rest[0];
case TransactionType.Payment: {
const proposalId = parsedTx.proposalId;
return await ws.db return await ws.db
.mktx((x) => [ .mktx((x) => [
x.purchases, x.purchases,
@ -229,11 +234,15 @@ export async function getTransactionById(
payRetryRecord, payRetryRecord,
); );
}); });
} else if (type === TransactionType.Refresh) { }
const refreshGroupId = rest[0];
case TransactionType.Refresh: {
// FIXME: We should return info about the refresh here!
throw Error(`no tx for refresh`); throw Error(`no tx for refresh`);
} else if (type === TransactionType.Tip) { }
const tipId = rest[0];
case TransactionType.Tip: {
const tipId = parsedTx.walletTipId;
return await ws.db return await ws.db
.mktx((x) => [x.tips, x.operationRetries]) .mktx((x) => [x.tips, x.operationRetries])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
@ -245,8 +254,10 @@ export async function getTransactionById(
); );
return buildTransactionForTip(tipRecord, retries); return buildTransactionForTip(tipRecord, retries);
}); });
} else if (type === TransactionType.Deposit) { }
const depositGroupId = rest[0];
case TransactionType.Deposit: {
const depositGroupId = parsedTx.depositGroupId;
return await ws.db return await ws.db
.mktx((x) => [x.depositGroups, x.operationRetries]) .mktx((x) => [x.depositGroups, x.operationRetries])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
@ -258,33 +269,42 @@ export async function getTransactionById(
); );
return buildTransactionForDeposit(depositRecord, retries); return buildTransactionForDeposit(depositRecord, retries);
}); });
} else if (type === TransactionType.Refund) { }
case TransactionType.Refund:
// FIXME! // FIXME!
throw Error("not implemented"); throw Error("not implemented");
} else if (type === TransactionType.PeerPullDebit) { case TransactionType.PeerPullDebit: {
const peerPullPaymentIncomingId = rest[0];
return await ws.db return await ws.db
.mktx((x) => [x.peerPullPaymentIncoming]) .mktx((x) => [x.peerPullPaymentIncoming])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const debit = await tx.peerPullPaymentIncoming.get( const debit = await tx.peerPullPaymentIncoming.get(
peerPullPaymentIncomingId, parsedTx.peerPullPaymentIncomingId,
); );
if (!debit) throw Error("not found"); if (!debit) throw Error("not found");
return buildTransactionForPullPaymentDebit(debit); return buildTransactionForPullPaymentDebit(debit);
}); });
} else if (type === TransactionType.PeerPushDebit) { }
const pursePub = rest[0];
case TransactionType.PeerPushDebit: {
return await ws.db return await ws.db
.mktx((x) => [x.peerPushPaymentInitiations, x.contractTerms]) .mktx((x) => [x.peerPushPaymentInitiations, x.contractTerms])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const debit = await tx.peerPushPaymentInitiations.get(pursePub); const debit = await tx.peerPushPaymentInitiations.get(
parsedTx.pursePub,
);
if (!debit) throw Error("not found"); if (!debit) throw Error("not found");
const ct = await tx.contractTerms.get(debit.contractTermsHash); const ct = await tx.contractTerms.get(debit.contractTermsHash);
checkDbInvariant(!!ct); checkDbInvariant(!!ct);
return buildTransactionForPushPaymentDebit(debit, ct.contractTermsRaw); return buildTransactionForPushPaymentDebit(
debit,
ct.contractTermsRaw,
);
}); });
} else if (type === TransactionType.PeerPushCredit) { }
const peerPushPaymentIncomingId = rest[0];
case TransactionType.PeerPushCredit: {
const peerPushPaymentIncomingId = parsedTx.peerPushPaymentIncomingId;
return await ws.db return await ws.db
.mktx((x) => [ .mktx((x) => [
x.peerPushPaymentIncoming, x.peerPushPaymentIncoming,
@ -320,8 +340,10 @@ export async function getTransactionById(
wgOrt, wgOrt,
); );
}); });
} else if (type === TransactionType.PeerPullCredit) { }
const pursePub = rest[0];
case TransactionType.PeerPullCredit: {
const pursePub = parsedTx.pursePub;
return await ws.db return await ws.db
.mktx((x) => [ .mktx((x) => [
x.peerPullPaymentInitiations, x.peerPullPaymentInitiations,
@ -356,16 +378,9 @@ export async function getTransactionById(
wgOrt, wgOrt,
); );
}); });
} else {
const unknownTxType: never = type;
throw Error(`can't retrieve a '${unknownTxType}' transaction`);
} }
} }
}
// FIXME: Just a marker helper for unknown states until DD37 is fully implemented.
const mkTxStateUnknown = () => ({
major: TransactionMajorState.Unknown,
});
function buildTransactionForPushPaymentDebit( function buildTransactionForPushPaymentDebit(
pi: PeerPushPaymentInitiationRecord, pi: PeerPushPaymentInitiationRecord,
@ -1293,7 +1308,13 @@ export function constructTransactionIdentifier(
export function parseTransactionIdentifier( export function parseTransactionIdentifier(
transactionId: string, transactionId: string,
): ParsedTransactionIdentifier | undefined { ): ParsedTransactionIdentifier | undefined {
const { type, args: rest } = parseId("any", transactionId); const txnParts = transactionId.split(":");
if (txnParts.length < 3) {
throw Error("id should have al least 3 parts separated by ':'");
}
const [prefix, type, ...rest] = txnParts;
switch (type) { switch (type) {
case TransactionType.Deposit: case TransactionType.Deposit:
@ -1489,10 +1510,15 @@ export async function deleteTransaction(
ws: InternalWalletState, ws: InternalWalletState,
transactionId: string, transactionId: string,
): Promise<void> { ): Promise<void> {
const { type, args: rest } = parseId("txn", transactionId); const parsedTx = parseTransactionIdentifier(transactionId);
if (type === TransactionType.PeerPushCredit) { if (!parsedTx) {
const peerPushPaymentIncomingId = rest[0]; throw Error("invalid transaction ID");
}
switch (parsedTx.tag) {
case TransactionType.PeerPushCredit: {
const peerPushPaymentIncomingId = parsedTx.peerPushPaymentIncomingId;
await ws.db await ws.db
.mktx((x) => [ .mktx((x) => [
x.withdrawalGroups, x.withdrawalGroups,
@ -1514,18 +1540,24 @@ export async function deleteTransaction(
if (withdrawalGroupRecord) { if (withdrawalGroupRecord) {
await tx.withdrawalGroups.delete(withdrawalGroupId); await tx.withdrawalGroups.delete(withdrawalGroupId);
await tx.tombstones.put({ await tx.tombstones.put({
id: TombstoneTag.DeleteWithdrawalGroup + ":" + withdrawalGroupId, id:
TombstoneTag.DeleteWithdrawalGroup + ":" + withdrawalGroupId,
}); });
} }
} }
await tx.peerPushPaymentIncoming.delete(peerPushPaymentIncomingId); await tx.peerPushPaymentIncoming.delete(peerPushPaymentIncomingId);
await tx.tombstones.put({ await tx.tombstones.put({
id: id:
TombstoneTag.DeletePeerPushCredit + ":" + peerPushPaymentIncomingId, TombstoneTag.DeletePeerPushCredit +
":" +
peerPushPaymentIncomingId,
}); });
}); });
} else if (type === TransactionType.PeerPullCredit) { return;
const pursePub = rest[0]; }
case TransactionType.PeerPullCredit: {
const pursePub = parsedTx.pursePub;
await ws.db await ws.db
.mktx((x) => [ .mktx((x) => [
x.withdrawalGroups, x.withdrawalGroups,
@ -1545,7 +1577,8 @@ export async function deleteTransaction(
if (withdrawalGroupRecord) { if (withdrawalGroupRecord) {
await tx.withdrawalGroups.delete(withdrawalGroupId); await tx.withdrawalGroups.delete(withdrawalGroupId);
await tx.tombstones.put({ await tx.tombstones.put({
id: TombstoneTag.DeleteWithdrawalGroup + ":" + withdrawalGroupId, id:
TombstoneTag.DeleteWithdrawalGroup + ":" + withdrawalGroupId,
}); });
} }
} }
@ -1554,8 +1587,12 @@ export async function deleteTransaction(
id: TombstoneTag.DeletePeerPullCredit + ":" + pursePub, id: TombstoneTag.DeletePeerPullCredit + ":" + pursePub,
}); });
}); });
} else if (type === TransactionType.Withdrawal) {
const withdrawalGroupId = rest[0]; return;
}
case TransactionType.Withdrawal: {
const withdrawalGroupId = parsedTx.withdrawalGroupId;
await ws.db await ws.db
.mktx((x) => [x.withdrawalGroups, x.tombstones]) .mktx((x) => [x.withdrawalGroups, x.tombstones])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
@ -1570,8 +1607,11 @@ export async function deleteTransaction(
return; return;
} }
}); });
} else if (type === TransactionType.Payment) { return;
const proposalId = rest[0]; }
case TransactionType.Payment: {
const proposalId = parsedTx.proposalId;
await ws.db await ws.db
.mktx((x) => [x.purchases, x.tombstones]) .mktx((x) => [x.purchases, x.tombstones])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
@ -1587,8 +1627,11 @@ export async function deleteTransaction(
}); });
} }
}); });
} else if (type === TransactionType.Refresh) { return;
const refreshGroupId = rest[0]; }
case TransactionType.Refresh: {
const refreshGroupId = parsedTx.refreshGroupId;
await ws.db await ws.db
.mktx((x) => [x.refreshGroups, x.tombstones]) .mktx((x) => [x.refreshGroups, x.tombstones])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
@ -1600,8 +1643,12 @@ export async function deleteTransaction(
}); });
} }
}); });
} else if (type === TransactionType.Tip) {
const tipId = rest[0]; return;
}
case TransactionType.Tip: {
const tipId = parsedTx.walletTipId;
await ws.db await ws.db
.mktx((x) => [x.tips, x.tombstones]) .mktx((x) => [x.tips, x.tombstones])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
@ -1613,8 +1660,11 @@ export async function deleteTransaction(
}); });
} }
}); });
} else if (type === TransactionType.Deposit) { return;
const depositGroupId = rest[0]; }
case TransactionType.Deposit: {
const depositGroupId = parsedTx.depositGroupId;
await ws.db await ws.db
.mktx((x) => [x.depositGroups, x.tombstones]) .mktx((x) => [x.depositGroups, x.tombstones])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
@ -1626,28 +1676,17 @@ export async function deleteTransaction(
}); });
} }
}); });
} else if (type === TransactionType.Refund) {
const proposalId = rest[0];
const executionTimeStr = rest[1];
await ws.db return;
.mktx((x) => [x.purchases, x.tombstones])
.runReadWrite(async (tx) => {
const purchase = await tx.purchases.get(proposalId);
if (purchase) {
// This should just influence the history view,
// but won't delete any actual refund information.
await tx.tombstones.put({
id: makeTombstoneId(
TombstoneTag.DeleteRefund,
proposalId,
executionTimeStr,
),
});
} }
});
} else if (type === TransactionType.PeerPullDebit) { case TransactionType.Refund: {
const peerPullPaymentIncomingId = rest[0]; // FIXME: Implement!
return;
}
case TransactionType.PeerPullDebit: {
const peerPullPaymentIncomingId = parsedTx.peerPullPaymentIncomingId;
await ws.db await ws.db
.mktx((x) => [x.peerPullPaymentIncoming, x.tombstones]) .mktx((x) => [x.peerPullPaymentIncoming, x.tombstones])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
@ -1664,8 +1703,12 @@ export async function deleteTransaction(
}); });
} }
}); });
} else if (type === TransactionType.PeerPushDebit) {
const pursePub = rest[0]; return;
}
case TransactionType.PeerPushDebit: {
const pursePub = parsedTx.pursePub;
await ws.db await ws.db
.mktx((x) => [x.peerPushPaymentInitiations, x.tombstones]) .mktx((x) => [x.peerPushPaymentInitiations, x.tombstones])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
@ -1677,9 +1720,8 @@ export async function deleteTransaction(
}); });
} }
}); });
} else { return;
const unknownTxType: never = type; }
throw Error(`can't delete a '${unknownTxType}' transaction`);
} }
} }

View File

@ -118,7 +118,6 @@ import {
WALLET_BANK_INTEGRATION_PROTOCOL_VERSION, WALLET_BANK_INTEGRATION_PROTOCOL_VERSION,
WALLET_EXCHANGE_PROTOCOL_VERSION, WALLET_EXCHANGE_PROTOCOL_VERSION,
} from "../versions.js"; } from "../versions.js";
import { makeTransactionId } from "./common.js";
import { import {
getExchangeDetails, getExchangeDetails,
getExchangePaytoUri, getExchangePaytoUri,
@ -1456,10 +1455,10 @@ export async function processWithdrawalGroup(
if (numKycRequired > 0) { if (numKycRequired > 0) {
if (kycInfo) { if (kycInfo) {
const txId = makeTransactionId( const txId = constructTransactionIdentifier({
TransactionType.Withdrawal, tag: TransactionType.Withdrawal,
withdrawalGroup.withdrawalGroupId, withdrawalGroupId: withdrawalGroup.withdrawalGroupId,
); });
await checkWithdrawalKycStatus( await checkWithdrawalKycStatus(
ws, ws,
withdrawalGroup.exchangeBaseUrl, withdrawalGroup.exchangeBaseUrl,
@ -2050,12 +2049,13 @@ async function processReserveBankStatus(
r.wgInfo.bankInfo.timestampBankConfirmed = now; r.wgInfo.bankInfo.timestampBankConfirmed = now;
r.status = WithdrawalGroupStatus.PendingQueryingStatus; r.status = WithdrawalGroupStatus.PendingQueryingStatus;
// FIXME: Notification is deprecated with DD37. // FIXME: Notification is deprecated with DD37.
const transactionId = constructTransactionIdentifier({
tag: TransactionType.Withdrawal,
withdrawalGroupId: r.withdrawalGroupId,
});
ws.notify({ ws.notify({
type: NotificationType.WithdrawalGroupBankConfirmed, type: NotificationType.WithdrawalGroupBankConfirmed,
transactionId: makeTransactionId( transactionId,
TransactionType.Withdrawal,
r.withdrawalGroupId,
),
}); });
} else { } else {
logger.info("withdrawal: transfer not yet confirmed by bank"); logger.info("withdrawal: transfer not yet confirmed by bank");

View File

@ -159,6 +159,7 @@ describe("Withdraw CTA states", () => {
paytoUris: ["payto://"], paytoUris: ["payto://"],
tosAccepted: true, tosAccepted: true,
ageRestrictionOptions: [], ageRestrictionOptions: [],
numCoins: 42,
}, },
); );
@ -222,6 +223,7 @@ describe("Withdraw CTA states", () => {
paytoUris: ["payto://"], paytoUris: ["payto://"],
tosAccepted: false, tosAccepted: false,
ageRestrictionOptions: [], ageRestrictionOptions: [],
numCoins: 42,
}, },
); );