aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/taler-wallet-core/src/db.ts5
-rw-r--r--packages/taler-wallet-core/src/operations/backup/import.ts78
-rw-r--r--packages/taler-wallet-core/src/operations/backup/state.ts3
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts2
4 files changed, 84 insertions, 4 deletions
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 609f43ea1..0ff34d3c7 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -1546,6 +1546,11 @@ export interface BackupProviderTerms {
}
export interface BackupProviderRecord {
+ /**
+ * Base URL of the provider.
+ *
+ * Primary key for the record.
+ */
baseUrl: string;
/**
diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts
index 931e6f92b..1bbba6e26 100644
--- a/packages/taler-wallet-core/src/operations/backup/import.ts
+++ b/packages/taler-wallet-core/src/operations/backup/import.ts
@@ -55,6 +55,7 @@ import { Logger } from "../../util/logging";
import { initRetryInfo } from "../../util/retries";
import { InternalWalletState } from "../state";
import { provideBackupState } from "./state";
+import { makeEventId, TombstoneTag } from "../transactions.js";
const logger = new Logger("operations/backup/import.ts");
@@ -121,6 +122,7 @@ async function recoverPayCoinSelection(
if (wireFee) {
totalWireFee = Amounts.add(totalWireFee, wireFee).amount;
}
+ coveredExchanges.add(coinRecord.exchangeBaseUrl);
}
}
@@ -226,6 +228,8 @@ export async function importBackup(
Stores.recoupGroups,
Stores.reserves,
Stores.withdrawalGroups,
+ Stores.tombstones,
+ Stores.depositGroups,
],
async (tx) => {
// FIXME: validate schema!
@@ -233,6 +237,14 @@ export async function importBackup(
// FIXME: validate version
+ for (const tombstone of backupBlob.tombstones) {
+ await tx.put(Stores.tombstones, {
+ id: tombstone,
+ });
+ }
+
+ const tombstoneSet = new Set(backupBlob.tombstones);
+
for (const backupExchange of backupBlob.exchanges) {
const existingExchange = await tx.get(
Stores.exchanges,
@@ -381,6 +393,10 @@ export async function importBackup(
for (const backupReserve of backupExchange.reserves) {
const reservePub =
cryptoComp.reservePrivToPub[backupReserve.reserve_priv];
+ const ts = makeEventId(TombstoneTag.DeleteReserve, reservePub);
+ if (tombstoneSet.has(ts)) {
+ continue;
+ }
checkLogicInvariant(!!reservePub);
const existingReserve = await tx.get(Stores.reserves, reservePub);
const instructedAmount = Amounts.parseOrThrow(
@@ -426,6 +442,13 @@ export async function importBackup(
});
}
for (const backupWg of backupReserve.withdrawal_groups) {
+ const ts = makeEventId(
+ TombstoneTag.DeleteWithdrawalGroup,
+ backupWg.withdrawal_group_id,
+ );
+ if (tombstoneSet.has(ts)) {
+ continue;
+ }
const existingWg = await tx.get(
Stores.withdrawalGroups,
backupWg.withdrawal_group_id,
@@ -456,6 +479,13 @@ export async function importBackup(
}
for (const backupProposal of backupBlob.proposals) {
+ const ts = makeEventId(
+ TombstoneTag.DeletePayment,
+ backupProposal.proposal_id,
+ );
+ if (tombstoneSet.has(ts)) {
+ continue;
+ }
const existingProposal = await tx.get(
Stores.proposals,
backupProposal.proposal_id,
@@ -555,6 +585,13 @@ export async function importBackup(
}
for (const backupPurchase of backupBlob.purchases) {
+ const ts = makeEventId(
+ TombstoneTag.DeletePayment,
+ backupPurchase.proposal_id,
+ );
+ if (tombstoneSet.has(ts)) {
+ continue;
+ }
const existingPurchase = await tx.get(
Stores.purchases,
backupPurchase.proposal_id,
@@ -704,6 +741,13 @@ export async function importBackup(
}
for (const backupRefreshGroup of backupBlob.refresh_groups) {
+ const ts = makeEventId(
+ TombstoneTag.DeleteRefreshGroup,
+ backupRefreshGroup.refresh_group_id,
+ );
+ if (tombstoneSet.has(ts)) {
+ continue;
+ }
const existingRg = await tx.get(
Stores.refreshGroups,
backupRefreshGroup.refresh_group_id,
@@ -783,6 +827,10 @@ export async function importBackup(
}
for (const backupTip of backupBlob.tips) {
+ const ts = makeEventId(TombstoneTag.DeleteTip, backupTip.wallet_tip_id);
+ if (tombstoneSet.has(ts)) {
+ continue;
+ }
const existingTip = await tx.get(Stores.tips, backupTip.wallet_tip_id);
if (!existingTip) {
const denomsSel = await getDenomSelStateFromBackup(
@@ -809,6 +857,36 @@ export async function importBackup(
});
}
}
+
+ // We now process tombstones.
+ // The import code above should already prevent
+ // importing things that are tombstoned,
+ // but we do tombstone processing last just to be sure.
+
+ for (const tombstone of backupBlob.tombstones) {
+ const [type, ...rest] = tombstone.split(":");
+ if (type === TombstoneTag.DeleteDepositGroup) {
+ await tx.delete(Stores.depositGroups, rest[0]);
+ } else if (type === TombstoneTag.DeletePayment) {
+ await tx.delete(Stores.purchases, rest[0]);
+ await tx.delete(Stores.proposals, rest[0]);
+ } else if (type === TombstoneTag.DeleteRefreshGroup) {
+ await tx.delete(Stores.refreshGroups, rest[0]);
+ } else if (type === TombstoneTag.DeleteRefund) {
+ // Nothing required, will just prevent display
+ // in the transactions list
+ } else if (type === TombstoneTag.DeleteReserve) {
+ // FIXME: Once we also have account (=kyc) reserves,
+ // we need to check if the reserve is an account before deleting here
+ await tx.delete(Stores.reserves, rest[0]);
+ } else if (type === TombstoneTag.DeleteTip) {
+ await tx.delete(Stores.tips, rest[0]);
+ } else if (type === TombstoneTag.DeleteWithdrawalGroup) {
+ await tx.delete(Stores.withdrawalGroups, rest[0]);
+ } else {
+ logger.warn(`unable to process tombstone of type '${type}'`);
+ }
+ }
},
);
}
diff --git a/packages/taler-wallet-core/src/operations/backup/state.ts b/packages/taler-wallet-core/src/operations/backup/state.ts
index 686c307a1..e2a0f4cf3 100644
--- a/packages/taler-wallet-core/src/operations/backup/state.ts
+++ b/packages/taler-wallet-core/src/operations/backup/state.ts
@@ -28,9 +28,6 @@ export interface WalletBackupConfState {
/**
* Last hash of the canonicalized plain-text backup.
- *
- * Used to determine whether the wallet's content changed
- * and we need to bump the clock.
*/
lastBackupPlainHash?: string;
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 02550a11e..70cd7496b 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -42,7 +42,7 @@ import { getFundingPaytoUris } from "./reserves";
/**
* Create an event ID from the type and the primary key for the event.
*/
-function makeEventId(
+export function makeEventId(
type: TransactionType | TombstoneTag,
...args: string[]
): string {