diff options
author | Florian Dold <florian@dold.me> | 2022-10-08 20:56:57 +0200 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2022-10-08 23:07:07 +0200 |
commit | 526f4eba9554f27e33afb0e02d19d870825b038c (patch) | |
tree | c35e41a20a3bc90da3beb81fa7831505ee64cfee /packages/taler-wallet-core/src/operations/backup | |
parent | eace0e0e7aad9113af758b829fffd873826e36e3 (diff) | |
download | wallet-core-526f4eba9554f27e33afb0e02d19d870825b038c.tar.xz |
wallet-core: Clean up merchant payments DB schema
Diffstat (limited to 'packages/taler-wallet-core/src/operations/backup')
3 files changed, 88 insertions, 219 deletions
diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts b/packages/taler-wallet-core/src/operations/backup/export.ts index c8454a62f..04fac7d38 100644 --- a/packages/taler-wallet-core/src/operations/backup/export.ts +++ b/packages/taler-wallet-core/src/operations/backup/export.ts @@ -37,7 +37,7 @@ import { BackupExchangeDetails, BackupExchangeWireFee, BackupOperationStatus, - BackupProposal, + BackupPayInfo, BackupProposalStatus, BackupPurchase, BackupRecoupGroup, @@ -62,11 +62,9 @@ import { WalletBackupContentV1, } from "@gnu-taler/taler-util"; import { - AbortStatus, CoinSourceType, CoinStatus, DenominationRecord, - OperationStatus, ProposalStatus, RefreshCoinStatus, RefundState, @@ -92,7 +90,6 @@ export async function exportBackup( x.coins, x.denominations, x.purchases, - x.proposals, x.refreshGroups, x.backupProviders, x.tips, @@ -109,7 +106,6 @@ export async function exportBackup( [url: string]: BackupDenomination[]; } = {}; const backupPurchases: BackupPurchase[] = []; - const backupProposals: BackupProposal[] = []; const backupRefreshGroups: BackupRefreshGroup[] = []; const backupBackupProviders: BackupBackupProvider[] = []; const backupTips: BackupTip[] = []; @@ -385,65 +381,61 @@ export async function exportBackup( } } - backupPurchases.push({ - contract_terms_raw: purch.download.contractTermsRaw, - auto_refund_deadline: purch.autoRefundDeadline, - merchant_pay_sig: purch.merchantPaySig, - pay_coins: purch.payCoinSelection.coinPubs.map((x, i) => ({ - coin_pub: x, - contribution: Amounts.stringify( - purch.payCoinSelection.coinContributions[i], - ), - })), - proposal_id: purch.proposalId, - refunds, - timestamp_accept: purch.timestampAccept, - timestamp_first_successful_pay: purch.timestampFirstSuccessfulPay, - abort_status: - purch.abortStatus === AbortStatus.None - ? undefined - : purch.abortStatus, - nonce_priv: purch.noncePriv, - merchant_sig: purch.download.contractData.merchantSig, - total_pay_cost: Amounts.stringify(purch.totalPayCost), - pay_coins_uid: purch.payCoinSelectionUid, - }); - }); - - await tx.proposals.iter().forEach((prop) => { - if (purchaseProposalIdSet.has(prop.proposalId)) { - return; - } let propStatus: BackupProposalStatus; - switch (prop.proposalStatus) { - case ProposalStatus.Accepted: + switch (purch.status) { + case ProposalStatus.Paid: + propStatus = BackupProposalStatus.Paid; return; - case ProposalStatus.Downloading: + case ProposalStatus.DownloadingProposal: case ProposalStatus.Proposed: propStatus = BackupProposalStatus.Proposed; break; - case ProposalStatus.PermanentlyFailed: + case ProposalStatus.ProposalDownloadFailed: propStatus = BackupProposalStatus.PermanentlyFailed; break; - case ProposalStatus.Refused: + case ProposalStatus.ProposalRefused: propStatus = BackupProposalStatus.Refused; break; - case ProposalStatus.Repurchase: + case ProposalStatus.RepurchaseDetected: propStatus = BackupProposalStatus.Repurchase; break; + default: + throw Error(); } - backupProposals.push({ - claim_token: prop.claimToken, - nonce_priv: prop.noncePriv, - proposal_id: prop.noncePriv, + + const payInfo = purch.payInfo; + let backupPayInfo: BackupPayInfo | undefined = undefined; + if (payInfo) { + backupPayInfo = { + pay_coins: payInfo.payCoinSelection.coinPubs.map((x, i) => ({ + coin_pub: x, + contribution: Amounts.stringify( + payInfo.payCoinSelection.coinContributions[i], + ), + })), + total_pay_cost: Amounts.stringify(payInfo.totalPayCost), + pay_coins_uid: payInfo.payCoinSelectionUid, + }; + } + + backupPurchases.push({ + contract_terms_raw: purch.download?.contractTermsRaw, + auto_refund_deadline: purch.autoRefundDeadline, + merchant_pay_sig: purch.merchantPaySig, + pay_info: backupPayInfo, + proposal_id: purch.proposalId, + refunds, + timestamp_accepted: purch.timestampAccept, + timestamp_first_successful_pay: purch.timestampFirstSuccessfulPay, + nonce_priv: purch.noncePriv, + merchant_sig: purch.download?.contractData.merchantSig, + claim_token: purch.claimToken, + merchant_base_url: purch.merchantBaseUrl, + order_id: purch.orderId, proposal_status: propStatus, - repurchase_proposal_id: prop.repurchaseProposalId, - timestamp: prop.timestamp, - contract_terms_raw: prop.download?.contractTermsRaw, - download_session_id: prop.downloadSessionId, - merchant_base_url: prop.merchantBaseUrl, - order_id: prop.orderId, - merchant_sig: prop.download?.contractData.merchantSig, + repurchase_proposal_id: purch.repurchaseProposalId, + download_session_id: purch.downloadSessionId, + timestamp_proposed: purch.timestamp, }); }); @@ -498,7 +490,6 @@ export async function exportBackup( wallet_root_pub: bs.walletRootPub, backup_providers: backupBackupProviders, current_device_id: bs.deviceId, - proposals: backupProposals, purchases: backupPurchases, recoup_groups: backupRecoupGroups, refresh_groups: backupRefreshGroups, diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts index fb747ef1c..00dbf6fa8 100644 --- a/packages/taler-wallet-core/src/operations/backup/import.ts +++ b/packages/taler-wallet-core/src/operations/backup/import.ts @@ -21,8 +21,8 @@ import { BackupCoin, BackupCoinSourceType, BackupDenomSel, + BackupPayInfo, BackupProposalStatus, - BackupPurchase, BackupRefreshReason, BackupRefundState, BackupWgType, @@ -37,7 +37,6 @@ import { WireInfo, } from "@gnu-taler/taler-util"; import { - AbortStatus, CoinRecord, CoinSource, CoinSourceType, @@ -48,28 +47,23 @@ import { OperationStatus, ProposalDownload, ProposalStatus, + PurchasePayInfo, RefreshCoinStatus, RefreshSessionRecord, RefundState, - ReserveBankInfo, - WithdrawalGroupStatus, WalletContractData, WalletRefundItem, WalletStoresV1, WgInfo, + WithdrawalGroupStatus, WithdrawalRecordType, } from "../../db.js"; import { InternalWalletState } from "../../internal-wallet-state.js"; import { assertUnreachable } from "../../util/assertUnreachable.js"; -import { - checkDbInvariant, - checkLogicInvariant, -} from "../../util/invariants.js"; +import { checkLogicInvariant } from "../../util/invariants.js"; import { GetReadOnlyAccess, GetReadWriteAccess } from "../../util/query.js"; -import { RetryInfo } from "../../util/retries.js"; -import { makeCoinAvailable } from "../../wallet.js"; +import { makeCoinAvailable, makeEventId, TombstoneTag } from "../common.js"; import { getExchangeDetails } from "../exchanges.js"; -import { makeEventId, TombstoneTag } from "../transactions.js"; import { provideBackupState } from "./state.js"; const logger = new Logger("operations/backup/import.ts"); @@ -95,10 +89,10 @@ async function recoverPayCoinSelection( denominations: typeof WalletStoresV1.denominations; }>, contractData: WalletContractData, - backupPurchase: BackupPurchase, + payInfo: BackupPayInfo, ): Promise<PayCoinSelection> { - const coinPubs: string[] = backupPurchase.pay_coins.map((x) => x.coin_pub); - const coinContributions: AmountJson[] = backupPurchase.pay_coins.map((x) => + const coinPubs: string[] = payInfo.pay_coins.map((x) => x.coin_pub); + const coinContributions: AmountJson[] = payInfo.pay_coins.map((x) => Amounts.parseOrThrow(x.contribution), ); @@ -316,7 +310,6 @@ export async function importBackup( x.coinAvailability, x.denominations, x.purchases, - x.proposals, x.refreshGroups, x.backupProviders, x.tips, @@ -560,113 +553,6 @@ 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.proposals.get( - backupProposal.proposal_id, - ); - if (!existingProposal) { - let download: ProposalDownload | undefined; - let proposalStatus: ProposalStatus; - switch (backupProposal.proposal_status) { - case BackupProposalStatus.Proposed: - if (backupProposal.contract_terms_raw) { - proposalStatus = ProposalStatus.Proposed; - } else { - proposalStatus = ProposalStatus.Downloading; - } - break; - case BackupProposalStatus.Refused: - proposalStatus = ProposalStatus.Refused; - break; - case BackupProposalStatus.Repurchase: - proposalStatus = ProposalStatus.Repurchase; - break; - case BackupProposalStatus.PermanentlyFailed: - proposalStatus = ProposalStatus.PermanentlyFailed; - break; - } - if (backupProposal.contract_terms_raw) { - checkDbInvariant(!!backupProposal.merchant_sig); - const parsedContractTerms = codecForContractTerms().decode( - backupProposal.contract_terms_raw, - ); - const amount = Amounts.parseOrThrow(parsedContractTerms.amount); - const contractTermsHash = - cryptoComp.proposalIdToContractTermsHash[ - backupProposal.proposal_id - ]; - let maxWireFee: AmountJson; - if (parsedContractTerms.max_wire_fee) { - maxWireFee = Amounts.parseOrThrow( - parsedContractTerms.max_wire_fee, - ); - } else { - maxWireFee = Amounts.getZero(amount.currency); - } - download = { - contractData: { - amount, - contractTermsHash: contractTermsHash, - fulfillmentUrl: parsedContractTerms.fulfillment_url ?? "", - merchantBaseUrl: parsedContractTerms.merchant_base_url, - merchantPub: parsedContractTerms.merchant_pub, - merchantSig: backupProposal.merchant_sig, - orderId: parsedContractTerms.order_id, - summary: parsedContractTerms.summary, - autoRefund: parsedContractTerms.auto_refund, - maxWireFee, - payDeadline: parsedContractTerms.pay_deadline, - refundDeadline: parsedContractTerms.refund_deadline, - wireFeeAmortization: - parsedContractTerms.wire_fee_amortization || 1, - allowedAuditors: parsedContractTerms.auditors.map((x) => ({ - auditorBaseUrl: x.url, - auditorPub: x.auditor_pub, - })), - allowedExchanges: parsedContractTerms.exchanges.map((x) => ({ - exchangeBaseUrl: x.url, - exchangePub: x.master_pub, - })), - timestamp: parsedContractTerms.timestamp, - wireMethod: parsedContractTerms.wire_method, - wireInfoHash: parsedContractTerms.h_wire, - maxDepositFee: Amounts.parseOrThrow( - parsedContractTerms.max_fee, - ), - merchant: parsedContractTerms.merchant, - products: parsedContractTerms.products, - summaryI18n: parsedContractTerms.summary_i18n, - deliveryDate: parsedContractTerms.delivery_date, - deliveryLocation: parsedContractTerms.delivery_location, - }, - contractTermsRaw: backupProposal.contract_terms_raw, - }; - } - await tx.proposals.put({ - claimToken: backupProposal.claim_token, - merchantBaseUrl: backupProposal.merchant_base_url, - timestamp: backupProposal.timestamp, - orderId: backupProposal.order_id, - noncePriv: backupProposal.nonce_priv, - noncePub: - cryptoComp.proposalNoncePrivToPub[backupProposal.nonce_priv], - proposalId: backupProposal.proposal_id, - repurchaseProposalId: backupProposal.repurchase_proposal_id, - download, - proposalStatus, - // FIXME! - downloadSessionId: undefined, - }); - } - } - for (const backupPurchase of backupBlob.purchases) { const ts = makeEventId( TombstoneTag.DeletePayment, @@ -678,6 +564,14 @@ export async function importBackup( const existingPurchase = await tx.purchases.get( backupPurchase.proposal_id, ); + let proposalStatus: ProposalStatus; + switch (backupPurchase.proposal_status) { + case BackupProposalStatus.Paid: + proposalStatus = ProposalStatus.Paid; + break; + default: + throw Error(); + } if (!existingPurchase) { const refunds: { [refundKey: string]: WalletRefundItem } = {}; for (const backupRefund of backupPurchase.refunds) { @@ -721,25 +615,6 @@ export async function importBackup( break; } } - let abortStatus: AbortStatus; - switch (backupPurchase.abort_status) { - case "abort-finished": - abortStatus = AbortStatus.AbortFinished; - break; - case "abort-refund": - abortStatus = AbortStatus.AbortRefund; - break; - case undefined: - abortStatus = AbortStatus.None; - break; - default: - logger.warn( - `got backup purchase abort_status ${j2s( - backupPurchase.abort_status, - )}`, - ); - throw Error("not reachable"); - } const parsedContractTerms = codecForContractTerms().decode( backupPurchase.contract_terms_raw, ); @@ -761,7 +636,7 @@ export async function importBackup( fulfillmentUrl: parsedContractTerms.fulfillment_url ?? "", merchantBaseUrl: parsedContractTerms.merchant_base_url, merchantPub: parsedContractTerms.merchant_pub, - merchantSig: backupPurchase.merchant_sig, + merchantSig: backupPurchase.merchant_sig!, orderId: parsedContractTerms.order_id, summary: parsedContractTerms.summary, autoRefund: parsedContractTerms.auto_refund, @@ -790,33 +665,46 @@ export async function importBackup( }, contractTermsRaw: backupPurchase.contract_terms_raw, }; + + let payInfo: PurchasePayInfo | undefined = undefined; + if (backupPurchase.pay_info) { + payInfo = { + coinDepositPermissions: undefined, + payCoinSelection: await recoverPayCoinSelection( + tx, + download.contractData, + backupPurchase.pay_info, + ), + payCoinSelectionUid: backupPurchase.pay_info.pay_coins_uid, + totalPayCost: Amounts.parseOrThrow( + backupPurchase.pay_info.total_pay_cost, + ), + }; + } + await tx.purchases.put({ proposalId: backupPurchase.proposal_id, noncePriv: backupPurchase.nonce_priv, noncePub: cryptoComp.proposalNoncePrivToPub[backupPurchase.nonce_priv], autoRefundDeadline: TalerProtocolTimestamp.never(), - refundAwaiting: undefined, - timestampAccept: backupPurchase.timestamp_accept, + timestampAccept: backupPurchase.timestamp_accepted, timestampFirstSuccessfulPay: backupPurchase.timestamp_first_successful_pay, timestampLastRefundStatus: undefined, merchantPaySig: backupPurchase.merchant_pay_sig, lastSessionId: undefined, - abortStatus, download, - paymentSubmitPending: - !backupPurchase.timestamp_first_successful_pay, - refundQueryRequested: false, - payCoinSelection: await recoverPayCoinSelection( - tx, - download.contractData, - backupPurchase, - ), - coinDepositPermissions: undefined, - totalPayCost: Amounts.parseOrThrow(backupPurchase.total_pay_cost), refunds, - payCoinSelectionUid: backupPurchase.pay_coins_uid, + claimToken: backupPurchase.claim_token, + downloadSessionId: backupPurchase.download_session_id, + merchantBaseUrl: backupPurchase.merchant_base_url, + orderId: backupPurchase.order_id, + payInfo, + refundAmountAwaiting: undefined, + repurchaseProposalId: backupPurchase.repurchase_proposal_id, + status: proposalStatus, + timestamp: backupPurchase.timestamp_proposed, }); } } @@ -948,7 +836,6 @@ export async function importBackup( await tx.depositGroups.delete(rest[0]); } else if (type === TombstoneTag.DeletePayment) { await tx.purchases.delete(rest[0]); - await tx.proposals.delete(rest[0]); } else if (type === TombstoneTag.DeleteRefreshGroup) { await tx.refreshGroups.delete(rest[0]); } else if (type === TombstoneTag.DeleteRefund) { diff --git a/packages/taler-wallet-core/src/operations/backup/index.ts b/packages/taler-wallet-core/src/operations/backup/index.ts index fc84ce4ef..3d3ebf04a 100644 --- a/packages/taler-wallet-core/src/operations/backup/index.ts +++ b/packages/taler-wallet-core/src/operations/backup/index.ts @@ -96,7 +96,7 @@ import { checkPaymentByProposalId, confirmPay, preparePayForUri, -} from "../pay.js"; +} from "../pay-merchant.js"; import { exportBackup } from "./export.js"; import { BackupCryptoPrecomputedData, importBackup } from "./import.js"; import { getWalletBackupState, provideBackupState } from "./state.js"; @@ -193,15 +193,6 @@ async function computeBackupCryptoData( eddsaGetPublic(decodeCrock(backupWg.reserve_priv)), ); } - for (const prop of backupContent.proposals) { - const { h: contractTermsHash } = await cryptoApi.hashString({ - str: canonicalJson(prop.contract_terms_raw), - }); - const noncePub = encodeCrock(eddsaGetPublic(decodeCrock(prop.nonce_priv))); - cryptoData.proposalNoncePrivToPub[prop.nonce_priv] = noncePub; - cryptoData.proposalIdToContractTermsHash[prop.proposal_id] = - contractTermsHash; - } for (const purch of backupContent.purchases) { const { h: contractTermsHash } = await cryptoApi.hashString({ str: canonicalJson(purch.contract_terms_raw), |