DB cleanup

This commit is contained in:
Florian Dold 2020-09-08 20:29:47 +05:30
parent 043a5f89fe
commit 6c0be1cc95
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
12 changed files with 38 additions and 252 deletions

View File

@ -29,7 +29,7 @@
import {
CoinRecord,
DenominationRecord,
RefreshPlanchetRecord,
RefreshPlanchet,
RefreshSessionRecord,
TipPlanchet,
WireFee,
@ -385,7 +385,7 @@ export class CryptoImplementation {
const transferPubs: string[] = [];
const transferPrivs: string[] = [];
const planchetsForGammas: RefreshPlanchetRecord[][] = [];
const planchetsForGammas: RefreshPlanchet[][] = [];
for (let i = 0; i < kappa; i++) {
const transferKeyPair = createEcdheKeyPair();
@ -405,7 +405,7 @@ export class CryptoImplementation {
sessionHc.update(amountToBuffer(valueWithFee));
for (let i = 0; i < kappa; i++) {
const planchets: RefreshPlanchetRecord[] = [];
const planchets: RefreshPlanchet[] = [];
for (let j = 0; j < newCoinDenoms.selectedDenoms.length; j++) {
const denomSel = newCoinDenoms.selectedDenoms[j];
for (let k = 0; k < denomSel.count; k++) {
@ -423,7 +423,7 @@ export class CryptoImplementation {
const pubHash = hash(coinPub);
const denomPub = decodeCrock(denomSel.denom.denomPub);
const ev = rsaBlind(pubHash, blindingFactor, denomPub);
const planchet: RefreshPlanchetRecord = {
const planchet: RefreshPlanchet = {
blindingKey: encodeCrock(blindingFactor),
coinEv: encodeCrock(ev),
privateKey: encodeCrock(coinPriv),

View File

@ -29,9 +29,6 @@ import {
DenominationStatus,
WireFee,
ExchangeUpdateReason,
ExchangeUpdatedEventRecord,
initRetryInfo,
updateRetryInfoTimeout,
} from "../types/dbTypes";
import { canonicalizeBaseUrl } from "../util/helpers";
import * as Amounts from "../util/amounts";
@ -64,6 +61,7 @@ import { URL } from "../util/url";
import { reconcileReserveHistory } from "../util/reserveHistoryUtil";
import { checkDbInvariant } from "../util/invariants";
import { NotificationType } from "../types/notifications";
import { updateRetryInfoTimeout, initRetryInfo } from "../util/retries";
const logger = new Logger("exchanges.ts");
@ -292,7 +290,7 @@ async function updateExchangeFinalize(
return;
}
await ws.db.runWithWriteTransaction(
[Stores.exchanges, Stores.exchangeUpdatedEvents],
[Stores.exchanges],
async (tx) => {
const r = await tx.get(Stores.exchanges, exchangeBaseUrl);
if (!r) {
@ -307,11 +305,6 @@ async function updateExchangeFinalize(
// as now new denominations might be available.
r.nextRefreshCheck = undefined;
await tx.put(Stores.exchanges, r);
const updateEvent: ExchangeUpdatedEventRecord = {
exchangeBaseUrl: exchange.baseUrl,
timestamp: getTimestampNow(),
};
await tx.put(Stores.exchangeUpdatedEvents, updateEvent);
},
);
}
@ -557,7 +550,7 @@ export async function getExchangeTrust(
);
if (currencyRecord) {
for (const trustedExchange of currencyRecord.exchanges) {
if (trustedExchange.exchangePub === exchangeDetails.masterPublicKey) {
if (trustedExchange.exchangeMasterPub === exchangeDetails.masterPublicKey) {
isTrusted = true;
break;
}

View File

@ -27,15 +27,11 @@
import { encodeCrock, getRandomBytes } from "../crypto/talerCrypto";
import {
CoinStatus,
initRetryInfo,
ProposalRecord,
ProposalStatus,
PurchaseRecord,
Stores,
updateRetryInfoTimeout,
PayEventRecord,
WalletContractData,
getRetryDuration,
CoinRecord,
DenominationRecord,
} from "../types/dbTypes";
@ -80,6 +76,7 @@ import {
} from "../util/http";
import { TalerErrorCode } from "../TalerErrorCode";
import { URL } from "../util/url";
import { initRetryInfo, updateRetryInfoTimeout, getRetryDuration } from "../util/retries";
/**
* Logger.
@ -833,7 +830,7 @@ async function storeFirstPaySuccess(
): Promise<void> {
const now = getTimestampNow();
await ws.db.runWithWriteTransaction(
[Stores.purchases, Stores.payEvents],
[Stores.purchases],
async (tx) => {
const purchase = await tx.get(Stores.purchases, proposalId);
@ -864,13 +861,6 @@ async function storeFirstPaySuccess(
}
await tx.put(Stores.purchases, purchase);
const payEvent: PayEventRecord = {
proposalId,
sessionId,
timestamp: now,
isReplay: !isFirst,
};
await tx.put(Stores.payEvents, payEvent);
},
);
}
@ -881,7 +871,7 @@ async function storePayReplaySuccess(
sessionId: string | undefined,
): Promise<void> {
await ws.db.runWithWriteTransaction(
[Stores.purchases, Stores.payEvents],
[Stores.purchases],
async (tx) => {
const purchase = await tx.get(Stores.purchases, proposalId);

View File

@ -34,14 +34,11 @@ import {
RefreshCoinSource,
ReserveRecordStatus,
RecoupGroupRecord,
initRetryInfo,
updateRetryInfoTimeout,
} from "../types/dbTypes";
import { codecForRecoupConfirmation } from "../types/talerTypes";
import { NotificationType } from "../types/notifications";
import {
forceQueryReserve,
getReserveRequestTimeout,
processReserve,
} from "./reserves";
@ -56,6 +53,7 @@ import { guardOperationException } from "./errors";
import { readSuccessResponseJsonOrThrow } from "../util/http";
import { URL } from "../util/url";
import { Logger } from "../util/logging";
import { initRetryInfo, updateRetryInfoTimeout } from "../util/retries";
const logger = new Logger("operations/recoup.ts");

View File

@ -19,11 +19,9 @@ import {
DenominationRecord,
Stores,
CoinStatus,
RefreshPlanchetRecord,
RefreshPlanchet,
CoinRecord,
RefreshSessionRecord,
initRetryInfo,
updateRetryInfoTimeout,
RefreshGroupRecord,
CoinSourceType,
} from "../types/dbTypes";
@ -56,8 +54,6 @@ import {
} from "../util/time";
import {
readSuccessResponseJsonOrThrow,
HttpResponse,
throwUnexpectedRequestError,
} from "../util/http";
import {
codecForExchangeMeltResponse,
@ -65,6 +61,7 @@ import {
} from "../types/talerTypes";
import { URL } from "../util/url";
import { checkDbInvariant } from "../util/invariants";
import { initRetryInfo, updateRetryInfoTimeout } from "../util/retries";
const logger = new Logger("refresh.ts");
@ -326,7 +323,7 @@ async function refreshReveal(
throw Error("inconsistent database");
}
const evs = planchets.map((x: RefreshPlanchetRecord) => x.coinEv);
const evs = planchets.map((x: RefreshPlanchet) => x.coinEv);
const linkSigs: string[] = [];
for (let i = 0; i < refreshSession.newDenoms.length; i++) {

View File

@ -32,8 +32,6 @@ import {
} from "../types/walletTypes";
import {
Stores,
updateRetryInfoTimeout,
initRetryInfo,
CoinStatus,
RefundReason,
RefundState,
@ -55,6 +53,7 @@ import { Logger } from "../util/logging";
import { readSuccessResponseJsonOrThrow } from "../util/http";
import { TransactionHandle } from "../util/query";
import { URL } from "../util/url";
import { updateRetryInfoTimeout, initRetryInfo } from "../util/retries";
const logger = new Logger("refund.ts");
@ -265,7 +264,6 @@ async function acceptRefunds(
Stores.coins,
Stores.denominations,
Stores.refreshGroups,
Stores.refundEvents,
],
async (tx) => {
const p = await tx.get(Stores.purchases, proposalId);

View File

@ -28,14 +28,9 @@ import {
CurrencyRecord,
Stores,
WithdrawalGroupRecord,
initRetryInfo,
updateRetryInfoTimeout,
ReserveUpdatedEventRecord,
WalletReserveHistoryItemType,
WithdrawalSourceType,
ReserveHistoryRecord,
ReserveBankInfo,
getRetryDuration,
} from "../types/dbTypes";
import { Logger } from "../util/logging";
import { Amounts } from "../util/amounts";
@ -86,6 +81,7 @@ import {
} from "../util/http";
import { codecForAny } from "../util/codec";
import { URL } from "../util/url";
import { initRetryInfo, getRetryDuration, updateRetryInfoTimeout } from "../util/retries";
const logger = new Logger("reserves.ts");
@ -206,8 +202,8 @@ export async function createReserve(
if (!isAudited && !isTrusted) {
currencyRecord.exchanges.push({
baseUrl: req.exchange,
exchangePub: exchangeDetails.masterPublicKey,
exchangeBaseUrl: req.exchange,
exchangeMasterPub: exchangeDetails.masterPublicKey,
});
}
@ -554,7 +550,7 @@ async function updateReserve(
const currency = balance.currency;
let updateSummary: ReserveHistorySummary | undefined;
await ws.db.runWithWriteTransaction(
[Stores.reserves, Stores.reserveUpdatedEvents, Stores.reserveHistory],
[Stores.reserves, Stores.reserveHistory],
async (tx) => {
const r = await tx.get(Stores.reserves, reservePub);
if (!r) {
@ -589,15 +585,6 @@ async function updateReserve(
reconciled.newAddedItems.length + reconciled.newMatchedItems.length !=
0
) {
const reserveUpdate: ReserveUpdatedEventRecord = {
reservePub: r.reservePub,
timestamp: getTimestampNow(),
amountReserveBalance: Amounts.stringify(balance),
amountExpected: Amounts.stringify(updateSummary.awaitedReserveAmount),
newHistoryTransactions,
reserveUpdateId,
};
await tx.put(Stores.reserveUpdatedEvents, reserveUpdate);
logger.trace("setting reserve status to 'withdrawing' after query");
r.reserveStatus = ReserveRecordStatus.WITHDRAWING;
r.retryInfo = initRetryInfo();

View File

@ -25,8 +25,6 @@ import {
import * as Amounts from "../util/amounts";
import {
Stores,
initRetryInfo,
updateRetryInfoTimeout,
TipPlanchet,
CoinRecord,
CoinSourceType,
@ -47,6 +45,7 @@ import { URL } from "../util/url";
import { Logger } from "../util/logging";
import { checkDbInvariant } from "../util/invariants";
import { TalerErrorCode } from "../TalerErrorCode";
import { initRetryInfo, updateRetryInfoTimeout } from "../util/retries";
const logger = new Logger("operations/tip.ts");

View File

@ -20,7 +20,6 @@
import { InternalWalletState } from "./state";
import {
Stores,
WithdrawalSourceType,
WalletRefundItem,
RefundState,
ReserveRecordStatus,
@ -95,10 +94,7 @@ export async function getTransactions(
Stores.reserveHistory,
Stores.tips,
Stores.withdrawalGroups,
Stores.payEvents,
Stores.planchets,
Stores.refundEvents,
Stores.reserveUpdatedEvents,
Stores.recoupGroups,
],
// Report withdrawals that are currently in progress.

View File

@ -21,12 +21,9 @@ import {
DenominationStatus,
CoinStatus,
CoinRecord,
initRetryInfo,
updateRetryInfoTimeout,
CoinSourceType,
DenominationSelectionInfo,
PlanchetRecord,
WithdrawalSourceType,
DenomSelectionState,
} from "../types/dbTypes";
import {
@ -64,6 +61,7 @@ import { readSuccessResponseJsonOrThrow } from "../util/http";
import { URL } from "../util/url";
import { TalerErrorCode } from "../TalerErrorCode";
import { encodeCrock } from "../crypto/talerCrypto";
import { updateRetryInfoTimeout, initRetryInfo } from "../util/retries";
const logger = new Logger("withdraw.ts");

View File

@ -46,6 +46,7 @@ import {
import { Timestamp, Duration, getTimestampNow } from "../util/time";
import { PayCoinSelection, PayCostInfo } from "../operations/pay";
import { IDBKeyPath } from "idb-bridge";
import { RetryInfo } from "../util/retries";
export enum ReserveRecordStatus {
/**
@ -84,74 +85,6 @@ export enum ReserveRecordStatus {
BANK_ABORTED = "bank-aborted",
}
export interface RetryInfo {
firstTry: Timestamp;
nextRetry: Timestamp;
retryCounter: number;
active: boolean;
}
export interface RetryPolicy {
readonly backoffDelta: Duration;
readonly backoffBase: number;
}
const defaultRetryPolicy: RetryPolicy = {
backoffBase: 1.5,
backoffDelta: { d_ms: 200 },
};
export function updateRetryInfoTimeout(
r: RetryInfo,
p: RetryPolicy = defaultRetryPolicy,
): void {
const now = getTimestampNow();
if (now.t_ms === "never") {
throw Error("assertion failed");
}
if (p.backoffDelta.d_ms === "forever") {
r.nextRetry = { t_ms: "never" };
return;
}
r.active = true;
const t =
now.t_ms + p.backoffDelta.d_ms * Math.pow(p.backoffBase, r.retryCounter);
r.nextRetry = { t_ms: t };
}
export function getRetryDuration(
r: RetryInfo,
p: RetryPolicy = defaultRetryPolicy,
): Duration {
if (p.backoffDelta.d_ms === "forever") {
return { d_ms: "forever" };
}
const t = p.backoffDelta.d_ms * Math.pow(p.backoffBase, r.retryCounter);
return { d_ms: t };
}
export function initRetryInfo(
active = true,
p: RetryPolicy = defaultRetryPolicy,
): RetryInfo {
if (!active) {
return {
active: false,
firstTry: { t_ms: Number.MAX_SAFE_INTEGER },
nextRetry: { t_ms: Number.MAX_SAFE_INTEGER },
retryCounter: 0,
};
}
const info = {
firstTry: getTimestampNow(),
active: true,
nextRetry: { t_ms: 0 },
retryCounter: 0,
};
updateRetryInfoTimeout(info, p);
return info;
}
export enum WalletReserveHistoryItemType {
Credit = "credit",
Withdraw = "withdraw",
@ -353,10 +286,12 @@ export interface AuditorRecord {
* Base url of the auditor.
*/
baseUrl: string;
/**
* Public signing key of the auditor.
*/
auditorPub: string;
/**
* Time when the auditing expires.
*/
@ -371,11 +306,12 @@ export interface ExchangeForCurrencyRecord {
/**
* FIXME: unused?
*/
exchangePub: string;
exchangeMasterPub: string;
/**
* Base URL of the exchange.
*/
baseUrl: string;
exchangeBaseUrl: string;
}
/**
@ -386,14 +322,17 @@ export interface CurrencyRecord {
* Name of the currency.
*/
name: string;
/**
* Number of fractional digits to show when rendering the currency.
*/
fractionalDigits: number;
/**
* Auditors that the wallet trusts for this currency.
*/
auditors: AuditorRecord[];
/**
* Exchanges that the wallet trusts for this currency.
*/
@ -722,7 +661,7 @@ export interface PlanchetRecord {
/**
* Planchet for a coin during refrehs.
*/
export interface RefreshPlanchetRecord {
export interface RefreshPlanchet {
/**
* Public key for the coin.
*/
@ -1083,7 +1022,7 @@ export interface RefreshSessionRecord {
/**
* Planchets for each cut-and-choose instance.
*/
planchetsForGammas: RefreshPlanchetRecord[][];
planchetsForGammas: RefreshPlanchet[][];
/**
* The transfer keys, kappa of them.
@ -1431,54 +1370,6 @@ export interface ConfigRecord {
value: any;
}
/**
* Coin that we're depositing ourselves.
*/
export interface DepositCoin {
coinPaySig: CoinDepositPermission;
/**
* Undefined if coin not deposited, otherwise signature
* from the exchange confirming the deposit.
*/
depositedSig?: string;
}
/**
* Record stored in the wallet's database when the user sends coins back to
* their own bank account. Stores the status of coins that are deposited to
* the wallet itself, where the wallet acts as a "merchant" for the customer.
*/
export interface CoinsReturnRecord {
contractTermsRaw: string;
contractData: WalletContractData;
/**
* Private key where corresponding
* public key is used in the contract terms
* as merchant pub.
*/
merchantPriv: string;
coins: DepositCoin[];
/**
* Exchange base URL to deposit coins at.
*/
exchange: string;
/**
* Our own wire information for the deposit.
*/
wire: any;
}
export enum WithdrawalSourceType {
Tip = "tip",
Reserve = "reserve",
}
export interface DenominationSelectionInfo {
totalCoinValue: AmountJson;
totalWithdrawCost: AmountJson;
@ -1610,31 +1501,6 @@ export enum ImportPayloadType {
CoreSchema = "core-schema",
}
/**
* Record to keep track of data imported into the wallet.
*/
export class WalletImportRecord {
/**
* Unique ID to reference this import record.
*/
walletImportId: string;
/**
* When was the data imported?
*/
timestampImportStarted: Timestamp;
timestampImportFinished: Timestamp | undefined;
payloadType: ImportPayloadType;
/**
* The actual data to import.
*/
payload: any;
}
/* tslint:disable:completed-docs */
class ExchangesStore extends Store<ExchangeRecord> {
constructor() {
@ -1773,51 +1639,21 @@ class PlanchetsStore extends Store<PlanchetRecord> {
);
}
class RefundEventsStore extends Store<RefundEventRecord> {
constructor() {
super("refundEvents", { keyPath: "refundGroupId" });
}
}
class PayEventsStore extends Store<PayEventRecord> {
constructor() {
super("payEvents", { keyPath: "proposalId" });
}
}
class ExchangeUpdatedEventsStore extends Store<ExchangeUpdatedEventRecord> {
constructor() {
super("exchangeUpdatedEvents", { keyPath: "exchangeBaseUrl" });
}
}
class ReserveUpdatedEventsStore extends Store<ReserveUpdatedEventRecord> {
constructor() {
super("reserveUpdatedEvents", { keyPath: "reservePub" });
}
}
/**
* This store is effectively a materialized index for
* reserve records that are for a bank-integrated withdrawal.
*/
class BankWithdrawUrisStore extends Store<BankWithdrawUriRecord> {
constructor() {
super("bankWithdrawUris", { keyPath: "talerWithdrawUri" });
}
}
class WalletImportsStore extends Store<WalletImportRecord> {
constructor() {
super("walletImports", { keyPath: "walletImportId" });
}
}
/**
* The stores and indices for the wallet database.
*/
export const Stores = {
coins: new CoinsStore(),
coinsReturns: new Store<CoinsReturnRecord>("coinsReturns", {
keyPath: "contractTermsHash",
}),
config: new ConfigStore(),
currencies: new CurrenciesStore(),
denominations: new DenominationsStore(),
@ -1837,11 +1673,4 @@ export const Stores = {
withdrawalGroups: new WithdrawalGroupsStore(),
planchets: new PlanchetsStore(),
bankWithdrawUris: new BankWithdrawUrisStore(),
refundEvents: new RefundEventsStore(),
payEvents: new PayEventsStore(),
reserveUpdatedEvents: new ReserveUpdatedEventsStore(),
exchangeUpdatedEvents: new ExchangeUpdatedEventsStore(),
walletImports: new WalletImportsStore(),
};
/* tslint:enable:completed-docs */

View File

@ -22,8 +22,9 @@
* Imports.
*/
import { TalerErrorDetails, BalancesResponse } from "./walletTypes";
import { RetryInfo, ReserveRecordStatus } from "./dbTypes";
import { ReserveRecordStatus } from "./dbTypes";
import { Timestamp, Duration } from "../util/time";
import { RetryInfo } from "../util/retries";
export enum PendingOperationType {
Bug = "bug",