diff options
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/taler-wallet-core/src/db.ts | 21 | ||||
| -rw-r--r-- | packages/taler-wallet-core/src/dbless.ts | 24 | ||||
| -rw-r--r-- | packages/taler-wallet-core/src/operations/deposits.ts | 35 | ||||
| -rw-r--r-- | packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts | 117 | ||||
| -rw-r--r-- | packages/taler-wallet-core/src/operations/transactions.ts | 42 | 
5 files changed, 142 insertions, 97 deletions
| diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 04c3ce723..9bf9a29cc 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -28,6 +28,7 @@ import {  } from "@gnu-taler/idb-bridge";  import {    AgeCommitmentProof, +  AmountJson,    AmountString,    Amounts,    AttentionInfo, @@ -1640,6 +1641,15 @@ export interface DepositTrackingInfo {  export interface DepositGroupRecord {    depositGroupId: string; +  currency: string; + +  /** +   * Instructed amount. +   */ +  amount: AmountString; + +  wireTransferDeadline: TalerProtocolTimestamp; +    merchantPub: string;    merchantPriv: string; @@ -1655,13 +1665,6 @@ export interface DepositGroupRecord {      salt: string;    }; -  /** -   * Verbatim contract terms. -   *  -   * FIXME: Move this to the contract terms object store! -   */ -  contractTermsRaw: MerchantContractTerms; -    contractTermsHash: string;    payCoinSelection: PayCoinSelection; @@ -1981,7 +1984,9 @@ export interface PeerPullPaymentIncomingRecord {    exchangeBaseUrl: string; -  contractTerms: PeerContractTerms; +  amount: AmountString; + +  contractTermsHash: string;    timestampCreated: TalerPreciseTimestamp; diff --git a/packages/taler-wallet-core/src/dbless.ts b/packages/taler-wallet-core/src/dbless.ts index 11c6c0f74..65c293bdf 100644 --- a/packages/taler-wallet-core/src/dbless.ts +++ b/packages/taler-wallet-core/src/dbless.ts @@ -33,12 +33,13 @@ import {    AmountString,    codecForAny,    codecForBankWithdrawalOperationPostResponse, -  codecForDepositSuccess, +  codecForBatchDepositSuccess,    codecForExchangeMeltResponse,    codecForExchangeRevealResponse,    codecForWithdrawResponse,    DenominationPubKey,    encodeCrock, +  ExchangeBatchDepositRequest,    ExchangeMeltRequest,    ExchangeProtocolVersion,    ExchangeWithdrawRequest, @@ -256,22 +257,27 @@ export async function depositCoin(args: {      refundDeadline: refundDeadline,      wireInfoHash: hashWire(depositPayto, wireSalt),    }); -  const requestBody = { -    contribution: Amounts.stringify(dp.contribution), +  const requestBody: ExchangeBatchDepositRequest = { +    coins: [ +      { +        contribution: Amounts.stringify(dp.contribution), +        coin_pub: dp.coin_pub, +        coin_sig: dp.coin_sig, +        denom_pub_hash: dp.h_denom, +        ub_sig: dp.ub_sig, +      }, +    ],      merchant_payto_uri: depositPayto,      wire_salt: wireSalt,      h_contract_terms: contractTermsHash, -    ub_sig: coin.denomSig,      timestamp: depositTimestamp,      wire_transfer_deadline: wireTransferDeadline,      refund_deadline: refundDeadline, -    coin_sig: dp.coin_sig, -    denom_pub_hash: dp.h_denom,      merchant_pub: merchantPub,    }; -  const url = new URL(`coins/${dp.coin_pub}/deposit`, dp.exchange_url); -  const httpResp = await http.postJson(url.href, requestBody); -  await readSuccessResponseJsonOrThrow(httpResp, codecForDepositSuccess()); +  const url = new URL(`batch-deposit`, dp.exchange_url); +  const httpResp = await http.fetch(url.href, { body: requestBody }); +  await readSuccessResponseJsonOrThrow(httpResp, codecForBatchDepositSuccess());  }  export async function refreshCoin(req: { diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts index a3483a332..2de8f30a1 100644 --- a/packages/taler-wallet-core/src/operations/deposits.ts +++ b/packages/taler-wallet-core/src/operations/deposits.ts @@ -884,8 +884,18 @@ async function processDepositGroupPendingDeposit(  ): Promise<TaskRunResult> {    logger.info("processing deposit group in pending(deposit)");    const depositGroupId = depositGroup.depositGroupId; +  const contractTermsRec = await ws.db +    .mktx((x) => [x.contractTerms]) +    .runReadOnly(async (tx) => { +      return tx.contractTerms.get(depositGroup.contractTermsHash); +    }); +  if (!contractTermsRec) { +    throw Error("contract terms for deposit not found in database"); +  } +  const contractTerms: MerchantContractTerms = +    contractTermsRec.contractTermsRaw;    const contractData = extractContractData( -    depositGroup.contractTermsRaw, +    contractTermsRec.contractTermsRaw,      depositGroup.contractTermsHash,      "",    ); @@ -921,12 +931,11 @@ async function processDepositGroupPendingDeposit(        coins,        h_contract_terms: depositGroup.contractTermsHash,        merchant_payto_uri: depositGroup.wire.payto_uri, -      merchant_pub: depositGroup.contractTermsRaw.merchant_pub, -      timestamp: depositGroup.contractTermsRaw.timestamp, +      merchant_pub: contractTerms.merchant_pub, +      timestamp: contractTerms.timestamp,        wire_salt: depositGroup.wire.salt, -      wire_transfer_deadline: -        depositGroup.contractTermsRaw.wire_transfer_deadline, -      refund_deadline: depositGroup.contractTermsRaw.refund_deadline, +      wire_transfer_deadline: contractTerms.wire_transfer_deadline, +      refund_deadline: contractTerms.refund_deadline,      };      for (let i = 0; i < depositPermissions.length; i++) { @@ -1086,7 +1095,10 @@ async function trackDeposit(    coinPub: string,    exchangeUrl: string,  ): Promise<TrackTransaction> { -  const wireHash = depositGroup.contractTermsRaw.h_wire; +  const wireHash = hashWire( +    depositGroup.wire.payto_uri, +    depositGroup.wire.salt, +  );    const url = new URL(      `deposits/${wireHash}/${depositGroup.merchantPub}/${depositGroup.contractTermsHash}/${coinPub}`, @@ -1358,8 +1370,9 @@ export async function createDepositGroup(    const depositGroup: DepositGroupRecord = {      contractTermsHash, -    contractTermsRaw: contractTerms,      depositGroupId, +    currency: Amounts.currencyOf(totalDepositCost), +    amount: contractData.amount,      noncePriv: noncePair.priv,      noncePub: noncePair.pub,      timestampCreated: AbsoluteTime.toPreciseTimestamp(now), @@ -1375,6 +1388,7 @@ export async function createDepositGroup(      counterpartyEffectiveDepositAmount: Amounts.stringify(        counterpartyEffectiveDepositAmount,      ), +    wireTransferDeadline: contractTerms.wire_transfer_deadline,      wire: {        payto_uri: req.depositPaytoUri,        salt: wireSalt, @@ -1395,6 +1409,7 @@ export async function createDepositGroup(        x.denominations,        x.refreshGroups,        x.coinAvailability, +      x.contractTerms,      ])      .runReadWrite(async (tx) => {        await spendCoins(ws, tx, { @@ -1406,6 +1421,10 @@ export async function createDepositGroup(          refreshReason: RefreshReason.PayDeposit,        });        await tx.depositGroups.put(depositGroup); +      await tx.contractTerms.put({ +        contractTermsRaw: contractTerms, +        h: contractTermsHash, +      });        return computeDepositTransactionStatus(depositGroup);      }); diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts index f357c41d5..5bcfa3418 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts @@ -19,6 +19,7 @@ import {    Amounts,    CoinRefreshRequest,    ConfirmPeerPullDebitRequest, +  ContractTermsUtil,    ExchangePurseDeposits,    HttpStatusCode,    Logger, @@ -103,9 +104,7 @@ async function handlePurseCreationConflict(      throw new TalerProtocolViolationError();    } -  const instructedAmount = Amounts.parseOrThrow( -    peerPullInc.contractTerms.amount, -  ); +  const instructedAmount = Amounts.parseOrThrow(peerPullInc.amount);    const sel = peerPullInc.coinSel;    if (!sel) { @@ -142,9 +141,7 @@ async function handlePurseCreationConflict(    await ws.db      .mktx((x) => [x.peerPullDebit])      .runReadWrite(async (tx) => { -      const myPpi = await tx.peerPullDebit.get( -        peerPullInc.peerPullDebitId, -      ); +      const myPpi = await tx.peerPullDebit.get(peerPullInc.peerPullDebitId);        if (!myPpi) {          return;        } @@ -220,9 +217,7 @@ async function processPeerPullDebitPendingDeposit(        const transitionInfo = await ws.db          .mktx((x) => [x.peerPullDebit])          .runReadWrite(async (tx) => { -          const pi = await tx.peerPullDebit.get( -            peerPullDebitId, -          ); +          const pi = await tx.peerPullDebit.get(peerPullDebitId);            if (!pi) {              throw Error("peer pull payment not found anymore");            } @@ -248,9 +243,7 @@ async function processPeerPullDebitPendingDeposit(            x.coins,          ])          .runReadWrite(async (tx) => { -          const pi = await tx.peerPullDebit.get( -            peerPullDebitId, -          ); +          const pi = await tx.peerPullDebit.get(peerPullDebitId);            if (!pi) {              throw Error("peer pull payment not found anymore");            } @@ -335,9 +328,7 @@ async function processPeerPullDebitAbortingRefresh(          }        }        if (newOpState) { -        const newDg = await tx.peerPullDebit.get( -          peerPullDebitId, -        ); +        const newDg = await tx.peerPullDebit.get(peerPullDebitId);          if (!newDg) {            return;          } @@ -391,9 +382,7 @@ export async function confirmPeerPullDebit(    } else if (req.peerPullDebitId) {      peerPullDebitId = req.peerPullDebitId;    } else { -    throw Error( -      "invalid request, transactionId or peerPullDebitId required", -    ); +    throw Error("invalid request, transactionId or peerPullDebitId required");    }    const peerPullInc = await ws.db @@ -408,9 +397,7 @@ export async function confirmPeerPullDebit(      );    } -  const instructedAmount = Amounts.parseOrThrow( -    peerPullInc.contractTerms.amount, -  ); +  const instructedAmount = Amounts.parseOrThrow(peerPullInc.amount);    const coinSelRes = await selectPeerCoins(ws, { instructedAmount });    logger.info(`selected p2p coins (pull): ${j2s(coinSelRes)}`); @@ -454,9 +441,7 @@ export async function confirmPeerPullDebit(          refreshReason: RefreshReason.PayPeerPull,        }); -      const pi = await tx.peerPullDebit.get( -        peerPullDebitId, -      ); +      const pi = await tx.peerPullDebit.get(peerPullDebitId);        if (!pi) {          throw Error();        } @@ -498,27 +483,36 @@ export async function preparePeerPullDebit(      throw Error("got invalid taler://pay-pull URI");    } -  const existingPullIncomingRecord = await ws.db -    .mktx((x) => [x.peerPullDebit]) +  const existing = await ws.db +    .mktx((x) => [x.peerPullDebit, x.contractTerms])      .runReadOnly(async (tx) => { -      return tx.peerPullDebit.indexes.byExchangeAndContractPriv.get([ -        uri.exchangeBaseUrl, -        uri.contractPriv, -      ]); +      const peerPullDebitRecord = +        await tx.peerPullDebit.indexes.byExchangeAndContractPriv.get([ +          uri.exchangeBaseUrl, +          uri.contractPriv, +        ]); +      if (!peerPullDebitRecord) { +        return; +      } +      const contractTerms = await tx.contractTerms.get( +        peerPullDebitRecord.contractTermsHash, +      ); +      if (!contractTerms) { +        return; +      } +      return { peerPullDebitRecord, contractTerms };      }); -  if (existingPullIncomingRecord) { +  if (existing) {      return { -      amount: existingPullIncomingRecord.contractTerms.amount, -      amountRaw: existingPullIncomingRecord.contractTerms.amount, -      amountEffective: existingPullIncomingRecord.totalCostEstimated, -      contractTerms: existingPullIncomingRecord.contractTerms, -      peerPullDebitId: -        existingPullIncomingRecord.peerPullDebitId, +      amount: existing.peerPullDebitRecord.amount, +      amountRaw: existing.peerPullDebitRecord.amount, +      amountEffective: existing.peerPullDebitRecord.totalCostEstimated, +      contractTerms: existing.contractTerms.contractTermsRaw, +      peerPullDebitId: existing.peerPullDebitRecord.peerPullDebitId,        transactionId: constructTransactionIdentifier({          tag: TransactionType.PeerPullDebit, -        peerPullDebitId: -          existingPullIncomingRecord.peerPullDebitId, +        peerPullDebitId: existing.peerPullDebitRecord.peerPullDebitId,        }),      };    } @@ -566,6 +560,8 @@ export async function preparePeerPullDebit(      throw Error("pull payments without contract terms not supported yet");    } +  const contractTermsHash = ContractTermsUtil.hashContractTerms(contractTerms); +    // FIXME: Why don't we compute the totalCost here?!    const instructedAmount = Amounts.parseOrThrow(contractTerms.amount); @@ -588,18 +584,23 @@ export async function preparePeerPullDebit(    );    await ws.db -    .mktx((x) => [x.peerPullDebit]) +    .mktx((x) => [x.peerPullDebit, x.contractTerms])      .runReadWrite(async (tx) => { -      await tx.peerPullDebit.add({ -        peerPullDebitId, -        contractPriv: contractPriv, -        exchangeBaseUrl: exchangeBaseUrl, -        pursePub: pursePub, -        timestampCreated: TalerPreciseTimestamp.now(), -        contractTerms, -        status: PeerPullDebitRecordStatus.DialogProposed, -        totalCostEstimated: Amounts.stringify(totalAmount), -      }); +      await tx.contractTerms.put({ +        h: contractTermsHash, +        contractTermsRaw: contractTerms, +      }), +        await tx.peerPullDebit.add({ +          peerPullDebitId, +          contractPriv: contractPriv, +          exchangeBaseUrl: exchangeBaseUrl, +          pursePub: pursePub, +          timestampCreated: TalerPreciseTimestamp.now(), +          contractTermsHash, +          amount: contractTerms.amount, +          status: PeerPullDebitRecordStatus.DialogProposed, +          totalCostEstimated: Amounts.stringify(totalAmount), +        });      });    return { @@ -631,9 +632,7 @@ export async function suspendPeerPullDebitTransaction(    const transitionInfo = await ws.db      .mktx((x) => [x.peerPullDebit])      .runReadWrite(async (tx) => { -      const pullDebitRec = await tx.peerPullDebit.get( -        peerPullDebitId, -      ); +      const pullDebitRec = await tx.peerPullDebit.get(peerPullDebitId);        if (!pullDebitRec) {          logger.warn(`peer pull debit ${peerPullDebitId} not found`);          return; @@ -692,9 +691,7 @@ export async function abortPeerPullDebitTransaction(    const transitionInfo = await ws.db      .mktx((x) => [x.peerPullDebit])      .runReadWrite(async (tx) => { -      const pullDebitRec = await tx.peerPullDebit.get( -        peerPullDebitId, -      ); +      const pullDebitRec = await tx.peerPullDebit.get(peerPullDebitId);        if (!pullDebitRec) {          logger.warn(`peer pull debit ${peerPullDebitId} not found`);          return; @@ -753,9 +750,7 @@ export async function failPeerPullDebitTransaction(    const transitionInfo = await ws.db      .mktx((x) => [x.peerPullDebit])      .runReadWrite(async (tx) => { -      const pullDebitRec = await tx.peerPullDebit.get( -        peerPullDebitId, -      ); +      const pullDebitRec = await tx.peerPullDebit.get(peerPullDebitId);        if (!pullDebitRec) {          logger.warn(`peer pull debit ${peerPullDebitId} not found`);          return; @@ -814,9 +809,7 @@ export async function resumePeerPullDebitTransaction(    const transitionInfo = await ws.db      .mktx((x) => [x.peerPullDebit])      .runReadWrite(async (tx) => { -      const pullDebitRec = await tx.peerPullDebit.get( -        peerPullDebitId, -      ); +      const pullDebitRec = await tx.peerPullDebit.get(peerPullDebitId);        if (!pullDebitRec) {          logger.warn(`peer pull debit ${peerPullDebitId} not found`);          return; diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts index 31655ad71..d7b277faf 100644 --- a/packages/taler-wallet-core/src/operations/transactions.ts +++ b/packages/taler-wallet-core/src/operations/transactions.ts @@ -346,11 +346,19 @@ export async function getTransactionById(      }      case TransactionType.PeerPullDebit: {        return await ws.db -        .mktx((x) => [x.peerPullDebit]) +        .mktx((x) => [x.peerPullDebit, x.contractTerms])          .runReadWrite(async (tx) => {            const debit = await tx.peerPullDebit.get(parsedTx.peerPullDebitId);            if (!debit) throw Error("not found"); -          return buildTransactionForPullPaymentDebit(debit); +          const contractTermsRec = await tx.contractTerms.get( +            debit.contractTermsHash, +          ); +          if (!contractTermsRec) +            throw Error("contract terms for peer-pull-debit not found"); +          return buildTransactionForPullPaymentDebit( +            debit, +            contractTermsRec.contractTermsRaw, +          );          });      } @@ -477,6 +485,7 @@ function buildTransactionForPushPaymentDebit(  function buildTransactionForPullPaymentDebit(    pi: PeerPullPaymentIncomingRecord, +  contractTerms: PeerContractTerms,    ort?: OperationRetryRecord,  ): Transaction {    return { @@ -485,12 +494,12 @@ function buildTransactionForPullPaymentDebit(      txActions: computePeerPullDebitTransactionActions(pi),      amountEffective: pi.coinSel?.totalCost        ? pi.coinSel?.totalCost -      : Amounts.stringify(pi.contractTerms.amount), -    amountRaw: Amounts.stringify(pi.contractTerms.amount), +      : Amounts.stringify(pi.amount), +    amountRaw: Amounts.stringify(pi.amount),      exchangeBaseUrl: pi.exchangeBaseUrl,      info: { -      expiration: pi.contractTerms.purse_expiration, -      summary: pi.contractTerms.summary, +      expiration: contractTerms.purse_expiration, +      summary: contractTerms.summary,      },      timestamp: pi.timestampCreated,      transactionId: constructTransactionIdentifier({ @@ -805,7 +814,7 @@ function buildTransactionForDeposit(      amountEffective: Amounts.stringify(dg.totalPayCost),      timestamp: dg.timestampCreated,      targetPaytoUri: dg.wire.payto_uri, -    wireTransferDeadline: dg.contractTermsRaw.wire_transfer_deadline, +    wireTransferDeadline: dg.wireTransferDeadline,      transactionId: constructTransactionIdentifier({        tag: TransactionType.Deposit,        depositGroupId: dg.depositGroupId, @@ -980,7 +989,7 @@ export async function getTransactions(        });        await iterRecordsForPeerPullDebit(tx, filter, async (pi) => { -        const amount = Amounts.parseOrThrow(pi.contractTerms.amount); +        const amount = Amounts.parseOrThrow(pi.amount);          if (shouldSkipCurrency(transactionsRequest, amount.currency)) {            return;          } @@ -991,10 +1000,23 @@ export async function getTransactions(            pi.status !== PeerPullDebitRecordStatus.PendingDeposit &&            pi.status !== PeerPullDebitRecordStatus.Done          ) { +          // FIXME: Why?!            return;          } -        transactions.push(buildTransactionForPullPaymentDebit(pi)); +        const contractTermsRec = await tx.contractTerms.get( +          pi.contractTermsHash, +        ); +        if (!contractTermsRec) { +          return; +        } + +        transactions.push( +          buildTransactionForPullPaymentDebit( +            pi, +            contractTermsRec.contractTermsRaw, +          ), +        );        });        await iterRecordsForPeerPushCredit(tx, filter, async (pi) => { @@ -1158,7 +1180,7 @@ export async function getTransactions(        });        await iterRecordsForDeposit(tx, filter, async (dg) => { -        const amount = Amounts.parseOrThrow(dg.contractTermsRaw.amount); +        const amount = Amounts.parseOrThrow(dg.amount);          if (shouldSkipCurrency(transactionsRequest, amount.currency)) {            return;          } | 
