exchange

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

commit 69159619a3e1bfb816cc91d3cc9150198934b6cf
parent 4a5e39300957413aeccf695a8d14854d3b6437de
Author: Özgür Kesim <oec@codeblau.de>
Date:   Wed, 30 Apr 2025 20:06:08 +0200

[exchange] fix reserve history data gathering, passing and parsing

Diffstat:
Msrc/exchange/taler-exchange-httpd_reserves_history.c | 6+++---
Msrc/exchangedb/pg_do_withdraw.c | 4+++-
Msrc/exchangedb/pg_get_reserve_by_h_planchets.c | 2+-
Msrc/exchangedb/pg_get_reserve_history.c | 2+-
Msrc/include/taler_exchange_service.h | 24+++++++++++++++++-------
Msrc/lib/exchange_api_reserves_history.c | 30++++++++++++++----------------
Msrc/lib/exchange_api_withdraw.c | 21+++++++++++++--------
Msrc/testing/testing_api_cmd_age_withdraw.c | 17++++++++++++-----
Msrc/testing/testing_api_cmd_batch_withdraw.c | 6+++---
Msrc/testing/testing_api_cmd_withdraw.c | 6+++---
10 files changed, 70 insertions(+), 48 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_reserves_history.c b/src/exchange/taler-exchange-httpd_reserves_history.c @@ -149,9 +149,6 @@ compile_reserve_history ( withdraw->num_coins, withdraw->denom_pub_hashes, sizeof(withdraw->denom_pub_hashes[0])), - GNUNET_JSON_pack_data_auto ( - "selected_h", - &withdraw->selected_h), TALER_JSON_pack_amount ( "withdraw_fee", &withdraw_fee), @@ -185,6 +182,9 @@ compile_reserve_history ( GNUNET_JSON_pack_uint64 ( "noreveal_index", withdraw->noreveal_index), + GNUNET_JSON_pack_data_auto ( + "selected_h", + &withdraw->selected_h), GNUNET_JSON_pack_uint64 ( "max_age", withdraw->max_age)))) diff --git a/src/exchangedb/pg_do_withdraw.c b/src/exchangedb/pg_do_withdraw.c @@ -58,7 +58,9 @@ TEH_PG_do_withdraw ( (withdraw->age_proof_required) ? GNUNET_PQ_query_param_uint16 (&withdraw->noreveal_index) : GNUNET_PQ_query_param_null (), - GNUNET_PQ_query_param_auto_from_type (&withdraw->selected_h), + (withdraw->age_proof_required) + ? GNUNET_PQ_query_param_auto_from_type (&withdraw->selected_h) + : GNUNET_PQ_query_param_null (), GNUNET_PQ_query_param_array_uint64 (withdraw->num_coins, withdraw->denom_serials, pg->conn), diff --git a/src/exchangedb/pg_get_reserve_by_h_planchets.c b/src/exchangedb/pg_get_reserve_by_h_planchets.c @@ -53,7 +53,7 @@ TEH_PG_get_reserve_by_h_planchets ( " reserve_pub" ",withdraw_id" " FROM withdraw" - " WHERE h_planchets=$1" + " WHERE planchets_h=$1" " LIMIT 1;"); return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "reserve_by_h_planchets", diff --git a/src/exchangedb/pg_get_reserve_history.c b/src/exchangedb/pg_get_reserve_history.c @@ -852,7 +852,7 @@ TEH_PG_get_reserve_history ( ",reserve_sig" ",max_age" ",noreveal_index" - ",h_blind_evs" + ",selected_h" ",blinding_seed" ",denom_serials" ",ARRAY(" diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h @@ -2167,6 +2167,11 @@ struct TALER_EXCHANGE_ReserveHistoryEntry json_t *out_authorization_sig; /** + * The running hash over all hashes of blinded planchets of the withrdawal + */ + struct TALER_HashBlindedPlanchetsP planchets_h; + + /** * If age restriction was required during the protocol */ bool age_restricted; @@ -2177,15 +2182,15 @@ struct TALER_EXCHANGE_ReserveHistoryEntry uint8_t max_age; /** - * If age_restricted is true, the index that is not to be revealed + * If @e age_restricted is true, the index that is not to be revealed * after the initial commitment in /withdraw */ uint8_t noreveal_index; /** - * The running hash over all hashes of blinded planchets of the withrdawal + * If @e age_restricted is true, the hash of the selected blinded planchets */ - struct TALER_HashBlindedPlanchetsP h_planchets; + struct TALER_HashBlindedPlanchetsP selected_h; /** * True, if no blinding_seed was provided. The value of @@ -2910,7 +2915,7 @@ struct TALER_EXCHANGE_WithdrawResponse /** * The commitment of the withdraw request, needed for the later calls to /recoup */ - struct TALER_HashBlindedPlanchetsP h_planchets; + struct TALER_HashBlindedPlanchetsP planchets_h; } ok; @@ -2928,10 +2933,15 @@ struct TALER_EXCHANGE_WithdrawResponse uint8_t noreveal_index; /** - * The commitment of the withdraw request with age restriction, needed for the + * The commitment of the withdraw request, needed for the * subsequent call to /reveal-withdraw and later calls to /recoup */ - struct TALER_HashBlindedPlanchetsP h_planchets; + struct TALER_HashBlindedPlanchetsP planchets_h; + + /** + * The hash of the selected batch of blinded coin envelopes. + */ + struct TALER_HashBlindedPlanchetsP selected_h; /** * The number of elements in @e coins, each referring to @@ -3151,7 +3161,7 @@ struct TALER_EXCHANGE_WithdrawBlindedResponse /** * The commitment of the withdraw request, needed for the later calls to /recoup */ - struct TALER_HashBlindedPlanchetsP h_planchets; + struct TALER_HashBlindedPlanchetsP planchets_h; } ok; diff --git a/src/lib/exchange_api_reserves_history.c b/src/lib/exchange_api_reserves_history.c @@ -205,30 +205,33 @@ parse_withdraw (struct TALER_EXCHANGE_ReserveHistoryEntry *rh, struct TALER_Amount withdraw_amount; uint8_t max_age = 0; uint8_t noreveal_index = 0; - struct TALER_HashBlindedPlanchetsP h_planchets; + struct TALER_HashBlindedPlanchetsP planchets_h; + struct TALER_HashBlindedPlanchetsP selected_h; struct TALER_ReserveSignatureP reserve_sig; struct TALER_BlindingMasterSeedP blinding_seed; - const json_t *j_h_coin_evs; const json_t *j_denom_pub_hashes; bool no_max_age; bool no_noreveal_index; bool no_blinding_seed; + bool no_selected_h; struct GNUNET_JSON_Specification withdraw_spec[] = { GNUNET_JSON_spec_fixed_auto ("reserve_sig", &reserve_sig), GNUNET_JSON_spec_uint16 ("num_coins", &num_coins), - GNUNET_JSON_spec_fixed_auto ("h_planchets", - &h_planchets), + GNUNET_JSON_spec_fixed_auto ("planchets_h", + &planchets_h), TALER_JSON_spec_amount_any ("amount", &withdraw_amount), TALER_JSON_spec_amount_any ("withdraw_fee", &withdraw_fee), - GNUNET_JSON_spec_array_const ("h_coin_evs", - &j_h_coin_evs), GNUNET_JSON_spec_array_const ("denom_pub_hashes", &j_denom_pub_hashes), GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ("selected_h", + &selected_h), + &no_selected_h), + GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_uint8 ("max_age", &max_age), &no_max_age), @@ -253,20 +256,14 @@ parse_withdraw (struct TALER_EXCHANGE_ReserveHistoryEntry *rh, return GNUNET_SYSERR; } - if (no_max_age != no_noreveal_index) + if ((no_max_age != no_noreveal_index) || + (no_max_age != no_selected_h)) { GNUNET_break_op (0); return GNUNET_SYSERR; } rh->details.withdraw.age_restricted = ! no_max_age; - if ((num_coins != json_array_size (j_h_coin_evs)) || - (num_coins != json_array_size (j_denom_pub_hashes))) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - /* Check that the signature is a valid withdraw request */ { struct TALER_Amount amount_without_fee; @@ -284,7 +281,7 @@ parse_withdraw (struct TALER_EXCHANGE_ReserveHistoryEntry *rh, TALER_wallet_withdraw_verify ( &amount_without_fee, &withdraw_fee, - &h_planchets, + &planchets_h, no_blinding_seed ? NULL : &blinding_seed, no_max_age ? NULL : &uc->keys->age_mask, no_max_age ? 0 : max_age, @@ -301,7 +298,8 @@ parse_withdraw (struct TALER_EXCHANGE_ReserveHistoryEntry *rh, rh->details.withdraw.fee = withdraw_fee; rh->details.withdraw.age_restricted = ! no_max_age; rh->details.withdraw.max_age = max_age; - rh->details.withdraw.h_planchets = h_planchets; + rh->details.withdraw.planchets_h = planchets_h; + rh->details.withdraw.selected_h = selected_h; rh->details.withdraw.noreveal_index = noreveal_index; rh->details.withdraw.no_blinding_seed = no_blinding_seed; if (! no_blinding_seed) diff --git a/src/lib/exchange_api_withdraw.c b/src/lib/exchange_api_withdraw.c @@ -180,9 +180,9 @@ struct TALER_EXCHANGE_WithdrawBlindedHandle struct TALER_EXCHANGE_Keys *keys; /** - * The hash of the planchets + * The hash of all the planchets */ - struct TALER_HashBlindedPlanchetsP h_planchets; + struct TALER_HashBlindedPlanchetsP planchets_h; /** * Seed used for the derival of blinding factors for denominations @@ -222,6 +222,11 @@ struct TALER_EXCHANGE_WithdrawBlindedHandle uint8_t max_age; /** + * If @e with_age_proof is true, the hash of all the selected planchets + */ + struct TALER_HashBlindedPlanchetsP selected_h; + + /** * Length of the either the @e blinded.input or * the @e blinded.with_age_proof_input array, * depending on @e with_age_proof. @@ -462,7 +467,7 @@ withdraw_blinded_ok ( response.details.ok.num_sigs = wbh->num_input; response.details.ok.blinded_denom_sigs = denoms_sig; - response.details.ok.h_planchets = wbh->h_planchets; + response.details.ok.planchets_h = wbh->planchets_h; wbh->callback ( wbh->callback_cls, &response); @@ -493,7 +498,7 @@ withdraw_blinded_created ( struct TALER_EXCHANGE_WithdrawBlindedResponse response = { .hr.reply = j_response, .hr.http_status = MHD_HTTP_CREATED, - .details.created.h_planchets = wbh->h_planchets, + .details.created.planchets_h = wbh->planchets_h, .details.created.num_coins = wbh->num_input, }; struct TALER_ExchangeSignatureP exchange_sig; @@ -518,7 +523,7 @@ withdraw_blinded_created ( if (GNUNET_OK != TALER_exchange_online_withdraw_age_confirmation_verify ( - &wbh->h_planchets, + &wbh->planchets_h, response.details.created.noreveal_index, &response.details.created.exchange_pub, &exchange_sig)) @@ -844,14 +849,14 @@ perform_withdraw_protocol ( /* Build the hash of the planchets */ GNUNET_CRYPTO_hash_context_finish ( coins_hctx, - &wbh->h_planchets.hash); + &wbh->planchets_h.hash); coins_hctx = NULL; /* Sign the request */ TALER_wallet_withdraw_sign ( &wbh->amount, &wbh->fee, - &wbh->h_planchets, + &wbh->planchets_h, wbh->blinding_seed, wbh->with_age_proof ? &wbh->age_mask: NULL, wbh->with_age_proof ? wbh->max_age : 0, @@ -964,7 +969,7 @@ copy_results ( resp.details.ok.num_sigs = wbr->details.ok.num_sigs; resp.details.ok.coin_details = details; - resp.details.ok.h_planchets = wbr->details.ok.h_planchets; + resp.details.ok.planchets_h = wbr->details.ok.planchets_h; memset (details, 0, sizeof(details)); diff --git a/src/testing/testing_api_cmd_age_withdraw.c b/src/testing/testing_api_cmd_age_withdraw.c @@ -149,7 +149,12 @@ struct AgeWithdrawState /** * The hash of the commitment, needed for the reveal step. */ - struct TALER_HashBlindedPlanchetsP h_planchets; + struct TALER_HashBlindedPlanchetsP planchets_h; + + /** + * The hash of the selected blinded planchets + */ + struct TALER_HashBlindedPlanchetsP selected_h; /** * Set to the KYC requirement payto hash *if* the exchange replied with a @@ -199,8 +204,10 @@ age_withdraw_cb ( { case MHD_HTTP_CREATED: aws->noreveal_index = response->details.created.noreveal_index; - aws->h_planchets = response->details.created.h_planchets; - aws->reserve_history.details.withdraw.h_planchets = aws->h_planchets; + aws->planchets_h = response->details.created.planchets_h; + aws->selected_h = response->details.created.selected_h; + aws->reserve_history.details.withdraw.planchets_h = aws->planchets_h; + aws->reserve_history.details.withdraw.selected_h = aws->selected_h; aws->reserve_history.details.withdraw.noreveal_index = aws->noreveal_index; aws->kappa_seed = response->details.created.kappa_seed; @@ -445,7 +452,7 @@ age_withdraw_traits ( &aws->denoms_pub[idx]), TALER_TESTING_make_trait_reserve_priv (&aws->reserve_priv), TALER_TESTING_make_trait_reserve_pub (&aws->reserve_pub), - TALER_TESTING_make_trait_withdraw_commitment (&aws->h_planchets), + TALER_TESTING_make_trait_withdraw_commitment (&aws->planchets_h), TALER_TESTING_make_trait_amounts (idx, &out->amount), /* FIXME[oec]: add legal requirement to response and handle it here, as well @@ -712,7 +719,7 @@ age_reveal_withdraw_run ( TALER_TESTING_interpreter_get_context (is), TALER_TESTING_get_exchange_url (is), aws->num_coins, - &aws->h_planchets, + &aws->planchets_h, &revealed_seeds, age_reveal_withdraw_cb, awrs); diff --git a/src/testing/testing_api_cmd_batch_withdraw.c b/src/testing/testing_api_cmd_batch_withdraw.c @@ -162,7 +162,7 @@ struct BatchWithdrawState /** * The commitment of the call to withdraw, needed later for recoup. */ - struct TALER_HashBlindedPlanchetsP h_planchets; + struct TALER_HashBlindedPlanchetsP planchets_h; }; @@ -205,7 +205,7 @@ batch_withdraw_cb (void *cls, TALER_denom_ewv_copy (&cs->details.alg_values, &wr->details.ok.coin_details[i].alg_values); } - ws->h_planchets = wr->details.ok.h_planchets; + ws->planchets_h = wr->details.ok.planchets_h; break; case MHD_HTTP_FORBIDDEN: /* nothing to check */ @@ -456,7 +456,7 @@ batch_withdraw_traits (void *cls, TALER_TESTING_make_trait_denom_sig (index, &cs->details.denom_sig), TALER_TESTING_make_trait_withdraw_seed (&ws->seed), - TALER_TESTING_make_trait_withdraw_commitment (&ws->h_planchets), + TALER_TESTING_make_trait_withdraw_commitment (&ws->planchets_h), TALER_TESTING_make_trait_reserve_priv (&ws->reserve_priv), TALER_TESTING_make_trait_reserve_pub (&ws->reserve_pub), TALER_TESTING_make_trait_amounts (index, diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c @@ -168,7 +168,7 @@ struct WithdrawState /** * The commitment for the withdraw operation, later needed for /recoup */ - struct TALER_HashBlindedPlanchetsP h_planchets; + struct TALER_HashBlindedPlanchetsP planchets_h; /** * Task scheduled to try later. @@ -309,7 +309,7 @@ withdraw_cb (void *cls, ws->bks = wr->details.ok.coin_details[0].blinding_key; TALER_denom_ewv_copy (&ws->exchange_vals, &wr->details.ok.coin_details[0].alg_values); - ws->h_planchets = wr->details.ok.h_planchets; + ws->planchets_h = wr->details.ok.planchets_h; if (0<ws->age) { /* copy the age-commitment data */ @@ -548,7 +548,7 @@ withdraw_traits (void *cls, &ws->coin_priv), TALER_TESTING_make_trait_withdraw_seed (&ws->seed), TALER_TESTING_make_trait_blinding_seed (&ws->blinding_seed), - TALER_TESTING_make_trait_withdraw_commitment (&ws->h_planchets), + TALER_TESTING_make_trait_withdraw_commitment (&ws->planchets_h), TALER_TESTING_make_trait_blinding_key (0 /* only one coin */, &ws->bks), TALER_TESTING_make_trait_exchange_wd_value (0 /* only one coin */,