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 "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 : * 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_BatchDepositHandle *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 : * Reference to previous deposit operation.
180 : * Only present if we're supposed to replay the previous deposit.
181 : */
182 : const char *deposit_reference;
183 :
184 : /**
185 : * Did we set the parameters for this deposit command?
186 : *
187 : * When we're referencing another deposit operation,
188 : * this will only be set after the command has been started.
189 : */
190 : bool command_initialized;
191 :
192 : /**
193 : * Reference to fetch the merchant private key from.
194 : * If NULL, we generate our own, fresh merchant key.
195 : */
196 : const char *merchant_priv_reference;
197 : };
198 :
199 :
200 : /**
201 : * Run the command.
202 : *
203 : * @param cls closure.
204 : * @param cmd the command to execute.
205 : * @param is the interpreter state.
206 : */
207 : static void
208 : deposit_run (void *cls,
209 : const struct TALER_TESTING_Command *cmd,
210 : struct TALER_TESTING_Interpreter *is);
211 :
212 :
213 : /**
214 : * Task scheduled to re-try #deposit_run.
215 : *
216 : * @param cls a `struct DepositState`
217 : */
218 : static void
219 0 : do_retry (void *cls)
220 : {
221 0 : struct DepositState *ds = cls;
222 :
223 0 : ds->retry_task = NULL;
224 0 : TALER_TESTING_touch_cmd (ds->is);
225 0 : deposit_run (ds,
226 : NULL,
227 : ds->is);
228 0 : }
229 :
230 :
231 : /**
232 : * Callback to analyze the /deposit response, just used to
233 : * check if the response code is acceptable.
234 : *
235 : * @param cls closure.
236 : * @param dr deposit response details
237 : */
238 : static void
239 96 : deposit_cb (void *cls,
240 : const struct TALER_EXCHANGE_BatchDepositResult *dr)
241 : {
242 96 : struct DepositState *ds = cls;
243 :
244 96 : ds->dh = NULL;
245 96 : if (ds->expected_response_code != dr->hr.http_status)
246 : {
247 0 : if (0 != ds->do_retry)
248 : {
249 0 : ds->do_retry--;
250 0 : if ( (0 == dr->hr.http_status) ||
251 0 : (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec) ||
252 0 : (MHD_HTTP_INTERNAL_SERVER_ERROR == dr->hr.http_status) )
253 : {
254 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
255 : "Retrying deposit failed with %u/%d\n",
256 : dr->hr.http_status,
257 : (int) dr->hr.ec);
258 : /* on DB conflicts, do not use backoff */
259 0 : if (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec)
260 0 : ds->backoff = GNUNET_TIME_UNIT_ZERO;
261 : else
262 0 : ds->backoff = GNUNET_TIME_randomized_backoff (ds->backoff,
263 : MAX_BACKOFF);
264 0 : TALER_TESTING_inc_tries (ds->is);
265 0 : GNUNET_assert (NULL == ds->retry_task);
266 : ds->retry_task
267 0 : = GNUNET_SCHEDULER_add_delayed (ds->backoff,
268 : &do_retry,
269 : ds);
270 0 : return;
271 : }
272 : }
273 0 : TALER_TESTING_unexpected_status_with_body (
274 : ds->is,
275 : dr->hr.http_status,
276 : ds->expected_response_code,
277 : dr->hr.reply);
278 :
279 0 : return;
280 : }
281 96 : if (MHD_HTTP_OK == dr->hr.http_status)
282 : {
283 82 : ds->deposit_succeeded = true;
284 82 : ds->exchange_timestamp = dr->details.ok.deposit_timestamp;
285 82 : ds->exchange_pub = *dr->details.ok.exchange_pub;
286 82 : ds->exchange_sig = *dr->details.ok.exchange_sig;
287 : }
288 96 : TALER_TESTING_interpreter_next (ds->is);
289 : }
290 :
291 :
292 : /**
293 : * Run the command.
294 : *
295 : * @param cls closure.
296 : * @param cmd the command to execute.
297 : * @param is the interpreter state.
298 : */
299 : static void
300 96 : deposit_run (void *cls,
301 : const struct TALER_TESTING_Command *cmd,
302 : struct TALER_TESTING_Interpreter *is)
303 : {
304 96 : struct DepositState *ds = cls;
305 : const struct TALER_TESTING_Command *coin_cmd;
306 : const struct TALER_TESTING_Command *acc_var;
307 : const struct TALER_CoinSpendPrivateKeyP *coin_priv;
308 : struct TALER_CoinSpendPublicKeyP coin_pub;
309 : const struct TALER_AgeCommitmentHash *phac;
310 : const struct TALER_DenominationSignature *denom_pub_sig;
311 : struct TALER_PrivateContractHashP h_contract_terms;
312 : enum TALER_ErrorCode ec;
313 : struct TALER_WireSaltP wire_salt;
314 : struct TALER_FullPayto payto_uri;
315 : struct GNUNET_JSON_Specification spec[] = {
316 96 : TALER_JSON_spec_full_payto_uri ("payto_uri",
317 : &payto_uri),
318 96 : GNUNET_JSON_spec_fixed_auto ("salt",
319 : &wire_salt),
320 96 : GNUNET_JSON_spec_end ()
321 : };
322 : const char *exchange_url
323 96 : = TALER_TESTING_get_exchange_url (is);
324 :
325 : (void) cmd;
326 96 : if (NULL == exchange_url)
327 : {
328 0 : GNUNET_break (0);
329 0 : return;
330 : }
331 96 : ds->is = is;
332 96 : if (! GNUNET_TIME_absolute_is_zero (ds->refund_deadline.abs_time))
333 : {
334 : struct GNUNET_TIME_Relative refund_deadline;
335 :
336 : refund_deadline
337 10 : = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline.abs_time);
338 : ds->wire_deadline
339 10 : = GNUNET_TIME_relative_to_timestamp (
340 : GNUNET_TIME_relative_multiply (refund_deadline,
341 : 2));
342 : }
343 : else
344 : {
345 86 : ds->refund_deadline = ds->wallet_timestamp;
346 86 : ds->wire_deadline = GNUNET_TIME_timestamp_get ();
347 : }
348 96 : if (NULL != ds->deposit_reference)
349 : {
350 : /* We're copying another deposit operation, initialize here. */
351 : const struct TALER_TESTING_Command *drcmd;
352 : struct DepositState *ods;
353 :
354 14 : drcmd = TALER_TESTING_interpreter_lookup_command (is,
355 : ds->deposit_reference);
356 14 : if (NULL == drcmd)
357 : {
358 0 : GNUNET_break (0);
359 0 : TALER_TESTING_interpreter_fail (is);
360 0 : return;
361 : }
362 14 : ods = drcmd->cls;
363 14 : ds->coin_reference = ods->coin_reference;
364 14 : ds->coin_index = ods->coin_index;
365 14 : ds->wire_details = json_incref (ods->wire_details);
366 14 : GNUNET_assert (NULL != ds->wire_details);
367 14 : ds->contract_terms = json_incref (ods->contract_terms);
368 14 : ds->wallet_timestamp = ods->wallet_timestamp;
369 14 : ds->refund_deadline = ods->refund_deadline;
370 14 : ds->wire_deadline = ods->wire_deadline;
371 14 : ds->amount = ods->amount;
372 14 : ds->account_priv = ods->account_priv;
373 14 : ds->account_pub = ods->account_pub;
374 14 : ds->command_initialized = true;
375 : }
376 82 : else if (NULL != ds->merchant_priv_reference)
377 : {
378 : /* We're copying the merchant key from another deposit operation */
379 : const struct TALER_MerchantPrivateKeyP *merchant_priv;
380 : const struct TALER_TESTING_Command *mpcmd;
381 :
382 2 : mpcmd = TALER_TESTING_interpreter_lookup_command (
383 : is,
384 : ds->merchant_priv_reference);
385 2 : if (NULL == mpcmd)
386 : {
387 0 : GNUNET_break (0);
388 0 : TALER_TESTING_interpreter_fail (is);
389 0 : return;
390 : }
391 2 : if ( (GNUNET_OK !=
392 2 : TALER_TESTING_get_trait_merchant_priv (mpcmd,
393 : &merchant_priv)) )
394 : {
395 0 : GNUNET_break (0);
396 0 : TALER_TESTING_interpreter_fail (is);
397 0 : return;
398 : }
399 2 : ds->account_priv.merchant_priv = *merchant_priv;
400 2 : GNUNET_CRYPTO_eddsa_key_get_public (
401 2 : &ds->account_priv.merchant_priv.eddsa_priv,
402 : &ds->account_pub.merchant_pub.eddsa_pub);
403 : }
404 80 : else if (NULL != (acc_var
405 80 : = TALER_TESTING_interpreter_get_command (
406 : is,
407 : "account-priv")))
408 : {
409 : const union TALER_AccountPrivateKeyP *account_priv;
410 :
411 48 : if ( (GNUNET_OK !=
412 48 : TALER_TESTING_get_trait_account_priv (acc_var,
413 : &account_priv)) )
414 : {
415 0 : GNUNET_break (0);
416 0 : TALER_TESTING_interpreter_fail (is);
417 0 : return;
418 : }
419 48 : ds->account_priv = *account_priv;
420 48 : GNUNET_CRYPTO_eddsa_key_get_public (
421 48 : &ds->account_priv.merchant_priv.eddsa_priv,
422 : &ds->account_pub.merchant_pub.eddsa_pub);
423 : }
424 : else
425 : {
426 32 : GNUNET_CRYPTO_eddsa_key_create (
427 : &ds->account_priv.merchant_priv.eddsa_priv);
428 32 : GNUNET_CRYPTO_eddsa_key_get_public (
429 32 : &ds->account_priv.merchant_priv.eddsa_priv,
430 : &ds->account_pub.merchant_pub.eddsa_pub);
431 : }
432 96 : GNUNET_assert (NULL != ds->wire_details);
433 96 : if (GNUNET_OK !=
434 96 : GNUNET_JSON_parse (ds->wire_details,
435 : spec,
436 : NULL, NULL))
437 : {
438 0 : json_dumpf (ds->wire_details,
439 : stderr,
440 : JSON_INDENT (2));
441 0 : GNUNET_break (0);
442 0 : TALER_TESTING_interpreter_fail (is);
443 0 : return;
444 : }
445 96 : GNUNET_assert (ds->coin_reference);
446 96 : coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
447 : ds->coin_reference);
448 96 : if (NULL == coin_cmd)
449 : {
450 0 : GNUNET_break (0);
451 0 : TALER_TESTING_interpreter_fail (is);
452 0 : return;
453 : }
454 : #if DUMP_CONTRACT
455 : fprintf (stderr,
456 : "Using contract:\n");
457 : json_dumpf (ds->contract_terms,
458 : stderr,
459 : JSON_INDENT (2));
460 : #endif
461 96 : if (GNUNET_OK !=
462 96 : TALER_TESTING_get_trait_coin_priv (coin_cmd,
463 : ds->coin_index,
464 : &coin_priv))
465 : {
466 0 : GNUNET_break (0);
467 0 : TALER_TESTING_interpreter_fail (is);
468 0 : return;
469 : }
470 96 : if (GNUNET_OK !=
471 96 : TALER_TESTING_get_trait_h_age_commitment (coin_cmd,
472 : ds->coin_index,
473 : &phac))
474 : {
475 0 : GNUNET_break (0);
476 0 : TALER_TESTING_interpreter_fail (is);
477 0 : return;
478 : }
479 96 : if (GNUNET_OK !=
480 96 : TALER_TESTING_get_trait_denom_pub (coin_cmd,
481 : ds->coin_index,
482 : &ds->denom_pub))
483 : {
484 0 : GNUNET_break (0);
485 0 : TALER_TESTING_interpreter_fail (is);
486 0 : return;
487 : }
488 96 : if (GNUNET_OK !=
489 96 : TALER_TESTING_get_trait_denom_sig (coin_cmd,
490 : ds->coin_index,
491 : &denom_pub_sig))
492 : {
493 0 : GNUNET_break (0);
494 0 : TALER_TESTING_interpreter_fail (is);
495 0 : return;
496 : }
497 96 : if (GNUNET_OK !=
498 96 : TALER_JSON_contract_hash (ds->contract_terms,
499 : &h_contract_terms))
500 : {
501 0 : GNUNET_break (0);
502 0 : TALER_TESTING_interpreter_fail (is);
503 0 : return;
504 : }
505 :
506 96 : ds->deposit_fee = ds->denom_pub->fees.deposit;
507 96 : GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
508 : &coin_pub.eddsa_pub);
509 :
510 : {
511 : struct TALER_MerchantWireHashP h_wire;
512 :
513 96 : GNUNET_assert (GNUNET_OK ==
514 : TALER_JSON_merchant_wire_signature_hash (ds->wire_details,
515 : &h_wire));
516 96 : TALER_wallet_deposit_sign (&ds->amount,
517 96 : &ds->denom_pub->fees.deposit,
518 : &h_wire,
519 : &h_contract_terms,
520 : NULL, /* wallet data hash */
521 : phac,
522 : NULL, /* hash of extensions */
523 96 : &ds->denom_pub->h_key,
524 : ds->wallet_timestamp,
525 96 : &ds->account_pub.merchant_pub,
526 : ds->refund_deadline,
527 : coin_priv,
528 : &ds->coin_sig);
529 96 : ds->che.type = TALER_EXCHANGE_CTT_DEPOSIT;
530 96 : ds->che.amount = ds->amount;
531 96 : ds->che.details.deposit.h_wire = h_wire;
532 96 : ds->che.details.deposit.h_contract_terms = h_contract_terms;
533 96 : ds->che.details.deposit.no_h_policy = true;
534 96 : ds->che.details.deposit.no_wallet_data_hash = true;
535 96 : ds->che.details.deposit.wallet_timestamp = ds->wallet_timestamp;
536 96 : ds->che.details.deposit.merchant_pub = ds->account_pub.merchant_pub;
537 96 : ds->che.details.deposit.refund_deadline = ds->refund_deadline;
538 96 : ds->che.details.deposit.sig = ds->coin_sig;
539 96 : ds->che.details.deposit.no_hac = true;
540 96 : ds->che.details.deposit.deposit_fee = ds->denom_pub->fees.deposit;
541 : }
542 96 : GNUNET_assert (NULL == ds->dh);
543 : {
544 96 : struct TALER_EXCHANGE_CoinDepositDetail cdd = {
545 : .amount = ds->amount,
546 : .coin_pub = coin_pub,
547 : .coin_sig = ds->coin_sig,
548 96 : .denom_sig = *denom_pub_sig,
549 96 : .h_denom_pub = ds->denom_pub->h_key,
550 : .h_age_commitment = {{{0}}},
551 : };
552 96 : struct TALER_EXCHANGE_DepositContractDetail dcd = {
553 : .wire_deadline = ds->wire_deadline,
554 : .merchant_payto_uri = payto_uri,
555 : .wire_salt = wire_salt,
556 : .h_contract_terms = h_contract_terms,
557 : .wallet_timestamp = ds->wallet_timestamp,
558 : .merchant_pub = ds->account_pub.merchant_pub,
559 : .refund_deadline = ds->refund_deadline
560 : };
561 :
562 96 : TALER_merchant_contract_sign (&h_contract_terms,
563 96 : &ds->account_priv.merchant_priv,
564 : &dcd.merchant_sig);
565 96 : if (NULL != phac)
566 32 : cdd.h_age_commitment = *phac;
567 :
568 96 : ds->dh = TALER_EXCHANGE_batch_deposit (
569 : TALER_TESTING_interpreter_get_context (is),
570 : exchange_url,
571 : TALER_TESTING_get_keys (is),
572 : &dcd,
573 : 1,
574 : &cdd,
575 : &deposit_cb,
576 : ds,
577 : &ec);
578 : }
579 96 : if (NULL == ds->dh)
580 : {
581 0 : GNUNET_break (0);
582 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
583 : "Could not create deposit with EC %d\n",
584 : (int) ec);
585 0 : TALER_TESTING_interpreter_fail (is);
586 0 : return;
587 : }
588 : }
589 :
590 :
591 : /**
592 : * Free the state of a "deposit" CMD, and possibly cancel a
593 : * pending operation thereof.
594 : *
595 : * @param cls closure, must be a `struct DepositState`.
596 : * @param cmd the command which is being cleaned up.
597 : */
598 : static void
599 96 : deposit_cleanup (void *cls,
600 : const struct TALER_TESTING_Command *cmd)
601 : {
602 96 : struct DepositState *ds = cls;
603 :
604 96 : if (NULL != ds->dh)
605 : {
606 0 : TALER_TESTING_command_incomplete (ds->is,
607 : cmd->label);
608 0 : TALER_EXCHANGE_batch_deposit_cancel (ds->dh);
609 0 : ds->dh = NULL;
610 : }
611 96 : if (NULL != ds->retry_task)
612 : {
613 0 : GNUNET_SCHEDULER_cancel (ds->retry_task);
614 0 : ds->retry_task = NULL;
615 : }
616 96 : json_decref (ds->wire_details);
617 96 : json_decref (ds->contract_terms);
618 96 : GNUNET_free (ds);
619 96 : }
620 :
621 :
622 : /**
623 : * Offer internal data from a "deposit" CMD, to other commands.
624 : *
625 : * @param cls closure.
626 : * @param[out] ret result.
627 : * @param trait name of the trait.
628 : * @param index index number of the object to offer.
629 : * @return #GNUNET_OK on success.
630 : */
631 : static enum GNUNET_GenericReturnValue
632 330 : deposit_traits (void *cls,
633 : const void **ret,
634 : const char *trait,
635 : unsigned int index)
636 : {
637 330 : struct DepositState *ds = cls;
638 : const struct TALER_TESTING_Command *coin_cmd;
639 : /* Will point to coin cmd internals. */
640 : const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv;
641 : struct TALER_CoinSpendPublicKeyP coin_spent_pub;
642 330 : const struct TALER_AgeCommitmentProof *age_commitment_proof=NULL;
643 330 : const struct TALER_AgeCommitmentHash *h_age_commitment=NULL;
644 :
645 330 : if (! ds->command_initialized)
646 : {
647 : /* No access to traits yet. */
648 0 : GNUNET_break (0);
649 0 : return GNUNET_NO;
650 : }
651 :
652 : coin_cmd
653 330 : = TALER_TESTING_interpreter_lookup_command (ds->is,
654 : ds->coin_reference);
655 330 : if (NULL == coin_cmd)
656 : {
657 0 : GNUNET_break (0);
658 0 : TALER_TESTING_interpreter_fail (ds->is);
659 0 : return GNUNET_NO;
660 : }
661 330 : if ( (GNUNET_OK !=
662 330 : TALER_TESTING_get_trait_coin_priv (coin_cmd,
663 : ds->coin_index,
664 330 : &coin_spent_priv)) ||
665 : (GNUNET_OK !=
666 330 : TALER_TESTING_get_trait_age_commitment_proof (coin_cmd,
667 : ds->coin_index,
668 330 : &age_commitment_proof)) ||
669 : (GNUNET_OK !=
670 330 : TALER_TESTING_get_trait_h_age_commitment (coin_cmd,
671 : ds->coin_index,
672 : &h_age_commitment)) )
673 : {
674 0 : GNUNET_break (0);
675 0 : TALER_TESTING_interpreter_fail (ds->is);
676 0 : return GNUNET_NO;
677 : }
678 :
679 330 : GNUNET_CRYPTO_eddsa_key_get_public (&coin_spent_priv->eddsa_priv,
680 : &coin_spent_pub.eddsa_pub);
681 :
682 : {
683 : struct TALER_TESTING_Trait traits[] = {
684 : /* First two traits are only available if
685 : ds->traits is true */
686 330 : TALER_TESTING_make_trait_exchange_pub (0,
687 330 : &ds->exchange_pub),
688 330 : TALER_TESTING_make_trait_exchange_sig (0,
689 330 : &ds->exchange_sig),
690 : /* These traits are always available */
691 330 : TALER_TESTING_make_trait_coin_history (0,
692 330 : &ds->che),
693 330 : TALER_TESTING_make_trait_coin_priv (0,
694 : coin_spent_priv),
695 330 : TALER_TESTING_make_trait_coin_pub (0,
696 : &coin_spent_pub),
697 330 : TALER_TESTING_make_trait_denom_pub (0,
698 : ds->denom_pub),
699 330 : TALER_TESTING_make_trait_coin_sig (0,
700 330 : &ds->coin_sig),
701 330 : TALER_TESTING_make_trait_age_commitment_proof (0,
702 : age_commitment_proof),
703 330 : TALER_TESTING_make_trait_h_age_commitment (0,
704 : h_age_commitment),
705 330 : TALER_TESTING_make_trait_wire_details (ds->wire_details),
706 330 : TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
707 330 : TALER_TESTING_make_trait_merchant_priv (&ds->account_priv.merchant_priv),
708 330 : TALER_TESTING_make_trait_merchant_pub (&ds->account_pub.merchant_pub),
709 330 : TALER_TESTING_make_trait_account_priv (&ds->account_priv),
710 330 : TALER_TESTING_make_trait_account_pub (&ds->account_pub),
711 330 : TALER_TESTING_make_trait_deposit_amount (0,
712 330 : &ds->amount),
713 330 : TALER_TESTING_make_trait_deposit_fee_amount (0,
714 330 : &ds->deposit_fee),
715 330 : TALER_TESTING_make_trait_timestamp (0,
716 330 : &ds->exchange_timestamp),
717 330 : TALER_TESTING_make_trait_wire_deadline (0,
718 330 : &ds->wire_deadline),
719 330 : TALER_TESTING_make_trait_refund_deadline (0,
720 330 : &ds->refund_deadline),
721 330 : TALER_TESTING_trait_end ()
722 : };
723 :
724 330 : return TALER_TESTING_get_trait ((ds->deposit_succeeded)
725 : ? traits
726 : : &traits[2],
727 : ret,
728 : trait,
729 : index);
730 : }
731 : }
732 :
733 :
734 : struct TALER_TESTING_Command
735 80 : TALER_TESTING_cmd_deposit (
736 : const char *label,
737 : const char *coin_reference,
738 : unsigned int coin_index,
739 : struct TALER_FullPayto target_account_payto,
740 : const char *contract_terms,
741 : struct GNUNET_TIME_Relative refund_deadline,
742 : const char *amount,
743 : unsigned int expected_response_code)
744 : {
745 : struct DepositState *ds;
746 :
747 80 : ds = GNUNET_new (struct DepositState);
748 80 : ds->coin_reference = coin_reference;
749 80 : ds->coin_index = coin_index;
750 80 : ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
751 80 : GNUNET_assert (NULL != ds->wire_details);
752 80 : ds->contract_terms = json_loads (contract_terms,
753 : JSON_REJECT_DUPLICATES,
754 : NULL);
755 80 : if (NULL == ds->contract_terms)
756 : {
757 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
758 : "Failed to parse contract terms `%s' for CMD `%s'\n",
759 : contract_terms,
760 : label);
761 0 : GNUNET_assert (0);
762 : }
763 80 : ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
764 80 : GNUNET_assert (0 ==
765 : json_object_set_new (ds->contract_terms,
766 : "timestamp",
767 : GNUNET_JSON_from_timestamp (
768 : ds->wallet_timestamp)));
769 80 : if (! GNUNET_TIME_relative_is_zero (refund_deadline))
770 : {
771 10 : ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
772 10 : GNUNET_assert (0 ==
773 : json_object_set_new (ds->contract_terms,
774 : "refund_deadline",
775 : GNUNET_JSON_from_timestamp (
776 : ds->refund_deadline)));
777 : }
778 80 : GNUNET_assert (GNUNET_OK ==
779 : TALER_string_to_amount (amount,
780 : &ds->amount));
781 80 : ds->expected_response_code = expected_response_code;
782 80 : ds->command_initialized = true;
783 : {
784 80 : struct TALER_TESTING_Command cmd = {
785 : .cls = ds,
786 : .label = label,
787 : .run = &deposit_run,
788 : .cleanup = &deposit_cleanup,
789 : .traits = &deposit_traits
790 : };
791 :
792 80 : return cmd;
793 : }
794 : }
795 :
796 :
797 : struct TALER_TESTING_Command
798 2 : TALER_TESTING_cmd_deposit_with_ref (
799 : const char *label,
800 : const char *coin_reference,
801 : unsigned int coin_index,
802 : struct TALER_FullPayto target_account_payto,
803 : const char *contract_terms,
804 : struct GNUNET_TIME_Relative refund_deadline,
805 : const char *amount,
806 : unsigned int expected_response_code,
807 : const char *merchant_priv_reference)
808 : {
809 : struct DepositState *ds;
810 :
811 2 : ds = GNUNET_new (struct DepositState);
812 2 : ds->merchant_priv_reference = merchant_priv_reference;
813 2 : ds->coin_reference = coin_reference;
814 2 : ds->coin_index = coin_index;
815 2 : ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
816 2 : GNUNET_assert (NULL != ds->wire_details);
817 2 : ds->contract_terms = json_loads (contract_terms,
818 : JSON_REJECT_DUPLICATES,
819 : NULL);
820 2 : if (NULL == ds->contract_terms)
821 : {
822 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
823 : "Failed to parse contract terms `%s' for CMD `%s'\n",
824 : contract_terms,
825 : label);
826 0 : GNUNET_assert (0);
827 : }
828 2 : ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
829 2 : GNUNET_assert (0 ==
830 : json_object_set_new (ds->contract_terms,
831 : "timestamp",
832 : GNUNET_JSON_from_timestamp (
833 : ds->wallet_timestamp)));
834 2 : if (0 != refund_deadline.rel_value_us)
835 : {
836 0 : ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
837 0 : GNUNET_assert (0 ==
838 : json_object_set_new (ds->contract_terms,
839 : "refund_deadline",
840 : GNUNET_JSON_from_timestamp (
841 : ds->refund_deadline)));
842 : }
843 2 : GNUNET_assert (GNUNET_OK ==
844 : TALER_string_to_amount (amount,
845 : &ds->amount));
846 2 : ds->expected_response_code = expected_response_code;
847 2 : ds->command_initialized = true;
848 : {
849 2 : struct TALER_TESTING_Command cmd = {
850 : .cls = ds,
851 : .label = label,
852 : .run = &deposit_run,
853 : .cleanup = &deposit_cleanup,
854 : .traits = &deposit_traits
855 : };
856 :
857 2 : return cmd;
858 : }
859 : }
860 :
861 :
862 : struct TALER_TESTING_Command
863 14 : TALER_TESTING_cmd_deposit_replay (
864 : const char *label,
865 : const char *deposit_reference,
866 : unsigned int expected_response_code)
867 : {
868 : struct DepositState *ds;
869 :
870 14 : ds = GNUNET_new (struct DepositState);
871 14 : ds->deposit_reference = deposit_reference;
872 14 : ds->expected_response_code = expected_response_code;
873 : {
874 14 : struct TALER_TESTING_Command cmd = {
875 : .cls = ds,
876 : .label = label,
877 : .run = &deposit_run,
878 : .cleanup = &deposit_cleanup,
879 : .traits = &deposit_traits
880 : };
881 :
882 14 : return cmd;
883 : }
884 : }
885 :
886 :
887 : struct TALER_TESTING_Command
888 0 : TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd)
889 : {
890 : struct DepositState *ds;
891 :
892 0 : GNUNET_assert (&deposit_run == cmd.run);
893 0 : ds = cmd.cls;
894 0 : ds->do_retry = NUM_RETRIES;
895 0 : return cmd;
896 : }
897 :
898 :
899 : /* end of testing_api_cmd_deposit.c */
|