diff options
Diffstat (limited to 'src/mint/taler-mint-httpd_db.c')
-rw-r--r-- | src/mint/taler-mint-httpd_db.c | 227 |
1 files changed, 121 insertions, 106 deletions
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 */ | ||