exchange

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

commit 4a5e39300957413aeccf695a8d14854d3b6437de
parent c80fe0cca497ae3ce5d27048be0ff3cb1dbe553e
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed, 30 Apr 2025 23:39:07 +0200

use more portable GNUNET_static_assert(); fix handling of return value from TALER_MHD_parse_json_data, use phase loop more consistently

Diffstat:
Msrc/exchange/taler-exchange-httpd_withdraw.c | 123++++++++++++++++++++++++++++++++++++++-----------------------------------------
1 file changed, 59 insertions(+), 64 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c @@ -80,15 +80,15 @@ enum WithdrawError */ static const uint64_t idempotency_check_required = 0 - | (1 << WITHDRAW_ERROR_DENOMINATION_EXPIRED) - | (1 << WITHDRAW_ERROR_DENOMINATION_KEY_UNKNOWN) - | (1 << WITHDRAW_ERROR_DENOMINATION_REVOKED) - | (1 << WITHDRAW_ERROR_INSUFFICIENT_FUNDS) - | (1 << WITHDRAW_ERROR_KEYS_MISSING) - | (1 << WITHDRAW_ERROR_KYC_REQUIRED); + | (1LLU << WITHDRAW_ERROR_DENOMINATION_EXPIRED) + | (1LLU << WITHDRAW_ERROR_DENOMINATION_KEY_UNKNOWN) + | (1LLU << WITHDRAW_ERROR_DENOMINATION_REVOKED) + | (1LLU << WITHDRAW_ERROR_INSUFFICIENT_FUNDS) + | (1LLU << WITHDRAW_ERROR_KEYS_MISSING) + | (1LLU << WITHDRAW_ERROR_KYC_REQUIRED); #define IDEMPOTENCY_CHECK_REQUIRED(ec) \ - (0 != (idempotency_check_required & (1 << (ec)))) + (0LLU != (idempotency_check_required & (1LLU << (ec)))) /** @@ -110,6 +110,7 @@ struct WithdrawContext */ enum { + WITHDRAW_PHASE_PARSE = 0, WITHDRAW_PHASE_CHECK_KEYS, WITHDRAW_PHASE_CHECK_RESERVE_SIGNATURE, WITHDRAW_PHASE_RUN_LEGI_CHECK, @@ -150,7 +151,6 @@ struct WithdrawContext */ struct TALER_NormalizedPaytoHashP h_normalized_payto; - /** * Captures all parameters provided in the JSON request */ @@ -176,30 +176,32 @@ struct WithdrawContext struct TALER_EXCHANGEDB_Withdraw withdraw_idem; /** - * Array ``num_coins`` of hashes of the public keys + * Array of ``withdraw.num_coins`` hashes of the public keys * of the denominations to withdraw. */ struct TALER_DenominationHashP *denoms_h; /** - * Number of planchets. If ``max_age`` was _not_ set, this is equal to ``num_coins``. - * Otherwise (``max_age`` was set) it is ``num_coins * kappa``. + * Number of planchets. If ``withdraw.max_age`` was _not_ set, this is equal to ``num_coins``. + * Otherwise (``withdraw.max_age`` was set) it is ``withdraw.num_coins * kappa``. */ size_t num_planchets; /** - * Array of ``num_planchets`` coin planchets. + * Array of ``withdraw.num_planchets`` coin planchets. * Note that the size depends on the age restriction: - * If ``age_proof_required`` is false, this is an array of length ``num_coins``. - * Otherwise it is an array of length ``kappa*num_coins``, arranged - * in runs of ``num_coins`` coins, [0..num_coins)..[0..num_coins), - * one for each kappa value. + * If ``withdraw.age_proof_required`` is false, + * this is an array of length ``withdraw.num_coins``. + * Otherwise it is an array of length ``kappa*withdraw.num_coins``, + * arranged in runs of ``num_coins`` coins, + * [0..num_coins)..[0..num_coins), + * one for each #TALER_CNC_KAPPA value. */ struct TALER_BlindedPlanchet *planchets; /** * If proof of age-restriction is required, the #TALER_CNC_KAPPA hashes - * of the batches of n coins. + * of the batches of ``withdraw.num_coins`` coins. */ struct TALER_HashBlindedPlanchetsP kappa_planchets_h[TALER_CNC_KAPPA]; @@ -214,8 +216,8 @@ struct WithdrawContext struct TALER_Amount fee; /** - * Array @e withdraw.num_r_pubs of indices into @e denoms_h - * of CS denominations. + * Array of length ``withdraw.num_cs_r_values`` of indices into + * @e denoms_h of CS denominations. */ uint32_t *cs_indices; @@ -262,10 +264,14 @@ struct WithdrawContext uint32_t birthday; } maximum_age_too_large; - /* The lowest age required */ + /** + * The lowest age required + */ uint16_t age_restriction_required; - /* Balance of the reserve */ + /** + * Balance of the reserve + */ struct TALER_Amount insufficient_funds; enum TALER_ErrorCode ec_confirmation_sign; @@ -671,10 +677,9 @@ phase_prepare_transaction ( uint8_t bit = sig->blinded_sig->details.blinded_cs_answer.b; wc->request.withdraw.cs_r_choices |= bit << i; - _Static_assert ( + GNUNET_static_assert ( TALER_MAX_REFRESH_COINS <= - sizeof(wc->request.withdraw.cs_r_choices) * 8, - "TALER_MAX_REFRESH_COINS too large"); + sizeof(wc->request.withdraw.cs_r_choices) * 8); } } wc->phase++; @@ -1556,14 +1561,13 @@ phase_generate_reply_error ( /** - * Creates a new context for the incoming withdraw request + * Initializes the new context for the incoming withdraw request * * @param wc withdraw request context * @param root json body of the request - * @return GNUNET_OK on success, GNUNET_SYSERR otherwise (response sent) */ -static enum GNUNET_GenericReturnValue -withdraw_new_request ( +static void +withdraw_phase_parse ( struct WithdrawContext *wc, const json_t *root) { @@ -1598,10 +1602,13 @@ withdraw_new_request ( res = TALER_MHD_parse_json_data (wc->rc->connection, root, spec); - if (GNUNET_OK != res) + if (GNUNET_YES != res) { GNUNET_break_op (0); - return GNUNET_NO; + wc->phase = (GNUNET_SYSERR == res) + ? WITHDRAW_PHASE_RETURN_NO + : WITHDRAW_PHASE_RETURN_YES; + return; } /* For now, we only support cipher "ED25519" for signatures by the reserve */ @@ -1614,7 +1621,7 @@ withdraw_new_request ( WITHDRAW_ERROR_RESERVE_CIPHER_UNKNOWN, reserve_cipher_unknown, cipher); - return GNUNET_NO; + return; } wc->request.withdraw.age_proof_required = ! no_max_age; @@ -1633,7 +1640,7 @@ withdraw_new_request ( WITHDRAW_ERROR_REQUEST_PARAMETER_MALFORMED, request_parameter_malformed, "max_age must be the lower edge of an age group"); - return GNUNET_NO; + return; } } @@ -1643,9 +1650,8 @@ withdraw_new_request ( size_t array_size = json_array_size (j_coin_evs); const char *error; - _Static_assert ( - TALER_MAX_REFRESH_COINS < INT_MAX / TALER_CNC_KAPPA, - "TALER_MAX_REFRESH_COINS too large"); + GNUNET_static_assert ( + TALER_MAX_REFRESH_COINS < INT_MAX / TALER_CNC_KAPPA); #define BAIL_IF(cond, msg) \ if ((cond)) { \ @@ -1689,7 +1695,7 @@ withdraw_new_request ( WITHDRAW_ERROR_REQUEST_PARAMETER_MALFORMED, request_parameter_malformed, error); - return GNUNET_NO; + return; } } /* extract the denomination hashes */ @@ -1711,11 +1717,14 @@ withdraw_new_request ( res = TALER_MHD_parse_json_data (wc->rc->connection, value, ispec); - if (GNUNET_OK != res) + if (GNUNET_YES != res) { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); - return GNUNET_NO; + wc->phase = (GNUNET_SYSERR == res) + ? WITHDRAW_PHASE_RETURN_NO + : WITHDRAW_PHASE_RETURN_YES; + return; } } } @@ -1727,12 +1736,10 @@ withdraw_new_request ( wc->request.planchets = GNUNET_new_array (wc->request.num_planchets, struct TALER_BlindedPlanchet); - - - json_array_foreach (j_coin_evs, idx, j_cev) { + json_array_foreach (j_coin_evs, idx, j_cev) + { /* Now parse the individual envelopes and calculate the hash of * the commitment along the way. */ - struct GNUNET_JSON_Specification kspec[] = { TALER_JSON_spec_blinded_planchet (NULL, &wc->request.planchets[idx]), @@ -1746,7 +1753,10 @@ withdraw_new_request ( { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); - return GNUNET_NO; + wc->phase = (GNUNET_SYSERR == res) + ? WITHDRAW_PHASE_RETURN_NO + : WITHDRAW_PHASE_RETURN_YES; + return; } /* Check for duplicate planchets. Technically a bug on @@ -1763,13 +1773,13 @@ withdraw_new_request ( GNUNET_JSON_parse_free (spec); SET_ERROR (wc, WITHDRAW_ERROR_IDEMPOTENT_PLANCHET); - return GNUNET_NO; + return; } } /* end duplicate check */ } /* json_array_foreach over j_coin_evs */ } /* scope of j_kappa_planchets, idx */ GNUNET_JSON_parse_free (spec); - return GNUNET_OK; + wc->phase = WITHDRAW_PHASE_CHECK_KEYS; } @@ -1780,10 +1790,8 @@ TEH_handler_withdraw ( const char *const args[0]) { struct WithdrawContext *wc = rc->rh_ctx; - enum GNUNET_GenericReturnValue r; (void) args; - if (NULL == wc) { wc = GNUNET_new (struct WithdrawContext); @@ -1791,24 +1799,7 @@ TEH_handler_withdraw ( rc->rh_cleaner = &clean_withdraw_rc; wc->rc = rc; wc->now = GNUNET_TIME_timestamp_get (); - r = withdraw_new_request (wc, - root); - switch (r) - { - case GNUNET_SYSERR: - return MHD_NO; - case GNUNET_OK: - wc->phase = WITHDRAW_PHASE_CHECK_KEYS; - break; - case GNUNET_NO: - wc->phase = WITHDRAW_PHASE_GENERATE_REPLY_ERROR; - break; - default: - GNUNET_break (0); - return MHD_NO; - } } - while (true) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -1819,6 +1810,10 @@ TEH_handler_withdraw ( wc->phase); switch (wc->phase) { + case WITHDRAW_PHASE_PARSE: + withdraw_phase_parse (wc, + root); + break; case WITHDRAW_PHASE_CHECK_KEYS: phase_check_keys (wc); break;