diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-01-28 22:18:53 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-01-28 22:18:53 +0100 |
commit | 1466048e4d19a198a33d1f224dbb5a25fa42b9c2 (patch) | |
tree | 5ac4f3b667309e7c5a0f0f6b3ae3b3ce610da73b | |
parent | fd1bcfecfa0698f1c29f8f530e511034f92546c7 (diff) | |
download | exchange-1466048e4d19a198a33d1f224dbb5a25fa42b9c2.tar.gz exchange-1466048e4d19a198a33d1f224dbb5a25fa42b9c2.zip |
cleaning up mint_db API
-rw-r--r-- | src/mint/mint.h | 30 | ||||
-rw-r--r-- | src/mint/mint_db.c | 932 | ||||
-rw-r--r-- | src/mint/mint_db.h | 447 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_db.c | 79 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_deposit.c | 23 | ||||
-rw-r--r-- | src/mint/test_mint_deposits.c | 40 |
6 files changed, 892 insertions, 659 deletions
diff --git a/src/mint/mint.h b/src/mint/mint.h index b29162b20..1e1221157 100644 --- a/src/mint/mint.h +++ b/src/mint/mint.h | |||
@@ -35,36 +35,6 @@ | |||
35 | 35 | ||
36 | 36 | ||
37 | 37 | ||
38 | /** | ||
39 | * Information we keep for a withdrawn coin to reproduce | ||
40 | * the /withdraw operation if needed, and to have proof | ||
41 | * that a reserve was drained by this amount. | ||
42 | */ | ||
43 | struct CollectableBlindcoin | ||
44 | { | ||
45 | |||
46 | /** | ||
47 | * Our signature over the (blinded) coin. | ||
48 | */ | ||
49 | struct GNUNET_CRYPTO_rsa_Signature *sig; | ||
50 | |||
51 | /** | ||
52 | * Denomination key (which coin was generated). | ||
53 | */ | ||
54 | struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub; | ||
55 | |||
56 | /** | ||
57 | * Public key of the reserve that was drained. | ||
58 | */ | ||
59 | struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub; | ||
60 | |||
61 | /** | ||
62 | * Signature confirming the withdrawl, matching @e reserve_pub, | ||
63 | * @e denom_pub and @e h_blind. | ||
64 | */ | ||
65 | struct GNUNET_CRYPTO_EddsaSignature reserve_sig; | ||
66 | }; | ||
67 | |||
68 | 38 | ||
69 | /** | 39 | /** |
70 | * Global information for a refreshing session. | 40 | * Global information for a refreshing session. |
diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 0f233a5ae..dcde03dc1 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c | |||
@@ -54,127 +54,49 @@ static char *TALER_MINT_db_connection_cfg_str; | |||
54 | } while (0) | 54 | } while (0) |
55 | 55 | ||
56 | 56 | ||
57 | /** | ||
58 | * Locate the response for a /withdraw request under the | ||
59 | * key of the hash of the blinded message. | ||
60 | * | ||
61 | * @param db_conn database connection to use | ||
62 | * @param h_blind hash of the blinded message | ||
63 | * @param collectable corresponding collectable coin (blind signature) | ||
64 | * if a coin is found | ||
65 | * @return #GNUNET_SYSERR on internal error | ||
66 | * #GNUNET_NO if the collectable was not found | ||
67 | * #GNUNET_YES on success | ||
68 | */ | ||
69 | int | ||
70 | TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn, | ||
71 | const struct GNUNET_HashCode *h_blind, | ||
72 | struct CollectableBlindcoin *collectable) | ||
73 | { | ||
74 | PGresult *result; | ||
75 | struct TALER_DB_QueryParam params[] = { | ||
76 | TALER_DB_QUERY_PARAM_PTR (h_blind), | ||
77 | TALER_DB_QUERY_PARAM_END | ||
78 | }; | ||
79 | char *sig_buf; | ||
80 | size_t sig_buf_size; | ||
81 | 57 | ||
82 | result = TALER_DB_exec_prepared (db_conn, | ||
83 | "get_collectable_blindcoins", | ||
84 | params); | ||
85 | |||
86 | if (PGRES_TUPLES_OK != PQresultStatus (result)) | ||
87 | { | ||
88 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
89 | "Query failed: %s\n", | ||
90 | PQresultErrorMessage (result)); | ||
91 | PQclear (result); | ||
92 | return GNUNET_SYSERR; | ||
93 | } | ||
94 | if (0 == PQntuples (result)) | ||
95 | { | ||
96 | PQclear (result); | ||
97 | return GNUNET_NO; | ||
98 | } | ||
99 | 58 | ||
100 | struct TALER_DB_ResultSpec rs[] = { | ||
101 | TALER_DB_RESULT_SPEC_VAR("blind_sig", &sig_buf, &sig_buf_size), | ||
102 | TALER_DB_RESULT_SPEC("denom_pub", &collectable->denom_pub), | ||
103 | TALER_DB_RESULT_SPEC("reserve_sig", &collectable->reserve_sig), | ||
104 | TALER_DB_RESULT_SPEC("reserve_pub", &collectable->reserve_pub), | ||
105 | TALER_DB_RESULT_SPEC_END | ||
106 | }; | ||
107 | 59 | ||
108 | if (GNUNET_OK != TALER_DB_extract_result (result, rs, 0)) | 60 | int |
109 | { | 61 | TALER_TALER_DB_extract_amount_nbo (PGresult *result, |
110 | GNUNET_break (0); | 62 | unsigned int row, |
111 | PQclear (result); | 63 | int indices[3], |
64 | struct TALER_AmountNBO *denom_nbo) | ||
65 | { | ||
66 | if ((indices[0] < 0) || (indices[1] < 0) || (indices[2] < 0)) | ||
67 | return GNUNET_NO; | ||
68 | if (sizeof (uint32_t) != PQgetlength (result, row, indices[0])) | ||
112 | return GNUNET_SYSERR; | 69 | return GNUNET_SYSERR; |
113 | } | 70 | if (sizeof (uint32_t) != PQgetlength (result, row, indices[1])) |
114 | PQclear (result); | 71 | return GNUNET_SYSERR; |
72 | if (PQgetlength (result, row, indices[2]) > TALER_CURRENCY_LEN) | ||
73 | return GNUNET_SYSERR; | ||
74 | denom_nbo->value = *(uint32_t *) PQgetvalue (result, row, indices[0]); | ||
75 | denom_nbo->fraction = *(uint32_t *) PQgetvalue (result, row, indices[1]); | ||
76 | memset (denom_nbo->currency, 0, TALER_CURRENCY_LEN); | ||
77 | memcpy (denom_nbo->currency, PQgetvalue (result, row, indices[2]), PQgetlength (result, row, indices[2])); | ||
115 | return GNUNET_OK; | 78 | return GNUNET_OK; |
116 | } | 79 | } |
117 | 80 | ||
118 | 81 | ||
119 | /** | ||
120 | * Store collectable bit coin under the corresponding | ||
121 | * hash of the blinded message. | ||
122 | * | ||
123 | * @param db_conn database connection to use | ||
124 | * @param h_blind hash of the blinded message | ||
125 | * @param collectable corresponding collectable coin (blind signature) | ||
126 | * if a coin is found | ||
127 | * @return #GNUNET_SYSERR on internal error | ||
128 | * #GNUNET_NO if the collectable was not found | ||
129 | * #GNUNET_YES on success | ||
130 | */ | ||
131 | int | 82 | int |
132 | TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn, | 83 | TALER_TALER_DB_extract_amount (PGresult *result, |
133 | const struct GNUNET_HashCode *h_blind, | 84 | unsigned int row, |
134 | const struct CollectableBlindcoin *collectable) | 85 | int indices[3], |
86 | struct TALER_Amount *denom) | ||
135 | { | 87 | { |
136 | PGresult *result; | 88 | struct TALER_AmountNBO denom_nbo; |
137 | char *sig_buf; | 89 | int res; |
138 | size_t sig_buf_size; | ||
139 | |||
140 | sig_buf_size = GNUNET_CRYPTO_rsa_signature_encode (collectable->sig, | ||
141 | &sig_buf); | ||
142 | { | ||
143 | struct TALER_DB_QueryParam params[] = { | ||
144 | TALER_DB_QUERY_PARAM_PTR (&h_blind), | ||
145 | TALER_DB_QUERY_PARAM_PTR_SIZED (sig_buf, sig_buf_size), | ||
146 | TALER_DB_QUERY_PARAM_PTR (&collectable->denom_pub), | ||
147 | TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_pub), | ||
148 | TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_sig), | ||
149 | TALER_DB_QUERY_PARAM_END | ||
150 | }; | ||
151 | |||
152 | result = TALER_DB_exec_prepared (db_conn, | ||
153 | "insert_collectable_blindcoins", | ||
154 | params); | ||
155 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | ||
156 | { | ||
157 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
158 | "Query failed: %s\n", | ||
159 | PQresultErrorMessage (result)); | ||
160 | PQclear (result); | ||
161 | return GNUNET_SYSERR; | ||
162 | } | ||
163 | 90 | ||
164 | if (0 != strcmp ("1", PQcmdTuples (result))) | 91 | res = TALER_TALER_DB_extract_amount_nbo (result, row, indices, &denom_nbo); |
165 | { | 92 | if (GNUNET_OK != res) |
166 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 93 | return res; |
167 | "Insert failed (updated '%s' tupes instead of '1')\n", | 94 | *denom = TALER_amount_ntoh (denom_nbo); |
168 | PQcmdTuples (result)); | ||
169 | PQclear (result); | ||
170 | return GNUNET_SYSERR; | ||
171 | } | ||
172 | PQclear (result); | ||
173 | } | ||
174 | return GNUNET_OK; | 95 | return GNUNET_OK; |
175 | } | 96 | } |
176 | 97 | ||
177 | 98 | ||
99 | |||
178 | int | 100 | int |
179 | TALER_MINT_DB_get_reserve (PGconn *db_conn, | 101 | TALER_MINT_DB_get_reserve (PGconn *db_conn, |
180 | const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub, | 102 | const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub, |
@@ -681,88 +603,51 @@ TALER_MINT_DB_prepare (PGconn *db_conn) | |||
681 | } | 603 | } |
682 | PQclear (result); | 604 | PQclear (result); |
683 | 605 | ||
684 | if (GNUNET_OK != TALER_MINT_DB_prepare_deposits (db_conn)) | 606 | result = PQprepare (db_conn, "insert_deposit", |
685 | { | 607 | "INSERT INTO deposits (" |
686 | GNUNET_break (0); | 608 | "coin_pub," |
687 | return GNUNET_SYSERR; | 609 | "denom_pub," |
688 | } | 610 | "transaction_id," |
689 | 611 | "amount_value," | |
690 | return GNUNET_OK; | 612 | "amount_fraction," |
691 | } | 613 | "amount_currency," |
692 | 614 | "merchant_pub," | |
693 | 615 | "h_contract," | |
694 | /** | 616 | "h_wire," |
695 | * Roll back the current transaction of a database connection. | 617 | "coin_sig," |
696 | * | 618 | "wire" |
697 | * @param db_conn the database connection | 619 | ") VALUES (" |
698 | * @return GNUNET_OK on success | 620 | "$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11" |
699 | */ | 621 | ")", |
700 | int | 622 | 11, NULL); |
701 | TALER_MINT_DB_rollback (PGconn *db_conn) | 623 | EXITIF (PGRES_COMMAND_OK != PQresultStatus(result)); |
702 | { | ||
703 | PGresult *result; | ||
704 | |||
705 | result = PQexec(db_conn, "ROLLBACK"); | ||
706 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | ||
707 | { | ||
708 | PQclear (result); | ||
709 | GNUNET_break (0); | ||
710 | return GNUNET_SYSERR; | ||
711 | } | ||
712 | |||
713 | PQclear (result); | 624 | PQclear (result); |
714 | return GNUNET_OK; | ||
715 | } | ||
716 | |||
717 | |||
718 | /** | ||
719 | * Roll back the current transaction of a database connection. | ||
720 | * | ||
721 | * @param db_conn the database connection | ||
722 | * @return GNUNET_OK on success | ||
723 | */ | ||
724 | int | ||
725 | TALER_MINT_DB_commit (PGconn *db_conn) | ||
726 | { | ||
727 | PGresult *result; | ||
728 | |||
729 | result = PQexec(db_conn, "COMMIT"); | ||
730 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | ||
731 | { | ||
732 | PQclear (result); | ||
733 | GNUNET_break (0); | ||
734 | return GNUNET_SYSERR; | ||
735 | } | ||
736 | 625 | ||
626 | result = PQprepare (db_conn, "get_deposit", | ||
627 | "SELECT " | ||
628 | "coin_pub," | ||
629 | "denom_pub," | ||
630 | "transaction_id," | ||
631 | "amount_value," | ||
632 | "amount_fraction," | ||
633 | "amount_currency," | ||
634 | "merchant_pub," | ||
635 | "h_contract," | ||
636 | "h_wire," | ||
637 | "coin_sig" | ||
638 | " FROM deposits WHERE (" | ||
639 | "coin_pub = $1" | ||
640 | ")", | ||
641 | 1, NULL); | ||
642 | EXITIF (PGRES_COMMAND_OK != PQresultStatus(result)); | ||
737 | PQclear (result); | 643 | PQclear (result); |
738 | return GNUNET_OK; | ||
739 | } | ||
740 | 644 | ||
645 | return GNUNET_OK; | ||
741 | 646 | ||
742 | /** | 647 | EXITIF_exit: |
743 | * Start a transaction. | 648 | break_db_err (result); |
744 | * | ||
745 | * @param db_conn the database connection | ||
746 | * @return GNUNET_OK on success | ||
747 | */ | ||
748 | int | ||
749 | TALER_MINT_DB_transaction (PGconn *db_conn) | ||
750 | { | ||
751 | PGresult *result; | ||
752 | |||
753 | result = PQexec(db_conn, "BEGIN"); | ||
754 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | ||
755 | { | ||
756 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
757 | "Can't start transaction: %s\n", | ||
758 | PQresultErrorMessage (result)); | ||
759 | PQclear (result); | ||
760 | GNUNET_break (0); | ||
761 | return GNUNET_SYSERR; | ||
762 | } | ||
763 | |||
764 | PQclear (result); | 649 | PQclear (result); |
765 | return GNUNET_OK; | 650 | return GNUNET_SYSERR; |
766 | } | 651 | } |
767 | 652 | ||
768 | 653 | ||
@@ -1495,91 +1380,6 @@ TALER_MINT_DB_get_refresh_collectable (PGconn *db_conn, | |||
1495 | } | 1380 | } |
1496 | 1381 | ||
1497 | 1382 | ||
1498 | |||
1499 | int | ||
1500 | TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn, | ||
1501 | const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub, | ||
1502 | uint16_t oldcoin_index, | ||
1503 | const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub, | ||
1504 | const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub) | ||
1505 | { | ||
1506 | uint16_t oldcoin_index_nbo = htons (oldcoin_index); | ||
1507 | char *buf; | ||
1508 | size_t buf_size; | ||
1509 | PGresult *result; | ||
1510 | |||
1511 | buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pub, | ||
1512 | &buf); | ||
1513 | { | ||
1514 | struct TALER_DB_QueryParam params[] = { | ||
1515 | TALER_DB_QUERY_PARAM_PTR(session_pub), | ||
1516 | TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo), | ||
1517 | TALER_DB_QUERY_PARAM_PTR(coin_pub), | ||
1518 | TALER_DB_QUERY_PARAM_PTR_SIZED(buf, buf_size), | ||
1519 | TALER_DB_QUERY_PARAM_END | ||
1520 | }; | ||
1521 | result = TALER_DB_exec_prepared (db_conn, "insert_refresh_melt", params); | ||
1522 | } | ||
1523 | GNUNET_free (buf); | ||
1524 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | ||
1525 | { | ||
1526 | break_db_err (result); | ||
1527 | PQclear (result); | ||
1528 | return GNUNET_SYSERR; | ||
1529 | } | ||
1530 | PQclear (result); | ||
1531 | return GNUNET_OK; | ||
1532 | } | ||
1533 | |||
1534 | |||
1535 | |||
1536 | int | ||
1537 | TALER_MINT_DB_get_refresh_melt (PGconn *db_conn, | ||
1538 | const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub, | ||
1539 | uint16_t oldcoin_index, | ||
1540 | struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub) | ||
1541 | { | ||
1542 | uint16_t oldcoin_index_nbo = htons (oldcoin_index); | ||
1543 | struct TALER_DB_QueryParam params[] = { | ||
1544 | TALER_DB_QUERY_PARAM_PTR(session_pub), | ||
1545 | TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo), | ||
1546 | TALER_DB_QUERY_PARAM_END | ||
1547 | }; | ||
1548 | |||
1549 | PGresult *result = TALER_DB_exec_prepared (db_conn, "get_refresh_melt", params); | ||
1550 | |||
1551 | if (PGRES_TUPLES_OK != PQresultStatus (result)) | ||
1552 | { | ||
1553 | break_db_err (result); | ||
1554 | PQclear (result); | ||
1555 | return GNUNET_SYSERR; | ||
1556 | } | ||
1557 | |||
1558 | if (0 == PQntuples (result)) | ||
1559 | { | ||
1560 | PQclear (result); | ||
1561 | return GNUNET_NO; | ||
1562 | } | ||
1563 | |||
1564 | GNUNET_assert (1 == PQntuples (result)); | ||
1565 | |||
1566 | struct TALER_DB_ResultSpec rs[] = { | ||
1567 | TALER_DB_RESULT_SPEC("coin_pub", coin_pub), | ||
1568 | TALER_DB_RESULT_SPEC_END | ||
1569 | }; | ||
1570 | |||
1571 | if (GNUNET_OK != TALER_DB_extract_result (result, rs, 0)) | ||
1572 | { | ||
1573 | PQclear (result); | ||
1574 | GNUNET_break (0); | ||
1575 | return GNUNET_SYSERR; | ||
1576 | } | ||
1577 | |||
1578 | PQclear (result); | ||
1579 | return GNUNET_OK; | ||
1580 | } | ||
1581 | |||
1582 | |||
1583 | int | 1383 | int |
1584 | TALER_db_get_link (PGconn *db_conn, | 1384 | TALER_db_get_link (PGconn *db_conn, |
1585 | const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub, | 1385 | const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub, |
@@ -1744,319 +1544,491 @@ TALER_db_get_transfer (PGconn *db_conn, | |||
1744 | } | 1544 | } |
1745 | 1545 | ||
1746 | 1546 | ||
1547 | |||
1548 | |||
1549 | |||
1550 | // Chaos | ||
1551 | //////////////////////////////////////////////////////////////// | ||
1552 | // Order | ||
1553 | |||
1554 | |||
1555 | |||
1556 | |||
1557 | |||
1558 | |||
1559 | /** | ||
1560 | * Close thread-local database connection when a thread is destroyed. | ||
1561 | * | ||
1562 | * @param closure we get from pthreads (the db handle) | ||
1563 | */ | ||
1564 | static void | ||
1565 | db_conn_destroy (void *cls) | ||
1566 | { | ||
1567 | PGconn *db_conn = cls; | ||
1568 | if (NULL != db_conn) | ||
1569 | PQfinish (db_conn); | ||
1570 | } | ||
1571 | |||
1572 | |||
1573 | /** | ||
1574 | * Initialize database subsystem. | ||
1575 | * | ||
1576 | * @param connection_cfg configuration to use to talk to DB | ||
1577 | * @return #GNUNET_OK on success | ||
1578 | */ | ||
1747 | int | 1579 | int |
1748 | TALER_MINT_DB_init_deposits (PGconn *conn, int tmp) | 1580 | TALER_MINT_DB_init (const char *connection_cfg) |
1749 | { | 1581 | { |
1750 | const char *tmp_str = (1 == tmp) ? "TEMPORARY" : ""; | 1582 | if (0 != pthread_key_create (&db_conn_threadlocal, |
1751 | char *sql; | 1583 | &db_conn_destroy)) |
1752 | PGresult *res; | 1584 | { |
1753 | int ret; | 1585 | fprintf (stderr, |
1586 | "Can't create pthread key.\n"); | ||
1587 | return GNUNET_SYSERR; | ||
1588 | } | ||
1589 | TALER_MINT_db_connection_cfg_str = GNUNET_strdup (connection_cfg); | ||
1590 | return GNUNET_OK; | ||
1591 | } | ||
1592 | |||
1593 | |||
1594 | /** | ||
1595 | * Get the thread-local database-handle. | ||
1596 | * Connect to the db if the connection does not exist yet. | ||
1597 | * | ||
1598 | * @return the database connection, or NULL on error | ||
1599 | */ | ||
1600 | PGconn * | ||
1601 | TALER_MINT_DB_get_connection (void) | ||
1602 | { | ||
1603 | PGconn *db_conn; | ||
1604 | |||
1605 | if (NULL != (db_conn = pthread_getspecific (db_conn_threadlocal))) | ||
1606 | return db_conn; | ||
1607 | |||
1608 | db_conn = PQconnectdb (TALER_MINT_db_connection_cfg_str); | ||
1609 | |||
1610 | if (CONNECTION_OK != PQstatus (db_conn)) | ||
1611 | { | ||
1612 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1613 | "db connection failed: %s\n", | ||
1614 | PQerrorMessage (db_conn)); | ||
1615 | GNUNET_break (0); | ||
1616 | return NULL; | ||
1617 | } | ||
1754 | 1618 | ||
1755 | res = NULL; | 1619 | if (GNUNET_OK != TALER_MINT_DB_prepare (db_conn)) |
1756 | (void) GNUNET_asprintf (&sql, | 1620 | { |
1757 | "CREATE %1$s TABLE IF NOT EXISTS deposits (" | 1621 | GNUNET_break (0); |
1758 | " coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (length(coin_pub)=32)" | 1622 | return NULL; |
1759 | ",denom_pub BYTEA NOT NULL CHECK (length(denom_pub)=32)" | ||
1760 | ",transaction_id INT8 NOT NULL" | ||
1761 | ",amount_value INT4 NOT NULL" | ||
1762 | ",amount_fraction INT4 NOT NULL" | ||
1763 | ",amount_currency VARCHAR(4) NOT NULL" | ||
1764 | ",merchant_pub BYTEA NOT NULL" | ||
1765 | ",h_contract BYTEA NOT NULL CHECK (length(h_contract)=64)" | ||
1766 | ",h_wire BYTEA NOT NULL CHECK (length(h_wire)=64)" | ||
1767 | ",coin_sig BYTEA NOT NULL CHECK (length(coin_sig)=64)" | ||
1768 | ",wire TEXT NOT NULL" | ||
1769 | ")", | ||
1770 | tmp_str); | ||
1771 | res = PQexec (conn, sql); | ||
1772 | GNUNET_free (sql); | ||
1773 | if (PGRES_COMMAND_OK != PQresultStatus (res)) | ||
1774 | { | ||
1775 | break_db_err (res); | ||
1776 | ret = GNUNET_SYSERR; | ||
1777 | } | 1623 | } |
1778 | else | 1624 | if (0 != pthread_setspecific (db_conn_threadlocal, |
1779 | ret = GNUNET_OK; | 1625 | db_conn)) |
1780 | PQclear (res); | 1626 | { |
1781 | return ret; | 1627 | GNUNET_break (0); |
1628 | return NULL; | ||
1629 | } | ||
1630 | return db_conn; | ||
1782 | } | 1631 | } |
1783 | 1632 | ||
1633 | |||
1634 | /** | ||
1635 | * Start a transaction. | ||
1636 | * | ||
1637 | * @param db_conn the database connection | ||
1638 | * @return #GNUNET_OK on success | ||
1639 | */ | ||
1784 | int | 1640 | int |
1785 | TALER_MINT_DB_prepare_deposits (PGconn *db_conn) | 1641 | TALER_MINT_DB_transaction (PGconn *db_conn) |
1786 | { | 1642 | { |
1787 | PGresult *result; | 1643 | PGresult *result; |
1788 | 1644 | ||
1789 | result = PQprepare (db_conn, "insert_deposit", | 1645 | result = PQexec(db_conn, "BEGIN"); |
1790 | "INSERT INTO deposits (" | 1646 | if (PGRES_COMMAND_OK != PQresultStatus (result)) |
1791 | "coin_pub," | 1647 | { |
1792 | "denom_pub," | 1648 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1793 | "transaction_id," | 1649 | "Can't start transaction: %s\n", |
1794 | "amount_value," | 1650 | PQresultErrorMessage (result)); |
1795 | "amount_fraction," | 1651 | PQclear (result); |
1796 | "amount_currency," | 1652 | GNUNET_break (0); |
1797 | "merchant_pub," | 1653 | return GNUNET_SYSERR; |
1798 | "h_contract," | 1654 | } |
1799 | "h_wire," | ||
1800 | "coin_sig," | ||
1801 | "wire" | ||
1802 | ") VALUES (" | ||
1803 | "$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11" | ||
1804 | ")", | ||
1805 | 11, NULL); | ||
1806 | EXITIF (PGRES_COMMAND_OK != PQresultStatus(result)); | ||
1807 | PQclear (result); | ||
1808 | 1655 | ||
1809 | result = PQprepare (db_conn, "get_deposit", | ||
1810 | "SELECT " | ||
1811 | "coin_pub," | ||
1812 | "denom_pub," | ||
1813 | "transaction_id," | ||
1814 | "amount_value," | ||
1815 | "amount_fraction," | ||
1816 | "amount_currency," | ||
1817 | "merchant_pub," | ||
1818 | "h_contract," | ||
1819 | "h_wire," | ||
1820 | "coin_sig" | ||
1821 | " FROM deposits WHERE (" | ||
1822 | "coin_pub = $1" | ||
1823 | ")", | ||
1824 | 1, NULL); | ||
1825 | EXITIF (PGRES_COMMAND_OK != PQresultStatus(result)); | ||
1826 | PQclear (result); | 1656 | PQclear (result); |
1827 | |||
1828 | return GNUNET_OK; | 1657 | return GNUNET_OK; |
1658 | } | ||
1659 | |||
1660 | |||
1661 | /** | ||
1662 | * Roll back the current transaction of a database connection. | ||
1663 | * | ||
1664 | * @param db_conn the database connection | ||
1665 | * @return #GNUNET_OK on success | ||
1666 | */ | ||
1667 | int | ||
1668 | TALER_MINT_DB_rollback (PGconn *db_conn) | ||
1669 | { | ||
1670 | PGresult *result; | ||
1671 | |||
1672 | result = PQexec(db_conn, | ||
1673 | "ROLLBACK"); | ||
1674 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | ||
1675 | { | ||
1676 | PQclear (result); | ||
1677 | GNUNET_break (0); | ||
1678 | return GNUNET_SYSERR; | ||
1679 | } | ||
1829 | 1680 | ||
1830 | EXITIF_exit: | ||
1831 | break_db_err (result); | ||
1832 | PQclear (result); | 1681 | PQclear (result); |
1833 | return GNUNET_SYSERR; | 1682 | return GNUNET_OK; |
1834 | } | 1683 | } |
1835 | 1684 | ||
1836 | 1685 | ||
1686 | /** | ||
1687 | * Commit the current transaction of a database connection. | ||
1688 | * | ||
1689 | * @param db_conn the database connection | ||
1690 | * @return #GNUNET_OK on success | ||
1691 | */ | ||
1837 | int | 1692 | int |
1838 | TALER_MINT_DB_insert_deposit (PGconn *db_conn, | 1693 | TALER_MINT_DB_commit (PGconn *db_conn) |
1839 | const struct Deposit *deposit) | ||
1840 | { | 1694 | { |
1841 | struct TALER_DB_QueryParam params[]= { | ||
1842 | TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub), | ||
1843 | TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_pub), // FIXME! | ||
1844 | TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_sig), // FIXME! | ||
1845 | TALER_DB_QUERY_PARAM_PTR (&deposit->transaction_id), | ||
1846 | TALER_DB_QUERY_PARAM_PTR (&deposit->purpose), // FIXME: enum Ok here? | ||
1847 | TALER_DB_QUERY_PARAM_PTR (&deposit->amount.value), | ||
1848 | TALER_DB_QUERY_PARAM_PTR (&deposit->amount.fraction), | ||
1849 | TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->amount.currency, | ||
1850 | strlen (deposit->amount.currency)), | ||
1851 | TALER_DB_QUERY_PARAM_PTR (&deposit->merchant_pub), | ||
1852 | TALER_DB_QUERY_PARAM_PTR (&deposit->h_contract), | ||
1853 | TALER_DB_QUERY_PARAM_PTR (&deposit->h_wire), | ||
1854 | TALER_DB_QUERY_PARAM_PTR (&deposit->csig), | ||
1855 | TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->wire, | ||
1856 | strlen ("FIXME")), // FIXME! json! | ||
1857 | TALER_DB_QUERY_PARAM_END | ||
1858 | }; | ||
1859 | PGresult *result; | 1695 | PGresult *result; |
1860 | 1696 | ||
1861 | result = TALER_DB_exec_prepared (db_conn, "insert_deposit", params); | 1697 | result = PQexec(db_conn, |
1698 | "COMMIT"); | ||
1862 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | 1699 | if (PGRES_COMMAND_OK != PQresultStatus (result)) |
1863 | { | 1700 | { |
1864 | break_db_err (result); | ||
1865 | PQclear (result); | 1701 | PQclear (result); |
1702 | GNUNET_break (0); | ||
1866 | return GNUNET_SYSERR; | 1703 | return GNUNET_SYSERR; |
1867 | } | 1704 | } |
1705 | |||
1868 | PQclear (result); | 1706 | PQclear (result); |
1869 | return GNUNET_OK; | 1707 | return GNUNET_OK; |
1870 | } | 1708 | } |
1871 | 1709 | ||
1872 | 1710 | ||
1711 | /** | ||
1712 | * Locate the response for a /withdraw request under the | ||
1713 | * key of the hash of the blinded message. | ||
1714 | * | ||
1715 | * @param db_conn database connection to use | ||
1716 | * @param h_blind hash of the blinded message | ||
1717 | * @param collectable corresponding collectable coin (blind signature) | ||
1718 | * if a coin is found | ||
1719 | * @return #GNUNET_SYSERR on internal error | ||
1720 | * #GNUNET_NO if the collectable was not found | ||
1721 | * #GNUNET_YES on success | ||
1722 | */ | ||
1873 | int | 1723 | int |
1874 | TALER_MINT_DB_get_deposit (PGconn *db_conn, | 1724 | TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn, |
1875 | const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub, | 1725 | const struct GNUNET_HashCode *h_blind, |
1876 | struct Deposit *deposit) | 1726 | struct CollectableBlindcoin *collectable) |
1877 | { | 1727 | { |
1728 | PGresult *result; | ||
1878 | struct TALER_DB_QueryParam params[] = { | 1729 | struct TALER_DB_QueryParam params[] = { |
1879 | TALER_DB_QUERY_PARAM_PTR (coin_pub), | 1730 | TALER_DB_QUERY_PARAM_PTR (h_blind), |
1880 | TALER_DB_QUERY_PARAM_END | 1731 | TALER_DB_QUERY_PARAM_END |
1881 | }; | 1732 | }; |
1882 | PGresult *result; | 1733 | char *sig_buf; |
1734 | size_t sig_buf_size; | ||
1883 | 1735 | ||
1884 | memset (deposit, 0, sizeof (struct Deposit)); | ||
1885 | result = TALER_DB_exec_prepared (db_conn, | 1736 | result = TALER_DB_exec_prepared (db_conn, |
1886 | "get_deposit", | 1737 | "get_collectable_blindcoins", |
1887 | params); | 1738 | params); |
1739 | |||
1888 | if (PGRES_TUPLES_OK != PQresultStatus (result)) | 1740 | if (PGRES_TUPLES_OK != PQresultStatus (result)) |
1889 | { | 1741 | { |
1890 | break_db_err (result); | 1742 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1891 | goto EXITIF_exit; | 1743 | "Query failed: %s\n", |
1744 | PQresultErrorMessage (result)); | ||
1745 | PQclear (result); | ||
1746 | return GNUNET_SYSERR; | ||
1892 | } | 1747 | } |
1893 | |||
1894 | if (0 == PQntuples (result)) | 1748 | if (0 == PQntuples (result)) |
1895 | { | 1749 | { |
1896 | PQclear (result); | 1750 | PQclear (result); |
1897 | return GNUNET_NO; | 1751 | return GNUNET_NO; |
1898 | } | 1752 | } |
1899 | 1753 | ||
1900 | if (1 != PQntuples (result)) | 1754 | struct TALER_DB_ResultSpec rs[] = { |
1901 | { | 1755 | TALER_DB_RESULT_SPEC_VAR("blind_sig", &sig_buf, &sig_buf_size), |
1902 | GNUNET_break (0); | 1756 | TALER_DB_RESULT_SPEC("denom_pub", &collectable->denom_pub), |
1903 | goto EXITIF_exit; | 1757 | TALER_DB_RESULT_SPEC("reserve_sig", &collectable->reserve_sig), |
1904 | } | 1758 | TALER_DB_RESULT_SPEC("reserve_pub", &collectable->reserve_pub), |
1759 | TALER_DB_RESULT_SPEC_END | ||
1760 | }; | ||
1905 | 1761 | ||
1762 | if (GNUNET_OK != TALER_DB_extract_result (result, rs, 0)) | ||
1906 | { | 1763 | { |
1907 | char *denom_sig_buf; | 1764 | GNUNET_break (0); |
1908 | size_t denom_sig_buf_size; | 1765 | PQclear (result); |
1909 | char *dk_buf; | 1766 | return GNUNET_SYSERR; |
1910 | size_t dk_buf_size; | ||
1911 | |||
1912 | struct TALER_DB_ResultSpec rs[] = { | ||
1913 | TALER_DB_RESULT_SPEC ("coin_pub", &deposit->coin.coin_pub), | ||
1914 | TALER_DB_RESULT_SPEC_VAR ("denom_pub", &dk_buf, &dk_buf_size), | ||
1915 | TALER_DB_RESULT_SPEC_VAR ("denom_sig", &denom_sig_buf, &denom_sig_buf_size), | ||
1916 | TALER_DB_RESULT_SPEC ("transaction_id", &deposit->transaction_id), | ||
1917 | TALER_DB_RESULT_SPEC ("merchant_pub", &deposit->merchant_pub), | ||
1918 | TALER_DB_RESULT_SPEC ("h_contract", &deposit->h_contract), | ||
1919 | TALER_DB_RESULT_SPEC ("h_wire", &deposit->h_wire), | ||
1920 | TALER_DB_RESULT_SPEC ("purpose", &deposit->purpose), | ||
1921 | // FIXME: many fields missing... | ||
1922 | TALER_DB_RESULT_SPEC_END | ||
1923 | }; | ||
1924 | EXITIF (GNUNET_OK != | ||
1925 | TALER_DB_extract_result (result, rs, 0)); | ||
1926 | EXITIF (GNUNET_OK != | ||
1927 | TALER_DB_extract_amount (result, 0, | ||
1928 | "amount_value", | ||
1929 | "amount_fraction", | ||
1930 | "amount_currency", | ||
1931 | &deposit->amount)); | ||
1932 | deposit->coin.denom_sig | ||
1933 | = GNUNET_CRYPTO_rsa_signature_decode (denom_sig_buf, | ||
1934 | denom_sig_buf_size); | ||
1935 | deposit->coin.denom_pub | ||
1936 | = GNUNET_CRYPTO_rsa_public_key_decode (dk_buf, | ||
1937 | dk_buf_size); | ||
1938 | } | 1767 | } |
1939 | |||
1940 | PQclear (result); | 1768 | PQclear (result); |
1941 | return GNUNET_OK; | 1769 | return GNUNET_OK; |
1942 | |||
1943 | EXITIF_exit: | ||
1944 | PQclear (result); | ||
1945 | GNUNET_free_non_null (deposit); | ||
1946 | deposit = NULL; | ||
1947 | return GNUNET_SYSERR; | ||
1948 | } | 1770 | } |
1949 | 1771 | ||
1950 | 1772 | ||
1951 | |||
1952 | /** | 1773 | /** |
1953 | * Get the thread-local database-handle. | 1774 | * Store collectable bit coin under the corresponding |
1954 | * Connect to the db if the connection does not exist yet. | 1775 | * hash of the blinded message. |
1955 | * | 1776 | * |
1956 | * @param the database connection, or NULL on error | 1777 | * @param db_conn database connection to use |
1778 | * @param h_blind hash of the blinded message | ||
1779 | * @param collectable corresponding collectable coin (blind signature) | ||
1780 | * if a coin is found | ||
1781 | * @return #GNUNET_SYSERR on internal error | ||
1782 | * #GNUNET_NO if the collectable was not found | ||
1783 | * #GNUNET_YES on success | ||
1957 | */ | 1784 | */ |
1958 | PGconn * | 1785 | int |
1959 | TALER_MINT_DB_get_connection (void) | 1786 | TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn, |
1787 | const struct GNUNET_HashCode *h_blind, | ||
1788 | const struct CollectableBlindcoin *collectable) | ||
1960 | { | 1789 | { |
1961 | PGconn *db_conn; | 1790 | PGresult *result; |
1791 | char *sig_buf; | ||
1792 | size_t sig_buf_size; | ||
1962 | 1793 | ||
1963 | if (NULL != (db_conn = pthread_getspecific (db_conn_threadlocal))) | 1794 | sig_buf_size = GNUNET_CRYPTO_rsa_signature_encode (collectable->sig, |
1964 | return db_conn; | 1795 | &sig_buf); |
1796 | { | ||
1797 | struct TALER_DB_QueryParam params[] = { | ||
1798 | TALER_DB_QUERY_PARAM_PTR (&h_blind), | ||
1799 | TALER_DB_QUERY_PARAM_PTR_SIZED (sig_buf, sig_buf_size), | ||
1800 | TALER_DB_QUERY_PARAM_PTR (&collectable->denom_pub), | ||
1801 | TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_pub), | ||
1802 | TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_sig), | ||
1803 | TALER_DB_QUERY_PARAM_END | ||
1804 | }; | ||
1965 | 1805 | ||
1966 | db_conn = PQconnectdb (TALER_MINT_db_connection_cfg_str); | 1806 | result = TALER_DB_exec_prepared (db_conn, |
1807 | "insert_collectable_blindcoins", | ||
1808 | params); | ||
1809 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | ||
1810 | { | ||
1811 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1812 | "Query failed: %s\n", | ||
1813 | PQresultErrorMessage (result)); | ||
1814 | PQclear (result); | ||
1815 | return GNUNET_SYSERR; | ||
1816 | } | ||
1967 | 1817 | ||
1968 | if (CONNECTION_OK != PQstatus (db_conn)) | 1818 | if (0 != strcmp ("1", PQcmdTuples (result))) |
1969 | { | 1819 | { |
1970 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1820 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1971 | "db connection failed: %s\n", | 1821 | "Insert failed (updated '%s' tupes instead of '1')\n", |
1972 | PQerrorMessage (db_conn)); | 1822 | PQcmdTuples (result)); |
1973 | GNUNET_break (0); | 1823 | PQclear (result); |
1974 | return NULL; | 1824 | return GNUNET_SYSERR; |
1825 | } | ||
1826 | PQclear (result); | ||
1975 | } | 1827 | } |
1828 | return GNUNET_OK; | ||
1829 | } | ||
1976 | 1830 | ||
1977 | if (GNUNET_OK != TALER_MINT_DB_prepare (db_conn)) | 1831 | |
1832 | /** | ||
1833 | * Check if we have the specified deposit already in the database. | ||
1834 | * | ||
1835 | * @param db_conn database connection | ||
1836 | * @param deposit deposit to search for | ||
1837 | * @return #GNUNET_YES if we know this operation, | ||
1838 | * #GNUNET_NO if this deposit is unknown to us | ||
1839 | */ | ||
1840 | int | ||
1841 | TALER_MINT_DB_have_deposit (PGconn *db_conn, | ||
1842 | const struct Deposit *deposit) | ||
1843 | { | ||
1844 | struct TALER_DB_QueryParam params[] = { | ||
1845 | TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub), // FIXME | ||
1846 | TALER_DB_QUERY_PARAM_END | ||
1847 | }; | ||
1848 | PGresult *result; | ||
1849 | |||
1850 | result = TALER_DB_exec_prepared (db_conn, | ||
1851 | "get_deposit", | ||
1852 | params); | ||
1853 | if (PGRES_TUPLES_OK != | ||
1854 | PQresultStatus (result)) | ||
1978 | { | 1855 | { |
1979 | GNUNET_break (0); | 1856 | break_db_err (result); |
1980 | return NULL; | 1857 | PQclear (result); |
1858 | return GNUNET_SYSERR; | ||
1981 | } | 1859 | } |
1982 | if (0 != pthread_setspecific (db_conn_threadlocal, db_conn)) | 1860 | |
1861 | if (0 == PQntuples (result)) | ||
1983 | { | 1862 | { |
1984 | GNUNET_break (0); | 1863 | PQclear (result); |
1985 | return NULL; | 1864 | return GNUNET_NO; |
1986 | } | 1865 | } |
1987 | return db_conn; | 1866 | return GNUNET_YES; |
1988 | } | 1867 | } |
1989 | 1868 | ||
1990 | 1869 | ||
1991 | /** | 1870 | /** |
1992 | * Close thread-local database connection when a thread is destroyed. | 1871 | * Insert information about deposited coin into the |
1872 | * database. | ||
1993 | * | 1873 | * |
1994 | * @param closure we get from pthreads (the db handle) | 1874 | * @param db_conn connection to the database |
1875 | * @param deposit deposit information to store | ||
1876 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
1995 | */ | 1877 | */ |
1996 | static void | 1878 | int |
1997 | db_conn_destroy (void *cls) | 1879 | TALER_MINT_DB_insert_deposit (PGconn *db_conn, |
1880 | const struct Deposit *deposit) | ||
1998 | { | 1881 | { |
1999 | PGconn *db_conn = cls; | 1882 | struct TALER_DB_QueryParam params[]= { |
2000 | if (NULL != db_conn) | 1883 | TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub), |
2001 | PQfinish (db_conn); | 1884 | TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_pub), // FIXME! |
1885 | TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_sig), // FIXME! | ||
1886 | TALER_DB_QUERY_PARAM_PTR (&deposit->transaction_id), | ||
1887 | TALER_DB_QUERY_PARAM_PTR (&deposit->amount.value), | ||
1888 | TALER_DB_QUERY_PARAM_PTR (&deposit->amount.fraction), | ||
1889 | TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->amount.currency, | ||
1890 | strlen (deposit->amount.currency)), | ||
1891 | TALER_DB_QUERY_PARAM_PTR (&deposit->merchant_pub), | ||
1892 | TALER_DB_QUERY_PARAM_PTR (&deposit->h_contract), | ||
1893 | TALER_DB_QUERY_PARAM_PTR (&deposit->h_wire), | ||
1894 | TALER_DB_QUERY_PARAM_PTR (&deposit->csig), | ||
1895 | TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->wire, | ||
1896 | strlen ("FIXME")), // FIXME! json! | ||
1897 | TALER_DB_QUERY_PARAM_END | ||
1898 | }; | ||
1899 | PGresult *result; | ||
1900 | |||
1901 | result = TALER_DB_exec_prepared (db_conn, "insert_deposit", params); | ||
1902 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | ||
1903 | { | ||
1904 | break_db_err (result); | ||
1905 | PQclear (result); | ||
1906 | return GNUNET_SYSERR; | ||
1907 | } | ||
1908 | PQclear (result); | ||
1909 | return GNUNET_OK; | ||
2002 | } | 1910 | } |
2003 | 1911 | ||
2004 | 1912 | ||
2005 | /** | 1913 | /** |
2006 | * Initialize database subsystem. | 1914 | * Test if the given /refresh/melt request is known to us. |
2007 | * | 1915 | * |
2008 | * @param connection_cfg configuration to use to talk to DB | 1916 | * @param db_conn database connection |
2009 | * @return #GNUNET_OK on success | 1917 | * @param melt melt operation |
1918 | * @return #GNUNET_YES if known, | ||
1919 | * #GNUENT_NO if not, | ||
1920 | * #GNUNET_SYSERR on internal error | ||
2010 | */ | 1921 | */ |
2011 | int | 1922 | int |
2012 | TALER_MINT_DB_init (const char *connection_cfg) | 1923 | TALER_MINT_DB_have_refresh_melt (PGconn *db_conn, |
1924 | const struct RefreshMelt *melt) | ||
2013 | { | 1925 | { |
1926 | uint16_t oldcoin_index_nbo = htons (melt->oldcoin_index); | ||
1927 | struct TALER_DB_QueryParam params[] = { | ||
1928 | TALER_DB_QUERY_PARAM_PTR(&melt->session_pub), | ||
1929 | TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo), | ||
1930 | TALER_DB_QUERY_PARAM_END | ||
1931 | }; | ||
2014 | 1932 | ||
2015 | if (0 != pthread_key_create (&db_conn_threadlocal, &db_conn_destroy)) | 1933 | PGresult *result = TALER_DB_exec_prepared (db_conn, |
1934 | "get_refresh_melt", | ||
1935 | params); | ||
1936 | if (PGRES_TUPLES_OK != PQresultStatus (result)) | ||
2016 | { | 1937 | { |
2017 | fprintf (stderr, | 1938 | break_db_err (result); |
2018 | "Can't create pthread key.\n"); | 1939 | PQclear (result); |
2019 | return GNUNET_SYSERR; | 1940 | return GNUNET_SYSERR; |
2020 | } | 1941 | } |
2021 | TALER_MINT_db_connection_cfg_str = GNUNET_strdup (connection_cfg); | 1942 | |
2022 | return GNUNET_OK; | 1943 | if (0 == PQntuples (result)) |
1944 | { | ||
1945 | PQclear (result); | ||
1946 | return GNUNET_NO; | ||
1947 | } | ||
1948 | GNUNET_break (1 == PQntuples (result)); | ||
1949 | PQclear (result); | ||
1950 | return GNUNET_YES; | ||
2023 | } | 1951 | } |
2024 | 1952 | ||
2025 | 1953 | ||
1954 | |||
1955 | /** | ||
1956 | * Store the given /refresh/melt request in the database. | ||
1957 | * | ||
1958 | * @param db_conn database connection | ||
1959 | * @param melt melt operation | ||
1960 | * @return #GNUNET_OK on success | ||
1961 | * #GNUNET_SYSERR on internal error | ||
1962 | */ | ||
2026 | int | 1963 | int |
2027 | TALER_TALER_DB_extract_amount_nbo (PGresult *result, | 1964 | TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn, |
2028 | unsigned int row, | 1965 | const struct RefreshMelt *melt) |
2029 | int indices[3], | ||
2030 | struct TALER_AmountNBO *denom_nbo) | ||
2031 | { | 1966 | { |
2032 | if ((indices[0] < 0) || (indices[1] < 0) || (indices[2] < 0)) | 1967 | uint16_t oldcoin_index_nbo = htons (melt->oldcoin_index); |
2033 | return GNUNET_NO; | 1968 | char *buf; |
2034 | if (sizeof (uint32_t) != PQgetlength (result, row, indices[0])) | 1969 | size_t buf_size; |
2035 | return GNUNET_SYSERR; | 1970 | PGresult *result; |
2036 | if (sizeof (uint32_t) != PQgetlength (result, row, indices[1])) | 1971 | |
2037 | return GNUNET_SYSERR; | 1972 | buf_size = GNUNET_CRYPTO_rsa_public_key_encode (melt->coin.denom_pub, |
2038 | if (PQgetlength (result, row, indices[2]) > TALER_CURRENCY_LEN) | 1973 | &buf); |
1974 | { | ||
1975 | struct TALER_DB_QueryParam params[] = { | ||
1976 | TALER_DB_QUERY_PARAM_PTR(&melt->session_pub), | ||
1977 | TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo), | ||
1978 | TALER_DB_QUERY_PARAM_PTR(&melt->coin.coin_pub), | ||
1979 | TALER_DB_QUERY_PARAM_PTR_SIZED(buf, buf_size), | ||
1980 | TALER_DB_QUERY_PARAM_END | ||
1981 | }; | ||
1982 | result = TALER_DB_exec_prepared (db_conn, "insert_refresh_melt", params); | ||
1983 | } | ||
1984 | GNUNET_free (buf); | ||
1985 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | ||
1986 | { | ||
1987 | break_db_err (result); | ||
1988 | PQclear (result); | ||
2039 | return GNUNET_SYSERR; | 1989 | return GNUNET_SYSERR; |
2040 | denom_nbo->value = *(uint32_t *) PQgetvalue (result, row, indices[0]); | 1990 | } |
2041 | denom_nbo->fraction = *(uint32_t *) PQgetvalue (result, row, indices[1]); | 1991 | PQclear (result); |
2042 | memset (denom_nbo->currency, 0, TALER_CURRENCY_LEN); | ||
2043 | memcpy (denom_nbo->currency, PQgetvalue (result, row, indices[2]), PQgetlength (result, row, indices[2])); | ||
2044 | return GNUNET_OK; | 1992 | return GNUNET_OK; |
2045 | } | 1993 | } |
2046 | 1994 | ||
2047 | 1995 | ||
1996 | /** | ||
1997 | * Get information about melted coin details from the database. | ||
1998 | * | ||
1999 | * @param db_conn database connection | ||
2000 | * @param session session key of the melt operation | ||
2001 | * @param oldcoin_index index of the coin to retrieve | ||
2002 | * @param melt melt data to fill in | ||
2003 | * @return #GNUNET_OK on success | ||
2004 | * #GNUNET_SYSERR on internal error | ||
2005 | */ | ||
2048 | int | 2006 | int |
2049 | TALER_TALER_DB_extract_amount (PGresult *result, | 2007 | TALER_MINT_DB_get_refresh_melt (PGconn *db_conn, |
2050 | unsigned int row, | 2008 | const struct GNUNET_CRYPTO_EddsaPublicKey *session, |
2051 | int indices[3], | 2009 | uint16_t oldcoin_index, |
2052 | struct TALER_Amount *denom) | 2010 | struct RefreshMelt *melt) |
2053 | { | 2011 | { |
2054 | struct TALER_AmountNBO denom_nbo; | 2012 | GNUNET_break (0); |
2055 | int res; | 2013 | return GNUNET_SYSERR; |
2014 | } | ||
2056 | 2015 | ||
2057 | res = TALER_TALER_DB_extract_amount_nbo (result, row, indices, &denom_nbo); | 2016 | |
2058 | if (GNUNET_OK != res) | 2017 | /** |
2059 | return res; | 2018 | * Compile a list of all (historic) transactions performed |
2060 | *denom = TALER_amount_ntoh (denom_nbo); | 2019 | * with the given coin (/refresh/melt and /deposit operations). |
2061 | return GNUNET_OK; | 2020 | * |
2021 | * @param db_conn database connection | ||
2022 | * @param coin_pub coin to investigate | ||
2023 | * @return list of transactions, NULL if coin is fresh | ||
2024 | */ | ||
2025 | struct TALER_MINT_DB_TransactionList * | ||
2026 | TALER_MINT_DB_get_coin_transactions (PGconn *db_conn, | ||
2027 | const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub) | ||
2028 | { | ||
2029 | GNUNET_break (0); // FIXME: implement! | ||
2030 | return NULL; | ||
2062 | } | 2031 | } |
2032 | |||
2033 | |||
2034 | /* end of mint_db.c */ | ||
diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h index b38b82b94..6e1fb4753 100644 --- a/src/mint/mint_db.h +++ b/src/mint/mint_db.h | |||
@@ -30,57 +30,12 @@ | |||
30 | #include "mint.h" | 30 | #include "mint.h" |
31 | 31 | ||
32 | 32 | ||
33 | int | ||
34 | TALER_MINT_DB_prepare (PGconn *db_conn); | ||
35 | |||
36 | 33 | ||
37 | /** | 34 | /** |
38 | * Locate the response for a /withdraw request under the | 35 | * FIXME. |
39 | * key of the hash of the blinded message. | ||
40 | * | ||
41 | * @param db_conn database connection to use | ||
42 | * @param h_blind hash of the blinded message | ||
43 | * @param collectable corresponding collectable coin (blind signature) | ||
44 | * if a coin is found | ||
45 | * @return #GNUNET_SYSERR on internal error | ||
46 | * #GNUNET_NO if the collectable was not found | ||
47 | * #GNUNET_YES on success | ||
48 | */ | 36 | */ |
49 | int | 37 | int |
50 | TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn, | 38 | TALER_MINT_DB_prepare (PGconn *db_conn); |
51 | const struct GNUNET_HashCode *h_blind, | ||
52 | struct CollectableBlindcoin *collectable); | ||
53 | |||
54 | |||
55 | /** | ||
56 | * Store collectable bit coin under the corresponding | ||
57 | * hash of the blinded message. | ||
58 | * | ||
59 | * @param db_conn database connection to use | ||
60 | * @param h_blind hash of the blinded message | ||
61 | * @param collectable corresponding collectable coin (blind signature) | ||
62 | * if a coin is found | ||
63 | * @return #GNUNET_SYSERR on internal error | ||
64 | * #GNUNET_NO if the collectable was not found | ||
65 | * #GNUNET_YES on success | ||
66 | */ | ||
67 | int | ||
68 | TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn, | ||
69 | const struct GNUNET_HashCode *h_blind, | ||
70 | const struct CollectableBlindcoin *collectable); | ||
71 | |||
72 | |||
73 | int | ||
74 | TALER_MINT_DB_rollback (PGconn *db_conn); | ||
75 | |||
76 | |||
77 | int | ||
78 | TALER_MINT_DB_transaction (PGconn *db_conn); | ||
79 | |||
80 | |||
81 | int | ||
82 | TALER_MINT_DB_commit (PGconn *db_conn); | ||
83 | |||
84 | 39 | ||
85 | 40 | ||
86 | /** | 41 | /** |
@@ -151,6 +106,9 @@ TALER_MINT_DB_update_reserve (PGconn *db_conn, | |||
151 | 106 | ||
152 | 107 | ||
153 | 108 | ||
109 | |||
110 | |||
111 | |||
154 | int | 112 | int |
155 | TALER_MINT_DB_insert_refresh_order (PGconn *db_conn, | 113 | TALER_MINT_DB_insert_refresh_order (PGconn *db_conn, |
156 | uint16_t newcoin_index, | 114 | uint16_t newcoin_index, |
@@ -163,8 +121,6 @@ TALER_MINT_DB_get_refresh_session (PGconn *db_conn, | |||
163 | struct RefreshSession *r_session); | 121 | struct RefreshSession *r_session); |
164 | 122 | ||
165 | 123 | ||
166 | |||
167 | |||
168 | /** | 124 | /** |
169 | * FIXME | 125 | * FIXME |
170 | */ | 126 | */ |
@@ -201,10 +157,6 @@ TALER_MINT_DB_insert_known_coin (PGconn *db_conn, | |||
201 | const struct KnownCoin *known_coin); | 157 | const struct KnownCoin *known_coin); |
202 | 158 | ||
203 | 159 | ||
204 | |||
205 | |||
206 | |||
207 | |||
208 | int | 160 | int |
209 | TALER_MINT_DB_create_refresh_session (PGconn *db_conn, | 161 | TALER_MINT_DB_create_refresh_session (PGconn *db_conn, |
210 | const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub); | 162 | const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub); |
@@ -276,19 +228,6 @@ TALER_MINT_DB_set_reveal_ok (PGconn *db_conn, | |||
276 | const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub); | 228 | const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub); |
277 | 229 | ||
278 | 230 | ||
279 | int | ||
280 | TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn, | ||
281 | const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub, | ||
282 | uint16_t oldcoin_index, | ||
283 | const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub, | ||
284 | const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub); | ||
285 | |||
286 | |||
287 | int | ||
288 | TALER_MINT_DB_get_refresh_melt (PGconn *db_conn, | ||
289 | const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub, | ||
290 | uint16_t oldcoin_index, | ||
291 | struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub); | ||
292 | 231 | ||
293 | 232 | ||
294 | /** | 233 | /** |
@@ -320,13 +259,139 @@ TALER_db_get_transfer (PGconn *db_conn, | |||
320 | struct GNUNET_CRYPTO_EcdsaPublicKey *transfer_pub, | 259 | struct GNUNET_CRYPTO_EcdsaPublicKey *transfer_pub, |
321 | struct GNUNET_HashCode *shared_secret_enc); | 260 | struct GNUNET_HashCode *shared_secret_enc); |
322 | 261 | ||
262 | |||
323 | int | 263 | int |
324 | TALER_MINT_DB_init_deposits (PGconn *db_conn, int temporary); | 264 | TALER_TALER_DB_extract_amount (PGresult *result, |
265 | unsigned int row, | ||
266 | int indices[3], | ||
267 | struct TALER_Amount *denom); | ||
268 | |||
269 | int | ||
270 | TALER_TALER_DB_extract_amount_nbo (PGresult *result, | ||
271 | unsigned int row, | ||
272 | int indices[3], | ||
273 | struct TALER_AmountNBO *denom_nbo); | ||
325 | 274 | ||
326 | 275 | ||
276 | |||
277 | |||
278 | |||
279 | // Chaos | ||
280 | //////////////////////////////////////////////////////////////// | ||
281 | // Order | ||
282 | |||
283 | |||
284 | |||
285 | /** | ||
286 | * Initialize database subsystem. | ||
287 | */ | ||
288 | int | ||
289 | TALER_MINT_DB_init (const char *connection_cfg); | ||
290 | |||
291 | |||
292 | /** | ||
293 | * Get the thread-local database-handle. | ||
294 | * Connect to the db if the connection does not exist yet. | ||
295 | * | ||
296 | * @param the database connection, or NULL on error | ||
297 | */ | ||
298 | PGconn * | ||
299 | TALER_MINT_DB_get_connection (void); | ||
300 | |||
301 | |||
302 | /** | ||
303 | * Start a transaction. | ||
304 | * | ||
305 | * @return #GNUNET_OK on success | ||
306 | */ | ||
307 | int | ||
308 | TALER_MINT_DB_transaction (PGconn *db_conn); | ||
309 | |||
310 | |||
311 | /** | ||
312 | * Commit a transaction. | ||
313 | * | ||
314 | * @return #GNUNET_OK on success | ||
315 | */ | ||
316 | int | ||
317 | TALER_MINT_DB_commit (PGconn *db_conn); | ||
318 | |||
319 | |||
320 | /** | ||
321 | * Abort/rollback a transaction. | ||
322 | * | ||
323 | * @return #GNUNET_OK on success | ||
324 | */ | ||
327 | int | 325 | int |
328 | TALER_MINT_DB_prepare_deposits (PGconn *db_conn); | 326 | TALER_MINT_DB_rollback (PGconn *db_conn); |
327 | |||
328 | |||
329 | |||
330 | /** | ||
331 | * Information we keep for a withdrawn coin to reproduce | ||
332 | * the /withdraw operation if needed, and to have proof | ||
333 | * that a reserve was drained by this amount. | ||
334 | */ | ||
335 | struct CollectableBlindcoin | ||
336 | { | ||
337 | |||
338 | /** | ||
339 | * Our signature over the (blinded) coin. | ||
340 | */ | ||
341 | struct GNUNET_CRYPTO_rsa_Signature *sig; | ||
342 | |||
343 | /** | ||
344 | * Denomination key (which coin was generated). | ||
345 | */ | ||
346 | struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub; | ||
347 | |||
348 | /** | ||
349 | * Public key of the reserve that was drained. | ||
350 | */ | ||
351 | struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub; | ||
329 | 352 | ||
353 | /** | ||
354 | * Signature confirming the withdrawl, matching @e reserve_pub, | ||
355 | * @e denom_pub and @e h_blind. | ||
356 | */ | ||
357 | struct GNUNET_CRYPTO_EddsaSignature reserve_sig; | ||
358 | }; | ||
359 | |||
360 | |||
361 | /** | ||
362 | * Locate the response for a /withdraw request under the | ||
363 | * key of the hash of the blinded message. | ||
364 | * | ||
365 | * @param db_conn database connection to use | ||
366 | * @param h_blind hash of the blinded message | ||
367 | * @param collectable corresponding collectable coin (blind signature) | ||
368 | * if a coin is found | ||
369 | * @return #GNUNET_SYSERR on internal error | ||
370 | * #GNUNET_NO if the collectable was not found | ||
371 | * #GNUNET_YES on success | ||
372 | */ | ||
373 | int | ||
374 | TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn, | ||
375 | const struct GNUNET_HashCode *h_blind, | ||
376 | struct CollectableBlindcoin *collectable); | ||
377 | |||
378 | |||
379 | /** | ||
380 | * Store collectable bit coin under the corresponding | ||
381 | * hash of the blinded message. | ||
382 | * | ||
383 | * @param db_conn database connection to use | ||
384 | * @param h_blind hash of the blinded message | ||
385 | * @param collectable corresponding collectable coin (blind signature) | ||
386 | * if a coin is found | ||
387 | * @return #GNUNET_SYSERR on internal error | ||
388 | * #GNUNET_NO if the collectable was not found | ||
389 | * #GNUNET_YES on success | ||
390 | */ | ||
391 | int | ||
392 | TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn, | ||
393 | const struct GNUNET_HashCode *h_blind, | ||
394 | const struct CollectableBlindcoin *collectable); | ||
330 | 395 | ||
331 | 396 | ||
332 | /** | 397 | /** |
@@ -384,59 +449,253 @@ struct Deposit | |||
384 | */ | 449 | */ |
385 | struct TALER_Amount amount; | 450 | struct TALER_Amount amount; |
386 | 451 | ||
387 | /** | 452 | }; |
388 | * Type of the deposit (also purpose of the signature). Either | ||
389 | * #TALER_SIGNATURE_DEPOSIT or #TALER_SIGNATURE_INCREMENTAL_DEPOSIT. | ||
390 | */ | ||
391 | uint32_t purpose; // FIXME: bad type, use ENUM! | ||
392 | 453 | ||
393 | 454 | ||
394 | }; | 455 | /** |
456 | * Check if we have the specified deposit already in the database. | ||
457 | * | ||
458 | * @param db_conn database connection | ||
459 | * @param deposit deposit to search for | ||
460 | * @return #GNUNET_YES if we know this operation, | ||
461 | * #GNUNET_NO if this deposit is unknown to us, | ||
462 | * #GNUNET_SYSERR on internal error | ||
463 | */ | ||
464 | int | ||
465 | TALER_MINT_DB_have_deposit (PGconn *db_conn, | ||
466 | const struct Deposit *deposit); | ||
395 | 467 | ||
396 | 468 | ||
469 | /** | ||
470 | * Insert information about deposited coin into the | ||
471 | * database. | ||
472 | * | ||
473 | * @param db_conn connection to the database | ||
474 | * @param deposit deposit information to store | ||
475 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
476 | */ | ||
397 | int | 477 | int |
398 | TALER_MINT_DB_insert_deposit (PGconn *db_conn, | 478 | TALER_MINT_DB_insert_deposit (PGconn *db_conn, |
399 | const struct Deposit *deposit); | 479 | const struct Deposit *deposit); |
400 | 480 | ||
401 | 481 | ||
402 | // FIXME: with fractional deposits, we need more than | 482 | /** |
403 | // just the coin key to lookup deposits... | 483 | * Specification for a /refresh/melt operation. |
404 | int | 484 | */ |
405 | TALER_MINT_DB_get_deposit (PGconn *db_conn, | 485 | struct RefreshMelt |
406 | const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub, | 486 | { |
407 | struct Deposit *r_deposit); | 487 | /** |
488 | * Information about the coin that is being melted. | ||
489 | */ | ||
490 | struct TALER_CoinPublicInfo coin; | ||
408 | 491 | ||
492 | /** | ||
493 | * Public key of the melting session. | ||
494 | */ | ||
495 | struct GNUNET_CRYPTO_EddsaPublicKey session_pub; | ||
409 | 496 | ||
497 | /** | ||
498 | * Signature over the melting operation. | ||
499 | */ | ||
500 | struct GNUNET_CRYPTO_EcdsaSignature coin_sig; | ||
410 | 501 | ||
502 | /** | ||
503 | * How much value is being melted? | ||
504 | */ | ||
505 | struct TALER_Amount amount; | ||
506 | |||
507 | /** | ||
508 | * What is the index of this coin in the melting session? | ||
509 | */ | ||
510 | uint16_t oldcoin_index; | ||
511 | |||
512 | }; | ||
411 | 513 | ||
412 | 514 | ||
413 | /** | 515 | /** |
414 | * Get the thread-local database-handle. | 516 | * Test if the given /refresh/melt request is known to us. |
415 | * Connect to the db if the connection does not exist yet. | ||
416 | * | 517 | * |
417 | * @param the database connection, or NULL on error | 518 | * @param db_conn database connection |
519 | * @param melt melt operation | ||
520 | * @return #GNUNET_YES if known, | ||
521 | * #GNUENT_NO if not, | ||
522 | * #GNUNET_SYSERR on internal error | ||
418 | */ | 523 | */ |
419 | PGconn * | 524 | int |
420 | TALER_MINT_DB_get_connection (void); | 525 | TALER_MINT_DB_have_refresh_melt (PGconn *db_conn, |
526 | const struct RefreshMelt *melt); | ||
421 | 527 | ||
422 | 528 | ||
529 | /** | ||
530 | * Store the given /refresh/melt request in the database. | ||
531 | * | ||
532 | * @param db_conn database connection | ||
533 | * @param melt melt operation | ||
534 | * @return #GNUNET_OK on success | ||
535 | * #GNUNET_SYSERR on internal error | ||
536 | */ | ||
423 | int | 537 | int |
424 | TALER_MINT_DB_init (const char *connection_cfg); | 538 | TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn, |
539 | const struct RefreshMelt *melt); | ||
540 | |||
541 | |||
542 | /** | ||
543 | * Get information about melted coin details from the database. | ||
544 | * | ||
545 | * @param db_conn database connection | ||
546 | * @param session session key of the melt operation | ||
547 | * @param oldcoin_index index of the coin to retrieve | ||
548 | * @param melt melt data to fill in | ||
549 | * @return #GNUNET_OK on success | ||
550 | * #GNUNET_SYSERR on internal error | ||
551 | */ | ||
552 | int | ||
553 | TALER_MINT_DB_get_refresh_melt (PGconn *db_conn, | ||
554 | const struct GNUNET_CRYPTO_EddsaPublicKey *session, | ||
555 | uint16_t oldcoin_index, | ||
556 | struct RefreshMelt *melt); | ||
557 | |||
558 | |||
559 | /** | ||
560 | * Specification for a /lock operation. | ||
561 | */ | ||
562 | struct Lock | ||
563 | { | ||
564 | /** | ||
565 | * Information about the coin that is being melted. | ||
566 | */ | ||
567 | struct TALER_CoinPublicInfo coin; | ||
425 | 568 | ||
569 | /** | ||
570 | * Signature over the melting operation. | ||
571 | */ | ||
572 | const struct GNUNET_CRYPTO_EcdsaSignature coin_sig; | ||
426 | 573 | ||
574 | /** | ||
575 | * How much value is being melted? | ||
576 | */ | ||
577 | struct TALER_Amount amount; | ||
578 | |||
579 | // FIXME: more needed... | ||
580 | }; | ||
427 | 581 | ||
428 | 582 | ||
583 | /** | ||
584 | * Test if the given /lock request is known to us. | ||
585 | * | ||
586 | * @param db_conn database connection | ||
587 | * @param lock lock operation | ||
588 | * @return #GNUNET_YES if known, | ||
589 | * #GNUENT_NO if not, | ||
590 | * #GNUNET_SYSERR on internal error | ||
591 | */ | ||
429 | int | 592 | int |
430 | TALER_TALER_DB_extract_amount (PGresult *result, | 593 | TALER_MINT_DB_have_lock (PGconn *db_conn, |
431 | unsigned int row, | 594 | const struct Lock *lock); |
432 | int indices[3], | ||
433 | struct TALER_Amount *denom); | ||
434 | 595 | ||
596 | |||
597 | /** | ||
598 | * Store the given /lock request in the database. | ||
599 | * | ||
600 | * @param db_conn database connection | ||
601 | * @param lock lock operation | ||
602 | * @return #GNUNET_OK on success | ||
603 | * #GNUNET_SYSERR on internal error | ||
604 | */ | ||
435 | int | 605 | int |
436 | TALER_TALER_DB_extract_amount_nbo (PGresult *result, | 606 | TALER_MINT_DB_insert_lock (PGconn *db_conn, |
437 | unsigned int row, | 607 | const struct Lock *lock); |
438 | int indices[3], | 608 | |
439 | struct TALER_AmountNBO *denom_nbo); | 609 | |
610 | /** | ||
611 | * Enumeration to classify the different types of transactions | ||
612 | * that can be done with a coin. | ||
613 | */ | ||
614 | enum TALER_MINT_DB_TransactionType | ||
615 | { | ||
616 | /** | ||
617 | * /deposit operation. | ||
618 | */ | ||
619 | TALER_MINT_DB_TT_DEPOSIT = 0, | ||
620 | |||
621 | /** | ||
622 | * /refresh/melt operation. | ||
623 | */ | ||
624 | TALER_MINT_DB_TT_REFRESH_MELT = 1, | ||
625 | |||
626 | /** | ||
627 | * /lock operation. | ||
628 | */ | ||
629 | TALER_MINT_DB_TT_LOCK = 2 | ||
630 | }; | ||
631 | |||
632 | |||
633 | /** | ||
634 | * List of transactions we performed for a particular coin. | ||
635 | */ | ||
636 | struct TALER_MINT_DB_TransactionList | ||
637 | { | ||
638 | |||
639 | /** | ||
640 | * Next pointer in the NULL-terminated linked list. | ||
641 | */ | ||
642 | struct TALER_MINT_DB_TransactionList *next; | ||
643 | |||
644 | /** | ||
645 | * Type of the transaction, determines what is stored in @e details. | ||
646 | */ | ||
647 | enum TALER_MINT_DB_TransactionType type; | ||
648 | |||
649 | /** | ||
650 | * Details about the transaction, depending on @e type. | ||
651 | */ | ||
652 | union | ||
653 | { | ||
654 | |||
655 | /** | ||
656 | * Details if transaction was a /deposit operation. | ||
657 | */ | ||
658 | struct Deposit *deposit; | ||
659 | |||
660 | /** | ||
661 | * Details if transaction was a /refresh/melt operation. | ||
662 | */ | ||
663 | struct RefreshMelt *melt; | ||
664 | |||
665 | /** | ||
666 | * Details if transaction was a /lock operation. | ||
667 | */ | ||
668 | struct Lock *lock; | ||
669 | |||
670 | } details; | ||
671 | |||
672 | }; | ||
673 | |||
674 | |||
675 | /** | ||
676 | * Compile a list of all (historic) transactions performed | ||
677 | * with the given coin (/refresh/melt and /deposit operations). | ||
678 | * | ||
679 | * @param db_conn database connection | ||
680 | * @param coin_pub coin to investigate | ||
681 | * @return list of transactions, NULL if coin is fresh | ||
682 | */ | ||
683 | struct TALER_MINT_DB_TransactionList * | ||
684 | TALER_MINT_DB_get_coin_transactions (PGconn *db_conn, | ||
685 | const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub); | ||
686 | |||
687 | |||
688 | /** | ||
689 | * Free linked list of transactions. | ||
690 | * | ||
691 | * @param list list to free | ||
692 | */ | ||
693 | void | ||
694 | TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list); | ||
695 | |||
696 | |||
697 | |||
698 | |||
440 | 699 | ||
441 | 700 | ||
442 | #endif /* _NEURO_MINT_DB_H */ | 701 | #endif /* _NEURO_MINT_DB_H */ |
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index f64e1508d..6dffbcd63 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c | |||
@@ -55,31 +55,35 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, | |||
55 | const struct Deposit *deposit) | 55 | const struct Deposit *deposit) |
56 | { | 56 | { |
57 | PGconn *db_conn; | 57 | PGconn *db_conn; |
58 | struct Deposit existing_deposit; | 58 | struct TALER_MINT_DB_TransactionList *tl; |
59 | int res; | ||
60 | 59 | ||
61 | if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) | 60 | if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) |
62 | { | 61 | { |
63 | GNUNET_break (0); | 62 | GNUNET_break (0); |
64 | return TALER_MINT_reply_internal_db_error (connection); | 63 | return TALER_MINT_reply_internal_db_error (connection); |
65 | } | 64 | } |
66 | res = TALER_MINT_DB_get_deposit (db_conn, | 65 | if (GNUNET_YES == |
67 | &deposit->coin.coin_pub, | 66 | TALER_MINT_DB_have_deposit (db_conn, |
68 | &existing_deposit); | 67 | deposit)) |
69 | if (GNUNET_YES == res) | 68 | { |
69 | return TALER_MINT_reply_deposit_success (connection, | ||
70 | &deposit->coin.coin_pub, | ||
71 | &deposit->h_wire, | ||
72 | &deposit->h_contract, | ||
73 | deposit->transaction_id, | ||
74 | &deposit->merchant_pub, | ||
75 | &deposit->amount); | ||
76 | } | ||
77 | if (GNUNET_OK != | ||
78 | TALER_MINT_DB_transaction (db_conn)) | ||
79 | { | ||
80 | GNUNET_break (0); | ||
81 | return TALER_MINT_reply_internal_db_error (connection); | ||
82 | } | ||
83 | tl = TALER_MINT_DB_get_coin_transactions (db_conn, | ||
84 | &deposit->coin.coin_pub); | ||
85 | if (NULL != tl) | ||
70 | { | 86 | { |
71 | // FIXME: memory leak | ||
72 | // FIXME: memcmp will not actually work here | ||
73 | if (0 == memcmp (&existing_deposit, | ||
74 | deposit, | ||
75 | sizeof (struct Deposit))) | ||
76 | return TALER_MINT_reply_deposit_success (connection, | ||
77 | &deposit->coin.coin_pub, | ||
78 | &deposit->h_wire, | ||
79 | &deposit->h_contract, | ||
80 | deposit->transaction_id, | ||
81 | &deposit->merchant_pub, | ||
82 | &deposit->amount); | ||
83 | // FIXME: in the future, check if there's enough credits | 87 | // FIXME: in the future, check if there's enough credits |
84 | // left on the coin. For now: refuse | 88 | // left on the coin. For now: refuse |
85 | // FIXME: return more information here | 89 | // FIXME: return more information here |
@@ -87,15 +91,9 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, | |||
87 | MHD_HTTP_FORBIDDEN, | 91 | MHD_HTTP_FORBIDDEN, |
88 | "{s:s}", | 92 | "{s:s}", |
89 | "error", | 93 | "error", |
90 | "double spending"); | 94 | "double spending"); |
91 | } | 95 | } |
92 | 96 | ||
93 | if (GNUNET_SYSERR == res) | ||
94 | { | ||
95 | GNUNET_break (0); | ||
96 | /* FIXME: return error message to client via MHD! */ | ||
97 | return MHD_NO; | ||
98 | } | ||
99 | 97 | ||
100 | { | 98 | { |
101 | struct KnownCoin known_coin; | 99 | struct KnownCoin known_coin; |
@@ -153,6 +151,14 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, | |||
153 | } | 151 | } |
154 | 152 | ||
155 | 153 | ||
154 | |||
155 | |||
156 | |||
157 | |||
158 | |||
159 | |||
160 | |||
161 | |||
156 | /** | 162 | /** |
157 | * Sign a reserve's status with the current signing key. | 163 | * Sign a reserve's status with the current signing key. |
158 | * FIXME: not sure why we do this. Should just return | 164 | * FIXME: not sure why we do this. Should just return |
@@ -474,6 +480,7 @@ refresh_accept_melts (struct MHD_Connection *connection, | |||
474 | struct KnownCoin known_coin; | 480 | struct KnownCoin known_coin; |
475 | // money the customer gets by melting the current coin | 481 | // money the customer gets by melting the current coin |
476 | struct TALER_Amount coin_gain; | 482 | struct TALER_Amount coin_gain; |
483 | struct RefreshMelt melt; | ||
477 | 484 | ||
478 | dki = &(TALER_MINT_get_denom_key (key_state, | 485 | dki = &(TALER_MINT_get_denom_key (key_state, |
479 | coin_public_infos[i].denom_pub)->issue); | 486 | coin_public_infos[i].denom_pub)->issue); |
@@ -523,10 +530,17 @@ refresh_accept_melts (struct MHD_Connection *connection, | |||
523 | return GNUNET_SYSERR; | 530 | return GNUNET_SYSERR; |
524 | } | 531 | } |
525 | 532 | ||
533 | // FIXME: test first if coin was already melted | ||
534 | // in this session, etc. | ||
535 | |||
536 | melt.coin = coin_public_infos[i]; | ||
537 | melt.session_pub = *session_pub; | ||
538 | // melt.coin_sig = FIXME; | ||
539 | // melt.amount = FIXME; | ||
540 | melt.oldcoin_index = i; | ||
526 | if (GNUNET_OK != | 541 | if (GNUNET_OK != |
527 | TALER_MINT_DB_insert_refresh_melt (db_conn, session_pub, i, | 542 | TALER_MINT_DB_insert_refresh_melt (db_conn, |
528 | &coin_public_infos[i].coin_pub, | 543 | &melt)) |
529 | coin_public_infos[i].denom_pub)) | ||
530 | { | 544 | { |
531 | GNUNET_break (0); | 545 | GNUNET_break (0); |
532 | return GNUNET_SYSERR; | 546 | return GNUNET_SYSERR; |
@@ -934,9 +948,9 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection, | |||
934 | for (j = 0; j < refresh_session.num_oldcoins; j++) | 948 | for (j = 0; j < refresh_session.num_oldcoins; j++) |
935 | { | 949 | { |
936 | struct RefreshCommitLink commit_link; | 950 | struct RefreshCommitLink commit_link; |
937 | struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub; | ||
938 | struct TALER_TransferSecret transfer_secret; | 951 | struct TALER_TransferSecret transfer_secret; |
939 | struct TALER_LinkSecret shared_secret; | 952 | struct TALER_LinkSecret shared_secret; |
953 | struct RefreshMelt melt; | ||
940 | 954 | ||
941 | res = TALER_MINT_DB_get_refresh_commit_link (db_conn, | 955 | res = TALER_MINT_DB_get_refresh_commit_link (db_conn, |
942 | refresh_session_pub, | 956 | refresh_session_pub, |
@@ -949,7 +963,10 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection, | |||
949 | return MHD_NO; | 963 | return MHD_NO; |
950 | } | 964 | } |
951 | 965 | ||
952 | res = TALER_MINT_DB_get_refresh_melt (db_conn, refresh_session_pub, j, &coin_pub); | 966 | res = TALER_MINT_DB_get_refresh_melt (db_conn, |
967 | refresh_session_pub, | ||
968 | j, | ||
969 | &melt); | ||
953 | if (GNUNET_OK != res) | 970 | if (GNUNET_OK != res) |
954 | { | 971 | { |
955 | GNUNET_break (0); | 972 | GNUNET_break (0); |
@@ -962,7 +979,7 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection, | |||
962 | /* FIXME: ECDHE/ECDSA-key type confusion! Can we reduce/avoid this? */ | 979 | /* FIXME: ECDHE/ECDSA-key type confusion! Can we reduce/avoid this? */ |
963 | if (GNUNET_OK != | 980 | if (GNUNET_OK != |
964 | GNUNET_CRYPTO_ecc_ecdh ((const struct GNUNET_CRYPTO_EcdhePrivateKey *) &transfer_privs[i+off][j], | 981 | GNUNET_CRYPTO_ecc_ecdh ((const struct GNUNET_CRYPTO_EcdhePrivateKey *) &transfer_privs[i+off][j], |
965 | (const struct GNUNET_CRYPTO_EcdhePublicKey *) &coin_pub, | 982 | (const struct GNUNET_CRYPTO_EcdhePublicKey *) &melt.coin.coin_pub, |
966 | &transfer_secret.key)) | 983 | &transfer_secret.key)) |
967 | { | 984 | { |
968 | GNUNET_break (0); | 985 | GNUNET_break (0); |
diff --git a/src/mint/taler-mint-httpd_deposit.c b/src/mint/taler-mint-httpd_deposit.c index 1e496d5a5..ec75c3ec0 100644 --- a/src/mint/taler-mint-httpd_deposit.c +++ b/src/mint/taler-mint-httpd_deposit.c | |||
@@ -112,8 +112,6 @@ verify_and_execute_deposit (struct MHD_Connection *connection, | |||
112 | * | 112 | * |
113 | * @param connection the MHD connection to handle | 113 | * @param connection the MHD connection to handle |
114 | * @param root root of the posted JSON | 114 | * @param root root of the posted JSON |
115 | * @param purpose is this a #TALER_SIGNATURE_WALLET_DEPOSIT or | ||
116 | * #TALER_SIGNATURE_INCREMENTAL_WALLET_DEPOSIT // FIXME: bad type, use enum! | ||
117 | * @param amount how much should be deposited | 115 | * @param amount how much should be deposited |
118 | * @param wire json describing the wire details (?) | 116 | * @param wire json describing the wire details (?) |
119 | * @return MHD result code | 117 | * @return MHD result code |
@@ -121,7 +119,6 @@ verify_and_execute_deposit (struct MHD_Connection *connection, | |||
121 | static int | 119 | static int |
122 | parse_and_handle_deposit_request (struct MHD_Connection *connection, | 120 | parse_and_handle_deposit_request (struct MHD_Connection *connection, |
123 | const json_t *root, | 121 | const json_t *root, |
124 | uint32_t purpose, | ||
125 | const struct TALER_Amount *amount, | 122 | const struct TALER_Amount *amount, |
126 | const json_t *wire) | 123 | const json_t *wire) |
127 | { | 124 | { |
@@ -187,7 +184,6 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection, | |||
187 | GNUNET_free (wire_enc); | 184 | GNUNET_free (wire_enc); |
188 | 185 | ||
189 | deposit.wire = wire; | 186 | deposit.wire = wire; |
190 | deposit.purpose = purpose; | ||
191 | deposit.amount = *amount; | 187 | deposit.amount = *amount; |
192 | res = verify_and_execute_deposit (connection, | 188 | res = verify_and_execute_deposit (connection, |
193 | &deposit); | 189 | &deposit); |
@@ -223,9 +219,7 @@ TALER_MINT_handler_deposit (struct RequestHandler *rh, | |||
223 | { | 219 | { |
224 | json_t *json; | 220 | json_t *json; |
225 | json_t *wire; | 221 | json_t *wire; |
226 | const char *deposit_type; | ||
227 | int res; | 222 | int res; |
228 | uint32_t purpose; | ||
229 | struct TALER_Amount amount; | 223 | struct TALER_Amount amount; |
230 | json_t *f; | 224 | json_t *f; |
231 | 225 | ||
@@ -240,7 +234,6 @@ TALER_MINT_handler_deposit (struct RequestHandler *rh, | |||
240 | return MHD_YES; | 234 | return MHD_YES; |
241 | if (-1 == json_unpack (json, | 235 | if (-1 == json_unpack (json, |
242 | "{s:s, s:o, f:o}", | 236 | "{s:s, s:o, f:o}", |
243 | "type", &deposit_type, | ||
244 | "wire", &wire, | 237 | "wire", &wire, |
245 | "f", &f)) | 238 | "f", &f)) |
246 | { | 239 | { |
@@ -267,24 +260,8 @@ TALER_MINT_handler_deposit (struct RequestHandler *rh, | |||
267 | json_decref (json); | 260 | json_decref (json); |
268 | return MHD_YES; | 261 | return MHD_YES; |
269 | } | 262 | } |
270 | /* FIXME: use array search and enum, this is ugly */ | ||
271 | if (0 == strcmp ("DIRECT_DEPOSIT", deposit_type)) | ||
272 | purpose = TALER_SIGNATURE_WALLET_DEPOSIT; | ||
273 | else if (0 == strcmp ("INCREMENTAL_DEPOSIT", deposit_type)) | ||
274 | purpose = TALER_SIGNATURE_INCREMENTAL_WALLET_DEPOSIT; | ||
275 | else | ||
276 | { | ||
277 | GNUNET_break_op (0); | ||
278 | json_decref (wire); | ||
279 | json_decref (json); | ||
280 | return TALER_MINT_reply_json_pack (connection, | ||
281 | MHD_HTTP_BAD_REQUEST, | ||
282 | "{s:s}", | ||
283 | "error", "Bad format"); | ||
284 | } | ||
285 | res = parse_and_handle_deposit_request (connection, | 263 | res = parse_and_handle_deposit_request (connection, |
286 | json, | 264 | json, |
287 | purpose, | ||
288 | &amount, | 265 | &amount, |
289 | wire); | 266 | wire); |
290 | json_decref (wire); | 267 | json_decref (wire); |
diff --git a/src/mint/test_mint_deposits.c b/src/mint/test_mint_deposits.c index 00664cbbf..045485b20 100644 --- a/src/mint/test_mint_deposits.c +++ b/src/mint/test_mint_deposits.c | |||
@@ -52,6 +52,44 @@ static int persistent; | |||
52 | static int result; | 52 | static int result; |
53 | 53 | ||
54 | 54 | ||
55 | int | ||
56 | TALER_MINT_DB_init_deposits (PGconn *conn, int tmp) | ||
57 | { | ||
58 | const char *tmp_str = (1 == tmp) ? "TEMPORARY" : ""; | ||
59 | char *sql; | ||
60 | PGresult *res; | ||
61 | int ret; | ||
62 | |||
63 | res = NULL; | ||
64 | (void) GNUNET_asprintf (&sql, | ||
65 | "CREATE %1$s TABLE IF NOT EXISTS deposits (" | ||
66 | " coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (length(coin_pub)=32)" | ||
67 | ",denom_pub BYTEA NOT NULL CHECK (length(denom_pub)=32)" | ||
68 | ",transaction_id INT8 NOT NULL" | ||
69 | ",amount_value INT4 NOT NULL" | ||
70 | ",amount_fraction INT4 NOT NULL" | ||
71 | ",amount_currency VARCHAR(4) NOT NULL" | ||
72 | ",merchant_pub BYTEA NOT NULL" | ||
73 | ",h_contract BYTEA NOT NULL CHECK (length(h_contract)=64)" | ||
74 | ",h_wire BYTEA NOT NULL CHECK (length(h_wire)=64)" | ||
75 | ",coin_sig BYTEA NOT NULL CHECK (length(coin_sig)=64)" | ||
76 | ",wire TEXT NOT NULL" | ||
77 | ")", | ||
78 | tmp_str); | ||
79 | res = PQexec (conn, sql); | ||
80 | GNUNET_free (sql); | ||
81 | if (PGRES_COMMAND_OK != PQresultStatus (res)) | ||
82 | { | ||
83 | break_db_err (res); | ||
84 | ret = GNUNET_SYSERR; | ||
85 | } | ||
86 | else | ||
87 | ret = GNUNET_OK; | ||
88 | PQclear (res); | ||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | |||
55 | static void | 93 | static void |
56 | do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 94 | do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
57 | { | 95 | { |
@@ -89,7 +127,7 @@ run (void *cls, char *const *args, const char *cfgfile, | |||
89 | &do_shutdown, NULL); | 127 | &do_shutdown, NULL); |
90 | EXITIF (NULL == (conn = PQconnectdb(DB_URI))); | 128 | EXITIF (NULL == (conn = PQconnectdb(DB_URI))); |
91 | EXITIF (GNUNET_OK != TALER_MINT_DB_init_deposits (conn, !persistent)); | 129 | EXITIF (GNUNET_OK != TALER_MINT_DB_init_deposits (conn, !persistent)); |
92 | EXITIF (GNUNET_OK != TALER_MINT_DB_prepare_deposits (conn)); | 130 | EXITIF (GNUNET_OK != TALER_MINT_DB_prepare (conn)); |
93 | deposit = GNUNET_malloc (sizeof (struct Deposit) + sizeof (wire)); | 131 | deposit = GNUNET_malloc (sizeof (struct Deposit) + sizeof (wire)); |
94 | /* Makeup a random coin public key */ | 132 | /* Makeup a random coin public key */ |
95 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, | 133 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, |