From 2703f10453999dd836ee3caf27d78c88fe96d265 Mon Sep 17 00:00:00 2001 From: chavic Date: Tue, 28 Jul 2026 16:06:26 +0200 Subject: [PATCH] Bump rust-payjoin to 1.0.0-rc.6 Move the submodule from f4a6008a to the payjoin-1.0.0-rc.6 release commit and adapt to the FFI surface changes: - PjParseException is now UriParseException. - BuildRecommended throws SenderInputException, and persisted sender errors are now SenderPersistedException.Transient/Fatal wrapping a SenderException, so the receiver-rejection handling matches SenderException.Response through the wrapper. - IPayjoinProposal drops UtxosToBeLocked and gains ProposalTxidIsStable. rc.5-format closed-session logs recorded scripts and witnesses in Closed(Success); rc.6 records a txid, so such logs fail replay after this bump. Every replay site already catches ReceiverReplayException and removes the session, which is the same terminal outcome a closed session gets on the next poller tick. --- .../TestUtils/PayjoinTestPayer.cs | 20 ++++++++++++++----- .../PayjoinSettlementFlowTests.cs | 2 +- .../PayjoinReceiverProposalFinalizerTests.cs | 4 ++-- .../Controllers/UIPayJoinController.cs | 2 +- .../PayjoinInvoicePaymentUrlService.cs | 2 +- .../Services/RunTestPaymentService.cs | 16 ++++++++++++--- rust-payjoin | 2 +- 7 files changed, 34 insertions(+), 14 deletions(-) diff --git a/BTCPayServer.Plugins.Payjoin.IntegrationTests/TestUtils/PayjoinTestPayer.cs b/BTCPayServer.Plugins.Payjoin.IntegrationTests/TestUtils/PayjoinTestPayer.cs index 4f75042..5d77373 100644 --- a/BTCPayServer.Plugins.Payjoin.IntegrationTests/TestUtils/PayjoinTestPayer.cs +++ b/BTCPayServer.Plugins.Payjoin.IntegrationTests/TestUtils/PayjoinTestPayer.cs @@ -138,7 +138,7 @@ private async Task CreateSenderPsbtAsync(SystemUri payme paymentAmount = Money.Satoshis(checked((long)amountSats.Value)).ToDecimal(MoneyUnit.BTC); using var _ = parsedUri.CheckPjSupported(); } - catch (PjParseException ex) + catch (UriParseException ex) { throw new InvalidOperationException($"Invalid BIP21 URI '{paymentUrl}': {ex.Message}", ex); } @@ -233,9 +233,9 @@ private async Task RequestProposalAsync(SystemUri paymentUrl, IReadOnlyLis } proposalPsbtBase64 = await PollForProposalAsync(current, senderPersister, ohttpRelayUrls, cancellationToken).ConfigureAwait(false); } - catch (SenderPersistedException.ResponseException ex) + catch (SenderPersistedException ex) when (SenderResponseOf(ex) is { } senderResponse) { - throw CreateSenderResponseFailure(ex); + throw CreateSenderResponseFailure(ex, senderResponse); } if (string.IsNullOrWhiteSpace(proposalPsbtBase64)) @@ -355,13 +355,23 @@ private async Task RequestProposalAsync(SystemUri paymentUrl, IReadOnlyLis throw new InvalidOperationException($"All configured OHTTP relays failed for payer store '{_payer.StoreId}'. LastError='{lastError?.Message}'", lastError); } - private InvalidOperationException CreateSenderResponseFailure(SenderPersistedException.ResponseException ex) + private InvalidOperationException CreateSenderResponseFailure(SenderPersistedException ex, global::Payjoin.ResponseException senderResponse) { return new InvalidOperationException( - $"Payjoin receiver rejected the proposal for payer store '{_payer.StoreId}': {FormatSenderResponseException(ex.v1)}", + $"Payjoin receiver rejected the proposal for payer store '{_payer.StoreId}': {FormatSenderResponseException(senderResponse)}", ex); } + private static global::Payjoin.ResponseException? SenderResponseOf(SenderPersistedException exception) + { + return exception switch + { + SenderPersistedException.Fatal { v1: SenderException.Response response } => response.v1, + SenderPersistedException.Transient { v1: SenderException.Response response } => response.v1, + _ => null + }; + } + private static string FormatSenderResponseException(global::Payjoin.ResponseException responseException) { return responseException switch diff --git a/BTCPayServer.Plugins.Payjoin.Tests/PayjoinSettlementFlowTests.cs b/BTCPayServer.Plugins.Payjoin.Tests/PayjoinSettlementFlowTests.cs index 807f288..8da97f9 100644 --- a/BTCPayServer.Plugins.Payjoin.Tests/PayjoinSettlementFlowTests.cs +++ b/BTCPayServer.Plugins.Payjoin.Tests/PayjoinSettlementFlowTests.cs @@ -407,7 +407,7 @@ private sealed class FixedPsbtProposal(string psbt) : IPayjoinProposal public RequestResponse CreatePostRequest(string ohttpRelay) => throw new NotSupportedException(); public PayjoinProposalTransition ProcessResponse(byte[] body, ClientResponse ohttpContext) => throw new NotSupportedException(); public string Psbt() => psbt; - public PayjoinOutPoint[] UtxosToBeLocked() => throw new NotSupportedException(); + public bool ProposalTxidIsStable() => throw new NotSupportedException(); } private sealed class NoOpSessionProcessor : IPayjoinReceiverSessionProcessor diff --git a/BTCPayServer.Plugins.Payjoin.Tests/Services/PayjoinReceiverProposalFinalizerTests.cs b/BTCPayServer.Plugins.Payjoin.Tests/Services/PayjoinReceiverProposalFinalizerTests.cs index b44b857..d2fbd49 100644 --- a/BTCPayServer.Plugins.Payjoin.Tests/Services/PayjoinReceiverProposalFinalizerTests.cs +++ b/BTCPayServer.Plugins.Payjoin.Tests/Services/PayjoinReceiverProposalFinalizerTests.cs @@ -170,7 +170,7 @@ private sealed class FixedPsbtProposal(string psbt) : IPayjoinProposal public RequestResponse CreatePostRequest(string ohttpRelay) => throw new NotSupportedException(); public PayjoinProposalTransition ProcessResponse(byte[] body, ClientResponse ohttpContext) => throw new NotSupportedException(); public string Psbt() => psbt; - public PayjoinOutPoint[] UtxosToBeLocked() => throw new NotSupportedException(); + public bool ProposalTxidIsStable() => throw new NotSupportedException(); } private sealed class ThrowingProposal : IPayjoinProposal @@ -179,7 +179,7 @@ private sealed class ThrowingProposal : IPayjoinProposal public RequestResponse CreatePostRequest(string ohttpRelay) => throw new NotSupportedException(); public PayjoinProposalTransition ProcessResponse(byte[] body, ClientResponse ohttpContext) => throw new NotSupportedException(); public string Psbt() => throw new NotSupportedException(); - public PayjoinOutPoint[] UtxosToBeLocked() => throw new NotSupportedException(); + public bool ProposalTxidIsStable() => throw new NotSupportedException(); } private sealed class UnusedRelayRequestSender : IPayjoinReceiverRelayRequestSender diff --git a/BTCPayServer.Plugins.Payjoin/Controllers/UIPayJoinController.cs b/BTCPayServer.Plugins.Payjoin/Controllers/UIPayJoinController.cs index 3a5fced..c80f560 100644 --- a/BTCPayServer.Plugins.Payjoin/Controllers/UIPayJoinController.cs +++ b/BTCPayServer.Plugins.Payjoin/Controllers/UIPayJoinController.cs @@ -145,7 +145,7 @@ public async Task> RunTestPayment([FromBody paymentAmount = Money.Satoshis(checked((long)amountSats.Value)).ToDecimal(MoneyUnit.BTC); using var _ = parsedUri.CheckPjSupported(); } - catch (PjParseException ex) + catch (UriParseException ex) { return RunTestPaymentFailure($"Invalid BIP21 URI: {ex.Message}"); } diff --git a/BTCPayServer.Plugins.Payjoin/Services/PayjoinInvoicePaymentUrlService.cs b/BTCPayServer.Plugins.Payjoin/Services/PayjoinInvoicePaymentUrlService.cs index 07cec2b..70fe649 100644 --- a/BTCPayServer.Plugins.Payjoin/Services/PayjoinInvoicePaymentUrlService.cs +++ b/BTCPayServer.Plugins.Payjoin/Services/PayjoinInvoicePaymentUrlService.cs @@ -151,7 +151,7 @@ private static bool IsPayjoinEnabled(string paymentUrl) using var _ = parsedUri.CheckPjSupported(); return true; } - catch (PjParseException) + catch (UriParseException) { return false; } diff --git a/BTCPayServer.Plugins.Payjoin/Services/RunTestPaymentService.cs b/BTCPayServer.Plugins.Payjoin/Services/RunTestPaymentService.cs index 2af20a7..a0636d9 100644 --- a/BTCPayServer.Plugins.Payjoin/Services/RunTestPaymentService.cs +++ b/BTCPayServer.Plugins.Payjoin/Services/RunTestPaymentService.cs @@ -272,13 +272,13 @@ private async Task RequestProposalAsync( current.Dispose(); } } - catch (BuildSenderException ex) + catch (SenderInputException ex) { throw new RunTestPaymentExecutionException($"Sender build failed: {ex.Message}", ex); } - catch (SenderPersistedException.ResponseException ex) + catch (SenderPersistedException ex) when (SenderResponseOf(ex) is { } senderResponse) { - throw new RunTestPaymentExecutionException($"Sender rejected by receiver: {FormatSenderResponseException(ex.v1)}", ex); + throw new RunTestPaymentExecutionException($"Sender rejected by receiver: {FormatSenderResponseException(senderResponse)}", ex); } catch (HttpRequestException ex) { @@ -442,6 +442,16 @@ private static IReadOnlyList GetConfiguredRelayUrls(RunTestPaymentCon throw new RunTestPaymentExecutionException("No OHTTP relays configured for test payment."); } + private static global::Payjoin.ResponseException? SenderResponseOf(SenderPersistedException exception) + { + return exception switch + { + SenderPersistedException.Fatal { v1: SenderException.Response response } => response.v1, + SenderPersistedException.Transient { v1: SenderException.Response response } => response.v1, + _ => null + }; + } + private static string FormatSenderResponseException(global::Payjoin.ResponseException responseException) { return responseException switch diff --git a/rust-payjoin b/rust-payjoin index f4a6008..dee54d6 160000 --- a/rust-payjoin +++ b/rust-payjoin @@ -1 +1 @@ -Subproject commit f4a6008a3a531530434bdd6911db864bcb42fc66 +Subproject commit dee54d6512f6860ffefefa93681694a623ab2328