support REFUNDS in transaction history in libtalerexchange
This commit is contained in:
parent
fbbc49bdad
commit
302070b86e
@ -40,10 +40,12 @@ int
|
|||||||
TALER_EXCHANGE_verify_coin_history (const char *currency,
|
TALER_EXCHANGE_verify_coin_history (const char *currency,
|
||||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||||
json_t *history,
|
json_t *history,
|
||||||
struct TALER_Amount *total)
|
struct TALER_Amount *total)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
size_t off;
|
size_t off;
|
||||||
|
int add;
|
||||||
|
struct TALER_Amount rtotal;
|
||||||
|
|
||||||
if (NULL == history)
|
if (NULL == history)
|
||||||
{
|
{
|
||||||
@ -58,6 +60,8 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
|
|||||||
}
|
}
|
||||||
TALER_amount_get_zero (currency,
|
TALER_amount_get_zero (currency,
|
||||||
total);
|
total);
|
||||||
|
TALER_amount_get_zero (currency,
|
||||||
|
&rtotal);
|
||||||
for (off=0;off<len;off++)
|
for (off=0;off<len;off++)
|
||||||
{
|
{
|
||||||
json_t *transaction;
|
json_t *transaction;
|
||||||
@ -89,6 +93,7 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
|
|||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
|
add = GNUNET_SYSERR;
|
||||||
if (0 == strcasecmp (type,
|
if (0 == strcasecmp (type,
|
||||||
"DEPOSIT"))
|
"DEPOSIT"))
|
||||||
{
|
{
|
||||||
@ -123,11 +128,12 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
|
|||||||
&dr->amount_with_fee);
|
&dr->amount_with_fee);
|
||||||
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);
|
GNUNET_JSON_parse_free (spec);
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
|
add = GNUNET_YES;
|
||||||
}
|
}
|
||||||
else if (0 == strcasecmp (type,
|
else if (0 == strcasecmp (type,
|
||||||
"MELT"))
|
"MELT"))
|
||||||
@ -167,6 +173,67 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
|
|||||||
GNUNET_JSON_parse_free (spec);
|
GNUNET_JSON_parse_free (spec);
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
|
add = GNUNET_YES;
|
||||||
|
}
|
||||||
|
else if (0 == strcasecmp (type,
|
||||||
|
"REFUND"))
|
||||||
|
{
|
||||||
|
const struct TALER_RefundRequestPS *rr;
|
||||||
|
struct TALER_Amount rr_amount;
|
||||||
|
struct TALER_Amount rr_fee;
|
||||||
|
struct TALER_Amount rr_delta;
|
||||||
|
|
||||||
|
if (details_size != sizeof (struct TALER_RefundRequestPS))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
GNUNET_JSON_parse_free (spec);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
rr = (const struct TALER_RefundRequestPS *) details;
|
||||||
|
if (details_size != ntohl (rr->purpose.size))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
GNUNET_JSON_parse_free (spec);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
|
||||||
|
&rr->purpose,
|
||||||
|
&sig.eddsa_signature,
|
||||||
|
&rr->merchant.eddsa_pub))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
GNUNET_JSON_parse_free (spec);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
TALER_amount_ntoh (&rr_amount,
|
||||||
|
&rr->refund_amount);
|
||||||
|
TALER_amount_ntoh (&rr_fee,
|
||||||
|
&rr->refund_fee);
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_amount_subtract (&rr_delta,
|
||||||
|
&rr_amount,
|
||||||
|
&rr_fee))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
GNUNET_JSON_parse_free (spec);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
if (0 != TALER_amount_cmp (&rr_delta,
|
||||||
|
&amount))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
GNUNET_JSON_parse_free (spec);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
/* NOTE/FIXME: theoretically, we could also check that the given
|
||||||
|
transaction_id and merchant_pub and h_contract appear in the
|
||||||
|
history under deposits. However, there is really no benefit
|
||||||
|
for the exchange to lie here, so not checking is probably OK
|
||||||
|
(an auditor ought to check, though). Then again, we similarly
|
||||||
|
had no reason to check the merchant's signature (other than a
|
||||||
|
well-formendess check). */
|
||||||
|
add = GNUNET_NO;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -175,18 +242,54 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
|
|||||||
GNUNET_JSON_parse_free (spec);
|
GNUNET_JSON_parse_free (spec);
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_YES == add)
|
||||||
TALER_amount_add (total,
|
|
||||||
total,
|
|
||||||
&amount))
|
|
||||||
{
|
{
|
||||||
/* overflow in history already!? inconceivable! Bad exchange! */
|
/* This amount should be added to the total */
|
||||||
GNUNET_break_op (0);
|
if (GNUNET_OK !=
|
||||||
GNUNET_JSON_parse_free (spec);
|
TALER_amount_add (total,
|
||||||
return GNUNET_SYSERR;
|
total,
|
||||||
|
&amount))
|
||||||
|
{
|
||||||
|
/* overflow in history already!? inconceivable! Bad exchange! */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
GNUNET_JSON_parse_free (spec);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* This amount should be subtracted from the total.
|
||||||
|
|
||||||
|
However, for the implementation, we first *add* up all of
|
||||||
|
these negative amounts, as we might get refunds before
|
||||||
|
deposits from a semi-evil exchange. Then, at the end, we do
|
||||||
|
the subtraction by calculating "total = total - rtotal" */
|
||||||
|
GNUNET_assert (GNUNET_NO == add);
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_amount_add (&rtotal,
|
||||||
|
&rtotal,
|
||||||
|
&amount))
|
||||||
|
{
|
||||||
|
/* overflow in refund history? inconceivable! Bad exchange! */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
GNUNET_JSON_parse_free (spec);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GNUNET_JSON_parse_free (spec);
|
GNUNET_JSON_parse_free (spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Finally, subtract 'rtotal' from total to handle the subtractions */
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_amount_subtract (total,
|
||||||
|
total,
|
||||||
|
&rtotal))
|
||||||
|
{
|
||||||
|
/* underflow in history? inconceivable! Bad exchange! */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
|
||||||
return GNUNET_OK;
|
return GNUNET_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,7 +408,7 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
|
|||||||
const char *type;
|
const char *type;
|
||||||
struct TALER_Amount value;
|
struct TALER_Amount value;
|
||||||
json_t *history;
|
json_t *history;
|
||||||
const struct TALER_CoinSpendSignatureP *sig;
|
const struct GNUNET_CRYPTO_EddsaSignature *sig;
|
||||||
const struct TALER_EXCHANGEDB_TransactionList *pos;
|
const struct TALER_EXCHANGEDB_TransactionList *pos;
|
||||||
|
|
||||||
history = json_array ();
|
history = json_array ();
|
||||||
@ -436,12 +436,12 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
|
|||||||
&deposit->deposit_fee);
|
&deposit->deposit_fee);
|
||||||
dr.merchant = deposit->merchant_pub;
|
dr.merchant = deposit->merchant_pub;
|
||||||
dr.coin_pub = deposit->coin.coin_pub;
|
dr.coin_pub = deposit->coin.coin_pub;
|
||||||
sig = &deposit->csig;
|
sig = &deposit->csig.eddsa_signature;
|
||||||
/* internal sanity check before we hand out a bogus sig... */
|
/* internal sanity check before we hand out a bogus sig... */
|
||||||
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,
|
||||||
&deposit->coin.coin_pub.eddsa_pub))
|
&deposit->coin.coin_pub.eddsa_pub))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -468,12 +468,12 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
|
|||||||
TALER_amount_hton (&ms.melt_fee,
|
TALER_amount_hton (&ms.melt_fee,
|
||||||
&melt->melt_fee);
|
&melt->melt_fee);
|
||||||
ms.coin_pub = melt->coin.coin_pub;
|
ms.coin_pub = melt->coin.coin_pub;
|
||||||
sig = &melt->coin_sig;
|
sig = &melt->coin_sig.eddsa_signature;
|
||||||
/* internal sanity check before we hand out a bogus sig... */
|
/* internal sanity check before we hand out a bogus sig... */
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
|
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
|
||||||
&ms.purpose,
|
&ms.purpose,
|
||||||
&sig->eddsa_signature,
|
sig,
|
||||||
&melt->coin.coin_pub.eddsa_pub))
|
&melt->coin.coin_pub.eddsa_pub))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -485,6 +485,48 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
|
|||||||
sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
|
sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TALER_EXCHANGEDB_TT_REFUND:
|
||||||
|
{
|
||||||
|
struct TALER_RefundRequestPS rr;
|
||||||
|
const struct TALER_EXCHANGEDB_Refund *refund = pos->details.refund;
|
||||||
|
|
||||||
|
type = "REFUND";
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_amount_subtract (&value,
|
||||||
|
&refund->refund_amount,
|
||||||
|
&refund->refund_fee))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
json_decref (history);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND);
|
||||||
|
rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS));
|
||||||
|
rr.h_contract = refund->h_contract;
|
||||||
|
rr.transaction_id = GNUNET_htonll (refund->transaction_id);
|
||||||
|
rr.coin_pub = refund->coin.coin_pub;
|
||||||
|
rr.merchant = refund->merchant_pub;
|
||||||
|
rr.rtransaction_id = GNUNET_htonll (refund->rtransaction_id);
|
||||||
|
TALER_amount_hton (&rr.refund_amount,
|
||||||
|
&refund->refund_amount);
|
||||||
|
TALER_amount_hton (&rr.refund_fee,
|
||||||
|
&refund->refund_fee);
|
||||||
|
/* internal sanity check before we hand out a bogus sig... */
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
|
||||||
|
&rr.purpose,
|
||||||
|
sig,
|
||||||
|
&refund->merchant_pub.eddsa_pub))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
json_decref (history);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sig = &refund->merchant_sig.eddsa_sig;
|
||||||
|
details = GNUNET_JSON_from_data (&rr.purpose,
|
||||||
|
sizeof (struct TALER_RefundRequestPS));
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
GNUNET_assert (0);
|
GNUNET_assert (0);
|
||||||
}
|
}
|
||||||
@ -493,7 +535,7 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
|
|||||||
"type", type,
|
"type", type,
|
||||||
"amount", TALER_JSON_from_amount (&value),
|
"amount", TALER_JSON_from_amount (&value),
|
||||||
"signature", GNUNET_JSON_from_data (sig,
|
"signature", GNUNET_JSON_from_data (sig,
|
||||||
sizeof (struct TALER_CoinSpendSignatureP)),
|
sizeof (struct GNUNET_CRYPTO_EddsaSignature)),
|
||||||
"details", details));
|
"details", details));
|
||||||
}
|
}
|
||||||
return history;
|
return history;
|
||||||
|
Loading…
Reference in New Issue
Block a user