exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit ff9a50fbfd214b425d4a7b03cbfe1202d8932821
parent cfa1403dace40e7b336603c1f64dcad1132956b8
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed, 23 Sep 2026 14:40:04 +0200

gana: update for CHALLENGER_VALIDATION_FAILED

Also brings in the recoup and permanent wallet transaction failure
entries that landed in GANA since the last update.

Issue: https://bugs.taler.net/n/11740
Signed-off-by: Christian Grothoff <christian@grothoff.org>

Diffstat:
Msrc/include/taler/taler_error_codes.h | 124++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/include/taler/taler_signatures.h | 12++++++++++++
Msrc/util/taler_error_codes.c | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
3 files changed, 235 insertions(+), 19 deletions(-)

diff --git a/src/include/taler/taler_error_codes.h b/src/include/taler/taler_error_codes.h @@ -1449,13 +1449,37 @@ enum TALER_ErrorCode /** * The coin's denomination has not been revoked yet. - * Returned with an HTTP status code of #MHD_HTTP_NOT_FOUND (404). + * Returned with an HTTP status code of #MHD_HTTP_GONE (410). * (A value of 0 indicates that the error is generated client-side). */ TALER_EC_EXCHANGE_RECOUP_NOT_ELIGIBLE = 1555, /** + * The number of coins in the recoup request does not match the number of coins signed in the withdraw operation. + * Returned with an HTTP status code of #MHD_HTTP_BAD_REQUEST (400). + * (A value of 0 indicates that the error is generated client-side). + */ + TALER_EC_EXCHANGE_RECOUP_WITHDRAW_BATCH_SIZE_MISMATCH = 1556, + + + /** + * The hash over the coins in the recoup request does not match the commitment of the withdraw operation. At least one disclosed coin was not part of the operation. + * Returned with an HTTP status code of #MHD_HTTP_CONFLICT (409). + * (A value of 0 indicates that the error is generated client-side). + */ + TALER_EC_EXCHANGE_RECOUP_WITHDRAW_COMMITMENT_MISMATCH = 1557, + + + /** + * The denomination of a disclosed coin differs from the denomination recorded for that position of the withdraw operation. + * Returned with an HTTP status code of #MHD_HTTP_CONFLICT (409). + * (A value of 0 indicates that the error is generated client-side). + */ + TALER_EC_EXCHANGE_RECOUP_WITHDRAW_DENOMINATION_MISMATCH = 1558, + + + /** * The given coin signature is invalid for the request. * Returned with an HTTP status code of #MHD_HTTP_FORBIDDEN (403). * (A value of 0 indicates that the error is generated client-side). @@ -1481,13 +1505,37 @@ enum TALER_ErrorCode /** * The coin's denomination has not been revoked yet. - * Returned with an HTTP status code of #MHD_HTTP_NOT_FOUND (404). + * Returned with an HTTP status code of #MHD_HTTP_GONE (410). * (A value of 0 indicates that the error is generated client-side). */ TALER_EC_EXCHANGE_RECOUP_REFRESH_NOT_ELIGIBLE = 1580, /** + * The number of coins in the recoup request does not match the number of coins signed in the refresh operation. + * Returned with an HTTP status code of #MHD_HTTP_BAD_REQUEST (400). + * (A value of 0 indicates that the error is generated client-side). + */ + TALER_EC_EXCHANGE_RECOUP_REFRESH_BATCH_SIZE_MISMATCH = 1581, + + + /** + * The hash over the coins in the recoup request does not match the commitment of the refresh operation. At least one disclosed coin was not part of the operation. + * Returned with an HTTP status code of #MHD_HTTP_CONFLICT (409). + * (A value of 0 indicates that the error is generated client-side). + */ + TALER_EC_EXCHANGE_RECOUP_REFRESH_COMMITMENT_MISMATCH = 1582, + + + /** + * The denomination of a disclosed coin differs from the denomination recorded for that position of the refresh operation. + * Returned with an HTTP status code of #MHD_HTTP_CONFLICT (409). + * (A value of 0 indicates that the error is generated client-side). + */ + TALER_EC_EXCHANGE_RECOUP_REFRESH_DENOMINATION_MISMATCH = 1583, + + + /** * This exchange does not allow clients to request `/keys` for times other than the current exchange time. * Returned with an HTTP status code of #MHD_HTTP_FORBIDDEN (403). * (A value of 0 indicates that the error is generated client-side). @@ -3486,8 +3534,8 @@ enum TALER_ErrorCode * Returned with an HTTP status code of #MHD_HTTP_NOT_FOUND (404). * (A value of 0 indicates that the error is generated client-side). */ - TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_INSTANCE_CONFIGURATION_LACKS_WIRE = - 2500, + TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_INSTANCE_CONFIGURATION_LACKS_WIRE = 2500 + , /** @@ -3624,8 +3672,8 @@ enum TALER_ErrorCode * Returned with an HTTP status code of #MHD_HTTP_GONE (410). * (A value of 0 indicates that the error is generated client-side). */ - TALER_EC_MERCHANT_PRIVATE_GET_STATISTICS_REPORT_GRANULARITY_UNAVAILABLE = - 2525, + TALER_EC_MERCHANT_PRIVATE_GET_STATISTICS_REPORT_GRANULARITY_UNAVAILABLE = 2525 + , /** @@ -3649,8 +3697,8 @@ enum TALER_ErrorCode * Returned with an HTTP status code of #MHD_HTTP_FORBIDDEN (403). * (A value of 0 indicates that the error is generated client-side). */ - TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ID_REFUND_NOT_ALLOWED_BY_CONTRACT = - 2532, + TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ID_REFUND_NOT_ALLOWED_BY_CONTRACT = 2532 + , /** @@ -3707,8 +3755,8 @@ enum TALER_ErrorCode * Returned with an HTTP status code of #MHD_HTTP_CONFLICT (409). * (A value of 0 indicates that the error is generated client-side). */ - TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ID_REFUND_EXTERNAL_ALREADY_EXISTS = - 2539, + TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ID_REFUND_EXTERNAL_ALREADY_EXISTS = 2539 + , /** @@ -5387,6 +5435,54 @@ enum TALER_ErrorCode /** + * The operation was completed or taken over by another wallet. + * Returned with an HTTP status code of #MHD_HTTP_UNINITIALIZED (0). + * (A value of 0 indicates that the error is generated client-side). + */ + TALER_EC_WALLET_TRANSACTION_COMPLETED_BY_OTHER_WALLET = 7070, + + + /** + * Refreshing one or more coins failed permanently. + * Returned with an HTTP status code of #MHD_HTTP_UNINITIALIZED (0). + * (A value of 0 indicates that the error is generated client-side). + */ + TALER_EC_WALLET_REFRESH_GROUP_FAILED = 7071, + + + /** + * Recouping one or more revoked coins failed permanently. + * Returned with an HTTP status code of #MHD_HTTP_UNINITIALIZED (0). + * (A value of 0 indicates that the error is generated client-side). + */ + TALER_EC_WALLET_RECOUP_GROUP_FAILED = 7072, + + + /** + * One or more refunds were permanently rejected by the exchange. + * Returned with an HTTP status code of #MHD_HTTP_UNINITIALIZED (0). + * (A value of 0 indicates that the error is generated client-side). + */ + TALER_EC_WALLET_REFUND_GROUP_FAILED = 7073, + + + /** + * Recovery of the transaction inputs failed or the recovery operation is missing. + * Returned with an HTTP status code of #MHD_HTTP_UNINITIALIZED (0). + * (A value of 0 indicates that the error is generated client-side). + */ + TALER_EC_WALLET_TRANSACTION_RECOVERY_FAILED = 7074, + + + /** + * An operation required to complete the transaction failed or is missing. + * Returned with an HTTP status code of #MHD_HTTP_UNINITIALIZED (0). + * (A value of 0 indicates that the error is generated client-side). + */ + TALER_EC_WALLET_TRANSACTION_DEPENDENCY_FAILED = 7075, + + + /** * The service encountered a timeout with its payment backend. * Returned with an HTTP status code of #MHD_HTTP_GATEWAY_TIMEOUT (504). * (A value of 0 indicates that the error is generated client-side). @@ -6283,6 +6379,14 @@ enum TALER_ErrorCode /** + * The validation failed permanently: the user exhausted all address changes, TAN transmissions and TAN attempts. The validation cannot succeed anymore; the user must be sent back to the client, which has to start a new validation if it wants to try again. + * Returned with an HTTP status code of #MHD_HTTP_GONE (410). + * (A value of 0 indicates that the error is generated client-side). + */ + TALER_EC_CHALLENGER_VALIDATION_FAILED = 9772, + + + /** * The request is invalid as the specified order is unpaid. The client should only call this endpoint after paying the order. * Returned with an HTTP status code of #MHD_HTTP_CONFLICT (409). * (A value of 0 indicates that the error is generated client-side). diff --git a/src/include/taler/taler_signatures.h b/src/include/taler/taler_signatures.h @@ -227,6 +227,18 @@ /** + * Signature where the Exchange confirms a batch recoup of coins to the reserve they were withdrawn from. + */ +#define TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_WITHDRAW_BATCH 1051 + + +/** + * Signature where the Exchange confirms a batch recoup of coins to the old coin they were refreshed from. + */ +#define TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH_BATCH 1052 + + +/** * Signature where the auditor confirms that he is aware of certain denomination keys from the exchange. */ #define TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS 1064 diff --git a/src/util/taler_error_codes.c b/src/util/taler_error_codes.c @@ -1419,7 +1419,31 @@ static const struct ErrorCodeAndHint code_hint_pairs[] = { /* 1555 */ .ec = TALER_EC_EXCHANGE_RECOUP_NOT_ELIGIBLE, .hint = "The coin's denomination has not been revoked yet.", - .http_code = MHD_HTTP_NOT_FOUND + .http_code = MHD_HTTP_GONE + }, + + { + /* 1556 */ + .ec = TALER_EC_EXCHANGE_RECOUP_WITHDRAW_BATCH_SIZE_MISMATCH, + .hint = + "The number of coins in the recoup request does not match the number of coins signed in the withdraw operation.", + .http_code = MHD_HTTP_BAD_REQUEST + }, + + { + /* 1557 */ + .ec = TALER_EC_EXCHANGE_RECOUP_WITHDRAW_COMMITMENT_MISMATCH, + .hint = + "The hash over the coins in the recoup request does not match the commitment of the withdraw operation. At least one disclosed coin was not part of the operation.", + .http_code = MHD_HTTP_CONFLICT + }, + + { + /* 1558 */ + .ec = TALER_EC_EXCHANGE_RECOUP_WITHDRAW_DENOMINATION_MISMATCH, + .hint = + "The denomination of a disclosed coin differs from the denomination recorded for that position of the withdraw operation.", + .http_code = MHD_HTTP_CONFLICT }, { @@ -1448,7 +1472,31 @@ static const struct ErrorCodeAndHint code_hint_pairs[] = { /* 1580 */ .ec = TALER_EC_EXCHANGE_RECOUP_REFRESH_NOT_ELIGIBLE, .hint = "The coin's denomination has not been revoked yet.", - .http_code = MHD_HTTP_NOT_FOUND + .http_code = MHD_HTTP_GONE + }, + + { + /* 1581 */ + .ec = TALER_EC_EXCHANGE_RECOUP_REFRESH_BATCH_SIZE_MISMATCH, + .hint = + "The number of coins in the recoup request does not match the number of coins signed in the refresh operation.", + .http_code = MHD_HTTP_BAD_REQUEST + }, + + { + /* 1582 */ + .ec = TALER_EC_EXCHANGE_RECOUP_REFRESH_COMMITMENT_MISMATCH, + .hint = + "The hash over the coins in the recoup request does not match the commitment of the refresh operation. At least one disclosed coin was not part of the operation.", + .http_code = MHD_HTTP_CONFLICT + }, + + { + /* 1583 */ + .ec = TALER_EC_EXCHANGE_RECOUP_REFRESH_DENOMINATION_MISMATCH, + .hint = + "The denomination of a disclosed coin differs from the denomination recorded for that position of the refresh operation.", + .http_code = MHD_HTTP_CONFLICT }, { @@ -2945,8 +2993,8 @@ static const struct ErrorCodeAndHint code_hint_pairs[] = { { /* 2166 */ - .ec = - TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_WIRE_FEE_ADDITION_FAILED, + .ec = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_WIRE_FEE_ADDITION_FAILED + , .hint = "The exchange of the deposited coin charges a wire fee that could not be added to the total (total amount too high).", .http_code = MHD_HTTP_INTERNAL_SERVER_ERROR @@ -3170,8 +3218,8 @@ static const struct ErrorCodeAndHint code_hint_pairs[] = { { /* 2254 */ - .ec = - TALER_EC_MERCHANT_POST_ORDERS_ID_ABORT_REFUND_REFUSED_PAYMENT_COMPLETE, + .ec = TALER_EC_MERCHANT_POST_ORDERS_ID_ABORT_REFUND_REFUSED_PAYMENT_COMPLETE + , .hint = "The payment was already completed and thus cannot be aborted anymore.", .http_code = MHD_HTTP_PRECONDITION_FAILED @@ -3438,8 +3486,8 @@ static const struct ErrorCodeAndHint code_hint_pairs[] = { { /* 2510 */ - .ec = - TALER_EC_MERCHANT_PRIVATE_PATCH_ORDERS_ID_FORGET_PATH_SYNTAX_INCORRECT, + .ec = TALER_EC_MERCHANT_PRIVATE_PATCH_ORDERS_ID_FORGET_PATH_SYNTAX_INCORRECT + , .hint = "One of the paths to forget is malformed.", .http_code = MHD_HTTP_BAD_REQUEST }, @@ -5189,6 +5237,50 @@ static const struct ErrorCodeAndHint code_hint_pairs[] = { }, { + /* 7070 */ + .ec = TALER_EC_WALLET_TRANSACTION_COMPLETED_BY_OTHER_WALLET, + .hint = "The operation was completed or taken over by another wallet.", + .http_code = MHD_HTTP_UNINITIALIZED + }, + + { + /* 7071 */ + .ec = TALER_EC_WALLET_REFRESH_GROUP_FAILED, + .hint = "Refreshing one or more coins failed permanently.", + .http_code = MHD_HTTP_UNINITIALIZED + }, + + { + /* 7072 */ + .ec = TALER_EC_WALLET_RECOUP_GROUP_FAILED, + .hint = "Recouping one or more revoked coins failed permanently.", + .http_code = MHD_HTTP_UNINITIALIZED + }, + + { + /* 7073 */ + .ec = TALER_EC_WALLET_REFUND_GROUP_FAILED, + .hint = "One or more refunds were permanently rejected by the exchange.", + .http_code = MHD_HTTP_UNINITIALIZED + }, + + { + /* 7074 */ + .ec = TALER_EC_WALLET_TRANSACTION_RECOVERY_FAILED, + .hint = + "Recovery of the transaction inputs failed or the recovery operation is missing.", + .http_code = MHD_HTTP_UNINITIALIZED + }, + + { + /* 7075 */ + .ec = TALER_EC_WALLET_TRANSACTION_DEPENDENCY_FAILED, + .hint = + "An operation required to complete the transaction failed or is missing.", + .http_code = MHD_HTTP_UNINITIALIZED + }, + + { /* 8000 */ .ec = TALER_EC_ANASTASIS_GENERIC_BACKEND_TIMEOUT, .hint = "The service encountered a timeout with its payment backend.", @@ -6033,6 +6125,14 @@ static const struct ErrorCodeAndHint code_hint_pairs[] = { }, { + /* 9772 */ + .ec = TALER_EC_CHALLENGER_VALIDATION_FAILED, + .hint = + "The validation failed permanently: the user exhausted all address changes, TAN transmissions and TAN attempts. The validation cannot succeed anymore; the user must be sent back to the client, which has to start a new validation if it wants to try again.", + .http_code = MHD_HTTP_GONE + }, + + { /* 9800 */ .ec = TALER_EC_PAIVANA_PAYMENT_MISSING, .hint = @@ -6126,7 +6226,7 @@ static const struct ErrorCodeAndHint code_hint_pairs[] = { /** * The length of @e code_hint_pairs. */ -static const unsigned int code_hint_pairs_length = 789; +static const unsigned int code_hint_pairs_length = 802; const char *