[age-withdraw] Added testing commands for age-withdraw and -reveal
Implemented - TALER_TESTING_cmd_age_withdraw - TALER_TESTING_cmd_age_withdraw_reveal Note: No test is using those commands yet.
This commit is contained in:
parent
c424cf99ab
commit
430bb0624a
@ -1513,6 +1513,11 @@ enum TALER_EXCHANGE_ReserveTransactionType
|
||||
*/
|
||||
TALER_EXCHANGE_RTT_WITHDRAWAL,
|
||||
|
||||
/**
|
||||
* Age-Withdrawal from the reserve.
|
||||
*/
|
||||
TALER_EXCHANGE_RTT_AGEWITHDRAWAL,
|
||||
|
||||
/**
|
||||
* /recoup operation.
|
||||
*/
|
||||
@ -1608,6 +1613,28 @@ struct TALER_EXCHANGE_ReserveHistoryEntry
|
||||
struct TALER_Amount fee;
|
||||
} withdraw;
|
||||
|
||||
/**
|
||||
* Information about withdraw operation.
|
||||
* @e type is #TALER_EXCHANGE_RTT_AGEWITHDRAWAL.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
/**
|
||||
* Signature authorizing the withdrawal for outgoing transaction.
|
||||
*/
|
||||
json_t *out_authorization_sig;
|
||||
|
||||
/**
|
||||
* Maximum age commited
|
||||
*/
|
||||
uint8_t max_age;
|
||||
|
||||
/**
|
||||
* Fee that was charged for the withdrawal.
|
||||
*/
|
||||
struct TALER_Amount fee;
|
||||
} age_withdraw;
|
||||
|
||||
/**
|
||||
* Information provided if the reserve was filled via /recoup.
|
||||
* @e type is #TALER_EXCHANGE_RTT_RECOUP.
|
||||
@ -2676,7 +2703,7 @@ struct TALER_EXCHANGE_AgeWithdrawCoinInput
|
||||
* The denomination of the coin. Must support age restriction, i.e
|
||||
* its .keys.age_mask MUST not be 0
|
||||
*/
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
|
||||
struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
|
||||
};
|
||||
|
||||
|
||||
@ -2691,6 +2718,11 @@ struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails
|
||||
*/
|
||||
struct TALER_CoinSpendPrivateKeyP coin_priv;
|
||||
|
||||
/**
|
||||
* Hash of the public key of the coin.
|
||||
*/
|
||||
struct TALER_CoinPubHashP h_coin_pub;
|
||||
|
||||
/**
|
||||
* Value used to blind the key for the signature.
|
||||
* Needed for recoup operations.
|
||||
@ -2713,6 +2745,11 @@ struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails
|
||||
* withdraw protocol.
|
||||
*/
|
||||
struct TALER_ExchangeWithdrawValues alg_values;
|
||||
|
||||
/**
|
||||
* The planchet constructed
|
||||
*/
|
||||
struct TALER_PlanchetDetail planchet;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2761,11 +2798,11 @@ struct TALER_EXCHANGE_AgeWithdrawResponse
|
||||
/**
|
||||
* The computed details of the non-revealed @e num_coins coins to keep.
|
||||
*/
|
||||
const struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails *coins;
|
||||
const struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails *coin_details;
|
||||
|
||||
/**
|
||||
* The array of blinded hashes of the non-revealed
|
||||
* (kappa - 1)*@e num_coins coins, needed for the reveal step;
|
||||
* @e num_coins coins, needed for the reveal step;
|
||||
*/
|
||||
const struct TALER_BlindedCoinHashP *blinded_coin_hs;
|
||||
|
||||
@ -2990,9 +3027,9 @@ struct TALER_EXCHANGE_AgeWithdrawRevealResponse
|
||||
struct
|
||||
{
|
||||
/**
|
||||
* Number of coins returned.
|
||||
* Number of signatures returned.
|
||||
*/
|
||||
unsigned int num_coins;
|
||||
unsigned int num_sigs;
|
||||
|
||||
/**
|
||||
* Array of @e num_coins blinded denomination signatures, giving each
|
||||
@ -3000,7 +3037,7 @@ struct TALER_EXCHANGE_AgeWithdrawRevealResponse
|
||||
* order (and should have the same length) in which the original
|
||||
* age-withdraw request specified the respective denomination keys.
|
||||
*/
|
||||
const struct TALER_BlindedDenominationSignature *denom_sigs;
|
||||
const struct TALER_BlindedDenominationSignature *blinded_denom_sigs;
|
||||
|
||||
} ok;
|
||||
} details;
|
||||
|
@ -2715,8 +2715,8 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits,
|
||||
op (refund_deadline, const struct GNUNET_TIME_Timestamp) \
|
||||
op (exchange_pub, const struct TALER_ExchangePublicKeyP) \
|
||||
op (exchange_sig, const struct TALER_ExchangeSignatureP) \
|
||||
op (blinding_key, const union TALER_DenominationBlindingKeyP)
|
||||
|
||||
op (blinding_key, const union TALER_DenominationBlindingKeyP) \
|
||||
op (h_blinded_coin, const struct TALER_BlindedCoinHashP)
|
||||
|
||||
TALER_TESTING_SIMPLE_TRAITS (TALER_TESTING_MAKE_DECL_SIMPLE_TRAIT)
|
||||
|
||||
|
@ -51,12 +51,6 @@ struct CoinCandidate
|
||||
*/
|
||||
struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails details;
|
||||
|
||||
/**
|
||||
* Hash of the public key of the coin we are signing.
|
||||
*/
|
||||
struct TALER_CoinPubHashP h_coin_pub;
|
||||
|
||||
|
||||
/**
|
||||
* Blinded hash of the coin
|
||||
**/
|
||||
@ -765,7 +759,7 @@ copy_results (
|
||||
{
|
||||
struct TALER_EXCHANGE_AgeWithdrawHandle *awh = cls;
|
||||
uint8_t idx = awbr->details.ok.noreveal_index;
|
||||
struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails coins[awh->num_coins];
|
||||
struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails details[awh->num_coins];
|
||||
struct TALER_BlindedCoinHashP blinded_coin_hs[awh->num_coins];
|
||||
struct TALER_EXCHANGE_AgeWithdrawResponse resp = {
|
||||
.hr = awbr->hr,
|
||||
@ -774,14 +768,15 @@ copy_results (
|
||||
.h_commitment = awbr->details.ok.h_commitment,
|
||||
.exchange_pub = awbr->details.ok.exchange_pub,
|
||||
.num_coins = awh->num_coins,
|
||||
.coins = coins,
|
||||
.coin_details = details,
|
||||
.blinded_coin_hs = blinded_coin_hs},
|
||||
},
|
||||
};
|
||||
|
||||
for (size_t n = 0; n< awh->num_coins; n++)
|
||||
{
|
||||
coins[n] = awh->coin_data[n].coin_candidates[idx].details;
|
||||
details[n] = awh->coin_data[n].coin_candidates[idx].details;
|
||||
details[n].planchet = awh->coin_data[n].planchet_details[idx];
|
||||
blinded_coin_hs[n] = awh->coin_data[n].coin_candidates[idx].blinded_coin_h;
|
||||
}
|
||||
|
||||
@ -915,7 +910,7 @@ csr_withdraw_done (
|
||||
&can->details.blinding_key,
|
||||
&can->details.coin_priv,
|
||||
&can->details.h_age_commitment,
|
||||
&can->h_coin_pub,
|
||||
&can->details.h_coin_pub,
|
||||
planchet))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
@ -1035,7 +1030,7 @@ prepare_coins (
|
||||
&can->details.blinding_key,
|
||||
&can->details.coin_priv,
|
||||
&can->details.h_age_commitment,
|
||||
&can->h_coin_pub,
|
||||
&can->details.h_coin_pub,
|
||||
planchet));
|
||||
FAIL_IF (GNUNET_OK !=
|
||||
TALER_coin_ev_hash (&planchet->blinded_planchet,
|
||||
|
@ -135,8 +135,8 @@ age_withdraw_reveal_ok (
|
||||
}
|
||||
}
|
||||
|
||||
response.details.ok.num_coins = awrh->num_coins;
|
||||
response.details.ok.denom_sigs = denom_sigs;
|
||||
response.details.ok.num_sigs = awrh->num_coins;
|
||||
response.details.ok.blinded_denom_sigs = denom_sigs;
|
||||
awrh->callback (awrh->callback_cls,
|
||||
&response);
|
||||
/* Make sure the callback isn't called again */
|
||||
|
@ -765,6 +765,8 @@ TALER_EXCHANGE_free_reserve_history (
|
||||
break;
|
||||
case TALER_EXCHANGE_RTT_WITHDRAWAL:
|
||||
break;
|
||||
case TALER_EXCHANGE_RTT_AGEWITHDRAWAL:
|
||||
break;
|
||||
case TALER_EXCHANGE_RTT_RECOUP:
|
||||
break;
|
||||
case TALER_EXCHANGE_RTT_CLOSING:
|
||||
|
@ -23,7 +23,9 @@
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include "taler_exchange_service.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include <gnunet/gnunet_common.h>
|
||||
#include <microhttpd.h>
|
||||
#include <gnunet/gnunet_curl_lib.h>
|
||||
#include "taler_signatures.h"
|
||||
@ -31,15 +33,26 @@
|
||||
#include "taler_testing_lib.h"
|
||||
|
||||
/*
|
||||
* The input and state of coin
|
||||
* The output state of coin
|
||||
*/
|
||||
struct CoinState
|
||||
struct CoinOutputState
|
||||
{
|
||||
struct TALER_RefreshMasterSecretP secret;
|
||||
|
||||
/**
|
||||
* The calculated details during "age-withdraw", for the selected coin.
|
||||
*/
|
||||
struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails details;
|
||||
|
||||
/**
|
||||
* The (wanted) value of the coin, MUST be the same as input.denom_pub.value;
|
||||
*/
|
||||
struct TALER_Amount amount;
|
||||
|
||||
/**
|
||||
* Reserve history entry that corresponds to this coin.
|
||||
* Will be of type #TALER_EXCHANGE_RTT_AGEWITHDRAWAL.
|
||||
*/
|
||||
struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -48,7 +61,38 @@ struct CoinState
|
||||
|
||||
struct AgeWithdrawState
|
||||
{
|
||||
/*
|
||||
|
||||
/**
|
||||
* Interpreter state (during command)
|
||||
*/
|
||||
struct TALER_TESTING_Interpreter *is;
|
||||
|
||||
/**
|
||||
* The age-withdraw handle
|
||||
*/
|
||||
struct TALER_EXCHANGE_AgeWithdrawHandle *handle;
|
||||
|
||||
/**
|
||||
* Exchange base URL. Only used as offered trait.
|
||||
*/
|
||||
char *exchange_url;
|
||||
|
||||
/**
|
||||
* URI of the reserve we are withdrawing from.
|
||||
*/
|
||||
char *reserve_payto_uri;
|
||||
|
||||
/**
|
||||
* Private key of the reserve we are withdrawing from.
|
||||
*/
|
||||
struct TALER_ReservePrivateKeyP reserve_priv;
|
||||
|
||||
/**
|
||||
* Public key of the reserve we are withdrawing from.
|
||||
*/
|
||||
struct TALER_ReservePublicKeyP reserve_pub;
|
||||
|
||||
/**
|
||||
* Which reserve should we withdraw from?
|
||||
*/
|
||||
const char *reserve_reference;
|
||||
@ -58,6 +102,11 @@ struct AgeWithdrawState
|
||||
*/
|
||||
unsigned int expected_response_code;
|
||||
|
||||
/**
|
||||
* Age mask
|
||||
*/
|
||||
struct TALER_AgeMask mask;
|
||||
|
||||
/**
|
||||
* The maximum age we commit to
|
||||
*/
|
||||
@ -69,12 +118,336 @@ struct AgeWithdrawState
|
||||
size_t num_coins;
|
||||
|
||||
/**
|
||||
* The input for the coins
|
||||
* The @e num_coins input that is provided to the
|
||||
* `TALER_EXCHANGE_age_withdraw` API.
|
||||
* Each contains kappa secrets, from which we will have
|
||||
* to disclose kappa-1 in a subsequent age-withdraw-reveal operation.
|
||||
*/
|
||||
struct CoinState *coins;
|
||||
struct TALER_EXCHANGE_AgeWithdrawCoinInput *coin_inputs;
|
||||
|
||||
/**
|
||||
* The output state of @e num_coins coins, calculated during the
|
||||
* "age-withdraw" operation.
|
||||
*/
|
||||
struct CoinOutputState *coin_outputs;
|
||||
|
||||
/**
|
||||
* The index returned by the exchange for the "age-withdraw" operation,
|
||||
* of the kappa coin candidates that we do not disclose and keep.
|
||||
*/
|
||||
uint8_t noreveal_index;
|
||||
|
||||
/**
|
||||
* The blinded hashes of the non-revealed (to keep) @e num_coins coins.
|
||||
*/
|
||||
const struct TALER_BlindedCoinHashP *blinded_coin_hs;
|
||||
|
||||
/**
|
||||
* The hash of the commitment, needed for the reveal step.
|
||||
*/
|
||||
struct TALER_AgeWithdrawCommitmentHashP h_commitment;
|
||||
|
||||
/**
|
||||
* Set to the KYC requirement payto hash *if* the exchange replied with a
|
||||
* request for KYC.
|
||||
*/
|
||||
struct TALER_PaytoHashP h_payto;
|
||||
|
||||
/**
|
||||
* Set to the KYC requirement row *if* the exchange replied with
|
||||
* a request for KYC.
|
||||
*/
|
||||
uint64_t requirement_row;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for the "age-withdraw" ooperation; It checks that the response
|
||||
* code is expected and store the exchange signature in the state.
|
||||
*
|
||||
* @param cls Closure of type `struct AgeWithdrawState *`
|
||||
* @param awr Repsonse details
|
||||
*/
|
||||
static void
|
||||
age_withdraw_cb (
|
||||
void *cls,
|
||||
const struct TALER_EXCHANGE_AgeWithdrawResponse *response)
|
||||
{
|
||||
struct AgeWithdrawState *aws = cls;
|
||||
struct TALER_TESTING_Interpreter *is = aws->is;
|
||||
|
||||
aws->handle = NULL;
|
||||
if (aws->expected_response_code != response->hr.http_status)
|
||||
{
|
||||
TALER_TESTING_unexpected_status_with_body (is,
|
||||
response->hr.http_status,
|
||||
aws->expected_response_code,
|
||||
response->hr.reply);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (response->hr.http_status)
|
||||
{
|
||||
case MHD_HTTP_OK:
|
||||
aws->noreveal_index = response->details.ok.noreveal_index;
|
||||
aws->h_commitment = response->details.ok.h_commitment;
|
||||
|
||||
GNUNET_assert (aws->num_coins == response->details.ok.num_coins);
|
||||
for (size_t n = 0; n < aws->num_coins; n++)
|
||||
{
|
||||
aws->coin_outputs[n].details = response->details.ok.coin_details[n];
|
||||
TALER_age_commitment_proof_deep_copy (
|
||||
&response->details.ok.coin_details[n].age_commitment_proof,
|
||||
&aws->coin_outputs[n].details.age_commitment_proof);
|
||||
}
|
||||
aws->blinded_coin_hs = response->details.ok.blinded_coin_hs;
|
||||
break;
|
||||
case MHD_HTTP_FORBIDDEN:
|
||||
case MHD_HTTP_NOT_FOUND:
|
||||
case MHD_HTTP_GONE:
|
||||
/* nothing to check */
|
||||
break;
|
||||
case MHD_HTTP_CONFLICT:
|
||||
/* TODO[oec]: Add this to the response-type and handle it here */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Age withdraw test command does not YET support status code %u\n",
|
||||
response->hr.http_status);
|
||||
break;
|
||||
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
|
||||
/* TODO[oec]: Add this to response-type and handle it here */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Age withdraw test command does not YET support status code %u\n",
|
||||
response->hr.http_status);
|
||||
break;
|
||||
default:
|
||||
/* Unsupported status code (by test harness) */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Age withdraw test command does not support status code %u\n",
|
||||
response->hr.http_status);
|
||||
GNUNET_break (0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* We are done with this command, pick the next one */
|
||||
TALER_TESTING_interpreter_next (is);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the command for age-withdraw.
|
||||
*/
|
||||
static void
|
||||
age_withdraw_run (
|
||||
void *cls,
|
||||
const struct TALER_TESTING_Command *cmd,
|
||||
struct TALER_TESTING_Interpreter *is)
|
||||
{
|
||||
struct AgeWithdrawState *aws = cls;
|
||||
struct TALER_EXCHANGE_Keys *keys = TALER_TESTING_get_keys (is);
|
||||
const struct TALER_ReservePrivateKeyP *rp;
|
||||
const struct TALER_TESTING_Command *create_reserve;
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *dpk;
|
||||
|
||||
aws->is = is;
|
||||
|
||||
/* Prepare the reserve related data */
|
||||
create_reserve
|
||||
= TALER_TESTING_interpreter_lookup_command (
|
||||
is,
|
||||
aws->reserve_reference);
|
||||
|
||||
if (NULL == create_reserve)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
TALER_TESTING_get_trait_reserve_priv (create_reserve,
|
||||
&rp))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
if (NULL == aws->exchange_url)
|
||||
aws->exchange_url
|
||||
= GNUNET_strdup (TALER_TESTING_get_exchange_url (is));
|
||||
aws->reserve_priv = *rp;
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&aws->reserve_priv.eddsa_priv,
|
||||
&aws->reserve_pub.eddsa_pub);
|
||||
aws->reserve_payto_uri
|
||||
= TALER_reserve_make_payto (aws->exchange_url,
|
||||
&aws->reserve_pub);
|
||||
|
||||
aws->coin_inputs = GNUNET_new_array (
|
||||
aws->num_coins,
|
||||
struct TALER_EXCHANGE_AgeWithdrawCoinInput);
|
||||
|
||||
for (unsigned int i = 0; i<aws->num_coins; i++)
|
||||
{
|
||||
struct TALER_EXCHANGE_AgeWithdrawCoinInput *input = &aws->coin_inputs[i];
|
||||
struct CoinOutputState *cos = &aws->coin_outputs[i];
|
||||
|
||||
/* randomly create the secrets for the kappa coin-candidates */
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
|
||||
&input->secrets,
|
||||
sizeof(input->secrets));
|
||||
/* Find denomination */
|
||||
dpk = TALER_TESTING_find_pk (keys,
|
||||
&cos->amount,
|
||||
true); /* _always_ use denominations with age-striction */
|
||||
if (NULL == dpk)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to determine denomination key at %s\n",
|
||||
(NULL != cmd) ? cmd->label : "<retried command>");
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
/* We copy the denomination key, as re-querying /keys
|
||||
* would free the old one. */
|
||||
input->denom_pub = TALER_EXCHANGE_copy_denomination_key (dpk);
|
||||
cos->reserve_history.type = TALER_EXCHANGE_RTT_AGEWITHDRAWAL;
|
||||
GNUNET_assert (0 <=
|
||||
TALER_amount_add (&cos->reserve_history.amount,
|
||||
&cos->amount,
|
||||
&input->denom_pub->fees.withdraw));
|
||||
cos->reserve_history.details.withdraw.fee = input->denom_pub->fees.withdraw;
|
||||
}
|
||||
|
||||
/* Execute the age-withdraw protocol */
|
||||
aws->handle =
|
||||
TALER_EXCHANGE_age_withdraw (
|
||||
TALER_TESTING_interpreter_get_context (is),
|
||||
keys,
|
||||
TALER_TESTING_get_exchange_url (is),
|
||||
rp,
|
||||
aws->num_coins,
|
||||
aws->coin_inputs,
|
||||
aws->max_age,
|
||||
&age_withdraw_cb,
|
||||
aws);
|
||||
|
||||
if (NULL == aws->handle)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free the state of a "age withdraw" CMD, and possibly cancel a
|
||||
* pending operation thereof
|
||||
*
|
||||
* @param cls Closure of type `struct AgeWithdrawState`
|
||||
* @param cmd The command beeing freed.
|
||||
*/
|
||||
static void
|
||||
age_withdraw_cleanup (
|
||||
void *cls,
|
||||
const struct TALER_TESTING_Command *cmd)
|
||||
{
|
||||
struct AgeWithdrawState *aws = cls;
|
||||
|
||||
if (NULL != aws->handle)
|
||||
{
|
||||
TALER_TESTING_command_incomplete (aws->is,
|
||||
cmd->label);
|
||||
TALER_EXCHANGE_age_withdraw_cancel (aws->handle);
|
||||
aws->handle = NULL;
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < aws->num_coins; n++)
|
||||
{
|
||||
struct TALER_EXCHANGE_AgeWithdrawCoinInput *in = &aws->coin_inputs[n];
|
||||
struct CoinOutputState *out = &aws->coin_outputs[n];
|
||||
|
||||
if (NULL != in->denom_pub)
|
||||
{
|
||||
TALER_EXCHANGE_destroy_denomination_key (in->denom_pub);
|
||||
in->denom_pub = NULL;
|
||||
}
|
||||
TALER_age_commitment_proof_free (&out->details.age_commitment_proof);
|
||||
}
|
||||
GNUNET_free (aws->coin_inputs);
|
||||
GNUNET_free (aws->coin_outputs);
|
||||
GNUNET_free (aws->exchange_url);
|
||||
GNUNET_free (aws->reserve_payto_uri);
|
||||
GNUNET_free (aws);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Offer internal data of a "age withdraw" CMD state to other commands.
|
||||
*
|
||||
* @param cls Closure of type `struct AgeWithdrawState`
|
||||
* @param[out] ret result (could be anything)
|
||||
* @param trait name of the trait
|
||||
* @param idx index number of the object to offer.
|
||||
* @return #GNUNET_OK on success
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
age_withdraw_traits (
|
||||
void *cls,
|
||||
const void **ret,
|
||||
const char *trait,
|
||||
unsigned int idx)
|
||||
{
|
||||
struct AgeWithdrawState *aws = cls;
|
||||
uint8_t k = aws->noreveal_index;
|
||||
struct TALER_EXCHANGE_AgeWithdrawCoinInput *in = &aws->coin_inputs[idx];
|
||||
struct CoinOutputState *out = &aws->coin_outputs[idx];
|
||||
struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails *details =
|
||||
&aws->coin_outputs[idx].details;
|
||||
struct TALER_TESTING_Trait traits[] = {
|
||||
/* history entry MUST be first due to response code logic below! */
|
||||
TALER_TESTING_make_trait_reserve_history (idx,
|
||||
&out->reserve_history),
|
||||
TALER_TESTING_make_trait_denom_pub (idx,
|
||||
in->denom_pub),
|
||||
TALER_TESTING_make_trait_reserve_priv (&aws->reserve_priv),
|
||||
TALER_TESTING_make_trait_reserve_pub (&aws->reserve_pub),
|
||||
TALER_TESTING_make_trait_amounts (idx,
|
||||
&out->amount),
|
||||
/* TODO[oec]: add legal requirement to response and handle it here, as well
|
||||
TALER_TESTING_make_trait_legi_requirement_row (&aws->requirement_row),
|
||||
TALER_TESTING_make_trait_h_payto (&aws->h_payto),
|
||||
*/
|
||||
TALER_TESTING_make_trait_h_blinded_coin (idx,
|
||||
&aws->blinded_coin_hs[idx]),
|
||||
TALER_TESTING_make_trait_payto_uri (aws->reserve_payto_uri),
|
||||
TALER_TESTING_make_trait_exchange_url (aws->exchange_url),
|
||||
TALER_TESTING_make_trait_coin_priv (idx,
|
||||
&details->coin_priv),
|
||||
TALER_TESTING_make_trait_planchet_secrets (idx,
|
||||
&in->secrets[k]),
|
||||
TALER_TESTING_make_trait_blinding_key (idx,
|
||||
&details->blinding_key),
|
||||
TALER_TESTING_make_trait_exchange_wd_value (idx,
|
||||
&details->alg_values),
|
||||
TALER_TESTING_make_trait_age_commitment_proof (
|
||||
idx,
|
||||
&details->age_commitment_proof),
|
||||
TALER_TESTING_make_trait_h_age_commitment (
|
||||
idx,
|
||||
&details->h_age_commitment),
|
||||
};
|
||||
|
||||
if (idx >= aws->num_coins)
|
||||
return GNUNET_NO;
|
||||
|
||||
return TALER_TESTING_get_trait ((aws->expected_response_code == MHD_HTTP_OK)
|
||||
? &traits[0] /* we have reserve history */
|
||||
: &traits[1], /* skip reserve history */
|
||||
ret,
|
||||
trait,
|
||||
idx);
|
||||
}
|
||||
|
||||
|
||||
struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_age_withdraw (const char *label,
|
||||
@ -89,55 +462,27 @@ TALER_TESTING_cmd_age_withdraw (const char *label,
|
||||
va_list ap;
|
||||
|
||||
aws = GNUNET_new (struct AgeWithdrawState);
|
||||
aws->max_age = max_age;
|
||||
aws->reserve_reference = reserve_reference;
|
||||
aws->expected_response_code = expected_response_code;
|
||||
|
||||
// TODO[oec]: check max_age!?
|
||||
aws->mask = TALER_extensions_get_age_restriction_mask ();
|
||||
aws->max_age = TALER_get_lowest_age (&aws->mask, max_age);
|
||||
|
||||
cnt = 1;
|
||||
va_start (ap, amount);
|
||||
while (NULL != (va_arg (ap, const char *)))
|
||||
cnt++;
|
||||
aws->num_coins = cnt;
|
||||
aws->coins = GNUNET_new_array (cnt,
|
||||
struct CoinState);
|
||||
aws->coin_outputs = GNUNET_new_array (cnt,
|
||||
struct CoinOutputState);
|
||||
va_end (ap);
|
||||
va_start (ap, amount);
|
||||
|
||||
for (unsigned int i = 0; i<aws->num_coins; i++)
|
||||
{
|
||||
struct CoinState *cs = &aws->coins[i];
|
||||
if (0 < max_age)
|
||||
{
|
||||
struct GNUNET_HashCode seed;
|
||||
struct TALER_AgeMask mask;
|
||||
|
||||
mask = TALER_extensions_get_age_restriction_mask ();
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
|
||||
&seed,
|
||||
sizeof(seed));
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_age_restriction_commit (
|
||||
&mask,
|
||||
max_age,
|
||||
&seed,
|
||||
&cs->details.age_commitment_proof))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to generate age commitment for age %d at %s\n",
|
||||
max_age,
|
||||
label);
|
||||
GNUNET_assert (0);
|
||||
}
|
||||
|
||||
TALER_age_commitment_hash (&cs->details.age_commitment_proof.commitment,
|
||||
&cs->details.h_age_commitment);
|
||||
}
|
||||
|
||||
struct CoinOutputState *out = &aws->coin_outputs[i];
|
||||
if (GNUNET_OK !=
|
||||
TALER_string_to_amount (amount,
|
||||
&cs->amount))
|
||||
&out->amount))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to parse amount `%s' at %s\n",
|
||||
@ -145,9 +490,10 @@ TALER_TESTING_cmd_age_withdraw (const char *label,
|
||||
label);
|
||||
GNUNET_assert (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* move on to next vararg! */
|
||||
amount = va_arg (ap, const char *);
|
||||
}
|
||||
GNUNET_assert (NULL == amount);
|
||||
va_end (ap);
|
||||
|
||||
@ -155,9 +501,9 @@ TALER_TESTING_cmd_age_withdraw (const char *label,
|
||||
struct TALER_TESTING_Command cmd = {
|
||||
.cls = aws,
|
||||
.label = label,
|
||||
.run = NULL, // &age_withdraw_run,
|
||||
.cleanup = NULL, // &age_withdraw_cleanup,
|
||||
.traits = NULL, // &age_withdraw_traits
|
||||
.run = &age_withdraw_run,
|
||||
.cleanup = &age_withdraw_cleanup,
|
||||
.traits = &age_withdraw_traits,
|
||||
};
|
||||
|
||||
return cmd;
|
||||
@ -165,4 +511,237 @@ TALER_TESTING_cmd_age_withdraw (const char *label,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The state for the age-withdraw-reveal operation
|
||||
*/
|
||||
struct AgeWithdrawRevealState
|
||||
{
|
||||
/**
|
||||
* The reference to the CMD resembling the previous call to age-withdraw
|
||||
*/
|
||||
const char *age_withdraw_reference;
|
||||
|
||||
/**
|
||||
* The state to the previous age-withdraw command
|
||||
*/
|
||||
const struct AgeWithdrawState *aws;
|
||||
|
||||
/**
|
||||
* The expected response code from the call to the
|
||||
* age-withdraw-reveal operation
|
||||
*/
|
||||
unsigned int expected_response_code;
|
||||
|
||||
/**
|
||||
* Interpreter state (during command)
|
||||
*/
|
||||
struct TALER_TESTING_Interpreter *is;
|
||||
|
||||
/**
|
||||
* The handle to the reveal-operation
|
||||
*/
|
||||
struct TALER_EXCHANGE_AgeWithdrawRevealHandle *handle;
|
||||
|
||||
|
||||
/**
|
||||
* Number of coins, extracted form the age withdraw command
|
||||
*/
|
||||
size_t num_coins;
|
||||
|
||||
/**
|
||||
* The signatures of the @e num_coins coins returned
|
||||
*/
|
||||
struct TALER_DenominationSignature *denom_sigs;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Callback for the reveal response
|
||||
*
|
||||
* @param cls Closure of type `struct AgeWithdrawRevealState`
|
||||
* @param awr The response
|
||||
*/
|
||||
static void
|
||||
age_withdraw_reveal_cb (
|
||||
void *cls,
|
||||
const struct TALER_EXCHANGE_AgeWithdrawRevealResponse *response)
|
||||
{
|
||||
struct AgeWithdrawRevealState *awrs = cls;
|
||||
struct TALER_TESTING_Interpreter *is = awrs->is;
|
||||
|
||||
awrs->handle = NULL;
|
||||
if (awrs->expected_response_code != response->hr.http_status)
|
||||
{
|
||||
TALER_TESTING_unexpected_status_with_body (is,
|
||||
response->hr.http_status,
|
||||
awrs->expected_response_code,
|
||||
response->hr.reply);
|
||||
return;
|
||||
}
|
||||
switch (response->hr.http_status)
|
||||
{
|
||||
case MHD_HTTP_OK:
|
||||
{
|
||||
const struct AgeWithdrawState *aws = awrs->aws;
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Got age-withdraw reveal success!\n");
|
||||
GNUNET_assert (awrs->num_coins == response->details.ok.num_sigs);
|
||||
for (size_t n = 0; n < awrs->num_coins; n++)
|
||||
TALER_denom_sig_unblind (&awrs->denom_sigs[n],
|
||||
&response->details.ok.blinded_denom_sigs[n],
|
||||
&aws->coin_outputs[n].details.blinding_key,
|
||||
&aws->coin_outputs[n].details.h_coin_pub,
|
||||
&aws->coin_outputs[n].details.alg_values,
|
||||
&aws->coin_inputs[n].denom_pub->key);
|
||||
}
|
||||
break;
|
||||
case MHD_HTTP_NOT_FOUND:
|
||||
case MHD_HTTP_FORBIDDEN:
|
||||
/* nothing to check */
|
||||
break;
|
||||
/* TODO[oec]: handle more cases !? */
|
||||
default:
|
||||
/* Unsupported status code (by test harness) */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Age withdraw reveal test command does not support status code %u\n",
|
||||
response->hr.http_status);
|
||||
GNUNET_break (0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* We are done with this command, pick the next one */
|
||||
TALER_TESTING_interpreter_next (is);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the command for age-withdraw-reveal
|
||||
*/
|
||||
static void
|
||||
age_withdraw_reveal_run (
|
||||
void *cls,
|
||||
const struct TALER_TESTING_Command *cmd,
|
||||
struct TALER_TESTING_Interpreter *is)
|
||||
{
|
||||
struct AgeWithdrawRevealState *awrs = cls;
|
||||
const struct TALER_TESTING_Command *age_withdraw_cmd;
|
||||
const struct AgeWithdrawState *aws;
|
||||
|
||||
(void) cmd;
|
||||
awrs->is = is;
|
||||
|
||||
/*
|
||||
* Get the command and state for the previous call to "age witdraw"
|
||||
*/
|
||||
age_withdraw_cmd =
|
||||
TALER_TESTING_interpreter_get_command (is,
|
||||
awrs->age_withdraw_reference);
|
||||
if (NULL == age_withdraw_cmd)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
}
|
||||
GNUNET_assert (age_withdraw_cmd->run == age_withdraw_run);
|
||||
aws = age_withdraw_cmd->cls;
|
||||
awrs->aws = aws;
|
||||
awrs->num_coins = aws->num_coins;
|
||||
|
||||
awrs->handle =
|
||||
TALER_EXCHANGE_age_withdraw_reveal (
|
||||
TALER_TESTING_interpreter_get_context (is),
|
||||
TALER_TESTING_get_exchange_url (is),
|
||||
aws->num_coins,
|
||||
aws->coin_inputs,
|
||||
aws->noreveal_index,
|
||||
&aws->h_commitment,
|
||||
age_withdraw_reveal_cb,
|
||||
awrs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free the state of a "age-withdraw-reveal" CMD, and possibly
|
||||
* cancel a pending operation thereof
|
||||
*
|
||||
* @param cls Closure of type `struct AgeWithdrawRevealState`
|
||||
* @param cmd The command being freed.
|
||||
*/
|
||||
static void
|
||||
age_withdraw_reveal_cleanup (
|
||||
void *cls,
|
||||
const struct TALER_TESTING_Command *cmd)
|
||||
{
|
||||
struct AgeWithdrawRevealState *awrs = cls;
|
||||
|
||||
if (NULL != awrs->handle)
|
||||
{
|
||||
TALER_TESTING_command_incomplete (awrs->is,
|
||||
cmd->label);
|
||||
TALER_EXCHANGE_age_withdraw_reveal_cancel (awrs->handle);
|
||||
awrs->handle = NULL;
|
||||
}
|
||||
GNUNET_free (awrs->denom_sigs);
|
||||
awrs->denom_sigs = NULL;
|
||||
GNUNET_free (awrs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Offer internal data of a "age withdraw reveal" CMD state to other commands.
|
||||
*
|
||||
* @param cls Closure of they `struct AgeWithdrawRevealState`
|
||||
* @param[out] ret result (could be anything)
|
||||
* @param trait name of the trait
|
||||
* @param idx index number of the object to offer.
|
||||
* @return #GNUNET_OK on success
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
age_withdraw_reveal_traits (
|
||||
void *cls,
|
||||
const void **ret,
|
||||
const char *trait,
|
||||
unsigned int idx)
|
||||
{
|
||||
struct AgeWithdrawRevealState *awrs = cls;
|
||||
struct TALER_TESTING_Trait traits[] = {
|
||||
TALER_TESTING_make_trait_denom_sig (idx,
|
||||
&awrs->denom_sigs[idx]),
|
||||
/* FIXME: shall we provide the traits from the previous
|
||||
* call to "age withdraw" as well? */
|
||||
};
|
||||
|
||||
if (idx >= awrs->num_coins)
|
||||
return GNUNET_NO;
|
||||
|
||||
return TALER_TESTING_get_trait (traits,
|
||||
ret,
|
||||
trait,
|
||||
idx);
|
||||
}
|
||||
|
||||
|
||||
struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_age_withdraw_reveal (
|
||||
const char *label,
|
||||
const char *age_withdraw_reference,
|
||||
unsigned int expected_response_code)
|
||||
{
|
||||
struct AgeWithdrawRevealState *awrs =
|
||||
GNUNET_new (struct AgeWithdrawRevealState);
|
||||
|
||||
awrs->age_withdraw_reference = age_withdraw_reference;
|
||||
awrs->expected_response_code = expected_response_code;
|
||||
|
||||
struct TALER_TESTING_Command cmd = {
|
||||
.cls = awrs,
|
||||
.label = label,
|
||||
.run = age_withdraw_reveal_run,
|
||||
.cleanup = age_withdraw_reveal_cleanup,
|
||||
.traits = age_withdraw_reveal_traits,
|
||||
};
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
||||
/* end of testing_api_cmd_age_withdraw.c */
|
||||
|
@ -23,6 +23,7 @@
|
||||
* @author Marcello Stanisci
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_exchange_service.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include <microhttpd.h>
|
||||
#include <gnunet/gnunet_curl_lib.h>
|
||||
@ -217,7 +218,7 @@ reserve_batch_withdraw_cb (void *cls,
|
||||
/* nothing to check */
|
||||
break;
|
||||
case MHD_HTTP_CONFLICT:
|
||||
/* nothing to check */
|
||||
/* TODO[oec]: Check if age-requirement is the reason */
|
||||
break;
|
||||
case MHD_HTTP_GONE:
|
||||
/* theoretically could check that the key was actually */
|
||||
@ -250,6 +251,7 @@ batch_withdraw_run (void *cls,
|
||||
struct TALER_TESTING_Interpreter *is)
|
||||
{
|
||||
struct BatchWithdrawState *ws = cls;
|
||||
const struct TALER_EXCHANGE_Keys *keys = TALER_TESTING_get_keys (is);
|
||||
const struct TALER_ReservePrivateKeyP *rp;
|
||||
const struct TALER_TESTING_Command *create_reserve;
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *dpk;
|
||||
@ -292,7 +294,7 @@ batch_withdraw_run (void *cls,
|
||||
struct TALER_EXCHANGE_WithdrawCoinInput *wci = &wcis[i];
|
||||
|
||||
TALER_planchet_master_setup_random (&cs->ps);
|
||||
dpk = TALER_TESTING_find_pk (TALER_TESTING_get_keys (is),
|
||||
dpk = TALER_TESTING_find_pk (keys,
|
||||
&cs->amount,
|
||||
ws->age > 0);
|
||||
if (NULL == dpk)
|
||||
@ -321,7 +323,7 @@ batch_withdraw_run (void *cls,
|
||||
ws->wsh = TALER_EXCHANGE_batch_withdraw (
|
||||
TALER_TESTING_interpreter_get_context (is),
|
||||
TALER_TESTING_get_exchange_url (is),
|
||||
TALER_TESTING_get_keys (is),
|
||||
keys,
|
||||
rp,
|
||||
ws->num_coins,
|
||||
wcis,
|
||||
|
@ -59,6 +59,20 @@ TALER_TESTING_history_entry_cmp (
|
||||
that should be good enough. */
|
||||
return 0;
|
||||
return 1;
|
||||
case TALER_EXCHANGE_RTT_AGEWITHDRAWAL:
|
||||
/* testing_api_cmd_age_withdraw doesn't set the out_authorization_sig,
|
||||
so we cannot test for it here. but if the amount matches,
|
||||
that should be good enough. */
|
||||
if ( (0 ==
|
||||
TALER_amount_cmp (&h1->amount,
|
||||
&h2->amount)) &&
|
||||
(0 ==
|
||||
TALER_amount_cmp (&h1->details.age_withdraw.fee,
|
||||
&h2->details.age_withdraw.fee)) &&
|
||||
(h1->details.age_withdraw.max_age ==
|
||||
h2->details.age_withdraw.max_age))
|
||||
return 0;
|
||||
return 1;
|
||||
case TALER_EXCHANGE_RTT_RECOUP:
|
||||
/* exchange_sig, exchange_pub and timestamp are NOT available
|
||||
from the original recoup response, hence here NOT check(able/ed) */
|
||||
|
@ -31,6 +31,9 @@
|
||||
#include "taler_testing_lib.h"
|
||||
|
||||
|
||||
/**
|
||||
* The interpreter and its state
|
||||
*/
|
||||
struct TALER_TESTING_Interpreter
|
||||
{
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user