diff options
Diffstat (limited to 'src/mint/taler-mint-httpd_db.c')
-rw-r--r-- | src/mint/taler-mint-httpd_db.c | 170 |
1 files changed, 111 insertions, 59 deletions
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index bf10cd29e..c3ecf0101 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c | |||
@@ -22,11 +22,6 @@ | |||
22 | * - actually abstract DB implementation (i.e. via plugin logic) | 22 | * - actually abstract DB implementation (i.e. via plugin logic) |
23 | * (this file should remain largely unchanged with the exception | 23 | * (this file should remain largely unchanged with the exception |
24 | * of the PQ-specific DB handle types) | 24 | * of the PQ-specific DB handle types) |
25 | * - /withdraw/sign: all | ||
26 | * + properly check all conditions and handle errors | ||
27 | * + properly check transaction logic | ||
28 | * + check for leaks | ||
29 | * + check low-level API | ||
30 | * - /refresh/melt: all | 25 | * - /refresh/melt: all |
31 | * + properly check all conditions and handle errors | 26 | * + properly check all conditions and handle errors |
32 | * + properly check transaction logic | 27 | * + properly check transaction logic |
@@ -264,11 +259,17 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection, | |||
264 | { | 259 | { |
265 | PGconn *db_conn; | 260 | PGconn *db_conn; |
266 | struct ReserveHistory *rh; | 261 | struct ReserveHistory *rh; |
262 | const struct ReserveHistory *pos; | ||
267 | struct MintKeyState *key_state; | 263 | struct MintKeyState *key_state; |
268 | struct CollectableBlindcoin collectable; | 264 | struct CollectableBlindcoin collectable; |
269 | struct TALER_MINT_DenomKeyIssuePriv *dki; | 265 | struct TALER_MINT_DenomKeyIssuePriv *dki; |
266 | struct TALER_MINT_DenomKeyIssuePriv *tdki; | ||
270 | struct GNUNET_CRYPTO_rsa_Signature *sig; | 267 | struct GNUNET_CRYPTO_rsa_Signature *sig; |
271 | struct TALER_Amount amount_required; | 268 | struct TALER_Amount amount_required; |
269 | struct TALER_Amount deposit_total; | ||
270 | struct TALER_Amount withdraw_total; | ||
271 | struct TALER_Amount balance; | ||
272 | struct TALER_Amount value; | ||
272 | struct GNUNET_HashCode h_blind; | 273 | struct GNUNET_HashCode h_blind; |
273 | int res; | 274 | int res; |
274 | 275 | ||
@@ -299,63 +300,102 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection, | |||
299 | return res; | 300 | return res; |
300 | } | 301 | } |
301 | GNUNET_assert (GNUNET_NO == res); | 302 | GNUNET_assert (GNUNET_NO == res); |
302 | rh = TALER_MINT_DB_get_reserve_history (db_conn, | ||
303 | reserve); | ||
304 | if (NULL == rh) | ||
305 | return TALER_MINT_reply_json_pack (connection, | ||
306 | MHD_HTTP_NOT_FOUND, | ||
307 | "{s:s}", | ||
308 | "error", | ||
309 | "Reserve not found"); | ||
310 | 303 | ||
304 | /* Check if balance is sufficient */ | ||
311 | key_state = TALER_MINT_key_state_acquire (); | 305 | key_state = TALER_MINT_key_state_acquire (); |
312 | dki = TALER_MINT_get_denom_key (key_state, | 306 | dki = TALER_MINT_get_denom_key (key_state, |
313 | denomination_pub); | 307 | denomination_pub); |
314 | TALER_MINT_key_state_release (key_state); | ||
315 | if (NULL == dki) | 308 | if (NULL == dki) |
309 | { | ||
310 | TALER_MINT_key_state_release (key_state); | ||
316 | return TALER_MINT_reply_json_pack (connection, | 311 | return TALER_MINT_reply_json_pack (connection, |
317 | MHD_HTTP_NOT_FOUND, | 312 | MHD_HTTP_NOT_FOUND, |
318 | "{s:s}", | 313 | "{s:s}", |
319 | "error", | 314 | "error", |
320 | "Denomination not found"); | 315 | "Denomination not found"); |
316 | } | ||
317 | if (GNUNET_OK != | ||
318 | TALER_MINT_DB_transaction (db_conn)) | ||
319 | { | ||
320 | GNUNET_break (0); | ||
321 | TALER_MINT_key_state_release (key_state); | ||
322 | return TALER_MINT_reply_internal_db_error (connection); | ||
323 | } | ||
321 | 324 | ||
322 | amount_required = TALER_amount_add (TALER_amount_ntoh (dki->issue.value), | 325 | rh = TALER_MINT_DB_get_reserve_history (db_conn, |
323 | TALER_amount_ntoh (dki->issue.fee_withdraw)); | 326 | reserve); |
324 | // FIX LOGIC! | 327 | if (NULL == rh) |
325 | #if 0 | 328 | { |
326 | if (0 < TALER_amount_cmp (amount_required, | 329 | TALER_MINT_DB_rollback (db_conn); |
327 | TALER_amount_ntoh (db_reserve.balance))) | 330 | TALER_MINT_key_state_release (key_state); |
328 | return TALER_MINT_reply_json_pack (connection, | 331 | return TALER_MINT_reply_json_pack (connection, |
329 | MHD_HTTP_PAYMENT_REQUIRED, | 332 | MHD_HTTP_NOT_FOUND, |
330 | "{s:s}", | 333 | "{s:s}", |
331 | "error", | 334 | "error", |
332 | "Insufficient funds"); | 335 | "Reserve not found"); |
336 | } | ||
337 | |||
338 | /* calculate amount required including fees */ | ||
339 | amount_required = TALER_amount_add (TALER_amount_ntoh (dki->issue.value), | ||
340 | TALER_amount_ntoh (dki->issue.fee_withdraw)); | ||
333 | 341 | ||
334 | db_reserve.balance = TALER_amount_hton | 342 | /* calculate balance of the reserve */ |
335 | (TALER_amount_subtract (TALER_amount_ntoh (db_reserve.balance), | 343 | res = 0; |
336 | amount_required)); | 344 | for (pos = rh; NULL != pos; pos = pos->next) |
345 | { | ||
346 | switch (pos->type) | ||
347 | { | ||
348 | case TALER_MINT_DB_RO_BANK_TO_MINT: | ||
349 | if (0 == (res & 1)) | ||
350 | deposit_total = pos->details.bank->amount; | ||
351 | else | ||
352 | deposit_total = TALER_amount_add (deposit_total, | ||
353 | pos->details.bank->amount); | ||
354 | res |= 1; | ||
355 | break; | ||
356 | case TALER_MINT_DB_RO_WITHDRAW_COIN: | ||
357 | tdki = TALER_MINT_get_denom_key (key_state, | ||
358 | pos->details.withdraw->denom_pub); | ||
359 | value = TALER_amount_ntoh (tdki->issue.value); | ||
360 | if (0 == (res & 2)) | ||
361 | withdraw_total = value; | ||
362 | else | ||
363 | withdraw_total = TALER_amount_add (withdraw_total, | ||
364 | value); | ||
365 | res |= 2; | ||
366 | break; | ||
367 | } | ||
368 | } | ||
337 | 369 | ||
370 | /* FIXME: good place to assert deposit_total > withdraw_total... */ | ||
371 | balance = TALER_amount_subtract (deposit_total, | ||
372 | withdraw_total); | ||
373 | if (0 < TALER_amount_cmp (amount_required, | ||
374 | balance)) | ||
375 | { | ||
376 | TALER_MINT_key_state_release (key_state); | ||
377 | TALER_MINT_DB_rollback (db_conn); | ||
378 | res = TALER_MINT_reply_withdraw_sign_insufficient_funds (connection, | ||
379 | rh); | ||
380 | TALER_MINT_DB_free_reserve_history (rh); | ||
381 | return res; | ||
382 | } | ||
383 | TALER_MINT_DB_free_reserve_history (rh); | ||
384 | |||
385 | /* Balance is good, sign the coin! */ | ||
338 | sig = GNUNET_CRYPTO_rsa_sign (dki->denom_priv, | 386 | sig = GNUNET_CRYPTO_rsa_sign (dki->denom_priv, |
339 | blinded_msg, | 387 | blinded_msg, |
340 | blinded_msg_len); | 388 | blinded_msg_len); |
389 | TALER_MINT_key_state_release (key_state); | ||
341 | if (NULL == sig) | 390 | if (NULL == sig) |
342 | { | 391 | { |
343 | GNUNET_break (0); | 392 | GNUNET_break (0); |
393 | TALER_MINT_DB_rollback (db_conn); | ||
344 | return TALER_MINT_reply_internal_error (connection, | 394 | return TALER_MINT_reply_internal_error (connection, |
345 | "Internal error"); | 395 | "Internal error"); |
346 | } | 396 | } |
347 | 397 | ||
348 | /* transaction start */ | 398 | // FIXME: can we avoid the cast? |
349 | if (GNUNET_OK != | ||
350 | TALER_MINT_DB_update_reserve (db_conn, | ||
351 | &db_reserve, | ||
352 | GNUNET_YES)) | ||
353 | { | ||
354 | GNUNET_break (0); | ||
355 | return TALER_MINT_reply_internal_db_error (connection); | ||
356 | } | ||
357 | #endif | ||
358 | |||
359 | collectable.denom_pub = (struct GNUNET_CRYPTO_rsa_PublicKey *) denomination_pub; | 399 | collectable.denom_pub = (struct GNUNET_CRYPTO_rsa_PublicKey *) denomination_pub; |
360 | collectable.sig = sig; | 400 | collectable.sig = sig; |
361 | collectable.reserve_pub = *reserve; | 401 | collectable.reserve_pub = *reserve; |
@@ -367,17 +407,27 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection, | |||
367 | { | 407 | { |
368 | GNUNET_break (0); | 408 | GNUNET_break (0); |
369 | GNUNET_CRYPTO_rsa_signature_free (sig); | 409 | GNUNET_CRYPTO_rsa_signature_free (sig); |
410 | TALER_MINT_DB_rollback (db_conn); | ||
370 | return TALER_MINT_reply_internal_db_error (connection); | 411 | return TALER_MINT_reply_internal_db_error (connection); |
371 | } | 412 | } |
372 | /* transaction end */ | 413 | if (GNUNET_OK != |
414 | TALER_MINT_DB_commit (db_conn)) | ||
415 | { | ||
416 | LOG_WARNING ("/withdraw/sign transaction commit failed\n"); | ||
417 | return TALER_MINT_reply_commit_error (connection); | ||
418 | } | ||
419 | res = TALER_MINT_reply_withdraw_sign_success (connection, | ||
420 | &collectable); | ||
373 | GNUNET_CRYPTO_rsa_signature_free (sig); | 421 | GNUNET_CRYPTO_rsa_signature_free (sig); |
374 | return TALER_MINT_reply_withdraw_sign_success (connection, | 422 | return res; |
375 | &collectable); | ||
376 | } | 423 | } |
377 | 424 | ||
378 | 425 | ||
426 | |||
427 | |||
428 | |||
379 | /** | 429 | /** |
380 | * Insert all requested denominations into the db, and compute the | 430 | * Insert all requested denominations into the DB, and compute the |
381 | * required cost of the denominations, including fees. | 431 | * required cost of the denominations, including fees. |
382 | * | 432 | * |
383 | * @param connection the connection to send an error response to | 433 | * @param connection the connection to send an error response to |
@@ -615,11 +665,11 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection, | |||
615 | } | 665 | } |
616 | 666 | ||
617 | 667 | ||
618 | if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn)) | 668 | if (GNUNET_OK != |
669 | TALER_MINT_DB_transaction (db_conn)) | ||
619 | { | 670 | { |
620 | // FIXME: return 'internal error'? | ||
621 | GNUNET_break (0); | 671 | GNUNET_break (0); |
622 | return MHD_NO; | 672 | return TALER_MINT_reply_internal_db_error (connection); |
623 | } | 673 | } |
624 | 674 | ||
625 | if (GNUNET_OK != TALER_MINT_DB_create_refresh_session (db_conn, | 675 | if (GNUNET_OK != TALER_MINT_DB_create_refresh_session (db_conn, |
@@ -678,10 +728,11 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection, | |||
678 | "not enough coins melted"); | 728 | "not enough coins melted"); |
679 | } | 729 | } |
680 | 730 | ||
681 | if (GNUNET_OK != TALER_MINT_DB_commit (db_conn)) | 731 | if (GNUNET_OK != |
732 | TALER_MINT_DB_commit (db_conn)) | ||
682 | { | 733 | { |
683 | GNUNET_break (0); | 734 | LOG_WARNING ("/refresh/melt transaction commit failed\n"); |
684 | return MHD_NO; | 735 | return TALER_MINT_reply_commit_error (connection); |
685 | } | 736 | } |
686 | if (GNUNET_OK != | 737 | if (GNUNET_OK != |
687 | (res = TALER_MINT_DB_get_refresh_session (db_conn, | 738 | (res = TALER_MINT_DB_get_refresh_session (db_conn, |
@@ -795,11 +846,11 @@ TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection, | |||
795 | return MHD_NO; | 846 | return MHD_NO; |
796 | } | 847 | } |
797 | 848 | ||
798 | if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn)) | 849 | if (GNUNET_OK != |
850 | TALER_MINT_DB_transaction (db_conn)) | ||
799 | { | 851 | { |
800 | // FIXME: return 'internal error'? | ||
801 | GNUNET_break (0); | 852 | GNUNET_break (0); |
802 | return MHD_NO; | 853 | return TALER_MINT_reply_internal_db_error (connection); |
803 | } | 854 | } |
804 | 855 | ||
805 | /* Re-fetch the session information from the database, | 856 | /* Re-fetch the session information from the database, |
@@ -816,11 +867,11 @@ TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection, | |||
816 | return MHD_NO; | 867 | return MHD_NO; |
817 | } | 868 | } |
818 | 869 | ||
819 | if (GNUNET_OK != TALER_MINT_DB_commit (db_conn)) | 870 | if (GNUNET_OK != |
871 | TALER_MINT_DB_commit (db_conn)) | ||
820 | { | 872 | { |
821 | // FIXME: return 'internal error'? | 873 | LOG_WARNING ("/refresh/commit transaction commit failed\n"); |
822 | GNUNET_break (0); | 874 | return TALER_MINT_reply_commit_error (connection); |
823 | return MHD_NO; | ||
824 | } | 875 | } |
825 | 876 | ||
826 | return TALER_MINT_reply_refresh_commit_success (connection, &refresh_session); | 877 | return TALER_MINT_reply_refresh_commit_success (connection, &refresh_session); |
@@ -1095,11 +1146,11 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection, | |||
1095 | } | 1146 | } |
1096 | 1147 | ||
1097 | 1148 | ||
1098 | if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn)) | 1149 | if (GNUNET_OK != |
1150 | TALER_MINT_DB_transaction (db_conn)) | ||
1099 | { | 1151 | { |
1100 | GNUNET_break (0); | 1152 | GNUNET_break (0); |
1101 | // FIXME: return error code! | 1153 | return TALER_MINT_reply_internal_db_error (connection); |
1102 | return MHD_NO; | ||
1103 | } | 1154 | } |
1104 | 1155 | ||
1105 | for (j = 0; j < refresh_session.num_newcoins; j++) | 1156 | for (j = 0; j < refresh_session.num_newcoins; j++) |
@@ -1169,10 +1220,11 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection, | |||
1169 | return MHD_NO; | 1220 | return MHD_NO; |
1170 | } | 1221 | } |
1171 | 1222 | ||
1172 | if (GNUNET_OK != TALER_MINT_DB_commit (db_conn)) | 1223 | if (GNUNET_OK != |
1224 | TALER_MINT_DB_commit (db_conn)) | ||
1173 | { | 1225 | { |
1174 | GNUNET_break (0); | 1226 | LOG_WARNING ("/refresh/reveal transaction commit failed\n"); |
1175 | return MHD_NO; | 1227 | return TALER_MINT_reply_commit_error (connection); |
1176 | } | 1228 | } |
1177 | 1229 | ||
1178 | return helper_refresh_reveal_send_response (connection, | 1230 | return helper_refresh_reveal_send_response (connection, |