aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2023-06-06 15:00:10 +0200
committerFlorian Dold <florian@dold.me>2023-06-06 15:00:15 +0200
commit474a171f5e6684ab7d11bb2987fc90fe6e1b37c8 (patch)
treefeb3184e1d8ad9a9edeea8a511fb4b9011a51d9a /packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
parent9d35a7dc9b47701abf893987b5e0d3d1e99effb0 (diff)
downloadwallet-core-474a171f5e6684ab7d11bb2987fc90fe6e1b37c8.tar.xz
wallet-core: deterministic p2p contract encryption
Diffstat (limited to 'packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts')
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts116
1 files changed, 72 insertions, 44 deletions
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 ac0aa9c87..a03980d46 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
@@ -34,6 +34,10 @@ import {
TransactionMinorState,
TransactionState,
TransactionType,
+ decodeCrock,
+ encodeCrock,
+ getRandomBytes,
+ hash,
j2s,
stringifyTalerUri,
} from "@gnu-taler/taler-util";
@@ -57,11 +61,7 @@ import {
OperationAttemptResultType,
constructTaskIdentifier,
} from "../util/retries.js";
-import {
- runLongpollAsync,
- spendCoins,
- runOperationWithErrorReporting,
-} from "./common.js";
+import { runLongpollAsync, spendCoins } from "./common.js";
import {
constructTransactionIdentifier,
notifyTransition,
@@ -69,6 +69,7 @@ import {
} from "./transactions.js";
import { assertUnreachable } from "../util/assertUnreachable.js";
import { checkLogicInvariant } from "../util/invariants.js";
+import { EncryptContractRequest } from "../crypto/cryptoTypes.js";
const logger = new Logger("pay-peer-push-debit.ts");
@@ -100,6 +101,7 @@ async function processPeerPushDebitCreateReserve(
ws: InternalWalletState,
peerPushInitiation: PeerPushPaymentInitiationRecord,
): Promise<OperationAttemptResult> {
+ logger.info("processing peer-push-debit pending(create-reserve)");
const pursePub = peerPushInitiation.pursePub;
const purseExpiration = peerPushInitiation.purseExpiration;
const hContractTerms = peerPushInitiation.contractTermsHash;
@@ -124,32 +126,49 @@ async function processPeerPushDebitCreateReserve(
coins,
});
- const econtractResp = await ws.cryptoApi.encryptContractForMerge({
+ const encryptContractRequest: EncryptContractRequest = {
contractTerms: peerPushInitiation.contractTerms,
mergePriv: peerPushInitiation.mergePriv,
pursePriv: peerPushInitiation.pursePriv,
pursePub: peerPushInitiation.pursePub,
contractPriv: peerPushInitiation.contractPriv,
contractPub: peerPushInitiation.contractPub,
- });
+ nonce: peerPushInitiation.contractEncNonce,
+ };
+
+ logger.info(`encrypt contract request: ${j2s(encryptContractRequest)}`);
+
+ const econtractResp = await ws.cryptoApi.encryptContractForMerge(
+ encryptContractRequest,
+ );
+
+ const econtractHash = encodeCrock(
+ hash(decodeCrock(econtractResp.econtract.econtract)),
+ );
+
+ logger.info(`econtract hash: ${econtractHash}`);
const createPurseUrl = new URL(
`purses/${peerPushInitiation.pursePub}/create`,
peerPushInitiation.exchangeBaseUrl,
);
+ const reqBody = {
+ amount: peerPushInitiation.amount,
+ merge_pub: peerPushInitiation.mergePub,
+ purse_sig: purseSigResp.sig,
+ h_contract_terms: hContractTerms,
+ purse_expiration: purseExpiration,
+ deposits: depositSigsResp.deposits,
+ min_age: 0,
+ econtract: econtractResp.econtract,
+ };
+
+ logger.info(`request body: ${j2s(reqBody)}`);
+
const httpResp = await ws.http.fetch(createPurseUrl.href, {
method: "POST",
- body: {
- amount: peerPushInitiation.amount,
- merge_pub: peerPushInitiation.mergePub,
- purse_sig: purseSigResp.sig,
- h_contract_terms: hContractTerms,
- purse_expiration: purseExpiration,
- deposits: depositSigsResp.deposits,
- min_age: 0,
- econtract: econtractResp.econtract,
- },
+ body: reqBody,
});
const resp = await httpResp.json();
@@ -157,24 +176,16 @@ async function processPeerPushDebitCreateReserve(
logger.info(`resp: ${j2s(resp)}`);
if (httpResp.status !== HttpStatusCode.Ok) {
+ // FIXME: do proper error reporting
throw Error("got error response from exchange");
}
- await ws.db
- .mktx((x) => [x.peerPushPaymentInitiations])
- .runReadWrite(async (tx) => {
- const ppi = await tx.peerPushPaymentInitiations.get(pursePub);
- if (!ppi) {
- return;
- }
- ppi.status = PeerPushPaymentInitiationStatus.Done;
- await tx.peerPushPaymentInitiations.put(ppi);
- });
+ await transitionPeerPushDebitTransaction(ws, pursePub, {
+ stFrom: PeerPushPaymentInitiationStatus.PendingCreatePurse,
+ stTo: PeerPushPaymentInitiationStatus.PendingReady,
+ });
- return {
- type: OperationAttemptResultType.Finished,
- result: undefined,
- };
+ return OperationAttemptResult.finishedEmpty();
}
async function processPeerPushDebitAbortingDeletePurse(
@@ -278,6 +289,7 @@ async function transitionPeerPushDebitTransaction(
const oldTxState = computePeerPushDebitTransactionState(ppiRec);
ppiRec.status = transitionSpec.stTo;
const newTxState = computePeerPushDebitTransactionState(ppiRec);
+ // FIXME: We don't transition here?!
return {
oldTxState,
newTxState,
@@ -341,6 +353,7 @@ async function processPeerPushDebitReady(
ws: InternalWalletState,
peerPushInitiation: PeerPushPaymentInitiationRecord,
): Promise<OperationAttemptResult> {
+ logger.info("processing peer-push-debit pending(ready)");
const pursePub = peerPushInitiation.pursePub;
const retryTag = constructTaskIdentifier({
tag: PendingTaskType.PeerPushDebit,
@@ -434,6 +447,12 @@ export async function processPeerPushDebit(
return processPeerPushDebitAbortingDeletePurse(ws, peerPushInitiation);
case PeerPushPaymentInitiationStatus.AbortingRefresh:
return processPeerPushDebitAbortingRefresh(ws, peerPushInitiation);
+ default: {
+ const txState = computePeerPushDebitTransactionState(peerPushInitiation);
+ logger.warn(
+ `not processing peer-push-debit transaction in state ${j2s(txState)}`,
+ );
+ }
}
return {
@@ -482,7 +501,16 @@ export async function initiatePeerPushDebit(
coinSelRes.result.coins,
);
- await ws.db
+ const pursePub = pursePair.pub;
+
+ const transactionId = constructTaskIdentifier({
+ tag: PendingTaskType.PeerPushDebit,
+ pursePub,
+ });
+
+ const contractEncNonce = encodeCrock(getRandomBytes(24));
+
+ const transitionInfo = await ws.db
.mktx((x) => [
x.exchanges,
x.contractTerms,
@@ -509,7 +537,7 @@ export async function initiatePeerPushDebit(
refreshReason: RefreshReason.PayPeerPush,
});
- await tx.peerPushPaymentInitiations.add({
+ const ppi: PeerPushPaymentInitiationRecord = {
amount: Amounts.stringify(instructedAmount),
contractPriv: contractKeyPair.priv,
contractPub: contractKeyPair.pub,
@@ -523,27 +551,28 @@ export async function initiatePeerPushDebit(
timestampCreated: TalerPreciseTimestamp.now(),
status: PeerPushPaymentInitiationStatus.PendingCreatePurse,
contractTerms: contractTerms,
+ contractEncNonce,
coinSel: {
coinPubs: sel.coins.map((x) => x.coinPub),
contributions: sel.coins.map((x) => x.contribution),
},
totalCost: Amounts.stringify(totalAmount),
- });
+ };
+
+ await tx.peerPushPaymentInitiations.add(ppi);
await tx.contractTerms.put({
h: hContractTerms,
contractTermsRaw: contractTerms,
});
- });
- const taskId = constructTaskIdentifier({
- tag: PendingTaskType.PeerPushDebit,
- pursePub: pursePair.pub,
- });
-
- await runOperationWithErrorReporting(ws, taskId, async () => {
- return await processPeerPushDebit(ws, pursePair.pub);
- });
+ const newTxState = computePeerPushDebitTransactionState(ppi);
+ return {
+ oldTxState: { major: TransactionMajorState.None },
+ newTxState,
+ };
+ });
+ notifyTransition(ws, transactionId, transitionInfo);
return {
contractPriv: contractKeyPair.priv,
@@ -903,4 +932,3 @@ export function computePeerPushDebitTransactionState(
};
}
}
-