exchange

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

commit 43e9029031dde0a7679b885db6f838878783c884
parent 073b76e9057087fbf0dae15921c558495281f1bf
Author: Christian Grothoff <grothoff@gnunet.org>
Date:   Thu,  1 May 2025 15:10:26 +0200

fix error handling on internal invariant violation

Diffstat:
Msrc/exchange/taler-exchange-httpd_melt_v27.c | 124+++++++++++++++++++++++++++++++++----------------------------------------------
Msrc/exchange/taler-exchange-httpd_withdraw.c | 10+++++-----
2 files changed, 56 insertions(+), 78 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_melt_v27.c b/src/exchange/taler-exchange-httpd_melt_v27.c @@ -267,19 +267,22 @@ struct MeltContext */ #define SET_ERROR(mc, ec) \ do \ - { (mc)->error.code = (ec); \ + { GNUNET_static_assert (MELT_ERROR_NONE != ec); \ + (mc)->error.code = (ec); \ (mc)->phase = MELT_PHASE_GENERATE_REPLY_ERROR; } while (0) #define SET_ERROR_WITH_FIELD(mc, ec, field) \ do \ - { (mc)->error.code = (ec); \ - (mc)->error.details.field = (field); \ + { GNUNET_static_assert (MELT_ERROR_NONE != ec); \ + (mc)->error.code = (ec); \ + (mc)->error.details.field = (field); \ (mc)->phase = MELT_PHASE_GENERATE_REPLY_ERROR; } while (0) #define SET_ERROR_WITH_DETAIL(mc, ec, field, value) \ do \ - { (mc)->error.code = (ec); \ - (mc)->error.details.field = (value); \ + { GNUNET_static_assert (MELT_ERROR_NONE != ec); \ + (mc)->error.code = (ec); \ + (mc)->error.details.field = (value); \ (mc)->phase = MELT_PHASE_GENERATE_REPLY_ERROR; } while (0) @@ -424,8 +427,7 @@ phase_parse_request ( /* validate array size */ GNUNET_static_assert ( - TALER_MAX_COINS < INT_MAX / TALER_CNC_KAPPA, - "TALER_MAX_COINS too large"); + TALER_MAX_COINS < INT_MAX / TALER_CNC_KAPPA); mc->request.refresh.num_coins = json_array_size (j_denoms_h); if (0 == mc->request.refresh.num_coins) @@ -1109,8 +1111,7 @@ phase_prepare_transaction ( mc->request.refresh.cs_r_choices |= bit << i; GNUNET_static_assert ( TALER_MAX_COINS <= - sizeof(mc->request.refresh.cs_r_choices) * 8, - "TALER_MAX_COINS too large"); + sizeof(mc->request.refresh.cs_r_choices) * 8); } } } @@ -1220,8 +1221,8 @@ phase_generate_reply_error ( GNUNET_assert (MELT_PHASE_GENERATE_REPLY_ERROR == mc->phase); GNUNET_assert (MELT_ERROR_NONE != mc->error.code); - if (IDEMPOTENCY_CHECK_REQUIRED (mc->error.code) - && melt_is_idempotent (mc)) + if (IDEMPOTENCY_CHECK_REQUIRED (mc->error.code) && + melt_is_idempotent (mc)) { return; } @@ -1229,10 +1230,7 @@ phase_generate_reply_error ( switch (mc->error.code) { case MELT_ERROR_NONE: - GNUNET_break (0); - mc->phase = MELT_PHASE_RETURN_YES; - return; - + break; case MELT_ERROR_REQUEST_PARAMETER_MALFORMED: finish_loop (mc, TALER_MHD_reply_with_error ( @@ -1240,8 +1238,7 @@ phase_generate_reply_error ( MHD_HTTP_BAD_REQUEST, TALER_EC_GENERIC_PARAMETER_MALFORMED, mc->error.details.request_parameter_malformed)); - break; - + return; case MELT_ERROR_KEYS_MISSING: finish_loop (mc, TALER_MHD_reply_with_error ( @@ -1249,8 +1246,7 @@ phase_generate_reply_error ( MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, NULL)); - break; - + return; case MELT_ERROR_DB_FETCH_FAILED: finish_loop (mc, TALER_MHD_reply_with_error ( @@ -1258,8 +1254,7 @@ phase_generate_reply_error ( MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_FETCH_FAILED, mc->error.details.db_fetch_context)); - break; - + return; case MELT_ERROR_DB_INVARIANT_FAILURE: finish_loop (mc, TALER_MHD_reply_with_error ( @@ -1267,8 +1262,7 @@ phase_generate_reply_error ( MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_INVARIANT_FAILURE, NULL)); - break; - + return; case MELT_ERROR_DB_PREFLIGHT_FAILURE: finish_loop (mc, TALER_MHD_reply_with_error ( @@ -1276,8 +1270,7 @@ phase_generate_reply_error ( MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_COMMIT_FAILED, "make_coin_known")); - break; - + return; case MELT_ERROR_DB_MAKE_COIN_KNOW_FAILURE: finish_loop (mc, TALER_MHD_reply_with_error ( @@ -1285,57 +1278,50 @@ phase_generate_reply_error ( MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_START_FAILED, "preflight failure")); - break; - + return; case MELT_ERROR_COIN_UNKNOWN: finish_loop (mc, TALER_MHD_reply_with_ec ( mc->rc->connection, TALER_EC_EXCHANGE_GENERIC_COIN_UNKNOWN, NULL)); - break; - + return; case MELT_COIN_CONFLICTING_DENOMINATION_KEY: finish_loop (mc, TALER_MHD_reply_with_ec ( mc->rc->connection, TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY, TALER_B2S (&mc->error.details.denom_h))); - break; - - case MELT_ERROR_COIN_EXPIRED_NO_ZOMBIE: + return; + case MELT_ERROR_COIN_EXPIRED_NO_ZOMBIE: finish_loop (mc, TALER_MHD_reply_with_error ( mc->rc->connection, MHD_HTTP_BAD_REQUEST, TALER_EC_EXCHANGE_MELT_COIN_EXPIRED_NO_ZOMBIE, NULL)); - break; - + return; case MELT_ERROR_DENOMINATION_SIGN: finish_loop (mc, TALER_MHD_reply_with_ec ( mc->rc->connection, mc->error.details.ec_denomination_sign, NULL)); - break; - + return; case MELT_ERROR_DENOMINATION_SIGNATURE_INVALID: finish_loop (mc, TALER_MHD_reply_with_error (mc->rc->connection, MHD_HTTP_FORBIDDEN, TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID, NULL)); - break; - + return; case MELT_ERROR_DENOMINATION_KEY_UNKNOWN: GNUNET_break_op (0); finish_loop (mc, TEH_RESPONSE_reply_unknown_denom_pub_hash ( mc->rc->connection, &mc->error.details.denom_h)); - break; - + return; case MELT_ERROR_DENOMINATION_EXPIRED: GNUNET_break_op (0); finish_loop (mc, @@ -1344,8 +1330,7 @@ phase_generate_reply_error ( &mc->error.details.denom_h, TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED, "MELT")); - break; - + return; case MELT_ERROR_DENOMINATION_VALIDITY_IN_FUTURE: finish_loop (mc, TEH_RESPONSE_reply_expired_denom_pub_hash ( @@ -1353,8 +1338,7 @@ phase_generate_reply_error ( &mc->error.details.denom_h, TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE, "MELT")); - break; - + return; case MELT_ERROR_DENOMINATION_REVOKED: GNUNET_break_op (0); finish_loop (mc, @@ -1362,35 +1346,32 @@ phase_generate_reply_error ( mc->rc->connection, TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED, NULL)); - break; - + return; case MELT_ERROR_COIN_CIPHER_MISMATCH: finish_loop (mc, TALER_MHD_reply_with_ec ( mc->rc->connection, TALER_EC_EXCHANGE_GENERIC_CIPHER_MISMATCH, NULL)); - break; - + return; case MELT_ERROR_BLINDING_SEED_REQUIRED: finish_loop (mc, TALER_MHD_reply_with_ec ( mc->rc->connection, TALER_EC_GENERIC_PARAMETER_MISSING, "blinding_seed")); - break; - + return; case MELT_ERROR_CRYPTO_HELPER: finish_loop (mc, TALER_MHD_reply_with_ec ( mc->rc->connection, TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, NULL)); - break; - + return; case MELT_ERROR_AGE_RESTRICTION_NOT_SUPPORTED_BY_DENOMINATION: { char msg[256]; + GNUNET_snprintf (msg, sizeof(msg), "denomination %s does not support age restriction", @@ -1400,17 +1381,15 @@ phase_generate_reply_error ( mc->rc->connection, TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN, msg)); - break; + return; } - case MELT_ERROR_AGE_RESTRICTION_COMMITMENT_INVALID: finish_loop (mc, TALER_MHD_reply_with_ec ( mc->rc->connection, TALER_EC_EXCHANGE_REFRESHES_REVEAL_AGE_RESTRICTION_COMMITMENT_INVALID, "old_age_commitment_h")); - break; - + return; case MELT_ERROR_AMOUNT_OVERFLOW: finish_loop (mc, TALER_MHD_reply_with_error ( @@ -1418,8 +1397,7 @@ phase_generate_reply_error ( MHD_HTTP_BAD_REQUEST, TALER_EC_EXCHANGE_REFRESHES_REVEAL_COST_CALCULATION_OVERFLOW, "amount")); - break; - + return; case MELT_ERROR_AMOUNT_PLUS_FEE_OVERFLOW: finish_loop (mc, TALER_MHD_reply_with_error ( @@ -1427,16 +1405,14 @@ phase_generate_reply_error ( MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_EXCHANGE_REFRESHES_REVEAL_COST_CALCULATION_OVERFLOW, "amount+fee")); - break; - + return; case MELT_ERROR_FEES_EXCEED_CONTRIBUTION: finish_loop (mc, TALER_MHD_reply_with_error (mc->rc->connection, MHD_HTTP_BAD_REQUEST, TALER_EC_EXCHANGE_MELT_FEES_EXCEED_CONTRIBUTION, NULL)); - break; - + return; case MELT_ERROR_AMOUNT_WITH_FEE_INCORRECT: finish_loop (mc, TALER_MHD_reply_with_error ( @@ -1444,16 +1420,14 @@ phase_generate_reply_error ( MHD_HTTP_BAD_REQUEST, TALER_EC_EXCHANGE_REFRESHES_REVEAL_COST_CALCULATION_OVERFLOW, "value_with_fee incorrect")); - break; - + return; case MELT_ERROR_CONFIRMATION_SIGN: finish_loop (mc, TALER_MHD_reply_with_ec ( mc->rc->connection, mc->error.details.ec_confirmation_sign, NULL)); - break; - + return; case MELT_ERROR_INSUFFICIENT_FUNDS: finish_loop (mc, TEH_RESPONSE_reply_coin_insufficient_funds ( @@ -1461,8 +1435,7 @@ phase_generate_reply_error ( TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS, &mc->request.refresh.coin.denom_pub_hash, &mc->request.refresh.coin.coin_pub)); - break; - + return; case MELT_ERROR_IDEMPOTENT_PLANCHET: finish_loop (mc, TALER_MHD_reply_with_error ( @@ -1470,8 +1443,7 @@ phase_generate_reply_error ( MHD_HTTP_BAD_REQUEST, TALER_EC_GENERIC_PARAMETER_MALFORMED, /* FIXME: new error! */ "idempotent planchet")); - break; - + return; case MELT_ERROR_NONCE_RESUSE: finish_loop (mc, TALER_MHD_reply_with_error ( @@ -1479,16 +1451,22 @@ phase_generate_reply_error ( MHD_HTTP_BAD_REQUEST, TALER_EC_GENERIC_PARAMETER_MALFORMED, /* FIXME: new error */ "nonce reuse")); - break; - + return; case MELT_ERROR_COIN_SIGNATURE_INVALID: finish_loop (mc, TALER_MHD_reply_with_ec ( mc->rc->connection, TALER_EC_EXCHANGE_MELT_COIN_SIGNATURE_INVALID, NULL)); - break; + return; } + GNUNET_break (0); + finish_loop (mc, + TALER_MHD_reply_with_error ( + mc->rc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "error phase without error")); } diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c @@ -296,21 +296,21 @@ struct WithdrawContext #define SET_ERROR(wc, ec) \ do \ { GNUNET_static_assert (WITHDRAW_ERROR_NONE != ec); \ - (wc)->error.code = (ec); \ + (wc)->error.code = (ec); \ (wc)->phase = WITHDRAW_PHASE_GENERATE_REPLY_ERROR; } while (0) #define SET_ERROR_WITH_FIELD(wc, ec, field) \ do \ { GNUNET_static_assert (WITHDRAW_ERROR_NONE != ec); \ - (wc)->error.code = (ec); \ - (wc)->error.details.field = (field); \ + (wc)->error.code = (ec); \ + (wc)->error.details.field = (field); \ (wc)->phase = WITHDRAW_PHASE_GENERATE_REPLY_ERROR; } while (0) #define SET_ERROR_WITH_DETAIL(wc, ec, field, value) \ do \ { GNUNET_static_assert (WITHDRAW_ERROR_NONE != ec); \ - (wc)->error.code = (ec); \ - (wc)->error.details.field = (value); \ + (wc)->error.code = (ec); \ + (wc)->error.details.field = (value); \ (wc)->phase = WITHDRAW_PHASE_GENERATE_REPLY_ERROR; } while (0)