taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 38e380c5c0ae4db1ab5124dc975138ba89f2dc2a
parent 3819d49e5e4c909a67996b45420326eb698dd4e5
Author: Florian Dold <florian@dold.me>
Date:   Fri, 13 Mar 2026 17:30:02 +0100

simplify/fix p2p push test and states

Diffstat:
Mpackages/taler-harness/src/harness/harness.ts | 2+-
Mpackages/taler-harness/src/integrationtests/test-peer-push.ts | 238+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mpackages/taler-wallet-core/src/pay-peer-push-credit.ts | 5++++-
3 files changed, 129 insertions(+), 116 deletions(-)

diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts @@ -331,7 +331,7 @@ export class GlobalTestState { } /** - * @deprecated use {@link assertThrowsAsync} instead + * @deprecated use {@link assertThrowsTalerErrorAsync} instead */ async assertThrowsTalerErrorAsyncLegacy( block: Promise<unknown>, diff --git a/packages/taler-harness/src/integrationtests/test-peer-push.ts b/packages/taler-harness/src/integrationtests/test-peer-push.ts @@ -124,14 +124,15 @@ export async function runPeerPushTest(t: GlobalTestState) { t.logStep("P2P push errors"); { - const ex1 = await t.assertThrowsTalerErrorAsyncLegacy( - wallet1.call(WalletApiOperation.InitiatePeerPushDebit, { - partialContractTerms: { - summary: "(this will fail)", - amount: "TESTKUDOS:250", - purse_expiration: purseExpiration, - }, - }), + const ex1 = await t.assertThrowsTalerErrorAsync( + async () => + await wallet1.call(WalletApiOperation.InitiatePeerPushDebit, { + partialContractTerms: { + summary: "(this will fail)", + amount: "TESTKUDOS:250", + purse_expiration: purseExpiration, + }, + }), ); t.assertTrue( ex1.errorDetail.code === TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION, @@ -139,11 +140,12 @@ export async function runPeerPushTest(t: GlobalTestState) { // FIXME propagate the error correctly // t.assertTrue(ex1.errorDetail.code === TalerErrorCode.WALLET_PEER_PUSH_PAYMENT_INSUFFICIENT_BALANCE); - const unknown_purse = await t.assertThrowsTalerErrorAsyncLegacy( - wallet1.call(WalletApiOperation.PreparePeerPushCredit, { - talerUri: - "taler+http://pay-push/localhost:8081/MQP1DP1J94ZZWNQS7TRDF1KJZ7V8H74CZF41V90FKXBPN5GNRN6G", - }), + const unknown_purse = await t.assertThrowsTalerErrorAsync( + async () => + await wallet1.call(WalletApiOperation.PreparePeerPushCredit, { + talerUri: + "taler+http://pay-push/localhost:8081/MQP1DP1J94ZZWNQS7TRDF1KJZ7V8H74CZF41V90FKXBPN5GNRN6G", + }), ); // FIXME this should fail with a proper error code t.assertTrue( @@ -194,49 +196,52 @@ export async function runPeerPushTest(t: GlobalTestState) { }), ]); - await Promise.all([ - wallet1.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: tx.transactionId, - txState: { - major: TransactionMajorState.Done, - }, - }), - Promise.race([ - Promise.all([ - wallet2.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: prepare2.transactionId, - txState: { - major: TransactionMajorState.Done, - }, - }), - wallet3.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: prepare3.transactionId, - txState: { - major: TransactionMajorState.Aborted, - }, - }), - ]), - Promise.all([ - wallet2.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: prepare2.transactionId, - txState: { - major: TransactionMajorState.Aborted, - }, - }), - wallet3.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: prepare3.transactionId, - txState: { - major: TransactionMajorState.Done, - }, - }), - ]), + // The single sender should succeed + await wallet1.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: tx.transactionId, + txState: { + major: TransactionMajorState.Done, + }, + }); + + // Wallet 4 never confirmed, but should notice that the P2P payment is gone + await wallet4.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare4.transactionId, + txState: { + major: TransactionMajorState.Aborted, + }, + }); + // Either wallet 2 succeeds and wallet 3 fails + // or vice versa. + await Promise.race([ + Promise.all([ + wallet2.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare2.transactionId, + txState: { + major: TransactionMajorState.Done, + }, + }), + wallet3.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare3.transactionId, + txState: { + major: TransactionMajorState.Failed, + }, + }), + ]), + Promise.all([ + wallet2.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare2.transactionId, + txState: { + major: TransactionMajorState.Failed, + }, + }), + wallet3.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare3.transactionId, + txState: { + major: TransactionMajorState.Done, + }, + }), ]), - wallet4.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: prepare4.transactionId, - txState: { - major: TransactionMajorState.Aborted, - }, - }), ]); { @@ -312,48 +317,47 @@ export async function runPeerPushTest(t: GlobalTestState) { ]); await exchange.start(); - await Promise.all([ - wallet1.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: tx.transactionId, - txState: { - major: TransactionMajorState.Done, - }, - }), - Promise.race([ - Promise.all([ - wallet2.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: prepare2.transactionId, - txState: { - major: TransactionMajorState.Done, - }, - }), - wallet3.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: prepare3.transactionId, - txState: { - major: TransactionMajorState.Aborted, - }, - }), - ]), - Promise.all([ - wallet2.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: prepare2.transactionId, - txState: { - major: TransactionMajorState.Aborted, - }, - }), - wallet3.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: prepare3.transactionId, - txState: { - major: TransactionMajorState.Done, - }, - }), - ]), + + await wallet1.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: tx.transactionId, + txState: { + major: TransactionMajorState.Done, + }, + }); + + await Promise.race([ + Promise.all([ + wallet2.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare2.transactionId, + txState: { + major: TransactionMajorState.Done, + }, + }), + wallet3.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare3.transactionId, + txState: { + major: TransactionMajorState.Failed, + }, + }), + ]), + Promise.all([ + wallet2.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare2.transactionId, + txState: { + major: TransactionMajorState.Failed, + }, + }), + wallet3.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare3.transactionId, + txState: { + major: TransactionMajorState.Done, + }, + }), ]), ]); } - t.logStep("P2P push abort"); - { + await t.runSpanAsync("P2P push abort", async () => { const tx = await initPeerPushDebit("abort"); const [prepare2, prepare3] = await Promise.all( @@ -372,27 +376,33 @@ export async function runPeerPushTest(t: GlobalTestState) { transactionId: prepare2.transactionId, }); - await Promise.all([ - wallet1.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: tx.transactionId, - txState: { - major: TransactionMajorState.Aborted, - }, - }), - wallet2.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: prepare2.transactionId, - txState: { - major: TransactionMajorState.Aborted, - }, - }), - wallet3.call(WalletApiOperation.TestingWaitTransactionState, { - transactionId: prepare3.transactionId, - txState: { - major: TransactionMajorState.Aborted, - }, - }), - ]); - } + t.logStep("waiting for wallet1"); + + await wallet1.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: tx.transactionId, + txState: { + major: TransactionMajorState.Aborted, + }, + }); + + t.logStep("waiting for wallet2"); + + await wallet2.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare2.transactionId, + txState: { + major: TransactionMajorState.Failed, + }, + }); + + t.logStep("waiting for wallet3"); + + await wallet3.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: prepare3.transactionId, + txState: { + major: TransactionMajorState.Aborted, + }, + }); + }); await t.runSpanAsync("P2P push abort before create purse", async () => { // Make sure the reserve can't be created. diff --git a/packages/taler-wallet-core/src/pay-peer-push-credit.ts b/packages/taler-wallet-core/src/pay-peer-push-credit.ts @@ -899,7 +899,10 @@ async function processPendingMerge( switch (rec.status) { case PeerPushCreditStatus.PendingMergeKycRequired: case PeerPushCreditStatus.PendingMerge: { - rec.status = PeerPushCreditStatus.Expired; + // Note that we do *not* go to an expired state here, + // because we also get a Gone status when the other + // wallet aborted the P2P payment. + rec.status = PeerPushCreditStatus.Failed; break; } default: