tombstone processing in backup import
This commit is contained in:
parent
f0ab1449c5
commit
6b1aea426a
@ -1546,6 +1546,11 @@ export interface BackupProviderTerms {
|
||||
}
|
||||
|
||||
export interface BackupProviderRecord {
|
||||
/**
|
||||
* Base URL of the provider.
|
||||
*
|
||||
* Primary key for the record.
|
||||
*/
|
||||
baseUrl: string;
|
||||
|
||||
/**
|
||||
|
@ -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}'`);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user