aboutsummaryrefslogtreecommitdiff
path: root/src/mint/taler-mint-httpd_db.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mint/taler-mint-httpd_db.c')
-rw-r--r--src/mint/taler-mint-httpd_db.c170
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,