diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-01-29 00:09:48 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-01-29 00:09:48 +0100 |
commit | 8adde040ab5c3fdc40b06537d3bab1aa60ecc5e5 (patch) | |
tree | 66cf29710aa422971cc73adefbcc887e98be5f17 | |
parent | b162d2e45829469df5327ea25b2bab1ba1ebaab9 (diff) | |
download | exchange-8adde040ab5c3fdc40b06537d3bab1aa60ecc5e5.tar.gz exchange-8adde040ab5c3fdc40b06537d3bab1aa60ecc5e5.zip |
towards proper implementation of /withdraw/status
-rw-r--r-- | src/mint/key_io.h | 1 | ||||
-rw-r--r-- | src/mint/mint_db.c | 228 | ||||
-rw-r--r-- | src/mint/mint_db.h | 182 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_db.c | 227 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_responses.c | 119 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_responses.h | 21 | ||||
-rw-r--r-- | src/util/amount.c | 42 |
7 files changed, 495 insertions, 325 deletions
diff --git a/src/mint/key_io.h b/src/mint/key_io.h index 44665e379..a14866f47 100644 --- a/src/mint/key_io.h +++ b/src/mint/key_io.h | |||
@@ -42,6 +42,7 @@ | |||
42 | struct TALER_MINT_SignKeyIssuePriv | 42 | struct TALER_MINT_SignKeyIssuePriv |
43 | { | 43 | { |
44 | struct GNUNET_CRYPTO_EddsaPrivateKey signkey_priv; | 44 | struct GNUNET_CRYPTO_EddsaPrivateKey signkey_priv; |
45 | |||
45 | struct TALER_MINT_SignKeyIssue issue; | 46 | struct TALER_MINT_SignKeyIssue issue; |
46 | }; | 47 | }; |
47 | 48 | ||
diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 5da2a5d46..0e448bf09 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c | |||
@@ -103,128 +103,6 @@ TALER_TALER_DB_extract_amount (PGresult *result, | |||
103 | } | 103 | } |
104 | 104 | ||
105 | 105 | ||
106 | |||
107 | int | ||
108 | TALER_MINT_DB_get_reserve (PGconn *db_conn, | ||
109 | const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub, | ||
110 | struct Reserve *reserve) | ||
111 | { | ||
112 | PGresult *result; | ||
113 | int res; | ||
114 | struct TALER_DB_QueryParam params[] = { | ||
115 | TALER_DB_QUERY_PARAM_PTR (reserve_pub), | ||
116 | TALER_DB_QUERY_PARAM_END | ||
117 | }; | ||
118 | |||
119 | result = TALER_DB_exec_prepared (db_conn, "get_reserve", params); | ||
120 | |||
121 | if (PGRES_TUPLES_OK != PQresultStatus (result)) | ||
122 | { | ||
123 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed: %s\n", PQresultErrorMessage (result)); | ||
124 | PQclear (result); | ||
125 | return GNUNET_SYSERR; | ||
126 | } | ||
127 | |||
128 | if (0 == PQntuples (result)) | ||
129 | { | ||
130 | PQclear (result); | ||
131 | return GNUNET_NO; | ||
132 | } | ||
133 | |||
134 | reserve->reserve_pub = *reserve_pub; | ||
135 | |||
136 | struct TALER_DB_ResultSpec rs[] = { | ||
137 | TALER_DB_RESULT_SPEC("status_sig", &reserve->status_sig), | ||
138 | TALER_DB_RESULT_SPEC("status_sign_pub", &reserve->status_sign_pub), | ||
139 | TALER_DB_RESULT_SPEC_END | ||
140 | }; | ||
141 | |||
142 | res = TALER_DB_extract_result (result, rs, 0); | ||
143 | if (GNUNET_SYSERR == res) | ||
144 | { | ||
145 | GNUNET_break (0); | ||
146 | PQclear (result); | ||
147 | return GNUNET_SYSERR; | ||
148 | } | ||
149 | |||
150 | { | ||
151 | int fnums[] = { | ||
152 | PQfnumber (result, "balance_value"), | ||
153 | PQfnumber (result, "balance_fraction"), | ||
154 | PQfnumber (result, "balance_currency"), | ||
155 | }; | ||
156 | if (GNUNET_OK != TALER_TALER_DB_extract_amount_nbo (result, 0, fnums, &reserve->balance)) | ||
157 | { | ||
158 | GNUNET_break (0); | ||
159 | PQclear (result); | ||
160 | return GNUNET_SYSERR; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | /* FIXME: Add expiration?? */ | ||
165 | |||
166 | PQclear (result); | ||
167 | return GNUNET_OK; | ||
168 | } | ||
169 | |||
170 | |||
171 | /* If fresh is GNUNET_YES, set some fields to NULL as they are not actually valid */ | ||
172 | int | ||
173 | TALER_MINT_DB_update_reserve (PGconn *db_conn, | ||
174 | const struct Reserve *reserve, | ||
175 | int fresh) | ||
176 | { | ||
177 | PGresult *result; | ||
178 | uint64_t stamp_sec; | ||
179 | |||
180 | stamp_sec = GNUNET_ntohll (GNUNET_TIME_absolute_ntoh (reserve->expiration).abs_value_us / 1000000); | ||
181 | |||
182 | struct TALER_DB_QueryParam params[] = { | ||
183 | TALER_DB_QUERY_PARAM_PTR (&reserve->reserve_pub), | ||
184 | TALER_DB_QUERY_PARAM_PTR (&reserve->balance.value), | ||
185 | TALER_DB_QUERY_PARAM_PTR (&reserve->balance.fraction), | ||
186 | TALER_DB_QUERY_PARAM_PTR_SIZED (&reserve->balance.currency, | ||
187 | strlen (reserve->balance.currency)), | ||
188 | TALER_DB_QUERY_PARAM_PTR (&reserve->status_sig), | ||
189 | TALER_DB_QUERY_PARAM_PTR (&reserve->status_sign_pub), | ||
190 | TALER_DB_QUERY_PARAM_PTR (&stamp_sec), | ||
191 | TALER_DB_QUERY_PARAM_END | ||
192 | }; | ||
193 | |||
194 | /* set some fields to NULL if they are not actually valid */ | ||
195 | |||
196 | if (GNUNET_YES == fresh) | ||
197 | { | ||
198 | unsigned i; | ||
199 | for (i = 4; i <= 7; i += 1) | ||
200 | { | ||
201 | params[i].data = NULL; | ||
202 | params[i].size = 0; | ||
203 | } | ||
204 | } | ||
205 | |||
206 | result = TALER_DB_exec_prepared (db_conn, "update_reserve", params); | ||
207 | |||
208 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | ||
209 | { | ||
210 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed: %s\n", PQresultErrorMessage (result)); | ||
211 | PQclear (result); | ||
212 | return GNUNET_SYSERR; | ||
213 | } | ||
214 | |||
215 | if (0 != strcmp ("1", PQcmdTuples (result))) | ||
216 | { | ||
217 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Update failed (updated '%s' tupes instead of '1')\n", | ||
218 | PQcmdTuples (result)); | ||
219 | return GNUNET_SYSERR; | ||
220 | } | ||
221 | |||
222 | PQclear (result); | ||
223 | return GNUNET_OK; | ||
224 | } | ||
225 | |||
226 | |||
227 | |||
228 | int | 106 | int |
229 | TALER_MINT_DB_prepare (PGconn *db_conn) | 107 | TALER_MINT_DB_prepare (PGconn *db_conn) |
230 | { | 108 | { |
@@ -1560,9 +1438,6 @@ TALER_db_get_transfer (PGconn *db_conn, | |||
1560 | 1438 | ||
1561 | 1439 | ||
1562 | 1440 | ||
1563 | |||
1564 | |||
1565 | |||
1566 | /** | 1441 | /** |
1567 | * Close thread-local database connection when a thread is destroyed. | 1442 | * Close thread-local database connection when a thread is destroyed. |
1568 | * | 1443 | * |
@@ -1712,6 +1587,10 @@ TALER_MINT_DB_commit (PGconn *db_conn) | |||
1712 | } | 1587 | } |
1713 | 1588 | ||
1714 | 1589 | ||
1590 | |||
1591 | |||
1592 | |||
1593 | |||
1715 | /** | 1594 | /** |
1716 | * Locate the response for a /withdraw request under the | 1595 | * Locate the response for a /withdraw request under the |
1717 | * key of the hash of the blinded message. | 1596 | * key of the hash of the blinded message. |
@@ -1729,6 +1608,7 @@ TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn, | |||
1729 | const struct GNUNET_HashCode *h_blind, | 1608 | const struct GNUNET_HashCode *h_blind, |
1730 | struct CollectableBlindcoin *collectable) | 1609 | struct CollectableBlindcoin *collectable) |
1731 | { | 1610 | { |
1611 | // FIXME: check logic! | ||
1732 | PGresult *result; | 1612 | PGresult *result; |
1733 | struct TALER_DB_QueryParam params[] = { | 1613 | struct TALER_DB_QueryParam params[] = { |
1734 | TALER_DB_QUERY_PARAM_PTR (h_blind), | 1614 | TALER_DB_QUERY_PARAM_PTR (h_blind), |
@@ -1792,6 +1672,7 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn, | |||
1792 | const struct GNUNET_HashCode *h_blind, | 1672 | const struct GNUNET_HashCode *h_blind, |
1793 | const struct CollectableBlindcoin *collectable) | 1673 | const struct CollectableBlindcoin *collectable) |
1794 | { | 1674 | { |
1675 | // FIXME: check logic! | ||
1795 | PGresult *result; | 1676 | PGresult *result; |
1796 | char *sig_buf; | 1677 | char *sig_buf; |
1797 | size_t sig_buf_size; | 1678 | size_t sig_buf_size; |
@@ -1835,6 +1716,95 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn, | |||
1835 | 1716 | ||
1836 | 1717 | ||
1837 | /** | 1718 | /** |
1719 | * Get all of the transaction history associated with the specified | ||
1720 | * reserve. | ||
1721 | * | ||
1722 | * @param db_conn connection to use | ||
1723 | * @param reserve_pub public key of the reserve | ||
1724 | * @return known transaction history (NULL if reserve is unknown) | ||
1725 | */ | ||
1726 | struct ReserveHistory * | ||
1727 | TALER_MINT_DB_get_reserve_history (PGconn *db_conn, | ||
1728 | const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub) | ||
1729 | { | ||
1730 | // FIXME: implement logic! | ||
1731 | PGresult *result; | ||
1732 | // int res; | ||
1733 | struct TALER_DB_QueryParam params[] = { | ||
1734 | TALER_DB_QUERY_PARAM_PTR (reserve_pub), | ||
1735 | TALER_DB_QUERY_PARAM_END | ||
1736 | }; | ||
1737 | |||
1738 | result = TALER_DB_exec_prepared (db_conn, "get_reserve", params); | ||
1739 | |||
1740 | if (PGRES_TUPLES_OK != PQresultStatus (result)) | ||
1741 | { | ||
1742 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1743 | "Query failed: %s\n", | ||
1744 | PQresultErrorMessage (result)); | ||
1745 | PQclear (result); | ||
1746 | return NULL; | ||
1747 | } | ||
1748 | |||
1749 | if (0 == PQntuples (result)) | ||
1750 | { | ||
1751 | PQclear (result); | ||
1752 | return NULL; | ||
1753 | } | ||
1754 | #if 0 | ||
1755 | reserve->reserve_pub = *reserve_pub; | ||
1756 | |||
1757 | struct TALER_DB_ResultSpec rs[] = { | ||
1758 | TALER_DB_RESULT_SPEC("status_sig", &reserve->status_sig), | ||
1759 | TALER_DB_RESULT_SPEC("status_sign_pub", &reserve->status_sign_pub), | ||
1760 | TALER_DB_RESULT_SPEC_END | ||
1761 | }; | ||
1762 | |||
1763 | res = TALER_DB_extract_result (result, rs, 0); | ||
1764 | if (GNUNET_SYSERR == res) | ||
1765 | { | ||
1766 | GNUNET_break (0); | ||
1767 | PQclear (result); | ||
1768 | return GNUNET_SYSERR; | ||
1769 | } | ||
1770 | |||
1771 | { | ||
1772 | int fnums[] = { | ||
1773 | PQfnumber (result, "balance_value"), | ||
1774 | PQfnumber (result, "balance_fraction"), | ||
1775 | PQfnumber (result, "balance_currency"), | ||
1776 | }; | ||
1777 | if (GNUNET_OK != TALER_TALER_DB_extract_amount_nbo (result, 0, fnums, &reserve->balance)) | ||
1778 | { | ||
1779 | GNUNET_break (0); | ||
1780 | PQclear (result); | ||
1781 | return GNUNET_SYSERR; | ||
1782 | } | ||
1783 | } | ||
1784 | |||
1785 | /* FIXME: Add expiration?? */ | ||
1786 | |||
1787 | PQclear (result); | ||
1788 | return GNUNET_OK; | ||
1789 | #endif | ||
1790 | return NULL; | ||
1791 | } | ||
1792 | |||
1793 | |||
1794 | /** | ||
1795 | * Free memory associated with the given reserve history. | ||
1796 | * | ||
1797 | * @param rh history to free. | ||
1798 | */ | ||
1799 | void | ||
1800 | TALER_MINT_DB_free_reserve_history (struct ReserveHistory *rh) | ||
1801 | { | ||
1802 | // FIXME: implement | ||
1803 | GNUNET_assert (0); | ||
1804 | } | ||
1805 | |||
1806 | |||
1807 | /** | ||
1838 | * Check if we have the specified deposit already in the database. | 1808 | * Check if we have the specified deposit already in the database. |
1839 | * | 1809 | * |
1840 | * @param db_conn database connection | 1810 | * @param db_conn database connection |
@@ -1846,6 +1816,7 @@ int | |||
1846 | TALER_MINT_DB_have_deposit (PGconn *db_conn, | 1816 | TALER_MINT_DB_have_deposit (PGconn *db_conn, |
1847 | const struct Deposit *deposit) | 1817 | const struct Deposit *deposit) |
1848 | { | 1818 | { |
1819 | // FIXME: check logic! | ||
1849 | struct TALER_DB_QueryParam params[] = { | 1820 | struct TALER_DB_QueryParam params[] = { |
1850 | TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub), // FIXME | 1821 | TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub), // FIXME |
1851 | TALER_DB_QUERY_PARAM_END | 1822 | TALER_DB_QUERY_PARAM_END |
@@ -1884,6 +1855,7 @@ int | |||
1884 | TALER_MINT_DB_insert_deposit (PGconn *db_conn, | 1855 | TALER_MINT_DB_insert_deposit (PGconn *db_conn, |
1885 | const struct Deposit *deposit) | 1856 | const struct Deposit *deposit) |
1886 | { | 1857 | { |
1858 | // FIXME: check logic! | ||
1887 | struct TALER_DB_QueryParam params[]= { | 1859 | struct TALER_DB_QueryParam params[]= { |
1888 | TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub), | 1860 | TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub), |
1889 | TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_pub), // FIXME! | 1861 | TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_pub), // FIXME! |
@@ -1928,6 +1900,7 @@ int | |||
1928 | TALER_MINT_DB_have_refresh_melt (PGconn *db_conn, | 1900 | TALER_MINT_DB_have_refresh_melt (PGconn *db_conn, |
1929 | const struct RefreshMelt *melt) | 1901 | const struct RefreshMelt *melt) |
1930 | { | 1902 | { |
1903 | // FIXME: check logic! | ||
1931 | uint16_t oldcoin_index_nbo = htons (melt->oldcoin_index); | 1904 | uint16_t oldcoin_index_nbo = htons (melt->oldcoin_index); |
1932 | struct TALER_DB_QueryParam params[] = { | 1905 | struct TALER_DB_QueryParam params[] = { |
1933 | TALER_DB_QUERY_PARAM_PTR(&melt->session_pub), | 1906 | TALER_DB_QUERY_PARAM_PTR(&melt->session_pub), |
@@ -1956,7 +1929,6 @@ TALER_MINT_DB_have_refresh_melt (PGconn *db_conn, | |||
1956 | } | 1929 | } |
1957 | 1930 | ||
1958 | 1931 | ||
1959 | |||
1960 | /** | 1932 | /** |
1961 | * Store the given /refresh/melt request in the database. | 1933 | * Store the given /refresh/melt request in the database. |
1962 | * | 1934 | * |
@@ -1969,6 +1941,7 @@ int | |||
1969 | TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn, | 1941 | TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn, |
1970 | const struct RefreshMelt *melt) | 1942 | const struct RefreshMelt *melt) |
1971 | { | 1943 | { |
1944 | // FIXME: check logic! | ||
1972 | uint16_t oldcoin_index_nbo = htons (melt->oldcoin_index); | 1945 | uint16_t oldcoin_index_nbo = htons (melt->oldcoin_index); |
1973 | char *buf; | 1946 | char *buf; |
1974 | size_t buf_size; | 1947 | size_t buf_size; |
@@ -2014,6 +1987,7 @@ TALER_MINT_DB_get_refresh_melt (PGconn *db_conn, | |||
2014 | uint16_t oldcoin_index, | 1987 | uint16_t oldcoin_index, |
2015 | struct RefreshMelt *melt) | 1988 | struct RefreshMelt *melt) |
2016 | { | 1989 | { |
1990 | // FIXME: check logic! | ||
2017 | GNUNET_break (0); | 1991 | GNUNET_break (0); |
2018 | return GNUNET_SYSERR; | 1992 | return GNUNET_SYSERR; |
2019 | } | 1993 | } |
@@ -2031,6 +2005,7 @@ struct TALER_MINT_DB_TransactionList * | |||
2031 | TALER_MINT_DB_get_coin_transactions (PGconn *db_conn, | 2005 | TALER_MINT_DB_get_coin_transactions (PGconn *db_conn, |
2032 | const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub) | 2006 | const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub) |
2033 | { | 2007 | { |
2008 | // FIXME: check logic! | ||
2034 | GNUNET_break (0); // FIXME: implement! | 2009 | GNUNET_break (0); // FIXME: implement! |
2035 | return NULL; | 2010 | return NULL; |
2036 | } | 2011 | } |
@@ -2044,6 +2019,7 @@ TALER_MINT_DB_get_coin_transactions (PGconn *db_conn, | |||
2044 | void | 2019 | void |
2045 | TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list) | 2020 | TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list) |
2046 | { | 2021 | { |
2022 | // FIXME: check logic! | ||
2047 | GNUNET_break (0); | 2023 | GNUNET_break (0); |
2048 | } | 2024 | } |
2049 | 2025 | ||
diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h index ff14ba1e4..4cb2a5f1e 100644 --- a/src/mint/mint_db.h +++ b/src/mint/mint_db.h | |||
@@ -38,77 +38,6 @@ int | |||
38 | TALER_MINT_DB_prepare (PGconn *db_conn); | 38 | TALER_MINT_DB_prepare (PGconn *db_conn); |
39 | 39 | ||
40 | 40 | ||
41 | /** | ||
42 | * Reserve row. Corresponds to table 'reserves' in the mint's | ||
43 | * database. FIXME: not sure this is how we want to store this | ||
44 | * information. Also, may currently used in different ways in the | ||
45 | * code, so we might need to separate the struct into different ones | ||
46 | * depending on the context it is used in. | ||
47 | */ | ||
48 | struct Reserve | ||
49 | { | ||
50 | /** | ||
51 | * Signature over the purse. | ||
52 | * Only valid if (blind_session_missing==GNUNET_YES). | ||
53 | */ | ||
54 | struct GNUNET_CRYPTO_EddsaSignature status_sig; | ||
55 | |||
56 | /** | ||
57 | * Signature with purpose TALER_SIGNATURE_PURSE. | ||
58 | * Only valid if (blind_session_missing==GNUNET_YES). | ||
59 | */ | ||
60 | struct GNUNET_CRYPTO_EccSignaturePurpose status_sig_purpose; | ||
61 | |||
62 | /** | ||
63 | * Signing key used to sign the purse. | ||
64 | * Only valid if (blind_session_missing==GNUNET_YES). | ||
65 | */ | ||
66 | struct GNUNET_CRYPTO_EddsaPublicKey status_sign_pub; | ||
67 | |||
68 | /** | ||
69 | * Withdraw public key, identifies the purse. | ||
70 | * Only the customer knows the corresponding private key. | ||
71 | */ | ||
72 | struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub; | ||
73 | |||
74 | /** | ||
75 | * Remaining balance in the purse. // FIXME: do not use NBO here! | ||
76 | */ | ||
77 | struct TALER_AmountNBO balance; | ||
78 | |||
79 | /** | ||
80 | * Expiration date for the purse. | ||
81 | */ | ||
82 | struct GNUNET_TIME_AbsoluteNBO expiration; | ||
83 | }; | ||
84 | |||
85 | |||
86 | int | ||
87 | TALER_MINT_DB_get_reserve (PGconn *db_conn, | ||
88 | const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub, | ||
89 | struct Reserve *reserve_res); | ||
90 | |||
91 | |||
92 | /** | ||
93 | * Update information about a reserve. | ||
94 | * | ||
95 | * @param db_conn | ||
96 | * @param reserve current reserve status | ||
97 | * @param fresh FIXME | ||
98 | * @return #GNUNET_OK on success | ||
99 | */ | ||
100 | int | ||
101 | TALER_MINT_DB_update_reserve (PGconn *db_conn, | ||
102 | const struct Reserve *reserve, | ||
103 | int fresh); | ||
104 | |||
105 | |||
106 | |||
107 | |||
108 | |||
109 | |||
110 | |||
111 | |||
112 | int | 41 | int |
113 | TALER_MINT_DB_insert_refresh_order (PGconn *db_conn, | 42 | TALER_MINT_DB_insert_refresh_order (PGconn *db_conn, |
114 | uint16_t newcoin_index, | 43 | uint16_t newcoin_index, |
@@ -328,6 +257,34 @@ void | |||
328 | TALER_MINT_DB_rollback (PGconn *db_conn); | 257 | TALER_MINT_DB_rollback (PGconn *db_conn); |
329 | 258 | ||
330 | 259 | ||
260 | /** | ||
261 | * Information we keep on a bank transfer that | ||
262 | * established a reserve. | ||
263 | */ | ||
264 | struct BankTransfer | ||
265 | { | ||
266 | |||
267 | /** | ||
268 | * Public key of the reserve that was filled. | ||
269 | */ | ||
270 | struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub; | ||
271 | |||
272 | /** | ||
273 | * Amount that was transferred to the mint. | ||
274 | */ | ||
275 | struct TALER_Amount amount; | ||
276 | |||
277 | /** | ||
278 | * Detailed wire information about the transaction. | ||
279 | */ | ||
280 | const json_t *wire; | ||
281 | |||
282 | }; | ||
283 | |||
284 | |||
285 | /* FIXME: add functions to add bank transfers to our DB | ||
286 | (and to test if we already did add one) */ | ||
287 | |||
331 | 288 | ||
332 | /** | 289 | /** |
333 | * Information we keep for a withdrawn coin to reproduce | 290 | * Information we keep for a withdrawn coin to reproduce |
@@ -360,6 +317,9 @@ struct CollectableBlindcoin | |||
360 | }; | 317 | }; |
361 | 318 | ||
362 | 319 | ||
320 | /* FIXME: need call to convert CollectableBlindcoin to JSON (#3527) */ | ||
321 | |||
322 | |||
363 | /** | 323 | /** |
364 | * Locate the response for a /withdraw request under the | 324 | * Locate the response for a /withdraw request under the |
365 | * key of the hash of the blinded message. | 325 | * key of the hash of the blinded message. |
@@ -396,6 +356,86 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn, | |||
396 | const struct CollectableBlindcoin *collectable); | 356 | const struct CollectableBlindcoin *collectable); |
397 | 357 | ||
398 | 358 | ||
359 | |||
360 | /** | ||
361 | * Types of operations on a reserved. | ||
362 | */ | ||
363 | enum TALER_MINT_DB_ReserveOperation | ||
364 | { | ||
365 | /** | ||
366 | * Money was deposited into the reserve via a bank transfer. | ||
367 | */ | ||
368 | TALER_MINT_DB_RO_BANK_TO_MINT = 0, | ||
369 | |||
370 | /** | ||
371 | * A Coin was withdrawn from the reserve using /withdraw. | ||
372 | */ | ||
373 | TALER_MINT_DB_RO_WITHDRAW_COIN = 1 | ||
374 | }; | ||
375 | |||
376 | |||
377 | /** | ||
378 | * Reserve history as a linked list. Lists all of the transactions | ||
379 | * associated with this reserve (such as the bank transfers that | ||
380 | * established the reserve and all /withdraw operations we have done | ||
381 | * since). | ||
382 | */ | ||
383 | struct ReserveHistory | ||
384 | { | ||
385 | |||
386 | /** | ||
387 | * Next entry in the reserve history. | ||
388 | */ | ||
389 | struct ReserveHistory *next; | ||
390 | |||
391 | /** | ||
392 | * Type of the event, determins @e details. | ||
393 | */ | ||
394 | enum TALER_MINT_DB_ReserveOperation type; | ||
395 | |||
396 | /** | ||
397 | * Details of the operation, depending on @e type. | ||
398 | */ | ||
399 | union | ||
400 | { | ||
401 | |||
402 | /** | ||
403 | * Details about a bank transfer to the mint. | ||
404 | */ | ||
405 | struct BankTransfer *bank; | ||
406 | |||
407 | /** | ||
408 | * Details about a /withdraw operation. | ||
409 | */ | ||
410 | struct CollectableBlindcoin *withdraw; | ||
411 | |||
412 | } details; | ||
413 | |||
414 | }; | ||
415 | |||
416 | |||
417 | /** | ||
418 | * Get all of the transaction history associated with the specified | ||
419 | * reserve. | ||
420 | * | ||
421 | * @param db_conn connection to use | ||
422 | * @param reserve_pub public key of the reserve | ||
423 | * @return known transaction history (NULL if reserve is unknown) | ||
424 | */ | ||
425 | struct ReserveHistory * | ||
426 | TALER_MINT_DB_get_reserve_history (PGconn *db_conn, | ||
427 | const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub); | ||
428 | |||
429 | |||
430 | /** | ||
431 | * Free memory associated with the given reserve history. | ||
432 | * | ||
433 | * @param rh history to free. | ||
434 | */ | ||
435 | void | ||
436 | TALER_MINT_DB_free_reserve_history (struct ReserveHistory *rh); | ||
437 | |||
438 | |||
399 | /** | 439 | /** |
400 | * Specification for a /deposit operation. | 440 | * Specification for a /deposit operation. |
401 | */ | 441 | */ |
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index c6f0fe2cb..bf10cd29e 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c | |||
@@ -22,12 +22,31 @@ | |||
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 | * - /deposit: properly check existing deposits | 25 | * - /withdraw/sign: all |
26 | * - /deposit: properly perform commit (check return value) | 26 | * + properly check all conditions and handle errors |
27 | * - /deposit: check for leaks | 27 | * + properly check transaction logic |
28 | * - ALL: check API: given structs are usually not perfect, as they | 28 | * + check for leaks |
29 | * often contain too many fields for the context | 29 | * + check low-level API |
30 | * - ALL: check transactional behavior | 30 | * - /refresh/melt: all |
31 | * + properly check all conditions and handle errors | ||
32 | * + properly check transaction logic | ||
33 | * + check for leaks | ||
34 | * + check low-level API | ||
35 | * - /refresh/commit: all | ||
36 | * + properly check all conditions and handle errors | ||
37 | * + properly check transaction logic | ||
38 | * + check for leaks | ||
39 | * + check low-level API | ||
40 | * - /refresh/reveal: all | ||
41 | * + properly check all conditions and handle errors | ||
42 | * + properly check transaction logic | ||
43 | * + check for leaks | ||
44 | * + check low-level API | ||
45 | * - /refresh/link: all | ||
46 | * + properly check all conditions and handle errors | ||
47 | * + properly check transaction logic | ||
48 | * + check for leaks | ||
49 | * + check low-level API | ||
31 | */ | 50 | */ |
32 | #include "platform.h" | 51 | #include "platform.h" |
33 | #include <pthread.h> | 52 | #include <pthread.h> |
@@ -43,6 +62,26 @@ | |||
43 | 62 | ||
44 | 63 | ||
45 | /** | 64 | /** |
65 | * Get an amount in the mint's currency that is zero. | ||
66 | * | ||
67 | * @return zero amount in the mint's currency | ||
68 | */ | ||
69 | static struct TALER_Amount | ||
70 | mint_amount_native_zero () | ||
71 | { | ||
72 | struct TALER_Amount amount; | ||
73 | |||
74 | memset (&amount, | ||
75 | 0, | ||
76 | sizeof (amount)); | ||
77 | memcpy (amount.currency, | ||
78 | MINT_CURRENCY, | ||
79 | strlen (MINT_CURRENCY) + 1); | ||
80 | return amount; | ||
81 | } | ||
82 | |||
83 | |||
84 | /** | ||
46 | * Execute a deposit. The validity of the coin and signature | 85 | * Execute a deposit. The validity of the coin and signature |
47 | * have already been checked. The database must now check that | 86 | * have already been checked. The database must now check that |
48 | * the coin is not (double or over) spent, and execute the | 87 | * the coin is not (double or over) spent, and execute the |
@@ -58,6 +97,15 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, | |||
58 | { | 97 | { |
59 | PGconn *db_conn; | 98 | PGconn *db_conn; |
60 | struct TALER_MINT_DB_TransactionList *tl; | 99 | struct TALER_MINT_DB_TransactionList *tl; |
100 | struct TALER_MINT_DB_TransactionList *pos; | ||
101 | struct TALER_Amount spent; | ||
102 | struct TALER_Amount value; | ||
103 | struct TALER_Amount fee_deposit; | ||
104 | struct TALER_Amount fee_withdraw; | ||
105 | struct TALER_Amount fee_refresh; | ||
106 | struct MintKeyState *mks; | ||
107 | struct TALER_MINT_DenomKeyIssuePriv *dki; | ||
108 | int ret; | ||
61 | 109 | ||
62 | if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) | 110 | if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) |
63 | { | 111 | { |
@@ -76,6 +124,14 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, | |||
76 | &deposit->merchant_pub, | 124 | &deposit->merchant_pub, |
77 | &deposit->amount); | 125 | &deposit->amount); |
78 | } | 126 | } |
127 | mks = TALER_MINT_key_state_acquire (); | ||
128 | dki = TALER_MINT_get_denom_key (mks, | ||
129 | deposit->coin.denom_pub); | ||
130 | value = TALER_amount_ntoh (dki->issue.value); | ||
131 | fee_deposit = TALER_amount_ntoh (dki->issue.fee_deposit); | ||
132 | fee_refresh = TALER_amount_ntoh (dki->issue.fee_refresh); | ||
133 | TALER_MINT_key_state_release (mks); | ||
134 | |||
79 | if (GNUNET_OK != | 135 | if (GNUNET_OK != |
80 | TALER_MINT_DB_transaction (db_conn)) | 136 | TALER_MINT_DB_transaction (db_conn)) |
81 | { | 137 | { |
@@ -84,19 +140,48 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, | |||
84 | } | 140 | } |
85 | tl = TALER_MINT_DB_get_coin_transactions (db_conn, | 141 | tl = TALER_MINT_DB_get_coin_transactions (db_conn, |
86 | &deposit->coin.coin_pub); | 142 | &deposit->coin.coin_pub); |
87 | if (NULL != tl) | 143 | spent = fee_withdraw; /* fee for THIS transaction */ |
144 | /* FIXME: need to deal better with integer overflows | ||
145 | in the logic that follows! (change amount.c API!) */ | ||
146 | spent = TALER_amount_add (spent, | ||
147 | deposit->amount); | ||
148 | |||
149 | for (pos = tl; NULL != pos; pos = pos->next) | ||
88 | { | 150 | { |
89 | // FIXME: in the future, check if there's enough credits | 151 | switch (pos->type) |
90 | // left on the coin. For now: refuse | 152 | { |
91 | // FIXME: return more information here | 153 | case TALER_MINT_DB_TT_DEPOSIT: |
92 | TALER_MINT_DB_rollback (db_conn); | 154 | spent = TALER_amount_add (spent, |
93 | return TALER_MINT_reply_json_pack (connection, | 155 | pos->details.deposit->amount); |
94 | MHD_HTTP_FORBIDDEN, | 156 | spent = TALER_amount_add (spent, |
95 | "{s:s}", | 157 | fee_deposit); |
96 | "error", "insufficient funds"); | 158 | break; |
159 | case TALER_MINT_DB_TT_REFRESH_MELT: | ||
160 | spent = TALER_amount_add (spent, | ||
161 | pos->details.melt->amount); | ||
162 | spent = TALER_amount_add (spent, | ||
163 | fee_refresh); | ||
164 | break; | ||
165 | case TALER_MINT_DB_TT_LOCK: | ||
166 | /* should check if lock is still active, | ||
167 | and if it is for THIS operation; if | ||
168 | lock is inactive, delete it; if lock | ||
169 | is for THIS operation, ignore it; | ||
170 | if lock is for another operation, | ||
171 | count it! */ | ||
172 | GNUNET_assert (0); // FIXME: not implemented! | ||
173 | break; | ||
174 | } | ||
97 | } | 175 | } |
98 | 176 | ||
99 | 177 | if (0 < TALER_amount_cmp (spent, value)) | |
178 | { | ||
179 | TALER_MINT_DB_rollback (db_conn); | ||
180 | ret = TALER_MINT_reply_insufficient_funds (connection, | ||
181 | tl); | ||
182 | TALER_MINT_DB_free_coin_transaction_list (tl); | ||
183 | return ret; | ||
184 | } | ||
100 | TALER_MINT_DB_free_coin_transaction_list (tl); | 185 | TALER_MINT_DB_free_coin_transaction_list (tl); |
101 | 186 | ||
102 | if (GNUNET_OK != | 187 | if (GNUNET_OK != |
@@ -124,37 +209,6 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, | |||
124 | } | 209 | } |
125 | 210 | ||
126 | 211 | ||
127 | |||
128 | |||
129 | |||
130 | |||
131 | |||
132 | |||
133 | |||
134 | |||
135 | /** | ||
136 | * Sign a reserve's status with the current signing key. | ||
137 | * FIXME: not sure why we do this. Should just return | ||
138 | * existing list of operations on the reserve. | ||
139 | * | ||
140 | * @param reserve the reserve to sign | ||
141 | * @param key_state the key state containing the current | ||
142 | * signing private key | ||
143 | */ | ||
144 | static void | ||
145 | sign_reserve (struct Reserve *reserve, | ||
146 | struct MintKeyState *key_state) | ||
147 | { | ||
148 | reserve->status_sign_pub = key_state->current_sign_key_issue.issue.signkey_pub; | ||
149 | reserve->status_sig_purpose.purpose = htonl (TALER_SIGNATURE_RESERVE_STATUS); | ||
150 | reserve->status_sig_purpose.size = htonl (sizeof (struct Reserve) - | ||
151 | offsetof (struct Reserve, status_sig_purpose)); | ||
152 | GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv, | ||
153 | &reserve->status_sig_purpose, | ||
154 | &reserve->status_sig); | ||
155 | } | ||
156 | |||
157 | |||
158 | /** | 212 | /** |
159 | * Execute a /withdraw/status. | 213 | * Execute a /withdraw/status. |
160 | * | 214 | * |
@@ -167,50 +221,25 @@ TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection, | |||
167 | const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub) | 221 | const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub) |
168 | { | 222 | { |
169 | PGconn *db_conn; | 223 | PGconn *db_conn; |
224 | struct ReserveHistory *rh; | ||
170 | int res; | 225 | int res; |
171 | struct Reserve reserve; | ||
172 | struct MintKeyState *key_state; | ||
173 | int must_update = GNUNET_NO; | ||
174 | 226 | ||
175 | if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) | 227 | if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) |
176 | { | 228 | { |
177 | GNUNET_break (0); | 229 | GNUNET_break (0); |
178 | return TALER_MINT_reply_internal_db_error (connection); | 230 | return TALER_MINT_reply_internal_db_error (connection); |
179 | } | 231 | } |
180 | res = TALER_MINT_DB_get_reserve (db_conn, | 232 | rh = TALER_MINT_DB_get_reserve_history (db_conn, |
181 | reserve_pub, | 233 | reserve_pub); |
182 | &reserve); | 234 | if (NULL == rh) |
183 | /* check if these are really the matching error codes, | ||
184 | seems odd... */ | ||
185 | if (GNUNET_SYSERR == res) | ||
186 | return TALER_MINT_reply_json_pack (connection, | 235 | return TALER_MINT_reply_json_pack (connection, |
187 | MHD_HTTP_NOT_FOUND, | 236 | MHD_HTTP_NOT_FOUND, |
188 | "{s:s}", | 237 | "{s:s}", |
189 | "error", | 238 | "error", "Reserve not found"); |
190 | "Reserve not found"); | 239 | res = TALER_MINT_reply_withdraw_status_success (connection, |
191 | if (GNUNET_OK != res) | 240 | rh); |
192 | { | 241 | TALER_MINT_DB_free_reserve_history (rh); |
193 | GNUNET_break (0); | 242 | return res; |
194 | return TALER_MINT_reply_internal_error (connection, | ||
195 | "Internal error"); | ||
196 | } | ||
197 | key_state = TALER_MINT_key_state_acquire (); | ||
198 | if (0 != memcmp (&key_state->current_sign_key_issue.issue.signkey_pub, | ||
199 | &reserve.status_sign_pub, | ||
200 | sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))) | ||
201 | { | ||
202 | sign_reserve (&reserve, key_state); | ||
203 | must_update = GNUNET_YES; | ||
204 | } | ||
205 | if ((GNUNET_YES == must_update) && | ||
206 | (GNUNET_OK != TALER_MINT_DB_update_reserve (db_conn, &reserve, !must_update))) | ||
207 | { | ||
208 | GNUNET_break (0); | ||
209 | return MHD_YES; | ||
210 | } | ||
211 | return TALER_MINT_reply_withdraw_status_success (connection, | ||
212 | TALER_amount_ntoh (reserve.balance), | ||
213 | GNUNET_TIME_absolute_ntoh (reserve.expiration)); | ||
214 | } | 243 | } |
215 | 244 | ||
216 | 245 | ||
@@ -234,7 +263,7 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection, | |||
234 | const struct GNUNET_CRYPTO_EddsaSignature *signature) | 263 | const struct GNUNET_CRYPTO_EddsaSignature *signature) |
235 | { | 264 | { |
236 | PGconn *db_conn; | 265 | PGconn *db_conn; |
237 | struct Reserve db_reserve; | 266 | struct ReserveHistory *rh; |
238 | struct MintKeyState *key_state; | 267 | struct MintKeyState *key_state; |
239 | struct CollectableBlindcoin collectable; | 268 | struct CollectableBlindcoin collectable; |
240 | struct TALER_MINT_DenomKeyIssuePriv *dki; | 269 | struct TALER_MINT_DenomKeyIssuePriv *dki; |
@@ -270,15 +299,9 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection, | |||
270 | return res; | 299 | return res; |
271 | } | 300 | } |
272 | GNUNET_assert (GNUNET_NO == res); | 301 | GNUNET_assert (GNUNET_NO == res); |
273 | res = TALER_MINT_DB_get_reserve (db_conn, | 302 | rh = TALER_MINT_DB_get_reserve_history (db_conn, |
274 | reserve, | 303 | reserve); |
275 | &db_reserve); | 304 | if (NULL == rh) |
276 | if (GNUNET_SYSERR == res) | ||
277 | { | ||
278 | GNUNET_break (0); | ||
279 | return TALER_MINT_reply_internal_db_error (connection); | ||
280 | } | ||
281 | if (GNUNET_NO == res) | ||
282 | return TALER_MINT_reply_json_pack (connection, | 305 | return TALER_MINT_reply_json_pack (connection, |
283 | MHD_HTTP_NOT_FOUND, | 306 | MHD_HTTP_NOT_FOUND, |
284 | "{s:s}", | 307 | "{s:s}", |
@@ -298,6 +321,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection, | |||
298 | 321 | ||
299 | amount_required = TALER_amount_add (TALER_amount_ntoh (dki->issue.value), | 322 | amount_required = TALER_amount_add (TALER_amount_ntoh (dki->issue.value), |
300 | TALER_amount_ntoh (dki->issue.fee_withdraw)); | 323 | TALER_amount_ntoh (dki->issue.fee_withdraw)); |
324 | // FIX LOGIC! | ||
325 | #if 0 | ||
301 | if (0 < TALER_amount_cmp (amount_required, | 326 | if (0 < TALER_amount_cmp (amount_required, |
302 | TALER_amount_ntoh (db_reserve.balance))) | 327 | TALER_amount_ntoh (db_reserve.balance))) |
303 | return TALER_MINT_reply_json_pack (connection, | 328 | return TALER_MINT_reply_json_pack (connection, |
@@ -329,6 +354,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection, | |||
329 | GNUNET_break (0); | 354 | GNUNET_break (0); |
330 | return TALER_MINT_reply_internal_db_error (connection); | 355 | return TALER_MINT_reply_internal_db_error (connection); |
331 | } | 356 | } |
357 | #endif | ||
358 | |||
332 | collectable.denom_pub = (struct GNUNET_CRYPTO_rsa_PublicKey *) denomination_pub; | 359 | collectable.denom_pub = (struct GNUNET_CRYPTO_rsa_PublicKey *) denomination_pub; |
333 | collectable.sig = sig; | 360 | collectable.sig = sig; |
334 | collectable.reserve_pub = *reserve; | 361 | collectable.reserve_pub = *reserve; |
@@ -401,21 +428,6 @@ refresh_accept_denoms (struct MHD_Connection *connection, | |||
401 | } | 428 | } |
402 | 429 | ||
403 | 430 | ||
404 | /** | ||
405 | * Get an amount in the mint's currency that is zero. | ||
406 | * | ||
407 | * @return zero amount in the mint's currency | ||
408 | */ | ||
409 | static struct TALER_Amount | ||
410 | mint_amount_native_zero () | ||
411 | { | ||
412 | struct TALER_Amount amount; | ||
413 | |||
414 | memset (&amount, 0, sizeof (amount)); | ||
415 | memcpy (amount.currency, MINT_CURRENCY, strlen (MINT_CURRENCY) + 1); | ||
416 | |||
417 | return amount; | ||
418 | } | ||
419 | 431 | ||
420 | 432 | ||
421 | /** | 433 | /** |
@@ -1290,3 +1302,6 @@ TALER_MINT_db_execute_refresh_link (struct MHD_Connection *connection, | |||
1290 | json_decref (root); | 1302 | json_decref (root); |
1291 | return res; | 1303 | return res; |
1292 | } | 1304 | } |
1305 | |||
1306 | |||
1307 | /* end of taler-mint-httpd_db.c */ | ||
diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c index 307e6ec17..bad87429c 100644 --- a/src/mint/taler-mint-httpd_responses.c +++ b/src/mint/taler-mint-httpd_responses.c | |||
@@ -309,31 +309,132 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection, | |||
309 | 309 | ||
310 | 310 | ||
311 | /** | 311 | /** |
312 | * Send proof that a /deposit, /refresh/melt or /lock request is | ||
313 | * invalid to client. This function will create a message with all of | ||
314 | * the operations affecting the coin that demonstrate that the coin | ||
315 | * has insufficient value. | ||
316 | * | ||
317 | * @param connection connection to the client | ||
318 | * @param tl transaction list to use to build reply | ||
319 | * @return MHD result code | ||
320 | */ | ||
321 | int | ||
322 | TALER_MINT_reply_insufficient_funds (struct MHD_Connection *connection, | ||
323 | const struct TALER_MINT_DB_TransactionList *tl) | ||
324 | { | ||
325 | const struct TALER_MINT_DB_TransactionList *pos; | ||
326 | int ret; | ||
327 | |||
328 | // FIXME: implement properly! | ||
329 | for (pos = tl; NULL != pos; pos = pos->next) | ||
330 | { | ||
331 | switch (pos->type) | ||
332 | { | ||
333 | case TALER_MINT_DB_TT_DEPOSIT: | ||
334 | /* FIXME: add operation details to json reply */ | ||
335 | break; | ||
336 | case TALER_MINT_DB_TT_REFRESH_MELT: | ||
337 | /* FIXME: add operation details to json reply */ | ||
338 | break; | ||
339 | case TALER_MINT_DB_TT_LOCK: | ||
340 | /* FIXME: add operation details to json reply */ | ||
341 | break; | ||
342 | } | ||
343 | } | ||
344 | |||
345 | ret = TALER_MINT_reply_json_pack (connection, | ||
346 | MHD_HTTP_FORBIDDEN, | ||
347 | "{s:s}", | ||
348 | "error", "insufficient funds"); | ||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | |||
353 | /** | ||
312 | * Send reserve status information to client. | 354 | * Send reserve status information to client. |
313 | * | 355 | * |
314 | * @param connection connection to the client | 356 | * @param connection connection to the client |
315 | * @param balance current reserve balance | 357 | * @param rh reserve history to return |
316 | * @param expiration when will the reserve expire | ||
317 | * @return MHD result code | 358 | * @return MHD result code |
318 | */ | 359 | */ |
319 | int | 360 | int |
320 | TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection, | 361 | TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection, |
321 | const struct TALER_Amount balance, | 362 | const struct ReserveHistory *rh) |
322 | struct GNUNET_TIME_Absolute expiration) | ||
323 | { | 363 | { |
364 | struct TALER_Amount deposit_total; | ||
365 | struct TALER_Amount withdraw_total; | ||
366 | struct TALER_Amount balance; | ||
367 | struct TALER_Amount value; | ||
324 | json_t *json_balance; | 368 | json_t *json_balance; |
325 | json_t *json_expiration; | 369 | json_t *json_history; |
326 | int ret; | 370 | int ret; |
371 | struct MintKeyState *key_state; | ||
372 | const struct ReserveHistory *pos; | ||
373 | struct TALER_MINT_DenomKeyIssuePriv *dki; | ||
374 | |||
375 | json_history = json_array (); | ||
376 | ret = 0; | ||
377 | for (pos = rh; NULL != pos; pos = pos->next) | ||
378 | { | ||
379 | switch (pos->type) | ||
380 | { | ||
381 | case TALER_MINT_DB_RO_BANK_TO_MINT: | ||
382 | if (0 == ret) | ||
383 | deposit_total = pos->details.bank->amount; | ||
384 | else | ||
385 | deposit_total = TALER_amount_add (deposit_total, | ||
386 | pos->details.bank->amount); | ||
387 | ret = 1; | ||
388 | json_array_append_new (json_history, | ||
389 | json_pack ("{s:s, s:o, s:o}", | ||
390 | "type", "DEPOSIT", | ||
391 | "wire", pos->details.bank->wire, | ||
392 | "amount", TALER_JSON_from_amount (pos->details.bank->amount))); | ||
393 | break; | ||
394 | case TALER_MINT_DB_RO_WITHDRAW_COIN: | ||
395 | break; | ||
396 | } | ||
397 | } | ||
398 | |||
399 | key_state = TALER_MINT_key_state_acquire (); | ||
400 | ret = 0; | ||
401 | for (pos = rh; NULL != pos; pos = pos->next) | ||
402 | { | ||
403 | switch (pos->type) | ||
404 | { | ||
405 | case TALER_MINT_DB_RO_BANK_TO_MINT: | ||
406 | break; | ||
407 | case TALER_MINT_DB_RO_WITHDRAW_COIN: | ||
408 | dki = TALER_MINT_get_denom_key (key_state, | ||
409 | pos->details.withdraw->denom_pub); | ||
410 | value = TALER_amount_ntoh (dki->issue.value); | ||
411 | if (0 == ret) | ||
412 | withdraw_total = value; | ||
413 | else | ||
414 | withdraw_total = TALER_amount_add (withdraw_total, | ||
415 | value); | ||
416 | ret = 1; | ||
417 | /* FIXME: add `struct CollectableBlindcoin` as JSON here as well! (#3527) */ | ||
418 | json_array_append_new (json_history, | ||
419 | json_pack ("{s:s, s:o, s:o}", | ||
420 | "type", "WITHDRAW", | ||
421 | "amount", TALER_JSON_from_amount (value))); | ||
422 | |||
423 | break; | ||
424 | } | ||
425 | } | ||
426 | TALER_MINT_key_state_release (key_state); | ||
327 | 427 | ||
428 | balance = TALER_amount_subtract (deposit_total, | ||
429 | withdraw_total); | ||
328 | json_balance = TALER_JSON_from_amount (balance); | 430 | json_balance = TALER_JSON_from_amount (balance); |
329 | json_expiration = TALER_JSON_from_abs (expiration); | ||
330 | ret = TALER_MINT_reply_json_pack (connection, | 431 | ret = TALER_MINT_reply_json_pack (connection, |
331 | MHD_HTTP_OK, | 432 | MHD_HTTP_OK, |
332 | "{s:o, s:o}", | 433 | "{s:o, s:o}", |
333 | "balance", json_balance, | 434 | "balance", json_balance, |
334 | "expiration", json_expiration); | 435 | "history", json_history); |
436 | json_decref (json_history); | ||
335 | json_decref (json_balance); | 437 | json_decref (json_balance); |
336 | json_decref (json_expiration); | ||
337 | return ret; | 438 | return ret; |
338 | } | 439 | } |
339 | 440 | ||
@@ -354,7 +455,7 @@ TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection, | |||
354 | char *sig_buf; | 455 | char *sig_buf; |
355 | int ret; | 456 | int ret; |
356 | 457 | ||
357 | /* FIXME: use TALER_JSON_from_sig here instead! */ | 458 | /* FIXME: use TALER_JSON_from_sig here instead!? */ |
358 | sig_buf_size = GNUNET_CRYPTO_rsa_signature_encode (collectable->sig, | 459 | sig_buf_size = GNUNET_CRYPTO_rsa_signature_encode (collectable->sig, |
359 | &sig_buf); | 460 | &sig_buf); |
360 | sig_json = TALER_JSON_from_data (sig_buf, | 461 | sig_json = TALER_JSON_from_data (sig_buf, |
diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h index f8a671e18..5e2f98638 100644 --- a/src/mint/taler-mint-httpd_responses.h +++ b/src/mint/taler-mint-httpd_responses.h | |||
@@ -182,17 +182,30 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection, | |||
182 | 182 | ||
183 | 183 | ||
184 | /** | 184 | /** |
185 | * Send proof that a /deposit, /refresh/melt or /lock request is | ||
186 | * invalid to client. This function will create a message with all of | ||
187 | * the operations affecting the coin that demonstrate that the coin | ||
188 | * has insufficient value. | ||
189 | * | ||
190 | * @param connection connection to the client | ||
191 | * @param tl transaction list to use to build reply | ||
192 | * @return MHD result code | ||
193 | */ | ||
194 | int | ||
195 | TALER_MINT_reply_insufficient_funds (struct MHD_Connection *connection, | ||
196 | const struct TALER_MINT_DB_TransactionList *tl); | ||
197 | |||
198 | |||
199 | /** | ||
185 | * Send reserve status information to client. | 200 | * Send reserve status information to client. |
186 | * | 201 | * |
187 | * @param connection connection to the client | 202 | * @param connection connection to the client |
188 | * @param balance current reserve balance | 203 | * @param rh reserve history to return |
189 | * @param expiration when will the reserve expire | ||
190 | * @return MHD result code | 204 | * @return MHD result code |
191 | */ | 205 | */ |
192 | int | 206 | int |
193 | TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection, | 207 | TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection, |
194 | struct TALER_Amount balance, | 208 | const struct ReserveHistory *rh); |
195 | struct GNUNET_TIME_Absolute expiration); | ||
196 | 209 | ||
197 | 210 | ||
198 | /** | 211 | /** |
diff --git a/src/util/amount.c b/src/util/amount.c index bb5bf0d5b..65fac78e3 100644 --- a/src/util/amount.c +++ b/src/util/amount.c | |||
@@ -19,6 +19,12 @@ | |||
19 | * @author Sree Harsha Totakura <sreeharsha@totakura.in> | 19 | * @author Sree Harsha Totakura <sreeharsha@totakura.in> |
20 | * @author Florian Dold | 20 | * @author Florian Dold |
21 | * @author Benedikt Mueller | 21 | * @author Benedikt Mueller |
22 | * | ||
23 | * TODO: | ||
24 | * - the way this library currently deals with underflow/overflow | ||
25 | * is insufficient; just going for UINT32_MAX on overflow | ||
26 | * will not do; similar issues for incompatible currencies; | ||
27 | * we need some more explicit logic to say 'bogus value', | ||
22 | */ | 28 | */ |
23 | #include "platform.h" | 29 | #include "platform.h" |
24 | #include "taler_util.h" | 30 | #include "taler_util.h" |
@@ -169,7 +175,8 @@ TALER_amount_ntoh (struct TALER_AmountNBO dn) | |||
169 | * @return result of the comparison | 175 | * @return result of the comparison |
170 | */ | 176 | */ |
171 | int | 177 | int |
172 | TALER_amount_cmp (struct TALER_Amount a1, struct TALER_Amount a2) | 178 | TALER_amount_cmp (struct TALER_Amount a1, |
179 | struct TALER_Amount a2) | ||
173 | { | 180 | { |
174 | a1 = TALER_amount_normalize (a1); | 181 | a1 = TALER_amount_normalize (a1); |
175 | a2 = TALER_amount_normalize (a2); | 182 | a2 = TALER_amount_normalize (a2); |
@@ -195,7 +202,8 @@ TALER_amount_cmp (struct TALER_Amount a1, struct TALER_Amount a2) | |||
195 | * @return (a1-a2) or 0 if a2>=a1 | 202 | * @return (a1-a2) or 0 if a2>=a1 |
196 | */ | 203 | */ |
197 | struct TALER_Amount | 204 | struct TALER_Amount |
198 | TALER_amount_subtract (struct TALER_Amount a1, struct TALER_Amount a2) | 205 | TALER_amount_subtract (struct TALER_Amount a1, |
206 | struct TALER_Amount a2) | ||
199 | { | 207 | { |
200 | a1 = TALER_amount_normalize (a1); | 208 | a1 = TALER_amount_normalize (a1); |
201 | a2 = TALER_amount_normalize (a2); | 209 | a2 = TALER_amount_normalize (a2); |
@@ -233,7 +241,8 @@ TALER_amount_subtract (struct TALER_Amount a1, struct TALER_Amount a2) | |||
233 | * @return sum of a1 and a2 | 241 | * @return sum of a1 and a2 |
234 | */ | 242 | */ |
235 | struct TALER_Amount | 243 | struct TALER_Amount |
236 | TALER_amount_add (struct TALER_Amount a1, struct TALER_Amount a2) | 244 | TALER_amount_add (struct TALER_Amount a1, |
245 | struct TALER_Amount a2) | ||
237 | { | 246 | { |
238 | a1 = TALER_amount_normalize (a1); | 247 | a1 = TALER_amount_normalize (a1); |
239 | a2 = TALER_amount_normalize (a2); | 248 | a2 = TALER_amount_normalize (a2); |
@@ -243,17 +252,25 @@ TALER_amount_add (struct TALER_Amount a1, struct TALER_Amount a2) | |||
243 | 252 | ||
244 | if (0 == a1.currency[0]) | 253 | if (0 == a1.currency[0]) |
245 | { | 254 | { |
246 | memcpy (a2.currency, a1.currency, TALER_CURRENCY_LEN); | 255 | memcpy (a2.currency, |
256 | a1.currency, | ||
257 | TALER_CURRENCY_LEN); | ||
247 | } | 258 | } |
248 | 259 | ||
249 | if (0 == a2.currency[0]) | 260 | if (0 == a2.currency[0]) |
250 | { | 261 | { |
251 | memcpy (a1.currency, a2.currency, TALER_CURRENCY_LEN); | 262 | memcpy (a1.currency, |
263 | a2.currency, | ||
264 | TALER_CURRENCY_LEN); | ||
252 | } | 265 | } |
253 | 266 | ||
254 | if (0 != a1.currency[0] && 0 != memcmp (a1.currency, a2.currency, TALER_CURRENCY_LEN)) | 267 | if ( (0 != a1.currency[0]) && |
268 | (0 != memcmp (a1.currency, | ||
269 | a2.currency, | ||
270 | TALER_CURRENCY_LEN)) ) | ||
255 | { | 271 | { |
256 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "adding mismatching currencies\n"); | 272 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
273 | "adding mismatching currencies\n"); | ||
257 | } | 274 | } |
258 | 275 | ||
259 | if (a1.value < a2.value) | 276 | if (a1.value < a2.value) |
@@ -312,11 +329,18 @@ TALER_amount_to_string (struct TALER_Amount amount) | |||
312 | n = (n * 10) % (AMOUNT_FRAC_BASE); | 329 | n = (n * 10) % (AMOUNT_FRAC_BASE); |
313 | } | 330 | } |
314 | tail[i] = 0; | 331 | tail[i] = 0; |
315 | len = GNUNET_asprintf (&result, "%s:%lu.%s", curr, (unsigned long) amount.value, tail); | 332 | len = GNUNET_asprintf (&result, |
333 | "%s:%lu.%s", | ||
334 | curr, | ||
335 | (unsigned long) amount.value, | ||
336 | tail); | ||
316 | } | 337 | } |
317 | else | 338 | else |
318 | { | 339 | { |
319 | len = GNUNET_asprintf (&result, "%s:%lu", curr, (unsigned long) amount.value); | 340 | len = GNUNET_asprintf (&result, |
341 | "%s:%lu", | ||
342 | curr, | ||
343 | (unsigned long) amount.value); | ||
320 | } | 344 | } |
321 | GNUNET_assert (len > 0); | 345 | GNUNET_assert (len > 0); |
322 | return result; | 346 | return result; |