implement #3887-handling in exchange-lib

This commit is contained in:
Christian Grothoff 2017-04-03 22:45:48 +02:00
parent dbb2368403
commit cc3aa31732
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
4 changed files with 273 additions and 92 deletions

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2015, 2016 Inria & GNUnet e.V. Copyright (C) 2015-2017 Inria & GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software terms of the GNU General Public License as published by the Free Software
@ -65,20 +65,12 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
{ {
json_t *transaction; json_t *transaction;
struct TALER_Amount amount; struct TALER_Amount amount;
struct TALER_CoinSpendSignatureP sig;
void *details;
size_t details_size;
const char *type; const char *type;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec_glob[] = {
TALER_JSON_spec_amount ("amount", TALER_JSON_spec_amount ("amount",
&amount), &amount),
GNUNET_JSON_spec_string ("type", GNUNET_JSON_spec_string ("type",
&type), &type),
GNUNET_JSON_spec_fixed_auto ("signature",
&sig),
GNUNET_JSON_spec_varsize ("details",
&details,
&details_size),
GNUNET_JSON_spec_end() GNUNET_JSON_spec_end()
}; };
@ -86,7 +78,7 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
off); off);
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_JSON_parse (transaction, GNUNET_JSON_parse (transaction,
spec, spec_glob,
NULL, NULL)) NULL, NULL))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
@ -96,40 +88,47 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
if (0 == strcasecmp (type, if (0 == strcasecmp (type,
"DEPOSIT")) "DEPOSIT"))
{ {
const struct TALER_DepositRequestPS *dr; struct TALER_DepositRequestPS dr;
struct TALER_Amount dr_amount; struct TALER_Amount dr_amount;
struct TALER_CoinSpendSignatureP sig;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("signature",
&sig),
GNUNET_JSON_spec_fixed_auto ("details",
&dr),
GNUNET_JSON_spec_end()
};
if (details_size != sizeof (struct TALER_DepositRequestPS)) if (GNUNET_OK !=
GNUNET_JSON_parse (transaction,
spec,
NULL, NULL))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
dr = (const struct TALER_DepositRequestPS *) details; /* TODO #4980 */
if (details_size != ntohl (dr->purpose.size)) if (sizeof (dr) != ntohl (dr.purpose.size))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
&dr->purpose, &dr.purpose,
&sig.eddsa_signature, &sig.eddsa_signature,
&coin_pub->eddsa_pub)) &coin_pub->eddsa_pub))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
TALER_amount_ntoh (&dr_amount, TALER_amount_ntoh (&dr_amount,
&dr->amount_with_fee); &dr.amount_with_fee);
/* TODO #4980 */
if (0 != TALER_amount_cmp (&dr_amount, if (0 != TALER_amount_cmp (&dr_amount,
&amount)) &amount))
{ {
GNUNET_break (0); GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
add = GNUNET_YES; add = GNUNET_YES;
@ -137,39 +136,47 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
else if (0 == strcasecmp (type, else if (0 == strcasecmp (type,
"MELT")) "MELT"))
{ {
const struct TALER_RefreshMeltCoinAffirmationPS *rm; struct TALER_RefreshMeltCoinAffirmationPS rm;
struct TALER_Amount rm_amount; struct TALER_Amount rm_amount;
struct TALER_CoinSpendSignatureP sig;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("signature",
&sig),
GNUNET_JSON_spec_fixed_auto ("details",
&rm),
GNUNET_JSON_spec_end()
};
if (details_size != sizeof (struct TALER_RefreshMeltCoinAffirmationPS)) if (GNUNET_OK !=
GNUNET_JSON_parse (transaction,
spec,
NULL, NULL))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
rm = (const struct TALER_RefreshMeltCoinAffirmationPS *) details; /* TODO #4980 */
if (details_size != ntohl (rm->purpose.size)) if (sizeof (rm) != ntohl (rm.purpose.size))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT, GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
&rm->purpose, &rm.purpose,
&sig.eddsa_signature, &sig.eddsa_signature,
&coin_pub->eddsa_pub)) &coin_pub->eddsa_pub))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
TALER_amount_ntoh (&rm_amount, TALER_amount_ntoh (&rm_amount,
&rm->amount_with_fee); &rm.amount_with_fee);
/* TODO #4980 */
if (0 != TALER_amount_cmp (&rm_amount, if (0 != TALER_amount_cmp (&rm_amount,
&amount)) &amount))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
add = GNUNET_YES; add = GNUNET_YES;
@ -177,55 +184,60 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
else if (0 == strcasecmp (type, else if (0 == strcasecmp (type,
"REFUND")) "REFUND"))
{ {
const struct TALER_RefundRequestPS *rr; struct TALER_RefundRequestPS rr;
struct TALER_Amount rr_amount; struct TALER_Amount rr_amount;
struct TALER_Amount rr_fee; struct TALER_Amount rr_fee;
struct TALER_Amount rr_delta; struct TALER_Amount rr_delta;
struct TALER_CoinSpendSignatureP sig;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("signature",
&sig),
GNUNET_JSON_spec_fixed_auto ("details",
&rr),
GNUNET_JSON_spec_end()
};
if (details_size != sizeof (struct TALER_RefundRequestPS)) if (GNUNET_OK !=
GNUNET_JSON_parse (transaction,
spec,
NULL, NULL))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
rr = (const struct TALER_RefundRequestPS *) details; /* TODO #4980 */
if (details_size != ntohl (rr->purpose.size)) if (sizeof (rr) != ntohl (rr.purpose.size))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND, GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
&rr->purpose, &rr.purpose,
&sig.eddsa_signature, &sig.eddsa_signature,
&rr->merchant.eddsa_pub)) &rr.merchant.eddsa_pub))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
TALER_amount_ntoh (&rr_amount, TALER_amount_ntoh (&rr_amount,
&rr->refund_amount); &rr.refund_amount);
TALER_amount_ntoh (&rr_fee,
&rr->refund_fee);
if (GNUNET_OK != if (GNUNET_OK !=
TALER_amount_subtract (&rr_delta, TALER_amount_subtract (&rr_delta,
&rr_amount, &rr_amount,
&rr_fee)) &rr_fee))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
/* TODO #4980 */
if (0 != TALER_amount_cmp (&rr_delta, if (0 != TALER_amount_cmp (&rr_delta,
&amount)) &amount))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
/* NOTE/FIXME: theoretically, we could also check that the given /* NOTE: theoretically, we could also check that the given
merchant_pub and h_proposal_data appear in the merchant_pub and h_proposal_data appear in the
history under deposits. However, there is really no benefit history under deposits. However, there is really no benefit
for the exchange to lie here, so not checking is probably OK for the exchange to lie here, so not checking is probably OK
@ -237,14 +249,59 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
else if (0 == strcasecmp (type, else if (0 == strcasecmp (type,
"PAYBACK")) "PAYBACK"))
{ {
GNUNET_break (0); /* #3887 */ struct TALER_PaybackConfirmationPS pc;
struct TALER_Amount pc_amount;
struct TALER_ExchangePublicKeyP exchange_pub;
struct TALER_ExchangeSignatureP exchange_sig;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&exchange_pub),
GNUNET_JSON_spec_fixed_auto ("details",
&pc),
GNUNET_JSON_spec_end()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (transaction,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
/* TODO #4980 */
if (sizeof (pc) != ntohl (pc.purpose.size))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK,
&pc.purpose,
&exchange_sig.eddsa_signature,
&exchange_pub.eddsa_pub))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
TALER_amount_ntoh (&pc_amount,
&pc.payback_amount);
/* TODO #4980 */
if (0 != TALER_amount_cmp (&pc_amount,
&amount))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
add = GNUNET_YES;
} }
else else
{ {
/* signature not supported, new version on server? */ /* signature not supported, new version on server? */
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
if (GNUNET_YES == add) if (GNUNET_YES == add)
@ -257,7 +314,6 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
{ {
/* overflow in history already!? inconceivable! Bad exchange! */ /* overflow in history already!? inconceivable! Bad exchange! */
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
} }
@ -277,11 +333,9 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
{ {
/* overflow in refund history? inconceivable! Bad exchange! */ /* overflow in refund history? inconceivable! Bad exchange! */
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
} }
GNUNET_JSON_parse_free (spec);
} }
/* Finally, subtract 'rtotal' from total to handle the subtractions */ /* Finally, subtract 'rtotal' from total to handle the subtractions */

View File

@ -77,7 +77,8 @@ struct TALER_EXCHANGE_ReserveStatusHandle
* Parse history given in JSON format and return it in binary * Parse history given in JSON format and return it in binary
* format. * format.
* *
* @param[in] history JSON array with the history * @param exchange connection to the exchange we can use
* @param history JSON array with the history
* @param reserve_pub public key of the reserve to inspect * @param reserve_pub public key of the reserve to inspect
* @param currency currency we expect the balance to be in * @param currency currency we expect the balance to be in
* @param[out] balance final balance * @param[out] balance final balance
@ -89,7 +90,8 @@ struct TALER_EXCHANGE_ReserveStatusHandle
* #GNUNET_SYSERR if there was a protocol violation in @a history * #GNUNET_SYSERR if there was a protocol violation in @a history
*/ */
static int static int
parse_reserve_history (const json_t *history, parse_reserve_history (struct TALER_EXCHANGE_Handle *exchange,
const json_t *history,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
const char *currency, const char *currency,
struct TALER_Amount *balance, struct TALER_Amount *balance,
@ -214,6 +216,7 @@ parse_reserve_history (const json_t *history,
} }
TALER_amount_ntoh (&amount_from_purpose, TALER_amount_ntoh (&amount_from_purpose,
&withdraw_purpose.amount_with_fee); &withdraw_purpose.amount_with_fee);
/* TODO #4980 */
if (0 != TALER_amount_cmp (&amount, if (0 != TALER_amount_cmp (&amount,
&amount_from_purpose)) &amount_from_purpose))
{ {
@ -259,13 +262,75 @@ parse_reserve_history (const json_t *history,
else if (0 == strcasecmp (type, else if (0 == strcasecmp (type,
"PAYBACK")) "PAYBACK"))
{ {
GNUNET_break (0); /* #3887 */ struct TALER_PaybackConfirmationPS pc;
struct TALER_Amount amount_from_purpose;
struct GNUNET_TIME_Absolute timestamp_from_purpose;
struct GNUNET_TIME_Absolute timestamp;
const struct TALER_EXCHANGE_Keys *key_state;
struct GNUNET_JSON_Specification payback_spec[] = {
GNUNET_JSON_spec_fixed_auto ("details",
&pc),
GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&rhistory[off].details.payback_details.exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&rhistory[off].details.payback_details.exchange_pub),
GNUNET_JSON_spec_absolute_time ("timetamp",
&timestamp),
TALER_JSON_spec_amount ("amount",
&rhistory[off].amount),
GNUNET_JSON_spec_end()
};
rhistory[off].type = TALER_EXCHANGE_RTT_PAYBACK;
if (GNUNET_OK !=
GNUNET_JSON_parse (transaction,
payback_spec,
NULL, NULL))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
rhistory[off].details.payback_details.coin_pub = pc.coin_pub;
TALER_amount_ntoh (&amount_from_purpose,
&pc.payback_amount);
rhistory[off].details.payback_details.timestamp = timestamp;
timestamp_from_purpose = GNUNET_TIME_absolute_ntoh (pc.timestamp);
/* TODO #4980 */
if ( (0 != memcmp (&pc.reserve_pub,
reserve_pub,
sizeof (*reserve_pub))) ||
(timestamp_from_purpose.abs_value_us !=
timestamp.abs_value_us) ||
(0 != TALER_amount_cmp (&amount_from_purpose,
&rhistory[off].amount)) )
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
key_state = TALER_EXCHANGE_get_keys (exchange);
if (GNUNET_OK !=
TALER_EXCHANGE_test_signing_key (key_state,
&rhistory[off].details.payback_details.exchange_pub))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK,
&pc.purpose,
&rhistory[off].details.payback_details.exchange_sig.eddsa_signature,
&rhistory[off].details.payback_details.exchange_pub.eddsa_pub))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
/* end type==PAYBACK */ /* end type==PAYBACK */
} }
else if (0 == strcasecmp (type, else if (0 == strcasecmp (type,
"CLOSING")) "CLOSING"))
{ {
GNUNET_break (0); /* #3887 / #4956 */ GNUNET_break (0); /* FIXME: implement with #4956 */
/* end type==CLOSING */ /* end type==CLOSING */
} }
else else
@ -304,9 +369,9 @@ handle_reserve_status_finished (void *cls,
long response_code, long response_code,
const json_t *json) const json_t *json)
{ {
struct TALER_EXCHANGE_ReserveStatusHandle *wsh = cls; struct TALER_EXCHANGE_ReserveStatusHandle *rsh = cls;
wsh->job = NULL; rsh->job = NULL;
switch (response_code) switch (response_code)
{ {
case 0: case 0:
@ -346,8 +411,9 @@ handle_reserve_status_finished (void *cls,
struct TALER_EXCHANGE_ReserveHistory rhistory[len]; struct TALER_EXCHANGE_ReserveHistory rhistory[len];
if (GNUNET_OK != if (GNUNET_OK !=
parse_reserve_history (history, parse_reserve_history (rsh->exchange,
&wsh->reserve_pub, history,
&rsh->reserve_pub,
balance.currency, balance.currency,
&balance_from_history, &balance_from_history,
len, len,
@ -366,14 +432,14 @@ handle_reserve_status_finished (void *cls,
response_code = 0; response_code = 0;
break; break;
} }
wsh->cb (wsh->cb_cls, rsh->cb (rsh->cb_cls,
response_code, response_code,
TALER_EC_NONE, TALER_EC_NONE,
json, json,
&balance, &balance,
len, len,
rhistory); rhistory);
wsh->cb = NULL; rsh->cb = NULL;
} }
} }
break; break;
@ -398,14 +464,14 @@ handle_reserve_status_finished (void *cls,
response_code = 0; response_code = 0;
break; break;
} }
if (NULL != wsh->cb) if (NULL != rsh->cb)
wsh->cb (wsh->cb_cls, rsh->cb (rsh->cb_cls,
response_code, response_code,
TALER_JSON_get_error_code (json), TALER_JSON_get_error_code (json),
json, json,
NULL, NULL,
0, NULL); 0, NULL);
TALER_EXCHANGE_reserve_status_cancel (wsh); TALER_EXCHANGE_reserve_status_cancel (rsh);
} }
@ -431,7 +497,7 @@ TALER_EXCHANGE_reserve_status (struct TALER_EXCHANGE_Handle *exchange,
TALER_EXCHANGE_ReserveStatusResultCallback cb, TALER_EXCHANGE_ReserveStatusResultCallback cb,
void *cb_cls) void *cb_cls)
{ {
struct TALER_EXCHANGE_ReserveStatusHandle *wsh; struct TALER_EXCHANGE_ReserveStatusHandle *rsh;
struct GNUNET_CURL_Context *ctx; struct GNUNET_CURL_Context *ctx;
CURL *eh; CURL *eh;
char *pub_str; char *pub_str;
@ -449,12 +515,12 @@ TALER_EXCHANGE_reserve_status (struct TALER_EXCHANGE_Handle *exchange,
"/reserve/status?reserve_pub=%s", "/reserve/status?reserve_pub=%s",
pub_str); pub_str);
GNUNET_free (pub_str); GNUNET_free (pub_str);
wsh = GNUNET_new (struct TALER_EXCHANGE_ReserveStatusHandle); rsh = GNUNET_new (struct TALER_EXCHANGE_ReserveStatusHandle);
wsh->exchange = exchange; rsh->exchange = exchange;
wsh->cb = cb; rsh->cb = cb;
wsh->cb_cls = cb_cls; rsh->cb_cls = cb_cls;
wsh->reserve_pub = *reserve_pub; rsh->reserve_pub = *reserve_pub;
wsh->url = MAH_path_to_url (exchange, rsh->url = MAH_path_to_url (exchange,
arg_str); arg_str);
GNUNET_free (arg_str); GNUNET_free (arg_str);
@ -462,14 +528,14 @@ TALER_EXCHANGE_reserve_status (struct TALER_EXCHANGE_Handle *exchange,
GNUNET_assert (CURLE_OK == GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh, curl_easy_setopt (eh,
CURLOPT_URL, CURLOPT_URL,
wsh->url)); rsh->url));
ctx = MAH_handle_to_context (exchange); ctx = MAH_handle_to_context (exchange);
wsh->job = GNUNET_CURL_job_add (ctx, rsh->job = GNUNET_CURL_job_add (ctx,
eh, eh,
GNUNET_NO, GNUNET_NO,
&handle_reserve_status_finished, &handle_reserve_status_finished,
wsh); rsh);
return wsh; return rsh;
} }
@ -477,18 +543,18 @@ TALER_EXCHANGE_reserve_status (struct TALER_EXCHANGE_Handle *exchange,
* Cancel a withdraw status request. This function cannot be used * Cancel a withdraw status request. This function cannot be used
* on a request handle if a response is already served for it. * on a request handle if a response is already served for it.
* *
* @param wsh the withdraw status request handle * @param rsh the withdraw status request handle
*/ */
void void
TALER_EXCHANGE_reserve_status_cancel (struct TALER_EXCHANGE_ReserveStatusHandle *wsh) TALER_EXCHANGE_reserve_status_cancel (struct TALER_EXCHANGE_ReserveStatusHandle *rsh)
{ {
if (NULL != wsh->job) if (NULL != rsh->job)
{ {
GNUNET_CURL_job_cancel (wsh->job); GNUNET_CURL_job_cancel (rsh->job);
wsh->job = NULL; rsh->job = NULL;
} }
GNUNET_free (wsh->url); GNUNET_free (rsh->url);
GNUNET_free (wsh); GNUNET_free (rsh);
} }
@ -663,7 +729,8 @@ reserve_withdraw_payment_required (struct TALER_EXCHANGE_ReserveWithdrawHandle *
struct TALER_EXCHANGE_ReserveHistory rhistory[len]; struct TALER_EXCHANGE_ReserveHistory rhistory[len];
if (GNUNET_OK != if (GNUNET_OK !=
parse_reserve_history (history, parse_reserve_history (wsh->exchange,
history,
&wsh->reserve_pub, &wsh->reserve_pub,
balance.currency, balance.currency,
&balance_from_history, &balance_from_history,

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014, 2015, 2016 GNUnet e.V. Copyright (C) 2014-2017 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software terms of the GNU Affero General Public License as published by the Free Software
@ -658,7 +658,17 @@ enum TALER_EXCHANGE_ReserveTransactionType {
/** /**
* Withdrawal from the reserve. * Withdrawal from the reserve.
*/ */
TALER_EXCHANGE_RTT_WITHDRAWAL TALER_EXCHANGE_RTT_WITHDRAWAL,
/**
* /payback operation.
*/
TALER_EXCHANGE_RTT_PAYBACK,
/**
* Reserve closed operation.
*/
TALER_EXCHANGE_RTT_CLOSE
}; };
@ -684,6 +694,10 @@ struct TALER_EXCHANGE_ReserveHistory
*/ */
union { union {
/**
* Information about a deposit that filled this reserve.
* @e type is #TALER_EXCHANGE_RTT_DEPOSIT.
*/
struct { struct {
/** /**
* Sender account information for the incoming transfer. * Sender account information for the incoming transfer.
@ -695,14 +709,60 @@ struct TALER_EXCHANGE_ReserveHistory
*/ */
json_t *transfer_details; json_t *transfer_details;
} in_details; } in_details;
/** /**
* Signature authorizing the withdrawal for outgoing transaction. * Signature authorizing the withdrawal for outgoing transaction.
* @e type is #TALER_EXCHANGE_RTT_WITHDRAWAL.
*/ */
json_t *out_authorization_sig; json_t *out_authorization_sig;
/**
* Information provided if the reserve was filled via /payback.
* @e type is #TALER_EXCHANGE_RTT_PAYBACK.
*/
struct {
/**
* Public key of the coin that was paid back.
*/
struct TALER_CoinSpendPublicKeyP coin_pub;
/**
* Signature of the coin of type
* #TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK.
*/
struct TALER_ExchangeSignatureP exchange_sig;
/**
* Public key of the exchange that was used for @e exchange_sig.
*/
struct TALER_ExchangePublicKeyP exchange_pub;
/**
* When did the /payback operation happen?
*/
struct GNUNET_TIME_Absolute timestamp;
} payback_details;
/**
* Information about a close operation of the reserve.
* @e type is #TALER_EXCHANGE_RTT_CLOSE.
*/
struct {
/**
* Receiver account information for the outgoing wire transfer.
*/
json_t *receiver_account_details;
/**
* Wire transfer details for the outgoing wire transfer.
*/
json_t *transfer_details;
} close_details;
} details; } details;
}; };

View File

@ -537,8 +537,8 @@ struct TALER_EXCHANGEDB_LinkDataList
* @brief Enumeration to classify the different types of transactions * @brief Enumeration to classify the different types of transactions
* that can be done with a coin. * that can be done with a coin.
*/ */
enum TALER_EXCHANGEDB_TransactionType enum TALER_EXCHANGEDB_TransactionType {
{
/** /**
* /deposit operation. * /deposit operation.
*/ */