aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/taler-harness/src/harness/helpers.ts35
-rw-r--r--packages/taler-harness/src/integrationtests/test-peer-to-peer-pull.ts74
-rw-r--r--packages/taler-util/src/notifications.ts15
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer.ts17
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts30
5 files changed, 147 insertions, 24 deletions
diff --git a/packages/taler-harness/src/harness/helpers.ts b/packages/taler-harness/src/harness/helpers.ts
index c1ce463fa..d203cc608 100644
--- a/packages/taler-harness/src/harness/helpers.ts
+++ b/packages/taler-harness/src/harness/helpers.ts
@@ -31,6 +31,7 @@ import {
PreparePayResultType,
NotificationType,
WithdrawalGroupFinishedNotification,
+ WalletNotification,
} from "@gnu-taler/taler-util";
import {
BankAccessApi,
@@ -297,7 +298,6 @@ export async function createSimpleTestkudosEnvironmentV2(
const walletService = new WalletService(t, {
name: "wallet",
- useInMemoryDb: true,
});
await walletService.start();
await walletService.pingUntilAvailable();
@@ -326,6 +326,39 @@ export async function createSimpleTestkudosEnvironmentV2(
};
}
+export interface CreateWalletArgs {
+ handleNotification?(wn: WalletNotification): void;
+ name: string;
+}
+
+export async function createWalletDaemonWithClient(
+ t: GlobalTestState,
+ args: CreateWalletArgs,
+): Promise<{ walletClient: WalletClient; walletService: WalletService }> {
+ const walletService = new WalletService(t, {
+ name: "wallet",
+ useInMemoryDb: true,
+ });
+ await walletService.start();
+ await walletService.pingUntilAvailable();
+
+ const walletClient = new WalletClient({
+ unixPath: walletService.socketPath,
+ onNotification(n) {
+ console.log("got notification", n);
+ if (args.handleNotification) {
+ args.handleNotification(n);
+ }
+ },
+ });
+ await walletClient.connect();
+ await walletClient.client.call(WalletApiOperation.InitWallet, {
+ skipDefaults: true,
+ });
+
+ return { walletClient, walletService };
+}
+
export interface FaultyMerchantTestEnvironment {
commonDb: DbInfo;
bank: BankService;
diff --git a/packages/taler-harness/src/integrationtests/test-peer-to-peer-pull.ts b/packages/taler-harness/src/integrationtests/test-peer-to-peer-pull.ts
index 0bab14578..58a1f271e 100644
--- a/packages/taler-harness/src/integrationtests/test-peer-to-peer-pull.ts
+++ b/packages/taler-harness/src/integrationtests/test-peer-to-peer-pull.ts
@@ -17,12 +17,21 @@
/**
* Imports.
*/
-import { AbsoluteTime, Duration, j2s } from "@gnu-taler/taler-util";
+import {
+ AbsoluteTime,
+ Duration,
+ j2s,
+ NotificationType,
+ WalletNotification,
+} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { GlobalTestState, WalletCli } from "../harness/harness.js";
import {
createSimpleTestkudosEnvironment,
+ createSimpleTestkudosEnvironmentV2,
+ createWalletDaemonWithClient,
withdrawViaBank,
+ withdrawViaBankV2,
} from "../harness/helpers.js";
/**
@@ -31,19 +40,40 @@ import {
export async function runPeerToPeerPullTest(t: GlobalTestState) {
// Set up test environment
- const { bank, exchange } = await createSimpleTestkudosEnvironment(t);
+ const { bank, exchange } = await createSimpleTestkudosEnvironmentV2(t);
+
+ let allW1Notifications: WalletNotification[] = [];
+ let allW2Notifications: WalletNotification[] = [];
+
+ const w1 = await createWalletDaemonWithClient(t, {
+ name: "w1",
+ handleNotification(wn) {
+ allW1Notifications.push(wn);
+ },
+ });
+ const w2 = await createWalletDaemonWithClient(t, {
+ name: "w2",
+ handleNotification(wn) {
+ allW2Notifications.push(wn);
+ },
+ });
// Withdraw digital cash into the wallet.
- const wallet1 = new WalletCli(t, "w1");
- const wallet2 = new WalletCli(t, "w2");
- await withdrawViaBank(t, {
- wallet: wallet2,
+ const wallet1 = w1.walletClient;
+ const wallet2 = w2.walletClient;
+
+ const withdrawalDoneCond = wallet2.waitForNotificationCond(
+ (x) => x.type === NotificationType.WithdrawGroupFinished,
+ );
+
+ await withdrawViaBankV2(t, {
+ walletClient: wallet2,
bank,
exchange,
amount: "TESTKUDOS:20",
});
- await wallet1.runUntilDone();
+ await withdrawalDoneCond;
const purse_expiration = AbsoluteTime.toTimestamp(
AbsoluteTime.addDuration(
@@ -52,6 +82,10 @@ export async function runPeerToPeerPullTest(t: GlobalTestState) {
),
);
+ const peerPullCreditReadyCond = wallet2.waitForNotificationCond(
+ (x) => x.type === NotificationType.PeerPullCreditReady,
+ );
+
const resp = await wallet1.client.call(
WalletApiOperation.InitiatePeerPullCredit,
{
@@ -64,9 +98,7 @@ export async function runPeerToPeerPullTest(t: GlobalTestState) {
},
);
- // Wait until the initiation is actually done.
- // FIXME: Use the daemonized wallet and notifications to know this
- await wallet1.runPending();
+ await peerPullCreditReadyCond;
const checkResp = await wallet2.client.call(
WalletApiOperation.PreparePeerPullDebit,
@@ -77,20 +109,23 @@ export async function runPeerToPeerPullTest(t: GlobalTestState) {
console.log(`checkResp: ${j2s(checkResp)}`);
- const acceptResp = await wallet2.client.call(
- WalletApiOperation.ConfirmPeerPullDebit,
- {
- peerPullPaymentIncomingId: checkResp.peerPullPaymentIncomingId,
- },
+ // FIXME: The wallet should emit a more appropriate notification here.
+ // Yes, it's technically a withdrawal.
+ const peerPullCreditDoneCond = wallet1.waitForNotificationCond(
+ (x) => x.type === NotificationType.WithdrawGroupFinished,
);
- await wallet1.runUntilDone();
- await wallet2.runUntilDone();
+ await wallet2.client.call(WalletApiOperation.ConfirmPeerPullDebit, {
+ peerPullPaymentIncomingId: checkResp.peerPullPaymentIncomingId,
+ });
+
+ await peerPullCreditDoneCond;
const txn1 = await wallet1.client.call(
WalletApiOperation.GetTransactions,
{},
);
+
const txn2 = await wallet2.client.call(
WalletApiOperation.GetTransactions,
{},
@@ -98,6 +133,11 @@ export async function runPeerToPeerPullTest(t: GlobalTestState) {
console.log(`txn1: ${j2s(txn1)}`);
console.log(`txn2: ${j2s(txn2)}`);
+
+ console.log(`w1 notifications: ${j2s(allW1Notifications)}`);
+
+ // Check that we don't have an excessive number of notifications.
+ t.assertTrue(allW1Notifications.length <= 60);
}
runPeerToPeerPullTest.suites = ["wallet"];
diff --git a/packages/taler-util/src/notifications.ts b/packages/taler-util/src/notifications.ts
index 55d838007..51d573a98 100644
--- a/packages/taler-util/src/notifications.ts
+++ b/packages/taler-util/src/notifications.ts
@@ -65,6 +65,7 @@ export enum NotificationType {
WithdrawalGroupKycRequested = "withdrawal-group-kyc-requested",
WithdrawalGroupBankConfirmed = "withdrawal-group-bank-confirmed",
WithdrawalGroupReserveReady = "withdrawal-group-reserve-ready",
+ PeerPullCreditReady = "peer-pull-credit-ready",
DepositOperationError = "deposit-operation-error",
}
@@ -135,11 +136,20 @@ export interface WithdrawalGroupBankConfirmed {
transactionId: string;
}
-export interface WithdrawalGroupReserveReady {
+export interface WithdrawalGroupReserveReadyNotification {
type: NotificationType.WithdrawalGroupReserveReady;
transactionId: string;
}
+/**
+ * The purse creation of a peer-pull-credit transaction
+ * is done, and the other party can now pay.
+ */
+export interface PeerPullCreditReadyNotification {
+ type: NotificationType.PeerPullCreditReady;
+ transactionId: string;
+}
+
export interface RefreshRevealedNotification {
type: NotificationType.RefreshRevealed;
}
@@ -316,4 +326,5 @@ export type WalletNotification =
| PayOperationSuccessNotification
| WithdrawalGroupKycRequested
| WithdrawalGroupBankConfirmed
- | WithdrawalGroupReserveReady;
+ | WithdrawalGroupReserveReadyNotification
+ | PeerPullCreditReadyNotification;
diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts b/packages/taler-wallet-core/src/operations/pay-peer.ts
index 8bde47df4..541e96280 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer.ts
@@ -72,6 +72,7 @@ import {
codecOptional,
codecForTimestamp,
CancellationToken,
+ NotificationType,
} from "@gnu-taler/taler-util";
import { SpendCoinDetails } from "../crypto/cryptoImplementation.js";
import {
@@ -119,7 +120,10 @@ import {
processWithdrawalGroup,
} from "./withdraw.js";
import { PendingTaskType } from "../pending-types.js";
-import { stopLongpolling } from "./transactions.js";
+import {
+ constructTransactionIdentifier,
+ stopLongpolling,
+} from "./transactions.js";
const logger = new Logger("operations/peer-to-peer.ts");
@@ -1507,6 +1511,14 @@ export async function processPeerPullCredit(
await tx.peerPullPaymentInitiations.put(pi2);
});
+ ws.notify({
+ type: NotificationType.PeerPullCreditReady,
+ transactionId: constructTransactionIdentifier({
+ tag: TransactionType.PeerPullCredit,
+ pursePub: pullIni.pursePub,
+ }),
+ });
+
return {
type: OperationAttemptResultType.Finished,
result: undefined,
@@ -1626,9 +1638,6 @@ export async function initiatePeerPullPayment(
const pursePair = await ws.cryptoApi.createEddsaKeypair({});
const mergePair = await ws.cryptoApi.createEddsaKeypair({});
- const instructedAmount = Amounts.parseOrThrow(
- req.partialContractTerms.amount,
- );
const contractTerms = req.partialContractTerms;
const hContractTerms = ContractTermsUtil.hashContractTerms(contractTerms);
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 1c2ce34bb..764115cef 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -64,6 +64,7 @@ import {
} from "../db.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import { PendingTaskType } from "../pending-types.js";
+import { assertUnreachable } from "../util/assertUnreachable.js";
import { checkDbInvariant } from "../util/invariants.js";
import { constructTaskIdentifier, TaskIdentifiers } from "../util/retries.js";
import {
@@ -1376,6 +1377,35 @@ export type ParsedTransactionIdentifier =
| { tag: TransactionType.Tip; walletTipId: string }
| { tag: TransactionType.Withdrawal; withdrawalGroupId: string };
+export function constructTransactionIdentifier(
+ pTxId: ParsedTransactionIdentifier,
+): string {
+ switch (pTxId.tag) {
+ case TransactionType.Deposit:
+ return `txn:${pTxId.tag}:${pTxId.depositGroupId}`;
+ case TransactionType.Payment:
+ return `txn:${pTxId.tag}:${pTxId.proposalId}`;
+ case TransactionType.PeerPullCredit:
+ return `txn:${pTxId.tag}:${pTxId.pursePub}`;
+ case TransactionType.PeerPullDebit:
+ return `txn:${pTxId.tag}:${pTxId.peerPullPaymentIncomingId}`;
+ case TransactionType.PeerPushCredit:
+ return `txn:${pTxId.tag}:${pTxId.peerPushPaymentIncomingId}`;
+ case TransactionType.PeerPushDebit:
+ return `txn:${pTxId.tag}:${pTxId.pursePub}`;
+ case TransactionType.Refresh:
+ return `txn:${pTxId.tag}:${pTxId.refreshGroupId}`;
+ case TransactionType.Refund:
+ return `txn:${pTxId.tag}:${pTxId.proposalId}:${pTxId.executionTime}`;
+ case TransactionType.Tip:
+ return `txn:${pTxId.tag}:${pTxId.walletTipId}`;
+ case TransactionType.Withdrawal:
+ return `txn:${pTxId.tag}:${pTxId.withdrawalGroupId}`;
+ default:
+ assertUnreachable(pTxId);
+ }
+}
+
/**
* Parse a transaction identifier string into a typed, structured representation.
*/