aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-05-12 13:34:49 +0200
committerFlorian Dold <florian@dold.me>2021-05-12 13:35:04 +0200
commitdebc2254fdf1cf748a846e429e32c2e92d557080 (patch)
tree2387fbb74977b5c58786332703c8d61189214c00 /packages
parent83b02069c931306c72c470e0285693719f65d0ca (diff)
towards backup based on add/remove set instead of clocks
Diffstat (limited to 'packages')
-rw-r--r--packages/taler-util/src/backupTypes.ts109
-rw-r--r--packages/taler-wallet-core/src/db.ts12
-rw-r--r--packages/taler-wallet-core/src/operations/backup/export.ts7
-rw-r--r--packages/taler-wallet-core/src/operations/backup/import.ts7
-rw-r--r--packages/taler-wallet-core/src/operations/backup/index.ts4
-rw-r--r--packages/taler-wallet-core/src/operations/pay.ts1
-rw-r--r--packages/taler-wallet-core/src/operations/reserves.ts1
-rw-r--r--packages/taler-wallet-core/src/operations/tip.ts2
8 files changed, 47 insertions, 96 deletions
diff --git a/packages/taler-util/src/backupTypes.ts b/packages/taler-util/src/backupTypes.ts
index fc6aaaad5..13ff75190 100644
--- a/packages/taler-util/src/backupTypes.ts
+++ b/packages/taler-util/src/backupTypes.ts
@@ -71,18 +71,12 @@ type BackupAmountString = string;
type DeviceIdString = string;
/**
- * Lamport clock timestamp.
- */
-export interface ClockStamp {
- deviceId: string;
- value: number;
-}
-
-/**
* Contract terms JSON.
*/
type RawContractTerms = any;
+type OperationUid = string;
+
/**
* Content of the backup.
*
@@ -116,16 +110,6 @@ export interface WalletBackupContentV1 {
current_device_id: DeviceIdString;
/**
- * Monotonically increasing clock of the wallet,
- * used to determine causality when merging backups.
- *
- * Information about other clocks, used to delete
- * tombstones in the hopefully rare case that multiple wallets
- * are connected to the same sync server.
- */
- clocks: { [device_id: string]: number };
-
- /**
* Timestamp of the backup.
*
* This timestamp should only be advanced if the content
@@ -183,21 +167,6 @@ export interface WalletBackupContentV1 {
recoup_groups: BackupRecoupGroup[];
/**
- * Tombstones for deleting purchases.
- */
- purchase_tombstones: {
- /**
- * Clock when the purchase was deleted
- */
- clock_deleted: ClockStamp;
-
- /**
- * Proposal ID identifying the purchase.
- */
- proposal_id: string;
- }[];
-
- /**
* Trusted auditors, either for official (3 letter) or local (4-12 letter)
* currencies.
*
@@ -224,6 +193,17 @@ export interface WalletBackupContentV1 {
* Permanent error reports.
*/
error_reports: BackupErrorReport[];
+
+ /**
+ * Deletion tombstones. Sorted by (type, id)
+ * in ascending order.
+ */
+ tombstones: Tombstone[];
+}
+
+export interface Tombstone {
+ type: string;
+ id: string;
}
/**
@@ -256,17 +236,10 @@ export interface BackupTrustAuditor {
auditor_pub: string;
/**
- * Clock when the auditor trust has been added.
- *
- * Can be undefined if this entry represents a removal delta
- * from the wallet's defaults.
- */
- clock_added?: ClockStamp;
-
- /**
- * Clock for when the auditor trust has been removed.
+ * UIDs for the operation of adding this auditor
+ * as a trusted auditor.
*/
- clock_removed?: ClockStamp;
+ uids: OperationUid;
}
/**
@@ -289,17 +262,10 @@ export interface BackupTrustExchange {
exchange_master_pub: string;
/**
- * Clock when the exchange trust has been added.
- *
- * Can be undefined if this entry represents a removal delta
- * from the wallet's defaults.
+ * UIDs for the operation of adding this exchange
+ * as trusted.
*/
- clock_added?: ClockStamp;
-
- /**
- * Clock for when the exchange trust has been removed.
- */
- clock_removed?: ClockStamp;
+ uids: OperationUid;
}
export class BackupBackupProviderTerms {
@@ -483,11 +449,6 @@ export interface BackupCoin {
* be refreshed in most situations.
*/
fresh: boolean;
-
- /**
- * Clock for the last update to current_amount/fresh.
- */
- last_clock?: ClockStamp;
}
/**
@@ -521,7 +482,6 @@ export interface BackupTip {
timestamp_created: Timestamp;
timestamp_finished?: Timestamp;
- finish_clock?: ClockStamp;
finish_is_failure?: boolean;
/**
@@ -549,7 +509,11 @@ export interface BackupTip {
*/
selected_denoms: BackupDenomSel;
- selected_denoms_clock?: ClockStamp;
+ /**
+ * UID for the denomination selection.
+ * Used to disambiguate when merging.
+ */
+ selected_denoms_uid: OperationUid;
}
/**
@@ -640,7 +604,6 @@ export interface BackupRefreshGroup {
timestamp_created: Timestamp;
timestamp_finish?: Timestamp;
- finish_clock?: ClockStamp;
finish_is_failure?: boolean;
}
@@ -664,7 +627,6 @@ export interface BackupWithdrawalGroup {
timestamp_created: Timestamp;
timestamp_finish?: Timestamp;
- finish_clock?: ClockStamp;
finish_is_failure?: boolean;
/**
@@ -682,7 +644,7 @@ export interface BackupWithdrawalGroup {
*/
selected_denoms: BackupDenomSel;
- selected_denoms_clock?: ClockStamp;
+ selected_denoms_id: OperationUid;
}
export enum BackupRefundState {
@@ -731,8 +693,6 @@ export interface BackupRefundItemCommon {
* accurately.
*/
total_refresh_cost_bound: BackupAmountString;
-
- last_clock?: ClockStamp;
}
/**
@@ -795,9 +755,9 @@ export interface BackupPurchase {
}[];
/**
- * Clock when the pay coin selection was made/updated.
+ * Unique ID to disambiguate pay coin selection on merge.
*/
- pay_coins_clock?: ClockStamp;
+ pay_coins_uid: OperationUid;
/**
* Total cost initially shown to the user.
@@ -842,11 +802,6 @@ export interface BackupPurchase {
defunct?: boolean;
/**
- * Clock for last update to defunct status.
- */
- defunct_clock?: ClockStamp;
-
- /**
* Abort status of the payment.
*/
abort_status?: "abort-refund" | "abort-finished";
@@ -1042,7 +997,6 @@ export interface BackupReserve {
withdrawal_groups: BackupWithdrawalGroup[];
defective?: boolean;
- defective_clock?: ClockStamp;
}
/**
@@ -1197,16 +1151,9 @@ export interface BackupExchange {
tos_etag_accepted: string | undefined;
/**
- * Clock value of the last update.
- */
- last_clock?: ClockStamp;
-
- /**
* Should this exchange be considered defective?
*/
defective?: boolean;
-
- defective_clock?: ClockStamp;
}
export enum BackupProposalStatus {
@@ -1284,8 +1231,6 @@ export interface BackupProposal {
*/
proposal_status: BackupProposalStatus;
- proposal_status_clock?: ClockStamp;
-
/**
* Proposal that this one got "redirected" to as part of
* the repurchase detection.
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index eb0de5646..22cbd16cc 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -978,6 +978,8 @@ export interface TipRecord {
*/
denomsSel: DenomSelectionState;
+ denomSelUid: string;
+
/**
* Tip ID chosen by the wallet.
*/
@@ -1310,6 +1312,8 @@ export interface PurchaseRecord {
payCoinSelection: PayCoinSelection;
+ payCoinSelectionUid: string;
+
/**
* Pending removals from pay coin selection.
*
@@ -1460,6 +1464,8 @@ export interface WithdrawalGroupRecord {
denomsSel: DenomSelectionState;
+ denomSelUid: string;
+
/**
* Retry info, always present even on completed operations so that indexing works.
*/
@@ -1564,12 +1570,6 @@ export interface BackupProviderRecord {
*/
lastBackupHash?: string;
- /**
- * Clock of the last backup that we already
- * merged.
- */
- lastBackupClock?: number;
-
lastBackupTimestamp?: Timestamp;
/**
diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts b/packages/taler-wallet-core/src/operations/backup/export.ts
index 07c7b9ece..4ccaf8f42 100644
--- a/packages/taler-wallet-core/src/operations/backup/export.ts
+++ b/packages/taler-wallet-core/src/operations/backup/export.ts
@@ -118,6 +118,7 @@ export async function exportBackup(
timestamp_finish: wg.timestampFinish,
withdrawal_group_id: wg.withdrawalGroupId,
secret_seed: wg.secretSeed,
+ selected_denoms_id: wg.denomSelUid,
});
});
@@ -160,6 +161,7 @@ export async function exportBackup(
timestamp_created: tip.createdTimestamp,
timestamp_expiration: tip.tipExpiration,
tip_amount_raw: Amounts.stringify(tip.tipAmountRaw),
+ selected_denoms_uid: tip.denomSelUid,
});
});
@@ -363,6 +365,7 @@ export async function exportBackup(
nonce_priv: purch.noncePriv,
merchant_sig: purch.download.contractData.merchantSig,
total_pay_cost: Amounts.stringify(purch.totalPayCost),
+ pay_coins_uid: purch.payCoinSelectionUid,
});
});
@@ -446,13 +449,11 @@ export async function exportBackup(
const backupBlob: WalletBackupContentV1 = {
schema_id: "gnu-taler-wallet-backup-content",
schema_version: 1,
- clocks: bs.clocks,
exchanges: backupExchanges,
wallet_root_pub: bs.walletRootPub,
backup_providers: backupBackupProviders,
current_device_id: bs.deviceId,
proposals: backupProposals,
- purchase_tombstones: [],
purchases: backupPurchases,
recoup_groups: backupRecoupGroups,
refresh_groups: backupRefreshGroups,
@@ -462,13 +463,13 @@ export async function exportBackup(
trusted_exchanges: {},
intern_table: {},
error_reports: [],
+ tombstones: [],
};
// If the backup changed, we increment our clock.
let h = encodeCrock(hash(stringToBytes(canonicalJson(backupBlob))));
if (h != bs.lastBackupPlainHash) {
- backupBlob.clocks[bs.deviceId] = ++bs.clocks[bs.deviceId];
bs.lastBackupPlainHash = encodeCrock(
hash(stringToBytes(canonicalJson(backupBlob))),
);
diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts
index e0ae379ab..931e6f92b 100644
--- a/packages/taler-wallet-core/src/operations/backup/import.ts
+++ b/packages/taler-wallet-core/src/operations/backup/import.ts
@@ -302,7 +302,9 @@ export async function importBackup(
denomPubHash,
]);
if (!existingDenom) {
- logger.info(`importing backup denomination: ${j2s(backupDenomination)}`);
+ logger.info(
+ `importing backup denomination: ${j2s(backupDenomination)}`,
+ );
await tx.put(Stores.denominations, {
denomPub: backupDenomination.denom_pub,
@@ -446,6 +448,7 @@ export async function importBackup(
timestampStart: backupWg.timestamp_created,
timestampFinish: backupWg.timestamp_finish,
withdrawalGroupId: backupWg.withdrawal_group_id,
+ denomSelUid: backupWg.selected_denoms_id,
});
}
}
@@ -695,6 +698,7 @@ export async function importBackup(
coinDepositPermissions: undefined,
totalPayCost: Amounts.parseOrThrow(backupPurchase.total_pay_cost),
refunds,
+ payCoinSelectionUid: backupPurchase.pay_coins_uid,
});
}
}
@@ -801,6 +805,7 @@ export async function importBackup(
tipAmountRaw: Amounts.parseOrThrow(backupTip.tip_amount_raw),
tipExpiration: backupTip.timestamp_expiration,
walletTipId: backupTip.wallet_tip_id,
+ denomSelUid: backupTip.selected_denoms_uid,
});
}
}
diff --git a/packages/taler-wallet-core/src/operations/backup/index.ts b/packages/taler-wallet-core/src/operations/backup/index.ts
index 49129d7de..b4c1a6c92 100644
--- a/packages/taler-wallet-core/src/operations/backup/index.ts
+++ b/packages/taler-wallet-core/src/operations/backup/index.ts
@@ -349,7 +349,6 @@ async function runBackupCycleForProvider(
}
prov.lastBackupHash = encodeCrock(currentBackupHash);
prov.lastBackupTimestamp = getTimestampNow();
- prov.lastBackupClock = backupJson.clocks[backupJson.current_device_id];
prov.lastError = undefined;
await tx.put(Stores.backupProviders, prov);
},
@@ -372,7 +371,6 @@ async function runBackupCycleForProvider(
return;
}
prov.lastBackupHash = encodeCrock(hash(backupEnc));
- prov.lastBackupClock = blob.clocks[blob.current_device_id];
prov.lastBackupTimestamp = getTimestampNow();
prov.lastError = undefined;
await tx.put(Stores.backupProviders, prov);
@@ -624,7 +622,6 @@ export async function getBackupInfo(
for (const x of providerRecords) {
providers.push({
active: x.active,
- lastRemoteClock: x.lastBackupClock,
syncProviderBaseUrl: x.baseUrl,
lastBackupTimestamp: x.lastBackupTimestamp,
paymentProposalIds: x.paymentProposalIds,
@@ -696,7 +693,6 @@ async function backupRecoveryTheirs(
for (const prov of providers) {
prov.lastBackupTimestamp = undefined;
prov.lastBackupHash = undefined;
- prov.lastBackupClock = undefined;
await tx.put(Stores.backupProviders, prov);
}
},
diff --git a/packages/taler-wallet-core/src/operations/pay.ts b/packages/taler-wallet-core/src/operations/pay.ts
index 2e8228e6e..1ed8d72b9 100644
--- a/packages/taler-wallet-core/src/operations/pay.ts
+++ b/packages/taler-wallet-core/src/operations/pay.ts
@@ -406,6 +406,7 @@ async function recordConfirmPay(
download: d,
lastSessionId: sessionId,
payCoinSelection: coinSelection,
+ payCoinSelectionUid: encodeCrock(getRandomBytes(32)),
totalPayCost: payCostInfo,
coinDepositPermissions,
timestampAccept: getTimestampNow(),
diff --git a/packages/taler-wallet-core/src/operations/reserves.ts b/packages/taler-wallet-core/src/operations/reserves.ts
index 984ce5a6b..855ee82ee 100644
--- a/packages/taler-wallet-core/src/operations/reserves.ts
+++ b/packages/taler-wallet-core/src/operations/reserves.ts
@@ -633,6 +633,7 @@ async function updateReserve(
lastError: undefined,
denomsSel: denomSelectionInfoToState(denomSelInfo),
secretSeed: encodeCrock(getRandomBytes(64)),
+ denomSelUid: encodeCrock(getRandomBytes(32)),
};
newReserve.lastError = undefined;
diff --git a/packages/taler-wallet-core/src/operations/tip.ts b/packages/taler-wallet-core/src/operations/tip.ts
index cc5274647..6de116098 100644
--- a/packages/taler-wallet-core/src/operations/tip.ts
+++ b/packages/taler-wallet-core/src/operations/tip.ts
@@ -107,6 +107,7 @@ export async function prepareTip(
const selectedDenoms = selectWithdrawalDenominations(amount, denoms);
const secretSeed = encodeCrock(getRandomBytes(64));
+ const denomSelUid = encodeCrock(getRandomBytes(32));
tipRecord = {
walletTipId: walletTipId,
@@ -127,6 +128,7 @@ export async function prepareTip(
denomsSel: denomSelectionInfoToState(selectedDenoms),
pickedUpTimestamp: undefined,
secretSeed,
+ denomSelUid,
};
await ws.db.put(Stores.tips, tipRecord);
}