merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit f21840abff90b109388882d3c361da54ae9e0e87
parent 582b2d9009839a5220517b2070708f7d4e77374b
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun,  2 Feb 2025 15:29:51 +0100

addess refactoring FIXME, remove some dead code

Diffstat:
Msrc/backend/taler-merchant-httpd_post-orders-ID-pay.c | 902+++++++++++++++++++++++++++++++++++++++++--------------------------------------
1 file changed, 470 insertions(+), 432 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2014-2024 Taler Systems SA + (C) 2014-2025 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 @@ -89,7 +89,7 @@ enum PayPhase /** * Initial phase where the request is parsed. */ - PP_INIT = 0, + PP_PARSE_PAY = 0, /** * Parse wallet data object from the pay request. @@ -365,8 +365,6 @@ struct ExchangeGroup */ struct PayContext { - // FIXME: group more entries by phase that initializes them, - // like we do for 'validate_tokens'. /** * Stored in a DLL. @@ -379,117 +377,171 @@ struct PayContext struct PayContext *prev; /** - * Array with @e num_exchange exchanges we are depositing - * coins into. + * MHD connection to return to */ - struct ExchangeGroup **egs; + struct MHD_Connection *connection; /** - * Array with @e coins_cnt coins we are despositing. + * Details about the client's request. */ - struct DepositConfirmation *dc; + struct TMH_HandlerContext *hc; /** - * Array with @e tokens_cnt input tokens passed to this request. + * Transaction ID given in @e root. */ - struct TokenUseConfirmation *tokens; + const char *order_id; /** - * Array with @e output_tokens_cnt signed tokens returned in - * the response to the wallet. + * Response to return, NULL if we don't have one yet. */ - struct SignedOutputToken *output_tokens; + struct MHD_Response *response; /** - * Array with @e token_envelopes_cnt (blinded) token envelopes. + * HTTP status code to use for the reply, i.e 200 for "OK". + * Special value UINT_MAX is used to indicate hard errors + * (no reply, return #MHD_NO). */ - struct TokenEnvelope *token_envelopes; + unsigned int response_code; /** - * MHD connection to return to + * Payment processing phase we are in. */ - struct MHD_Connection *connection; + enum PayPhase phase; /** - * Details about the client's request. + * #GNUNET_NO if the @e connection was not suspended, + * #GNUNET_YES if the @e connection was suspended, + * #GNUNET_SYSERR if @e connection was resumed to as + * part of #MH_force_pc_resume during shutdown. */ - struct TMH_HandlerContext *hc; + enum GNUNET_GenericReturnValue suspended; /** - * What wire method (of the @e mi) was selected by the wallet? - * Set in #phase_parse_pay(). + * Results from the phase_parse_pay() */ - struct TMH_WireMethod *wm; + struct + { - /** - * Task called when the (suspended) processing for - * the /pay request times out. - * Happens when we don't get a response from the exchange. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; + /** + * Array with @e num_exchanges exchanges we are depositing + * coins into. + */ + struct ExchangeGroup **egs; - /** - * Response to return, NULL if we don't have one yet. - */ - struct MHD_Response *response; + /** + * Array with @e coins_cnt coins we are despositing. + */ + struct DepositConfirmation *dc; - /** - * Index of selected choice in the @e contract_terms choices array. - */ - int64_t choice_index; + /** + * Array with @e tokens_cnt input tokens passed to this request. + */ + struct TokenUseConfirmation *tokens; - /** - * Our contract (or NULL if not available). - */ - json_t *contract_terms_json; + /** + * Optional session id given in @e root. + * NULL if not given. + */ + char *session_id; + /** + * Wallet data json object from the request. Containing additional + * wallet data such as the selected choice_index. + */ + const json_t *wallet_data; - /** - * Parsed contract terms, NULL when parsing failed. - */ - struct TALER_MERCHANT_Contract *contract_terms; + /** + * Number of coins this payment is made of. Length + * of the @e dc array. + */ + size_t coins_cnt; - /** - * Wallet data json object from the request. Containing additional - * wallet data such as the selected choice_index. - */ - const json_t *wallet_data; + /** + * Number of input tokens passed to this request. Length + * of the @e tokens array. + */ + size_t tokens_cnt; - /** - * Hash of the canonicalized wallet data json object. - */ - struct GNUNET_HashCode h_wallet_data; + /** + * Number of exchanges involved in the payment. Length + * of the @e eg array. + */ + unsigned int num_exchanges; - /** - * Output commitment hash calculated from the 'tokens_evs' field of the request. - */ - struct GNUNET_HashCode h_outputs; + } parse_pay; /** - * Placeholder for #TALER_MHD_parse_post_json() to keep its internal state. + * Results from the phase_wallet_data() */ - void *json_parse_context; + struct + { - /** - * Optional session id given in @e root. - * NULL if not given. - */ - char *session_id; + /** + * Array with @e token_envelopes_cnt (blinded) token envelopes. + */ + struct TokenEnvelope *token_envelopes; - /** - * Transaction ID given in @e root. - */ - const char *order_id; + /** + * Index of selected choice in the @e contract_terms choices array. + */ + int64_t choice_index; - /** - * Serial number of this order in the database (set once we did the lookup). - */ - uint64_t order_serial; + /** + * Number of token envelopes passed to this request. + * Length of the @e token_envelopes array. + */ + size_t token_envelopes_cnt; + + /** + * Hash of the canonicalized wallet data json object. + */ + struct GNUNET_HashCode h_wallet_data; + + } parse_wallet_data; /** - * Hashed proposal. + * Results from the phase_check_contract() */ - struct TALER_PrivateContractHashP h_contract_terms; + struct + { + + /** + * Hashed @e contract_terms. + */ + struct TALER_PrivateContractHashP h_contract_terms; + + /** + * Our contract (or NULL if not available). + */ + json_t *contract_terms_json; + + /** + * Parsed contract terms, NULL when parsing failed. + */ + struct TALER_MERCHANT_Contract *contract_terms; + + /** + * What wire method (of the @e mi) was selected by the wallet? + * Set in #phase_parse_pay(). + */ + struct TMH_WireMethod *wm; + + /** + * Set to the POS key, if applicable for this order. + */ + char *pos_key; + + /** + * Serial number of this order in the database (set once we did the lookup). + */ + uint64_t order_serial; + + /** + * Algorithm chosen for generating the confirmation code. + */ + enum TALER_MerchantConfirmationAlgorithm pos_alg; + + } check_contract; /** * Results from the phase_validate_tokens() @@ -512,119 +564,95 @@ struct PayContext */ struct TALER_Amount brutto; - } validate_tokens; - - /** - * Considering all the coins with the "found_in_db" flag - * set, what is the total amount we were so far paid on - * this contract? - */ - struct TALER_Amount total_paid; - - /** - * Considering all the coins with the "found_in_db" flag - * set, what is the total amount we had to pay in deposit - * fees so far on this contract? - */ - struct TALER_Amount total_fees_paid; + /** + * Array with @e output_tokens_len signed tokens returned in + * the response to the wallet. + */ + struct SignedOutputToken *output_tokens; - /** - * Considering all the coins with the "found_in_db" flag - * set, what is the total amount we already refunded? - */ - struct TALER_Amount total_refunded; + /** + * Number of output tokens to return in the response. + * Length of the @e output_tokens array. + */ + unsigned int output_tokens_len; - /** - * Set to the POS key, if applicable for this order. - */ - char *pos_key; + } validate_tokens; /** - * Algorithm chosen for generating the confirmation code. + * Results from the phase_execute_pay_transaction() */ - enum TALER_MerchantConfirmationAlgorithm pos_alg; + struct + { - /** - * Number of coins this payment is made of. Length - * of the @e dc array. - */ - size_t coins_cnt; + /** + * Considering all the coins with the "found_in_db" flag + * set, what is the total amount we were so far paid on + * this contract? + */ + struct TALER_Amount total_paid; - /** - * Number of input tokens passed to this request. Length - * of the @e tokens array. - */ - size_t tokens_cnt; + /** + * Considering all the coins with the "found_in_db" flag + * set, what is the total amount we had to pay in deposit + * fees so far on this contract? + */ + struct TALER_Amount total_fees_paid; - /** - * Number of token envelopes passed to this request. - * Length of the @e token_envelopes array. - */ - size_t token_envelopes_cnt; + /** + * Considering all the coins with the "found_in_db" flag + * set, what is the total amount we already refunded? + */ + struct TALER_Amount total_refunded; - /** - * Number of output tokens to return in the response. - * Length of the @e output_tokens array. - */ - unsigned int output_tokens_len; + /** + * Number of coin deposits pending. + */ + unsigned int pending; - /** - * Number of exchanges involved in the payment. Length - * of the @e eg array. - */ - unsigned int num_exchanges; + /** + * How often have we retried the 'main' transaction? + */ + unsigned int retry_counter; - /** - * How often have we retried the 'main' transaction? - */ - unsigned int retry_counter; + /** + * Set to true if the deposit currency of a coin + * does not match the contract currency. + */ + bool deposit_currency_mismatch; - /** - * Number of batch transactions pending. - */ - unsigned int pending_at_eg; + /** + * Set to true if the database contains a (bogus) + * refund for a different currency. + */ + bool refund_currency_mismatch; - /** - * Number of coin deposits pending. - */ - unsigned int pending; + } pay_transaction; /** - * HTTP status code to use for the reply, i.e 200 for "OK". - * Special value UINT_MAX is used to indicate hard errors - * (no reply, return #MHD_NO). + * Results from the phase_batch_deposits() */ - unsigned int response_code; + struct + { - /** - * Payment processing phase we are in. - */ - enum PayPhase phase; + /** + * Task called when the (suspended) processing for + * the /pay request times out. + * Happens when we don't get a response from the exchange. + */ + struct GNUNET_SCHEDULER_Task *timeout_task; - /** - * #GNUNET_NO if the @e connection was not suspended, - * #GNUNET_YES if the @e connection was suspended, - * #GNUNET_SYSERR if @e connection was resumed to as - * part of #MH_force_pc_resume during shutdown. - */ - enum GNUNET_GenericReturnValue suspended; + /** + * Number of batch transactions pending. + */ + unsigned int pending_at_eg; - /** - * Set to true if the deposit currency of a coin - * does not match the contract currency. - */ - bool deposit_currency_mismatch; + /** + * Did any exchange deny a deposit for legal reasons? + */ + bool got_451; - /** - * Set to true if the database contains a (bogus) - * refund for a different currency. - */ - bool refund_currency_mismatch; + } batch_deposits; - /** - * Did any exchange deny a deposit for legal reasons? - */ - bool got_451; }; @@ -646,10 +674,10 @@ TMH_force_pc_resume () NULL != pc; pc = pc->next) { - if (NULL != pc->timeout_task) + if (NULL != pc->batch_deposits.timeout_task) { - GNUNET_SCHEDULER_cancel (pc->timeout_task); - pc->timeout_task = NULL; + GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task); + pc->batch_deposits.timeout_task = NULL; } if (GNUNET_YES == pc->suspended) { @@ -694,28 +722,28 @@ resume_pay_with_response (struct PayContext *pc, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Resuming /pay handling. HTTP status for our reply is %u.\n", response_code); - for (unsigned int i = 0; i<pc->num_exchanges; i++) + for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) { - struct ExchangeGroup *eg = pc->egs[i]; + struct ExchangeGroup *eg = pc->parse_pay.egs[i]; if (NULL != eg->fo) { TMH_EXCHANGES_keys4exchange_cancel (eg->fo); eg->fo = NULL; - pc->pending_at_eg--; + pc->batch_deposits.pending_at_eg--; } if (NULL != eg->bdh) { TALER_EXCHANGE_batch_deposit_cancel (eg->bdh); eg->bdh = NULL; - pc->pending_at_eg--; + pc->batch_deposits.pending_at_eg--; } } - GNUNET_assert (0 == pc->pending_at_eg); - if (NULL != pc->timeout_task) + GNUNET_assert (0 == pc->batch_deposits.pending_at_eg); + if (NULL != pc->batch_deposits.timeout_task) { - GNUNET_SCHEDULER_cancel (pc->timeout_task); - pc->timeout_task = NULL; + GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task); + pc->batch_deposits.timeout_task = NULL; } pc->phase = PP_RETURN_RESPONSE; pay_resume (pc); @@ -793,13 +821,13 @@ phase_fail_for_legal_reasons (struct PayContext *pc) { json_t *exchanges; - GNUNET_assert (0 == pc->pending); - GNUNET_assert (pc->got_451); + GNUNET_assert (0 == pc->pay_transaction.pending); + GNUNET_assert (pc->batch_deposits.got_451); exchanges = json_array (); GNUNET_assert (NULL != exchanges); - for (unsigned int i = 0; i<pc->num_exchanges; i++) + for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) { - struct ExchangeGroup *eg = pc->egs[i]; + struct ExchangeGroup *eg = pc->parse_pay.egs[i]; GNUNET_assert (NULL == eg->fo); GNUNET_assert (NULL == eg->bdh); @@ -840,9 +868,9 @@ batch_deposit_transaction (const struct ExchangeGroup *eg, GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (pc->validate_tokens.brutto.currency, &total_without_fees)); - for (size_t i = 0; i<pc->coins_cnt; i++) + for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) { - struct DepositConfirmation *dc = &pc->dc[i]; + struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; struct TALER_Amount amount_without_fees; /* might want to group deposits by batch more explicitly ... */ @@ -864,21 +892,21 @@ batch_deposit_transaction (const struct ExchangeGroup *eg, TMH_db->cls, pc->hc->instance->settings.id, dr->details.ok.deposit_timestamp, - &pc->h_contract_terms, + &pc->check_contract.h_contract_terms, eg->exchange_url, - pc->contract_terms->wire_deadline, + pc->check_contract.contract_terms->wire_deadline, &total_without_fees, &eg->wire_fee, - &pc->wm->h_wire, + &pc->check_contract.wm->h_wire, dr->details.ok.exchange_sig, dr->details.ok.exchange_pub, &b_dep_serial); if (qs <= 0) return qs; /* Entire batch already known or failure, we're done */ - for (size_t i = 0; i<pc->coins_cnt; i++) + for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) { - struct DepositConfirmation *dc = &pc->dc[i]; + struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; /* might want to group deposits by batch more explicitly ... */ if (0 != strcmp (eg->exchange_url, @@ -927,7 +955,7 @@ handle_batch_deposit_ok (struct ExchangeGroup *eg, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing successful payment %s (%s) at instance `%s'\n", pc->hc->infix, - GNUNET_h2s (&pc->h_contract_terms.hash), + GNUNET_h2s (&pc->check_contract.h_contract_terms.hash), pc->hc->instance->settings.id); for (unsigned int r = 0; r<MAX_RETRIES; r++) { @@ -983,17 +1011,17 @@ handle_batch_deposit_ok (struct ExchangeGroup *eg, } /* Transaction is done, mark affected coins as complete as well. */ - for (size_t i = 0; i<pc->coins_cnt; i++) + for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) { - struct DepositConfirmation *dc = &pc->dc[i]; + struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; if (0 != strcmp (eg->exchange_url, - pc->dc[i].exchange_url)) + pc->parse_pay.dc[i].exchange_url)) continue; if (dc->found_in_db) continue; dc->found_in_db = true; /* well, at least NOW it'd be true ;-) */ - pc->pending--; + pc->pay_transaction.pending--; } } @@ -1016,8 +1044,8 @@ notify_kyc_required (const struct ExchangeGroup *eg) char *extra; hws = GNUNET_STRINGS_data_to_string_alloc ( - &eg->pc->contract_terms->h_wire, - sizeof (eg->pc->contract_terms->h_wire)); + &eg->pc->check_contract.contract_terms->h_wire, + sizeof (eg->pc->check_contract.contract_terms->h_wire)); GNUNET_asprintf (&extra, "%s %s", hws, @@ -1046,7 +1074,7 @@ batch_deposit_cb ( struct PayContext *pc = eg->pc; eg->bdh = NULL; - pc->pending_at_eg--; + pc->batch_deposits.pending_at_eg--; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Batch deposit completed with status %u\n", dr->hr.http_status); @@ -1056,7 +1084,7 @@ batch_deposit_cb ( case MHD_HTTP_OK: handle_batch_deposit_ok (eg, dr); - if (0 == pc->pending_at_eg) + if (0 == pc->batch_deposits.pending_at_eg) { pc->phase = PP_PAY_TRANSACTION; pay_resume (pc); @@ -1065,20 +1093,20 @@ batch_deposit_cb ( case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: notify_kyc_required (eg); eg->got_451 = true; - pc->got_451 = true; - /* update pc->pending */ - for (size_t i = 0; i<pc->coins_cnt; i++) + pc->batch_deposits.got_451 = true; + /* update pc->pay_transaction.pending */ + for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) { - struct DepositConfirmation *dc = &pc->dc[i]; + struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; if (0 != strcmp (eg->exchange_url, - pc->dc[i].exchange_url)) + pc->parse_pay.dc[i].exchange_url)) continue; if (dc->found_in_db) continue; - pc->pending--; + pc->pay_transaction.pending--; } - if (0 == pc->pending_at_eg) + if (0 == pc->batch_deposits.pending_at_eg) { pc->phase = PP_PAY_TRANSACTION; pay_resume (pc); @@ -1172,7 +1200,7 @@ process_pay_with_keys ( struct TALER_Amount max_amount; eg->fo = NULL; - pc->pending_at_eg--; + pc->batch_deposits.pending_at_eg--; GNUNET_SCHEDULER_begin_async_scope (&hc->async_scope_id); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Processing payment with exchange %s\n", @@ -1204,7 +1232,7 @@ process_pay_with_keys ( TMH_exchange_check_debit ( pc->hc->instance->settings.id, exchange, - pc->wm, + pc->check_contract.wm, &max_amount)) { if (eg->tried_force_keys) @@ -1234,7 +1262,7 @@ process_pay_with_keys ( if (GNUNET_OK != TMH_EXCHANGES_lookup_wire_fee (exchange, - pc->wm->wire_method, + pc->check_contract.wm->wire_method, &eg->wire_fee)) { if (eg->tried_force_keys) @@ -1243,7 +1271,7 @@ process_pay_with_keys ( resume_pay_with_error ( pc, TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED, - pc->wm->wire_method); + pc->check_contract.wm->wire_method); return; } force_keys (eg); @@ -1256,14 +1284,14 @@ process_pay_with_keys ( /* Initiate /batch-deposit operation for all coins of the current exchange (!) */ group_size = 0; - for (size_t i = 0; i<pc->coins_cnt; i++) + for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) { - struct DepositConfirmation *dc = &pc->dc[i]; + struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; const struct TALER_EXCHANGE_DenomPublicKey *denom_details; bool is_age_restricted_denom = false; if (0 != strcmp (eg->exchange_url, - pc->dc[i].exchange_url)) + pc->parse_pay.dc[i].exchange_url)) continue; if (dc->found_in_db) continue; @@ -1318,7 +1346,7 @@ process_pay_with_keys ( is_age_restricted_denom = (0 != denom_details->key.age_mask.bits); if (is_age_restricted_denom && - (0 < pc->contract_terms->minimum_age)) + (0 < pc->check_contract.contract_terms->minimum_age)) { /* Minimum age given and restricted coin provided: We need to verify the * minimum age */ @@ -1342,7 +1370,7 @@ process_pay_with_keys ( if (GNUNET_OK != TALER_age_commitment_verify ( &dc->age_commitment, - pc->contract_terms->minimum_age, + pc->check_contract.contract_terms->minimum_age, &dc->minimum_age_sig)) code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_VERIFICATION_FAILED; AGE_FAIL: @@ -1392,8 +1420,8 @@ AGE_FAIL: GNUNET_break (0); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Group size zero, %u batch transactions remain pending\n", - pc->pending_at_eg); - if (0 == pc->pending_at_eg) + pc->batch_deposits.pending_at_eg); + if (0 == pc->batch_deposits.pending_at_eg) { pc->phase = PP_PAY_TRANSACTION; pay_resume (pc); @@ -1405,24 +1433,24 @@ AGE_FAIL: { struct TALER_EXCHANGE_CoinDepositDetail cdds[group_size]; struct TALER_EXCHANGE_DepositContractDetail dcd = { - .wire_deadline = pc->contract_terms->wire_deadline, - .merchant_payto_uri = pc->wm->payto_uri, - .wire_salt = pc->wm->wire_salt, - .h_contract_terms = pc->h_contract_terms, - .wallet_data_hash = pc->h_wallet_data, - .wallet_timestamp = pc->contract_terms->timestamp, + .wire_deadline = pc->check_contract.contract_terms->wire_deadline, + .merchant_payto_uri = pc->check_contract.wm->payto_uri, + .wire_salt = pc->check_contract.wm->wire_salt, + .h_contract_terms = pc->check_contract.h_contract_terms, + .wallet_data_hash = pc->parse_wallet_data.h_wallet_data, + .wallet_timestamp = pc->check_contract.contract_terms->timestamp, .merchant_pub = hc->instance->merchant_pub, - .refund_deadline = pc->contract_terms->refund_deadline + .refund_deadline = pc->check_contract.contract_terms->refund_deadline }; enum TALER_ErrorCode ec; size_t off = 0; - TALER_merchant_contract_sign (&pc->h_contract_terms, + TALER_merchant_contract_sign (&pc->check_contract.h_contract_terms, &pc->hc->instance->merchant_priv, &dcd.merchant_sig); - for (size_t i = 0; i<pc->coins_cnt; i++) + for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) { - struct DepositConfirmation *dc = &pc->dc[i]; + struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; if (dc->found_in_db) continue; @@ -1435,6 +1463,8 @@ AGE_FAIL: GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Initiating batch deposit with %u coins\n", group_size); + /* Note: the coin signatures over the wallet_data_hash are + checked inside of this call */ eg->bdh = TALER_EXCHANGE_batch_deposit ( TMH_curl_ctx, eg->exchange_url, @@ -1460,7 +1490,7 @@ AGE_FAIL: eg->exchange_url))); return; } - pc->pending_at_eg++; + pc->batch_deposits.pending_at_eg++; if (TMH_force_audit) TALER_EXCHANGE_batch_deposit_force_dc (eg->bdh); } @@ -1488,7 +1518,7 @@ force_keys (struct ExchangeGroup *eg) eg->exchange_url); return; } - pc->pending_at_eg++; + pc->batch_deposits.pending_at_eg++; } @@ -1502,7 +1532,7 @@ handle_pay_timeout (void *cls) { struct PayContext *pc = cls; - pc->timeout_task = NULL; + pc->batch_deposits.timeout_task = NULL; GNUNET_assert (GNUNET_YES == pc->suspended); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Resuming pay with error after timeout\n"); @@ -1544,17 +1574,17 @@ get_pay_timeout (unsigned int num_coins) static void phase_batch_deposits (struct PayContext *pc) { - for (unsigned int i = 0; i<pc->num_exchanges; i++) + for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) { - struct ExchangeGroup *eg = pc->egs[i]; + struct ExchangeGroup *eg = pc->parse_pay.egs[i]; bool have_coins = false; - for (size_t j = 0; j<pc->coins_cnt; j++) + for (size_t j = 0; j<pc->parse_pay.coins_cnt; j++) { - struct DepositConfirmation *dc = &pc->dc[j]; + struct DepositConfirmation *dc = &pc->parse_pay.dc[j]; if (0 != strcmp (eg->exchange_url, - pc->dc[j].exchange_url)) + dc->exchange_url)) continue; if (dc->found_in_db) continue; @@ -1582,9 +1612,9 @@ phase_batch_deposits (struct PayContext *pc) eg->exchange_url)); return; } - pc->pending_at_eg++; + pc->batch_deposits.pending_at_eg++; } - if (0 == pc->pending_at_eg) + if (0 == pc->batch_deposits.pending_at_eg) { pc->phase = PP_PAY_TRANSACTION; pay_resume (pc); @@ -1593,9 +1623,9 @@ phase_batch_deposits (struct PayContext *pc) /* Suspend while we interact with the exchange */ MHD_suspend_connection (pc->connection); pc->suspended = GNUNET_YES; - GNUNET_assert (NULL == pc->timeout_task); - pc->timeout_task - = GNUNET_SCHEDULER_add_delayed (get_pay_timeout (pc->coins_cnt), + GNUNET_assert (NULL == pc->batch_deposits.timeout_task); + pc->batch_deposits.timeout_task + = GNUNET_SCHEDULER_add_delayed (get_pay_timeout (pc->parse_pay.coins_cnt), &handle_pay_timeout, pc); } @@ -1613,7 +1643,7 @@ build_token_sigs (struct PayContext *pc) json_t *token_sigs = json_array (); GNUNET_assert (NULL != token_sigs); - for (unsigned int i = 0; i < pc->output_tokens_len; i++) + for (unsigned int i = 0; i < pc->validate_tokens.output_tokens_len; i++) { GNUNET_assert (0 == json_array_append_new ( @@ -1621,7 +1651,7 @@ build_token_sigs (struct PayContext *pc) GNUNET_JSON_PACK ( GNUNET_JSON_pack_blinded_sig ( "blind_sig", - pc->output_tokens[i].sig.signature) + pc->validate_tokens.output_tokens[i].sig.signature) ))); } return token_sigs; @@ -1642,17 +1672,18 @@ phase_success_response (struct PayContext *pc) /* Sign on our end (as the payment did go through, even if it may have been refunded already) */ - TALER_merchant_pay_sign (&pc->h_contract_terms, + TALER_merchant_pay_sign (&pc->check_contract.h_contract_terms, &pc->hc->instance->merchant_priv, &sig); /* Build the response */ - pos_confirmation = (NULL == pc->pos_key) + pos_confirmation = (NULL == pc->check_contract.pos_key) ? NULL - : TALER_build_pos_confirmation (pc->pos_key, - pc->pos_alg, + : TALER_build_pos_confirmation (pc->check_contract.pos_key, + pc->check_contract.pos_alg, &pc->validate_tokens.brutto, - pc->contract_terms->timestamp); - token_sigs = (0 >= pc->output_tokens_len) + pc->check_contract.contract_terms->timestamp + ); + token_sigs = (0 >= pc->validate_tokens.output_tokens_len) ? NULL : build_token_sigs (pc); pay_end (pc, @@ -1698,8 +1729,8 @@ phase_payment_notification (struct PayContext *pc) NULL, 0); } - if ( (NULL != pc->session_id) && - (NULL != pc->contract_terms->fulfillment_url) ) + if ( (NULL != pc->parse_pay.session_id) && + (NULL != pc->check_contract.contract_terms->fulfillment_url) ) { struct TMH_SessionEventP session_eh = { .header.size = htons (sizeof (session_eh)), @@ -1709,13 +1740,14 @@ phase_payment_notification (struct PayContext *pc) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Notifying clients about session change to %s for %s\n", - pc->session_id, - pc->contract_terms->fulfillment_url); - GNUNET_CRYPTO_hash (pc->session_id, - strlen (pc->session_id), + pc->parse_pay.session_id, + pc->check_contract.contract_terms->fulfillment_url); + GNUNET_CRYPTO_hash (pc->parse_pay.session_id, + strlen (pc->parse_pay.session_id), &session_eh.h_session_id); - GNUNET_CRYPTO_hash (pc->contract_terms->fulfillment_url, - strlen (pc->contract_terms->fulfillment_url), + GNUNET_CRYPTO_hash (pc->check_contract.contract_terms->fulfillment_url, + strlen (pc->check_contract.contract_terms-> + fulfillment_url), &session_eh.h_fulfillment_url); TMH_db->event_notify (TMH_db->cls, &session_eh.header, @@ -1746,9 +1778,9 @@ check_coin_paid (void *cls, { struct PayContext *pc = cls; - for (size_t i = 0; i<pc->coins_cnt; i++) + for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) { - struct DepositConfirmation *dc = &pc->dc[i]; + struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; if (dc->found_in_db) continue; /* processed earlier, skip "expensive" memcmp() */ @@ -1768,29 +1800,29 @@ check_coin_paid (void *cls, "Deposit of coin `%s' already in our DB.\n", TALER_B2S (coin_pub)); if ( (GNUNET_OK != - TALER_amount_cmp_currency (&pc->total_paid, + TALER_amount_cmp_currency (&pc->pay_transaction.total_paid, amount_with_fee)) || (GNUNET_OK != - TALER_amount_cmp_currency (&pc->total_fees_paid, + TALER_amount_cmp_currency (&pc->pay_transaction.total_fees_paid, deposit_fee)) ) { GNUNET_break_op (0); - pc->deposit_currency_mismatch = true; + pc->pay_transaction.deposit_currency_mismatch = true; break; } GNUNET_assert (0 <= - TALER_amount_add (&pc->total_paid, - &pc->total_paid, + TALER_amount_add (&pc->pay_transaction.total_paid, + &pc->pay_transaction.total_paid, amount_with_fee)); GNUNET_assert (0 <= - TALER_amount_add (&pc->total_fees_paid, - &pc->total_fees_paid, + TALER_amount_add (&pc->pay_transaction.total_fees_paid, + &pc->pay_transaction.total_fees_paid, deposit_fee)); dc->deposit_fee = *deposit_fee; dc->refund_fee = *refund_fee; dc->cdd.amount = *amount_with_fee; dc->found_in_db = true; - pc->pending--; + pc->pay_transaction.pending--; } } @@ -1820,25 +1852,25 @@ check_coin_refunded (void *cls, an abort-pay refund (an unusual but possible case), we need to make sure that existing refunds are accounted for. */ - for (size_t i = 0; i<pc->coins_cnt; i++) + for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) { - struct DepositConfirmation *dc = &pc->dc[i]; + struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; /* Get matching coins from results. */ if (0 != GNUNET_memcmp (coin_pub, &dc->cdd.coin_pub)) continue; if (GNUNET_OK != - TALER_amount_cmp_currency (&pc->total_refunded, + TALER_amount_cmp_currency (&pc->pay_transaction.total_refunded, refund_amount)) { GNUNET_break (0); - pc->refund_currency_mismatch = true; + pc->pay_transaction.refund_currency_mismatch = true; break; } GNUNET_assert (0 <= - TALER_amount_add (&pc->total_refunded, - &pc->total_refunded, + TALER_amount_add (&pc->pay_transaction.total_refunded, + &pc->pay_transaction.total_refunded, refund_amount)); break; } @@ -1861,16 +1893,16 @@ check_payment_sufficient (struct PayContext *pc) struct TALER_Amount total_wire_fee; struct TALER_Amount total_needed; - if (0 == pc->coins_cnt) + if (0 == pc->parse_pay.coins_cnt) return TALER_amount_is_zero (&pc->validate_tokens.brutto); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (pc->validate_tokens.brutto.currency, &total_wire_fee)); - for (unsigned int i = 0; i < pc->num_exchanges; i++) + for (unsigned int i = 0; i < pc->parse_pay.num_exchanges; i++) { if (GNUNET_OK != TALER_amount_cmp_currency (&total_wire_fee, - &pc->egs[i]->wire_fee)) + &pc->parse_pay.egs[i]->wire_fee)) { GNUNET_break_op (0); pay_end (pc, @@ -1883,7 +1915,7 @@ check_payment_sufficient (struct PayContext *pc) if (0 > TALER_amount_add (&total_wire_fee, &total_wire_fee, - &pc->egs[i]->wire_fee)) + &pc->parse_pay.egs[i]->wire_fee)) { GNUNET_break (0); pay_end (pc, @@ -1906,9 +1938,9 @@ check_payment_sufficient (struct PayContext *pc) GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (pc->validate_tokens.brutto.currency, &acc_amount)); - for (size_t i = 0; i<pc->coins_cnt; i++) + for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) { - struct DepositConfirmation *dc = &pc->dc[i]; + struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; GNUNET_assert (dc->found_in_db); if ( (GNUNET_OK != @@ -1975,7 +2007,7 @@ check_payment_sufficient (struct PayContext *pc) TALER_amount2s (&pc->validate_tokens.max_fee)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Total refunded amount: %s\n", - TALER_amount2s (&pc->total_refunded)); + TALER_amount2s (&pc->pay_transaction.total_refunded)); /* Now compare exchange wire fee compared to * what we are willing to pay */ @@ -2049,11 +2081,11 @@ check_payment_sufficient (struct PayContext *pc) /* Do not count refunds towards the payment */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Subtracting total refunds from paid amount: %s\n", - TALER_amount2s (&pc->total_refunded)); + TALER_amount2s (&pc->pay_transaction.total_refunded)); if (0 > TALER_amount_subtract (&final_amount, &acc_amount, - &pc->total_refunded)) + &pc->pay_transaction.total_refunded)) { GNUNET_break (0); pay_end (pc, @@ -2119,13 +2151,13 @@ phase_execute_pay_transaction (struct PayContext *pc) struct TMH_HandlerContext *hc = pc->hc; const char *instance_id = hc->instance->settings.id; - if (pc->got_451) + if (pc->batch_deposits.got_451) { pc->phase = PP_FAIL_LEGAL_REASONS; return; } /* Avoid re-trying transactions on soft errors forever! */ - if (pc->retry_counter++ > MAX_RETRIES) + if (pc->pay_transaction.retry_counter++ > MAX_RETRIES) { GNUNET_break (0); pay_end (pc, @@ -2141,16 +2173,16 @@ phase_execute_pay_transaction (struct PayContext *pc) and check_payment_sufficient()). */ GNUNET_break (GNUNET_OK == TALER_amount_set_zero (pc->validate_tokens.brutto.currency, - &pc->total_paid)); + &pc->pay_transaction.total_paid)); GNUNET_break (GNUNET_OK == TALER_amount_set_zero (pc->validate_tokens.brutto.currency, - &pc->total_fees_paid)); + &pc->pay_transaction.total_fees_paid)); GNUNET_break (GNUNET_OK == TALER_amount_set_zero (pc->validate_tokens.brutto.currency, - &pc->total_refunded)); - for (size_t i = 0; i<pc->coins_cnt; i++) - pc->dc[i].found_in_db = false; - pc->pending = pc->coins_cnt; + &pc->pay_transaction.total_refunded)); + for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) + pc->parse_pay.dc[i].found_in_db = false; + pc->pay_transaction.pending = pc->parse_pay.coins_cnt; /* First, try to see if we have all we need already done */ TMH_db->preflight (TMH_db->cls); @@ -2167,16 +2199,15 @@ phase_execute_pay_transaction (struct PayContext *pc) return; } - for (size_t i = 0; i<pc->tokens_cnt; i++) + for (size_t i = 0; i<pc->parse_pay.tokens_cnt; i++) { - struct TokenUseConfirmation *tuc = &pc->tokens[i]; - + struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; enum GNUNET_DB_QueryStatus qs; /* Insert used token into database, the unique constraint will case an error if this token was used before. */ qs = TMH_db->insert_spent_token (TMH_db->cls, - &pc->h_contract_terms, + &pc->check_contract.h_contract_terms, &tuc->h_issue, &tuc->pub, &tuc->sig, @@ -2215,7 +2246,7 @@ phase_execute_pay_transaction (struct PayContext *pc) /* Check if some of these coins already succeeded for _this_ contract. */ qs = TMH_db->lookup_deposits (TMH_db->cls, instance_id, - &pc->h_contract_terms, + &pc->check_contract.h_contract_terms, &check_coin_paid, pc); if (0 > qs) @@ -2232,7 +2263,7 @@ phase_execute_pay_transaction (struct PayContext *pc) "lookup deposits")); return; } - if (pc->deposit_currency_mismatch) + if (pc->pay_transaction.deposit_currency_mismatch) { TMH_db->rollback (TMH_db->cls); GNUNET_break_op (0); @@ -2252,7 +2283,7 @@ phase_execute_pay_transaction (struct PayContext *pc) /* Check if we refunded some of the coins */ qs = TMH_db->lookup_refunds (TMH_db->cls, instance_id, - &pc->h_contract_terms, + &pc->check_contract.h_contract_terms, &check_coin_refunded, pc); if (0 > qs) @@ -2269,7 +2300,7 @@ phase_execute_pay_transaction (struct PayContext *pc) "lookup refunds")); return; } - if (pc->refund_currency_mismatch) + if (pc->pay_transaction.refund_currency_mismatch) { TMH_db->rollback (TMH_db->cls); pay_end (pc, @@ -2282,7 +2313,7 @@ phase_execute_pay_transaction (struct PayContext *pc) } /* Check if there are coins that still need to be processed */ - if (0 != pc->pending) + if (0 != pc->pay_transaction.pending) { /* we made no DB changes, so we can just rollback */ TMH_db->rollback (TMH_db->cls); @@ -2293,7 +2324,7 @@ phase_execute_pay_transaction (struct PayContext *pc) return; } - /* 0 == pc->pending: all coins processed, let's see if that was enough */ + /* 0 == pc->pay_transaction.pending: all coins processed, let's see if that was enough */ if (! check_payment_sufficient (pc)) { /* check_payment_sufficient() will have queued an error already. @@ -2305,14 +2336,14 @@ phase_execute_pay_transaction (struct PayContext *pc) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Order `%s' (%s) was fully paid\n", pc->order_id, - GNUNET_h2s (&pc->h_contract_terms.hash)); + GNUNET_h2s (&pc->check_contract.h_contract_terms.hash)); { enum GNUNET_DB_QueryStatus qs; qs = TMH_db->mark_contract_paid (TMH_db->cls, instance_id, - &pc->h_contract_terms, - pc->session_id); + &pc->check_contract.h_contract_terms, + pc->parse_pay.session_id); if (qs < 0) { TMH_db->rollback (TMH_db->cls); @@ -2329,14 +2360,14 @@ phase_execute_pay_transaction (struct PayContext *pc) } /* Store signed output tokens in database. */ - for (size_t i = 0; i<pc->output_tokens_len; i++) + for (size_t i = 0; i<pc->validate_tokens.output_tokens_len; i++) { - struct SignedOutputToken *output = &pc->output_tokens[i]; + struct SignedOutputToken *output = &pc->validate_tokens.output_tokens[i]; enum GNUNET_DB_QueryStatus qs; qs = TMH_db->insert_issued_token (TMH_db->cls, - &pc->h_contract_terms, + &pc->check_contract.h_contract_terms, &output->h_issue, &output->sig); @@ -2358,15 +2389,15 @@ phase_execute_pay_transaction (struct PayContext *pc) TMH_notify_order_change (hc->instance, TMH_OSF_CLAIMED | TMH_OSF_PAID, - pc->contract_terms->timestamp, - pc->order_serial); + pc->check_contract.contract_terms->timestamp, + pc->check_contract.order_serial); { enum GNUNET_DB_QueryStatus qs; json_t *jhook; jhook = GNUNET_JSON_PACK ( GNUNET_JSON_pack_object_incref ("contract_terms", - pc->contract_terms_json), + pc->check_contract.contract_terms_json), GNUNET_JSON_pack_string ("order_id", pc->order_id) ); @@ -2436,7 +2467,7 @@ find_valid_input_tokens ( for (unsigned int j = 0; j < expected_num; j++) { - struct TokenUseConfirmation *tuc = &pc->tokens[index + j]; + struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[index + j]; const struct TALER_MERCHANT_ContractTokenFamilyKey *key = NULL; for (unsigned int i=0; i<family->keys_len; i++) @@ -2491,8 +2522,8 @@ find_valid_input_tokens ( } if (GNUNET_OK != - TALER_wallet_token_use_verify (&pc->h_contract_terms, - &pc->h_wallet_data, + TALER_wallet_token_use_verify (&pc->check_contract.h_contract_terms, + &pc->parse_wallet_data.h_wallet_data, &tuc->pub, &tuc->sig)) { @@ -2561,11 +2592,12 @@ sign_token_envelopes (struct PayContext *pc, for (unsigned int j = 0; j<expected_num; j++) { unsigned int pos = index + j; - const struct TokenEnvelope *env = &pc->token_envelopes[pos]; - struct SignedOutputToken *output = &pc->output_tokens[pos]; + const struct TokenEnvelope *env + = &pc->parse_wallet_data.token_envelopes[pos]; + struct SignedOutputToken *output = &pc->validate_tokens.output_tokens[pos]; - if ( (pos >= pc->token_envelopes_cnt) || - (pos >= pc->output_tokens_len) ) + if ( (pos >= pc->parse_wallet_data.token_envelopes_cnt) || + (pos >= pc->validate_tokens.output_tokens_len) ) { GNUNET_assert (0); /* this should not happen */ return GNUNET_NO; @@ -2627,11 +2659,11 @@ find_family (const struct PayContext *pc, const char *slug) { for (unsigned int i = 0; - i < pc->contract_terms->details.v1.token_authorities_len; + i < pc->check_contract.contract_terms->details.v1.token_authorities_len; i++) { const struct TALER_MERCHANT_ContractTokenFamily *tfi - = &pc->contract_terms->details.v1.token_authorities[i]; + = &pc->check_contract.contract_terms->details.v1.token_authorities[i]; if (0 == strcmp (tfi->slug, slug)) @@ -2658,18 +2690,21 @@ find_family (const struct PayContext *pc, static void phase_validate_tokens (struct PayContext *pc) { - switch (pc->contract_terms->version) + switch (pc->check_contract.contract_terms->version) { case TALER_MERCHANT_CONTRACT_VERSION_0: /* No tokens to validate */ pc->phase = PP_PAY_TRANSACTION; - pc->validate_tokens.max_fee = pc->contract_terms->details.v0.max_fee; - pc->validate_tokens.brutto = pc->contract_terms->details.v0.brutto; + pc->validate_tokens.max_fee + = pc->check_contract.contract_terms->details.v0.max_fee; + pc->validate_tokens.brutto + = pc->check_contract.contract_terms->details.v0.brutto; break; case TALER_MERCHANT_CONTRACT_VERSION_1: { const struct TALER_MERCHANT_ContractChoice *selected - = &pc->contract_terms->details.v1.choices[pc->choice_index]; + = &pc->check_contract.contract_terms->details.v1.choices[ + pc->parse_wallet_data.choice_index]; pc->validate_tokens.max_fee = selected->max_fee; pc->validate_tokens.brutto = selected->amount; @@ -2712,8 +2747,8 @@ phase_validate_tokens (struct PayContext *pc) } } - GNUNET_array_grow (pc->output_tokens, - pc->output_tokens_len, + GNUNET_array_grow (pc->validate_tokens.output_tokens, + pc->validate_tokens.output_tokens_len, selected->outputs_len); for (unsigned int i = 0; i<selected->outputs_len; i++) @@ -2764,8 +2799,8 @@ phase_validate_tokens (struct PayContext *pc) TMH_db->cls, pc->hc->instance->settings.id, family->slug, - pc->contract_terms->timestamp, - pc->contract_terms->pay_deadline, + pc->check_contract.contract_terms->timestamp, + pc->check_contract.contract_terms->pay_deadline, &details); if (qs <= 0) { @@ -2773,9 +2808,11 @@ phase_validate_tokens (struct PayContext *pc) GNUNET_ERROR_TYPE_ERROR, "Did not find key for %s at [%llu,%llu]\n", family->slug, - (unsigned long long) pc->contract_terms->timestamp.abs_time. + (unsigned long long) pc->check_contract.contract_terms->timestamp. + abs_time. abs_value_us, - (unsigned long long) pc->contract_terms->pay_deadline.abs_time. + (unsigned long long) pc->check_contract.contract_terms->pay_deadline + .abs_time. abs_value_us); GNUNET_break (0); pay_end (pc, @@ -2806,9 +2843,9 @@ phase_validate_tokens (struct PayContext *pc) } } - for (size_t i = 0; i<pc->coins_cnt; i++) + for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) { - const struct DepositConfirmation *dc = &pc->dc[i]; + const struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; if (GNUNET_OK != TALER_amount_cmp_currency (&dc->cdd.amount, @@ -2817,7 +2854,7 @@ phase_validate_tokens (struct PayContext *pc) GNUNET_break_op (0); fprintf (stderr, "HERE (%u): %s != %s\n", - (unsigned int) pc->contract_terms->version, + (unsigned int) pc->check_contract.contract_terms->version, dc->cdd.amount.currency, TALER_amount2s (&pc->validate_tokens.brutto)); pay_end (pc, @@ -2860,9 +2897,9 @@ deposit_paid_check ( { struct PayContext *pc = cls; - for (size_t i = 0; i<pc->coins_cnt; i++) + for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) { - struct DepositConfirmation *dci = &pc->dc[i]; + struct DepositConfirmation *dci = &pc->parse_pay.dc[i]; if ( (0 == GNUNET_memcmp (&dci->cdd.coin_pub, @@ -2896,9 +2933,9 @@ input_tokens_paid_check ( { struct PayContext *pc = cls; - for (size_t i = 0; i<pc->tokens_cnt; i++) + for (size_t i = 0; i<pc->parse_pay.tokens_cnt; i++) { - struct TokenUseConfirmation *tuc = &pc->tokens[i]; + struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; if ( (0 == GNUNET_memcmp (&tuc->pub, use_pub)) && @@ -2930,7 +2967,7 @@ phase_contract_paid (struct PayContext *pc) enum GNUNET_DB_QueryStatus qs; qs = TMH_db->lookup_deposits_by_order (TMH_db->cls, - pc->order_serial, + pc->check_contract.order_serial, &deposit_paid_check, pc); /* Since orders with choices can have a price of zero, @@ -2947,9 +2984,9 @@ phase_contract_paid (struct PayContext *pc) return; } } - for (size_t i = 0; i<pc->coins_cnt && ! unmatched; i++) + for (size_t i = 0; i<pc->parse_pay.coins_cnt && ! unmatched; i++) { - struct DepositConfirmation *dci = &pc->dc[i]; + struct DepositConfirmation *dci = &pc->parse_pay.dc[i]; if (! dci->matched_in_db) unmatched = true; @@ -2960,7 +2997,7 @@ phase_contract_paid (struct PayContext *pc) /* FIXME: Use h_contract instead of order_serial here? */ qs = TMH_db->lookup_spent_tokens_by_order (TMH_db->cls, - pc->order_serial, + pc->check_contract.order_serial, &input_tokens_paid_check, pc); @@ -2976,9 +3013,9 @@ phase_contract_paid (struct PayContext *pc) return; } } - for (size_t i = 0; i<pc->tokens_cnt && ! unmatched; i++) + for (size_t i = 0; i<pc->parse_pay.tokens_cnt && ! unmatched; i++) { - struct TokenUseConfirmation *tuc = &pc->tokens[i]; + struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; if (! tuc->found_in_db) unmatched = true; @@ -2991,7 +3028,7 @@ phase_contract_paid (struct PayContext *pc) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Idempotent pay request for order `%s', signing again\n", pc->order_id); - TALER_merchant_pay_sign (&pc->h_contract_terms, + TALER_merchant_pay_sign (&pc->check_contract.h_contract_terms, &pc->hc->instance->merchant_priv, &sig); /* FIXME: Add token_sigs to response body. */ @@ -3011,15 +3048,15 @@ phase_contract_paid (struct PayContext *pc) pc->order_id); refunds = json_array (); GNUNET_assert (NULL != refunds); - for (size_t i = 0; i<pc->coins_cnt; i++) + for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) { - struct DepositConfirmation *dci = &pc->dc[i]; + struct DepositConfirmation *dci = &pc->parse_pay.dc[i]; struct TALER_MerchantSignatureP merchant_sig; if (dci->matched_in_db) continue; TALER_merchant_refund_sign (&dci->cdd.coin_pub, - &pc->h_contract_terms, + &pc->check_contract.h_contract_terms, 0, /* rtransaction id */ &dci->cdd.amount, &pc->hc->instance->merchant_priv, @@ -3064,27 +3101,25 @@ phase_check_contract (struct PayContext *pc) enum GNUNET_DB_QueryStatus qs; bool paid = false; - if (NULL != pc->contract_terms_json) + if (NULL != pc->check_contract.contract_terms_json) { - json_decref (pc->contract_terms_json); - pc->contract_terms_json = NULL; + json_decref (pc->check_contract.contract_terms_json); + pc->check_contract.contract_terms_json = NULL; } - - if (NULL != pc->contract_terms) + if (NULL != pc->check_contract.contract_terms) { - TALER_MERCHANT_contract_free (pc->contract_terms); - pc->contract_terms = NULL; + TALER_MERCHANT_contract_free (pc->check_contract.contract_terms); + pc->check_contract.contract_terms = NULL; } - qs = TMH_db->lookup_contract_terms2 (TMH_db->cls, pc->hc->instance->settings.id, pc->order_id, - &pc->contract_terms_json, - &pc->order_serial, + &pc->check_contract.contract_terms_json, + &pc->check_contract.order_serial, &paid, NULL, - &pc->pos_key, - &pc->pos_alg); + &pc->check_contract.pos_key, + &pc->check_contract.pos_alg); if (0 > qs) { /* single, read-only SQL statements should never cause @@ -3111,12 +3146,14 @@ phase_check_contract (struct PayContext *pc) return; } /* hash contract (needed later) */ - json_dumpf (pc->contract_terms_json, +#if DEBUG + json_dumpf (pc->check_contract.contract_terms_json, stderr, JSON_INDENT (2)); +#endif if (GNUNET_OK != - TALER_JSON_contract_hash (pc->contract_terms_json, - &pc->h_contract_terms)) + TALER_JSON_contract_hash (pc->check_contract.contract_terms_json, + &pc->check_contract.h_contract_terms)) { GNUNET_break (0); pay_end (pc, @@ -3138,13 +3175,13 @@ phase_check_contract (struct PayContext *pc) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Handling payment for order `%s' with contract hash `%s'\n", pc->order_id, - GNUNET_h2s (&pc->h_contract_terms.hash)); + GNUNET_h2s (&pc->check_contract.h_contract_terms.hash)); - pc->contract_terms = TALER_MERCHANT_contract_parse ( - pc->contract_terms_json, + pc->check_contract.contract_terms = TALER_MERCHANT_contract_parse ( + pc->check_contract.contract_terms_json, true); - if (NULL == pc->contract_terms) + if (NULL == pc->check_contract.contract_terms) { /* invalid contract */ GNUNET_break (0); @@ -3159,11 +3196,11 @@ phase_check_contract (struct PayContext *pc) /* Get details from contract and check fundamentals */ { - switch (pc->contract_terms->version) + switch (pc->check_contract.contract_terms->version) { case TALER_MERCHANT_CONTRACT_VERSION_0: { - if (pc->choice_index > 0) + if (pc->parse_wallet_data.choice_index > 0) { GNUNET_break (0); pay_end (pc, @@ -3178,7 +3215,7 @@ phase_check_contract (struct PayContext *pc) break; case TALER_MERCHANT_CONTRACT_VERSION_1: { - if (pc->choice_index < 0) + if (pc->parse_wallet_data.choice_index < 0) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Order `%s' has non-empty choices array but" @@ -3193,14 +3230,15 @@ phase_check_contract (struct PayContext *pc) NULL)); return; } - if (pc->choice_index >= pc->contract_terms->details.v1.choices_len) + if (pc->parse_wallet_data.choice_index >= + pc->check_contract.contract_terms->details.v1.choices_len) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Order `%s' has choices array with %u elements but " "request has 'choice_index' field with value %ld\n", pc->order_id, - pc->contract_terms->details.v1.choices_len, - pc->choice_index); + pc->check_contract.contract_terms->details.v1.choices_len, + pc->parse_wallet_data.choice_index); GNUNET_break (0); pay_end (pc, TALER_MHD_reply_with_error ( @@ -3225,10 +3263,11 @@ phase_check_contract (struct PayContext *pc) } } - - if (GNUNET_TIME_timestamp_cmp (pc->contract_terms->wire_deadline, + if (GNUNET_TIME_timestamp_cmp (pc->check_contract.contract_terms-> + wire_deadline, <, - pc->contract_terms->refund_deadline)) + pc->check_contract.contract_terms-> + refund_deadline)) { /* This should already have been checked when creating the order! */ GNUNET_break (0); @@ -3240,7 +3279,8 @@ phase_check_contract (struct PayContext *pc) NULL)); return; } - if (GNUNET_TIME_absolute_is_past (pc->contract_terms->pay_deadline.abs_time)) + if (GNUNET_TIME_absolute_is_past (pc->check_contract.contract_terms-> + pay_deadline.abs_time)) { /* too late */ pay_end (pc, @@ -3257,7 +3297,7 @@ phase_check_contract (struct PayContext *pc) struct TMH_WireMethod *wm; wm = pc->hc->instance->wm_head; - while (0 != GNUNET_memcmp (&pc->contract_terms->h_wire, + while (0 != GNUNET_memcmp (&pc->check_contract.contract_terms->h_wire, &wm->h_wire)) wm = wm->next; if (NULL == wm) @@ -3271,7 +3311,7 @@ phase_check_contract (struct PayContext *pc) NULL)); return; } - pc->wm = wm; + pc->check_contract.wm = wm; } pc->phase = PP_VALIDATE_TOKENS; } @@ -3291,7 +3331,7 @@ phase_parse_wallet_data (struct PayContext *pc) struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_int64 ("choice_index", - &pc->choice_index), + &pc->parse_wallet_data.choice_index), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_array_const ("tokens_evs", @@ -3300,8 +3340,8 @@ phase_parse_wallet_data (struct PayContext *pc) GNUNET_JSON_spec_end () }; - pc->choice_index = -1; - if (NULL == pc->wallet_data) + pc->parse_wallet_data.choice_index = -1; + if (NULL == pc->parse_pay.wallet_data) { pc->phase = PP_CHECK_CONTRACT; return; @@ -3310,7 +3350,7 @@ phase_parse_wallet_data (struct PayContext *pc) enum GNUNET_GenericReturnValue res; res = TALER_MHD_parse_json_data (pc->connection, - pc->wallet_data, + pc->parse_pay.wallet_data, spec); if (GNUNET_YES != res) { @@ -3323,8 +3363,10 @@ phase_parse_wallet_data (struct PayContext *pc) } } - pc->token_envelopes_cnt = json_array_size (tokens_evs); - if (pc->token_envelopes_cnt > MAX_TOKEN_ALLOWED_OUTPUTs) + pc->parse_wallet_data.token_envelopes_cnt + = json_array_size (tokens_evs); + if (pc->parse_wallet_data.token_envelopes_cnt > + MAX_TOKEN_ALLOWED_OUTPUTs) { GNUNET_break_op (0); pay_end (pc, @@ -3335,15 +3377,9 @@ phase_parse_wallet_data (struct PayContext *pc) "'tokens_evs' array too long")); return; } - if (0 < pc->token_envelopes_cnt) - { - /* Calculate output commitment to be verified later. */ - TALER_json_hash (tokens_evs, - &pc->h_outputs); - } - - pc->token_envelopes = GNUNET_new_array (pc->token_envelopes_cnt, - struct TokenEnvelope); + pc->parse_wallet_data.token_envelopes + = GNUNET_new_array (pc->parse_wallet_data.token_envelopes_cnt, + struct TokenEnvelope); { unsigned int tokens_ev_index; @@ -3353,7 +3389,8 @@ phase_parse_wallet_data (struct PayContext *pc) tokens_ev_index, token_ev) { - struct TokenEnvelope *ev = &pc->token_envelopes[tokens_ev_index]; + struct TokenEnvelope *ev + = &pc->parse_wallet_data.token_envelopes[tokens_ev_index]; struct GNUNET_JSON_Specification ispec[] = { TALER_JSON_spec_token_envelope ("token_ev", &ev->blinded_token), @@ -3380,7 +3417,8 @@ phase_parse_wallet_data (struct PayContext *pc) { if (0 == GNUNET_memcmp (ev->blinded_token.blinded_pub, - pc->token_envelopes[j].blinded_token.blinded_pub)) + pc->parse_wallet_data.token_envelopes[j]. + blinded_token.blinded_pub)) { GNUNET_break_op (0); pay_end (pc, @@ -3395,8 +3433,8 @@ phase_parse_wallet_data (struct PayContext *pc) } } - TALER_json_hash (pc->wallet_data, - &pc->h_wallet_data); + TALER_json_hash (pc->parse_pay.wallet_data, + &pc->parse_wallet_data.h_wallet_data); pc->phase = PP_CHECK_CONTRACT; } @@ -3423,7 +3461,7 @@ phase_parse_pay (struct PayContext *pc) NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_object_const ("wallet_data", - &pc->wallet_data), + &pc->parse_pay.wallet_data), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_array_const ("tokens", @@ -3432,7 +3470,7 @@ phase_parse_pay (struct PayContext *pc) GNUNET_JSON_spec_end () }; - GNUNET_assert (PP_INIT == pc->phase); + GNUNET_assert (PP_PARSE_PAY == pc->phase); { enum GNUNET_GenericReturnValue res; @@ -3453,16 +3491,16 @@ phase_parse_pay (struct PayContext *pc) /* copy session ID (if set) */ if (NULL != session_id) { - pc->session_id = GNUNET_strdup (session_id); + pc->parse_pay.session_id = GNUNET_strdup (session_id); } else { /* use empty string as default if client didn't specify it */ - pc->session_id = GNUNET_strdup (""); + pc->parse_pay.session_id = GNUNET_strdup (""); } - pc->coins_cnt = json_array_size (coins); - if (pc->coins_cnt > MAX_COIN_ALLOWED_COINS) + pc->parse_pay.coins_cnt = json_array_size (coins); + if (pc->parse_pay.coins_cnt > MAX_COIN_ALLOWED_COINS) { GNUNET_break_op (0); pay_end (pc, @@ -3474,8 +3512,8 @@ phase_parse_pay (struct PayContext *pc) return; } /* note: 1 coin = 1 deposit confirmation expected */ - pc->dc = GNUNET_new_array (pc->coins_cnt, - struct DepositConfirmation); + pc->parse_pay.dc = GNUNET_new_array (pc->parse_pay.coins_cnt, + struct DepositConfirmation); /* This loop populates the array 'dc' in 'pc' */ { @@ -3484,7 +3522,7 @@ phase_parse_pay (struct PayContext *pc) json_array_foreach (coins, coins_index, coin) { - struct DepositConfirmation *dc = &pc->dc[coins_index]; + struct DepositConfirmation *dc = &pc->parse_pay.dc[coins_index]; const char *exchange_url; struct GNUNET_JSON_Specification ispec[] = { GNUNET_JSON_spec_fixed_auto ("coin_sig", @@ -3536,7 +3574,7 @@ phase_parse_pay (struct PayContext *pc) { if (0 == GNUNET_memcmp (&dc->cdd.coin_pub, - &pc->dc[j].cdd.coin_pub)) + &pc->parse_pay.dc[j].cdd.coin_pub)) { GNUNET_break_op (0); pay_end (pc, @@ -3568,13 +3606,13 @@ phase_parse_pay (struct PayContext *pc) } /* Setup exchange group */ - for (unsigned int i = 0; i<pc->num_exchanges; i++) + for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) { if (0 == - strcmp (pc->egs[i]->exchange_url, + strcmp (pc->parse_pay.egs[i]->exchange_url, exchange_url)) { - eg = pc->egs[i]; + eg = pc->parse_pay.egs[i]; break; } } @@ -3584,8 +3622,8 @@ phase_parse_pay (struct PayContext *pc) eg->pc = pc; eg->exchange_url = dc->exchange_url; eg->total = dc->cdd.amount; - GNUNET_array_append (pc->egs, - pc->num_exchanges, + GNUNET_array_append (pc->parse_pay.egs, + pc->parse_pay.num_exchanges, eg); } else @@ -3608,8 +3646,8 @@ phase_parse_pay (struct PayContext *pc) } } - pc->tokens_cnt = json_array_size (tokens); - if (pc->tokens_cnt > MAX_TOKEN_ALLOWED_INPUTs) + pc->parse_pay.tokens_cnt = json_array_size (tokens); + if (pc->parse_pay.tokens_cnt > MAX_TOKEN_ALLOWED_INPUTs) { GNUNET_break_op (0); pay_end (pc, @@ -3621,8 +3659,8 @@ phase_parse_pay (struct PayContext *pc) return; } - pc->tokens = GNUNET_new_array (pc->tokens_cnt, - struct TokenUseConfirmation); + pc->parse_pay.tokens = GNUNET_new_array (pc->parse_pay.tokens_cnt, + struct TokenUseConfirmation); /* This look populates the array 'tokens' in 'pc' */ { @@ -3631,7 +3669,7 @@ phase_parse_pay (struct PayContext *pc) json_array_foreach (tokens, tokens_index, token) { - struct TokenUseConfirmation *tuc = &pc->tokens[tokens_index]; + struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[tokens_index]; struct GNUNET_JSON_Specification ispec[] = { GNUNET_JSON_spec_fixed_auto ("token_sig", &tuc->sig), @@ -3662,7 +3700,7 @@ phase_parse_pay (struct PayContext *pc) { if (0 == GNUNET_memcmp (&tuc->pub, - &pc->tokens[j].pub)) + &pc->parse_pay.tokens[j].pub)) { GNUNET_break_op (0); pay_end (pc, @@ -3690,48 +3728,48 @@ pay_context_cleanup (void *cls) { struct PayContext *pc = cls; - if (NULL != pc->timeout_task) + if (NULL != pc->batch_deposits.timeout_task) { - GNUNET_SCHEDULER_cancel (pc->timeout_task); - pc->timeout_task = NULL; + GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task); + pc->batch_deposits.timeout_task = NULL; } - if (NULL != pc->contract_terms_json) + if (NULL != pc->check_contract.contract_terms_json) { - json_decref (pc->contract_terms_json); - pc->contract_terms_json = NULL; + json_decref (pc->check_contract.contract_terms_json); + pc->check_contract.contract_terms_json = NULL; } - for (unsigned int i = 0; i<pc->coins_cnt; i++) + for (unsigned int i = 0; i<pc->parse_pay.coins_cnt; i++) { - struct DepositConfirmation *dc = &pc->dc[i]; + struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; TALER_denom_sig_free (&dc->cdd.denom_sig); GNUNET_free (dc->exchange_url); } - GNUNET_free (pc->dc); - for (unsigned int i = 0; i<pc->num_exchanges; i++) + GNUNET_free (pc->parse_pay.dc); + for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) { - struct ExchangeGroup *eg = pc->egs[i]; + struct ExchangeGroup *eg = pc->parse_pay.egs[i]; if (NULL != eg->fo) TMH_EXCHANGES_keys4exchange_cancel (eg->fo); GNUNET_free (eg); } - GNUNET_free (pc->egs); - if (NULL != pc->contract_terms) + GNUNET_free (pc->parse_pay.egs); + if (NULL != pc->check_contract.contract_terms) { - TALER_MERCHANT_contract_free (pc->contract_terms); - pc->contract_terms = NULL; + TALER_MERCHANT_contract_free (pc->check_contract.contract_terms); + pc->check_contract.contract_terms = NULL; } if (NULL != pc->response) { MHD_destroy_response (pc->response); pc->response = NULL; } - GNUNET_free (pc->session_id); + GNUNET_free (pc->parse_pay.session_id); GNUNET_CONTAINER_DLL_remove (pc_head, pc_tail, pc); - GNUNET_free (pc->pos_key); + GNUNET_free (pc->check_contract.pos_key); GNUNET_free (pc); } @@ -3763,7 +3801,7 @@ TMH_post_orders_ID_pay (const struct TMH_RequestHandler *rh, (int) pc->phase); switch (pc->phase) { - case PP_INIT: + case PP_PARSE_PAY: phase_parse_pay (pc); break; case PP_PARSE_WALLET_DATA: