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