From 9e3f4bdd791f87df25cfd2b818c7ef385b78b35d Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 24 Jul 2019 11:57:03 +0200 Subject: getting revocation/payback test with refreshed coins to pass --- src/exchange/taler-exchange-httpd_payback.c | 1 + src/exchange/taler-exchange-httpd_refresh_reveal.c | 10 +- .../taler-exchange-httpd_reserve_withdraw.c | 6 +- src/exchangedb/plugin_exchangedb_postgres.c | 14 +- src/include/taler_exchange_service.h | 1 + src/include/taler_testing_lib.h | 15 +- src/lib/Makefile.am | 4 +- src/lib/exchange_api_refresh.c | 32 +++-- src/lib/test_auditor_api.c | 4 +- src/lib/test_exchange_api.c | 12 +- src/lib/test_exchange_api_revocation.c | 46 +++--- src/lib/test_exchange_api_twisted.c | 4 +- src/lib/testing_api_cmd_refresh.c | 157 +++++++++++++-------- 13 files changed, 186 insertions(+), 120 deletions(-) (limited to 'src') diff --git a/src/exchange/taler-exchange-httpd_payback.c b/src/exchange/taler-exchange-httpd_payback.c index 8cfc1aecc..50c0ffdbc 100644 --- a/src/exchange/taler-exchange-httpd_payback.c +++ b/src/exchange/taler-exchange-httpd_payback.c @@ -305,6 +305,7 @@ payback_transaction (void *cls, } return qs; } + GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (pc->value.currency, &spent)); diff --git a/src/exchange/taler-exchange-httpd_refresh_reveal.c b/src/exchange/taler-exchange-httpd_refresh_reveal.c index d34c85a92..47287b155 100644 --- a/src/exchange/taler-exchange-httpd_refresh_reveal.c +++ b/src/exchange/taler-exchange-httpd_refresh_reveal.c @@ -556,7 +556,7 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, GNUNET_break_op (0); return TEH_RESPONSE_reply_arg_invalid (connection, TALER_EC_REFRESH_REVEAL_NEW_DENOMS_ARRAY_SIZE_EXCESSIVE, - "new_denoms"); + "new_denoms_h"); } if (json_array_size (new_denoms_h_json) != @@ -640,7 +640,7 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, TEH_KS_release (key_state); return TEH_RESPONSE_reply_arg_invalid (connection, TALER_EC_REFRESH_REVEAL_FRESH_DENOMINATION_KEY_NOT_FOUND, - "new_denoms"); + "new_denoms_h"); } GNUNET_assert (NULL != dkis[i]->denom_priv.rsa_private_key); } @@ -674,7 +674,7 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, /* lookup old_coin_pub in database */ { enum GNUNET_DB_QueryStatus qs; - + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != (qs = TEH_plugin->get_melt (TEH_plugin->cls, NULL, @@ -725,7 +725,7 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, ldp.purpose.size = htonl (sizeof (ldp)); ldp.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_LINK); ldp.h_denom_pub = dki_h[i]; - ldp.old_coin_pub = refresh_melt.session.coin.coin_pub; + ldp.old_coin_pub = refresh_melt.session.coin.coin_pub; ldp.transfer_pub = rctx->gamma_tp; GNUNET_CRYPTO_hash (rcds[i].coin_ev, rcds[i].coin_ev_size, @@ -744,7 +744,7 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, } } } - + rctx->num_fresh_coins = num_fresh_coins; rctx->rcds = rcds; rctx->dkis = dkis; diff --git a/src/exchange/taler-exchange-httpd_reserve_withdraw.c b/src/exchange/taler-exchange-httpd_reserve_withdraw.c index 32d53980d..65bca25e5 100644 --- a/src/exchange/taler-exchange-httpd_reserve_withdraw.c +++ b/src/exchange/taler-exchange-httpd_reserve_withdraw.c @@ -286,7 +286,7 @@ withdraw_transaction (void *cls, return GNUNET_DB_STATUS_HARD_ERROR; } *mhd_ret = reply_reserve_withdraw_insufficient_funds (connection, - rh); + rh); TEH_plugin->free_reserve_history (TEH_plugin->cls, rh); return GNUNET_DB_STATUS_HARD_ERROR; @@ -319,8 +319,8 @@ withdraw_transaction (void *cls, wc->collectable.h_coin_envelope = wc->wsrd.h_coin_envelope; wc->collectable.reserve_sig = wc->signature; qs = TEH_plugin->insert_withdraw_info (TEH_plugin->cls, - session, - &wc->collectable); + session, + &wc->collectable); if (0 > qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index c95ed2616..72e77fa6b 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -2593,8 +2593,8 @@ postgres_insert_withdraw_info (void *cls, now = GNUNET_TIME_absolute_get (); (void) GNUNET_TIME_round_abs (&now); qs = GNUNET_PQ_eval_prepared_non_select (session->conn, - "insert_withdraw_info", - params); + "insert_withdraw_info", + params); if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); @@ -2627,6 +2627,9 @@ postgres_insert_withdraw_info (void *cls, TALER_B2S (&collectable->reserve_pub)); return GNUNET_DB_STATUS_SOFT_ERROR; } + /* FIXME: idle_reserve_expiration_time is not a good value here, + we should base this on the LEGAL expiration time of coins + as we need reserve data for payback! */ expiry = GNUNET_TIME_absolute_add (now, pg->idle_reserve_expiration_time); reserve.expiry = GNUNET_TIME_absolute_max (expiry, @@ -7721,11 +7724,12 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) return NULL; } } + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, - "exchangedb", - "IDLE_RESERVE_EXPIRATION_TIME", - &pg->idle_reserve_expiration_time)) + "exchangedb", + "IDLE_RESERVE_EXPIRATION_TIME", + &pg->idle_reserve_expiration_time)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "exchangedb", diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 7bcfee9e4..4ced8ad92 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -511,6 +511,7 @@ TALER_EXCHANGE_get_signing_key_details (const struct TALER_EXCHANGE_Keys *keys, const char * TALER_EXCHANGE_get_base_url (const struct TALER_EXCHANGE_Handle *exchange); + /** * Obtain the denomination key details from the exchange. * diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index c08cfdc5c..41cc8b501 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -131,6 +131,7 @@ TALER_TESTING_cert_cb const struct TALER_EXCHANGE_Keys *keys, enum TALER_EXCHANGE_VersionCompatibility compat); + /** * Wait for the exchange to have started. Waits for at * most 10s, after that returns 77 to indicate an error. @@ -1108,19 +1109,18 @@ TALER_TESTING_cmd_deposit_with_retry * Create a "refresh melt" command. * * @param label command label. - * @param amount amount to be melted. * @param coin_reference reference to a command * that will provide a coin to refresh. * @param expected_response_code expected HTTP code. - * + * @param ... NULL-terminated list of amounts to be melted * @return the command. */ struct TALER_TESTING_Command TALER_TESTING_cmd_refresh_melt (const char *label, - const char *amount, const char *coin_reference, - unsigned int expected_response_code); + unsigned int expected_response_code, + ...); /** @@ -1129,19 +1129,18 @@ TALER_TESTING_cmd_refresh_melt * request, see #5312. * * @param label command label - * @param amount FIXME not used. * @param coin_reference reference to a command that will provide * a coin to refresh * @param expected_response_code expected HTTP code - * + * @param ... NULL-terminated list of amounts to be melted * @return the command. */ struct TALER_TESTING_Command TALER_TESTING_cmd_refresh_melt_double (const char *label, - const char *amount, const char *coin_reference, - unsigned int expected_response_code); + unsigned int expected_response_code, + ...); /** diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 71301e58d..fddc961f5 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -192,8 +192,8 @@ TESTS = \ $(check_PROGRAMS) # expected to fail for now: test incomplete, feature not implemented! -XFAIL_TESTS = \ - test_exchange_api_revocation +#XFAIL_TESTS = \ +# test_exchange_api_revocation test_exchange_api_SOURCES = \ test_exchange_api.c diff --git a/src/lib/exchange_api_refresh.c b/src/lib/exchange_api_refresh.c index c12fd32db..617eab393 100644 --- a/src/lib/exchange_api_refresh.c +++ b/src/lib/exchange_api_refresh.c @@ -1518,11 +1518,11 @@ handle_refresh_reveal_finished (void *cls, */ struct TALER_EXCHANGE_RefreshRevealHandle * TALER_EXCHANGE_refresh_reveal (struct TALER_EXCHANGE_Handle *exchange, - size_t refresh_data_length, - const char *refresh_data, - uint32_t noreveal_index, - TALER_EXCHANGE_RefreshRevealCallback reveal_cb, - void *reveal_cb_cls) + size_t refresh_data_length, + const char *refresh_data, + uint32_t noreveal_index, + TALER_EXCHANGE_RefreshRevealCallback reveal_cb, + void *reveal_cb_cls) { struct TALER_EXCHANGE_RefreshRevealHandle *rrh; json_t *transfer_privs; @@ -1535,15 +1535,6 @@ TALER_EXCHANGE_refresh_reveal (struct TALER_EXCHANGE_Handle *exchange, struct MeltData *md; struct TALER_TransferPublicKeyP transfer_pub; - GNUNET_assert (GNUNET_YES == - TEAH_handle_is_ready (exchange)); - md = deserialize_melt_data (refresh_data, - refresh_data_length); - if (NULL == md) - { - GNUNET_break (0); - return NULL; - } if (noreveal_index >= TALER_CNC_KAPPA) { /* We check this here, as it would be really bad to below just @@ -1553,6 +1544,19 @@ TALER_EXCHANGE_refresh_reveal (struct TALER_EXCHANGE_Handle *exchange, GNUNET_break (0); return NULL; } + if (GNUNET_YES != + TEAH_handle_is_ready (exchange)) + { + GNUNET_break (0); + return NULL; + } + md = deserialize_melt_data (refresh_data, + refresh_data_length); + if (NULL == md) + { + GNUNET_break (0); + return NULL; + } /* now transfer_pub */ GNUNET_CRYPTO_ecdhe_key_get_public (&md->melted_coin.transfer_priv[noreveal_index].ecdhe_priv, diff --git a/src/lib/test_auditor_api.c b/src/lib/test_auditor_api.c index 6595ea767..df69eac9e 100644 --- a/src/lib/test_auditor_api.c +++ b/src/lib/test_auditor_api.c @@ -231,9 +231,9 @@ run (void *cls, * Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x * EUR:0.13) */ TALER_TESTING_cmd_refresh_melt_double ("refresh-melt-1", - "EUR:4", "refresh-withdraw-coin-1", - MHD_HTTP_OK), + MHD_HTTP_OK, + NULL), /** * Complete (successful) melt operation, and withdraw the coins */ diff --git a/src/lib/test_exchange_api.c b/src/lib/test_exchange_api.c index dc868d1d3..33a2df9dd 100644 --- a/src/lib/test_exchange_api.c +++ b/src/lib/test_exchange_api.c @@ -309,8 +309,10 @@ run (void *cls, * Melt the rest of the coin's value * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */ TALER_TESTING_cmd_refresh_melt_double - ("refresh-melt-1", "EUR:4", - "refresh-withdraw-coin-1", MHD_HTTP_OK), + ("refresh-melt-1", + "refresh-withdraw-coin-1", + MHD_HTTP_OK, + NULL), /** * Complete (successful) melt operation, and * withdraw the coins @@ -360,8 +362,10 @@ run (void *cls, /* Test running a failing melt operation (same operation * again must fail) */ TALER_TESTING_cmd_refresh_melt - ("refresh-melt-failing", "EUR:4", - "refresh-withdraw-coin-1", MHD_HTTP_FORBIDDEN), + ("refresh-melt-failing", + "refresh-withdraw-coin-1", + MHD_HTTP_FORBIDDEN, + NULL), /* FIXME: also test with coin that was already melted * (signature differs from coin that was deposited...) */ diff --git a/src/lib/test_exchange_api_revocation.c b/src/lib/test_exchange_api_revocation.c index bd1d91c66..14bb4553f 100644 --- a/src/lib/test_exchange_api_revocation.c +++ b/src/lib/test_exchange_api_revocation.c @@ -142,11 +142,13 @@ run (void *cls, \"value\":\"EUR:1\"}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", MHD_HTTP_OK), /** - * Melt the rest of the coin's value - * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */ - TALER_TESTING_cmd_refresh_melt_double - ("refresh-melt-1", "EUR:4", - "withdraw-coin-1", MHD_HTTP_OK), + * Melt SOME of the rest of the coin's value + * (EUR:3.17 = 3x EUR:1.03 + 7x EUR:0.13) */ + TALER_TESTING_cmd_refresh_melt + ("refresh-melt-1", + "withdraw-coin-1", + MHD_HTTP_OK, + NULL), /** * Complete (successful) melt operation, and withdraw the coins */ @@ -174,45 +176,49 @@ run (void *cls, "refresh-reveal-1#2", "EUR:1", "refresh-melt-1"), - /* Melt original coin AGAIN (FIXME: this command - is simply WRONG as it neither matches - the EUR:3 that were paid back NOR is melt_double - precisely right here!) -- it always tries to MELT EUR:4, which is too much! */ - TALER_TESTING_cmd_refresh_melt_double - ("refresh-melt-2", "EUR:3", - "withdraw-coin-1", MHD_HTTP_OK), + /* Now we have EUR:3.83 EUR back after 3x EUR:1 in paybacks */ + /* Melt original coin AGAIN, but only create one 0.1 EUR coin; + This costs EUR:0.03 in refresh and EUR:01 in withdraw fees, + leaving EUR:3.69. */ + TALER_TESTING_cmd_refresh_melt + ("refresh-melt-2", + "withdraw-coin-1", + MHD_HTTP_OK, + "EUR:0.1", + NULL), /** * Complete (successful) melt operation, and withdraw the coins */ TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-2", "refresh-melt-2", MHD_HTTP_OK), - /* Make refreshed coin invalid */ + /* Revokes refreshed EUR:0.1 coin */ TALER_TESTING_cmd_revoke ("revoke-2", MHD_HTTP_OK, "refresh-reveal-2", CONFIG_FILE), - /* Make also original coin invalid */ + /* Revoke also original coin denomination */ TALER_TESTING_cmd_revoke ("revoke-3", MHD_HTTP_OK, "withdraw-coin-1", CONFIG_FILE), - /* Refund coin to original coin */ + /* Refund coin EUR:0.1 to original coin, creating zombie! */ TALER_TESTING_cmd_payback ("payback-2", MHD_HTTP_OK, - "refresh-melt-2", - "EUR:1", + "refresh-reveal-2", + "EUR:0.1", "refresh-melt-2"), - /* Refund original coin to reserve */ + /* Due to payback, original coin is now at EUR:3.79 */ + /* Refund original (now zombie) coin to reserve */ TALER_TESTING_cmd_payback ("payback-3", MHD_HTTP_OK, "withdraw-coin-1", - "EUR:1", + "EUR:3.79", NULL), /* Check the money is back with the reserve */ TALER_TESTING_cmd_status ("payback-reserve-status-1", "create-reserve-1", - "EUR:1.0", + "EUR:3.79", MHD_HTTP_OK), TALER_TESTING_cmd_end () }; diff --git a/src/lib/test_exchange_api_twisted.c b/src/lib/test_exchange_api_twisted.c index 7ba9cbaae..48a4ed36e 100644 --- a/src/lib/test_exchange_api_twisted.c +++ b/src/lib/test_exchange_api_twisted.c @@ -187,9 +187,9 @@ run (void *cls, * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */ TALER_TESTING_cmd_refresh_melt ("refresh-melt", - "EUR:4", "refresh-withdraw-coin", - MHD_HTTP_OK), + MHD_HTTP_OK, + NULL), /* Trigger 409 Conflict. */ TALER_TESTING_cmd_flip_upload diff --git a/src/lib/testing_api_cmd_refresh.c b/src/lib/testing_api_cmd_refresh.c index bc67af7f9..b2754edd8 100644 --- a/src/lib/testing_api_cmd_refresh.c +++ b/src/lib/testing_api_cmd_refresh.c @@ -37,16 +37,6 @@ struct MeltDetails { - /** - * Amount to melt (including fee). - */ - const char *amount; - - /** - * Reference to reserve_withdraw operations for coin to - * be used for the /refresh/melt operation. - */ - const char *coin_reference; }; @@ -57,9 +47,10 @@ struct RefreshMeltState { /** - * Information about coins to be melted. + * Reference to reserve_withdraw operations for coin to + * be used for the /refresh/melt operation. */ - struct MeltDetails melted_coin; + const char *coin_reference; /** * "Crypto data" used in the refresh operation. @@ -107,6 +98,11 @@ struct RefreshMeltState */ size_t refresh_data_length; + /** + * Amounts to be generated during melt. + */ + const char **melt_fresh_amounts; + /** * Number of fresh coins generated by the melt. */ @@ -314,12 +310,12 @@ reveal_cb (void *cls, "Retrying refresh reveal failed with %u/%d\n", http_status, (int) ec); - /* on DB conflicts, do not use backoff */ - if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) - rrs->backoff = GNUNET_TIME_UNIT_ZERO; - else - rrs->backoff = EXCHANGE_LIB_BACKOFF (rrs->backoff); - rrs->retry_task = GNUNET_SCHEDULER_add_delayed (rrs->backoff, + /* on DB conflicts, do not use backoff */ + if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) + rrs->backoff = GNUNET_TIME_UNIT_ZERO; + else + rrs->backoff = EXCHANGE_LIB_BACKOFF (rrs->backoff); + rrs->retry_task = GNUNET_SCHEDULER_add_delayed (rrs->backoff, &do_reveal_retry, rrs); return; @@ -691,12 +687,9 @@ refresh_link_run (void *cls, /* find reserve_withdraw command */ { - const struct MeltDetails *md; - rms = melt_cmd->cls; - md = &rms->melted_coin; coin_cmd = TALER_TESTING_interpreter_lookup_command - (rls->is, md->coin_reference); + (rls->is, rms->coin_reference); if (NULL == coin_cmd) { GNUNET_break (0); @@ -879,11 +872,14 @@ refresh_melt_run (void *cls, { struct RefreshMeltState *rms = cls; unsigned int num_fresh_coins; - /* FIXME: this should be dynamic */ - const char *melt_fresh_amounts[] = { + const char *default_melt_fresh_amounts[] = { "EUR:1", "EUR:1", "EUR:1", "EUR:0.1", - NULL}; + NULL + }; + const char **melt_fresh_amounts; + if (NULL == (melt_fresh_amounts = rms->melt_fresh_amounts)) + melt_fresh_amounts = default_melt_fresh_amounts; rms->is = is; rms->noreveal_index = UINT16_MAX; for (num_fresh_coins=0; @@ -899,11 +895,10 @@ refresh_melt_run (void *cls, const struct TALER_DenominationSignature *melt_sig; const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub; const struct TALER_TESTING_Command *coin_command; - const struct MeltDetails *md = &rms->melted_coin; if (NULL == (coin_command = TALER_TESTING_interpreter_lookup_command - (is, md->coin_reference))) + (is, rms->coin_reference))) { GNUNET_break (0); TALER_TESTING_interpreter_fail (rms->is); @@ -918,18 +913,6 @@ refresh_melt_run (void *cls, return; } - if (GNUNET_OK != - TALER_string_to_amount (md->amount, - &melt_amount)) - { - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", - md->amount, - is->ip); - TALER_TESTING_interpreter_fail (rms->is); - return; - } if (GNUNET_OK != TALER_TESTING_get_trait_denom_sig (coin_command, 0, @@ -946,6 +929,9 @@ refresh_melt_run (void *cls, TALER_TESTING_interpreter_fail (rms->is); return; } + /* Melt amount starts with the melt fee of the old coin; we'll add the + values and withdraw fees of the fresh coins next */ + melt_amount = melt_denom_pub->fee_refresh; for (unsigned int i=0;iis); return; } - + GNUNET_assert (GNUNET_OK == + TALER_amount_add (&melt_amount, + &melt_amount, + &fresh_amount)); + GNUNET_assert (GNUNET_OK == + TALER_amount_add (&melt_amount, + &melt_amount, + &fresh_pk->fee_withdraw)); rms->fresh_pks[i] = *fresh_pk; } rms->refresh_data = TALER_EXCHANGE_refresh_prepare @@ -1028,6 +1021,7 @@ refresh_melt_cleanup (void *cls, GNUNET_free_non_null (rms->refresh_data); rms->refresh_data = NULL; rms->refresh_data_length = 0; + GNUNET_free_non_null (rms->melt_fresh_amounts); GNUNET_free (rms); } @@ -1069,32 +1063,83 @@ refresh_melt_traits (void *cls, } +/** + * Parse list of amounts for melt operation. + * + * @param rms[in,out] where to store the list + * @param ap NULL-termianted list of amounts to be melted (one per fresh coin) + * @return #GNUNET_OK on success + */ +static int +parse_amounts (struct RefreshMeltState *rms, + va_list ap) +{ + unsigned int len; + unsigned int off; + const char *amount; + + len = 0; + off = 0; + while (NULL != (amount = va_arg (ap, const char *))) + { + if (len == off) + { + struct TALER_Amount a; + + GNUNET_array_grow (rms->melt_fresh_amounts, + len, + off + 16); + if (GNUNET_OK != + TALER_string_to_amount (amount, &a)) + { + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at index %u\n", + amount, off); + GNUNET_free (rms->melt_fresh_amounts); + rms->melt_fresh_amounts = NULL; + return GNUNET_SYSERR; + } + rms->melt_fresh_amounts[off++] = amount; + } + } + if (0 == off) + return GNUNET_OK; /* no amounts given == use defaults! */ + /* ensure NULL-termination */ + GNUNET_array_grow (rms->melt_fresh_amounts, + len, + off + 1); + return GNUNET_OK; +} + + /** * Create a "refresh melt" command. * * @param label command label. - * @param amount amount to be melted. * @param coin_reference reference to a command * that will provide a coin to refresh. * @param expected_response_code expected HTTP code. - * + * @param ... NULL-terminated list of amounts to be melted * @return the command. */ struct TALER_TESTING_Command TALER_TESTING_cmd_refresh_melt (const char *label, - const char *amount, const char *coin_reference, - unsigned int expected_response_code) + unsigned int expected_response_code, + ...) { struct RefreshMeltState *rms; - struct MeltDetails md; + va_list ap; - md.coin_reference = coin_reference; - md.amount = amount; rms = GNUNET_new (struct RefreshMeltState); - rms->melted_coin = md; + rms->coin_reference = coin_reference; rms->expected_response_code = expected_response_code; + va_start (ap, expected_response_code); + GNUNET_assert (GNUNET_OK == + parse_amounts (rms, ap)); + va_end (ap); { struct TALER_TESTING_Command cmd = { .label = label, @@ -1116,28 +1161,30 @@ TALER_TESTING_cmd_refresh_melt * * @param label command label * @param exchange connection to the exchange - * @param amount amount to be melted. * @param coin_reference reference to a command that will provide * a coin to refresh * @param expected_response_code expected HTTP code + * @param ... NULL-terminated list of amounts to be melted * @return the command. */ struct TALER_TESTING_Command TALER_TESTING_cmd_refresh_melt_double (const char *label, - const char *amount, const char *coin_reference, - unsigned int expected_response_code) + unsigned int expected_response_code, + ...) { struct RefreshMeltState *rms; - struct MeltDetails md; + va_list ap; - md.coin_reference = coin_reference; - md.amount = amount; rms = GNUNET_new (struct RefreshMeltState); - rms->melted_coin = md; + rms->coin_reference = coin_reference; rms->expected_response_code = expected_response_code; rms->double_melt = GNUNET_YES; + va_start (ap, expected_response_code); + GNUNET_assert (GNUNET_OK == + parse_amounts (rms, ap)); + va_end (ap); { struct TALER_TESTING_Command cmd = { .label = label, -- cgit v1.2.3