diff options
Diffstat (limited to 'src/exchange/taler-exchange-httpd_purses_create.c')
-rw-r--r-- | src/exchange/taler-exchange-httpd_purses_create.c | 642 |
1 files changed, 201 insertions, 441 deletions
diff --git a/src/exchange/taler-exchange-httpd_purses_create.c b/src/exchange/taler-exchange-httpd_purses_create.c index dba4fa4ae..2de9468fe 100644 --- a/src/exchange/taler-exchange-httpd_purses_create.c +++ b/src/exchange/taler-exchange-httpd_purses_create.c @@ -25,9 +25,9 @@ #include <gnunet/gnunet_json_lib.h> #include <jansson.h> #include <microhttpd.h> -#include <pthread.h> #include "taler_json_lib.h" #include "taler_mhd_lib.h" +#include "taler-exchange-httpd_common_deposit.h" #include "taler-exchange-httpd_purses_create.h" #include "taler-exchange-httpd_responses.h" #include "taler_exchangedb_lib.h" @@ -35,56 +35,10 @@ /** - * Information about an individual coin being deposited. - */ -struct Coin -{ - /** - * Public information about the coin. - */ - struct TALER_CoinPublicInfo cpi; - - /** - * Signature affirming spending the coin. - */ - struct TALER_CoinSpendSignatureP coin_sig; - - /** - * Amount to be put into the purse from this coin. - */ - struct TALER_Amount amount; - - /** - * Deposit fee applicable to this coin. - */ - struct TALER_Amount deposit_fee; - - /** - * Amount to be put into the purse from this coin. - */ - struct TALER_Amount amount_minus_fee; - - /** - * ID of the coin in known_coins. - */ - uint64_t known_coin_id; -}; - - -/** * Closure for #create_transaction. */ 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. @@ -92,11 +46,6 @@ struct PurseCreateContext struct TALER_Amount deposit_total; /** - * When should the purse expire. - */ - struct GNUNET_TIME_Timestamp purse_expiration; - - /** * Our current time. */ struct GNUNET_TIME_Timestamp exchange_timestamp; @@ -107,9 +56,9 @@ struct PurseCreateContext struct TALER_PurseMergePublicKeyP merge_pub; /** - * Contract decryption key for the purse. + * Encrypted contract of for the purse. */ - struct TALER_ContractDiffiePublicP contract_pub; + struct TALER_EncryptedContract econtract; /** * Signature of the client affiming this request. @@ -117,29 +66,14 @@ struct PurseCreateContext struct TALER_PurseContractSignatureP purse_sig; /** - * Signature of the client affiming this encrypted contract. + * Fundamental details about the purse. */ - struct TALER_PurseContractSignatureP econtract_sig; - - /** - * Hash of the contract terms of the purse. - */ - struct TALER_PrivateContractHashP h_contract_terms; + struct TEH_PurseDetails pd; /** * Array of coins being deposited. */ - struct Coin *coins; - - /** - * Encrypted contract, can be NULL. - */ - void *econtract; - - /** - * Number of bytes in @e econtract. - */ - size_t econtract_size; + struct TEH_PurseDepositedCoin *coins; /** * Length of the @e coins array. @@ -150,53 +84,13 @@ struct PurseCreateContext * Minimum age for deposits into this purse. */ uint32_t min_age; -}; + /** + * Do we have an @e econtract? + */ + bool no_econtract; -/** - * 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)); -} +}; /** @@ -222,20 +116,22 @@ create_transaction (void *cls, struct TALER_Amount purse_fee; bool in_conflict = true; - TALER_amount_set_zero (pcc->amount.currency, - &purse_fee); + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (TEH_currency, + &purse_fee)); /* 1) create purse */ - qs = TEH_plugin->insert_purse_request (TEH_plugin->cls, - pcc->purse_pub, - &pcc->merge_pub, - pcc->purse_expiration, - &pcc->h_contract_terms, - pcc->min_age, - TALER_WAMF_MODE_MERGE_FULLY_PAID_PURSE, - &purse_fee, - &pcc->amount, - &pcc->purse_sig, - &in_conflict); + qs = TEH_plugin->insert_purse_request ( + TEH_plugin->cls, + &pcc->pd.purse_pub, + &pcc->merge_pub, + pcc->pd.purse_expiration, + &pcc->pd.h_contract_terms, + pcc->min_age, + TALER_WAMF_MODE_MERGE_FULLY_PAID_PURSE, + &purse_fee, + &pcc->pd.target_amount, + &pcc->purse_sig, + &in_conflict); if (qs < 0) { if (GNUNET_DB_STATUS_SOFT_ERROR == qs) @@ -260,15 +156,15 @@ create_transaction (void *cls, uint32_t min_age; TEH_plugin->rollback (TEH_plugin->cls); - qs = TEH_plugin->select_purse_request (TEH_plugin->cls, - pcc->purse_pub, - &merge_pub, - &purse_expiration, - &h_contract_terms, - &min_age, - &target_amount, - &balance, - &purse_sig); + qs = TEH_plugin->get_purse_request (TEH_plugin->cls, + &pcc->pd.purse_pub, + &merge_pub, + &purse_expiration, + &h_contract_terms, + &min_age, + &target_amount, + &balance, + &purse_sig); if (qs < 0) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); @@ -302,17 +198,25 @@ create_transaction (void *cls, /* 2) deposit all coins */ for (unsigned int i = 0; i<pcc->num_coins; i++) { - struct Coin *coin = &pcc->coins[i]; + struct TEH_PurseDepositedCoin *coin = &pcc->coins[i]; bool balance_ok = false; bool conflict = true; + bool too_late = true; + qs = TEH_make_coin_known (&coin->cpi, + connection, + &coin->known_coin_id, + mhd_ret); + 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, &coin->amount_minus_fee, &balance_ok, + &too_late, &conflict); if (qs <= 0) { @@ -329,25 +233,43 @@ create_transaction (void *cls, } if (! balance_ok) { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Coin %s has insufficient balance for purse deposit of amount %s\n", + TALER_B2S (&coin->cpi.coin_pub), + TALER_amount2s (&coin->amount)); *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds ( connection, TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS, + &coin->cpi.denom_pub_hash, &coin->cpi.coin_pub); return GNUNET_DB_STATUS_HARD_ERROR; } + if (too_late) + { + *mhd_ret + = TALER_MHD_reply_with_ec ( + connection, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "too late to deposit on purse creation"); + return GNUNET_DB_STATUS_HARD_ERROR; + } if (conflict) { struct TALER_Amount amount; struct TALER_CoinSpendPublicKeyP coin_pub; struct TALER_CoinSpendSignatureP coin_sig; + struct TALER_DenominationHashP h_denom_pub; + struct TALER_AgeCommitmentHash phac; char *partner_url = NULL; 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, + &phac, &coin_sig, &partner_url); if (qs < 0) @@ -372,6 +294,10 @@ create_transaction (void *cls, &coin_pub), GNUNET_JSON_pack_data_auto ("coin_sig", &coin_sig), + GNUNET_JSON_pack_data_auto ("h_denom_pub", + &h_denom_pub), + GNUNET_JSON_pack_data_auto ("h_age_restrictions", + &phac), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_string ("partner_url", partner_url)), @@ -382,68 +308,64 @@ create_transaction (void *cls, } } /* 3) if present, persist contract */ - in_conflict = true; - qs = TEH_plugin->insert_contract (TEH_plugin->cls, - pcc->purse_pub, - &pcc->contract_pub, - pcc->econtract_size, - pcc->econtract, - &pcc->econtract_sig, - &in_conflict); - if (qs < 0) + if (! pcc->no_econtract) { - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - return qs; - TALER_LOG_WARNING ("Failed to store purse information in database\n"); - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_STORE_FAILED, - "purse create contract"); - return GNUNET_DB_STATUS_HARD_ERROR; - } - if (in_conflict) - { - struct TALER_ContractDiffiePublicP pub_ckey; - struct TALER_PurseContractSignatureP econtract_sig; - size_t econtract_size; - void *econtract; - struct GNUNET_HashCode h_econtract; - - qs = TEH_plugin->select_contract_by_purse (TEH_plugin->cls, - pcc->purse_pub, - &pub_ckey, - &econtract_sig, - &econtract_size, - &econtract); - if (qs <= 0) + in_conflict = true; + qs = TEH_plugin->insert_contract (TEH_plugin->cls, + &pcc->pd.purse_pub, + &pcc->econtract, + &in_conflict); + if (qs < 0) { if (GNUNET_DB_STATUS_SOFT_ERROR == qs) return qs; - GNUNET_break (0 != qs); - TALER_LOG_WARNING ( - "Failed to store fetch contract information from database\n"); + TALER_LOG_WARNING ("Failed to store purse information in database\n"); *mhd_ret = TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "select contract"); + TALER_EC_GENERIC_DB_STORE_FAILED, + "purse create contract"); + return GNUNET_DB_STATUS_HARD_ERROR; + } + if (in_conflict) + { + struct TALER_EncryptedContract econtract; + struct GNUNET_HashCode h_econtract; + + qs = TEH_plugin->select_contract_by_purse ( + TEH_plugin->cls, + &pcc->pd.purse_pub, + &econtract); + if (qs <= 0) + { + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + return qs; + GNUNET_break (0 != qs); + TALER_LOG_WARNING ( + "Failed to store fetch contract information from database\n"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "select contract"); + return GNUNET_DB_STATUS_HARD_ERROR; + } + GNUNET_CRYPTO_hash (econtract.econtract, + econtract.econtract_size, + &h_econtract); + *mhd_ret + = TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_CONFLICT, + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA), + GNUNET_JSON_pack_data_auto ("h_econtract", + &h_econtract), + GNUNET_JSON_pack_data_auto ("econtract_sig", + &econtract.econtract_sig), + GNUNET_JSON_pack_data_auto ("contract_pub", + &econtract.contract_pub)); + GNUNET_free (econtract.econtract); return GNUNET_DB_STATUS_HARD_ERROR; } - GNUNET_CRYPTO_hash (econtract, - econtract_size, - &h_econtract); - *mhd_ret - = TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_CONFLICT, - TALER_JSON_pack_ec ( - TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA), - GNUNET_JSON_pack_data_auto ("h_econtract", - &h_econtract), - GNUNET_JSON_pack_data_auto ("econtract_sig", - &econtract_sig), - GNUNET_JSON_pack_data_auto ("pub_ckey", - &pub_ckey)); - return GNUNET_DB_STATUS_HARD_ERROR; } return qs; } @@ -453,8 +375,8 @@ create_transaction (void *cls, * Parse a coin and check signature of the coin and the denomination * signature over the coin. * - * @param[in,out] our HTTP connection - * @param[in,out] request context + * @param[in,out] connection our HTTP connection + * @param[in,out] pcc request context * @param[out] coin coin to initialize * @param jcoin coin to parse * @return #GNUNET_OK on success, #GNUNET_NO if an error was returned, @@ -463,207 +385,36 @@ create_transaction (void *cls, static enum GNUNET_GenericReturnValue parse_coin (struct MHD_Connection *connection, struct PurseCreateContext *pcc, - struct Coin *coin, + struct TEH_PurseDepositedCoin *coin, const json_t *jcoin) { - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount ("amount", - TEH_currency, - &coin->amount), - GNUNET_JSON_spec_fixed_auto ("denom_pub_hash", - &coin->cpi.denom_pub_hash), - TALER_JSON_spec_denom_sig ("ub_sig", - &coin->cpi.denom_sig), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_fixed_auto ("h_age_commitment", - &coin->cpi.h_age_commitment), - &coin->cpi.no_age_commitment), - GNUNET_JSON_spec_fixed_auto ("coin_sig", - &coin->coin_sig), - GNUNET_JSON_spec_fixed_auto ("coin_pub", - &coin->cpi.coin_pub), - GNUNET_JSON_spec_end () - }; - - { - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (connection, - jcoin, - spec); - if (GNUNET_OK != res) - return res; - } + enum GNUNET_GenericReturnValue iret; if (GNUNET_OK != - TALER_wallet_purse_deposit_verify (TEH_base_url, - pcc->purse_pub, - &coin->amount, - &coin->cpi.coin_pub, - &coin->coin_sig)) + (iret = TEH_common_purse_deposit_parse_coin (connection, + coin, + jcoin))) + return iret; + if (GNUNET_OK != + (iret = TEH_common_deposit_check_purse_deposit ( + connection, + coin, + &pcc->pd.purse_pub, + pcc->min_age))) + return iret; + if (0 > + TALER_amount_add (&pcc->deposit_total, + &pcc->deposit_total, + &coin->amount_minus_fee)) { - TALER_LOG_WARNING ( - "Invalid coin signature on /purses/$PID/create request\n"); - GNUNET_JSON_parse_free (spec); + GNUNET_break (0); return (MHD_YES == TALER_MHD_reply_with_error (connection, - MHD_HTTP_FORBIDDEN, - TALER_EC_EXCHANGE_PURSE_CREATE_COIN_SIGNATURE_INVALID, - TEH_base_url)) - ? GNUNET_NO : GNUNET_SYSERR; - } - /* check denomination exists and is valid */ - { - struct TEH_DenominationKey *dk; - MHD_RESULT mret; - - dk = TEH_keys_denomination_by_hash (&coin->cpi.denom_pub_hash, - connection, - &mret); - if (NULL == dk) - { - GNUNET_JSON_parse_free (spec); - return (MHD_YES == mret) ? GNUNET_NO : GNUNET_SYSERR; - } - if (0 > TALER_amount_cmp (&dk->meta.value, - &coin->amount)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_EXCHANGE_GENERIC_AMOUNT_EXCEEDS_DENOMINATION_VALUE, - NULL)) - ? GNUNET_NO : GNUNET_SYSERR; - } - if (GNUNET_TIME_absolute_is_past (dk->meta.expire_deposit.abs_time)) - { - /* This denomination is past the expiration time for deposits */ - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - TEH_RESPONSE_reply_expired_denom_pub_hash ( - connection, - &coin->cpi.denom_pub_hash, - TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED, - "PURSE CREATE")) - ? GNUNET_NO : GNUNET_SYSERR; - } - if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time)) - { - /* This denomination is not yet valid */ - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - TEH_RESPONSE_reply_expired_denom_pub_hash ( - connection, - &coin->cpi.denom_pub_hash, - TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE, - "PURSE CREATE")) - ? GNUNET_NO : GNUNET_SYSERR; - } - if (dk->recoup_possible) - { - /* This denomination has been revoked */ - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - TEH_RESPONSE_reply_expired_denom_pub_hash ( - connection, - &coin->cpi.denom_pub_hash, - TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED, - "PURSE CREATE")) - ? GNUNET_NO : GNUNET_SYSERR; - } - if (dk->denom_pub.cipher != coin->cpi.denom_sig.cipher) - { - /* denomination cipher and denomination signature cipher not the same */ - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_EXCHANGE_GENERIC_CIPHER_MISMATCH, - NULL)) - ? GNUNET_NO : GNUNET_SYSERR; - } - - coin->deposit_fee = dk->meta.fees.deposit; - if (0 < TALER_amount_cmp (&coin->deposit_fee, - &coin->amount)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_EXCHANGE_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE, - NULL); - } - GNUNET_assert (0 <= - TALER_amount_subtract (&coin->amount_minus_fee, - &coin->amount, - &coin->deposit_fee)); - /* check coin signature */ - switch (dk->denom_pub.cipher) - { - case TALER_DENOMINATION_RSA: - TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_RSA]++; - break; - case TALER_DENOMINATION_CS: - TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_CS]++; - break; - default: - break; - } - if (GNUNET_YES != - TALER_test_coin_valid (&coin->cpi, - &dk->denom_pub)) - { - TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - TALER_MHD_reply_with_error (connection, - MHD_HTTP_FORBIDDEN, - TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID, - NULL)) - ? GNUNET_NO : GNUNET_SYSERR; - } - if (0 > - TALER_amount_add (&pcc->deposit_total, - &pcc->deposit_total, - &coin->amount_minus_fee)) - { - GNUNET_break (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_FAILED_COMPUTE_AMOUNT, - "total deposit contribution"); - } - } - { - MHD_RESULT mhd_ret = MHD_NO; - enum GNUNET_DB_QueryStatus qs; - - /* make sure coin is 'known' in database */ - for (unsigned int tries = 0; tries<MAX_TRANSACTION_COMMIT_RETRIES; tries++) - { - qs = TEH_make_coin_known (&coin->cpi, - connection, - &coin->known_coin_id, - &mhd_ret); - /* no transaction => no serialization failures should be possible */ - if (GNUNET_DB_STATUS_SOFT_ERROR != qs) - break; - } - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - { - GNUNET_break (0); - return (MHD_YES == - TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_COMMIT_FAILED, - "make_coin_known")) - ? GNUNET_NO : GNUNET_SYSERR; - } - if (qs < 0) - return (MHD_YES == mhd_ret) ? GNUNET_NO : GNUNET_SYSERR; + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_FAILED_COMPUTE_AMOUNT, + "total deposit contribution")) + ? GNUNET_NO + : GNUNET_SYSERR; } return GNUNET_OK; } @@ -676,41 +427,32 @@ 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; + const json_t *deposits; json_t *deposit; unsigned int idx; 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 ( - GNUNET_JSON_spec_varsize ("econtract", - &pcc.econtract, - &pcc.econtract_size), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_fixed_auto ("econtract_sig", - &pcc.econtract_sig), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_fixed_auto ("contract_pub", - &pcc.contract_pub), - NULL), + TALER_JSON_spec_econtract ("econtract", + &pcc.econtract), + &pcc.no_econtract), GNUNET_JSON_spec_fixed_auto ("merge_pub", &pcc.merge_pub), GNUNET_JSON_spec_fixed_auto ("purse_sig", &pcc.purse_sig), GNUNET_JSON_spec_fixed_auto ("h_contract_terms", - &pcc.h_contract_terms), - GNUNET_JSON_spec_json ("deposits", - &deposits), + &pcc.pd.h_contract_terms), + GNUNET_JSON_spec_array_const ("deposits", + &deposits), GNUNET_JSON_spec_timestamp ("purse_expiration", - &pcc.purse_expiration), + &pcc.pd.purse_expiration), GNUNET_JSON_spec_end () }; const struct TEH_GlobalFee *gf; @@ -735,21 +477,19 @@ 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)) { GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error (connection, MHD_HTTP_BAD_REQUEST, 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); return TALER_MHD_reply_with_error (connection, MHD_HTTP_BAD_REQUEST, TALER_EC_EXCHANGE_PURSE_CREATE_EXPIRATION_IS_NEVER, @@ -760,14 +500,26 @@ TEH_handler_purses_create ( (pcc.num_coins > TALER_MAX_FRESH_COINS) ) { GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error (connection, MHD_HTTP_BAD_REQUEST, TALER_EC_GENERIC_PARAMETER_MALFORMED, "deposits"); } - gf = TEH_keys_global_fee_by_time (TEH_keys_get_state (), - pcc.exchange_timestamp); + { + struct TEH_KeyStateHandle *keys; + + keys = TEH_keys_get_state (); + if (NULL == keys) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, + NULL); + } + gf = TEH_keys_global_fee_by_time (keys, + pcc.exchange_timestamp); + } if (NULL == gf) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -779,11 +531,11 @@ TEH_handler_purses_create ( } /* parse deposits */ pcc.coins = GNUNET_new_array (pcc.num_coins, - struct Coin); + struct TEH_PurseDepositedCoin); json_array_foreach (deposits, idx, deposit) { enum GNUNET_GenericReturnValue res; - struct Coin *coin = &pcc.coins[idx]; + struct TEH_PurseDepositedCoin *coin = &pcc.coins[idx]; res = parse_coin (connection, &pcc, @@ -791,7 +543,8 @@ TEH_handler_purses_create ( deposit); if (GNUNET_OK != res) { - GNUNET_JSON_parse_free (spec); + for (unsigned int i = 0; i<idx; i++) + TEH_common_purse_deposit_free_coin (&pcc.coins[i]); GNUNET_free (pcc.coins); return (GNUNET_NO == res) ? MHD_YES : MHD_NO; } @@ -801,7 +554,6 @@ TEH_handler_purses_create ( &pcc.deposit_total)) { GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); GNUNET_free (pcc.coins); return TALER_MHD_reply_with_error (connection, MHD_HTTP_BAD_REQUEST, @@ -811,32 +563,35 @@ TEH_handler_purses_create ( TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; if (GNUNET_OK != - TALER_wallet_purse_create_verify (pcc.purse_expiration, - &pcc.h_contract_terms, - &pcc.merge_pub, - pcc.min_age, - &pcc.amount, - pcc.purse_pub, - &pcc.purse_sig)) + TALER_wallet_purse_create_verify ( + pcc.pd.purse_expiration, + &pcc.pd.h_contract_terms, + &pcc.merge_pub, + pcc.min_age, + &pcc.pd.target_amount, + &pcc.pd.purse_pub, + &pcc.purse_sig)) { TALER_LOG_WARNING ("Invalid signature on /purses/$PID/create request\n"); - GNUNET_JSON_parse_free (spec); + for (unsigned int i = 0; i<pcc.num_coins; i++) + TEH_common_purse_deposit_free_coin (&pcc.coins[i]); GNUNET_free (pcc.coins); return TALER_MHD_reply_with_error (connection, MHD_HTTP_FORBIDDEN, TALER_EC_EXCHANGE_PURSE_CREATE_SIGNATURE_INVALID, NULL); } - if ( (NULL != pcc.econtract) && + if ( (! pcc.no_econtract) && (GNUNET_OK != - TALER_wallet_econtract_upload_verify (pcc.econtract, - pcc.econtract_size, - &pcc.contract_pub, + TALER_wallet_econtract_upload_verify (pcc.econtract.econtract, + pcc.econtract.econtract_size, + &pcc.econtract.contract_pub, purse_pub, - &pcc.econtract_sig)) ) + &pcc.econtract.econtract_sig)) ) { TALER_LOG_WARNING ("Invalid signature on /purses/$PID/create request\n"); - GNUNET_JSON_parse_free (spec); + for (unsigned int i = 0; i<pcc.num_coins; i++) + TEH_common_purse_deposit_free_coin (&pcc.coins[i]); GNUNET_free (pcc.coins); return TALER_MHD_reply_with_error (connection, MHD_HTTP_FORBIDDEN, @@ -849,7 +604,8 @@ TEH_handler_purses_create ( TEH_plugin->preflight (TEH_plugin->cls)) { GNUNET_break (0); - GNUNET_JSON_parse_free (spec); + for (unsigned int i = 0; i<pcc.num_coins; i++) + TEH_common_purse_deposit_free_coin (&pcc.coins[i]); GNUNET_free (pcc.coins); return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, @@ -869,7 +625,8 @@ TEH_handler_purses_create ( &create_transaction, &pcc)) { - GNUNET_JSON_parse_free (spec); + for (unsigned int i = 0; i<pcc.num_coins; i++) + TEH_common_purse_deposit_free_coin (&pcc.coins[i]); GNUNET_free (pcc.coins); return mhd_ret; } @@ -879,10 +636,13 @@ 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; i<pcc.num_coins; i++) + TEH_common_purse_deposit_free_coin (&pcc.coins[i]); GNUNET_free (pcc.coins); - GNUNET_JSON_parse_free (spec); return res; } } |