aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-01-29 00:09:48 +0100
committerChristian Grothoff <christian@grothoff.org>2015-01-29 00:09:48 +0100
commit8adde040ab5c3fdc40b06537d3bab1aa60ecc5e5 (patch)
tree66cf29710aa422971cc73adefbcc887e98be5f17
parentb162d2e45829469df5327ea25b2bab1ba1ebaab9 (diff)
downloadexchange-8adde040ab5c3fdc40b06537d3bab1aa60ecc5e5.tar.gz
exchange-8adde040ab5c3fdc40b06537d3bab1aa60ecc5e5.zip
towards proper implementation of /withdraw/status
-rw-r--r--src/mint/key_io.h1
-rw-r--r--src/mint/mint_db.c228
-rw-r--r--src/mint/mint_db.h182
-rw-r--r--src/mint/taler-mint-httpd_db.c227
-rw-r--r--src/mint/taler-mint-httpd_responses.c119
-rw-r--r--src/mint/taler-mint-httpd_responses.h21
-rw-r--r--src/util/amount.c42
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 @@
42struct TALER_MINT_SignKeyIssuePriv 42struct 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
107int
108TALER_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 */
172int
173TALER_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
228int 106int
229TALER_MINT_DB_prepare (PGconn *db_conn) 107TALER_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 */
1726struct ReserveHistory *
1727TALER_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 */
1799void
1800TALER_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
1846TALER_MINT_DB_have_deposit (PGconn *db_conn, 1816TALER_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
1884TALER_MINT_DB_insert_deposit (PGconn *db_conn, 1855TALER_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
1928TALER_MINT_DB_have_refresh_melt (PGconn *db_conn, 1900TALER_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
1969TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn, 1941TALER_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 *
2031TALER_MINT_DB_get_coin_transactions (PGconn *db_conn, 2005TALER_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,
2044void 2019void
2045TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list) 2020TALER_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
38TALER_MINT_DB_prepare (PGconn *db_conn); 38TALER_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 */
48struct 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
86int
87TALER_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 */
100int
101TALER_MINT_DB_update_reserve (PGconn *db_conn,
102 const struct Reserve *reserve,
103 int fresh);
104
105
106
107
108
109
110
111
112int 41int
113TALER_MINT_DB_insert_refresh_order (PGconn *db_conn, 42TALER_MINT_DB_insert_refresh_order (PGconn *db_conn,
114 uint16_t newcoin_index, 43 uint16_t newcoin_index,
@@ -328,6 +257,34 @@ void
328TALER_MINT_DB_rollback (PGconn *db_conn); 257TALER_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 */
264struct 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 */
363enum 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 */
383struct 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 */
425struct ReserveHistory *
426TALER_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 */
435void
436TALER_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 */
69static struct TALER_Amount
70mint_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 */
144static void
145sign_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 */
409static struct TALER_Amount
410mint_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 */
321int
322TALER_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 */
319int 360int
320TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection, 361TALER_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 */
194int
195TALER_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 */
192int 206int
193TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection, 207TALER_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 */
171int 177int
172TALER_amount_cmp (struct TALER_Amount a1, struct TALER_Amount a2) 178TALER_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 */
197struct TALER_Amount 204struct TALER_Amount
198TALER_amount_subtract (struct TALER_Amount a1, struct TALER_Amount a2) 205TALER_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 */
235struct TALER_Amount 243struct TALER_Amount
236TALER_amount_add (struct TALER_Amount a1, struct TALER_Amount a2) 244TALER_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;