Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2018-2024 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it
6 : under the terms of the GNU General Public License as published by
7 : the Free Software Foundation; either version 3, or (at your
8 : option) any later version.
9 :
10 : TALER is distributed in the hope that it will be useful, but
11 : WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public
16 : License along with TALER; see the file COPYING. If not, see
17 : <http://www.gnu.org/licenses/>
18 : */
19 : /**
20 : * @file testing/testing_api_cmd_deposit.c
21 : * @brief command for testing /deposit.
22 : * @author Marcello Stanisci
23 : */
24 : #include "taler/taler_json_lib.h"
25 : #include <gnunet/gnunet_curl_lib.h>
26 : #include "taler/taler_testing_lib.h"
27 : #include "taler/taler_signatures.h"
28 : #include "taler/backoff.h"
29 :
30 :
31 : /**
32 : * How often do we retry before giving up?
33 : */
34 : #define NUM_RETRIES 5
35 :
36 : /**
37 : * How long do we wait AT MOST when retrying?
38 : */
39 : #define MAX_BACKOFF GNUNET_TIME_relative_multiply ( \
40 : GNUNET_TIME_UNIT_MILLISECONDS, 100)
41 :
42 :
43 : /**
44 : * State for a "deposit" CMD.
45 : */
46 : struct DepositState
47 : {
48 :
49 : /**
50 : * Amount to deposit.
51 : */
52 : struct TALER_Amount amount;
53 :
54 : /**
55 : * Deposit fee.
56 : */
57 : struct TALER_Amount deposit_fee;
58 :
59 : /**
60 : * Reference to any command that is able to provide a coin.
61 : */
62 : const char *coin_reference;
63 :
64 : /**
65 : * If @e coin_reference refers to an operation that generated
66 : * an array of coins, this value determines which coin to pick.
67 : */
68 : unsigned int coin_index;
69 :
70 : /**
71 : * Our coin signature.
72 : */
73 : struct TALER_CoinSpendSignatureP coin_sig;
74 :
75 : /**
76 : * Wire details of who is depositing -- this would be merchant
77 : * wire details in a normal scenario.
78 : */
79 : json_t *wire_details;
80 :
81 : /**
82 : * JSON string describing what a proposal is about.
83 : */
84 : json_t *contract_terms;
85 :
86 : /**
87 : * Refund deadline. Zero for no refunds.
88 : */
89 : struct GNUNET_TIME_Timestamp refund_deadline;
90 :
91 : /**
92 : * Wire deadline.
93 : */
94 : struct GNUNET_TIME_Timestamp wire_deadline;
95 :
96 : /**
97 : * Set (by the interpreter) to a fresh private key. This
98 : * key will be used to sign the deposit request.
99 : */
100 : union TALER_AccountPrivateKeyP account_priv;
101 :
102 : /**
103 : * Set (by the interpreter) to the public key
104 : * corresponding to @e account_priv.
105 : */
106 : union TALER_AccountPublicKeyP account_pub;
107 :
108 : /**
109 : * Deposit handle while operation is running.
110 : */
111 : struct TALER_EXCHANGE_PostBatchDepositHandle *dh;
112 :
113 : /**
114 : * Denomination public key of the deposited coin.
115 : */
116 : const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
117 :
118 : /**
119 : * Timestamp of the /deposit operation in the wallet (contract signing time).
120 : */
121 : struct GNUNET_TIME_Timestamp wallet_timestamp;
122 :
123 : /**
124 : * Interpreter state.
125 : */
126 : struct TALER_TESTING_Interpreter *is;
127 :
128 : /**
129 : * Task scheduled to try later.
130 : */
131 : struct GNUNET_SCHEDULER_Task *retry_task;
132 :
133 : /**
134 : * How long do we wait until we retry?
135 : */
136 : struct GNUNET_TIME_Relative backoff;
137 :
138 : /**
139 : * Expected HTTP response code.
140 : */
141 : unsigned int expected_response_code;
142 :
143 : /**
144 : * How often should we retry on (transient) failures?
145 : */
146 : unsigned int do_retry;
147 :
148 : /**
149 : * Set to true if the /deposit succeeded
150 : * and we now can provide the resulting traits.
151 : */
152 : bool deposit_succeeded;
153 :
154 : /**
155 : * Expected entry in the coin history created by this
156 : * operation.
157 : */
158 : struct TALER_EXCHANGE_CoinHistoryEntry che;
159 :
160 : /**
161 : * When did the exchange receive the deposit?
162 : */
163 : struct GNUNET_TIME_Timestamp exchange_timestamp;
164 :
165 : /**
166 : * Signing key used by the exchange to sign the
167 : * deposit confirmation.
168 : */
169 : struct TALER_ExchangePublicKeyP exchange_pub;
170 :
171 : /**
172 : * Signature from the exchange on the
173 : * deposit confirmation.
174 : */
175 : struct TALER_ExchangeSignatureP exchange_sig;
176 :
177 : /**
178 : * Cumulative total the @e exchange_sig signed over.
179 : */
180 : struct TALER_Amount cumulative_total;
181 :
182 : /**
183 : * Reference to previous deposit operation.
184 : * Only present if we're supposed to replay the previous deposit.
185 : */
186 : const char *deposit_reference;
187 :
188 : /**
189 : * Did we set the parameters for this deposit command?
190 : *
191 : * When we're referencing another deposit operation,
192 : * this will only be set after the command has been started.
193 : */
194 : bool command_initialized;
195 :
196 : /**
197 : * Reference to fetch the merchant private key from.
198 : * If NULL, we generate our own, fresh merchant key.
199 : */
200 : const char *merchant_priv_reference;
201 : };
202 :
203 :
204 : /**
205 : * Run the command.
206 : *
207 : * @param cls closure.
208 : * @param cmd the command to execute.
209 : * @param is the interpreter state.
210 : */
211 : static void
212 : deposit_run (void *cls,
213 : const struct TALER_TESTING_Command *cmd,
214 : struct TALER_TESTING_Interpreter *is);
215 :
216 :
217 : /**
218 : * Task scheduled to re-try #deposit_run.
219 : *
220 : * @param cls a `struct DepositState`
221 : */
222 : static void
223 0 : do_retry (void *cls)
224 : {
225 0 : struct DepositState *ds = cls;
226 :
227 0 : ds->retry_task = NULL;
228 0 : TALER_TESTING_touch_cmd (ds->is);
229 0 : deposit_run (ds,
230 : NULL,
231 : ds->is);
232 0 : }
233 :
234 :
235 : /**
236 : * Callback to analyze the /deposit response, just used to
237 : * check if the response code is acceptable.
238 : *
239 : * @param cls closure.
240 : * @param dr deposit response details
241 : */
242 : static void
243 96 : deposit_cb (void *cls,
244 : const struct TALER_EXCHANGE_PostBatchDepositResponse *dr)
245 : {
246 96 : struct DepositState *ds = cls;
247 :
248 96 : ds->dh = NULL;
249 96 : if (ds->expected_response_code != dr->hr.http_status)
250 : {
251 0 : if (0 != ds->do_retry)
252 : {
253 0 : ds->do_retry--;
254 0 : if ( (0 == dr->hr.http_status) ||
255 0 : (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec) ||
256 0 : (MHD_HTTP_INTERNAL_SERVER_ERROR == dr->hr.http_status) )
257 : {
258 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
259 : "Retrying deposit failed with %u/%d\n",
260 : dr->hr.http_status,
261 : (int) dr->hr.ec);
262 : /* on DB conflicts, do not use backoff */
263 0 : if (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec)
264 0 : ds->backoff = GNUNET_TIME_UNIT_ZERO;
265 : else
266 0 : ds->backoff = GNUNET_TIME_randomized_backoff (ds->backoff,
267 : MAX_BACKOFF);
268 0 : TALER_TESTING_inc_tries (ds->is);
269 0 : GNUNET_assert (NULL == ds->retry_task);
270 : ds->retry_task
271 0 : = GNUNET_SCHEDULER_add_delayed (ds->backoff,
272 : &do_retry,
273 : ds);
274 0 : return;
275 : }
276 : }
277 0 : TALER_TESTING_unexpected_status_with_body (
278 : ds->is,
279 : dr->hr.http_status,
280 : ds->expected_response_code,
281 : dr->hr.reply);
282 :
283 0 : return;
284 : }
285 96 : if (MHD_HTTP_OK == dr->hr.http_status)
286 : {
287 82 : ds->deposit_succeeded = true;
288 82 : ds->exchange_timestamp = dr->details.ok.deposit_timestamp;
289 82 : ds->exchange_pub = *dr->details.ok.exchange_pub;
290 82 : ds->exchange_sig = *dr->details.ok.exchange_sig;
291 82 : ds->cumulative_total = dr->details.ok.accumulated_total_without_fee;
292 : }
293 96 : TALER_TESTING_interpreter_next (ds->is);
294 : }
295 :
296 :
297 : /**
298 : * Run the command.
299 : *
300 : * @param cls closure.
301 : * @param cmd the command to execute.
302 : * @param is the interpreter state.
303 : */
304 : static void
305 96 : deposit_run (void *cls,
306 : const struct TALER_TESTING_Command *cmd,
307 : struct TALER_TESTING_Interpreter *is)
308 : {
309 96 : struct DepositState *ds = cls;
310 : const struct TALER_TESTING_Command *coin_cmd;
311 : const struct TALER_TESTING_Command *acc_var;
312 : const struct TALER_CoinSpendPrivateKeyP *coin_priv;
313 : struct TALER_CoinSpendPublicKeyP coin_pub;
314 : const struct TALER_AgeCommitmentHashP *phac;
315 : const struct TALER_DenominationSignature *denom_pub_sig;
316 : struct TALER_PrivateContractHashP h_contract_terms;
317 : enum TALER_ErrorCode ec;
318 : struct TALER_WireSaltP wire_salt;
319 : struct TALER_FullPayto payto_uri;
320 : struct GNUNET_JSON_Specification spec[] = {
321 96 : TALER_JSON_spec_full_payto_uri ("payto_uri",
322 : &payto_uri),
323 96 : GNUNET_JSON_spec_fixed_auto ("salt",
324 : &wire_salt),
325 96 : GNUNET_JSON_spec_end ()
326 : };
327 : const char *exchange_url
328 96 : = TALER_TESTING_get_exchange_url (is);
329 :
330 : (void) cmd;
331 96 : if (NULL == exchange_url)
332 : {
333 0 : GNUNET_break (0);
334 0 : return;
335 : }
336 96 : ds->is = is;
337 96 : if (! GNUNET_TIME_absolute_is_zero (ds->refund_deadline.abs_time))
338 : {
339 : struct GNUNET_TIME_Relative refund_deadline;
340 :
341 : refund_deadline
342 10 : = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline.abs_time);
343 : ds->wire_deadline
344 10 : = GNUNET_TIME_relative_to_timestamp (
345 : GNUNET_TIME_relative_multiply (refund_deadline,
346 : 2));
347 : }
348 : else
349 : {
350 86 : ds->refund_deadline = ds->wallet_timestamp;
351 86 : ds->wire_deadline = GNUNET_TIME_timestamp_get ();
352 : }
353 96 : if (NULL != ds->deposit_reference)
354 : {
355 : /* We're copying another deposit operation, initialize here. */
356 : const struct TALER_TESTING_Command *drcmd;
357 : struct DepositState *ods;
358 :
359 14 : drcmd = TALER_TESTING_interpreter_lookup_command (is,
360 : ds->deposit_reference);
361 14 : if (NULL == drcmd)
362 : {
363 0 : GNUNET_break (0);
364 0 : TALER_TESTING_interpreter_fail (is);
365 0 : return;
366 : }
367 14 : ods = drcmd->cls;
368 14 : ds->coin_reference = ods->coin_reference;
369 14 : ds->coin_index = ods->coin_index;
370 14 : ds->wire_details = json_incref (ods->wire_details);
371 14 : GNUNET_assert (NULL != ds->wire_details);
372 14 : ds->contract_terms = json_incref (ods->contract_terms);
373 14 : ds->wallet_timestamp = ods->wallet_timestamp;
374 14 : ds->refund_deadline = ods->refund_deadline;
375 14 : ds->wire_deadline = ods->wire_deadline;
376 14 : ds->amount = ods->amount;
377 14 : ds->account_priv = ods->account_priv;
378 14 : ds->account_pub = ods->account_pub;
379 14 : ds->command_initialized = true;
380 : }
381 82 : else if (NULL != ds->merchant_priv_reference)
382 : {
383 : /* We're copying the merchant key from another deposit operation */
384 : const struct TALER_MerchantPrivateKeyP *merchant_priv;
385 : const struct TALER_TESTING_Command *mpcmd;
386 :
387 2 : mpcmd = TALER_TESTING_interpreter_lookup_command (
388 : is,
389 : ds->merchant_priv_reference);
390 2 : if (NULL == mpcmd)
391 : {
392 0 : GNUNET_break (0);
393 0 : TALER_TESTING_interpreter_fail (is);
394 0 : return;
395 : }
396 2 : if ( (GNUNET_OK !=
397 2 : TALER_TESTING_get_trait_merchant_priv (mpcmd,
398 : &merchant_priv)) )
399 : {
400 0 : GNUNET_break (0);
401 0 : TALER_TESTING_interpreter_fail (is);
402 0 : return;
403 : }
404 2 : ds->account_priv.merchant_priv = *merchant_priv;
405 2 : GNUNET_CRYPTO_eddsa_key_get_public (
406 2 : &ds->account_priv.merchant_priv.eddsa_priv,
407 : &ds->account_pub.merchant_pub.eddsa_pub);
408 : }
409 80 : else if (NULL != (acc_var
410 80 : = TALER_TESTING_interpreter_get_command (
411 : is,
412 : "account-priv")))
413 : {
414 : const union TALER_AccountPrivateKeyP *account_priv;
415 :
416 48 : if ( (GNUNET_OK !=
417 48 : TALER_TESTING_get_trait_account_priv (acc_var,
418 : &account_priv)) )
419 : {
420 0 : GNUNET_break (0);
421 0 : TALER_TESTING_interpreter_fail (is);
422 0 : return;
423 : }
424 48 : ds->account_priv = *account_priv;
425 48 : GNUNET_CRYPTO_eddsa_key_get_public (
426 48 : &ds->account_priv.merchant_priv.eddsa_priv,
427 : &ds->account_pub.merchant_pub.eddsa_pub);
428 : }
429 : else
430 : {
431 32 : GNUNET_CRYPTO_eddsa_key_create (
432 : &ds->account_priv.merchant_priv.eddsa_priv);
433 32 : GNUNET_CRYPTO_eddsa_key_get_public (
434 32 : &ds->account_priv.merchant_priv.eddsa_priv,
435 : &ds->account_pub.merchant_pub.eddsa_pub);
436 : }
437 96 : GNUNET_assert (NULL != ds->wire_details);
438 96 : if (GNUNET_OK !=
439 96 : GNUNET_JSON_parse (ds->wire_details,
440 : spec,
441 : NULL, NULL))
442 : {
443 0 : json_dumpf (ds->wire_details,
444 : stderr,
445 : JSON_INDENT (2));
446 0 : GNUNET_break (0);
447 0 : TALER_TESTING_interpreter_fail (is);
448 0 : return;
449 : }
450 96 : GNUNET_assert (ds->coin_reference);
451 96 : coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
452 : ds->coin_reference);
453 96 : if (NULL == coin_cmd)
454 : {
455 0 : GNUNET_break (0);
456 0 : TALER_TESTING_interpreter_fail (is);
457 0 : return;
458 : }
459 : #if DUMP_CONTRACT
460 : fprintf (stderr,
461 : "Using contract:\n");
462 : json_dumpf (ds->contract_terms,
463 : stderr,
464 : JSON_INDENT (2));
465 : #endif
466 96 : if (GNUNET_OK !=
467 96 : TALER_TESTING_get_trait_coin_priv (coin_cmd,
468 : ds->coin_index,
469 : &coin_priv))
470 : {
471 0 : GNUNET_break (0);
472 0 : TALER_TESTING_interpreter_fail (is);
473 0 : return;
474 : }
475 96 : if (GNUNET_OK !=
476 96 : TALER_TESTING_get_trait_h_age_commitment (coin_cmd,
477 : ds->coin_index,
478 : &phac))
479 : {
480 0 : GNUNET_break (0);
481 0 : TALER_TESTING_interpreter_fail (is);
482 0 : return;
483 : }
484 96 : if (GNUNET_OK !=
485 96 : TALER_TESTING_get_trait_denom_pub (coin_cmd,
486 : ds->coin_index,
487 : &ds->denom_pub))
488 : {
489 0 : GNUNET_break (0);
490 0 : TALER_TESTING_interpreter_fail (is);
491 0 : return;
492 : }
493 96 : if (GNUNET_OK !=
494 96 : TALER_TESTING_get_trait_denom_sig (coin_cmd,
495 : ds->coin_index,
496 : &denom_pub_sig))
497 : {
498 0 : GNUNET_break (0);
499 0 : TALER_TESTING_interpreter_fail (is);
500 0 : return;
501 : }
502 96 : if (GNUNET_OK !=
503 96 : TALER_JSON_contract_hash (ds->contract_terms,
504 : &h_contract_terms))
505 : {
506 0 : GNUNET_break (0);
507 0 : TALER_TESTING_interpreter_fail (is);
508 0 : return;
509 : }
510 :
511 96 : ds->deposit_fee = ds->denom_pub->fees.deposit;
512 96 : GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
513 : &coin_pub.eddsa_pub);
514 :
515 : {
516 : struct TALER_MerchantWireHashP h_wire;
517 :
518 96 : GNUNET_assert (GNUNET_OK ==
519 : TALER_JSON_merchant_wire_signature_hash (ds->wire_details,
520 : &h_wire));
521 96 : TALER_wallet_deposit_sign (&ds->amount,
522 96 : &ds->denom_pub->fees.deposit,
523 : &h_wire,
524 : &h_contract_terms,
525 : NULL, /* wallet data hash */
526 : phac,
527 : NULL, /* hash of extensions */
528 96 : &ds->denom_pub->h_key,
529 : ds->wallet_timestamp,
530 96 : &ds->account_pub.merchant_pub,
531 : ds->refund_deadline,
532 : coin_priv,
533 : &ds->coin_sig);
534 96 : ds->che.type = TALER_EXCHANGE_CTT_DEPOSIT;
535 96 : ds->che.amount = ds->amount;
536 96 : ds->che.details.deposit.h_wire = h_wire;
537 96 : ds->che.details.deposit.h_contract_terms = h_contract_terms;
538 96 : ds->che.details.deposit.no_h_policy = true;
539 96 : ds->che.details.deposit.no_wallet_data_hash = true;
540 96 : ds->che.details.deposit.wallet_timestamp = ds->wallet_timestamp;
541 96 : ds->che.details.deposit.merchant_pub = ds->account_pub.merchant_pub;
542 96 : ds->che.details.deposit.refund_deadline = ds->refund_deadline;
543 96 : ds->che.details.deposit.sig = ds->coin_sig;
544 96 : ds->che.details.deposit.no_hac = true;
545 96 : ds->che.details.deposit.deposit_fee = ds->denom_pub->fees.deposit;
546 : }
547 96 : GNUNET_assert (NULL == ds->dh);
548 : {
549 96 : struct TALER_EXCHANGE_CoinDepositDetail cdd = {
550 : .amount = ds->amount,
551 : .coin_pub = coin_pub,
552 : .coin_sig = ds->coin_sig,
553 96 : .denom_sig = *denom_pub_sig,
554 96 : .h_denom_pub = ds->denom_pub->h_key,
555 : .h_age_commitment = {{{0}}},
556 : };
557 96 : struct TALER_EXCHANGE_DepositContractDetail dcd = {
558 : .wire_deadline = ds->wire_deadline,
559 : .merchant_payto_uri = payto_uri,
560 : .wire_salt = wire_salt,
561 : .h_contract_terms = h_contract_terms,
562 : .wallet_timestamp = ds->wallet_timestamp,
563 : .merchant_pub = ds->account_pub.merchant_pub,
564 : .refund_deadline = ds->refund_deadline
565 : };
566 :
567 96 : TALER_merchant_contract_sign (&h_contract_terms,
568 96 : &ds->account_priv.merchant_priv,
569 : &dcd.merchant_sig);
570 96 : if (NULL != phac)
571 32 : cdd.h_age_commitment = *phac;
572 :
573 96 : ds->dh = TALER_EXCHANGE_post_batch_deposit_create (
574 : TALER_TESTING_interpreter_get_context (is),
575 : exchange_url,
576 : TALER_TESTING_get_keys (is),
577 : &dcd,
578 : 1,
579 : &cdd,
580 : &ec);
581 : }
582 96 : if (NULL == ds->dh)
583 : {
584 0 : GNUNET_break (0);
585 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
586 : "Could not create deposit with EC %d\n",
587 : (int) ec);
588 0 : TALER_TESTING_interpreter_fail (is);
589 0 : return;
590 : }
591 96 : TALER_EXCHANGE_post_batch_deposit_start (ds->dh,
592 : &deposit_cb,
593 : ds);
594 : }
595 :
596 :
597 : /**
598 : * Free the state of a "deposit" CMD, and possibly cancel a
599 : * pending operation thereof.
600 : *
601 : * @param cls closure, must be a `struct DepositState`.
602 : * @param cmd the command which is being cleaned up.
603 : */
604 : static void
605 96 : deposit_cleanup (void *cls,
606 : const struct TALER_TESTING_Command *cmd)
607 : {
608 96 : struct DepositState *ds = cls;
609 :
610 96 : if (NULL != ds->dh)
611 : {
612 0 : TALER_TESTING_command_incomplete (ds->is,
613 : cmd->label);
614 0 : TALER_EXCHANGE_post_batch_deposit_cancel (ds->dh);
615 0 : ds->dh = NULL;
616 : }
617 96 : if (NULL != ds->retry_task)
618 : {
619 0 : GNUNET_SCHEDULER_cancel (ds->retry_task);
620 0 : ds->retry_task = NULL;
621 : }
622 96 : json_decref (ds->wire_details);
623 96 : json_decref (ds->contract_terms);
624 96 : GNUNET_free (ds);
625 96 : }
626 :
627 :
628 : /**
629 : * Offer internal data from a "deposit" CMD, to other commands.
630 : *
631 : * @param cls closure.
632 : * @param[out] ret result.
633 : * @param trait name of the trait.
634 : * @param index index number of the object to offer.
635 : * @return #GNUNET_OK on success.
636 : */
637 : static enum GNUNET_GenericReturnValue
638 332 : deposit_traits (void *cls,
639 : const void **ret,
640 : const char *trait,
641 : unsigned int index)
642 : {
643 332 : struct DepositState *ds = cls;
644 : const struct TALER_TESTING_Command *coin_cmd;
645 : /* Will point to coin cmd internals. */
646 : const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv;
647 : const struct TALER_CoinSpendPublicKeyP *coin_spent_pub;
648 332 : const struct TALER_AgeCommitmentProof *age_commitment_proof=NULL;
649 332 : const struct TALER_AgeCommitmentHashP *h_age_commitment=NULL;
650 :
651 332 : if (! ds->command_initialized)
652 : {
653 : /* No access to traits yet. */
654 0 : GNUNET_break (0);
655 0 : return GNUNET_NO;
656 : }
657 :
658 : coin_cmd
659 332 : = TALER_TESTING_interpreter_lookup_command (ds->is,
660 : ds->coin_reference);
661 332 : if (NULL == coin_cmd)
662 : {
663 0 : GNUNET_break (0);
664 0 : TALER_TESTING_interpreter_fail (ds->is);
665 0 : return GNUNET_NO;
666 : }
667 332 : if ( (GNUNET_OK !=
668 332 : TALER_TESTING_get_trait_coin_priv (coin_cmd,
669 : ds->coin_index,
670 332 : &coin_spent_priv)) ||
671 : (GNUNET_OK !=
672 332 : TALER_TESTING_get_trait_coin_pub (coin_cmd,
673 : ds->coin_index,
674 332 : &coin_spent_pub)) ||
675 : (GNUNET_OK !=
676 332 : TALER_TESTING_get_trait_age_commitment_proof (coin_cmd,
677 : ds->coin_index,
678 332 : &age_commitment_proof)) ||
679 : (GNUNET_OK !=
680 332 : TALER_TESTING_get_trait_h_age_commitment (coin_cmd,
681 : ds->coin_index,
682 : &h_age_commitment)) )
683 : {
684 0 : GNUNET_break (0);
685 0 : TALER_TESTING_interpreter_fail (ds->is);
686 0 : return GNUNET_NO;
687 : }
688 :
689 : {
690 : struct TALER_TESTING_Trait traits[] = {
691 : /* First two traits are only available if
692 : ds->traits is true */
693 332 : TALER_TESTING_make_trait_exchange_pub (0,
694 332 : &ds->exchange_pub),
695 332 : TALER_TESTING_make_trait_exchange_sig (0,
696 332 : &ds->exchange_sig),
697 332 : TALER_TESTING_make_trait_amount (&ds->cumulative_total),
698 : /* These traits are always available */
699 332 : TALER_TESTING_make_trait_coin_history (0,
700 332 : &ds->che),
701 332 : TALER_TESTING_make_trait_coin_priv (0,
702 : coin_spent_priv),
703 332 : TALER_TESTING_make_trait_coin_pub (0,
704 : coin_spent_pub),
705 332 : TALER_TESTING_make_trait_denom_pub (0,
706 : ds->denom_pub),
707 332 : TALER_TESTING_make_trait_coin_sig (0,
708 332 : &ds->coin_sig),
709 332 : TALER_TESTING_make_trait_age_commitment_proof (0,
710 : age_commitment_proof),
711 332 : TALER_TESTING_make_trait_h_age_commitment (0,
712 : h_age_commitment),
713 332 : TALER_TESTING_make_trait_wire_details (ds->wire_details),
714 332 : TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
715 332 : TALER_TESTING_make_trait_merchant_priv (&ds->account_priv.merchant_priv),
716 332 : TALER_TESTING_make_trait_merchant_pub (&ds->account_pub.merchant_pub),
717 332 : TALER_TESTING_make_trait_account_priv (&ds->account_priv),
718 332 : TALER_TESTING_make_trait_account_pub (&ds->account_pub),
719 332 : TALER_TESTING_make_trait_deposit_amount (0,
720 332 : &ds->amount),
721 332 : TALER_TESTING_make_trait_deposit_fee_amount (0,
722 332 : &ds->deposit_fee),
723 332 : TALER_TESTING_make_trait_timestamp (0,
724 332 : &ds->exchange_timestamp),
725 332 : TALER_TESTING_make_trait_wire_deadline (0,
726 332 : &ds->wire_deadline),
727 332 : TALER_TESTING_make_trait_refund_deadline (0,
728 332 : &ds->refund_deadline),
729 332 : TALER_TESTING_trait_end ()
730 : };
731 :
732 332 : return TALER_TESTING_get_trait ((ds->deposit_succeeded)
733 : ? traits
734 : : &traits[2],
735 : ret,
736 : trait,
737 : index);
738 : }
739 : }
740 :
741 :
742 : struct TALER_TESTING_Command
743 80 : TALER_TESTING_cmd_deposit (
744 : const char *label,
745 : const char *coin_reference,
746 : unsigned int coin_index,
747 : struct TALER_FullPayto target_account_payto,
748 : const char *contract_terms,
749 : struct GNUNET_TIME_Relative refund_deadline,
750 : const char *amount,
751 : unsigned int expected_response_code)
752 : {
753 : struct DepositState *ds;
754 :
755 80 : ds = GNUNET_new (struct DepositState);
756 80 : ds->coin_reference = coin_reference;
757 80 : ds->coin_index = coin_index;
758 80 : ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
759 80 : GNUNET_assert (NULL != ds->wire_details);
760 80 : ds->contract_terms = json_loads (contract_terms,
761 : JSON_REJECT_DUPLICATES,
762 : NULL);
763 80 : if (NULL == ds->contract_terms)
764 : {
765 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
766 : "Failed to parse contract terms `%s' for CMD `%s'\n",
767 : contract_terms,
768 : label);
769 0 : GNUNET_assert (0);
770 : }
771 80 : ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
772 80 : GNUNET_assert (0 ==
773 : json_object_set_new (ds->contract_terms,
774 : "timestamp",
775 : GNUNET_JSON_from_timestamp (
776 : ds->wallet_timestamp)));
777 80 : if (! GNUNET_TIME_relative_is_zero (refund_deadline))
778 : {
779 10 : ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
780 10 : GNUNET_assert (0 ==
781 : json_object_set_new (ds->contract_terms,
782 : "refund_deadline",
783 : GNUNET_JSON_from_timestamp (
784 : ds->refund_deadline)));
785 : }
786 80 : GNUNET_assert (GNUNET_OK ==
787 : TALER_string_to_amount (amount,
788 : &ds->amount));
789 80 : ds->expected_response_code = expected_response_code;
790 80 : ds->command_initialized = true;
791 : {
792 80 : struct TALER_TESTING_Command cmd = {
793 : .cls = ds,
794 : .label = label,
795 : .run = &deposit_run,
796 : .cleanup = &deposit_cleanup,
797 : .traits = &deposit_traits
798 : };
799 :
800 80 : return cmd;
801 : }
802 : }
803 :
804 :
805 : struct TALER_TESTING_Command
806 2 : TALER_TESTING_cmd_deposit_with_ref (
807 : const char *label,
808 : const char *coin_reference,
809 : unsigned int coin_index,
810 : struct TALER_FullPayto target_account_payto,
811 : const char *contract_terms,
812 : struct GNUNET_TIME_Relative refund_deadline,
813 : const char *amount,
814 : unsigned int expected_response_code,
815 : const char *merchant_priv_reference)
816 : {
817 : struct DepositState *ds;
818 :
819 2 : ds = GNUNET_new (struct DepositState);
820 2 : ds->merchant_priv_reference = merchant_priv_reference;
821 2 : ds->coin_reference = coin_reference;
822 2 : ds->coin_index = coin_index;
823 2 : ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
824 2 : GNUNET_assert (NULL != ds->wire_details);
825 2 : ds->contract_terms = json_loads (contract_terms,
826 : JSON_REJECT_DUPLICATES,
827 : NULL);
828 2 : if (NULL == ds->contract_terms)
829 : {
830 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
831 : "Failed to parse contract terms `%s' for CMD `%s'\n",
832 : contract_terms,
833 : label);
834 0 : GNUNET_assert (0);
835 : }
836 2 : ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
837 2 : GNUNET_assert (0 ==
838 : json_object_set_new (ds->contract_terms,
839 : "timestamp",
840 : GNUNET_JSON_from_timestamp (
841 : ds->wallet_timestamp)));
842 2 : if (0 != refund_deadline.rel_value_us)
843 : {
844 0 : ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
845 0 : GNUNET_assert (0 ==
846 : json_object_set_new (ds->contract_terms,
847 : "refund_deadline",
848 : GNUNET_JSON_from_timestamp (
849 : ds->refund_deadline)));
850 : }
851 2 : GNUNET_assert (GNUNET_OK ==
852 : TALER_string_to_amount (amount,
853 : &ds->amount));
854 2 : ds->expected_response_code = expected_response_code;
855 2 : ds->command_initialized = true;
856 : {
857 2 : struct TALER_TESTING_Command cmd = {
858 : .cls = ds,
859 : .label = label,
860 : .run = &deposit_run,
861 : .cleanup = &deposit_cleanup,
862 : .traits = &deposit_traits
863 : };
864 :
865 2 : return cmd;
866 : }
867 : }
868 :
869 :
870 : struct TALER_TESTING_Command
871 14 : TALER_TESTING_cmd_deposit_replay (
872 : const char *label,
873 : const char *deposit_reference,
874 : unsigned int expected_response_code)
875 : {
876 : struct DepositState *ds;
877 :
878 14 : ds = GNUNET_new (struct DepositState);
879 14 : ds->deposit_reference = deposit_reference;
880 14 : ds->expected_response_code = expected_response_code;
881 : {
882 14 : struct TALER_TESTING_Command cmd = {
883 : .cls = ds,
884 : .label = label,
885 : .run = &deposit_run,
886 : .cleanup = &deposit_cleanup,
887 : .traits = &deposit_traits
888 : };
889 :
890 14 : return cmd;
891 : }
892 : }
893 :
894 :
895 : struct TALER_TESTING_Command
896 0 : TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd)
897 : {
898 : struct DepositState *ds;
899 :
900 0 : GNUNET_assert (&deposit_run == cmd.run);
901 0 : ds = cmd.cls;
902 0 : ds->do_retry = NUM_RETRIES;
903 0 : return cmd;
904 : }
905 :
906 :
907 : /* end of testing_api_cmd_deposit.c */
|