Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2018-2021 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 "platform.h"
25 : #include "taler_json_lib.h"
26 : #include <gnunet/gnunet_curl_lib.h>
27 : #include "taler_testing_lib.h"
28 : #include "taler_signatures.h"
29 : #include "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 : * Wire details of who is depositing -- this would be merchant
73 : * wire details in a normal scenario.
74 : */
75 : json_t *wire_details;
76 :
77 : /**
78 : * JSON string describing what a proposal is about.
79 : */
80 : json_t *contract_terms;
81 :
82 : /**
83 : * Refund deadline. Zero for no refunds.
84 : */
85 : struct GNUNET_TIME_Timestamp refund_deadline;
86 :
87 : /**
88 : * Wire deadline.
89 : */
90 : struct GNUNET_TIME_Timestamp wire_deadline;
91 :
92 : /**
93 : * Set (by the interpreter) to a fresh private key. This
94 : * key will be used to sign the deposit request.
95 : */
96 : struct TALER_MerchantPrivateKeyP merchant_priv;
97 :
98 : /**
99 : * Deposit handle while operation is running.
100 : */
101 : struct TALER_EXCHANGE_DepositHandle *dh;
102 :
103 : /**
104 : * Timestamp of the /deposit operation in the wallet (contract signing time).
105 : */
106 : struct GNUNET_TIME_Timestamp wallet_timestamp;
107 :
108 : /**
109 : * Interpreter state.
110 : */
111 : struct TALER_TESTING_Interpreter *is;
112 :
113 : /**
114 : * Task scheduled to try later.
115 : */
116 : struct GNUNET_SCHEDULER_Task *retry_task;
117 :
118 : /**
119 : * How long do we wait until we retry?
120 : */
121 : struct GNUNET_TIME_Relative backoff;
122 :
123 : /**
124 : * Expected HTTP response code.
125 : */
126 : unsigned int expected_response_code;
127 :
128 : /**
129 : * How often should we retry on (transient) failures?
130 : */
131 : unsigned int do_retry;
132 :
133 : /**
134 : * Set to #GNUNET_YES if the /deposit succeeded
135 : * and we now can provide the resulting traits.
136 : */
137 : int deposit_succeeded;
138 :
139 : /**
140 : * When did the exchange receive the deposit?
141 : */
142 : struct GNUNET_TIME_Timestamp exchange_timestamp;
143 :
144 : /**
145 : * Signing key used by the exchange to sign the
146 : * deposit confirmation.
147 : */
148 : struct TALER_ExchangePublicKeyP exchange_pub;
149 :
150 : /**
151 : * Signature from the exchange on the
152 : * deposit confirmation.
153 : */
154 : struct TALER_ExchangeSignatureP exchange_sig;
155 :
156 : /**
157 : * Reference to previous deposit operation.
158 : * Only present if we're supposed to replay the previous deposit.
159 : */
160 : const char *deposit_reference;
161 :
162 : /**
163 : * Did we set the parameters for this deposit command?
164 : *
165 : * When we're referencing another deposit operation,
166 : * this will only be set after the command has been started.
167 : */
168 : int command_initialized;
169 :
170 : /**
171 : * Reference to fetch the merchant private key from.
172 : * If NULL, we generate our own, fresh merchant key.
173 : */
174 : const char *merchant_priv_reference;
175 : };
176 :
177 :
178 : /**
179 : * Run the command.
180 : *
181 : * @param cls closure.
182 : * @param cmd the command to execute.
183 : * @param is the interpreter state.
184 : */
185 : static void
186 : deposit_run (void *cls,
187 : const struct TALER_TESTING_Command *cmd,
188 : struct TALER_TESTING_Interpreter *is);
189 :
190 :
191 : /**
192 : * Task scheduled to re-try #deposit_run.
193 : *
194 : * @param cls a `struct DepositState`
195 : */
196 : static void
197 0 : do_retry (void *cls)
198 : {
199 0 : struct DepositState *ds = cls;
200 :
201 0 : ds->retry_task = NULL;
202 0 : ds->is->commands[ds->is->ip].last_req_time
203 0 : = GNUNET_TIME_absolute_get ();
204 0 : deposit_run (ds,
205 : NULL,
206 : ds->is);
207 0 : }
208 :
209 :
210 : /**
211 : * Callback to analyze the /deposit response, just used to
212 : * check if the response code is acceptable.
213 : *
214 : * @param cls closure.
215 : * @param dr deposit response details
216 : */
217 : static void
218 0 : deposit_cb (void *cls,
219 : const struct TALER_EXCHANGE_DepositResult *dr)
220 : {
221 0 : struct DepositState *ds = cls;
222 :
223 0 : ds->dh = NULL;
224 0 : if (ds->expected_response_code != dr->hr.http_status)
225 : {
226 0 : if (0 != ds->do_retry)
227 : {
228 0 : ds->do_retry--;
229 0 : if ( (0 == dr->hr.http_status) ||
230 0 : (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec) ||
231 0 : (MHD_HTTP_INTERNAL_SERVER_ERROR == dr->hr.http_status) )
232 : {
233 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
234 : "Retrying deposit failed with %u/%d\n",
235 : dr->hr.http_status,
236 : (int) dr->hr.ec);
237 : /* on DB conflicts, do not use backoff */
238 0 : if (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec)
239 0 : ds->backoff = GNUNET_TIME_UNIT_ZERO;
240 : else
241 0 : ds->backoff = GNUNET_TIME_randomized_backoff (ds->backoff,
242 : MAX_BACKOFF);
243 0 : ds->is->commands[ds->is->ip].num_tries++;
244 0 : GNUNET_assert (NULL == ds->retry_task);
245 : ds->retry_task
246 0 : = GNUNET_SCHEDULER_add_delayed (ds->backoff,
247 : &do_retry,
248 : ds);
249 0 : return;
250 : }
251 : }
252 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
253 : "Unexpected response code %u to command %s in %s:%u\n",
254 : dr->hr.http_status,
255 : ds->is->commands[ds->is->ip].label,
256 : __FILE__,
257 : __LINE__);
258 0 : json_dumpf (dr->hr.reply,
259 : stderr,
260 : JSON_INDENT (2));
261 0 : TALER_TESTING_interpreter_fail (ds->is);
262 0 : return;
263 : }
264 0 : if (MHD_HTTP_OK == dr->hr.http_status)
265 : {
266 0 : ds->deposit_succeeded = GNUNET_YES;
267 0 : ds->exchange_timestamp = dr->details.success.deposit_timestamp;
268 0 : ds->exchange_pub = *dr->details.success.exchange_pub;
269 0 : ds->exchange_sig = *dr->details.success.exchange_sig;
270 : }
271 0 : TALER_TESTING_interpreter_next (ds->is);
272 : }
273 :
274 :
275 : /**
276 : * Run the command.
277 : *
278 : * @param cls closure.
279 : * @param cmd the command to execute.
280 : * @param is the interpreter state.
281 : */
282 : static void
283 0 : deposit_run (void *cls,
284 : const struct TALER_TESTING_Command *cmd,
285 : struct TALER_TESTING_Interpreter *is)
286 : {
287 0 : struct DepositState *ds = cls;
288 : const struct TALER_TESTING_Command *coin_cmd;
289 : const struct TALER_CoinSpendPrivateKeyP *coin_priv;
290 : struct TALER_CoinSpendPublicKeyP coin_pub;
291 0 : const struct TALER_AgeCommitmentProof *age_commitment_proof = NULL;
292 0 : struct TALER_AgeCommitmentHash h_age_commitment = {0};
293 : const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
294 : const struct TALER_DenominationSignature *denom_pub_sig;
295 : struct TALER_CoinSpendSignatureP coin_sig;
296 : struct TALER_MerchantPublicKeyP merchant_pub;
297 : struct TALER_PrivateContractHashP h_contract_terms;
298 : enum TALER_ErrorCode ec;
299 : struct TALER_WireSaltP wire_salt;
300 : const char *payto_uri;
301 : struct GNUNET_JSON_Specification spec[] = {
302 0 : GNUNET_JSON_spec_string ("payto_uri",
303 : &payto_uri),
304 0 : GNUNET_JSON_spec_fixed_auto ("salt",
305 : &wire_salt),
306 0 : GNUNET_JSON_spec_end ()
307 : };
308 :
309 : (void) cmd;
310 0 : ds->is = is;
311 0 : if (NULL != ds->deposit_reference)
312 : {
313 : /* We're copying another deposit operation, initialize here. */
314 : const struct TALER_TESTING_Command *cmd;
315 : struct DepositState *ods;
316 :
317 0 : cmd = TALER_TESTING_interpreter_lookup_command (is,
318 : ds->deposit_reference);
319 0 : if (NULL == cmd)
320 : {
321 0 : GNUNET_break (0);
322 0 : TALER_TESTING_interpreter_fail (is);
323 0 : return;
324 : }
325 0 : ods = cmd->cls;
326 0 : ds->coin_reference = ods->coin_reference;
327 0 : ds->coin_index = ods->coin_index;
328 0 : ds->wire_details = json_incref (ods->wire_details);
329 0 : GNUNET_assert (NULL != ds->wire_details);
330 0 : ds->contract_terms = json_incref (ods->contract_terms);
331 0 : ds->wallet_timestamp = ods->wallet_timestamp;
332 0 : ds->refund_deadline = ods->refund_deadline;
333 0 : ds->amount = ods->amount;
334 0 : ds->merchant_priv = ods->merchant_priv;
335 0 : ds->command_initialized = GNUNET_YES;
336 : }
337 0 : else if (NULL != ds->merchant_priv_reference)
338 : {
339 : /* We're copying the merchant key from another deposit operation */
340 : const struct TALER_MerchantPrivateKeyP *merchant_priv;
341 : const struct TALER_TESTING_Command *cmd;
342 :
343 0 : cmd = TALER_TESTING_interpreter_lookup_command (is,
344 : ds->merchant_priv_reference);
345 0 : if (NULL == cmd)
346 : {
347 0 : GNUNET_break (0);
348 0 : TALER_TESTING_interpreter_fail (is);
349 0 : return;
350 : }
351 0 : if ( (GNUNET_OK !=
352 0 : TALER_TESTING_get_trait_merchant_priv (cmd,
353 : &merchant_priv)) )
354 : {
355 0 : GNUNET_break (0);
356 0 : TALER_TESTING_interpreter_fail (is);
357 0 : return;
358 : }
359 0 : ds->merchant_priv = *merchant_priv;
360 : }
361 0 : GNUNET_assert (NULL != ds->wire_details);
362 0 : if (GNUNET_OK !=
363 0 : GNUNET_JSON_parse (ds->wire_details,
364 : spec,
365 : NULL, NULL))
366 : {
367 0 : json_dumpf (ds->wire_details,
368 : stderr,
369 : JSON_INDENT (2));
370 0 : GNUNET_break (0);
371 0 : TALER_TESTING_interpreter_fail (is);
372 0 : return;
373 : }
374 0 : GNUNET_assert (ds->coin_reference);
375 0 : coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
376 : ds->coin_reference);
377 0 : if (NULL == coin_cmd)
378 : {
379 0 : GNUNET_break (0);
380 0 : TALER_TESTING_interpreter_fail (is);
381 0 : return;
382 : }
383 :
384 0 : if ( (GNUNET_OK !=
385 0 : TALER_TESTING_get_trait_coin_priv (coin_cmd,
386 : ds->coin_index,
387 0 : &coin_priv)) ||
388 : (GNUNET_OK !=
389 0 : TALER_TESTING_get_trait_age_commitment_proof (coin_cmd,
390 : ds->coin_index,
391 0 : &age_commitment_proof)) ||
392 : (GNUNET_OK !=
393 0 : TALER_TESTING_get_trait_denom_pub (coin_cmd,
394 : ds->coin_index,
395 0 : &denom_pub)) ||
396 : (GNUNET_OK !=
397 0 : TALER_TESTING_get_trait_denom_sig (coin_cmd,
398 : ds->coin_index,
399 0 : &denom_pub_sig)) ||
400 : (GNUNET_OK !=
401 0 : TALER_JSON_contract_hash (ds->contract_terms,
402 : &h_contract_terms)) )
403 : {
404 0 : GNUNET_break (0);
405 0 : TALER_TESTING_interpreter_fail (is);
406 0 : return;
407 : }
408 :
409 0 : if (NULL != age_commitment_proof)
410 : {
411 0 : TALER_age_commitment_hash (&age_commitment_proof->commitment,
412 : &h_age_commitment);
413 : }
414 0 : ds->deposit_fee = denom_pub->fees.deposit;
415 0 : GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
416 : &coin_pub.eddsa_pub);
417 :
418 0 : if (! GNUNET_TIME_absolute_is_zero (ds->refund_deadline.abs_time))
419 : {
420 : struct GNUNET_TIME_Relative refund_deadline;
421 :
422 : refund_deadline
423 0 : = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline.abs_time);
424 : ds->wire_deadline
425 : =
426 0 : GNUNET_TIME_relative_to_timestamp (
427 : GNUNET_TIME_relative_multiply (refund_deadline,
428 : 2));
429 : }
430 : else
431 : {
432 0 : ds->refund_deadline = ds->wallet_timestamp;
433 0 : ds->wire_deadline = GNUNET_TIME_timestamp_get ();
434 : }
435 0 : GNUNET_CRYPTO_eddsa_key_get_public (&ds->merchant_priv.eddsa_priv,
436 : &merchant_pub.eddsa_pub);
437 : {
438 : struct TALER_MerchantWireHashP h_wire;
439 :
440 0 : GNUNET_assert (GNUNET_OK ==
441 : TALER_JSON_merchant_wire_signature_hash (ds->wire_details,
442 : &h_wire));
443 0 : TALER_wallet_deposit_sign (&ds->amount,
444 0 : &denom_pub->fees.deposit,
445 : &h_wire,
446 : &h_contract_terms,
447 : &h_age_commitment,
448 : NULL, /* FIXME #7270: add hash of extensions */
449 0 : &denom_pub->h_key,
450 : ds->wallet_timestamp,
451 : &merchant_pub,
452 : ds->refund_deadline,
453 : coin_priv,
454 : &coin_sig);
455 : }
456 0 : GNUNET_assert (NULL == ds->dh);
457 : {
458 0 : struct TALER_EXCHANGE_CoinDepositDetail cdd = {
459 : .amount = ds->amount,
460 : .h_age_commitment = h_age_commitment,
461 : .coin_pub = coin_pub,
462 : .coin_sig = coin_sig,
463 0 : .denom_sig = *denom_pub_sig,
464 0 : .h_denom_pub = denom_pub->h_key
465 : };
466 0 : struct TALER_EXCHANGE_DepositContractDetail dcd = {
467 : .wire_deadline = ds->wire_deadline,
468 : .merchant_payto_uri = payto_uri,
469 : .wire_salt = wire_salt,
470 : .h_contract_terms = h_contract_terms,
471 : .extension_details = NULL /* FIXME #7270-OEC */,
472 : .timestamp = ds->wallet_timestamp,
473 : .merchant_pub = merchant_pub,
474 : .refund_deadline = ds->refund_deadline
475 : };
476 :
477 0 : ds->dh = TALER_EXCHANGE_deposit (is->exchange,
478 : &dcd,
479 : &cdd,
480 : &deposit_cb,
481 : ds,
482 : &ec);
483 : }
484 0 : if (NULL == ds->dh)
485 : {
486 0 : GNUNET_break (0);
487 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
488 : "Could not create deposit with EC %d\n",
489 : (int) ec);
490 0 : TALER_TESTING_interpreter_fail (is);
491 0 : return;
492 : }
493 : }
494 :
495 :
496 : /**
497 : * Free the state of a "deposit" CMD, and possibly cancel a
498 : * pending operation thereof.
499 : *
500 : * @param cls closure, must be a `struct DepositState`.
501 : * @param cmd the command which is being cleaned up.
502 : */
503 : static void
504 0 : deposit_cleanup (void *cls,
505 : const struct TALER_TESTING_Command *cmd)
506 : {
507 0 : struct DepositState *ds = cls;
508 :
509 0 : if (NULL != ds->dh)
510 : {
511 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
512 : "Command %u (%s) did not complete\n",
513 : ds->is->ip,
514 : cmd->label);
515 0 : TALER_EXCHANGE_deposit_cancel (ds->dh);
516 0 : ds->dh = NULL;
517 : }
518 0 : if (NULL != ds->retry_task)
519 : {
520 0 : GNUNET_SCHEDULER_cancel (ds->retry_task);
521 0 : ds->retry_task = NULL;
522 : }
523 0 : json_decref (ds->wire_details);
524 0 : json_decref (ds->contract_terms);
525 0 : GNUNET_free (ds);
526 0 : }
527 :
528 :
529 : /**
530 : * Offer internal data from a "deposit" CMD, to other commands.
531 : *
532 : * @param cls closure.
533 : * @param[out] ret result.
534 : * @param trait name of the trait.
535 : * @param index index number of the object to offer.
536 : * @return #GNUNET_OK on success.
537 : */
538 : static enum GNUNET_GenericReturnValue
539 0 : deposit_traits (void *cls,
540 : const void **ret,
541 : const char *trait,
542 : unsigned int index)
543 : {
544 0 : struct DepositState *ds = cls;
545 : const struct TALER_TESTING_Command *coin_cmd;
546 : /* Will point to coin cmd internals. */
547 : const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv;
548 : const struct TALER_AgeCommitmentProof *age_commitment_proof;
549 :
550 0 : if (GNUNET_YES != ds->command_initialized)
551 : {
552 : /* No access to traits yet. */
553 0 : GNUNET_break (0);
554 0 : return GNUNET_NO;
555 : }
556 :
557 : coin_cmd
558 0 : = TALER_TESTING_interpreter_lookup_command (ds->is,
559 : ds->coin_reference);
560 0 : if (NULL == coin_cmd)
561 : {
562 0 : GNUNET_break (0);
563 0 : TALER_TESTING_interpreter_fail (ds->is);
564 0 : return GNUNET_NO;
565 : }
566 0 : if ( (GNUNET_OK !=
567 0 : TALER_TESTING_get_trait_coin_priv (coin_cmd,
568 : ds->coin_index,
569 0 : &coin_spent_priv)) ||
570 : (GNUNET_OK !=
571 0 : TALER_TESTING_get_trait_age_commitment_proof (coin_cmd,
572 : ds->coin_index,
573 : &age_commitment_proof)) )
574 : {
575 0 : GNUNET_break (0);
576 0 : TALER_TESTING_interpreter_fail (ds->is);
577 0 : return GNUNET_NO;
578 : }
579 : {
580 : struct TALER_TESTING_Trait traits[] = {
581 : /* First two traits are only available if
582 : ds->traits is #GNUNET_YES */
583 0 : TALER_TESTING_make_trait_exchange_pub (0,
584 0 : &ds->exchange_pub),
585 0 : TALER_TESTING_make_trait_exchange_sig (0,
586 0 : &ds->exchange_sig),
587 : /* These traits are always available */
588 0 : TALER_TESTING_make_trait_coin_priv (0,
589 : coin_spent_priv),
590 0 : TALER_TESTING_make_trait_age_commitment_proof (0,
591 : age_commitment_proof),
592 0 : TALER_TESTING_make_trait_wire_details (ds->wire_details),
593 0 : TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
594 0 : TALER_TESTING_make_trait_merchant_priv (&ds->merchant_priv),
595 0 : TALER_TESTING_make_trait_deposit_amount (0,
596 0 : &ds->amount),
597 0 : TALER_TESTING_make_trait_deposit_fee_amount (0,
598 0 : &ds->deposit_fee),
599 0 : TALER_TESTING_make_trait_timestamp (0,
600 0 : &ds->exchange_timestamp),
601 0 : TALER_TESTING_make_trait_wire_deadline (0,
602 0 : &ds->wire_deadline),
603 0 : TALER_TESTING_make_trait_refund_deadline (0,
604 0 : &ds->refund_deadline),
605 0 : TALER_TESTING_trait_end ()
606 : };
607 :
608 0 : return TALER_TESTING_get_trait ((ds->deposit_succeeded)
609 : ? traits
610 : : &traits[2],
611 : ret,
612 : trait,
613 : index);
614 : }
615 : }
616 :
617 :
618 : struct TALER_TESTING_Command
619 0 : TALER_TESTING_cmd_deposit (const char *label,
620 : const char *coin_reference,
621 : unsigned int coin_index,
622 : const char *target_account_payto,
623 : const char *contract_terms,
624 : struct GNUNET_TIME_Relative refund_deadline,
625 : const char *amount,
626 : unsigned int expected_response_code)
627 : {
628 : struct DepositState *ds;
629 :
630 0 : ds = GNUNET_new (struct DepositState);
631 0 : ds->coin_reference = coin_reference;
632 0 : ds->coin_index = coin_index;
633 0 : ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
634 0 : GNUNET_assert (NULL != ds->wire_details);
635 0 : ds->contract_terms = json_loads (contract_terms,
636 : JSON_REJECT_DUPLICATES,
637 : NULL);
638 0 : GNUNET_CRYPTO_eddsa_key_create (&ds->merchant_priv.eddsa_priv);
639 0 : if (NULL == ds->contract_terms)
640 : {
641 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
642 : "Failed to parse contract terms `%s' for CMD `%s'\n",
643 : contract_terms,
644 : label);
645 0 : GNUNET_assert (0);
646 : }
647 0 : ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
648 0 : GNUNET_assert (0 ==
649 : json_object_set_new (ds->contract_terms,
650 : "timestamp",
651 : GNUNET_JSON_from_timestamp (
652 : ds->wallet_timestamp)));
653 0 : if (! GNUNET_TIME_relative_is_zero (refund_deadline))
654 : {
655 0 : ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
656 0 : GNUNET_assert (0 ==
657 : json_object_set_new (ds->contract_terms,
658 : "refund_deadline",
659 : GNUNET_JSON_from_timestamp (
660 : ds->refund_deadline)));
661 : }
662 0 : GNUNET_assert (GNUNET_OK ==
663 : TALER_string_to_amount (amount,
664 : &ds->amount));
665 0 : ds->expected_response_code = expected_response_code;
666 0 : ds->command_initialized = GNUNET_YES;
667 : {
668 0 : struct TALER_TESTING_Command cmd = {
669 : .cls = ds,
670 : .label = label,
671 : .run = &deposit_run,
672 : .cleanup = &deposit_cleanup,
673 : .traits = &deposit_traits
674 : };
675 :
676 0 : return cmd;
677 : }
678 : }
679 :
680 :
681 : struct TALER_TESTING_Command
682 0 : TALER_TESTING_cmd_deposit_with_ref (const char *label,
683 : const char *coin_reference,
684 : unsigned int coin_index,
685 : const char *target_account_payto,
686 : const char *contract_terms,
687 : struct GNUNET_TIME_Relative refund_deadline,
688 : const char *amount,
689 : unsigned int expected_response_code,
690 : const char *merchant_priv_reference)
691 : {
692 : struct DepositState *ds;
693 :
694 0 : ds = GNUNET_new (struct DepositState);
695 0 : ds->merchant_priv_reference = merchant_priv_reference;
696 0 : ds->coin_reference = coin_reference;
697 0 : ds->coin_index = coin_index;
698 0 : ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
699 0 : GNUNET_assert (NULL != ds->wire_details);
700 0 : ds->contract_terms = json_loads (contract_terms,
701 : JSON_REJECT_DUPLICATES,
702 : NULL);
703 0 : if (NULL == ds->contract_terms)
704 : {
705 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
706 : "Failed to parse contract terms `%s' for CMD `%s'\n",
707 : contract_terms,
708 : label);
709 0 : GNUNET_assert (0);
710 : }
711 0 : ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
712 0 : json_object_set_new (ds->contract_terms,
713 : "timestamp",
714 : GNUNET_JSON_from_timestamp (ds->wallet_timestamp));
715 0 : if (0 != refund_deadline.rel_value_us)
716 : {
717 0 : ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
718 0 : json_object_set_new (ds->contract_terms,
719 : "refund_deadline",
720 : GNUNET_JSON_from_timestamp (ds->refund_deadline));
721 : }
722 0 : GNUNET_assert (GNUNET_OK ==
723 : TALER_string_to_amount (amount,
724 : &ds->amount));
725 0 : ds->expected_response_code = expected_response_code;
726 0 : ds->command_initialized = GNUNET_YES;
727 : {
728 0 : struct TALER_TESTING_Command cmd = {
729 : .cls = ds,
730 : .label = label,
731 : .run = &deposit_run,
732 : .cleanup = &deposit_cleanup,
733 : .traits = &deposit_traits
734 : };
735 :
736 0 : return cmd;
737 : }
738 : }
739 :
740 :
741 : struct TALER_TESTING_Command
742 0 : TALER_TESTING_cmd_deposit_replay (const char *label,
743 : const char *deposit_reference,
744 : unsigned int expected_response_code)
745 : {
746 : struct DepositState *ds;
747 :
748 0 : ds = GNUNET_new (struct DepositState);
749 0 : ds->deposit_reference = deposit_reference;
750 0 : ds->expected_response_code = expected_response_code;
751 : {
752 0 : struct TALER_TESTING_Command cmd = {
753 : .cls = ds,
754 : .label = label,
755 : .run = &deposit_run,
756 : .cleanup = &deposit_cleanup,
757 : .traits = &deposit_traits
758 : };
759 :
760 0 : return cmd;
761 : }
762 : }
763 :
764 :
765 : struct TALER_TESTING_Command
766 0 : TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd)
767 : {
768 : struct DepositState *ds;
769 :
770 0 : GNUNET_assert (&deposit_run == cmd.run);
771 0 : ds = cmd.cls;
772 0 : ds->do_retry = NUM_RETRIES;
773 0 : return cmd;
774 : }
775 :
776 :
777 : /* end of testing_api_cmd_deposit.c */
|