-towards reserve history testing

This commit is contained in:
Christian Grothoff 2022-05-23 11:15:05 +02:00
parent b3844e4923
commit f1a58b0fd8
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
5 changed files with 232 additions and 53 deletions

View File

@ -1767,6 +1767,18 @@ struct TALER_EXCHANGE_ReserveHistory
*/
struct TALER_EXCHANGE_HttpResponse hr;
/**
* Timestamp of when we made the history request
* (client-side).
*/
struct GNUNET_TIME_Timestamp ts;
/**
* Reserve signature affirming the history request
* (generated as part of the request).
*/
const struct TALER_ReserveSignatureP *reserve_sig;
/**
* Details depending on @e hr.http_status.
*/
@ -4388,6 +4400,11 @@ struct TALER_EXCHANGE_AccountMergeResponse
*/
struct TALER_EXCHANGE_HttpResponse hr;
/**
* Reserve signature affirming the merge.
*/
const struct TALER_ReserveSignatureP *reserve_sig;
/**
* Details depending on the HTTP status.
*/
@ -4398,6 +4415,20 @@ struct TALER_EXCHANGE_AccountMergeResponse
*/
struct
{
/**
* Signature by the exchange affirming the merge.
*/
struct TALER_ExchangeSignatureP exchange_sig;
/**
* Online signing key used by the exchange.
*/
struct TALER_ExchangePublicKeyP exchange_pub;
/**
* Timestamp of the exchange for @e exchange_sig.
*/
struct GNUNET_TIME_Timestamp etime;
} success;

View File

@ -104,6 +104,12 @@ struct TALER_EXCHANGE_AccountMergeHandle
* Our merge key.
*/
struct TALER_PurseMergePrivateKeyP merge_priv;
/**
* Reserve signature affirming the merge.
*/
struct TALER_ReserveSignatureP reserve_sig;
};
@ -168,7 +174,8 @@ handle_purse_merge_finished (void *cls,
const json_t *j = response;
struct TALER_EXCHANGE_AccountMergeResponse dr = {
.hr.reply = j,
.hr.http_status = (unsigned int) response_code
.hr.http_status = (unsigned int) response_code,
.reserve_sig = &pch->reserve_sig
};
pch->job = NULL;
@ -180,17 +187,14 @@ handle_purse_merge_finished (void *cls,
case MHD_HTTP_OK:
{
const struct TALER_EXCHANGE_Keys *key_state;
struct GNUNET_TIME_Timestamp etime;
struct TALER_Amount total_deposited;
struct TALER_ExchangeSignatureP exchange_sig;
struct TALER_ExchangePublicKeyP exchange_pub;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&exchange_sig),
&dr.details.success.exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&exchange_pub),
&dr.details.success.exchange_pub),
GNUNET_JSON_spec_timestamp ("exchange_timestamp",
&etime),
&dr.details.success.etime),
TALER_JSON_spec_amount ("merge_amount",
pch->purse_value_after_fees.currency,
&total_deposited),
@ -210,7 +214,7 @@ handle_purse_merge_finished (void *cls,
key_state = TALER_EXCHANGE_get_keys (pch->exchange);
if (GNUNET_OK !=
TALER_EXCHANGE_test_signing_key (key_state,
&exchange_pub))
&dr.details.success.exchange_pub))
{
GNUNET_break_op (0);
dr.hr.http_status = 0;
@ -219,15 +223,15 @@ handle_purse_merge_finished (void *cls,
}
if (GNUNET_OK !=
TALER_exchange_online_purse_merged_verify (
etime,
dr.details.success.etime,
pch->purse_expiration,
&pch->purse_value_after_fees,
&pch->purse_pub,
&pch->h_contract_terms,
&pch->reserve_pub,
pch->provider_url,
&exchange_pub,
&exchange_sig))
&dr.details.success.exchange_pub,
&dr.details.success.exchange_sig))
{
GNUNET_break_op (0);
dr.hr.http_status = 0;
@ -367,7 +371,6 @@ TALER_EXCHANGE_account_merge (
json_t *merge_obj;
CURL *eh;
struct TALER_PurseMergeSignatureP merge_sig;
struct TALER_ReserveSignatureP reserve_sig;
char arg_str[sizeof (pch->purse_pub) * 2 + 32];
char *reserve_url;
@ -442,7 +445,7 @@ TALER_EXCHANGE_account_merge (
min_age,
TALER_WAMF_MODE_MERGE_FULLY_PAID_PURSE,
reserve_priv,
&reserve_sig);
&pch->reserve_sig);
}
merge_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("payto_uri",
@ -450,7 +453,7 @@ TALER_EXCHANGE_account_merge (
GNUNET_JSON_pack_data_auto ("merge_sig",
&merge_sig),
GNUNET_JSON_pack_data_auto ("reserve_sig",
&reserve_sig),
&pch->reserve_sig),
GNUNET_JSON_pack_timestamp ("merge_timestamp",
merge_timestamp));
GNUNET_assert (NULL != merge_obj);

View File

@ -64,15 +64,25 @@ struct TALER_EXCHANGE_ReservesHistoryHandle
*/
TALER_EXCHANGE_ReservesHistoryCallback cb;
/**
* Closure for @a cb.
*/
void *cb_cls;
/**
* Public key of the reserve we are querying.
*/
struct TALER_ReservePublicKeyP reserve_pub;
/**
* Closure for @a cb.
* Our signature.
*/
void *cb_cls;
struct TALER_ReserveSignatureP reserve_sig;
/**
* When did we make the request.
*/
struct GNUNET_TIME_Timestamp ts;
};
@ -93,7 +103,9 @@ handle_reserves_history_ok (struct TALER_EXCHANGE_ReservesHistoryHandle *rsh,
unsigned int len;
struct TALER_EXCHANGE_ReserveHistory rs = {
.hr.reply = j,
.hr.http_status = MHD_HTTP_OK
.hr.http_status = MHD_HTTP_OK,
.ts = rsh->ts,
.reserve_sig = &rsh->reserve_sig
};
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_amount_any ("balance",
@ -247,9 +259,8 @@ TALER_EXCHANGE_reserves_history (
struct GNUNET_CURL_Context *ctx;
CURL *eh;
char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32];
struct TALER_ReserveSignatureP reserve_sig;
struct GNUNET_TIME_Timestamp ts
= GNUNET_TIME_timestamp_get ();
const struct TALER_EXCHANGE_Keys *keys;
const struct TALER_EXCHANGE_GlobalFee *gf;
if (GNUNET_YES !=
TEAH_handle_is_ready (exchange))
@ -261,6 +272,7 @@ TALER_EXCHANGE_reserves_history (
rsh->exchange = exchange;
rsh->cb = cb;
rsh->cb_cls = cb_cls;
rsh->ts = GNUNET_TIME_timestamp_get ();
GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
&rsh->reserve_pub.eddsa_pub);
{
@ -293,16 +305,21 @@ TALER_EXCHANGE_reserves_history (
GNUNET_free (rsh);
return NULL;
}
TALER_wallet_reserve_history_sign (ts,
NULL, /* FIXME: fee! */
keys = TALER_EXCHANGE_get_keys (exchange);
GNUNET_assert (NULL != keys);
gf = TALER_EXCHANGE_get_global_fee (keys,
rsh->ts);
GNUNET_assert (NULL != gf);
TALER_wallet_reserve_history_sign (rsh->ts,
&gf->fees.history,
reserve_priv,
&reserve_sig);
&rsh->reserve_sig);
{
json_t *history_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_timestamp ("request_timestamp",
ts),
rsh->ts),
GNUNET_JSON_pack_data_auto ("reserve_sig",
&reserve_sig));
&rsh->reserve_sig));
if (GNUNET_OK !=
TALER_curl_easy_post (&rsh->post_ctx,

View File

@ -71,6 +71,42 @@ struct PurseMergeState
*/
struct TALER_TESTING_Interpreter *is;
/**
* Reserve history entry that corresponds to this operation.
* Will be of type #TALER_EXCHANGE_RTT_MERGE.
*/
struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
/**
* Public key of the purse.
*/
struct TALER_PurseContractPublicKeyP purse_pub;
/**
* Public key of the merge capability.
*/
struct TALER_PurseMergePublicKeyP merge_pub;
/**
* Contract value.
*/
struct TALER_Amount value_after_fees;
/**
* Hash of the contract.
*/
struct TALER_PrivateContractHashP h_contract_terms;
/**
* When does the purse expire.
*/
struct GNUNET_TIME_Timestamp purse_expiration;
/**
* Minimum age of deposits into the purse.
*/
uint32_t min_age;
/**
* Expected HTTP response code.
*/
@ -93,6 +129,36 @@ merge_cb (void *cls,
struct PurseMergeState *ds = cls;
ds->dh = NULL;
if (MHD_HTTP_OK == dr->hr.http_status)
{
const struct TALER_EXCHANGE_Keys *keys;
const struct TALER_EXCHANGE_GlobalFee *gf;
ds->reserve_history.type = TALER_EXCHANGE_RTT_MERGE;
keys = TALER_EXCHANGE_get_keys (ds->is->exchange);
GNUNET_assert (NULL != keys);
gf = TALER_EXCHANGE_get_global_fee (keys,
ds->merge_timestamp);
GNUNET_assert (NULL != gf);
ds->reserve_history.amount = gf->fees.purse;
ds->reserve_history.details.merge_details.purse_fee = gf->fees.purse;
ds->reserve_history.details.merge_details.h_contract_terms
= ds->h_contract_terms;
ds->reserve_history.details.merge_details.merge_pub
= ds->merge_pub;
ds->reserve_history.details.merge_details.reserve_sig
= *dr->reserve_sig;
ds->reserve_history.details.merge_details.merge_timestamp
= ds->merge_timestamp;
ds->reserve_history.details.merge_details.purse_expiration
= ds->purse_expiration;
ds->reserve_history.details.merge_details.min_age
= ds->min_age;
ds->reserve_history.details.merge_details.flags
= TALER_WAMF_MODE_MERGE_FULLY_PAID_PURSE;
}
if (ds->expected_response_code != dr->hr.http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -124,13 +190,8 @@ merge_run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct PurseMergeState *ds = cls;
const struct TALER_PurseContractPublicKeyP *purse_pub;
const struct TALER_PurseMergePrivateKeyP *merge_priv;
const json_t *ct;
struct TALER_PrivateContractHashP h_contract_terms;
uint32_t min_age = 0;
struct TALER_Amount value_after_fees;
struct GNUNET_TIME_Timestamp purse_expiration;
const struct TALER_TESTING_Command *ref;
(void) cmd;
@ -146,6 +207,9 @@ merge_run (void *cls,
TALER_TESTING_interpreter_fail (ds->is);
return;
}
{
const struct TALER_PurseContractPublicKeyP *purse_pub;
if (GNUNET_OK !=
TALER_TESTING_get_trait_purse_pub (ref,
&purse_pub))
@ -154,6 +218,9 @@ merge_run (void *cls,
TALER_TESTING_interpreter_fail (ds->is);
return;
}
ds->purse_pub = *purse_pub;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_contract_terms (ref,
&ct))
@ -164,7 +231,7 @@ merge_run (void *cls,
}
if (GNUNET_OK !=
TALER_JSON_contract_hash (ct,
&h_contract_terms))
&ds->h_contract_terms))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (ds->is);
@ -173,12 +240,12 @@ merge_run (void *cls,
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_timestamp ("pay_deadline",
&purse_expiration),
&ds->purse_expiration),
TALER_JSON_spec_amount_any ("amount",
&value_after_fees),
&ds->value_after_fees),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_uint32 ("minimum_age",
&min_age),
&ds->min_age),
NULL),
GNUNET_JSON_spec_end ()
};
@ -217,17 +284,19 @@ merge_run (void *cls,
}
GNUNET_CRYPTO_eddsa_key_get_public (&ds->reserve_priv.eddsa_priv,
&ds->reserve_pub.eddsa_pub);
GNUNET_CRYPTO_eddsa_key_get_public (&merge_priv->eddsa_priv,
&ds->merge_pub.eddsa_pub);
ds->merge_timestamp = GNUNET_TIME_timestamp_get ();
ds->dh = TALER_EXCHANGE_account_merge (
is->exchange,
NULL, /* no wad */
&ds->reserve_priv,
purse_pub,
&ds->purse_pub,
merge_priv,
&h_contract_terms,
min_age,
&value_after_fees,
purse_expiration,
&ds->h_contract_terms,
ds->min_age,
&ds->value_after_fees,
ds->purse_expiration,
ds->merge_timestamp,
&merge_cb,
ds);
@ -285,12 +354,16 @@ merge_traits (void *cls,
{
struct PurseMergeState *ds = cls;
struct TALER_TESTING_Trait traits[] = {
/* history entry MUST be first due to response code logic below! */
TALER_TESTING_make_trait_reserve_history (&ds->reserve_history),
TALER_TESTING_make_trait_timestamp (0,
&ds->merge_timestamp),
TALER_TESTING_trait_end ()
};
return TALER_TESTING_get_trait (traits,
return TALER_TESTING_get_trait ((ds->expected_response_code == MHD_HTTP_OK)
? &traits[0] /* we have reserve history */
: &traits[1], /* skip reserve history */
ret,
trait,
index);

View File

@ -32,6 +32,12 @@
*/
struct HistoryState
{
/**
* Public key of the reserve being analyzed.
*/
struct TALER_ReservePublicKeyP reserve_pub;
/**
* Label to the command which created the reserve to check,
* needed to resort the reserve key.
@ -54,19 +60,21 @@ struct HistoryState
const struct TALER_ReservePrivateKeyP *reserve_priv;
/**
* Public key of the reserve being analyzed.
* Interpreter state.
*/
struct TALER_ReservePublicKeyP reserve_pub;
struct TALER_TESTING_Interpreter *is;
/**
* Reserve history entry that corresponds to this operation.
* Will be of type #TALER_EXCHANGE_RTT_HISTORY.
*/
struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
/**
* Expected HTTP response code.
*/
unsigned int expected_response_code;
/**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
};
@ -177,6 +185,21 @@ reserve_history_cb (void *cls,
struct TALER_Amount eb;
ss->rsh = NULL;
if (MHD_HTTP_OK == rs->hr.http_status)
{
const struct TALER_EXCHANGE_Keys *keys;
const struct TALER_EXCHANGE_GlobalFee *gf;
ss->reserve_history.type = TALER_EXCHANGE_RTT_HISTORY;
keys = TALER_EXCHANGE_get_keys (ss->is->exchange);
GNUNET_assert (NULL != keys);
gf = TALER_EXCHANGE_get_global_fee (keys,
rs->ts);
GNUNET_assert (NULL != gf);
ss->reserve_history.amount = gf->fees.history;
ss->reserve_history.details.history_details.request_timestamp = rs->ts;
ss->reserve_history.details.history_details.reserve_sig = *rs->reserve_sig;
}
if (ss->expected_response_code != rs->hr.http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -290,6 +313,37 @@ history_run (void *cls,
}
/**
* Offer internal data from a "history" CMD, to other commands.
*
* @param cls closure.
* @param[out] ret result.
* @param trait name of the trait.
* @param index index number of the object to offer.
* @return #GNUNET_OK on success.
*/
static enum GNUNET_GenericReturnValue
history_traits (void *cls,
const void **ret,
const char *trait,
unsigned int index)
{
struct HistoryState *hs = cls;
struct TALER_TESTING_Trait traits[] = {
/* history entry MUST be first due to response code logic below! */
TALER_TESTING_make_trait_reserve_history (&hs->reserve_history),
TALER_TESTING_trait_end ()
};
return TALER_TESTING_get_trait ((hs->expected_response_code == MHD_HTTP_OK)
? &traits[0] /* we have reserve history */
: &traits[1], /* skip reserve history */
ret,
trait,
index);
}
/**
* Cleanup the state from a "reserve history" CMD, and possibly
* cancel a pending operation thereof.
@ -334,7 +388,8 @@ TALER_TESTING_cmd_reserve_history (const char *label,
.cls = ss,
.label = label,
.run = &history_run,
.cleanup = &history_cleanup
.cleanup = &history_cleanup,
.traits = &history_traits
};
return cmd;