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