complete P2P/W2W conflict handling, deduplicate code across handlers
This commit is contained in:
parent
6c81796d6f
commit
b9963f7525
@ -456,6 +456,21 @@ parse_planchets (const struct TEH_RequestContext *rc,
|
|||||||
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
|
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
|
||||||
}
|
}
|
||||||
pc->collectable.reserve_pub = *wc->reserve_pub;
|
pc->collectable.reserve_pub = *wc->reserve_pub;
|
||||||
|
for (unsigned int k = 0; k<i; k++)
|
||||||
|
{
|
||||||
|
const struct PlanchetContext *kpc = &wc->planchets[k];
|
||||||
|
|
||||||
|
if (0 ==
|
||||||
|
TALER_blinded_planchet_cmp (&kpc->blinded_planchet,
|
||||||
|
&pc->blinded_planchet))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return TALER_MHD_reply_with_error (rc->connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
TALER_EC_GENERIC_PARAMETER_MALFORMED,
|
||||||
|
"duplicate planchet");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ksh = TEH_keys_get_state ();
|
ksh = TEH_keys_get_state ();
|
||||||
|
@ -61,15 +61,19 @@ TEH_make_coin_known (const struct TALER_CoinPublicInfo *coin,
|
|||||||
NULL);
|
NULL);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
case TALER_EXCHANGEDB_CKS_DENOM_CONFLICT:
|
case TALER_EXCHANGEDB_CKS_DENOM_CONFLICT:
|
||||||
|
/* FIXME-Oec: insufficient_funds != denom conflict! */
|
||||||
*mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
|
*mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||||
connection,
|
connection,
|
||||||
TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY,
|
TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY,
|
||||||
|
&h_denom_pub,
|
||||||
&coin->coin_pub);
|
&coin->coin_pub);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
case TALER_EXCHANGEDB_CKS_AGE_CONFLICT:
|
case TALER_EXCHANGEDB_CKS_AGE_CONFLICT:
|
||||||
|
/* FIXME-Oec: insufficient_funds != Age conflict! */
|
||||||
*mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
|
*mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||||
connection,
|
connection,
|
||||||
TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH,
|
TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH,
|
||||||
|
&h_denom_pub,
|
||||||
&coin->coin_pub);
|
&coin->coin_pub);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of TALER
|
||||||
Copyright (C) 2014-2021 Taler Systems SA
|
Copyright (C) 2014-2022 Taler Systems SA
|
||||||
|
|
||||||
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
|
||||||
@ -178,10 +178,12 @@ deposit_transaction (void *cls,
|
|||||||
}
|
}
|
||||||
if (in_conflict)
|
if (in_conflict)
|
||||||
{
|
{
|
||||||
|
/* FIXME: conficting contract != insufficient funds */
|
||||||
*mhd_ret
|
*mhd_ret
|
||||||
= TEH_RESPONSE_reply_coin_insufficient_funds (
|
= TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||||
connection,
|
connection,
|
||||||
TALER_EC_EXCHANGE_DEPOSIT_CONFLICTING_CONTRACT,
|
TALER_EC_EXCHANGE_DEPOSIT_CONFLICTING_CONTRACT,
|
||||||
|
&dc->deposit->coin.denom_pub_hash,
|
||||||
&dc->deposit->coin.coin_pub);
|
&dc->deposit->coin.coin_pub);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
@ -191,6 +193,7 @@ deposit_transaction (void *cls,
|
|||||||
= TEH_RESPONSE_reply_coin_insufficient_funds (
|
= TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||||
connection,
|
connection,
|
||||||
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
|
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
|
||||||
|
&dc->deposit->coin.denom_pub_hash,
|
||||||
&dc->deposit->coin.coin_pub);
|
&dc->deposit->coin.coin_pub);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -196,6 +196,7 @@ melt_transaction (void *cls,
|
|||||||
= TEH_RESPONSE_reply_coin_insufficient_funds (
|
= TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||||
connection,
|
connection,
|
||||||
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
|
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
|
||||||
|
&rmc->refresh_session.coin.denom_pub_hash,
|
||||||
&rmc->refresh_session.coin.coin_pub);
|
&rmc->refresh_session.coin.coin_pub);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -319,6 +319,7 @@ create_transaction (void *cls,
|
|||||||
= TEH_RESPONSE_reply_coin_insufficient_funds (
|
= TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||||
connection,
|
connection,
|
||||||
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
|
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
|
||||||
|
&coin->cpi.denom_pub_hash,
|
||||||
&coin->cpi.coin_pub);
|
&coin->cpi.coin_pub);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -229,6 +229,7 @@ deposit_transaction (void *cls,
|
|||||||
= TEH_RESPONSE_reply_coin_insufficient_funds (
|
= TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||||
connection,
|
connection,
|
||||||
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
|
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
|
||||||
|
&coin->cpi.denom_pub_hash,
|
||||||
&coin->cpi.coin_pub);
|
&coin->cpi.coin_pub);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -325,14 +325,13 @@ merge_transaction (void *cls,
|
|||||||
GNUNET_JSON_pack_data_auto ("merge_sig",
|
GNUNET_JSON_pack_data_auto ("merge_sig",
|
||||||
&merge_sig),
|
&merge_sig),
|
||||||
GNUNET_JSON_pack_allow_null (
|
GNUNET_JSON_pack_allow_null (
|
||||||
GNUNET_JSON_pack_string ("partner_base_url",
|
GNUNET_JSON_pack_string ("partner_url",
|
||||||
partner_url)),
|
partner_url)),
|
||||||
GNUNET_JSON_pack_data_auto ("reserve_pub",
|
GNUNET_JSON_pack_data_auto ("reserve_pub",
|
||||||
&reserve_pub));
|
&reserve_pub));
|
||||||
GNUNET_free (partner_url);
|
GNUNET_free (partner_url);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
// FIXME: if ! kyc check, return 451!
|
|
||||||
return qs;
|
return qs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +146,7 @@ recoup_refresh_transaction (void *cls,
|
|||||||
*mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
|
*mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||||
connection,
|
connection,
|
||||||
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
|
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
|
||||||
|
&pc->coin->denom_pub_hash,
|
||||||
&pc->coin->coin_pub);
|
&pc->coin->coin_pub);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -149,6 +149,7 @@ recoup_transaction (void *cls,
|
|||||||
*mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
|
*mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||||
connection,
|
connection,
|
||||||
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
|
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
|
||||||
|
&pc->coin->denom_pub_hash,
|
||||||
&pc->coin->coin_pub);
|
&pc->coin->coin_pub);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -158,10 +158,10 @@ refund_transaction (void *cls,
|
|||||||
}
|
}
|
||||||
if (conflict)
|
if (conflict)
|
||||||
{
|
{
|
||||||
TEH_plugin->rollback (TEH_plugin->cls);
|
|
||||||
*mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
|
*mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||||
connection,
|
connection,
|
||||||
TALER_EC_EXCHANGE_REFUND_INCONSISTENT_AMOUNT,
|
TALER_EC_EXCHANGE_REFUND_INCONSISTENT_AMOUNT,
|
||||||
|
&refund->coin.denom_pub_hash,
|
||||||
&refund->coin.coin_pub);
|
&refund->coin.coin_pub);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
@ -175,10 +175,10 @@ refund_transaction (void *cls,
|
|||||||
}
|
}
|
||||||
if (! refund_ok)
|
if (! refund_ok)
|
||||||
{
|
{
|
||||||
TEH_plugin->rollback (TEH_plugin->cls);
|
|
||||||
*mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
|
*mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||||
connection,
|
connection,
|
||||||
TALER_EC_EXCHANGE_REFUND_CONFLICT_DEPOSIT_INSUFFICIENT,
|
TALER_EC_EXCHANGE_REFUND_CONFLICT_DEPOSIT_INSUFFICIENT,
|
||||||
|
&refund->coin.denom_pub_hash,
|
||||||
&refund->coin.coin_pub);
|
&refund->coin.coin_pub);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
@ -200,7 +200,6 @@ static MHD_RESULT
|
|||||||
verify_and_execute_refund (struct MHD_Connection *connection,
|
verify_and_execute_refund (struct MHD_Connection *connection,
|
||||||
struct TALER_EXCHANGEDB_Refund *refund)
|
struct TALER_EXCHANGEDB_Refund *refund)
|
||||||
{
|
{
|
||||||
struct TALER_DenominationHashP denom_hash;
|
|
||||||
struct RefundContext rctx = {
|
struct RefundContext rctx = {
|
||||||
.refund = refund
|
.refund = refund
|
||||||
};
|
};
|
||||||
@ -228,15 +227,16 @@ verify_and_execute_refund (struct MHD_Connection *connection,
|
|||||||
qs = TEH_plugin->get_coin_denomination (TEH_plugin->cls,
|
qs = TEH_plugin->get_coin_denomination (TEH_plugin->cls,
|
||||||
&refund->coin.coin_pub,
|
&refund->coin.coin_pub,
|
||||||
&rctx.known_coin_id,
|
&rctx.known_coin_id,
|
||||||
&denom_hash);
|
&refund->coin.denom_pub_hash);
|
||||||
if (0 > qs)
|
if (0 > qs)
|
||||||
{
|
{
|
||||||
MHD_RESULT res;
|
MHD_RESULT res;
|
||||||
char *dhs;
|
char *dhs;
|
||||||
|
|
||||||
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
|
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
|
||||||
dhs = GNUNET_STRINGS_data_to_string_alloc (&denom_hash,
|
dhs = GNUNET_STRINGS_data_to_string_alloc (
|
||||||
sizeof (denom_hash));
|
&refund->coin.denom_pub_hash,
|
||||||
|
sizeof (refund->coin.denom_pub_hash));
|
||||||
res = TALER_MHD_reply_with_error (connection,
|
res = TALER_MHD_reply_with_error (connection,
|
||||||
MHD_HTTP_NOT_FOUND,
|
MHD_HTTP_NOT_FOUND,
|
||||||
TALER_EC_EXCHANGE_REFUND_COIN_NOT_FOUND,
|
TALER_EC_EXCHANGE_REFUND_COIN_NOT_FOUND,
|
||||||
@ -251,7 +251,7 @@ verify_and_execute_refund (struct MHD_Connection *connection,
|
|||||||
struct TEH_DenominationKey *dk;
|
struct TEH_DenominationKey *dk;
|
||||||
MHD_RESULT mret;
|
MHD_RESULT mret;
|
||||||
|
|
||||||
dk = TEH_keys_denomination_by_hash (&denom_hash,
|
dk = TEH_keys_denomination_by_hash (&refund->coin.denom_pub_hash,
|
||||||
connection,
|
connection,
|
||||||
&mret);
|
&mret);
|
||||||
if (NULL == dk)
|
if (NULL == dk)
|
||||||
|
@ -70,18 +70,19 @@ TEH_RESPONSE_compile_transaction_history (
|
|||||||
/* internal sanity check before we hand out a bogus sig... */
|
/* internal sanity check before we hand out a bogus sig... */
|
||||||
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
|
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_wallet_deposit_verify (&deposit->amount_with_fee,
|
TALER_wallet_deposit_verify (
|
||||||
&deposit->deposit_fee,
|
&deposit->amount_with_fee,
|
||||||
&h_wire,
|
&deposit->deposit_fee,
|
||||||
&deposit->h_contract_terms,
|
&h_wire,
|
||||||
&deposit->h_age_commitment,
|
&deposit->h_contract_terms,
|
||||||
NULL /* h_extensions! */,
|
&deposit->h_age_commitment,
|
||||||
&deposit->h_denom_pub,
|
NULL /* h_extensions! */,
|
||||||
deposit->timestamp,
|
&deposit->h_denom_pub,
|
||||||
&deposit->merchant_pub,
|
deposit->timestamp,
|
||||||
deposit->refund_deadline,
|
&deposit->merchant_pub,
|
||||||
coin_pub,
|
deposit->refund_deadline,
|
||||||
&deposit->csig))
|
coin_pub,
|
||||||
|
&deposit->csig))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
json_decref (history);
|
json_decref (history);
|
||||||
@ -109,8 +110,6 @@ TEH_RESPONSE_compile_transaction_history (
|
|||||||
&deposit->h_contract_terms),
|
&deposit->h_contract_terms),
|
||||||
GNUNET_JSON_pack_data_auto ("h_wire",
|
GNUNET_JSON_pack_data_auto ("h_wire",
|
||||||
&h_wire),
|
&h_wire),
|
||||||
GNUNET_JSON_pack_data_auto ("h_denom_pub",
|
|
||||||
&deposit->h_denom_pub),
|
|
||||||
GNUNET_JSON_pack_allow_null (
|
GNUNET_JSON_pack_allow_null (
|
||||||
deposit->no_age_commitment ?
|
deposit->no_age_commitment ?
|
||||||
GNUNET_JSON_pack_string (
|
GNUNET_JSON_pack_string (
|
||||||
@ -135,13 +134,14 @@ TEH_RESPONSE_compile_transaction_history (
|
|||||||
#if ENABLE_SANITY_CHECKS
|
#if ENABLE_SANITY_CHECKS
|
||||||
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
|
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_wallet_melt_verify (&melt->amount_with_fee,
|
TALER_wallet_melt_verify (
|
||||||
&melt->melt_fee,
|
&melt->amount_with_fee,
|
||||||
&melt->rc,
|
&melt->melt_fee,
|
||||||
&melt->h_denom_pub,
|
&melt->rc,
|
||||||
&melt->h_age_commitment,
|
&melt->h_denom_pub,
|
||||||
coin_pub,
|
&melt->h_age_commitment,
|
||||||
&melt->coin_sig))
|
coin_pub,
|
||||||
|
&melt->coin_sig))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
json_decref (history);
|
json_decref (history);
|
||||||
@ -166,8 +166,6 @@ TEH_RESPONSE_compile_transaction_history (
|
|||||||
&melt->melt_fee),
|
&melt->melt_fee),
|
||||||
GNUNET_JSON_pack_data_auto ("rc",
|
GNUNET_JSON_pack_data_auto ("rc",
|
||||||
&melt->rc),
|
&melt->rc),
|
||||||
GNUNET_JSON_pack_data_auto ("h_denom_pub",
|
|
||||||
&melt->h_denom_pub),
|
|
||||||
GNUNET_JSON_pack_allow_null (
|
GNUNET_JSON_pack_allow_null (
|
||||||
GNUNET_JSON_pack_data_auto ("h_age_commitment",
|
GNUNET_JSON_pack_data_auto ("h_age_commitment",
|
||||||
phac)),
|
phac)),
|
||||||
@ -189,12 +187,13 @@ TEH_RESPONSE_compile_transaction_history (
|
|||||||
#if ENABLE_SANITY_CHECKS
|
#if ENABLE_SANITY_CHECKS
|
||||||
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
|
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_merchant_refund_verify (coin_pub,
|
TALER_merchant_refund_verify (
|
||||||
&refund->h_contract_terms,
|
coin_pub,
|
||||||
refund->rtransaction_id,
|
&refund->h_contract_terms,
|
||||||
&refund->refund_amount,
|
refund->rtransaction_id,
|
||||||
&refund->merchant_pub,
|
&refund->refund_amount,
|
||||||
&refund->merchant_sig))
|
&refund->merchant_pub,
|
||||||
|
&refund->merchant_sig))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
json_decref (history);
|
json_decref (history);
|
||||||
@ -319,8 +318,6 @@ TEH_RESPONSE_compile_transaction_history (
|
|||||||
&epub),
|
&epub),
|
||||||
GNUNET_JSON_pack_data_auto ("reserve_pub",
|
GNUNET_JSON_pack_data_auto ("reserve_pub",
|
||||||
&recoup->reserve_pub),
|
&recoup->reserve_pub),
|
||||||
GNUNET_JSON_pack_data_auto ("h_denom_pub",
|
|
||||||
&recoup->h_denom_pub),
|
|
||||||
GNUNET_JSON_pack_data_auto ("coin_sig",
|
GNUNET_JSON_pack_data_auto ("coin_sig",
|
||||||
&recoup->coin_sig),
|
&recoup->coin_sig),
|
||||||
GNUNET_JSON_pack_data_auto ("coin_blind",
|
GNUNET_JSON_pack_data_auto ("coin_blind",
|
||||||
@ -376,8 +373,6 @@ TEH_RESPONSE_compile_transaction_history (
|
|||||||
&epub),
|
&epub),
|
||||||
GNUNET_JSON_pack_data_auto ("old_coin_pub",
|
GNUNET_JSON_pack_data_auto ("old_coin_pub",
|
||||||
&pr->old_coin_pub),
|
&pr->old_coin_pub),
|
||||||
GNUNET_JSON_pack_data_auto ("h_denom_pub",
|
|
||||||
&pr->coin.denom_pub_hash),
|
|
||||||
GNUNET_JSON_pack_data_auto ("coin_sig",
|
GNUNET_JSON_pack_data_auto ("coin_sig",
|
||||||
&pr->coin_sig),
|
&pr->coin_sig),
|
||||||
GNUNET_JSON_pack_data_auto ("coin_blind",
|
GNUNET_JSON_pack_data_auto ("coin_blind",
|
||||||
@ -558,18 +553,31 @@ MHD_RESULT
|
|||||||
TEH_RESPONSE_reply_coin_insufficient_funds (
|
TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||||
struct MHD_Connection *connection,
|
struct MHD_Connection *connection,
|
||||||
enum TALER_ErrorCode ec,
|
enum TALER_ErrorCode ec,
|
||||||
|
const struct TALER_DenominationHashP *h_denom_pub,
|
||||||
const struct TALER_CoinSpendPublicKeyP *coin_pub)
|
const struct TALER_CoinSpendPublicKeyP *coin_pub)
|
||||||
{
|
{
|
||||||
struct TALER_EXCHANGEDB_TransactionList *tl;
|
struct TALER_EXCHANGEDB_TransactionList *tl;
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
json_t *history;
|
json_t *history;
|
||||||
|
|
||||||
// FIXME: maybe start read-committed transaction here?
|
TEH_plugin->rollback (TEH_plugin->cls);
|
||||||
// => check all callers (that they aborted already!)
|
// FIXME: maybe start read-only transaction here?
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TEH_plugin->start_read_committed (TEH_plugin->cls,
|
||||||
|
"get_coin_transactions"))
|
||||||
|
{
|
||||||
|
return TALER_MHD_reply_with_error (
|
||||||
|
connection,
|
||||||
|
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||||
|
TALER_EC_GENERIC_DB_START_FAILED,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
// FIXME: simplify, 3rd arg is always 'true' now?
|
||||||
qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
|
qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
|
||||||
coin_pub,
|
coin_pub,
|
||||||
GNUNET_NO,
|
true,
|
||||||
&tl);
|
&tl);
|
||||||
|
TEH_plugin->rollback (TEH_plugin->cls);
|
||||||
if (0 > qs)
|
if (0 > qs)
|
||||||
{
|
{
|
||||||
return TALER_MHD_reply_with_error (
|
return TALER_MHD_reply_with_error (
|
||||||
@ -597,6 +605,8 @@ TEH_RESPONSE_reply_coin_insufficient_funds (
|
|||||||
TALER_JSON_pack_ec (ec),
|
TALER_JSON_pack_ec (ec),
|
||||||
GNUNET_JSON_pack_data_auto ("coin_pub",
|
GNUNET_JSON_pack_data_auto ("coin_pub",
|
||||||
coin_pub),
|
coin_pub),
|
||||||
|
GNUNET_JSON_pack_data_auto ("h_denom_pub",
|
||||||
|
h_denom_pub),
|
||||||
GNUNET_JSON_pack_array_steal ("history",
|
GNUNET_JSON_pack_array_steal ("history",
|
||||||
history));
|
history));
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,7 @@ TEH_RESPONSE_reply_invalid_denom_cipher_for_operation (
|
|||||||
*
|
*
|
||||||
* @param connection connection to the client
|
* @param connection connection to the client
|
||||||
* @param ec error code to return
|
* @param ec error code to return
|
||||||
|
* @param h_denom_pub hash of the denomination of the coin
|
||||||
* @param coin_pub public key of the coin
|
* @param coin_pub public key of the coin
|
||||||
* @return MHD result code
|
* @return MHD result code
|
||||||
*/
|
*/
|
||||||
@ -120,6 +121,7 @@ MHD_RESULT
|
|||||||
TEH_RESPONSE_reply_coin_insufficient_funds (
|
TEH_RESPONSE_reply_coin_insufficient_funds (
|
||||||
struct MHD_Connection *connection,
|
struct MHD_Connection *connection,
|
||||||
enum TALER_ErrorCode ec,
|
enum TALER_ErrorCode ec,
|
||||||
|
const struct TALER_DenominationHashP *h_denom_pub,
|
||||||
const struct TALER_CoinSpendPublicKeyP *coin_pub);
|
const struct TALER_CoinSpendPublicKeyP *coin_pub);
|
||||||
|
|
||||||
|
|
||||||
|
@ -8403,7 +8403,6 @@ add_coin_melt (void *cls,
|
|||||||
chc->failed = true;
|
chc->failed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||||
tl->next = chc->head;
|
tl->next = chc->head;
|
||||||
@ -8704,7 +8703,7 @@ static enum GNUNET_DB_QueryStatus
|
|||||||
postgres_get_coin_transactions (
|
postgres_get_coin_transactions (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||||
int include_recoup,
|
bool include_recoup,
|
||||||
struct TALER_EXCHANGEDB_TransactionList **tlp)
|
struct TALER_EXCHANGEDB_TransactionList **tlp)
|
||||||
{
|
{
|
||||||
struct PostgresClosure *pg = cls;
|
struct PostgresClosure *pg = cls;
|
||||||
|
@ -2978,21 +2978,17 @@ TALER_EXCHANGE_deposits_get_cancel (
|
|||||||
* Convenience function. Verifies a coin's transaction history as
|
* Convenience function. Verifies a coin's transaction history as
|
||||||
* returned by the exchange.
|
* returned by the exchange.
|
||||||
*
|
*
|
||||||
* @param dk fee structure for the coin, NULL to skip verifying fees
|
* @param dk fee structure for the coin
|
||||||
* @param currency expected currency for the coin
|
|
||||||
* @param coin_pub public key of the coin
|
* @param coin_pub public key of the coin
|
||||||
* @param history history of the coin in json encoding
|
* @param history history of the coin in json encoding
|
||||||
* @param[out] h_denom_pub set to the hash of the coin's denomination (if available)
|
|
||||||
* @param[out] total how much of the coin has been spent according to @a history
|
* @param[out] total how much of the coin has been spent according to @a history
|
||||||
* @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not
|
* @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not
|
||||||
*/
|
*/
|
||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_EXCHANGE_verify_coin_history (
|
TALER_EXCHANGE_verify_coin_history (
|
||||||
const struct TALER_EXCHANGE_DenomPublicKey *dk,
|
const struct TALER_EXCHANGE_DenomPublicKey *dk,
|
||||||
const char *currency,
|
|
||||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||||
json_t *history,
|
json_t *history,
|
||||||
struct TALER_DenominationHashP *h_denom_pub,
|
|
||||||
struct TALER_Amount *total);
|
struct TALER_Amount *total);
|
||||||
|
|
||||||
|
|
||||||
|
@ -3620,7 +3620,7 @@ struct TALER_EXCHANGEDB_Plugin
|
|||||||
enum GNUNET_DB_QueryStatus
|
enum GNUNET_DB_QueryStatus
|
||||||
(*get_coin_transactions)(void *cls,
|
(*get_coin_transactions)(void *cls,
|
||||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||||
int include_recoup,
|
bool include_recoup,
|
||||||
struct TALER_EXCHANGEDB_TransactionList **tlp);
|
struct TALER_EXCHANGEDB_TransactionList **tlp);
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "taler_json_lib.h"
|
#include "taler_json_lib.h"
|
||||||
#include <gnunet/gnunet_curl_lib.h>
|
#include <gnunet/gnunet_curl_lib.h>
|
||||||
|
#include "exchange_api_common.h"
|
||||||
#include "exchange_api_handle.h"
|
#include "exchange_api_handle.h"
|
||||||
#include "taler_signatures.h"
|
#include "taler_signatures.h"
|
||||||
|
|
||||||
@ -684,11 +685,6 @@ struct CoinHistoryParseContext
|
|||||||
*/
|
*/
|
||||||
const struct TALER_CoinSpendPublicKeyP *coin_pub;
|
const struct TALER_CoinSpendPublicKeyP *coin_pub;
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash of @e dk, set from parsing.
|
|
||||||
*/
|
|
||||||
struct TALER_DenominationHashP *h_denom_pub;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Where to sum up total refunds.
|
* Where to sum up total refunds.
|
||||||
*/
|
*/
|
||||||
@ -749,8 +745,6 @@ help_deposit (struct CoinHistoryParseContext *pc,
|
|||||||
&h_contract_terms),
|
&h_contract_terms),
|
||||||
GNUNET_JSON_spec_fixed_auto ("h_wire",
|
GNUNET_JSON_spec_fixed_auto ("h_wire",
|
||||||
&h_wire),
|
&h_wire),
|
||||||
GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
|
|
||||||
pc->h_denom_pub),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
GNUNET_JSON_spec_mark_optional (
|
||||||
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
|
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
|
||||||
&hac),
|
&hac),
|
||||||
@ -784,7 +778,7 @@ help_deposit (struct CoinHistoryParseContext *pc,
|
|||||||
&h_contract_terms,
|
&h_contract_terms,
|
||||||
no_hac ? NULL : &hac,
|
no_hac ? NULL : &hac,
|
||||||
NULL /* h_extensions! */,
|
NULL /* h_extensions! */,
|
||||||
pc->h_denom_pub,
|
&pc->dk->h_key,
|
||||||
wallet_timestamp,
|
wallet_timestamp,
|
||||||
&merchant_pub,
|
&merchant_pub,
|
||||||
refund_deadline,
|
refund_deadline,
|
||||||
@ -836,8 +830,6 @@ help_melt (struct CoinHistoryParseContext *pc,
|
|||||||
&sig),
|
&sig),
|
||||||
GNUNET_JSON_spec_fixed_auto ("rc",
|
GNUNET_JSON_spec_fixed_auto ("rc",
|
||||||
&rc),
|
&rc),
|
||||||
GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
|
|
||||||
pc->h_denom_pub),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
GNUNET_JSON_spec_mark_optional (
|
||||||
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
|
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
|
||||||
&h_age_commitment),
|
&h_age_commitment),
|
||||||
@ -876,7 +868,7 @@ help_melt (struct CoinHistoryParseContext *pc,
|
|||||||
amount,
|
amount,
|
||||||
&melt_fee,
|
&melt_fee,
|
||||||
&rc,
|
&rc,
|
||||||
pc->h_denom_pub,
|
&pc->dk->h_key,
|
||||||
no_hac
|
no_hac
|
||||||
? NULL
|
? NULL
|
||||||
: &h_age_commitment,
|
: &h_age_commitment,
|
||||||
@ -1008,8 +1000,6 @@ help_recoup (struct CoinHistoryParseContext *pc,
|
|||||||
&coin_sig),
|
&coin_sig),
|
||||||
GNUNET_JSON_spec_fixed_auto ("coin_blind",
|
GNUNET_JSON_spec_fixed_auto ("coin_blind",
|
||||||
&coin_bks),
|
&coin_bks),
|
||||||
GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
|
|
||||||
pc->h_denom_pub),
|
|
||||||
GNUNET_JSON_spec_timestamp ("timestamp",
|
GNUNET_JSON_spec_timestamp ("timestamp",
|
||||||
×tamp),
|
×tamp),
|
||||||
GNUNET_JSON_spec_end ()
|
GNUNET_JSON_spec_end ()
|
||||||
@ -1036,7 +1026,7 @@ help_recoup (struct CoinHistoryParseContext *pc,
|
|||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_wallet_recoup_verify (pc->h_denom_pub,
|
TALER_wallet_recoup_verify (&pc->dk->h_key,
|
||||||
&coin_bks,
|
&coin_bks,
|
||||||
pc->coin_pub,
|
pc->coin_pub,
|
||||||
&coin_sig))
|
&coin_sig))
|
||||||
@ -1081,8 +1071,6 @@ help_recoup_refresh (struct CoinHistoryParseContext *pc,
|
|||||||
&old_coin_pub),
|
&old_coin_pub),
|
||||||
GNUNET_JSON_spec_fixed_auto ("coin_blind",
|
GNUNET_JSON_spec_fixed_auto ("coin_blind",
|
||||||
&coin_bks),
|
&coin_bks),
|
||||||
GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
|
|
||||||
pc->h_denom_pub),
|
|
||||||
GNUNET_JSON_spec_timestamp ("timestamp",
|
GNUNET_JSON_spec_timestamp ("timestamp",
|
||||||
×tamp),
|
×tamp),
|
||||||
GNUNET_JSON_spec_end ()
|
GNUNET_JSON_spec_end ()
|
||||||
@ -1109,7 +1097,7 @@ help_recoup_refresh (struct CoinHistoryParseContext *pc,
|
|||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_wallet_recoup_verify (pc->h_denom_pub,
|
TALER_wallet_recoup_verify (&pc->dk->h_key,
|
||||||
&coin_bks,
|
&coin_bks,
|
||||||
pc->coin_pub,
|
pc->coin_pub,
|
||||||
&coin_sig))
|
&coin_sig))
|
||||||
@ -1250,12 +1238,11 @@ help_purse_deposit (struct CoinHistoryParseContext *pc,
|
|||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_EXCHANGE_verify_coin_history (
|
TALER_EXCHANGE_verify_coin_history (
|
||||||
const struct TALER_EXCHANGE_DenomPublicKey *dk,
|
const struct TALER_EXCHANGE_DenomPublicKey *dk,
|
||||||
const char *currency,
|
|
||||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||||
json_t *history,
|
json_t *history,
|
||||||
struct TALER_DenominationHashP *h_denom_pub,
|
|
||||||
struct TALER_Amount *total)
|
struct TALER_Amount *total)
|
||||||
{
|
{
|
||||||
|
const char *currency = dk->value.currency;
|
||||||
const struct
|
const struct
|
||||||
{
|
{
|
||||||
const char *type;
|
const char *type;
|
||||||
@ -1273,8 +1260,7 @@ TALER_EXCHANGE_verify_coin_history (
|
|||||||
struct CoinHistoryParseContext pc = {
|
struct CoinHistoryParseContext pc = {
|
||||||
.dk = dk,
|
.dk = dk,
|
||||||
.coin_pub = coin_pub,
|
.coin_pub = coin_pub,
|
||||||
.total = total,
|
.total = total
|
||||||
.h_denom_pub = h_denom_pub
|
|
||||||
};
|
};
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
@ -1528,11 +1514,10 @@ TALER_EXCHANGE_check_purse_merge_conflict_ (
|
|||||||
{
|
{
|
||||||
struct TALER_PurseMergeSignatureP merge_sig;
|
struct TALER_PurseMergeSignatureP merge_sig;
|
||||||
struct GNUNET_TIME_Timestamp merge_timestamp;
|
struct GNUNET_TIME_Timestamp merge_timestamp;
|
||||||
const char *partner_url = exchange_url;
|
const char *partner_url = NULL;
|
||||||
struct TALER_ReservePublicKeyP reserve_pub;
|
struct TALER_ReservePublicKeyP reserve_pub;
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
GNUNET_JSON_spec_mark_optional (
|
GNUNET_JSON_spec_mark_optional (
|
||||||
// FIXME: partner_url or partner_base_url?
|
|
||||||
GNUNET_JSON_spec_string ("partner_url",
|
GNUNET_JSON_spec_string ("partner_url",
|
||||||
&partner_url),
|
&partner_url),
|
||||||
NULL),
|
NULL),
|
||||||
@ -1554,6 +1539,8 @@ TALER_EXCHANGE_check_purse_merge_conflict_ (
|
|||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
|
if (NULL == partner_url)
|
||||||
|
partner_url = exchange_url;
|
||||||
payto_uri = make_payto (partner_url,
|
payto_uri = make_payto (partner_url,
|
||||||
&reserve_pub);
|
&reserve_pub);
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
@ -1581,18 +1568,55 @@ TALER_EXCHANGE_check_purse_merge_conflict_ (
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
enum GNUNET_GenericReturnValue
|
||||||
* Check proof of a contract conflict.
|
TALER_EXCHANGE_check_purse_coin_conflict_ (
|
||||||
*
|
const struct TALER_PurseContractPublicKeyP *purse_pub,
|
||||||
* DESIGN-FIXME: this 'proof' doesn't really proof a conflict!
|
const char *exchange_url,
|
||||||
*
|
const json_t *proof,
|
||||||
* @param ccontract_sig conflicting signature (must
|
struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||||
* not match the signature from the proof)
|
struct TALER_CoinSpendSignatureP *coin_sig)
|
||||||
* @param purse_pub public key of the purse
|
{
|
||||||
* @param exchange_url the base URL of this exchange
|
const char *partner_url = NULL;
|
||||||
* @param proof the proof to check
|
struct TALER_Amount amount;
|
||||||
* @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a purse_sig
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
*/
|
GNUNET_JSON_spec_fixed_auto ("coin_sig",
|
||||||
|
coin_sig),
|
||||||
|
GNUNET_JSON_spec_fixed_auto ("coin_pub",
|
||||||
|
coin_pub),
|
||||||
|
GNUNET_JSON_spec_mark_optional (
|
||||||
|
GNUNET_JSON_spec_string ("partner_url",
|
||||||
|
&partner_url),
|
||||||
|
NULL),
|
||||||
|
TALER_JSON_spec_amount_any ("amount",
|
||||||
|
&amount),
|
||||||
|
GNUNET_JSON_spec_end ()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_JSON_parse (proof,
|
||||||
|
spec,
|
||||||
|
NULL, NULL))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
if (NULL == partner_url)
|
||||||
|
partner_url = exchange_url;
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_wallet_purse_deposit_verify (
|
||||||
|
partner_url,
|
||||||
|
purse_pub,
|
||||||
|
&amount,
|
||||||
|
coin_pub,
|
||||||
|
coin_sig))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_EXCHANGE_check_purse_econtract_conflict_ (
|
TALER_EXCHANGE_check_purse_econtract_conflict_ (
|
||||||
const struct TALER_PurseContractSignatureP *ccontract_sig,
|
const struct TALER_PurseContractSignatureP *ccontract_sig,
|
||||||
@ -1642,4 +1666,278 @@ TALER_EXCHANGE_check_purse_econtract_conflict_ (
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_EXCHANGE_check_coin_amount_conflict_ (
|
||||||
|
const struct TALER_EXCHANGE_Keys *keys,
|
||||||
|
const json_t *proof,
|
||||||
|
struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||||
|
struct TALER_Amount *remaining)
|
||||||
|
{
|
||||||
|
json_t *history;
|
||||||
|
struct TALER_Amount total;
|
||||||
|
struct TALER_DenominationHashP h_denom_pub;
|
||||||
|
const struct TALER_EXCHANGE_DenomPublicKey *dki;
|
||||||
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
|
GNUNET_JSON_spec_fixed_auto ("coin_pub",
|
||||||
|
coin_pub),
|
||||||
|
GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
|
||||||
|
&h_denom_pub),
|
||||||
|
GNUNET_JSON_spec_json ("history",
|
||||||
|
&history),
|
||||||
|
GNUNET_JSON_spec_end ()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_JSON_parse (proof,
|
||||||
|
spec,
|
||||||
|
NULL, NULL))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
dki = TALER_EXCHANGE_get_denomination_key_by_hash (
|
||||||
|
keys,
|
||||||
|
&h_denom_pub);
|
||||||
|
if (NULL == dki)
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_EXCHANGE_verify_coin_history (dki,
|
||||||
|
coin_pub,
|
||||||
|
history,
|
||||||
|
&total))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
json_decref (history);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
json_decref (history);
|
||||||
|
if (0 >
|
||||||
|
TALER_amount_subtract (remaining,
|
||||||
|
&dki->value,
|
||||||
|
&total))
|
||||||
|
{
|
||||||
|
/* Strange 'proof': coin was double-spent
|
||||||
|
before our transaction?! */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that @a coin_sig does NOT appear in
|
||||||
|
* the history of @a proof and thus whatever transaction
|
||||||
|
* is authorized by @a coin_sig is a conflict with
|
||||||
|
* @a proof.
|
||||||
|
*
|
||||||
|
* @param proof a proof to check
|
||||||
|
* @param coin_sig signature that must not be in @a proof
|
||||||
|
* @return #GNUNET_OK if @a coin_sig is not in @a proof
|
||||||
|
*/
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_EXCHANGE_check_coin_signature_conflict_ (
|
||||||
|
const json_t *proof,
|
||||||
|
const struct TALER_CoinSpendSignatureP *coin_sig)
|
||||||
|
{
|
||||||
|
json_t *history;
|
||||||
|
size_t off;
|
||||||
|
json_t *entry;
|
||||||
|
|
||||||
|
history = json_object_get (proof,
|
||||||
|
"history");
|
||||||
|
if (NULL == history)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
json_array_foreach (history, off, entry)
|
||||||
|
{
|
||||||
|
struct TALER_CoinSpendSignatureP cs;
|
||||||
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
|
GNUNET_JSON_spec_fixed_auto ("coin_sig",
|
||||||
|
&cs),
|
||||||
|
GNUNET_JSON_spec_end ()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_JSON_parse (entry,
|
||||||
|
spec,
|
||||||
|
NULL, NULL))
|
||||||
|
continue; /* entry without coin signature */
|
||||||
|
if (0 ==
|
||||||
|
GNUNET_memcmp (&cs,
|
||||||
|
coin_sig))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_EXCHANGE_check_coin_denomination_conflict_ (
|
||||||
|
const json_t *proof,
|
||||||
|
const struct TALER_DenominationHashP *ch_denom_pub)
|
||||||
|
{
|
||||||
|
struct TALER_DenominationHashP h_denom_pub;
|
||||||
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
|
GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
|
||||||
|
&h_denom_pub),
|
||||||
|
GNUNET_JSON_spec_end ()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_JSON_parse (proof,
|
||||||
|
spec,
|
||||||
|
NULL, NULL))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
if (0 ==
|
||||||
|
GNUNET_memcmp (ch_denom_pub,
|
||||||
|
&h_denom_pub))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
/* indeed, proof with different denomination key provided */
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_EXCHANGE_check_coin_conflict_ (
|
||||||
|
const struct TALER_EXCHANGE_Keys *keys,
|
||||||
|
const json_t *proof,
|
||||||
|
const struct TALER_EXCHANGE_DenomPublicKey *dk,
|
||||||
|
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||||
|
const struct TALER_CoinSpendSignatureP *coin_sig,
|
||||||
|
const struct TALER_Amount *required)
|
||||||
|
{
|
||||||
|
enum TALER_ErrorCode ec;
|
||||||
|
|
||||||
|
ec = TALER_JSON_get_error_code (proof);
|
||||||
|
switch (ec)
|
||||||
|
{
|
||||||
|
case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
|
||||||
|
{
|
||||||
|
struct TALER_Amount left;
|
||||||
|
struct TALER_CoinSpendPublicKeyP pcoin_pub;
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_EXCHANGE_check_coin_amount_conflict_ (
|
||||||
|
keys,
|
||||||
|
proof,
|
||||||
|
&pcoin_pub,
|
||||||
|
&left))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
if (0 !=
|
||||||
|
GNUNET_memcmp (&pcoin_pub,
|
||||||
|
coin_pub))
|
||||||
|
{
|
||||||
|
/* conflict is for a different coin! */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
if (-1 !=
|
||||||
|
TALER_amount_cmp (&left,
|
||||||
|
required))
|
||||||
|
{
|
||||||
|
/* Balance was sufficient after all; recoup MAY have still been possible */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_EXCHANGE_check_coin_signature_conflict_ (
|
||||||
|
proof,
|
||||||
|
coin_sig))
|
||||||
|
{
|
||||||
|
/* Not a conflicting transaction: ours is included! */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
|
||||||
|
{
|
||||||
|
struct TALER_Amount left;
|
||||||
|
struct TALER_CoinSpendPublicKeyP pcoin_pub;
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_EXCHANGE_check_coin_amount_conflict_ (
|
||||||
|
keys,
|
||||||
|
proof,
|
||||||
|
&pcoin_pub,
|
||||||
|
&left))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
if (0 !=
|
||||||
|
GNUNET_memcmp (&pcoin_pub,
|
||||||
|
coin_pub))
|
||||||
|
{
|
||||||
|
/* conflict is for a different coin! */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_EXCHANGE_check_coin_denomination_conflict_ (
|
||||||
|
proof,
|
||||||
|
&dk->h_key))
|
||||||
|
{
|
||||||
|
/* Eh, same denomination, hence no conflict */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_EXCHANGE_get_min_denomination_ (
|
||||||
|
const struct TALER_EXCHANGE_Keys *keys,
|
||||||
|
struct TALER_Amount *min)
|
||||||
|
{
|
||||||
|
bool have_min = false;
|
||||||
|
for (unsigned int i = 0; i<keys->num_denom_keys; i++)
|
||||||
|
{
|
||||||
|
const struct TALER_EXCHANGE_DenomPublicKey *dk = &keys->denom_keys[i];
|
||||||
|
|
||||||
|
if (! have_min)
|
||||||
|
{
|
||||||
|
*min = dk->value;
|
||||||
|
have_min = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (1 != TALER_amount_cmp (min,
|
||||||
|
&dk->value))
|
||||||
|
continue;
|
||||||
|
*min = dk->value;
|
||||||
|
}
|
||||||
|
if (! have_min)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* end of exchange_api_common.c */
|
/* end of exchange_api_common.c */
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#define EXCHANGE_API_COMMON_H
|
#define EXCHANGE_API_COMMON_H
|
||||||
|
|
||||||
#include "taler_json_lib.h"
|
#include "taler_json_lib.h"
|
||||||
|
#include "taler_exchange_service.h"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,7 +34,7 @@
|
|||||||
* @param purse_pub the public key (must match
|
* @param purse_pub the public key (must match
|
||||||
* the signature from the proof)
|
* the signature from the proof)
|
||||||
* @param proof the proof to check
|
* @param proof the proof to check
|
||||||
* @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a purse_sig
|
* @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a cpurse_sig
|
||||||
*/
|
*/
|
||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_EXCHANGE_check_purse_create_conflict_ (
|
TALER_EXCHANGE_check_purse_create_conflict_ (
|
||||||
@ -51,7 +52,7 @@ TALER_EXCHANGE_check_purse_create_conflict_ (
|
|||||||
* the signature from the proof)
|
* the signature from the proof)
|
||||||
* @param exchange_url the base URL of this exchange
|
* @param exchange_url the base URL of this exchange
|
||||||
* @param proof the proof to check
|
* @param proof the proof to check
|
||||||
* @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a purse_sig
|
* @return #GNUNET_OK if the @a proof is OK for @a purse_pub and @a merge_pub and conflicts with @a cmerge_sig
|
||||||
*/
|
*/
|
||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_EXCHANGE_check_purse_merge_conflict_ (
|
TALER_EXCHANGE_check_purse_merge_conflict_ (
|
||||||
@ -63,16 +64,38 @@ TALER_EXCHANGE_check_purse_merge_conflict_ (
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check proof of a contract conflict.
|
* Check @a proof that claims this coin was spend
|
||||||
|
* differently on the same purse already. Note that
|
||||||
|
* the caller must still check that @a coin_pub is
|
||||||
|
* in the list of coins that were used, and that
|
||||||
|
* @a coin_sig is different from the signature the
|
||||||
|
* caller used.
|
||||||
*
|
*
|
||||||
* DESIGN-FIXME: this 'proof' doesn't really proof a conflict!
|
* @param purse_pub the public key of the purse
|
||||||
|
* @param exchange_url base URL of our exchange
|
||||||
|
* @param proof the proof to check
|
||||||
|
* @param[out] coin_pub set to the conflicting coin
|
||||||
|
* @param[out] coin_sig set to the conflicting signature
|
||||||
|
* @return #GNUNET_OK if the @a proof is OK for @a purse_pub and showing that @a coin_pub was spent using @a coin_sig.
|
||||||
|
*/
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_EXCHANGE_check_purse_coin_conflict_ (
|
||||||
|
const struct TALER_PurseContractPublicKeyP *purse_pub,
|
||||||
|
const char *exchange_url,
|
||||||
|
const json_t *proof,
|
||||||
|
struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||||
|
struct TALER_CoinSpendSignatureP *coin_sig);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check proof of a contract conflict.
|
||||||
*
|
*
|
||||||
* @param ccontract_sig conflicting signature (must
|
* @param ccontract_sig conflicting signature (must
|
||||||
* not match the signature from the proof)
|
* not match the signature from the proof)
|
||||||
* @param purse_pub public key of the purse
|
* @param purse_pub public key of the purse
|
||||||
* @param exchange_url the base URL of this exchange
|
* @param exchange_url the base URL of this exchange
|
||||||
* @param proof the proof to check
|
* @param proof the proof to check
|
||||||
* @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a purse_sig
|
* @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a ccontract_sig
|
||||||
*/
|
*/
|
||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_EXCHANGE_check_purse_econtract_conflict_ (
|
TALER_EXCHANGE_check_purse_econtract_conflict_ (
|
||||||
@ -81,4 +104,94 @@ TALER_EXCHANGE_check_purse_econtract_conflict_ (
|
|||||||
const json_t *proof);
|
const json_t *proof);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check proof of a coin spend value conflict.
|
||||||
|
*
|
||||||
|
* @param keys exchange /keys structure
|
||||||
|
* @param proof the proof to check
|
||||||
|
* @param[out] coin_pub set to the public key of the
|
||||||
|
* coin that is claimed to have an insufficient
|
||||||
|
* balance
|
||||||
|
* @param[out] remaining set to the remaining balance
|
||||||
|
* of the coin as provided by the proof
|
||||||
|
* @return #GNUNET_OK if the @a proof is OK for @a purse_pub demonstrating that @a coin_pub has only @a remaining balance.
|
||||||
|
*/
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_EXCHANGE_check_coin_amount_conflict_ (
|
||||||
|
const struct TALER_EXCHANGE_Keys *keys,
|
||||||
|
const json_t *proof,
|
||||||
|
struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||||
|
struct TALER_Amount *remaining);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that @a proof contains a coin history
|
||||||
|
* that demonstrates that @a coin_pub was previously
|
||||||
|
* used with a denomination key that is different
|
||||||
|
* from @a ch_denom_pub. Note that the coin history
|
||||||
|
* MUST have been checked before using
|
||||||
|
* #TALER_EXCHANGE_check_coin_amount_conflict_().
|
||||||
|
*
|
||||||
|
* @param proof a proof to check
|
||||||
|
* @param ch_denom_pub hash of the conflicting denomination
|
||||||
|
* @return #GNUNET_OK if @a ch_denom_pub differs from the
|
||||||
|
* denomination hash given by the history of the coin
|
||||||
|
*/
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_EXCHANGE_check_coin_denomination_conflict_ (
|
||||||
|
const json_t *proof,
|
||||||
|
const struct TALER_DenominationHashP *ch_denom_pub);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that @a coin_sig does NOT appear in
|
||||||
|
* the history of @a proof and thus whatever transaction
|
||||||
|
* is authorized by @a coin_sig is a conflict with
|
||||||
|
* @a proof.
|
||||||
|
*
|
||||||
|
* @param proof a proof to check
|
||||||
|
* @param coin_sig signature that must not be in @a proof
|
||||||
|
* @return #GNUNET_OK if @a coin_sig is not in @a proof
|
||||||
|
*/
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_EXCHANGE_check_coin_signature_conflict_ (
|
||||||
|
const json_t *proof,
|
||||||
|
const struct TALER_CoinSpendSignatureP *coin_sig);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that the provided @a proof indeeds indicates
|
||||||
|
* a conflict for @a coin_pub.
|
||||||
|
*
|
||||||
|
* @param keys exchange keys
|
||||||
|
* @param proof provided conflict proof
|
||||||
|
* @param dk denomination of @a coin_pub that the client
|
||||||
|
* used
|
||||||
|
* @param coin_pub public key of the coin
|
||||||
|
* @param coin_sig signature over operation that conflicted
|
||||||
|
* @param required balance required on the coin for the operation
|
||||||
|
* @return #GNUNET_OK if @a proof holds
|
||||||
|
*/
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_EXCHANGE_check_coin_conflict_ (
|
||||||
|
const struct TALER_EXCHANGE_Keys *keys,
|
||||||
|
const json_t *proof,
|
||||||
|
const struct TALER_EXCHANGE_DenomPublicKey *dk,
|
||||||
|
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||||
|
const struct TALER_CoinSpendSignatureP *coin_sig,
|
||||||
|
const struct TALER_Amount *required);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the smallest denomination amount in @e keys.
|
||||||
|
*
|
||||||
|
* @param keys keys to search
|
||||||
|
* @param[out] min set to the smallest amount
|
||||||
|
* @return #GNUNET_SYSERR if there are no denominations in @a keys
|
||||||
|
*/
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_EXCHANGE_get_min_denomination_ (
|
||||||
|
const struct TALER_EXCHANGE_Keys *keys,
|
||||||
|
struct TALER_Amount *min);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "taler_json_lib.h"
|
#include "taler_json_lib.h"
|
||||||
#include "taler_auditor_service.h"
|
#include "taler_auditor_service.h"
|
||||||
#include "taler_exchange_service.h"
|
#include "taler_exchange_service.h"
|
||||||
|
#include "exchange_api_common.h"
|
||||||
#include "exchange_api_handle.h"
|
#include "exchange_api_handle.h"
|
||||||
#include "taler_signatures.h"
|
#include "taler_signatures.h"
|
||||||
#include "exchange_api_curl_defaults.h"
|
#include "exchange_api_curl_defaults.h"
|
||||||
@ -128,6 +129,11 @@ struct TALER_EXCHANGE_DepositHandle
|
|||||||
*/
|
*/
|
||||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Our signature for the deposit operation.
|
||||||
|
*/
|
||||||
|
struct TALER_CoinSpendSignatureP coin_sig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Merchant's public key. Allows the merchant to later refund
|
* The Merchant's public key. Allows the merchant to later refund
|
||||||
* the transaction or to inquire about the wire transfer identifier.
|
* the transaction or to inquire about the wire transfer identifier.
|
||||||
@ -226,77 +232,6 @@ auditor_cb (void *cls,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify that the signatures on the "403 FORBIDDEN" response from the
|
|
||||||
* exchange demonstrating customer double-spending are valid.
|
|
||||||
*
|
|
||||||
* @param dh deposit handle
|
|
||||||
* @param json json reply with the signature(s) and transaction history
|
|
||||||
* @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
|
|
||||||
*/
|
|
||||||
static enum GNUNET_GenericReturnValue
|
|
||||||
verify_deposit_signature_conflict (
|
|
||||||
const struct TALER_EXCHANGE_DepositHandle *dh,
|
|
||||||
const json_t *json)
|
|
||||||
{
|
|
||||||
json_t *history;
|
|
||||||
struct TALER_Amount total;
|
|
||||||
enum TALER_ErrorCode ec;
|
|
||||||
struct TALER_DenominationHashP h_denom_pub;
|
|
||||||
|
|
||||||
memset (&h_denom_pub,
|
|
||||||
0,
|
|
||||||
sizeof (h_denom_pub));
|
|
||||||
history = json_object_get (json,
|
|
||||||
"history");
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
TALER_EXCHANGE_verify_coin_history (&dh->dki,
|
|
||||||
dh->dki.value.currency,
|
|
||||||
&dh->coin_pub,
|
|
||||||
history,
|
|
||||||
&h_denom_pub,
|
|
||||||
&total))
|
|
||||||
{
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
ec = TALER_JSON_get_error_code (json);
|
|
||||||
switch (ec)
|
|
||||||
{
|
|
||||||
case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
|
|
||||||
if (0 >
|
|
||||||
TALER_amount_add (&total,
|
|
||||||
&total,
|
|
||||||
&dh->amount_with_fee))
|
|
||||||
{
|
|
||||||
/* clearly not OK if our transaction would have caused
|
|
||||||
the overflow... */
|
|
||||||
return GNUNET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 >= TALER_amount_cmp (&total,
|
|
||||||
&dh->dki.value))
|
|
||||||
{
|
|
||||||
/* transaction should have still fit */
|
|
||||||
GNUNET_break (0);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
/* everything OK, proof of double-spending was provided */
|
|
||||||
return GNUNET_OK;
|
|
||||||
case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
|
|
||||||
if (0 != GNUNET_memcmp (&dh->dki.h_key,
|
|
||||||
&h_denom_pub))
|
|
||||||
return GNUNET_OK; /* indeed, proof with different denomination key provided */
|
|
||||||
/* invalid proof provided */
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
default:
|
|
||||||
/* unexpected error code */
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called when we're done processing the
|
* Function called when we're done processing the
|
||||||
* HTTP /deposit request.
|
* HTTP /deposit request.
|
||||||
@ -316,8 +251,10 @@ handle_deposit_finished (void *cls,
|
|||||||
.hr.reply = j,
|
.hr.reply = j,
|
||||||
.hr.http_status = (unsigned int) response_code
|
.hr.http_status = (unsigned int) response_code
|
||||||
};
|
};
|
||||||
|
const struct TALER_EXCHANGE_Keys *keys;
|
||||||
|
|
||||||
dh->job = NULL;
|
dh->job = NULL;
|
||||||
|
keys = TALER_EXCHANGE_get_keys (dh->exchange);
|
||||||
switch (response_code)
|
switch (response_code)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -409,19 +346,21 @@ handle_deposit_finished (void *cls,
|
|||||||
happen, we should pass the JSON reply to the application */
|
happen, we should pass the JSON reply to the application */
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_CONFLICT:
|
case MHD_HTTP_CONFLICT:
|
||||||
/* Double spending; check signatures on transaction history */
|
dr.hr.ec = TALER_JSON_get_error_code (j);
|
||||||
|
dr.hr.hint = TALER_JSON_get_error_hint (j);
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
verify_deposit_signature_conflict (dh,
|
TALER_EXCHANGE_check_coin_conflict_ (
|
||||||
j))
|
keys,
|
||||||
|
j,
|
||||||
|
&dh->dki,
|
||||||
|
&dh->coin_pub,
|
||||||
|
&dh->coin_sig,
|
||||||
|
&dh->amount_with_fee))
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
dr.hr.http_status = 0;
|
dr.hr.http_status = 0;
|
||||||
dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
}
|
break;
|
||||||
else
|
|
||||||
{
|
|
||||||
dr.hr.ec = TALER_JSON_get_error_code (j);
|
|
||||||
dr.hr.hint = TALER_JSON_get_error_hint (j);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_GONE:
|
case MHD_HTTP_GONE:
|
||||||
@ -692,6 +631,8 @@ TALER_EXCHANGE_deposit (
|
|||||||
dh->exchange = exchange;
|
dh->exchange = exchange;
|
||||||
dh->cb = cb;
|
dh->cb = cb;
|
||||||
dh->cb_cls = cb_cls;
|
dh->cb_cls = cb_cls;
|
||||||
|
dh->coin_sig = *coin_sig;
|
||||||
|
dh->coin_pub = *coin_pub;
|
||||||
dh->url = TEAH_path_to_url (exchange,
|
dh->url = TEAH_path_to_url (exchange,
|
||||||
arg_str);
|
arg_str);
|
||||||
if (NULL == dh->url)
|
if (NULL == dh->url)
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <gnunet/gnunet_curl_lib.h>
|
#include <gnunet/gnunet_curl_lib.h>
|
||||||
#include "taler_json_lib.h"
|
#include "taler_json_lib.h"
|
||||||
#include "taler_exchange_service.h"
|
#include "taler_exchange_service.h"
|
||||||
|
#include "exchange_api_common.h"
|
||||||
#include "exchange_api_handle.h"
|
#include "exchange_api_handle.h"
|
||||||
#include "taler_signatures.h"
|
#include "taler_signatures.h"
|
||||||
#include "exchange_api_curl_defaults.h"
|
#include "exchange_api_curl_defaults.h"
|
||||||
@ -101,6 +102,11 @@ struct TALER_EXCHANGE_MeltHandle
|
|||||||
*/
|
*/
|
||||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature affirming the melt.
|
||||||
|
*/
|
||||||
|
struct TALER_CoinSpendSignatureP coin_sig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Public information about the coin's denomination key
|
* @brief Public information about the coin's denomination key
|
||||||
*/
|
*/
|
||||||
@ -183,143 +189,6 @@ verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle *mh,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify that the signatures on the "409 CONFLICT" response from the
|
|
||||||
* exchange demonstrating customer denomination key differences
|
|
||||||
* resulting from coin private key reuse are valid.
|
|
||||||
*
|
|
||||||
* @param mh melt handle
|
|
||||||
* @param json json reply with the signature(s) and transaction history
|
|
||||||
* @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
|
|
||||||
*/
|
|
||||||
static enum GNUNET_GenericReturnValue
|
|
||||||
verify_melt_signature_denom_conflict (struct TALER_EXCHANGE_MeltHandle *mh,
|
|
||||||
const json_t *json)
|
|
||||||
|
|
||||||
{
|
|
||||||
json_t *history;
|
|
||||||
struct TALER_Amount total;
|
|
||||||
struct TALER_DenominationHashP h_denom_pub;
|
|
||||||
|
|
||||||
memset (&h_denom_pub,
|
|
||||||
0,
|
|
||||||
sizeof (h_denom_pub));
|
|
||||||
history = json_object_get (json,
|
|
||||||
"history");
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
TALER_EXCHANGE_verify_coin_history (mh->dki,
|
|
||||||
mh->dki->value.currency,
|
|
||||||
&mh->coin_pub,
|
|
||||||
history,
|
|
||||||
&h_denom_pub,
|
|
||||||
&total))
|
|
||||||
{
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
if (0 != GNUNET_memcmp (&mh->dki->h_key,
|
|
||||||
&h_denom_pub))
|
|
||||||
return GNUNET_OK; /* indeed, proof with different denomination key provided */
|
|
||||||
/* invalid proof provided */
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify that the signatures on the "409 CONFLICT" response from the
|
|
||||||
* exchange demonstrating customer double-spending are valid.
|
|
||||||
*
|
|
||||||
* @param mh melt handle
|
|
||||||
* @param json json reply with the signature(s) and transaction history
|
|
||||||
* @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
|
|
||||||
*/
|
|
||||||
static enum GNUNET_GenericReturnValue
|
|
||||||
verify_melt_signature_spend_conflict (struct TALER_EXCHANGE_MeltHandle *mh,
|
|
||||||
const json_t *json)
|
|
||||||
{
|
|
||||||
json_t *history;
|
|
||||||
struct TALER_Amount total;
|
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
|
||||||
GNUNET_JSON_spec_json ("history",
|
|
||||||
&history),
|
|
||||||
GNUNET_JSON_spec_end ()
|
|
||||||
};
|
|
||||||
const struct MeltedCoin *mc;
|
|
||||||
enum TALER_ErrorCode ec;
|
|
||||||
struct TALER_DenominationHashP h_denom_pub;
|
|
||||||
|
|
||||||
/* parse JSON reply */
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
GNUNET_JSON_parse (json,
|
|
||||||
spec,
|
|
||||||
NULL, NULL))
|
|
||||||
{
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find out which coin was deemed problematic by the exchange */
|
|
||||||
mc = &mh->md.melted_coin;
|
|
||||||
/* verify coin history */
|
|
||||||
memset (&h_denom_pub,
|
|
||||||
0,
|
|
||||||
sizeof (h_denom_pub));
|
|
||||||
history = json_object_get (json,
|
|
||||||
"history");
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
TALER_EXCHANGE_verify_coin_history (mh->dki,
|
|
||||||
mc->original_value.currency,
|
|
||||||
&mh->coin_pub,
|
|
||||||
history,
|
|
||||||
&h_denom_pub,
|
|
||||||
&total))
|
|
||||||
{
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
json_decref (history);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
json_decref (history);
|
|
||||||
|
|
||||||
ec = TALER_JSON_get_error_code (json);
|
|
||||||
switch (ec)
|
|
||||||
{
|
|
||||||
case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
|
|
||||||
/* check if melt operation was really too expensive given history */
|
|
||||||
if (0 >
|
|
||||||
TALER_amount_add (&total,
|
|
||||||
&total,
|
|
||||||
&mc->melt_amount_with_fee))
|
|
||||||
{
|
|
||||||
/* clearly not OK if our transaction would have caused
|
|
||||||
the overflow... */
|
|
||||||
return GNUNET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 >= TALER_amount_cmp (&total,
|
|
||||||
&mc->original_value))
|
|
||||||
{
|
|
||||||
/* transaction should have still fit */
|
|
||||||
GNUNET_break (0);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* everything OK, valid proof of double-spending was provided */
|
|
||||||
return GNUNET_OK;
|
|
||||||
case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
|
|
||||||
if (0 != GNUNET_memcmp (&mh->dki->h_key,
|
|
||||||
&h_denom_pub))
|
|
||||||
return GNUNET_OK; /* indeed, proof with different denomination key provided */
|
|
||||||
/* invalid proof provided */
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
default:
|
|
||||||
/* unexpected error code */
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called when we're done processing the
|
* Function called when we're done processing the
|
||||||
* HTTP /coins/$COIN_PUB/melt request.
|
* HTTP /coins/$COIN_PUB/melt request.
|
||||||
@ -339,8 +208,10 @@ handle_melt_finished (void *cls,
|
|||||||
.hr.reply = j,
|
.hr.reply = j,
|
||||||
.hr.http_status = (unsigned int) response_code
|
.hr.http_status = (unsigned int) response_code
|
||||||
};
|
};
|
||||||
|
const struct TALER_EXCHANGE_Keys *keys;
|
||||||
|
|
||||||
mh->job = NULL;
|
mh->job = NULL;
|
||||||
|
keys = TALER_EXCHANGE_get_keys (mh->exchange);
|
||||||
switch (response_code)
|
switch (response_code)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -372,36 +243,19 @@ handle_melt_finished (void *cls,
|
|||||||
break;
|
break;
|
||||||
case MHD_HTTP_CONFLICT:
|
case MHD_HTTP_CONFLICT:
|
||||||
mr.hr.ec = TALER_JSON_get_error_code (j);
|
mr.hr.ec = TALER_JSON_get_error_code (j);
|
||||||
switch (mr.hr.ec)
|
mr.hr.hint = TALER_JSON_get_error_hint (j);
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_EXCHANGE_check_coin_conflict_ (
|
||||||
|
keys,
|
||||||
|
j,
|
||||||
|
mh->dki,
|
||||||
|
&mh->coin_pub,
|
||||||
|
&mh->coin_sig,
|
||||||
|
&mh->md.melted_coin.melt_amount_with_fee))
|
||||||
{
|
{
|
||||||
case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
|
|
||||||
/* Double spending; check signatures on transaction history */
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
verify_melt_signature_spend_conflict (mh,
|
|
||||||
j))
|
|
||||||
{
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
mr.hr.http_status = 0;
|
|
||||||
mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE;
|
|
||||||
mr.hr.hint = TALER_JSON_get_error_hint (j);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
verify_melt_signature_denom_conflict (mh,
|
|
||||||
j))
|
|
||||||
{
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
mr.hr.http_status = 0;
|
|
||||||
mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE;
|
|
||||||
mr.hr.hint = TALER_JSON_get_error_hint (j);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
mr.hr.http_status = 0;
|
mr.hr.http_status = 0;
|
||||||
mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE;
|
mr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
mr.hr.hint = TALER_JSON_get_error_hint (j);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -456,7 +310,6 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
|
|||||||
json_t *melt_obj;
|
json_t *melt_obj;
|
||||||
CURL *eh;
|
CURL *eh;
|
||||||
struct GNUNET_CURL_Context *ctx;
|
struct GNUNET_CURL_Context *ctx;
|
||||||
struct TALER_CoinSpendSignatureP confirm_sig;
|
|
||||||
char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
|
char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
|
||||||
struct TALER_DenominationHashP h_denom_pub;
|
struct TALER_DenominationHashP h_denom_pub;
|
||||||
struct TALER_ExchangeWithdrawValues alg_values[mh->rd->fresh_pks_len];
|
struct TALER_ExchangeWithdrawValues alg_values[mh->rd->fresh_pks_len];
|
||||||
@ -480,7 +333,7 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
|
|||||||
&h_denom_pub,
|
&h_denom_pub,
|
||||||
mh->md.melted_coin.h_age_commitment,
|
mh->md.melted_coin.h_age_commitment,
|
||||||
&mh->md.melted_coin.coin_priv,
|
&mh->md.melted_coin.coin_priv,
|
||||||
&confirm_sig);
|
&mh->coin_sig);
|
||||||
GNUNET_CRYPTO_eddsa_key_get_public (&mh->md.melted_coin.coin_priv.eddsa_priv,
|
GNUNET_CRYPTO_eddsa_key_get_public (&mh->md.melted_coin.coin_priv.eddsa_priv,
|
||||||
&mh->coin_pub.eddsa_pub);
|
&mh->coin_pub.eddsa_pub);
|
||||||
melt_obj = GNUNET_JSON_PACK (
|
melt_obj = GNUNET_JSON_PACK (
|
||||||
@ -489,7 +342,7 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
|
|||||||
TALER_JSON_pack_denom_sig ("denom_sig",
|
TALER_JSON_pack_denom_sig ("denom_sig",
|
||||||
&mh->md.melted_coin.sig),
|
&mh->md.melted_coin.sig),
|
||||||
GNUNET_JSON_pack_data_auto ("confirm_sig",
|
GNUNET_JSON_pack_data_auto ("confirm_sig",
|
||||||
&confirm_sig),
|
&mh->coin_sig),
|
||||||
TALER_JSON_pack_amount ("value_with_fee",
|
TALER_JSON_pack_amount ("value_with_fee",
|
||||||
&mh->md.melted_coin.melt_amount_with_fee),
|
&mh->md.melted_coin.melt_amount_with_fee),
|
||||||
GNUNET_JSON_pack_data_auto ("rc",
|
GNUNET_JSON_pack_data_auto ("rc",
|
||||||
|
@ -34,6 +34,33 @@
|
|||||||
#include "exchange_api_curl_defaults.h"
|
#include "exchange_api_curl_defaults.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information we track per deposited coin.
|
||||||
|
*/
|
||||||
|
struct Deposit
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Coin's public key.
|
||||||
|
*/
|
||||||
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature made with the coin.
|
||||||
|
*/
|
||||||
|
struct TALER_CoinSpendSignatureP coin_sig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coin's denomination.
|
||||||
|
*/
|
||||||
|
struct TALER_DenominationHashP h_denom_pub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How much did we say the coin contributed.
|
||||||
|
*/
|
||||||
|
struct TALER_Amount contribution;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A purse create with deposit handle
|
* @brief A purse create with deposit handle
|
||||||
*/
|
*/
|
||||||
@ -106,6 +133,16 @@ struct TALER_EXCHANGE_PurseCreateDepositHandle
|
|||||||
*/
|
*/
|
||||||
struct GNUNET_TIME_Timestamp purse_expiration;
|
struct GNUNET_TIME_Timestamp purse_expiration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of @e num_deposit deposits.
|
||||||
|
*/
|
||||||
|
struct Deposit *deposits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How many deposits did we make?
|
||||||
|
*/
|
||||||
|
unsigned int num_deposits;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -128,8 +165,10 @@ handle_purse_create_deposit_finished (void *cls,
|
|||||||
.hr.reply = j,
|
.hr.reply = j,
|
||||||
.hr.http_status = (unsigned int) response_code
|
.hr.http_status = (unsigned int) response_code
|
||||||
};
|
};
|
||||||
|
const struct TALER_EXCHANGE_Keys *keys;
|
||||||
|
|
||||||
pch->job = NULL;
|
pch->job = NULL;
|
||||||
|
keys = TALER_EXCHANGE_get_keys (pch->exchange);
|
||||||
switch (response_code)
|
switch (response_code)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -232,43 +271,151 @@ handle_purse_create_deposit_finished (void *cls,
|
|||||||
break;
|
break;
|
||||||
case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
|
case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
|
||||||
{
|
{
|
||||||
#if FIXME
|
struct TALER_Amount left;
|
||||||
struct TALER_Amount total;
|
struct TALER_CoinSpendPublicKeyP pcoin_pub;
|
||||||
struct TALER_DenominationHashP h_denom_pub;
|
bool found = false;
|
||||||
const struct TALER_EXCHANGE_DenomPublicKey *dk = NULL;
|
|
||||||
|
|
||||||
// FIXME: parse coin_pub
|
|
||||||
// FIXME: lookup dk for that coin from our deposits array!
|
|
||||||
|
|
||||||
if (NULL == dk)
|
|
||||||
{
|
|
||||||
/* not one of our coins */
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
dr.hr.http_status = 0;
|
|
||||||
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_EXCHANGE_verify_coin_history (dk,
|
TALER_EXCHANGE_check_coin_amount_conflict_ (
|
||||||
pch->exchange->currency,
|
keys,
|
||||||
&coin_pub,
|
j,
|
||||||
history,
|
&pcoin_pub,
|
||||||
&h_denom_pub,
|
&left))
|
||||||
&total))
|
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
dr.hr.http_status = 0;
|
dr.hr.http_status = 0;
|
||||||
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// FIXME: check total is too high for the request...
|
for (unsigned int i = 0; i<pch->num_deposits; i++)
|
||||||
#endif
|
{
|
||||||
|
struct Deposit *deposit = &pch->deposits[i];
|
||||||
|
|
||||||
|
if (0 != GNUNET_memcmp (&pcoin_pub,
|
||||||
|
&deposit->coin_pub))
|
||||||
|
continue;
|
||||||
|
if (-1 !=
|
||||||
|
TALER_amount_cmp (&left,
|
||||||
|
&deposit->contribution))
|
||||||
|
{
|
||||||
|
/* Balance was sufficient after all; recoup MAY have still been possible */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_EXCHANGE_check_coin_signature_conflict_ (
|
||||||
|
j,
|
||||||
|
&deposit->coin_sig))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (! found)
|
||||||
|
{
|
||||||
|
/* conflict is for a different coin! */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
|
||||||
|
{
|
||||||
|
struct TALER_Amount left;
|
||||||
|
struct TALER_CoinSpendPublicKeyP pcoin_pub;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_EXCHANGE_check_coin_amount_conflict_ (
|
||||||
|
keys,
|
||||||
|
j,
|
||||||
|
&pcoin_pub,
|
||||||
|
&left))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i<pch->num_deposits; i++)
|
||||||
|
{
|
||||||
|
struct Deposit *deposit = &pch->deposits[i];
|
||||||
|
|
||||||
|
if (0 !=
|
||||||
|
GNUNET_memcmp (&pcoin_pub,
|
||||||
|
&deposit->coin_pub))
|
||||||
|
continue;
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_EXCHANGE_check_coin_denomination_conflict_ (
|
||||||
|
j,
|
||||||
|
&deposit->h_denom_pub))
|
||||||
|
{
|
||||||
|
/* Eh, same denomination, hence no conflict */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (! found)
|
||||||
|
{
|
||||||
|
/* conflict is for a different coin! */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* meta data conflict is real! */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA:
|
case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA:
|
||||||
{
|
{
|
||||||
// FIXME!
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||||
break;
|
struct TALER_CoinSpendSignatureP coin_sig;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_EXCHANGE_check_purse_coin_conflict_ (
|
||||||
|
&pch->purse_pub,
|
||||||
|
pch->exchange->url,
|
||||||
|
j,
|
||||||
|
&coin_pub,
|
||||||
|
&coin_sig))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i<pch->num_deposits; i++)
|
||||||
|
{
|
||||||
|
struct Deposit *deposit = &pch->deposits[i];
|
||||||
|
|
||||||
|
if (0 !=
|
||||||
|
GNUNET_memcmp (&coin_pub,
|
||||||
|
&deposit->coin_pub))
|
||||||
|
continue;
|
||||||
|
if (0 ==
|
||||||
|
GNUNET_memcmp (&coin_sig,
|
||||||
|
&deposit->coin_sig))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (! found)
|
||||||
|
{
|
||||||
|
/* conflict is for a different coin! */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA:
|
case TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA:
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
@ -408,6 +555,9 @@ TALER_EXCHANGE_purse_create_with_deposit (
|
|||||||
GNUNET_free (pch);
|
GNUNET_free (pch);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
pch->num_deposits = num_deposits;
|
||||||
|
pch->deposits = GNUNET_new_array (num_deposits,
|
||||||
|
struct Deposit);
|
||||||
deposit_arr = json_array ();
|
deposit_arr = json_array ();
|
||||||
GNUNET_assert (NULL != deposit_arr);
|
GNUNET_assert (NULL != deposit_arr);
|
||||||
url = TEAH_path_to_url (exchange,
|
url = TEAH_path_to_url (exchange,
|
||||||
@ -418,9 +568,8 @@ TALER_EXCHANGE_purse_create_with_deposit (
|
|||||||
for (unsigned int i = 0; i<num_deposits; i++)
|
for (unsigned int i = 0; i<num_deposits; i++)
|
||||||
{
|
{
|
||||||
const struct TALER_EXCHANGE_PurseDeposit *deposit = &deposits[i];
|
const struct TALER_EXCHANGE_PurseDeposit *deposit = &deposits[i];
|
||||||
|
struct Deposit *d = &pch->deposits[i];
|
||||||
json_t *jdeposit;
|
json_t *jdeposit;
|
||||||
struct TALER_CoinSpendSignatureP coin_sig;
|
|
||||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
|
||||||
#if FIXME_OEC
|
#if FIXME_OEC
|
||||||
struct TALER_AgeCommitmentHash agh;
|
struct TALER_AgeCommitmentHash agh;
|
||||||
struct TALER_AgeCommitmentHash *aghp = NULL;
|
struct TALER_AgeCommitmentHash *aghp = NULL;
|
||||||
@ -441,14 +590,16 @@ TALER_EXCHANGE_purse_create_with_deposit (
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
d->contribution = deposit->amount;
|
||||||
|
d->h_denom_pub = deposit->h_denom_pub;
|
||||||
GNUNET_CRYPTO_eddsa_key_get_public (&deposit->coin_priv.eddsa_priv,
|
GNUNET_CRYPTO_eddsa_key_get_public (&deposit->coin_priv.eddsa_priv,
|
||||||
&coin_pub.eddsa_pub);
|
&d->coin_pub.eddsa_pub);
|
||||||
TALER_wallet_purse_deposit_sign (
|
TALER_wallet_purse_deposit_sign (
|
||||||
url,
|
url,
|
||||||
&pch->purse_pub,
|
&pch->purse_pub,
|
||||||
&deposit->amount,
|
&deposit->amount,
|
||||||
&deposit->coin_priv,
|
&deposit->coin_priv,
|
||||||
&coin_sig);
|
&d->coin_sig);
|
||||||
jdeposit = GNUNET_JSON_PACK (
|
jdeposit = GNUNET_JSON_PACK (
|
||||||
#if FIXME_OEC
|
#if FIXME_OEC
|
||||||
GNUNET_JSON_pack_allow_null (
|
GNUNET_JSON_pack_allow_null (
|
||||||
@ -465,9 +616,9 @@ TALER_EXCHANGE_purse_create_with_deposit (
|
|||||||
TALER_JSON_pack_denom_sig ("ub_sig",
|
TALER_JSON_pack_denom_sig ("ub_sig",
|
||||||
&deposit->denom_sig),
|
&deposit->denom_sig),
|
||||||
GNUNET_JSON_pack_data_auto ("coin_sig",
|
GNUNET_JSON_pack_data_auto ("coin_sig",
|
||||||
&coin_sig),
|
&d->coin_sig),
|
||||||
GNUNET_JSON_pack_data_auto ("coin_pub",
|
GNUNET_JSON_pack_data_auto ("coin_pub",
|
||||||
&coin_pub));
|
&d->coin_pub));
|
||||||
GNUNET_assert (0 ==
|
GNUNET_assert (0 ==
|
||||||
json_array_append_new (deposit_arr,
|
json_array_append_new (deposit_arr,
|
||||||
jdeposit));
|
jdeposit));
|
||||||
@ -529,6 +680,7 @@ TALER_EXCHANGE_purse_create_with_deposit (
|
|||||||
curl_easy_cleanup (eh);
|
curl_easy_cleanup (eh);
|
||||||
json_decref (create_obj);
|
json_decref (create_obj);
|
||||||
GNUNET_free (pch->econtract.econtract);
|
GNUNET_free (pch->econtract.econtract);
|
||||||
|
GNUNET_free (pch->deposits);
|
||||||
GNUNET_free (pch->url);
|
GNUNET_free (pch->url);
|
||||||
GNUNET_free (pch);
|
GNUNET_free (pch);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -558,6 +710,7 @@ TALER_EXCHANGE_purse_create_with_deposit_cancel (
|
|||||||
}
|
}
|
||||||
GNUNET_free (pch->econtract.econtract);
|
GNUNET_free (pch->econtract.econtract);
|
||||||
GNUNET_free (pch->url);
|
GNUNET_free (pch->url);
|
||||||
|
GNUNET_free (pch->deposits);
|
||||||
TALER_curl_easy_post_finished (&pch->ctx);
|
TALER_curl_easy_post_finished (&pch->ctx);
|
||||||
GNUNET_free (pch);
|
GNUNET_free (pch);
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <gnunet/gnunet_curl_lib.h>
|
#include <gnunet/gnunet_curl_lib.h>
|
||||||
#include "taler_json_lib.h"
|
#include "taler_json_lib.h"
|
||||||
#include "taler_exchange_service.h"
|
#include "taler_exchange_service.h"
|
||||||
|
#include "exchange_api_common.h"
|
||||||
#include "exchange_api_handle.h"
|
#include "exchange_api_handle.h"
|
||||||
#include "taler_signatures.h"
|
#include "taler_signatures.h"
|
||||||
#include "exchange_api_curl_defaults.h"
|
#include "exchange_api_curl_defaults.h"
|
||||||
@ -43,6 +44,11 @@ struct Coin
|
|||||||
*/
|
*/
|
||||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature made with the coin.
|
||||||
|
*/
|
||||||
|
struct TALER_CoinSpendSignatureP coin_sig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Coin's denomination.
|
* Coin's denomination.
|
||||||
*/
|
*/
|
||||||
@ -226,30 +232,17 @@ handle_purse_deposit_finished (void *cls,
|
|||||||
{
|
{
|
||||||
case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA:
|
case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA:
|
||||||
{
|
{
|
||||||
const char *partner_url = NULL;
|
|
||||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||||
struct TALER_CoinSpendSignatureP coin_sig;
|
struct TALER_CoinSpendSignatureP coin_sig;
|
||||||
struct TALER_Amount amount;
|
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
|
||||||
GNUNET_JSON_spec_fixed_auto ("coin_sig",
|
|
||||||
&coin_sig),
|
|
||||||
GNUNET_JSON_spec_fixed_auto ("coin_pub",
|
|
||||||
&coin_pub),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_string ("partner_url",
|
|
||||||
&partner_url),
|
|
||||||
NULL),
|
|
||||||
TALER_JSON_spec_amount ("amount",
|
|
||||||
keys->currency,
|
|
||||||
&amount),
|
|
||||||
GNUNET_JSON_spec_end ()
|
|
||||||
};
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_JSON_parse (j,
|
TALER_EXCHANGE_check_purse_coin_conflict_ (
|
||||||
spec,
|
&pch->purse_pub,
|
||||||
NULL, NULL))
|
pch->base_url,
|
||||||
|
j,
|
||||||
|
&coin_pub,
|
||||||
|
&coin_sig))
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
dr.hr.http_status = 0;
|
dr.hr.http_status = 0;
|
||||||
@ -257,29 +250,21 @@ handle_purse_deposit_finished (void *cls,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (unsigned int i = 0; i<pch->num_deposits; i++)
|
for (unsigned int i = 0; i<pch->num_deposits; i++)
|
||||||
|
{
|
||||||
if (0 == GNUNET_memcmp (&coin_pub,
|
if (0 == GNUNET_memcmp (&coin_pub,
|
||||||
&pch->coins[i].coin_pub))
|
&pch->coins[i].coin_pub))
|
||||||
{
|
{
|
||||||
|
if (0 == GNUNET_memcmp (&coin_sig,
|
||||||
|
&pch->coins[i].coin_sig))
|
||||||
|
{
|
||||||
|
/* identical signature => not a conflict */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (! found)
|
|
||||||
{
|
|
||||||
/* proof is about a coin we did not even deposit */
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
dr.hr.http_status = 0;
|
|
||||||
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (NULL == partner_url)
|
if (! found)
|
||||||
partner_url = pch->base_url;
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
TALER_wallet_purse_deposit_verify (
|
|
||||||
partner_url,
|
|
||||||
&pch->purse_pub,
|
|
||||||
&amount,
|
|
||||||
&coin_pub,
|
|
||||||
&coin_sig))
|
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
dr.hr.http_status = 0;
|
dr.hr.http_status = 0;
|
||||||
@ -291,27 +276,18 @@ handle_purse_deposit_finished (void *cls,
|
|||||||
}
|
}
|
||||||
case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
|
case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
|
||||||
{
|
{
|
||||||
json_t *history;
|
|
||||||
struct TALER_Amount total;
|
|
||||||
struct TALER_DenominationHashP h_denom_pub;
|
|
||||||
const struct TALER_EXCHANGE_DenomPublicKey *dki;
|
|
||||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct TALER_Amount remaining;
|
||||||
GNUNET_JSON_spec_fixed_auto ("coin_pub",
|
|
||||||
&coin_pub),
|
|
||||||
GNUNET_JSON_spec_json ("history",
|
|
||||||
&history),
|
|
||||||
GNUNET_JSON_spec_end ()
|
|
||||||
};
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
const struct Coin *my_coin;
|
const struct Coin *my_coin;
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_JSON_parse (j,
|
TALER_EXCHANGE_check_coin_amount_conflict_ (
|
||||||
spec,
|
keys,
|
||||||
NULL, NULL))
|
j,
|
||||||
|
&coin_pub,
|
||||||
|
&remaining))
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
|
||||||
dr.hr.http_status = 0;
|
dr.hr.http_status = 0;
|
||||||
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
break;
|
break;
|
||||||
@ -334,45 +310,22 @@ handle_purse_deposit_finished (void *cls,
|
|||||||
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dki = TALER_EXCHANGE_get_denomination_key_by_hash (
|
if (1 == TALER_amount_cmp (&remaining,
|
||||||
keys,
|
&my_coin->contribution))
|
||||||
&my_coin->h_denom_pub);
|
|
||||||
if (NULL == dki)
|
|
||||||
{
|
|
||||||
dr.hr.http_status = 0;
|
|
||||||
dr.hr.ec = TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
TALER_EXCHANGE_verify_coin_history (dki,
|
|
||||||
dki->value.currency,
|
|
||||||
&coin_pub,
|
|
||||||
history,
|
|
||||||
&h_denom_pub,
|
|
||||||
&total))
|
|
||||||
{
|
{
|
||||||
|
/* transaction should have still fit */
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
dr.hr.http_status = 0;
|
dr.hr.http_status = 0;
|
||||||
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
json_decref (history);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
json_decref (history);
|
if (GNUNET_OK !=
|
||||||
if (0 >
|
TALER_EXCHANGE_check_coin_signature_conflict_ (
|
||||||
TALER_amount_add (&total,
|
j,
|
||||||
&total,
|
&my_coin->coin_sig))
|
||||||
&my_coin->contribution))
|
|
||||||
{
|
{
|
||||||
/* clearly not OK if our transaction would have caused
|
/* THIS transaction must not be in the conflicting history */
|
||||||
the overflow... */
|
GNUNET_break_op (0);
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (0 >= TALER_amount_cmp (&total,
|
|
||||||
&dki->value))
|
|
||||||
{
|
|
||||||
/* transaction should have still fit */
|
|
||||||
GNUNET_break (0);
|
|
||||||
dr.hr.http_status = 0;
|
dr.hr.http_status = 0;
|
||||||
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
break;
|
break;
|
||||||
@ -382,27 +335,18 @@ handle_purse_deposit_finished (void *cls,
|
|||||||
}
|
}
|
||||||
case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
|
case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
|
||||||
{
|
{
|
||||||
json_t *history;
|
|
||||||
struct TALER_Amount total;
|
|
||||||
struct TALER_DenominationHashP h_denom_pub;
|
|
||||||
const struct Coin *my_coin;
|
|
||||||
const struct TALER_EXCHANGE_DenomPublicKey *dki;
|
|
||||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct TALER_Amount remaining;
|
||||||
GNUNET_JSON_spec_fixed_auto ("coin_pub",
|
|
||||||
&coin_pub),
|
|
||||||
GNUNET_JSON_spec_json ("history",
|
|
||||||
&history),
|
|
||||||
GNUNET_JSON_spec_end ()
|
|
||||||
};
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
const struct Coin *my_coin;
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_JSON_parse (j,
|
TALER_EXCHANGE_check_coin_amount_conflict_ (
|
||||||
spec,
|
keys,
|
||||||
NULL, NULL))
|
j,
|
||||||
|
&coin_pub,
|
||||||
|
&remaining))
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
|
||||||
dr.hr.http_status = 0;
|
dr.hr.http_status = 0;
|
||||||
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
break;
|
break;
|
||||||
@ -425,31 +369,12 @@ handle_purse_deposit_finished (void *cls,
|
|||||||
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dki = TALER_EXCHANGE_get_denomination_key_by_hash (
|
|
||||||
keys,
|
|
||||||
&my_coin->h_denom_pub);
|
|
||||||
memset (&h_denom_pub,
|
|
||||||
0,
|
|
||||||
sizeof (h_denom_pub));
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_EXCHANGE_verify_coin_history (dki,
|
TALER_EXCHANGE_check_coin_denomination_conflict_ (
|
||||||
dki->value.currency,
|
j,
|
||||||
&coin_pub,
|
&my_coin->h_denom_pub))
|
||||||
history,
|
|
||||||
&h_denom_pub,
|
|
||||||
&total))
|
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
/* no conflicting denomination detected */
|
||||||
dr.hr.http_status = 0;
|
|
||||||
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
|
||||||
json_decref (history);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
json_decref (history);
|
|
||||||
if (0 == GNUNET_memcmp (&dki->h_key,
|
|
||||||
&h_denom_pub))
|
|
||||||
{
|
|
||||||
/* sorry, this proves nothing */
|
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
dr.hr.http_status = 0;
|
dr.hr.http_status = 0;
|
||||||
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
@ -562,7 +487,6 @@ TALER_EXCHANGE_purse_deposit (
|
|||||||
const struct TALER_EXCHANGE_PurseDeposit *deposit = &deposits[i];
|
const struct TALER_EXCHANGE_PurseDeposit *deposit = &deposits[i];
|
||||||
struct Coin *coin = &pch->coins[i];
|
struct Coin *coin = &pch->coins[i];
|
||||||
json_t *jdeposit;
|
json_t *jdeposit;
|
||||||
struct TALER_CoinSpendSignatureP coin_sig;
|
|
||||||
#if FIXME_OEC
|
#if FIXME_OEC
|
||||||
struct TALER_AgeCommitmentHash agh;
|
struct TALER_AgeCommitmentHash agh;
|
||||||
struct TALER_AgeCommitmentHash *aghp = NULL;
|
struct TALER_AgeCommitmentHash *aghp = NULL;
|
||||||
@ -593,7 +517,7 @@ TALER_EXCHANGE_purse_deposit (
|
|||||||
&pch->purse_pub,
|
&pch->purse_pub,
|
||||||
&deposit->amount,
|
&deposit->amount,
|
||||||
&deposit->coin_priv,
|
&deposit->coin_priv,
|
||||||
&coin_sig);
|
&coin->coin_sig);
|
||||||
jdeposit = GNUNET_JSON_PACK (
|
jdeposit = GNUNET_JSON_PACK (
|
||||||
#if FIXME_OEC
|
#if FIXME_OEC
|
||||||
GNUNET_JSON_pack_allow_null (
|
GNUNET_JSON_pack_allow_null (
|
||||||
@ -612,7 +536,7 @@ TALER_EXCHANGE_purse_deposit (
|
|||||||
GNUNET_JSON_pack_data_auto ("coin_pub",
|
GNUNET_JSON_pack_data_auto ("coin_pub",
|
||||||
&coin->coin_pub),
|
&coin->coin_pub),
|
||||||
GNUNET_JSON_pack_data_auto ("coin_sig",
|
GNUNET_JSON_pack_data_auto ("coin_sig",
|
||||||
&coin_sig));
|
&coin->coin_sig));
|
||||||
GNUNET_assert (0 ==
|
GNUNET_assert (0 ==
|
||||||
json_array_append_new (deposit_arr,
|
json_array_append_new (deposit_arr,
|
||||||
jdeposit));
|
jdeposit));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of TALER
|
||||||
Copyright (C) 2017-2021 Taler Systems SA
|
Copyright (C) 2017-2022 Taler Systems SA
|
||||||
|
|
||||||
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
|
||||||
@ -27,6 +27,7 @@
|
|||||||
#include <gnunet/gnunet_curl_lib.h>
|
#include <gnunet/gnunet_curl_lib.h>
|
||||||
#include "taler_json_lib.h"
|
#include "taler_json_lib.h"
|
||||||
#include "taler_exchange_service.h"
|
#include "taler_exchange_service.h"
|
||||||
|
#include "exchange_api_common.h"
|
||||||
#include "exchange_api_handle.h"
|
#include "exchange_api_handle.h"
|
||||||
#include "taler_signatures.h"
|
#include "taler_signatures.h"
|
||||||
#include "exchange_api_curl_defaults.h"
|
#include "exchange_api_curl_defaults.h"
|
||||||
@ -59,6 +60,11 @@ struct TALER_EXCHANGE_RecoupHandle
|
|||||||
*/
|
*/
|
||||||
struct TALER_EXCHANGE_DenomPublicKey pk;
|
struct TALER_EXCHANGE_DenomPublicKey pk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Our signature requesting the recoup.
|
||||||
|
*/
|
||||||
|
struct TALER_CoinSpendSignatureP coin_sig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle for the request.
|
* Handle for the request.
|
||||||
*/
|
*/
|
||||||
@ -139,8 +145,10 @@ handle_recoup_finished (void *cls,
|
|||||||
.reply = j,
|
.reply = j,
|
||||||
.http_status = (unsigned int) response_code
|
.http_status = (unsigned int) response_code
|
||||||
};
|
};
|
||||||
|
const struct TALER_EXCHANGE_Keys *keys;
|
||||||
|
|
||||||
ph->job = NULL;
|
ph->job = NULL;
|
||||||
|
keys = TALER_EXCHANGE_get_keys (ph->exchange);
|
||||||
switch (response_code)
|
switch (response_code)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -166,76 +174,34 @@ handle_recoup_finished (void *cls,
|
|||||||
break;
|
break;
|
||||||
case MHD_HTTP_CONFLICT:
|
case MHD_HTTP_CONFLICT:
|
||||||
{
|
{
|
||||||
/* Insufficient funds, proof attached */
|
struct TALER_Amount min_key;
|
||||||
json_t *history;
|
|
||||||
struct TALER_Amount total;
|
|
||||||
struct TALER_DenominationHashP h_denom_pub;
|
|
||||||
const struct TALER_EXCHANGE_DenomPublicKey *dki;
|
|
||||||
enum TALER_ErrorCode ec;
|
|
||||||
|
|
||||||
dki = &ph->pk;
|
hr.ec = TALER_JSON_get_error_code (j);
|
||||||
history = json_object_get (j,
|
hr.hint = TALER_JSON_get_error_hint (j);
|
||||||
"history");
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_EXCHANGE_verify_coin_history (dki,
|
TALER_EXCHANGE_get_min_denomination_ (keys,
|
||||||
dki->fees.deposit.currency,
|
&min_key))
|
||||||
&ph->coin_pub,
|
|
||||||
history,
|
|
||||||
&h_denom_pub,
|
|
||||||
&total))
|
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break (0);
|
||||||
hr.http_status = 0;
|
|
||||||
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hr.ec = TALER_JSON_get_error_code (j);
|
|
||||||
hr.hint = TALER_JSON_get_error_hint (j);
|
|
||||||
}
|
|
||||||
ec = TALER_JSON_get_error_code (j);
|
|
||||||
switch (ec)
|
|
||||||
{
|
|
||||||
case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
|
|
||||||
if (0 > TALER_amount_cmp (&total,
|
|
||||||
&dki->value))
|
|
||||||
{
|
|
||||||
/* recoup MAY have still been possible */
|
|
||||||
/* FIXME: This code may falsely complain, as we do not
|
|
||||||
know that the smallest denomination offered by the
|
|
||||||
exchange is here. We should look at the key
|
|
||||||
structure of ph->exchange, and find the smallest
|
|
||||||
_currently withdrawable_ denomination and check
|
|
||||||
if the value remaining would suffice... */
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
hr.http_status = 0;
|
|
||||||
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
|
|
||||||
if (0 == GNUNET_memcmp (&ph->pk.h_key,
|
|
||||||
&h_denom_pub))
|
|
||||||
{
|
|
||||||
/* invalid proof provided */
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
hr.http_status = 0;
|
|
||||||
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* valid error from exchange */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
hr.http_status = 0;
|
hr.http_status = 0;
|
||||||
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ph->cb (ph->cb_cls,
|
if (GNUNET_OK !=
|
||||||
&hr,
|
TALER_EXCHANGE_check_coin_conflict_ (
|
||||||
NULL);
|
keys,
|
||||||
TALER_EXCHANGE_recoup_cancel (ph);
|
j,
|
||||||
return;
|
&ph->pk,
|
||||||
|
&ph->coin_pub,
|
||||||
|
&ph->coin_sig,
|
||||||
|
&min_key))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
hr.http_status = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case MHD_HTTP_FORBIDDEN:
|
case MHD_HTTP_FORBIDDEN:
|
||||||
/* Nothing really to verify, exchange says one of the signatures is
|
/* Nothing really to verify, exchange says one of the signatures is
|
||||||
@ -291,8 +257,6 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
|
|||||||
{
|
{
|
||||||
struct TALER_EXCHANGE_RecoupHandle *ph;
|
struct TALER_EXCHANGE_RecoupHandle *ph;
|
||||||
struct GNUNET_CURL_Context *ctx;
|
struct GNUNET_CURL_Context *ctx;
|
||||||
struct TALER_CoinSpendSignatureP coin_sig;
|
|
||||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
|
||||||
struct TALER_DenominationHashP h_denom_pub;
|
struct TALER_DenominationHashP h_denom_pub;
|
||||||
json_t *recoup_obj;
|
json_t *recoup_obj;
|
||||||
CURL *eh;
|
CURL *eh;
|
||||||
@ -302,7 +266,7 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
|
|||||||
|
|
||||||
GNUNET_assert (GNUNET_YES ==
|
GNUNET_assert (GNUNET_YES ==
|
||||||
TEAH_handle_is_ready (exchange));
|
TEAH_handle_is_ready (exchange));
|
||||||
|
ph = GNUNET_new (struct TALER_EXCHANGE_RecoupHandle);
|
||||||
TALER_planchet_setup_coin_priv (ps,
|
TALER_planchet_setup_coin_priv (ps,
|
||||||
exchange_vals,
|
exchange_vals,
|
||||||
&coin_priv);
|
&coin_priv);
|
||||||
@ -310,13 +274,13 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
|
|||||||
exchange_vals,
|
exchange_vals,
|
||||||
&bks);
|
&bks);
|
||||||
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
|
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
|
||||||
&coin_pub.eddsa_pub);
|
&ph->coin_pub.eddsa_pub);
|
||||||
TALER_denom_pub_hash (&pk->key,
|
TALER_denom_pub_hash (&pk->key,
|
||||||
&h_denom_pub);
|
&h_denom_pub);
|
||||||
TALER_wallet_recoup_sign (&h_denom_pub,
|
TALER_wallet_recoup_sign (&h_denom_pub,
|
||||||
&bks,
|
&bks,
|
||||||
&coin_priv,
|
&coin_priv,
|
||||||
&coin_sig);
|
&ph->coin_sig);
|
||||||
recoup_obj = GNUNET_JSON_PACK (
|
recoup_obj = GNUNET_JSON_PACK (
|
||||||
GNUNET_JSON_pack_data_auto ("denom_pub_hash",
|
GNUNET_JSON_pack_data_auto ("denom_pub_hash",
|
||||||
&h_denom_pub),
|
&h_denom_pub),
|
||||||
@ -325,7 +289,7 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
|
|||||||
TALER_JSON_pack_exchange_withdraw_values ("ewv",
|
TALER_JSON_pack_exchange_withdraw_values ("ewv",
|
||||||
exchange_vals),
|
exchange_vals),
|
||||||
GNUNET_JSON_pack_data_auto ("coin_sig",
|
GNUNET_JSON_pack_data_auto ("coin_sig",
|
||||||
&coin_sig),
|
&ph->coin_sig),
|
||||||
GNUNET_JSON_pack_data_auto ("coin_blind_key_secret",
|
GNUNET_JSON_pack_data_auto ("coin_blind_key_secret",
|
||||||
&bks));
|
&bks));
|
||||||
if (TALER_DENOMINATION_CS == denom_sig->cipher)
|
if (TALER_DENOMINATION_CS == denom_sig->cipher)
|
||||||
@ -352,7 +316,7 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
|
|||||||
char *end;
|
char *end;
|
||||||
|
|
||||||
end = GNUNET_STRINGS_data_to_string (
|
end = GNUNET_STRINGS_data_to_string (
|
||||||
&coin_pub,
|
&ph->coin_pub,
|
||||||
sizeof (struct TALER_CoinSpendPublicKeyP),
|
sizeof (struct TALER_CoinSpendPublicKeyP),
|
||||||
pub_str,
|
pub_str,
|
||||||
sizeof (pub_str));
|
sizeof (pub_str));
|
||||||
@ -363,8 +327,6 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
|
|||||||
pub_str);
|
pub_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
ph = GNUNET_new (struct TALER_EXCHANGE_RecoupHandle);
|
|
||||||
ph->coin_pub = coin_pub;
|
|
||||||
ph->exchange = exchange;
|
ph->exchange = exchange;
|
||||||
ph->pk = *pk;
|
ph->pk = *pk;
|
||||||
memset (&ph->pk.key,
|
memset (&ph->pk.key,
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <gnunet/gnunet_curl_lib.h>
|
#include <gnunet/gnunet_curl_lib.h>
|
||||||
#include "taler_json_lib.h"
|
#include "taler_json_lib.h"
|
||||||
#include "taler_exchange_service.h"
|
#include "taler_exchange_service.h"
|
||||||
|
#include "exchange_api_common.h"
|
||||||
#include "exchange_api_handle.h"
|
#include "exchange_api_handle.h"
|
||||||
#include "taler_signatures.h"
|
#include "taler_signatures.h"
|
||||||
#include "exchange_api_curl_defaults.h"
|
#include "exchange_api_curl_defaults.h"
|
||||||
@ -79,6 +80,11 @@ struct TALER_EXCHANGE_RecoupRefreshHandle
|
|||||||
*/
|
*/
|
||||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature affirming the recoup-refresh operation.
|
||||||
|
*/
|
||||||
|
struct TALER_CoinSpendSignatureP coin_sig;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -140,8 +146,10 @@ handle_recoup_refresh_finished (void *cls,
|
|||||||
.reply = j,
|
.reply = j,
|
||||||
.http_status = (unsigned int) response_code
|
.http_status = (unsigned int) response_code
|
||||||
};
|
};
|
||||||
|
const struct TALER_EXCHANGE_Keys *keys;
|
||||||
|
|
||||||
ph->job = NULL;
|
ph->job = NULL;
|
||||||
|
keys = TALER_EXCHANGE_get_keys (ph->exchange);
|
||||||
switch (response_code)
|
switch (response_code)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -180,76 +188,34 @@ handle_recoup_refresh_finished (void *cls,
|
|||||||
break;
|
break;
|
||||||
case MHD_HTTP_CONFLICT:
|
case MHD_HTTP_CONFLICT:
|
||||||
{
|
{
|
||||||
/* Insufficient funds, proof attached */
|
struct TALER_Amount min_key;
|
||||||
json_t *history;
|
|
||||||
struct TALER_Amount total;
|
|
||||||
struct TALER_DenominationHashP h_denom_pub;
|
|
||||||
const struct TALER_EXCHANGE_DenomPublicKey *dki;
|
|
||||||
enum TALER_ErrorCode ec;
|
|
||||||
|
|
||||||
dki = &ph->pk;
|
hr.ec = TALER_JSON_get_error_code (j);
|
||||||
history = json_object_get (j,
|
hr.hint = TALER_JSON_get_error_hint (j);
|
||||||
"history");
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_EXCHANGE_verify_coin_history (dki,
|
TALER_EXCHANGE_get_min_denomination_ (keys,
|
||||||
dki->fees.deposit.currency,
|
&min_key))
|
||||||
&ph->coin_pub,
|
|
||||||
history,
|
|
||||||
&h_denom_pub,
|
|
||||||
&total))
|
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break (0);
|
||||||
hr.http_status = 0;
|
|
||||||
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hr.ec = TALER_JSON_get_error_code (j);
|
|
||||||
hr.hint = TALER_JSON_get_error_hint (j);
|
|
||||||
}
|
|
||||||
ec = TALER_JSON_get_error_code (j);
|
|
||||||
switch (ec)
|
|
||||||
{
|
|
||||||
case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
|
|
||||||
if (0 > TALER_amount_cmp (&total,
|
|
||||||
&dki->value))
|
|
||||||
{
|
|
||||||
/* recoup MAY have still been possible */
|
|
||||||
/* FIXME: This code may falsely complain, as we do not
|
|
||||||
know that the smallest denomination offered by the
|
|
||||||
exchange is here. We should look at the key
|
|
||||||
structure of ph->exchange, and find the smallest
|
|
||||||
_currently withdrawable_ denomination and check
|
|
||||||
if the value remaining would suffice... */
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
hr.http_status = 0;
|
|
||||||
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
|
|
||||||
if (0 == GNUNET_memcmp (&ph->pk.h_key,
|
|
||||||
&h_denom_pub))
|
|
||||||
{
|
|
||||||
/* invalid proof provided */
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
hr.http_status = 0;
|
|
||||||
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* valid error from exchange */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
hr.http_status = 0;
|
hr.http_status = 0;
|
||||||
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ph->cb (ph->cb_cls,
|
if (GNUNET_OK !=
|
||||||
&hr,
|
TALER_EXCHANGE_check_coin_conflict_ (
|
||||||
NULL);
|
keys,
|
||||||
TALER_EXCHANGE_recoup_refresh_cancel (ph);
|
j,
|
||||||
return;
|
&ph->pk,
|
||||||
|
&ph->coin_pub,
|
||||||
|
&ph->coin_sig,
|
||||||
|
&min_key))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
hr.http_status = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case MHD_HTTP_GONE:
|
case MHD_HTTP_GONE:
|
||||||
/* Kind of normal: the money was already sent to the merchant
|
/* Kind of normal: the money was already sent to the merchant
|
||||||
@ -295,8 +261,6 @@ TALER_EXCHANGE_recoup_refresh (
|
|||||||
{
|
{
|
||||||
struct TALER_EXCHANGE_RecoupRefreshHandle *ph;
|
struct TALER_EXCHANGE_RecoupRefreshHandle *ph;
|
||||||
struct GNUNET_CURL_Context *ctx;
|
struct GNUNET_CURL_Context *ctx;
|
||||||
struct TALER_CoinSpendSignatureP coin_sig;
|
|
||||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
|
||||||
struct TALER_DenominationHashP h_denom_pub;
|
struct TALER_DenominationHashP h_denom_pub;
|
||||||
json_t *recoup_obj;
|
json_t *recoup_obj;
|
||||||
CURL *eh;
|
CURL *eh;
|
||||||
@ -307,6 +271,14 @@ TALER_EXCHANGE_recoup_refresh (
|
|||||||
GNUNET_assert (NULL != recoup_cb);
|
GNUNET_assert (NULL != recoup_cb);
|
||||||
GNUNET_assert (GNUNET_YES ==
|
GNUNET_assert (GNUNET_YES ==
|
||||||
TEAH_handle_is_ready (exchange));
|
TEAH_handle_is_ready (exchange));
|
||||||
|
ph = GNUNET_new (struct TALER_EXCHANGE_RecoupRefreshHandle);
|
||||||
|
ph->exchange = exchange;
|
||||||
|
ph->pk = *pk;
|
||||||
|
memset (&ph->pk.key,
|
||||||
|
0,
|
||||||
|
sizeof (ph->pk.key)); /* zero out, as lifetime cannot be warranted */
|
||||||
|
ph->cb = recoup_cb;
|
||||||
|
ph->cb_cls = recoup_cb_cls;
|
||||||
TALER_planchet_setup_coin_priv (ps,
|
TALER_planchet_setup_coin_priv (ps,
|
||||||
exchange_vals,
|
exchange_vals,
|
||||||
&coin_priv);
|
&coin_priv);
|
||||||
@ -314,13 +286,13 @@ TALER_EXCHANGE_recoup_refresh (
|
|||||||
exchange_vals,
|
exchange_vals,
|
||||||
&bks);
|
&bks);
|
||||||
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
|
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
|
||||||
&coin_pub.eddsa_pub);
|
&ph->coin_pub.eddsa_pub);
|
||||||
TALER_denom_pub_hash (&pk->key,
|
TALER_denom_pub_hash (&pk->key,
|
||||||
&h_denom_pub);
|
&h_denom_pub);
|
||||||
TALER_wallet_recoup_refresh_sign (&h_denom_pub,
|
TALER_wallet_recoup_refresh_sign (&h_denom_pub,
|
||||||
&bks,
|
&bks,
|
||||||
&coin_priv,
|
&coin_priv,
|
||||||
&coin_sig);
|
&ph->coin_sig);
|
||||||
recoup_obj = GNUNET_JSON_PACK (
|
recoup_obj = GNUNET_JSON_PACK (
|
||||||
GNUNET_JSON_pack_data_auto ("denom_pub_hash",
|
GNUNET_JSON_pack_data_auto ("denom_pub_hash",
|
||||||
&h_denom_pub),
|
&h_denom_pub),
|
||||||
@ -329,7 +301,7 @@ TALER_EXCHANGE_recoup_refresh (
|
|||||||
TALER_JSON_pack_exchange_withdraw_values ("ewv",
|
TALER_JSON_pack_exchange_withdraw_values ("ewv",
|
||||||
exchange_vals),
|
exchange_vals),
|
||||||
GNUNET_JSON_pack_data_auto ("coin_sig",
|
GNUNET_JSON_pack_data_auto ("coin_sig",
|
||||||
&coin_sig),
|
&ph->coin_sig),
|
||||||
GNUNET_JSON_pack_data_auto ("coin_blind_key_secret",
|
GNUNET_JSON_pack_data_auto ("coin_blind_key_secret",
|
||||||
&bks));
|
&bks));
|
||||||
|
|
||||||
@ -358,7 +330,7 @@ TALER_EXCHANGE_recoup_refresh (
|
|||||||
char *end;
|
char *end;
|
||||||
|
|
||||||
end = GNUNET_STRINGS_data_to_string (
|
end = GNUNET_STRINGS_data_to_string (
|
||||||
&coin_pub,
|
&ph->coin_pub,
|
||||||
sizeof (struct TALER_CoinSpendPublicKeyP),
|
sizeof (struct TALER_CoinSpendPublicKeyP),
|
||||||
pub_str,
|
pub_str,
|
||||||
sizeof (pub_str));
|
sizeof (pub_str));
|
||||||
@ -369,15 +341,6 @@ TALER_EXCHANGE_recoup_refresh (
|
|||||||
pub_str);
|
pub_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
ph = GNUNET_new (struct TALER_EXCHANGE_RecoupRefreshHandle);
|
|
||||||
ph->coin_pub = coin_pub;
|
|
||||||
ph->exchange = exchange;
|
|
||||||
ph->pk = *pk;
|
|
||||||
memset (&ph->pk.key,
|
|
||||||
0,
|
|
||||||
sizeof (ph->pk.key)); /* zero out, as lifetime cannot be warranted */
|
|
||||||
ph->cb = recoup_cb;
|
|
||||||
ph->cb_cls = recoup_cb_cls;
|
|
||||||
ph->url = TEAH_path_to_url (exchange,
|
ph->url = TEAH_path_to_url (exchange,
|
||||||
arg_str);
|
arg_str);
|
||||||
if (NULL == ph->url)
|
if (NULL == ph->url)
|
||||||
|
@ -173,9 +173,12 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
|
|||||||
const json_t *json)
|
const json_t *json)
|
||||||
{
|
{
|
||||||
json_t *history;
|
json_t *history;
|
||||||
|
struct TALER_DenominationHashP h_denom_pub;
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
GNUNET_JSON_spec_json ("history",
|
GNUNET_JSON_spec_json ("history",
|
||||||
&history),
|
&history),
|
||||||
|
GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
|
||||||
|
&h_denom_pub),
|
||||||
GNUNET_JSON_spec_end ()
|
GNUNET_JSON_spec_end ()
|
||||||
};
|
};
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -234,7 +237,6 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
|
|||||||
struct TALER_AgeCommitmentHash h_age_commitment;
|
struct TALER_AgeCommitmentHash h_age_commitment;
|
||||||
bool no_hac;
|
bool no_hac;
|
||||||
// struct TALER_ExtensionContractHashP h_extensions; // FIXME!
|
// struct TALER_ExtensionContractHashP h_extensions; // FIXME!
|
||||||
struct TALER_DenominationHashP h_denom_pub;
|
|
||||||
struct GNUNET_TIME_Timestamp wallet_timestamp;
|
struct GNUNET_TIME_Timestamp wallet_timestamp;
|
||||||
struct TALER_MerchantPublicKeyP merchant_pub;
|
struct TALER_MerchantPublicKeyP merchant_pub;
|
||||||
struct GNUNET_TIME_Timestamp refund_deadline;
|
struct GNUNET_TIME_Timestamp refund_deadline;
|
||||||
@ -246,8 +248,6 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
|
|||||||
&h_contract_terms),
|
&h_contract_terms),
|
||||||
GNUNET_JSON_spec_fixed_auto ("h_wire",
|
GNUNET_JSON_spec_fixed_auto ("h_wire",
|
||||||
&h_wire),
|
&h_wire),
|
||||||
GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
|
|
||||||
&h_denom_pub),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
GNUNET_JSON_spec_mark_optional (
|
||||||
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
|
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
|
||||||
&h_age_commitment),
|
&h_age_commitment),
|
||||||
@ -429,24 +429,22 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (have_refund)
|
||||||
{
|
{
|
||||||
if (have_refund)
|
if (0 >
|
||||||
|
TALER_amount_add (&rtotal,
|
||||||
|
&rtotal,
|
||||||
|
&rh->refund_amount))
|
||||||
{
|
{
|
||||||
if (0 >
|
GNUNET_break (0);
|
||||||
TALER_amount_add (&rtotal,
|
GNUNET_JSON_parse_free (spec);
|
||||||
&rtotal,
|
return GNUNET_SYSERR;
|
||||||
&rh->refund_amount))
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
GNUNET_JSON_parse_free (spec);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rtotal = rh->refund_amount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rtotal = rh->refund_amount;
|
||||||
|
}
|
||||||
if (-1 == TALER_amount_cmp (&dtotal,
|
if (-1 == TALER_amount_cmp (&dtotal,
|
||||||
&rtotal))
|
&rtotal))
|
||||||
{
|
{
|
||||||
|
@ -257,7 +257,7 @@ deposit_cb (void *cls,
|
|||||||
__LINE__);
|
__LINE__);
|
||||||
json_dumpf (dr->hr.reply,
|
json_dumpf (dr->hr.reply,
|
||||||
stderr,
|
stderr,
|
||||||
0);
|
JSON_INDENT (2));
|
||||||
TALER_TESTING_interpreter_fail (ds->is);
|
TALER_TESTING_interpreter_fail (ds->is);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,7 @@ deposit_cb (void *cls,
|
|||||||
__LINE__);
|
__LINE__);
|
||||||
json_dumpf (dr->hr.reply,
|
json_dumpf (dr->hr.reply,
|
||||||
stderr,
|
stderr,
|
||||||
0);
|
JSON_INDENT (2));
|
||||||
TALER_TESTING_interpreter_fail (ds->is);
|
TALER_TESTING_interpreter_fail (ds->is);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user