aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2023-09-08 11:45:31 +0200
committerFlorian Dold <florian@dold.me>2023-09-08 11:45:31 +0200
commit132ece8e53d2c7d69c943a2898ed07411c63f12f (patch)
treedbe97c498c5853efd844aab4502ae97d8dec7b4a
parentc660db82c12e08020661828f1d8383baa7ef0e02 (diff)
wallet-core: store contract terms in separate object store only
-rw-r--r--packages/taler-wallet-core/src/db.ts75
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts33
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts1
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts33
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts64
5 files changed, 106 insertions, 100 deletions
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 9aedb888b..679ca2842 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -102,6 +102,14 @@ import { RetryInfo, TaskIdentifiers } from "./operations/common.js";
*/
/**
+ FIXMEs:
+ - Contract terms can be quite large. We currently tend to read the
+ full contract terms from the DB quite often.
+ Instead, we should probably extract what we need into a separate object
+ store.
+ */
+
+/**
* Name of the Taler database. This is effectively the major
* version of the DB schema. Whenever it changes, custom import logic
* for all previous versions must be written, which should be
@@ -166,47 +174,47 @@ export enum WithdrawalGroupStatus {
/**
* Reserve must be registered with the bank.
*/
- PendingRegisteringBank = 0x0100_0000,
- SuspendedRegisteringBank = 0x0110_0000,
+ PendingRegisteringBank = 0x0100_0001,
+ SuspendedRegisteringBank = 0x0110_0001,
/**
* We've registered reserve's information with the bank
* and are now waiting for the user to confirm the withdraw
* with the bank (typically 2nd factor auth).
*/
- PendingWaitConfirmBank = 0x0100_0001,
- SuspendedWaitConfirmBank = 0x0110_0001,
+ PendingWaitConfirmBank = 0x0100_0002,
+ SuspendedWaitConfirmBank = 0x0110_0002,
/**
* Querying reserve status with the exchange.
*/
- PendingQueryingStatus = 0x0100_0002,
- SuspendedQueryingStatus = 0x0110_0002,
+ PendingQueryingStatus = 0x0100_0003,
+ SuspendedQueryingStatus = 0x0110_0003,
/**
* Ready for withdrawal.
*/
- PendingReady = 0x0100_0003,
- SuspendedReady = 0x0110_0003,
+ PendingReady = 0x0100_0004,
+ SuspendedReady = 0x0110_0004,
/**
* We are telling the bank that we don't want to complete
* the withdrawal!
*/
- AbortingBank = 0x0103_0000,
- SuspendedAbortingBank = 0x0113_0000,
+ AbortingBank = 0x0103_0001,
+ SuspendedAbortingBank = 0x0113_0001,
/**
* Exchange wants KYC info from the user.
*/
- PendingKyc = 0x0100_0004,
- SuspendedKyc = 0x0110_004,
+ PendingKyc = 0x0100_0005,
+ SuspendedKyc = 0x0110_005,
/**
* Exchange is doing AML checks.
*/
- PendingAml = 0x0100_0005,
- SuspendedAml = 0x0100_0005,
+ PendingAml = 0x0100_0006,
+ SuspendedAml = 0x0100_0006,
/**
* The corresponding withdraw record has been created.
@@ -218,9 +226,9 @@ export enum WithdrawalGroupStatus {
/**
* The bank aborted the withdrawal.
*/
- FailedBankAborted = 0x0501_0000,
+ FailedBankAborted = 0x0501_0001,
- FailedAbortingBank = 0x0501_0001,
+ FailedAbortingBank = 0x0501_0002,
/**
* Aborted in a state where we were supposed to
@@ -272,9 +280,9 @@ export interface ReserveBankInfo {
*/
export enum DenominationVerificationStatus {
/**
- * Verification was delayed.
+ * Verification was delayed (pending).
*/
- Unverified = 0x0500_0000,
+ Unverified = 0x0100_0000,
/**
* Verified as valid.
@@ -532,6 +540,7 @@ export enum ExchangeEntryDbRecordStatus {
Used = 3,
}
+// FIXME: Use status ranges for this as well?
export enum ExchangeEntryDbUpdateStatus {
Initial = 1,
InitialUpdate = 2,
@@ -612,9 +621,9 @@ export interface ExchangeEntryRecord {
}
export enum PlanchetStatus {
- Pending = 10 /* ACTIVE_START */,
- KycRequired = 11 /* ACTIVE_START + 1 */,
- WithdrawalDone = 50 /* DORMANT_START */,
+ Pending = 0x0100_0000,
+ KycRequired = 0x0100_0001,
+ WithdrawalDone = 0x0500_000,
}
/**
@@ -1358,7 +1367,8 @@ export interface WgInfoBankManual {
export interface WgInfoBankPeerPull {
withdrawalType: WithdrawalRecordType.PeerPullCredit;
- contractTerms: any;
+ // FIXME: include a transaction ID here?
+
/**
* Needed to quickly construct the taler:// URI for the counterparty
* without a join.
@@ -1369,7 +1379,7 @@ export interface WgInfoBankPeerPull {
export interface WgInfoBankPeerPush {
withdrawalType: WithdrawalRecordType.PeerPushCredit;
- contractTerms: any;
+ // FIXME: include a transaction ID here?
}
export interface WgInfoBankRecoup {
@@ -1829,11 +1839,6 @@ export interface PeerPushDebitRecord {
*/
contractEncNonce: string;
- /**
- * FIXME: Put those in a different object store!
- */
- contractTerms: PeerContractTerms;
-
purseExpiration: TalerProtocolTimestamp;
timestampCreated: TalerPreciseTimestamp;
@@ -1861,7 +1866,7 @@ export enum PeerPullPaymentCreditStatus {
SuspendedCreatePurse = 0x0110_0000,
SuspendedReady = 0x0110_0001,
SuspendedMergeKycRequired = 0x0110_0002,
- SuspendedWithdrawing = 0x0113_0000,
+ SuspendedWithdrawing = 0x0110_0000,
SuspendedAbortingDeletePurse = 0x0113_0000,
@@ -1878,6 +1883,7 @@ export interface PeerPullCreditRecord {
/**
* Amount requested.
+ * FIXME: What type of instructed amount is i?
*/
amount: AmountString;
@@ -1908,11 +1914,6 @@ export interface PeerPullCreditRecord {
contractEncNonce: string;
- /**
- * FIXME: Put in separate object store!
- */
- contractTerms: PeerContractTerms;
-
mergeTimestamp: TalerPreciseTimestamp;
mergeReserveRowId: number;
@@ -2529,8 +2530,7 @@ export const WalletStoresV1 = {
byWithdrawalGroupId: describeIndex(
"byWithdrawalGroupId",
"withdrawalGroupId",
- {
- },
+ {},
),
},
),
@@ -2571,8 +2571,7 @@ export const WalletStoresV1 = {
}),
{
byProposalId: describeIndex("byProposalId", "proposalId"),
- byStatus: describeIndex("byStatus", "status", {
- }),
+ byStatus: describeIndex("byStatus", "status", {}),
},
),
refundItems: describeStore(
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts b/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts
index edadad1fc..0355eb152 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts
@@ -27,6 +27,7 @@ import {
InitiatePeerPullCreditResponse,
Logger,
NotificationType,
+ PeerContractTerms,
TalerErrorCode,
TalerPreciseTimestamp,
TalerProtocolTimestamp,
@@ -143,7 +144,6 @@ async function queryPurseForPeerPullCredit(
amount: Amounts.parseOrThrow(pullIni.amount),
wgInfo: {
withdrawalType: WithdrawalRecordType.PeerPullCredit,
- contractTerms: pullIni.contractTerms,
contractPriv: pullIni.contractPriv,
},
forcedWithdrawalGroupId: pullIni.withdrawalGroupId,
@@ -283,9 +283,7 @@ async function processPeerPullCreditAbortingDeletePurse(
if (!ppiRec) {
return undefined;
}
- if (
- ppiRec.status !== PeerPullPaymentCreditStatus.AbortingDeletePurse
- ) {
+ if (ppiRec.status !== PeerPullPaymentCreditStatus.AbortingDeletePurse) {
return undefined;
}
const oldTxState = computePeerPullCreditTransactionState(ppiRec);
@@ -371,6 +369,18 @@ async function handlePeerPullCreditCreatePurse(
throw Error("merge reserve for peer pull payment not found in database");
}
+ const contractTermsRecord = await ws.db
+ .mktx((x) => [x.contractTerms])
+ .runReadOnly(async (tx) => {
+ return tx.contractTerms.get(pullIni.contractTermsHash);
+ });
+
+ if (!contractTermsRecord) {
+ throw Error("contract terms for peer pull payment not found in database");
+ }
+
+ const contractTerms: PeerContractTerms = contractTermsRecord.contractTermsRaw;
+
const reservePayto = talerPaytoFromExchangeReserve(
pullIni.exchangeBaseUrl,
mergeReserve.reservePub,
@@ -379,19 +389,19 @@ async function handlePeerPullCreditCreatePurse(
const econtractResp = await ws.cryptoApi.encryptContractForDeposit({
contractPriv: pullIni.contractPriv,
contractPub: pullIni.contractPub,
- contractTerms: pullIni.contractTerms,
+ contractTerms: contractTermsRecord,
pursePriv: pullIni.pursePriv,
pursePub: pullIni.pursePub,
nonce: pullIni.contractEncNonce,
});
- const purseExpiration = pullIni.contractTerms.purse_expiration;
+ const purseExpiration = contractTerms.purse_expiration;
const sigRes = await ws.cryptoApi.signReservePurseCreate({
contractTermsHash: pullIni.contractTermsHash,
flags: WalletAccountMergeFlags.CreateWithPurseFee,
mergePriv: pullIni.mergePriv,
mergeTimestamp: TalerPreciseTimestamp.round(pullIni.mergeTimestamp),
- purseAmount: pullIni.contractTerms.amount,
+ purseAmount: pullIni.amount,
purseExpiration: purseExpiration,
purseFee: purseFee,
pursePriv: pullIni.pursePriv,
@@ -410,7 +420,7 @@ async function handlePeerPullCreditCreatePurse(
purse_fee: purseFee,
purse_pub: pullIni.pursePub,
purse_sig: sigRes.purseSig,
- purse_value: pullIni.contractTerms.amount,
+ purse_value: pullIni.amount,
reserve_sig: sigRes.accountSig,
econtract: econtractResp.econtract,
};
@@ -585,8 +595,7 @@ async function processPeerPullCreditKycRequired(
requirementRow: kycPending.requirement_row,
};
peerInc.kycUrl = kycStatus.kyc_url;
- peerInc.status =
- PeerPullPaymentCreditStatus.PendingMergeKycRequired;
+ peerInc.status = PeerPullPaymentCreditStatus.PendingMergeKycRequired;
const newTxState = computePeerPullCreditTransactionState(peerInc);
await tx.peerPullCredit.put(peerInc);
// We'll remove this eventually! New clients should rely on the
@@ -769,7 +778,6 @@ export async function initiatePeerPullPayment(
mergePriv: mergePair.priv,
mergePub: mergePair.pub,
status: PeerPullPaymentCreditStatus.PendingCreatePurse,
- contractTerms: contractTerms,
mergeTimestamp,
contractEncNonce,
mergeReserveRowId: mergeReserveRowId,
@@ -848,8 +856,7 @@ export async function suspendPeerPullCreditTransaction(
newStatus = PeerPullPaymentCreditStatus.SuspendedReady;
break;
case PeerPullPaymentCreditStatus.AbortingDeletePurse:
- newStatus =
- PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse;
+ newStatus = PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse;
break;
case PeerPullPaymentCreditStatus.Done:
case PeerPullPaymentCreditStatus.SuspendedCreatePurse:
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts b/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts
index f0f659aa3..89d9e3b49 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts
@@ -446,7 +446,6 @@ async function handlePendingMerge(
amount,
wgInfo: {
withdrawalType: WithdrawalRecordType.PeerPushCredit,
- contractTerms,
},
forcedWithdrawalGroupId: peerInc.withdrawalGroupId,
exchangeBaseUrl: peerInc.exchangeBaseUrl,
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
index a2e7a6891..e80ffc059 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
@@ -154,9 +154,7 @@ async function handlePurseCreationConflict(
await ws.db
.mktx((x) => [x.peerPushDebit])
.runReadWrite(async (tx) => {
- const myPpi = await tx.peerPushDebit.get(
- peerPushInitiation.pursePub,
- );
+ const myPpi = await tx.peerPushDebit.get(peerPushInitiation.pursePub);
if (!myPpi) {
return;
}
@@ -182,10 +180,27 @@ async function processPeerPushDebitCreateReserve(
ws: InternalWalletState,
peerPushInitiation: PeerPushDebitRecord,
): Promise<TaskRunResult> {
- logger.info("processing peer-push-debit pending(create-reserve)");
const pursePub = peerPushInitiation.pursePub;
const purseExpiration = peerPushInitiation.purseExpiration;
const hContractTerms = peerPushInitiation.contractTermsHash;
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.PeerPushDebit,
+ pursePub: pursePub,
+ });
+
+ logger.trace(`processing ${transactionId} pending(create-reserve)`);
+
+ const contractTermsRecord = await ws.db
+ .mktx((x) => [x.contractTerms])
+ .runReadOnly(async (tx) => {
+ return tx.contractTerms.get(hContractTerms);
+ });
+
+ if (!contractTermsRecord) {
+ throw Error(
+ `db invariant failed, contract terms for ${transactionId} missing`,
+ );
+ }
const purseSigResp = await ws.cryptoApi.signPurseCreation({
hContractTerms,
@@ -208,7 +223,7 @@ async function processPeerPushDebitCreateReserve(
});
const encryptContractRequest: EncryptContractRequest = {
- contractTerms: peerPushInitiation.contractTerms,
+ contractTerms: contractTermsRecord.contractTermsRaw,
mergePriv: peerPushInitiation.mergePriv,
pursePriv: peerPushInitiation.pursePriv,
pursePub: peerPushInitiation.pursePub,
@@ -329,9 +344,7 @@ async function processPeerPushDebitAbortingDeletePurse(
if (!ppiRec) {
return undefined;
}
- if (
- ppiRec.status !== PeerPushDebitStatus.AbortingDeletePurse
- ) {
+ if (ppiRec.status !== PeerPushDebitStatus.AbortingDeletePurse) {
return undefined;
}
const currency = Amounts.currencyOf(ppiRec.amount);
@@ -658,7 +671,6 @@ export async function initiatePeerPushDebit(
pursePub: pursePair.pub,
timestampCreated: TalerPreciseTimestamp.now(),
status: PeerPushDebitStatus.PendingCreatePurse,
- contractTerms: contractTerms,
contractEncNonce,
coinSel: {
coinPubs: sel.coins.map((x) => x.coinPub),
@@ -881,8 +893,7 @@ export async function suspendPeerPushDebitTransaction(
newStatus = PeerPushDebitStatus.SuspendedAbortingRefresh;
break;
case PeerPushDebitStatus.AbortingDeletePurse:
- newStatus =
- PeerPushDebitStatus.SuspendedAbortingDeletePurse;
+ newStatus = PeerPushDebitStatus.SuspendedAbortingDeletePurse;
break;
case PeerPushDebitStatus.PendingReady:
newStatus = PeerPushDebitStatus.SuspendedReady;
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 5c57195c1..ff9fbf57a 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -154,7 +154,18 @@ import {
resumePeerPushDebitTransaction,
abortPeerPushDebitTransaction,
} from "./pay-peer-push-debit.js";
-import { iterRecordsForDeposit, iterRecordsForPeerPullDebit, iterRecordsForPeerPullInitiation, iterRecordsForPeerPushCredit, iterRecordsForPeerPushInitiation, iterRecordsForPurchase, iterRecordsForRefresh, iterRecordsForRefund, iterRecordsForReward, iterRecordsForWithdrawal } from "./pending.js";
+import {
+ iterRecordsForDeposit,
+ iterRecordsForPeerPullDebit,
+ iterRecordsForPeerPullInitiation,
+ iterRecordsForPeerPushCredit,
+ iterRecordsForPeerPushInitiation,
+ iterRecordsForPurchase,
+ iterRecordsForRefresh,
+ iterRecordsForRefund,
+ iterRecordsForReward,
+ iterRecordsForWithdrawal,
+} from "./pending.js";
const logger = new Logger("taler-wallet-core:transactions.ts");
@@ -337,9 +348,7 @@ export async function getTransactionById(
return await ws.db
.mktx((x) => [x.peerPullDebit])
.runReadWrite(async (tx) => {
- const debit = await tx.peerPullDebit.get(
- parsedTx.peerPullDebitId,
- );
+ const debit = await tx.peerPullDebit.get(parsedTx.peerPullDebitId);
if (!debit) throw Error("not found");
return buildTransactionForPullPaymentDebit(debit);
});
@@ -349,9 +358,7 @@ export async function getTransactionById(
return await ws.db
.mktx((x) => [x.peerPushDebit, x.contractTerms])
.runReadWrite(async (tx) => {
- const debit = await tx.peerPushDebit.get(
- parsedTx.pursePub,
- );
+ const debit = await tx.peerPushDebit.get(parsedTx.pursePub);
if (!debit) throw Error("not found");
const ct = await tx.contractTerms.get(debit.contractTermsHash);
checkDbInvariant(!!ct);
@@ -372,9 +379,7 @@ export async function getTransactionById(
x.operationRetries,
])
.runReadWrite(async (tx) => {
- const pushInc = await tx.peerPushCredit.get(
- peerPushCreditId,
- );
+ const pushInc = await tx.peerPushCredit.get(peerPushCreditId);
if (!pushInc) throw Error("not found");
const ct = await tx.contractTerms.get(pushInc.contractTermsHash);
checkDbInvariant(!!ct);
@@ -532,8 +537,8 @@ function buildTransactionForPeerPullCredit(
// Old transactions don't have it!
timestamp: pullCredit.mergeTimestamp ?? TalerPreciseTimestamp.now(),
info: {
- expiration: wsr.wgInfo.contractTerms.purse_expiration,
- summary: wsr.wgInfo.contractTerms.summary,
+ expiration: peerContractTerms.purse_expiration,
+ summary: peerContractTerms.summary,
},
talerUri: stringifyPayPullUri({
exchangeBaseUrl: wsr.exchangeBaseUrl,
@@ -600,8 +605,8 @@ function buildTransactionForPeerPushCredit(
amountRaw: Amounts.stringify(wsr.instructedAmount),
exchangeBaseUrl: wsr.exchangeBaseUrl,
info: {
- expiration: wsr.wgInfo.contractTerms.purse_expiration,
- summary: wsr.wgInfo.contractTerms.summary,
+ expiration: peerContractTerms.purse_expiration,
+ summary: peerContractTerms.summary,
},
timestamp: wsr.timestampStart,
transactionId: constructTransactionIdentifier({
@@ -1033,7 +1038,7 @@ export async function getTransactions(
),
);
});
-
+
await iterRecordsForPeerPullInitiation(tx, filter, async (pi) => {
const currency = Amounts.currencyOf(pi.amount);
if (shouldSkipCurrency(transactionsRequest, currency)) {
@@ -1078,7 +1083,7 @@ export async function getTransactions(
);
transactions.push(buildTransactionForRefund(refundGroup, contractData));
});
-
+
await iterRecordsForRefresh(tx, filter, async (rg) => {
if (shouldSkipCurrency(transactionsRequest, rg.currency)) {
return;
@@ -1099,7 +1104,7 @@ export async function getTransactions(
}
});
- await iterRecordsForWithdrawal(tx, filter ,async (wsr) => {
+ await iterRecordsForWithdrawal(tx, filter, async (wsr) => {
if (
shouldSkipCurrency(
transactionsRequest,
@@ -1643,15 +1648,9 @@ export async function deleteTransaction(
case TransactionType.PeerPushCredit: {
const peerPushCreditId = parsedTx.peerPushCreditId;
await ws.db
- .mktx((x) => [
- x.withdrawalGroups,
- x.peerPushCredit,
- x.tombstones,
- ])
+ .mktx((x) => [x.withdrawalGroups, x.peerPushCredit, x.tombstones])
.runReadWrite(async (tx) => {
- const pushInc = await tx.peerPushCredit.get(
- peerPushCreditId,
- );
+ const pushInc = await tx.peerPushCredit.get(peerPushCreditId);
if (!pushInc) {
return;
}
@@ -1670,10 +1669,7 @@ export async function deleteTransaction(
}
await tx.peerPushCredit.delete(peerPushCreditId);
await tx.tombstones.put({
- id:
- TombstoneTag.DeletePeerPushCredit +
- ":" +
- peerPushCreditId,
+ id: TombstoneTag.DeletePeerPushCredit + ":" + peerPushCreditId,
});
});
return;
@@ -1682,11 +1678,7 @@ export async function deleteTransaction(
case TransactionType.PeerPullCredit: {
const pursePub = parsedTx.pursePub;
await ws.db
- .mktx((x) => [
- x.withdrawalGroups,
- x.peerPullCredit,
- x.tombstones,
- ])
+ .mktx((x) => [x.withdrawalGroups, x.peerPullCredit, x.tombstones])
.runReadWrite(async (tx) => {
const pullIni = await tx.peerPullCredit.get(pursePub);
if (!pullIni) {
@@ -1813,9 +1805,7 @@ export async function deleteTransaction(
await ws.db
.mktx((x) => [x.peerPullDebit, x.tombstones])
.runReadWrite(async (tx) => {
- const debit = await tx.peerPullDebit.get(
- peerPullDebitId,
- );
+ const debit = await tx.peerPullDebit.get(peerPullDebitId);
if (debit) {
await tx.peerPullDebit.delete(peerPullDebitId);
await tx.tombstones.put({ id: transactionId });