diff options
Diffstat (limited to 'src/testing/testing_api_cmd_refresh.c')
-rw-r--r-- | src/testing/testing_api_cmd_refresh.c | 727 |
1 files changed, 398 insertions, 329 deletions
diff --git a/src/testing/testing_api_cmd_refresh.c b/src/testing/testing_api_cmd_refresh.c index fcf8540c0..111e9118f 100644 --- a/src/testing/testing_api_cmd_refresh.c +++ b/src/testing/testing_api_cmd_refresh.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA + Copyright (C) 2018-2022 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -70,10 +70,17 @@ struct TALER_TESTING_FreshCoinData */ struct TALER_CoinSpendPrivateKeyP coin_priv; + /* + * Fresh age commitment for the coin with proof and its hash, NULL if not + * applicable. + */ + struct TALER_AgeCommitmentProof *age_commitment_proof; + struct TALER_AgeCommitmentHash h_age_commitment; + /** * The blinding key (needed for recoup operations). */ - struct TALER_DenominationBlindingKeyP blinding_key; + union GNUNET_CRYPTO_BlindingSecretP blinding_key; }; @@ -91,9 +98,14 @@ struct RefreshMeltState const char *coin_reference; /** - * "Crypto data" used in the refresh operation. + * Data used in the refresh operation. + */ + struct TALER_EXCHANGE_RefreshData refresh_data; + + /** + * Our command. */ - char *refresh_data; + const struct TALER_TESTING_Command *cmd; /** * Reference to a previous melt command. @@ -106,6 +118,12 @@ struct RefreshMeltState struct TALER_EXCHANGE_MeltHandle *rmh; /** + * Expected entry in the coin history created by this + * operation. + */ + struct TALER_EXCHANGE_CoinHistoryEntry che; + + /** * Interpreter state. */ struct TALER_TESTING_Interpreter *is; @@ -117,11 +135,27 @@ struct RefreshMeltState struct TALER_EXCHANGE_DenomPublicKey *fresh_pks; /** + * Array of @e num_fresh_coins of results from + * the melt operation. + */ + struct TALER_EXCHANGE_MeltBlindingDetail *mbds; + + /** + * Entropy seed for the refresh-melt operation. + */ + struct TALER_RefreshMasterSecretP rms; + + /** * Private key of the dirty coin being melted. */ const struct TALER_CoinSpendPrivateKeyP *melt_priv; /** + * Public key of the dirty coin being melted. + */ + struct TALER_CoinSpendPublicKeyP melt_pub; + + /** * Task scheduled to try later. */ struct GNUNET_SCHEDULER_Task *retry_task; @@ -137,11 +171,6 @@ struct RefreshMeltState struct GNUNET_TIME_Relative total_backoff; /** - * Number of bytes in @e refresh_data. - */ - size_t refresh_data_length; - - /** * Amounts to be generated during melt. */ const char **melt_fresh_amounts; @@ -167,7 +196,7 @@ struct RefreshMeltState * exchange to pick any previous /rerfesh/melt operation from * the database. */ - unsigned int double_melt; + bool double_melt; /** * How often should we retry on (transient) failures? @@ -197,6 +226,11 @@ struct RefreshRevealState struct TALER_EXCHANGE_RefreshesRevealHandle *rrh; /** + * Our command. + */ + const struct TALER_TESTING_Command *cmd; + + /** * Convenience struct to keep in one place all the * data related to one fresh coin, set by the reveal callback * as it comes from the exchange. @@ -204,6 +238,12 @@ struct RefreshRevealState struct TALER_TESTING_FreshCoinData *fresh_coins; /** + * Array of @e num_fresh_coins planchet secrets derived + * from the transfer secret per fresh coin. + */ + struct TALER_PlanchetMasterSecretP *psa; + + /** * Interpreter state. */ struct TALER_TESTING_Interpreter *is; @@ -254,6 +294,11 @@ struct RefreshLinkState const char *reveal_reference; /** + * Our command. + */ + const struct TALER_TESTING_Command *cmd; + + /** * Handle to the ongoing operation. */ struct TALER_EXCHANGE_LinkHandle *rlh; @@ -315,8 +360,7 @@ do_reveal_retry (void *cls) struct RefreshRevealState *rrs = cls; rrs->retry_task = NULL; - rrs->is->commands[rrs->is->ip].last_req_time - = GNUNET_TIME_absolute_get (); + TALER_TESTING_touch_cmd (rrs->is); refresh_reveal_run (rrs, NULL, rrs->is); @@ -329,23 +373,14 @@ do_reveal_retry (void *cls) * coming from the exchange, namely the fresh coins. * * @param cls closure, a `struct RefreshRevealState` - * @param hr HTTP response details - * @param num_coins number of fresh coins created, length of the - * @a sigs and @a coin_privs arrays, 0 if the operation - * failed. - * @param coin_privs array of @a num_coins private keys for the - * coins that were created, NULL on error. - * @param sigs array of signature over @a num_coins coins, - * NULL on error. + * @param rr HTTP response details */ static void reveal_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - unsigned int num_coins, - const struct TALER_PlanchetSecretsP *coin_privs, - const struct TALER_DenominationSignature *sigs) + const struct TALER_EXCHANGE_RevealResult *rr) { struct RefreshRevealState *rrs = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &rr->hr; const struct TALER_TESTING_Command *melt_cmd; rrs->rrh = NULL; @@ -370,24 +405,16 @@ reveal_cb (void *cls, MAX_BACKOFF); rrs->total_backoff = GNUNET_TIME_relative_add (rrs->total_backoff, rrs->backoff); - rrs->is->commands[rrs->is->ip].num_tries++; + TALER_TESTING_inc_tries (rrs->is); rrs->retry_task = GNUNET_SCHEDULER_add_delayed (rrs->backoff, &do_reveal_retry, rrs); return; } } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - hr->http_status, - (int) hr->ec, - rrs->is->commands[rrs->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (rrs->is); + TALER_TESTING_unexpected_status (rrs->is, + hr->http_status, + rrs->expected_response_code); return; } melt_cmd = TALER_TESTING_interpreter_lookup_command (rrs->is, @@ -398,16 +425,22 @@ reveal_cb (void *cls, TALER_TESTING_interpreter_fail (rrs->is); return; } - rrs->num_fresh_coins = num_coins; switch (hr->http_status) { case MHD_HTTP_OK: - rrs->fresh_coins = GNUNET_new_array (num_coins, + rrs->num_fresh_coins = rr->details.ok.num_coins; + rrs->psa = GNUNET_new_array (rrs->num_fresh_coins, + struct TALER_PlanchetMasterSecretP); + rrs->fresh_coins = GNUNET_new_array (rrs->num_fresh_coins, struct TALER_TESTING_FreshCoinData); - for (unsigned int i = 0; i<num_coins; i++) + for (unsigned int i = 0; i<rrs->num_fresh_coins; i++) { + const struct TALER_EXCHANGE_RevealedCoinInfo *coin + = &rr->details.ok.coins[i]; struct TALER_TESTING_FreshCoinData *fc = &rrs->fresh_coins[i]; + rrs->psa[i] = coin->ps; + fc->blinding_key = coin->bks; if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub (melt_cmd, i, @@ -417,18 +450,25 @@ reveal_cb (void *cls, TALER_TESTING_interpreter_fail (rrs->is); return; } - fc->coin_priv = coin_privs[i].coin_priv; - fc->blinding_key = coin_privs[i].blinding_key; - fc->sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup - (sigs[i].rsa_signature); + fc->coin_priv = coin->coin_priv; + + if (NULL != coin->age_commitment_proof) + { + fc->age_commitment_proof = + TALER_age_commitment_proof_duplicate (coin->age_commitment_proof); + fc->h_age_commitment = coin->h_age_commitment; + } + + TALER_denom_sig_copy (&fc->sig, + &coin->sig); } if (0 != rrs->total_backoff.rel_value_us) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Total reveal backoff for %s was %s\n", - rrs->is->commands[rrs->is->ip].label, + rrs->cmd->label, GNUNET_STRINGS_relative_time_to_string (rrs->total_backoff, - GNUNET_YES)); + true)); } break; default: @@ -449,6 +489,19 @@ reveal_cb (void *cls, * @param is the interpreter state. */ static void +melt_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is); + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void refresh_reveal_run (void *cls, const struct TALER_TESTING_Command *cmd, struct TALER_TESTING_Interpreter *is) @@ -457,6 +510,7 @@ refresh_reveal_run (void *cls, struct RefreshMeltState *rms; const struct TALER_TESTING_Command *melt_cmd; + rrs->cmd = cmd; rrs->is = is; melt_cmd = TALER_TESTING_interpreter_lookup_command (is, rrs->melt_reference); @@ -466,14 +520,24 @@ refresh_reveal_run (void *cls, TALER_TESTING_interpreter_fail (rrs->is); return; } + GNUNET_assert (melt_cmd->run == &melt_run); rms = melt_cmd->cls; - rrs->rrh = TALER_EXCHANGE_refreshes_reveal (is->exchange, - rms->refresh_data_length, - rms->refresh_data, - rms->noreveal_index, - &reveal_cb, - rrs); - + { + struct TALER_ExchangeWithdrawValues alg_values[rms->num_fresh_coins]; + + for (unsigned int i = 0; i<rms->num_fresh_coins; i++) + alg_values[i] = rms->mbds[i].alg_value; + rrs->rrh = TALER_EXCHANGE_refreshes_reveal ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + &rms->rms, + &rms->refresh_data, + rms->num_fresh_coins, + alg_values, + rms->noreveal_index, + &reveal_cb, + rrs); + } if (NULL == rrs->rrh) { GNUNET_break (0); @@ -496,12 +560,11 @@ refresh_reveal_cleanup (void *cls, { struct RefreshRevealState *rrs = cls; + (void) cmd; if (NULL != rrs->rrh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - rrs->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (rrs->is, + cmd->label); TALER_EXCHANGE_refreshes_reveal_cancel (rrs->rrh); rrs->rrh = NULL; } @@ -512,10 +575,14 @@ refresh_reveal_cleanup (void *cls, } for (unsigned int j = 0; j < rrs->num_fresh_coins; j++) - GNUNET_CRYPTO_rsa_signature_free (rrs->fresh_coins[j].sig.rsa_signature); + { + TALER_denom_sig_free (&rrs->fresh_coins[j].sig); + TALER_age_commitment_proof_free (rrs->fresh_coins[j].age_commitment_proof); + GNUNET_free (rrs->fresh_coins[j].age_commitment_proof); + } GNUNET_free (rrs->fresh_coins); - rrs->fresh_coins = NULL; + GNUNET_free (rrs->psa); rrs->num_fresh_coins = 0; GNUNET_free (rrs); } @@ -545,8 +612,7 @@ do_link_retry (void *cls) struct RefreshLinkState *rls = cls; rls->retry_task = NULL; - rls->is->commands[rls->is->ip].last_req_time - = GNUNET_TIME_absolute_get (); + TALER_TESTING_touch_cmd (rls->is); refresh_link_run (rls, NULL, rls->is); @@ -559,29 +625,15 @@ do_link_retry (void *cls) * withdrawn by the "refresh reveal" CMD. * * @param cls closure. - * @param hr HTTP response details - * @param num_coins number of fresh coins created, length of the - * @a sigs and @a coin_privs arrays, 0 if the operation - * failed. - * @param coin_privs array of @a num_coins private keys for the - * coins that were created, NULL on error. - * @param sigs array of signature over @a num_coins coins, NULL on - * error. - * @param pubs array of public keys for the @a sigs, - * NULL on error. + * @param lr HTTP response details */ static void link_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - unsigned int num_coins, - const struct TALER_CoinSpendPrivateKeyP *coin_privs, - const struct TALER_DenominationSignature *sigs, - const struct TALER_DenominationPublicKey *pubs) + const struct TALER_EXCHANGE_LinkResult *lr) { - struct RefreshLinkState *rls = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &lr->hr; const struct TALER_TESTING_Command *reveal_cmd; - struct TALER_TESTING_Command *link_cmd = &rls->is->commands[rls->is->ip]; unsigned int found; const unsigned int *num_fresh_coins; @@ -607,24 +659,16 @@ link_cb (void *cls, MAX_BACKOFF); rls->total_backoff = GNUNET_TIME_relative_add (rls->total_backoff, rls->backoff); - rls->is->commands[rls->is->ip].num_tries++; + TALER_TESTING_inc_tries (rls->is); rls->retry_task = GNUNET_SCHEDULER_add_delayed (rls->backoff, &do_link_retry, rls); return; } } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - hr->http_status, - (int) hr->ec, - link_cmd->label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (rls->is); + TALER_TESTING_unexpected_status (rls->is, + hr->http_status, + rls->expected_response_code); return; } reveal_cmd = TALER_TESTING_interpreter_lookup_command (rls->is, @@ -641,19 +685,18 @@ link_cb (void *cls, case MHD_HTTP_OK: /* check that number of coins returned matches */ if (GNUNET_OK != - TALER_TESTING_get_trait_uint (reveal_cmd, - 0, - &num_fresh_coins)) + TALER_TESTING_get_trait_array_length (reveal_cmd, + &num_fresh_coins)) { GNUNET_break (0); TALER_TESTING_interpreter_fail (rls->is); return; } - if (num_coins != *num_fresh_coins) + if (lr->details.ok.num_coins != *num_fresh_coins) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected number of fresh coins: %d vs %d in %s:%u\n", - num_coins, + lr->details.ok.num_coins, *num_fresh_coins, __FILE__, __LINE__); @@ -661,22 +704,21 @@ link_cb (void *cls, return; } /* check that the coins match */ - for (unsigned int i = 0; i<num_coins; i++) - for (unsigned int j = i + 1; j<num_coins; j++) + for (unsigned int i = 0; i<lr->details.ok.num_coins; i++) + for (unsigned int j = i + 1; j<lr->details.ok.num_coins; j++) if (0 == - GNUNET_memcmp (&coin_privs[i], - &coin_privs[j])) + GNUNET_memcmp (&lr->details.ok.coins[i].coin_priv, + &lr->details.ok.coins[j].coin_priv)) GNUNET_break (0); /* Note: coins might be legitimately permutated in here... */ found = 0; /* Will point to the pointer inside the cmd state. */ { - const struct TALER_TESTING_FreshCoinData *fc = NULL; + const struct TALER_TESTING_FreshCoinData **fc = NULL; if (GNUNET_OK != TALER_TESTING_get_trait_fresh_coins (reveal_cmd, - 0, &fc)) { GNUNET_break (0); @@ -684,29 +726,38 @@ link_cb (void *cls, return; } - for (unsigned int i = 0; i<num_coins; i++) - for (unsigned int j = 0; j<num_coins; j++) + for (unsigned int i = 0; i<lr->details.ok.num_coins; i++) + { + const struct TALER_EXCHANGE_LinkedCoinInfo *lci_i + = &lr->details.ok.coins[i]; + + for (unsigned int j = 0; j<lr->details.ok.num_coins; j++) { + const struct TALER_TESTING_FreshCoinData *fcj + = &(*fc)[j]; + if ( (0 == - GNUNET_memcmp (&coin_privs[i], - &fc[j].coin_priv)) && + GNUNET_memcmp (&fcj->coin_priv, + &lci_i->coin_priv)) && (0 == - GNUNET_CRYPTO_rsa_signature_cmp (fc[i].sig.rsa_signature, - sigs[j].rsa_signature)) && + TALER_denom_sig_cmp (&fcj->sig, + &lci_i->sig)) && (0 == - GNUNET_CRYPTO_rsa_public_key_cmp (fc[i].pk->key.rsa_public_key, - pubs[j].rsa_public_key)) ) + TALER_denom_pub_cmp (&fcj->pk->key, + &lci_i->pub)) ) { found++; break; } - } + } /* for j*/ + } /* for i */ } - if (found != num_coins) + if (found != lr->details.ok.num_coins) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Only %u/%u coins match expectations\n", - found, num_coins); + found, + lr->details.ok.num_coins); GNUNET_break (0); TALER_TESTING_interpreter_fail (rls->is); return; @@ -715,9 +766,9 @@ link_cb (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Total link backoff for %s was %s\n", - rls->is->commands[rls->is->ip].label, + rls->cmd->label, GNUNET_STRINGS_relative_time_to_string (rls->total_backoff, - GNUNET_YES)); + true)); } break; default: @@ -748,8 +799,16 @@ refresh_link_run (void *cls, const struct TALER_TESTING_Command *reveal_cmd; const struct TALER_TESTING_Command *melt_cmd; const struct TALER_TESTING_Command *coin_cmd; + const char *exchange_url; + rls->cmd = cmd; rls->is = is; + exchange_url = TALER_TESTING_get_exchange_url (is); + if (NULL == exchange_url) + { + GNUNET_break (0); + return; + } reveal_cmd = TALER_TESTING_interpreter_lookup_command (rls->is, rls->reveal_reference); if (NULL == reveal_cmd) @@ -769,21 +828,22 @@ refresh_link_run (void *cls, } /* find reserve_withdraw command */ + GNUNET_assert (melt_cmd->run == &melt_run); + rms = melt_cmd->cls; + coin_cmd = TALER_TESTING_interpreter_lookup_command (rls->is, + rms->coin_reference); + if (NULL == coin_cmd) { - rms = melt_cmd->cls; - coin_cmd = TALER_TESTING_interpreter_lookup_command (rls->is, - rms->coin_reference); - if (NULL == coin_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rls->is); - return; - } + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rls->is); + return; } const struct TALER_CoinSpendPrivateKeyP *coin_priv; - if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv - (coin_cmd, 0, &coin_priv)) + if (GNUNET_OK != + TALER_TESTING_get_trait_coin_priv (coin_cmd, + 0, + &coin_priv)) { GNUNET_break (0); TALER_TESTING_interpreter_fail (rls->is); @@ -791,10 +851,13 @@ refresh_link_run (void *cls, } /* finally, use private key from withdraw sign command */ - rls->rlh = TALER_EXCHANGE_link (is->exchange, - coin_priv, - &link_cb, - rls); + rls->rlh = TALER_EXCHANGE_link ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + coin_priv, + rms->refresh_data.melt_age_commitment_proof, + &link_cb, + rls); if (NULL == rls->rlh) { @@ -820,11 +883,8 @@ refresh_link_cleanup (void *cls, if (NULL != rls->rlh) { - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - rls->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (rls->is, + cmd->label); TALER_EXCHANGE_link_cancel (rls->rlh); rls->rlh = NULL; } @@ -838,19 +898,6 @@ refresh_link_cleanup (void *cls, /** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -melt_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is); - - -/** * Task scheduled to re-try #melt_run. * * @param cls a `struct RefreshMeltState` @@ -861,8 +908,7 @@ do_melt_retry (void *cls) struct RefreshMeltState *rms = cls; rms->retry_task = NULL; - rms->is->commands[rms->is->ip].last_req_time - = GNUNET_TIME_absolute_get (); + TALER_TESTING_touch_cmd (rms->is); melt_run (rms, NULL, rms->is); @@ -875,18 +921,14 @@ do_melt_retry (void *cls) * CMD was set to do so. * * @param cls closure. - * @param hr HTTP response details - * @param noreveal_index choice by the exchange in the - * cut-and-choose protocol, UINT16_MAX on error. - * @param exchange_pub public key the exchange used for signing. + * @param mr melt response details */ static void melt_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - uint32_t noreveal_index, - const struct TALER_ExchangePublicKeyP *exchange_pub) + const struct TALER_EXCHANGE_MeltResponse *mr) { struct RefreshMeltState *rms = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &mr->hr; rms->rmh = NULL; if (rms->expected_response_code != hr->http_status) @@ -910,45 +952,57 @@ melt_cb (void *cls, MAX_BACKOFF); rms->total_backoff = GNUNET_TIME_relative_add (rms->total_backoff, rms->backoff); - rms->is->commands[rms->is->ip].num_tries++; + TALER_TESTING_inc_tries (rms->is); rms->retry_task = GNUNET_SCHEDULER_add_delayed (rms->backoff, &do_melt_retry, rms); return; } } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - hr->http_status, - (int) hr->ec, - rms->is->commands[rms->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (rms->is); + TALER_TESTING_unexpected_status_with_body (rms->is, + hr->http_status, + rms->expected_response_code, + hr->reply); return; } - rms->noreveal_index = noreveal_index; + if (MHD_HTTP_OK == hr->http_status) + { + rms->noreveal_index = mr->details.ok.noreveal_index; + if (mr->details.ok.num_mbds != rms->num_fresh_coins) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rms->is); + return; + } + GNUNET_free (rms->mbds); + rms->mbds = GNUNET_new_array ( + mr->details.ok.num_mbds, + struct TALER_EXCHANGE_MeltBlindingDetail); + for (unsigned int i = 0; i<mr->details.ok.num_mbds; i++) + TALER_denom_ewv_copy (&rms->mbds[i].alg_value, + &mr->details.ok.mbds[i].alg_value); + } if (0 != rms->total_backoff.rel_value_us) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Total melt backoff for %s was %s\n", - rms->is->commands[rms->is->ip].label, + rms->cmd->label, GNUNET_STRINGS_relative_time_to_string (rms->total_backoff, - GNUNET_YES)); + true)); } - if (GNUNET_YES == rms->double_melt) + if (rms->double_melt) { TALER_LOG_DEBUG ("Doubling the melt (%s)\n", - rms->is->commands[rms->is->ip].label); - rms->rmh = TALER_EXCHANGE_melt (rms->is->exchange, - rms->refresh_data_length, - rms->refresh_data, - &melt_cb, - rms); - rms->double_melt = GNUNET_NO; + rms->cmd->label); + rms->rmh = TALER_EXCHANGE_melt ( + TALER_TESTING_interpreter_get_context (rms->is), + TALER_TESTING_get_exchange_url (rms->is), + TALER_TESTING_get_keys (rms->is), + &rms->rms, + &rms->refresh_data, + &melt_cb, + rms); + rms->double_melt = false; return; } TALER_TESTING_interpreter_next (rms->is); @@ -975,36 +1029,53 @@ melt_run (void *cls, }; const char **melt_fresh_amounts; + rms->cmd = cmd; if (NULL == (melt_fresh_amounts = rms->melt_fresh_amounts)) melt_fresh_amounts = default_melt_fresh_amounts; rms->is = is; rms->noreveal_index = UINT16_MAX; + TALER_refresh_master_setup_random (&rms->rms); for (num_fresh_coins = 0; NULL != melt_fresh_amounts[num_fresh_coins]; num_fresh_coins++) ; rms->num_fresh_coins = num_fresh_coins; - rms->fresh_pks = GNUNET_new_array - (num_fresh_coins, - struct TALER_EXCHANGE_DenomPublicKey); + rms->fresh_pks = GNUNET_new_array ( + num_fresh_coins, + struct TALER_EXCHANGE_DenomPublicKey); { struct TALER_Amount melt_amount; struct TALER_Amount fresh_amount; + const struct TALER_AgeCommitmentProof *age_commitment_proof = NULL; + const struct TALER_AgeCommitmentHash *h_age_commitment = NULL; const struct TALER_DenominationSignature *melt_sig; const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub; const struct TALER_TESTING_Command *coin_command; + bool age_restricted_denom; if (NULL == (coin_command - = TALER_TESTING_interpreter_lookup_command - (is, rms->coin_reference))) + = TALER_TESTING_interpreter_lookup_command ( + is, + rms->coin_reference))) { GNUNET_break (0); TALER_TESTING_interpreter_fail (rms->is); return; } - if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv - (coin_command, 0, &rms->melt_priv)) + if (GNUNET_OK != + TALER_TESTING_get_trait_coin_priv (coin_command, + 0, + &rms->melt_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rms->is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_age_commitment_proof (coin_command, + 0, + &age_commitment_proof)) { GNUNET_break (0); TALER_TESTING_interpreter_fail (rms->is); @@ -1012,6 +1083,15 @@ melt_run (void *cls, } if (GNUNET_OK != + TALER_TESTING_get_trait_h_age_commitment (coin_command, + 0, + &h_age_commitment)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rms->is); + return; + } + if (GNUNET_OK != TALER_TESTING_get_trait_denom_sig (coin_command, 0, &melt_sig)) @@ -1020,32 +1100,42 @@ melt_run (void *cls, TALER_TESTING_interpreter_fail (rms->is); return; } - if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub - (coin_command, 0, &melt_denom_pub)) + if (GNUNET_OK != + TALER_TESTING_get_trait_denom_pub (coin_command, + 0, + &melt_denom_pub)) { GNUNET_break (0); 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; + melt_amount = melt_denom_pub->fees.refresh; + age_restricted_denom = melt_denom_pub->key.age_mask.bits != 0; + GNUNET_assert (age_restricted_denom == (NULL != age_commitment_proof)); + GNUNET_assert ((NULL == age_commitment_proof) || + (0 < age_commitment_proof->commitment.num)); for (unsigned int i = 0; i<num_fresh_coins; i++) { const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk; - if (GNUNET_OK != TALER_string_to_amount - (melt_fresh_amounts[i], &fresh_amount)) + if (GNUNET_OK != + TALER_string_to_amount (melt_fresh_amounts[i], + &fresh_amount)) { GNUNET_break (0); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to parse amount `%s' at index %u\n", - melt_fresh_amounts[i], i); + melt_fresh_amounts[i], + i); TALER_TESTING_interpreter_fail (rms->is); return; } - fresh_pk = TALER_TESTING_find_pk - (TALER_EXCHANGE_get_keys (is->exchange), &fresh_amount); + fresh_pk = TALER_TESTING_find_pk (TALER_TESTING_get_keys (rms->is), + &fresh_amount, + age_restricted_denom); if (NULL == fresh_pk) { GNUNET_break (0); @@ -1060,32 +1150,49 @@ melt_run (void *cls, GNUNET_assert (0 <= TALER_amount_add (&melt_amount, &melt_amount, - &fresh_pk->fee_withdraw)); + &fresh_pk->fees.withdraw)); rms->fresh_pks[i] = *fresh_pk; /* Make a deep copy of the RSA key */ - rms->fresh_pks[i].key.rsa_public_key - = GNUNET_CRYPTO_rsa_public_key_dup (fresh_pk->key.rsa_public_key); - } - rms->refresh_data - = TALER_EXCHANGE_refresh_prepare (rms->melt_priv, - &melt_amount, - melt_sig, - melt_denom_pub, - num_fresh_coins, - rms->fresh_pks, - &rms->refresh_data_length); - - if (NULL == rms->refresh_data) + TALER_denom_pub_copy (&rms->fresh_pks[i].key, + &fresh_pk->key); + } /* end for */ + + rms->refresh_data.melt_priv = *rms->melt_priv; + GNUNET_CRYPTO_eddsa_key_get_public (&rms->melt_priv->eddsa_priv, + &rms->melt_pub.eddsa_pub); + rms->refresh_data.melt_amount = melt_amount; + rms->refresh_data.melt_sig = *melt_sig; + rms->refresh_data.melt_pk = *melt_denom_pub; + + if (NULL != age_commitment_proof) { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rms->is); - return; + GNUNET_assert (NULL != h_age_commitment); + rms->refresh_data.melt_age_commitment_proof = age_commitment_proof; + rms->refresh_data.melt_h_age_commitment = h_age_commitment; } - rms->rmh = TALER_EXCHANGE_melt (is->exchange, - rms->refresh_data_length, - rms->refresh_data, - &melt_cb, - rms); + rms->refresh_data.fresh_pks = rms->fresh_pks; + rms->refresh_data.fresh_pks_len = num_fresh_coins; + + GNUNET_assert (age_restricted_denom == + (NULL != age_commitment_proof)); + GNUNET_assert ((NULL == age_commitment_proof) || + (0 < age_commitment_proof->commitment.num)); + + rms->che.type = TALER_EXCHANGE_CTT_MELT; + rms->che.amount = melt_amount; + if (NULL != age_commitment_proof) + rms->che.details.melt.h_age_commitment = *h_age_commitment; + else + rms->che.details.melt.no_hac = true; + + rms->rmh = TALER_EXCHANGE_melt ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), + &rms->rms, + &rms->refresh_data, + &melt_cb, + rms); if (NULL == rms->rmh) { @@ -1110,11 +1217,11 @@ melt_cleanup (void *cls, { struct RefreshMeltState *rms = cls; + (void) cmd; if (NULL != rms->rmh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - rms->is->ip, rms->is->commands[rms->is->ip].label); + TALER_TESTING_command_incomplete (rms->is, + cmd->label); TALER_EXCHANGE_melt_cancel (rms->rmh); rms->rmh = NULL; } @@ -1126,13 +1233,15 @@ melt_cleanup (void *cls, if (NULL != rms->fresh_pks) { for (unsigned int i = 0; i < rms->num_fresh_coins; i++) - GNUNET_CRYPTO_rsa_public_key_free (rms->fresh_pks[i].key.rsa_public_key); + TALER_denom_pub_free (&rms->fresh_pks[i].key); + GNUNET_free (rms->fresh_pks); + } + if (NULL != rms->mbds) + { + for (unsigned int i = 0; i < rms->num_fresh_coins; i++) + TALER_denom_ewv_free (&rms->mbds[i].alg_value); + GNUNET_free (rms->mbds); } - GNUNET_free (rms->fresh_pks); - rms->fresh_pks = NULL; - GNUNET_free (rms->refresh_data); - rms->refresh_data = NULL; - rms->refresh_data_length = 0; GNUNET_free (rms->melt_fresh_amounts); GNUNET_free (rms); } @@ -1147,7 +1256,7 @@ melt_cleanup (void *cls, * @param index index number of the object to offer. * @return #GNUNET_OK on success. */ -static int +static enum GNUNET_GenericReturnValue melt_traits (void *cls, const void **ret, const char *trait, @@ -1162,8 +1271,25 @@ melt_traits (void *cls, } { struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_denom_pub (index, &rms->fresh_pks[index]), - TALER_TESTING_make_trait_coin_priv (0, rms->melt_priv), + TALER_TESTING_make_trait_denom_pub (index, + &rms->fresh_pks[index]), + TALER_TESTING_make_trait_coin_priv (0, + rms->melt_priv), + TALER_TESTING_make_trait_coin_pub (0, + &rms->melt_pub), + TALER_TESTING_make_trait_coin_history (0, + &rms->che), + TALER_TESTING_make_trait_age_commitment_proof ( + index, + rms->refresh_data.melt_age_commitment_proof), + TALER_TESTING_make_trait_h_age_commitment ( + index, + rms->refresh_data.melt_h_age_commitment), + TALER_TESTING_make_trait_refresh_secret (&rms->rms), + (NULL != rms->mbds) + ? TALER_TESTING_make_trait_exchange_wd_value (index, + &rms->mbds[index].alg_value) + : TALER_TESTING_trait_end (), TALER_TESTING_trait_end () }; @@ -1182,7 +1308,7 @@ melt_traits (void *cls, * @param ap NULL-termianted list of amounts to be melted (one per fresh coin) * @return #GNUNET_OK on success */ -static int +static enum GNUNET_GenericReturnValue parse_amounts (struct RefreshMeltState *rms, va_list ap) { @@ -1225,16 +1351,6 @@ parse_amounts (struct RefreshMeltState *rms, } -/** - * Create a "refresh melt" command. - * - * @param label command label. - * @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_melt (const char *label, const char *coin_reference, @@ -1247,7 +1363,8 @@ TALER_TESTING_cmd_melt (const char *label, rms = GNUNET_new (struct RefreshMeltState); rms->coin_reference = coin_reference; rms->expected_response_code = expected_response_code; - va_start (ap, expected_response_code); + va_start (ap, + expected_response_code); GNUNET_assert (GNUNET_OK == parse_amounts (rms, ap)); va_end (ap); @@ -1265,18 +1382,6 @@ TALER_TESTING_cmd_melt (const char *label, } -/** - * Create a "refresh melt" CMD that does TWO /refresh/melt - * requests. This was needed to test the replay of a valid melt - * request, see #5312. - * - * @param label command label - * @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_melt_double (const char *label, const char *coin_reference, @@ -1289,8 +1394,9 @@ TALER_TESTING_cmd_melt_double (const char *label, rms = GNUNET_new (struct RefreshMeltState); rms->coin_reference = coin_reference; rms->expected_response_code = expected_response_code; - rms->double_melt = GNUNET_YES; - va_start (ap, expected_response_code); + rms->double_melt = true; + va_start (ap, + expected_response_code); GNUNET_assert (GNUNET_OK == parse_amounts (rms, ap)); va_end (ap); @@ -1308,12 +1414,6 @@ TALER_TESTING_cmd_melt_double (const char *label, } -/** - * Modify a "refresh melt" command to enable retries. - * - * @param cmd command - * @return modified command. - */ struct TALER_TESTING_Command TALER_TESTING_cmd_melt_with_retry (struct TALER_TESTING_Command cmd) { @@ -1335,65 +1435,54 @@ TALER_TESTING_cmd_melt_with_retry (struct TALER_TESTING_Command cmd) * @param index index number of the object to offer. * @return #GNUNET_OK on success. */ -static int +static enum GNUNET_GenericReturnValue refresh_reveal_traits (void *cls, const void **ret, const char *trait, unsigned int index) { struct RefreshRevealState *rrs = cls; - unsigned int num_coins = rrs->num_fresh_coins; -#define NUM_TRAITS ((num_coins * 4) + 3) - struct TALER_TESTING_Trait traits[NUM_TRAITS]; - - /* Making coin privs traits */ - for (unsigned int i = 0; i<num_coins; i++) - traits[i] = TALER_TESTING_make_trait_coin_priv - (i, &rrs->fresh_coins[i].coin_priv); - - /* Making denom pubs traits */ - for (unsigned int i = 0; i<num_coins; i++) - traits[num_coins + i] - = TALER_TESTING_make_trait_denom_pub - (i, rrs->fresh_coins[i].pk); - - /* Making denom sigs traits */ - for (unsigned int i = 0; i<num_coins; i++) - traits[(num_coins * 2) + i] - = TALER_TESTING_make_trait_denom_sig - (i, &rrs->fresh_coins[i].sig); - /* blinding key traits */ - for (unsigned int i = 0; i<num_coins; i++) - traits[(num_coins * 3) + i] - = TALER_TESTING_make_trait_blinding_key (i, - &rrs->fresh_coins[i].blinding_key), - - /* number of fresh coins */ - traits[(num_coins * 4)] = TALER_TESTING_make_trait_uint - (0, &rrs->num_fresh_coins); - - /* whole array of fresh coins */ - traits[(num_coins * 4) + 1] - = TALER_TESTING_make_trait_fresh_coins (0, rrs->fresh_coins), - - /* end of traits */ - traits[(num_coins * 4) + 2] = TALER_TESTING_trait_end (); - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); + + if (index >= rrs->num_fresh_coins) + return GNUNET_SYSERR; + + { + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_coin_priv ( + index, + &rrs->fresh_coins[index].coin_priv), + TALER_TESTING_make_trait_age_commitment_proof ( + index, + rrs->fresh_coins[index].age_commitment_proof), + TALER_TESTING_make_trait_h_age_commitment ( + index, + &rrs->fresh_coins[index].h_age_commitment), + TALER_TESTING_make_trait_denom_pub ( + index, + rrs->fresh_coins[index].pk), + TALER_TESTING_make_trait_denom_sig ( + index, + &rrs->fresh_coins[index].sig), + TALER_TESTING_make_trait_blinding_key ( + index, + &rrs->fresh_coins[index].blinding_key), + TALER_TESTING_make_trait_array_length ( + &rrs->num_fresh_coins), + TALER_TESTING_make_trait_fresh_coins ( + (const struct TALER_TESTING_FreshCoinData **) &rrs->fresh_coins), + TALER_TESTING_make_trait_planchet_secrets (index, + &rrs->psa[index]), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); + } } -/** - * Create a "refresh reveal" command. - * - * @param label command label. - * @param melt_reference reference to a "refresh melt" command. - * @param expected_response_code expected HTTP response code. - * @return the command. - */ struct TALER_TESTING_Command TALER_TESTING_cmd_refresh_reveal (const char *label, const char *melt_reference, @@ -1418,12 +1507,6 @@ TALER_TESTING_cmd_refresh_reveal (const char *label, } -/** - * Modify a "refresh reveal" command to enable retries. - * - * @param cmd command - * @return modified command. - */ struct TALER_TESTING_Command TALER_TESTING_cmd_refresh_reveal_with_retry (struct TALER_TESTING_Command cmd) { @@ -1436,14 +1519,6 @@ TALER_TESTING_cmd_refresh_reveal_with_retry (struct TALER_TESTING_Command cmd) } -/** - * Create a "refresh link" command. - * - * @param label command label. - * @param reveal_reference reference to a "refresh reveal" CMD. - * @param expected_response_code expected HTTP response code - * @return the "refresh link" command - */ struct TALER_TESTING_Command TALER_TESTING_cmd_refresh_link (const char *label, const char *reveal_reference, @@ -1467,12 +1542,6 @@ TALER_TESTING_cmd_refresh_link (const char *label, } -/** - * Modify a "refresh link" command to enable retries. - * - * @param cmd command - * @return modified command. - */ struct TALER_TESTING_Command TALER_TESTING_cmd_refresh_link_with_retry (struct TALER_TESTING_Command cmd) { |