From 3ff92b9bbcf072d0b9840ad1c6af0a2bc1b1ef21 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 5 Jul 2022 12:07:27 +0200 Subject: -deduplicate purse creation confirmation logic --- src/exchange/taler-exchange-httpd_purses_create.c | 112 +++++-------------- src/exchange/taler-exchange-httpd_reserves_purse.c | 120 ++++++--------------- src/exchange/taler-exchange-httpd_responses.c | 42 ++++++++ src/exchange/taler-exchange-httpd_responses.h | 46 +++++++- 4 files changed, 144 insertions(+), 176 deletions(-) diff --git a/src/exchange/taler-exchange-httpd_purses_create.c b/src/exchange/taler-exchange-httpd_purses_create.c index 9cabdb1a1..078357899 100644 --- a/src/exchange/taler-exchange-httpd_purses_create.c +++ b/src/exchange/taler-exchange-httpd_purses_create.c @@ -39,26 +39,12 @@ */ struct PurseCreateContext { - /** - * Public key of the purse we are creating. - */ - const struct TALER_PurseContractPublicKeyP *purse_pub; - - /** - * Total amount to be put into the purse. - */ - struct TALER_Amount amount; /** * Total actually deposited by all the coins. */ struct TALER_Amount deposit_total; - /** - * When should the purse expire. - */ - struct GNUNET_TIME_Timestamp purse_expiration; - /** * Our current time. */ @@ -80,9 +66,9 @@ struct PurseCreateContext struct TALER_PurseContractSignatureP purse_sig; /** - * Hash of the contract terms of the purse. + * Fundamental details about the purse. */ - struct TALER_PrivateContractHashP h_contract_terms; + struct TEH_PurseDetails pd; /** * Array of coins being deposited. @@ -107,52 +93,6 @@ struct PurseCreateContext }; -/** - * Send confirmation of purse creation success to client. - * - * @param connection connection to the client - * @param pcc details about the request that succeeded - * @return MHD result code - */ -static MHD_RESULT -reply_create_success (struct MHD_Connection *connection, - const struct PurseCreateContext *pcc) -{ - struct TALER_ExchangePublicKeyP pub; - struct TALER_ExchangeSignatureP sig; - enum TALER_ErrorCode ec; - - if (TALER_EC_NONE != - (ec = TALER_exchange_online_purse_created_sign ( - &TEH_keys_exchange_sign_, - pcc->exchange_timestamp, - pcc->purse_expiration, - &pcc->amount, - &pcc->deposit_total, - pcc->purse_pub, - &pcc->h_contract_terms, - &pub, - &sig))) - { - GNUNET_break (0); - return TALER_MHD_reply_with_ec (connection, - ec, - NULL); - } - return TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - TALER_JSON_pack_amount ("total_deposited", - &pcc->deposit_total), - GNUNET_JSON_pack_timestamp ("exchange_timestamp", - pcc->exchange_timestamp), - GNUNET_JSON_pack_data_auto ("exchange_sig", - &sig), - GNUNET_JSON_pack_data_auto ("exchange_pub", - &pub)); -} - - /** * Execute database transaction for /purses/$PID/create. Runs the transaction * logic; IF it returns a non-error code, the transaction logic MUST NOT queue @@ -177,19 +117,19 @@ create_transaction (void *cls, bool in_conflict = true; GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (pcc->amount.currency, + TALER_amount_set_zero (TEH_currency, &purse_fee)); /* 1) create purse */ qs = TEH_plugin->insert_purse_request ( TEH_plugin->cls, - pcc->purse_pub, + &pcc->pd.purse_pub, &pcc->merge_pub, - pcc->purse_expiration, - &pcc->h_contract_terms, + pcc->pd.purse_expiration, + &pcc->pd.h_contract_terms, pcc->min_age, TALER_WAMF_MODE_MERGE_FULLY_PAID_PURSE, &purse_fee, - &pcc->amount, + &pcc->pd.target_amount, &pcc->purse_sig, &in_conflict); if (qs < 0) @@ -217,7 +157,7 @@ create_transaction (void *cls, TEH_plugin->rollback (TEH_plugin->cls); qs = TEH_plugin->select_purse_request (TEH_plugin->cls, - pcc->purse_pub, + &pcc->pd.purse_pub, &merge_pub, &purse_expiration, &h_contract_terms, @@ -269,7 +209,7 @@ create_transaction (void *cls, if (qs < 0) return qs; qs = TEH_plugin->do_purse_deposit (TEH_plugin->cls, - pcc->purse_pub, + &pcc->pd.purse_pub, &coin->cpi.coin_pub, &coin->amount, &coin->coin_sig, @@ -310,7 +250,7 @@ create_transaction (void *cls, TEH_plugin->rollback (TEH_plugin->cls); qs = TEH_plugin->get_purse_deposit (TEH_plugin->cls, - pcc->purse_pub, + &pcc->pd.purse_pub, &coin->cpi.coin_pub, &amount, &h_denom_pub, @@ -357,7 +297,7 @@ create_transaction (void *cls, { in_conflict = true; qs = TEH_plugin->insert_contract (TEH_plugin->cls, - pcc->purse_pub, + &pcc->pd.purse_pub, &pcc->econtract, &in_conflict); if (qs < 0) @@ -378,7 +318,7 @@ create_transaction (void *cls, qs = TEH_plugin->select_contract_by_purse ( TEH_plugin->cls, - pcc->purse_pub, + &pcc->pd.purse_pub, &econtract); if (qs <= 0) { @@ -444,7 +384,7 @@ parse_coin (struct MHD_Connection *connection, (iret = TEH_common_deposit_check_purse_deposit ( connection, coin, - pcc->purse_pub, + &pcc->pd.purse_pub, pcc->min_age))) return iret; if (0 > @@ -472,7 +412,7 @@ TEH_handler_purses_create ( const json_t *root) { struct PurseCreateContext pcc = { - .purse_pub = purse_pub, + .pd.purse_pub = *purse_pub, .exchange_timestamp = GNUNET_TIME_timestamp_get () }; json_t *deposits; @@ -481,7 +421,7 @@ TEH_handler_purses_create ( struct GNUNET_JSON_Specification spec[] = { TALER_JSON_spec_amount ("amount", TEH_currency, - &pcc.amount), + &pcc.pd.target_amount), GNUNET_JSON_spec_uint32 ("min_age", &pcc.min_age), GNUNET_JSON_spec_mark_optional ( @@ -493,11 +433,11 @@ TEH_handler_purses_create ( GNUNET_JSON_spec_fixed_auto ("purse_sig", &pcc.purse_sig), GNUNET_JSON_spec_fixed_auto ("h_contract_terms", - &pcc.h_contract_terms), + &pcc.pd.h_contract_terms), GNUNET_JSON_spec_json ("deposits", &deposits), GNUNET_JSON_spec_timestamp ("purse_expiration", - &pcc.purse_expiration), + &pcc.pd.purse_expiration), GNUNET_JSON_spec_end () }; const struct TEH_GlobalFee *gf; @@ -522,7 +462,7 @@ TEH_handler_purses_create ( GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TEH_currency, &pcc.deposit_total)); - if (GNUNET_TIME_timestamp_cmp (pcc.purse_expiration, + if (GNUNET_TIME_timestamp_cmp (pcc.pd.purse_expiration, <, pcc.exchange_timestamp)) { @@ -533,7 +473,7 @@ TEH_handler_purses_create ( TALER_EC_EXCHANGE_PURSE_CREATE_EXPIRATION_BEFORE_NOW, NULL); } - if (GNUNET_TIME_absolute_is_never (pcc.purse_expiration.abs_time)) + if (GNUNET_TIME_absolute_is_never (pcc.pd.purse_expiration.abs_time)) { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); @@ -615,12 +555,12 @@ TEH_handler_purses_create ( if (GNUNET_OK != TALER_wallet_purse_create_verify ( - pcc.purse_expiration, - &pcc.h_contract_terms, + pcc.pd.purse_expiration, + &pcc.pd.h_contract_terms, &pcc.merge_pub, pcc.min_age, - &pcc.amount, - pcc.purse_pub, + &pcc.pd.target_amount, + &pcc.pd.purse_pub, &pcc.purse_sig)) { TALER_LOG_WARNING ("Invalid signature on /purses/$PID/create request\n"); @@ -691,8 +631,10 @@ TEH_handler_purses_create ( { MHD_RESULT res; - res = reply_create_success (connection, - &pcc); + res = TEH_RESPONSE_reply_purse_created (connection, + pcc.exchange_timestamp, + &pcc.deposit_total, + &pcc.pd); for (unsigned int i = 0; iexchange_timestamp, - rpc->purse_expiration, - &rpc->amount, - &rpc->deposit_total, - &rpc->purse_pub, - &rpc->h_contract_terms, - &pub, - &sig))) - { - GNUNET_break (0); - return TALER_MHD_reply_with_ec (connection, - ec, - NULL); - } - // FIXME: share logic with /purses/$PID/create API! - return TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - TALER_JSON_pack_amount ("total_deposited", - &rpc->deposit_total), - GNUNET_JSON_pack_timestamp ("exchange_timestamp", - rpc->exchange_timestamp), - GNUNET_JSON_pack_data_auto ("exchange_sig", - &sig), - GNUNET_JSON_pack_data_auto ("exchange_pub", - &pub)); -} - - /** * Execute database transaction for /reserves/$PID/purse. Runs the transaction * logic; IF it returns a non-error code, the transaction logic MUST NOT queue @@ -207,14 +145,14 @@ purse_transaction (void *cls, /* 1) store purse */ qs = TEH_plugin->insert_purse_request ( TEH_plugin->cls, - &rpc->purse_pub, + &rpc->pd.purse_pub, &rpc->merge_pub, - rpc->purse_expiration, - &rpc->h_contract_terms, + rpc->pd.purse_expiration, + &rpc->pd.h_contract_terms, rpc->min_age, rpc->flags, &rpc->purse_fee, - &rpc->amount, + &rpc->pd.target_amount, &rpc->purse_sig, &in_conflict); if (qs < 0) @@ -245,7 +183,7 @@ purse_transaction (void *cls, TEH_plugin->rollback (TEH_plugin->cls); qs = TEH_plugin->select_purse_request ( TEH_plugin->cls, - &rpc->purse_pub, + &rpc->pd.purse_pub, &merge_pub, &purse_expiration, &h_contract_terms, @@ -299,7 +237,7 @@ purse_transaction (void *cls, rpc->flags); qs = TEH_plugin->do_reserve_purse ( TEH_plugin->cls, - &rpc->purse_pub, + &rpc->pd.purse_pub, &rpc->merge_sig, rpc->merge_timestamp, &rpc->reserve_sig, @@ -412,7 +350,7 @@ purse_transaction (void *cls, bool in_conflict = true; qs = TEH_plugin->insert_contract (TEH_plugin->cls, - &rpc->purse_pub, + &rpc->pd.purse_pub, &rpc->econtract, &in_conflict); if (qs < 0) @@ -433,7 +371,7 @@ purse_transaction (void *cls, qs = TEH_plugin->select_contract_by_purse ( TEH_plugin->cls, - &rpc->purse_pub, + &rpc->pd.purse_pub, &econtract); if (qs <= 0) { @@ -486,7 +424,7 @@ TEH_handler_reserves_purse ( struct GNUNET_JSON_Specification spec[] = { TALER_JSON_spec_amount ("purse_value", TEH_currency, - &rpc.amount), + &rpc.pd.target_amount), GNUNET_JSON_spec_uint32 ("min_age", &rpc.min_age), GNUNET_JSON_spec_mark_optional ( @@ -505,15 +443,15 @@ TEH_handler_reserves_purse ( GNUNET_JSON_spec_fixed_auto ("reserve_sig", &rpc.reserve_sig), GNUNET_JSON_spec_fixed_auto ("purse_pub", - &rpc.purse_pub), + &rpc.pd.purse_pub), GNUNET_JSON_spec_fixed_auto ("purse_sig", &rpc.purse_sig), GNUNET_JSON_spec_fixed_auto ("h_contract_terms", - &rpc.h_contract_terms), + &rpc.pd.h_contract_terms), GNUNET_JSON_spec_timestamp ("merge_timestamp", &rpc.merge_timestamp), GNUNET_JSON_spec_timestamp ("purse_expiration", - &rpc.purse_expiration), + &rpc.pd.purse_expiration), GNUNET_JSON_spec_end () }; @@ -537,7 +475,7 @@ TEH_handler_reserves_purse ( GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TEH_currency, &rpc.deposit_total)); - if (GNUNET_TIME_timestamp_cmp (rpc.purse_expiration, + if (GNUNET_TIME_timestamp_cmp (rpc.pd.purse_expiration, <, rpc.exchange_timestamp)) { @@ -548,7 +486,7 @@ TEH_handler_reserves_purse ( TALER_EC_EXCHANGE_RESERVES_PURSE_EXPIRATION_BEFORE_NOW, NULL); } - if (GNUNET_TIME_absolute_is_never (rpc.purse_expiration.abs_time)) + if (GNUNET_TIME_absolute_is_never (rpc.pd.purse_expiration.abs_time)) { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); @@ -607,12 +545,12 @@ TEH_handler_reserves_purse ( } TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; if (GNUNET_OK != - TALER_wallet_purse_create_verify (rpc.purse_expiration, - &rpc.h_contract_terms, + TALER_wallet_purse_create_verify (rpc.pd.purse_expiration, + &rpc.pd.h_contract_terms, &rpc.merge_pub, rpc.min_age, - &rpc.amount, - &rpc.purse_pub, + &rpc.pd.target_amount, + &rpc.pd.purse_pub, &rpc.purse_sig)) { GNUNET_break_op (0); @@ -626,7 +564,7 @@ TEH_handler_reserves_purse ( if (GNUNET_OK != TALER_wallet_purse_merge_verify (TEH_base_url, rpc.merge_timestamp, - &rpc.purse_pub, + &rpc.pd.purse_pub, &rpc.merge_pub, &rpc.merge_sig)) { @@ -640,10 +578,10 @@ TEH_handler_reserves_purse ( } if (GNUNET_OK != TALER_wallet_account_merge_verify (rpc.merge_timestamp, - &rpc.purse_pub, - rpc.purse_expiration, - &rpc.h_contract_terms, - &rpc.amount, + &rpc.pd.purse_pub, + rpc.pd.purse_expiration, + &rpc.pd.h_contract_terms, + &rpc.pd.target_amount, &rpc.purse_fee, rpc.min_age, rpc.flags, @@ -663,7 +601,7 @@ TEH_handler_reserves_purse ( TALER_wallet_econtract_upload_verify (rpc.econtract.econtract, rpc.econtract.econtract_size, &rpc.econtract.contract_pub, - &rpc.purse_pub, + &rpc.pd.purse_pub, &rpc.econtract.econtract_sig)) ) { TALER_LOG_WARNING ("Invalid signature on /reserves/$PID/purse request\n"); @@ -707,8 +645,10 @@ TEH_handler_reserves_purse ( { MHD_RESULT res; - res = reply_purse_success (connection, - &rpc); + res = TEH_RESPONSE_reply_purse_created (connection, + rpc.exchange_timestamp, + &rpc.deposit_total, + &rpc.pd); GNUNET_JSON_parse_free (spec); return res; } diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c index c33cdfc19..bcdc14ece 100644 --- a/src/exchange/taler-exchange-httpd_responses.c +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -937,4 +937,46 @@ TEH_RESPONSE_reply_reserve_insufficient_balance ( } +MHD_RESULT +TEH_RESPONSE_reply_purse_created ( + struct MHD_Connection *connection, + struct GNUNET_TIME_Timestamp exchange_timestamp, + const struct TALER_Amount *purse_balance, + const struct TEH_PurseDetails *pd) +{ + struct TALER_ExchangePublicKeyP pub; + struct TALER_ExchangeSignatureP sig; + enum TALER_ErrorCode ec; + + if (TALER_EC_NONE != + (ec = TALER_exchange_online_purse_created_sign ( + &TEH_keys_exchange_sign_, + exchange_timestamp, + pd->purse_expiration, + &pd->target_amount, + purse_balance, + &pd->purse_pub, + &pd->h_contract_terms, + &pub, + &sig))) + { + GNUNET_break (0); + return TALER_MHD_reply_with_ec (connection, + ec, + NULL); + } + return TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + TALER_JSON_pack_amount ("total_deposited", + purse_balance), + GNUNET_JSON_pack_timestamp ("exchange_timestamp", + exchange_timestamp), + GNUNET_JSON_pack_data_auto ("exchange_sig", + &sig), + GNUNET_JSON_pack_data_auto ("exchange_pub", + &pub)); +} + + /* end of taler-exchange-httpd_responses.c */ diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h index dde4c2c87..6cd672414 100644 --- a/src/exchange/taler-exchange-httpd_responses.h +++ b/src/exchange/taler-exchange-httpd_responses.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2019 Taler Systems SA + Copyright (C) 2014-2022 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -124,6 +124,50 @@ TEH_RESPONSE_reply_coin_insufficient_funds ( const struct TALER_DenominationHashP *h_denom_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub); +/** + * Fundamental details about a purse. + */ +struct TEH_PurseDetails +{ + /** + * When should the purse expire. + */ + struct GNUNET_TIME_Timestamp purse_expiration; + + /** + * Hash of the contract terms of the purse. + */ + struct TALER_PrivateContractHashP h_contract_terms; + + /** + * Public key of the purse we are creating. + */ + struct TALER_PurseContractPublicKeyP purse_pub; + + /** + * Total amount to be put into the purse. + */ + struct TALER_Amount target_amount; +}; + + +/** + * Send confirmation that a purse was created with + * the current purse balance. + * + * @param connection connection to the client + * @param pd purse details + * @param exchange_timestamp our time for purse creation + * @param purse_balance current balance in the purse + * @return MHD result code + */ +MHD_RESULT +TEH_RESPONSE_reply_purse_created ( + struct MHD_Connection *connection, + struct GNUNET_TIME_Timestamp exchange_timestamp, + const struct TALER_Amount *purse_balance, + const struct TEH_PurseDetails *pd); + /** * Compile the transaction history of a coin into a JSON object. -- cgit v1.2.3