diff options
author | Christian Grothoff <grothoff@gnunet.org> | 2022-04-01 16:39:07 +0200 |
---|---|---|
committer | Christian Grothoff <grothoff@gnunet.org> | 2022-04-01 16:39:07 +0200 |
commit | caf66486e70d896b1dd4eca3785fd42185a540cd (patch) | |
tree | bc4323b6fc7d1e256b485daaf7c20bdfa9037cfd /src/exchange | |
parent | 747ae5ef094731650911838a51e49db778b18ab6 (diff) | |
download | exchange-caf66486e70d896b1dd4eca3785fd42185a540cd.tar.gz exchange-caf66486e70d896b1dd4eca3785fd42185a540cd.tar.bz2 exchange-caf66486e70d896b1dd4eca3785fd42185a540cd.zip |
work on purse creation logic
Diffstat (limited to 'src/exchange')
-rw-r--r-- | src/exchange/taler-exchange-httpd_deposit.c | 12 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_melt.c | 2 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_purses_create.c | 249 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_withdraw.c | 1 |
4 files changed, 213 insertions, 51 deletions
diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c index 59d25904f..011f5f159 100644 --- a/src/exchange/taler-exchange-httpd_deposit.c +++ b/src/exchange/taler-exchange-httpd_deposit.c @@ -178,7 +178,6 @@ deposit_transaction (void *cls, } if (in_conflict) { - TEH_plugin->rollback (TEH_plugin->cls); *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds ( connection, @@ -188,7 +187,6 @@ deposit_transaction (void *cls, } if (! balance_ok) { - TEH_plugin->rollback (TEH_plugin->cls); *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds ( connection, @@ -323,6 +321,16 @@ TEH_handler_deposit (struct MHD_Connection *connection, GNUNET_JSON_parse_free (spec); return mret; } + if (0 > TALER_amount_cmp (&dk->meta.value, + &deposit.amount_with_fee)) + { + GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_EXCHANGE_GENERIC_AMOUNT_EXCEEDS_DENOMINATION_VALUE, + NULL); + } if (GNUNET_TIME_absolute_is_past (dk->meta.expire_deposit.abs_time)) { /* This denomination is past the expiration time for deposits */ diff --git a/src/exchange/taler-exchange-httpd_melt.c b/src/exchange/taler-exchange-httpd_melt.c index 6fe97c8f2..2ff03023a 100644 --- a/src/exchange/taler-exchange-httpd_melt.c +++ b/src/exchange/taler-exchange-httpd_melt.c @@ -183,7 +183,6 @@ melt_transaction (void *cls, if (rmc->zombie_required) { GNUNET_break_op (0); - TEH_plugin->rollback (TEH_plugin->cls); *mhd_ret = TALER_MHD_reply_with_error (connection, MHD_HTTP_BAD_REQUEST, TALER_EC_EXCHANGE_MELT_COIN_EXPIRED_NO_ZOMBIE, @@ -193,7 +192,6 @@ melt_transaction (void *cls, if (! balance_ok) { GNUNET_break_op (0); - TEH_plugin->rollback (TEH_plugin->cls); *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds ( connection, diff --git a/src/exchange/taler-exchange-httpd_purses_create.c b/src/exchange/taler-exchange-httpd_purses_create.c index ee822b259..75cb448a2 100644 --- a/src/exchange/taler-exchange-httpd_purses_create.c +++ b/src/exchange/taler-exchange-httpd_purses_create.c @@ -58,6 +58,11 @@ struct Coin * Deposit fee applicable for this coin. */ struct TALER_Amount deposit_fee; + + /** + * Amount to be put into the purse from this coin. + */ + struct TALER_Amount amount_minus_fee; }; @@ -147,22 +152,22 @@ reply_create_success (struct MHD_Connection *connection, { struct TALER_ExchangePublicKeyP pub; struct TALER_ExchangeSignatureP sig; - // FIXME: define what exactly we sign over! - struct TALER_DepositConfirmationPS dc = { - .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION), - .purpose.size = htonl (sizeof (dc)), - .h_contract_terms = pcc->h_contract_terms, - .purse_pub = *pcc->purse_pub - }; enum TALER_ErrorCode ec; - TALER_amount_hton (&dc.amount_without_fee, - &pcc->amount); if (TALER_EC_NONE != - (ec = TEH_keys_exchange_sign (&dc, - &pub, - &sig))) + (ec = TALER_exchange_online_purse_created_sign ( + &TEH_keys_exchange_sign_, + pcc->exchange_timestamp, + pcc->purse_expiration, + &pcc->amount, + &pcc->total_deposited, + pcc->purse_pub, + &pcc->merge_pub, + &pcc->h_contract_terms, + &pub, + &sig))) { + GNUNET_break (0); return TALER_MHD_reply_with_ec (connection, ec, NULL); @@ -170,8 +175,10 @@ reply_create_success (struct MHD_Connection *connection, return TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_OK, - // GNUNET_JSON_pack_timestamp ("exchange_timestamp", - // pcc->exchange_timestamp), + GNUNET_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", @@ -199,43 +206,143 @@ create_transaction (void *cls, { struct PurseCreateContext *pcc = cls; enum GNUNET_DB_QueryStatus qs; - bool balance_ok; - bool in_conflict; - - // 1) create purse - // 2) deposit all coins - // 3) if present, persist contract - // Also: nicely report errors... - qs = TEH_plugin->XXX (TEH_plugin->cls, ...); + bool in_conflict = true; + + /* 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, + &pcc->amount, + &pcc->purse_sig, + &in_conflict); if (qs < 0) { 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"); + TALER_LOG_WARNING ( + "Failed to store create 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"); return qs; } if (in_conflict) { + struct TALER_PurseMergePublicKeyP merge_pub; + struct GNUNET_TIME_Timestamp purse_expiration; + struct TALER_PrivateContractHashP h_contract_terms; + struct TALER_Amount target_amount; + struct TALER_Amount balance; + struct TALER_PurseContractSignatureP purse_sig; + 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, + &target_amount, + &balance, + &purse_sig); + if (qs < 0) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + TALER_LOG_WARNING ("Failed to fetch purse information from database\n"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "select purse request"); + return GNUNET_DB_STATUS_HARD_ERROR; + } *mhd_ret - = TEH_RESPONSE_reply_coin_insufficient_funds ( + = return TALER_MHD_REPLY_JSON_PACK ( connection, - TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_CONTRACT, - &coin->pci.coin_pub); + MHD_HTTP_CONFLICT, + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_META_DATA), + GNUNET_JSON_pack_amount ("amount", + &amount), + GNUNET_JSON_pack_timestamp ("purse_expiration", + purse_expiration), + GNUNET_JSON_pack_data_auto ("purse_sig", + &purse_sig), + GNUNET_JSON_pack_data_auto ("h_contract_terms", + &h_contract_terms), + GNUNET_JSON_pack_data_auto ("merge_pub", + &merge_pub)); return GNUNET_DB_STATUS_HARD_ERROR; } - if (! balance_ok) + /* 2) deposit all coins */ + for (unsigned int i = 0; i<pcc->num_coins; i++) { - TEH_plugin->rollback (TEH_plugin->cls); + struct Coin *coin = &pcc->coins[i]; + bool balance_ok = false; + + qs = TEH_plugin->do_purse_deposit (TEH_plugin->cls, + &pcc->purse_pub, + &coin->cpi.coin_pub, + &coin->amount, + &coin->coin_sig, + &coin->amount_minus_fee, + &balance_ok); + if (qs < 0) + { + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + return qs; + TALER_LOG_WARNING ( + "Failed to store purse deposit 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 deposit"); + return qs; + } + if (! balance_ok) + { + *mhd_ret + = TEH_RESPONSE_reply_coin_insufficient_funds ( + connection, + TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS, + &coin->pci.coin_pub); + return GNUNET_DB_STATUS_HARD_ERROR; + } + } + /* 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, + &in_conflict); + if (qs < 0) + { + 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 qs; + } + if (in_conflict) + { + /* FIXME-DESIGN: we have no proof that the + client is at fault here! + => need 2nd client signature over the encrypted + contract (and ECDHE public key)!!! */ *mhd_ret - = TEH_RESPONSE_reply_coin_insufficient_funds ( + = TEH_RESPONSE_reply_with_error ( connection, - TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS, - &coin->pci.coin_pub); + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_CONTRACT_STORED, + NULL); return GNUNET_DB_STATUS_HARD_ERROR; } return qs; @@ -289,7 +396,7 @@ parse_coin (struct MHD_Connection *connection, } if (GNUNET_OK != - TALER_wallet_purse_deposit_verify ("http://FIXME-URL", + TALER_wallet_purse_deposit_verify (TEH_base_url, &pcc->purse_pub, &pcc->amount, &coin->coin_pub, @@ -301,7 +408,7 @@ parse_coin (struct MHD_Connection *connection, TALER_MHD_reply_with_error (connection, MHD_HTTP_UNAUTHORIZED, TALER_EC_EXCHANGE_PURSE_CREATE_COIN_SIGNATURE_INVALID, - NULL)) + TEH_base_url)) ? GNUNET_NO : GNUNET_SYSERR; } /* check denomination exists and is valid */ @@ -317,6 +424,18 @@ parse_coin (struct MHD_Connection *connection, 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 */ @@ -366,6 +485,20 @@ parse_coin (struct MHD_Connection *connection, } 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_subtact (&coin->amount_minus_fee, + &coin->amount, + &coin->deposit_fee)); /* check coin signature */ switch (dk->denom_pub.cipher) { @@ -391,6 +524,17 @@ parse_coin (struct MHD_Connection *connection, 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; @@ -425,10 +569,10 @@ parse_coin (struct MHD_Connection *connection, MHD_RESULT -TEH_handler_purses_create (struct MHD_Connection *connection, - const struct - TALER_PurseContractPublicKeyP *purse_pub, - const json_t *root) +TEH_handler_purses_create ( + struct MHD_Connection *connection, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const json_t *root) { struct PurseCreateContext pcc = { .purse_pub = purse_pub, @@ -461,6 +605,7 @@ TEH_handler_purses_create (struct MHD_Connection *connection, &pcc.purse_expiration), GNUNET_JSON_spec_end () }; + const struct TEH_GlobalFee *gf; { enum GNUNET_GenericReturnValue res; @@ -479,7 +624,9 @@ TEH_handler_purses_create (struct MHD_Connection *connection, return MHD_YES; /* failure */ } } - + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (TEH_currency, + &pcc.deposit_total)); if (GNUNET_TIME_timestamp_cmp (pcc.purse_expiration, <, pcc.exchange_timestamp)) @@ -511,6 +658,17 @@ TEH_handler_purses_create (struct MHD_Connection *connection, TALER_EC_EXCHANGE_GENERIC_PARAMETER_MALFORMED, "deposits"); } + gf = TEH_keys_global_fee_by_time (TEH_keys_get_state (), + pcc.exchange_timestamp); + if (NULL == gf) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Cannot create purse: global fees not configured!\n"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_GENERIC_GLOBAL_FEES_MISSING, + NULL); + } /* parse deposits */ pcc.coins = GNUNET_new_array (struct Coin, pcc.num_coins); @@ -531,8 +689,7 @@ TEH_handler_purses_create (struct MHD_Connection *connection, } } - // FIXME: get purse_fee! - if (0 < TALER_amount_cmp (&purse_fee, + if (0 < TALER_amount_cmp (&gf->fees.purse, &pcc.deposit_total)) { GNUNET_break_op (0); @@ -543,7 +700,6 @@ TEH_handler_purses_create (struct MHD_Connection *connection, TALER_EC_EXCHANGE_CREATE_PURSE_NEGATIVE_VALUE_AFTER_FEE, NULL); } - TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; if (GNUNET_OK != @@ -560,7 +716,7 @@ TEH_handler_purses_create (struct MHD_Connection *connection, GNUNET_free (pcc.coins); return TALER_MHD_reply_with_error (connection, MHD_HTTP_UNAUTHORIZED, - TALER_EC_EXCHANGE_PURSE_CREATE_COIN_SIGNATURE_INVALID, + TALER_EC_EXCHANGE_PURSE_CREATE_SIGNATURE_INVALID, NULL); } @@ -568,6 +724,7 @@ TEH_handler_purses_create (struct MHD_Connection *connection, TEH_plugin->preflight (TEH_plugin->cls)) { GNUNET_break (0); + GNUNET_JSON_parse_free (spec); GNUNET_free (pcc.coins); return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c index 5765181b2..d5ecd3386 100644 --- a/src/exchange/taler-exchange-httpd_withdraw.c +++ b/src/exchange/taler-exchange-httpd_withdraw.c @@ -256,7 +256,6 @@ withdraw_transaction (void *cls, } if (! below_limit) { - TEH_plugin->rollback (TEH_plugin->cls); *mhd_ret = TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_ACCEPTED, |