aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-01-29 00:45:07 +0100
committerChristian Grothoff <christian@grothoff.org>2015-01-29 00:45:07 +0100
commit758ce80519f17b580807f432192eae9ff13cb418 (patch)
tree376867e94f59dd34caa0856eed104deed9b25dc3
parent8adde040ab5c3fdc40b06537d3bab1aa60ecc5e5 (diff)
downloadexchange-758ce80519f17b580807f432192eae9ff13cb418.tar.gz
exchange-758ce80519f17b580807f432192eae9ff13cb418.zip
clean up /withdraw/sign logic
-rw-r--r--src/mint/taler-mint-httpd_db.c170
-rw-r--r--src/mint/taler-mint-httpd_responses.c78
-rw-r--r--src/mint/taler-mint-httpd_responses.h14
3 files changed, 191 insertions, 71 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,
diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c
index bad87429c..ffb764a1d 100644
--- a/src/mint/taler-mint-httpd_responses.c
+++ b/src/mint/taler-mint-httpd_responses.c
@@ -351,26 +351,25 @@ TALER_MINT_reply_insufficient_funds (struct MHD_Connection *connection,
351 351
352 352
353/** 353/**
354 * Send reserve status information to client. 354 * Compile the history of a reserve into a JSON object
355 * and calculate the total balance.
355 * 356 *
356 * @param connection connection to the client 357 * @param rh reserve history to JSON-ify
357 * @param rh reserve history to return 358 * @param balance[OUT] set to current reserve balance
358 * @return MHD result code 359 * @return json representation of the @a rh
359 */ 360 */
360int 361static json_t *
361TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection, 362compile_reserve_history (const struct ReserveHistory *rh,
362 const struct ReserveHistory *rh) 363 struct TALER_Amount *balance)
363{ 364{
364 struct TALER_Amount deposit_total; 365 struct TALER_Amount deposit_total;
365 struct TALER_Amount withdraw_total; 366 struct TALER_Amount withdraw_total;
366 struct TALER_Amount balance;
367 struct TALER_Amount value; 367 struct TALER_Amount value;
368 json_t *json_balance;
369 json_t *json_history; 368 json_t *json_history;
370 int ret; 369 int ret;
371 struct MintKeyState *key_state;
372 const struct ReserveHistory *pos; 370 const struct ReserveHistory *pos;
373 struct TALER_MINT_DenomKeyIssuePriv *dki; 371 struct TALER_MINT_DenomKeyIssuePriv *dki;
372 struct MintKeyState *key_state;
374 373
375 json_history = json_array (); 374 json_history = json_array ();
376 ret = 0; 375 ret = 0;
@@ -425,8 +424,30 @@ TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
425 } 424 }
426 TALER_MINT_key_state_release (key_state); 425 TALER_MINT_key_state_release (key_state);
427 426
428 balance = TALER_amount_subtract (deposit_total, 427 *balance = TALER_amount_subtract (deposit_total,
429 withdraw_total); 428 withdraw_total);
429 return json_history;
430}
431
432
433/**
434 * Send reserve status information to client.
435 *
436 * @param connection connection to the client
437 * @param rh reserve history to return
438 * @return MHD result code
439 */
440int
441TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
442 const struct ReserveHistory *rh)
443{
444 json_t *json_balance;
445 json_t *json_history;
446 struct TALER_Amount balance;
447 int ret;
448
449 json_history = compile_reserve_history (rh,
450 &balance);
430 json_balance = TALER_JSON_from_amount (balance); 451 json_balance = TALER_JSON_from_amount (balance);
431 ret = TALER_MINT_reply_json_pack (connection, 452 ret = TALER_MINT_reply_json_pack (connection,
432 MHD_HTTP_OK, 453 MHD_HTTP_OK,
@@ -440,6 +461,39 @@ TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
440 461
441 462
442/** 463/**
464 * Send reserve status information to client with the
465 * message that we have insufficient funds for the
466 * requested /withdraw/sign operation.
467 *
468 * @param connection connection to the client
469 * @param rh reserve history to return
470 * @return MHD result code
471 */
472int
473TALER_MINT_reply_withdraw_sign_insufficient_funds (struct MHD_Connection *connection,
474 const struct ReserveHistory *rh)
475{
476 json_t *json_balance;
477 json_t *json_history;
478 struct TALER_Amount balance;
479 int ret;
480
481 json_history = compile_reserve_history (rh,
482 &balance);
483 json_balance = TALER_JSON_from_amount (balance);
484 ret = TALER_MINT_reply_json_pack (connection,
485 MHD_HTTP_PAYMENT_REQUIRED,
486 "{s:s, s:o, s:o}",
487 "error", "Insufficient funds"
488 "balance", json_balance,
489 "history", json_history);
490 json_decref (json_history);
491 json_decref (json_balance);
492 return ret;
493}
494
495
496/**
443 * Send blinded coin information to client. 497 * Send blinded coin information to client.
444 * 498 *
445 * @param connection connection to the client 499 * @param connection connection to the client
diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h
index 5e2f98638..ebe1038fd 100644
--- a/src/mint/taler-mint-httpd_responses.h
+++ b/src/mint/taler-mint-httpd_responses.h
@@ -209,6 +209,20 @@ TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
209 209
210 210
211/** 211/**
212 * Send reserve status information to client with the
213 * message that we have insufficient funds for the
214 * requested /withdraw/sign operation.
215 *
216 * @param connection connection to the client
217 * @param rh reserve history to return
218 * @return MHD result code
219 */
220int
221TALER_MINT_reply_withdraw_sign_insufficient_funds (struct MHD_Connection *connection,
222 const struct ReserveHistory *rh);
223
224
225/**
212 * Send blinded coin information to client. 226 * Send blinded coin information to client.
213 * 227 *
214 * @param connection connection to the client 228 * @param connection connection to the client