implement rest of exchange logic for #3887 (return payback information in reserve and coin histories)

This commit is contained in:
Christian Grothoff 2017-04-03 16:40:31 +02:00
parent 5b867c4b8e
commit 29a2f9b345
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
9 changed files with 185 additions and 70 deletions

View File

@ -94,13 +94,13 @@ verify_payback_signature_ok (const struct TALER_EXCHANGE_PaybackHandle *ph,
struct TALER_ExchangePublicKeyP exchange_pub;
struct TALER_ExchangeSignatureP exchange_sig;
struct TALER_Amount amount;
struct GNUNET_TIME_Absolute deadline;
struct GNUNET_TIME_Absolute timestamp;
const struct TALER_EXCHANGE_Keys *key_state;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", &exchange_pub),
TALER_JSON_spec_amount ("amount", &amount),
GNUNET_JSON_spec_absolute_time ("payback_deadline", &deadline),
GNUNET_JSON_spec_absolute_time ("timestamp", &timestamp),
GNUNET_JSON_spec_fixed_auto ("reserve_pub", &pc.reserve_pub),
GNUNET_JSON_spec_end()
};
@ -123,7 +123,7 @@ verify_payback_signature_ok (const struct TALER_EXCHANGE_PaybackHandle *ph,
}
pc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK);
pc.purpose.size = htonl (sizeof (pc));
pc.payback_deadline = GNUNET_TIME_absolute_hton (deadline);
pc.timestamp = GNUNET_TIME_absolute_hton (timestamp);
TALER_amount_hton (&pc.payback_amount,
&amount);
pc.coin_pub = ph->coin_pub;
@ -140,7 +140,7 @@ verify_payback_signature_ok (const struct TALER_EXCHANGE_PaybackHandle *ph,
MHD_HTTP_OK,
TALER_EC_NONE,
&amount,
deadline,
timestamp,
&pc.reserve_pub,
json);
return GNUNET_OK;

View File

@ -2335,7 +2335,7 @@ TEH_DB_execute_payback (struct MHD_Connection *connection,
struct TALER_ReservePublicKeyP reserve_pub;
struct TALER_Amount amount;
struct TALER_Amount spent;
struct GNUNET_TIME_Absolute payback_deadline;
struct GNUNET_TIME_Absolute now;
if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{
@ -2406,6 +2406,8 @@ TEH_DB_execute_payback (struct MHD_Connection *connection,
}
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl);
now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now);
/* add coin to list of wire transfers for payback */
ret = TEH_plugin->insert_payback_request (TEH_plugin->cls,
@ -2416,7 +2418,7 @@ TEH_DB_execute_payback (struct MHD_Connection *connection,
coin_blind,
&amount,
h_blind,
&payback_deadline);
now);
if (GNUNET_SYSERR == ret)
{
TALER_LOG_WARNING ("Failed to store /payback information in database\n");
@ -2432,7 +2434,7 @@ TEH_DB_execute_payback (struct MHD_Connection *connection,
&coin->coin_pub,
&reserve_pub,
&amount,
payback_deadline);
now);
}

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014, 2015, 2016, 2017 Inria & GNUnet e.V.
Copyright (C) 2014-2017 Inria & GNUnet e.V.
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
@ -554,32 +554,34 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
case TALER_EXCHANGEDB_TT_PAYBACK:
{
const struct TALER_EXCHANGEDB_Payback *payback = pos->details.payback;
struct TALER_PaybackRequestPS pr;
struct TALER_PaybackConfirmationPS pc;
struct TALER_ExchangePublicKeyP epub;
struct TALER_ExchangeSignatureP esig;
type = "PAYBACK";
value = payback->value;
pr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_PAYBACK);
pr.purpose.size = htonl (sizeof (pr));
pr.coin_pub = payback->coin_pub;
GNUNET_CRYPTO_rsa_public_key_hash (payback->denom_pub.rsa_public_key,
&pr.h_denom_pub);
pr.coin_blind = payback->coin_blind;
/* internal sanity check before we hand out a bogus sig... */
sig = &payback->coin_sig.eddsa_signature;
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_PAYBACK,
&pr.purpose,
sig,
&payback->coin_pub.eddsa_pub))
{
GNUNET_break (0);
json_decref (history);
return NULL;
}
details = GNUNET_JSON_from_data_auto (&pr);
pc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK);
pc.purpose.size = htonl (sizeof (pc));
pc.timestamp = GNUNET_TIME_absolute_hton (payback->timestamp);
TALER_amount_hton (&pc.payback_amount,
&payback->value);
pc.coin_pub = payback->coin_pub;
pc.reserve_pub = payback->reserve_pub;
TEH_KS_sign (&pc.purpose,
&epub,
&esig);
details = GNUNET_JSON_from_data_auto (&pc);
GNUNET_assert (0 ==
json_array_append_new (history,
json_pack ("{s:s, s:o, s:o, s:o, s:o}",
"type", type,
"amount", TALER_JSON_from_amount (&value),
"exchange_sig", GNUNET_JSON_from_data_auto (&esig),
"exchange_pub", GNUNET_JSON_from_data_auto (&epub),
"details", details)));
}
break;
/* do not go to the default handler, we already appended! */
continue;
default:
GNUNET_assert (0);
}
@ -646,6 +648,11 @@ compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHistory *rh,
int ret;
const struct TALER_EXCHANGEDB_ReserveHistory *pos;
struct TALER_WithdrawRequestPS wr;
const struct TALER_EXCHANGEDB_Payback *payback;
struct TALER_PaybackConfirmationPS pc;
struct TALER_ReserveCloseConfirmationPS rcc;
struct TALER_ExchangePublicKeyP pub;
struct TALER_ExchangeSignatureP sig;
json_history = json_array ();
ret = 0;
@ -654,7 +661,7 @@ compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHistory *rh,
switch (pos->type)
{
case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
if (0 == ret)
if (0 == (1 & ret))
deposit_total = pos->details.bank->amount;
else
if (GNUNET_OK !=
@ -665,7 +672,7 @@ compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHistory *rh,
json_decref (json_history);
return NULL;
}
ret = 1;
ret |= 1;
GNUNET_assert (0 ==
json_array_append_new (json_history,
json_pack ("{s:s, s:O, s:O, s:o}",
@ -674,21 +681,9 @@ compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHistory *rh,
"transfer_details", pos->details.bank->transfer_details,
"amount", TALER_JSON_from_amount (&pos->details.bank->amount))));
break;
case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
break;
}
}
ret = 0;
for (pos = rh; NULL != pos; pos = pos->next)
{
switch (pos->type)
{
case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
break;
case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
value = pos->details.withdraw->amount_with_fee;
if (0 == ret)
if (0 == (2 & ret))
{
withdraw_total = value;
}
@ -703,7 +698,7 @@ compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHistory *rh,
return NULL;
}
}
ret = 1;
ret |= 2;
wr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
wr.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS));
wr.reserve_pub = pos->details.withdraw->reserve_pub;
@ -720,11 +715,91 @@ compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHistory *rh,
"type", "WITHDRAW",
"signature", GNUNET_JSON_from_data_auto (&pos->details.withdraw->reserve_sig),
"details", GNUNET_JSON_from_data_auto (&wr),
"amount", TALER_JSON_from_amount (&value))));
break;
case TALER_EXCHANGEDB_RO_PAYBACK_COIN:
payback = pos->details.payback;
if (0 == (1 & ret))
deposit_total = payback->value;
else
if (GNUNET_OK !=
TALER_amount_add (&deposit_total,
&deposit_total,
&payback->value))
{
json_decref (json_history);
return NULL;
}
ret |= 1;
pc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK);
pc.purpose.size = htonl (sizeof (struct TALER_PaybackConfirmationPS));
pc.timestamp = GNUNET_TIME_absolute_hton (payback->timestamp);
TALER_amount_hton (&pc.payback_amount,
&payback->value);
pc.coin_pub = payback->coin_pub;
pc.reserve_pub = payback->reserve_pub;
TEH_KS_sign (&pc.purpose,
&pub,
&sig);
GNUNET_assert (0 ==
json_array_append_new (json_history,
json_pack ("{s:s, s:o, s:o, s:o, s:o}",
"type", "PAYBACK",
"exchange_pub", GNUNET_JSON_from_data_auto (&pub),
"exchange_sig", GNUNET_JSON_from_data_auto (&sig),
"timestamp", GNUNET_JSON_from_time_abs (payback->timestamp),
"amount", TALER_JSON_from_amount (&payback->value))));
break;
case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK:
value = pos->details.bank->amount;
if (0 == (2 & ret))
{
withdraw_total = value;
}
else
{
if (GNUNET_OK !=
TALER_amount_add (&withdraw_total,
&withdraw_total,
&value))
{
json_decref (json_history);
return NULL;
}
}
ret |= 2;
rcc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED);
rcc.purpose.size = htonl (sizeof (struct TALER_ReserveCloseConfirmationPS));
rcc.timestamp = GNUNET_TIME_absolute_hton (pos->details.bank->execution_date);
TALER_amount_hton (&rcc.closing_amount,
&value);
rcc.reserve_pub = pos->details.bank->reserve_pub;
TALER_JSON_hash (pos->details.bank->sender_account_details,
&rcc.h_wire);
TEH_KS_sign (&rcc.purpose,
&pub,
&sig);
GNUNET_assert (0 ==
json_array_append_new (json_history,
json_pack ("{s:s, s:o, s:o, s:o, s:o}",
"type", "CLOSING",
"exchange_pub", GNUNET_JSON_from_data_auto (&pub),
"exchange_sig", GNUNET_JSON_from_data_auto (&sig),
"details", GNUNET_JSON_from_data_auto (&rcc),
"amount", TALER_JSON_from_amount (&value))));
break;
}
}
if (0 == ret)
if (0 == (1 & ret))
{
GNUNET_break (0);
json_decref (json_history);
return NULL;
}
if (0 == (2 & ret))
{
/* did not encounter any withdraw operations, set to zero */
TALER_amount_get_zero (deposit_total.currency,
@ -1352,7 +1427,7 @@ TEH_RESPONSE_reply_payback_unknown (struct MHD_Connection *connection,
* @param coin_pub coin for which we are processing the payback request
* @param reserve_pub public key of the reserve that will receive the payback
* @param amount the amount we will wire back
* @param payback_deadline deadline by which the exchange promises to pay
* @param timestamp when did the exchange receive the /payback request
* @return MHD result code
*/
int
@ -1360,7 +1435,7 @@ TEH_RESPONSE_reply_payback_success (struct MHD_Connection *connection,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *amount,
struct GNUNET_TIME_Absolute payback_deadline)
struct GNUNET_TIME_Absolute timestamp)
{
struct TALER_PaybackConfirmationPS pc;
struct TALER_ExchangePublicKeyP pub;
@ -1368,7 +1443,7 @@ TEH_RESPONSE_reply_payback_success (struct MHD_Connection *connection,
pc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK);
pc.purpose.size = htonl (sizeof (struct TALER_PaybackConfirmationPS));
pc.payback_deadline = GNUNET_TIME_absolute_hton (payback_deadline);
pc.timestamp = GNUNET_TIME_absolute_hton (timestamp);
TALER_amount_hton (&pc.payback_amount,
amount);
pc.coin_pub = *coin_pub;
@ -1380,7 +1455,7 @@ TEH_RESPONSE_reply_payback_success (struct MHD_Connection *connection,
MHD_HTTP_OK,
"{s:o, s:o, s:o, s:o, s:o}",
"reserve_pub", GNUNET_JSON_from_data_auto (reserve_pub),
"payback_deadline", GNUNET_JSON_from_time_abs (payback_deadline),
"timestamp", GNUNET_JSON_from_time_abs (timestamp),
"amount", TALER_JSON_from_amount (amount),
"exchange_sig", GNUNET_JSON_from_data_auto (&sig),
"exchange_pub", GNUNET_JSON_from_data_auto (&pub));

View File

@ -579,7 +579,7 @@ TEH_RESPONSE_reply_payback_unknown (struct MHD_Connection *connection,
* @param coin_pub coin for which we are processing the payback request
* @param reserve_pub public key of the reserve that will receive the payback
* @param amount the amount we will wire back
* @param payback_deadline deadline by which the exchange promises to pay
* @param timestamp when did the exchange receive the /payback request
* @return MHD result code
*/
int
@ -587,7 +587,7 @@ TEH_RESPONSE_reply_payback_success (struct MHD_Connection *connection,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *amount,
struct GNUNET_TIME_Absolute payback_deadline);
struct GNUNET_TIME_Absolute timestamp);
#endif

View File

@ -5629,7 +5629,7 @@ postgres_select_wire_out_above_serial_id (void *cls,
* @param amount total amount to be paid back
* @param receiver_account_details who should receive the funds
* @parma h_blind_ev hash of the blinded coin's envelope (must match reserves_out entry)
* @param[out] deadline set to absolute time by when the exchange plans to pay it back
* @param timestamp current time (rounded)
* @return #GNUNET_OK on success,
* #GNUNET_SYSERR on DB errors
*/
@ -5642,10 +5642,9 @@ postgres_insert_payback_request (void *cls,
const struct TALER_DenominationBlindingKeyP *coin_blind,
const struct TALER_Amount *amount,
const struct GNUNET_HashCode *h_blind_ev,
struct GNUNET_TIME_Absolute *deadline)
struct GNUNET_TIME_Absolute timestamp)
{
PGresult *result;
struct GNUNET_TIME_Absolute now;
struct GNUNET_TIME_Absolute expiry;
struct TALER_EXCHANGEDB_Reserve reserve;
struct GNUNET_PQ_QueryParam params[] = {
@ -5654,12 +5653,11 @@ postgres_insert_payback_request (void *cls,
GNUNET_PQ_query_param_auto_from_type (coin_sig),
GNUNET_PQ_query_param_auto_from_type (coin_blind),
TALER_PQ_query_param_amount (amount),
GNUNET_PQ_query_param_absolute_time (&now),
GNUNET_PQ_query_param_absolute_time (&timestamp),
GNUNET_PQ_query_param_auto_from_type (h_blind_ev),
GNUNET_PQ_query_param_end
};
now = GNUNET_TIME_absolute_get ();
result = GNUNET_PQ_exec_prepared (session->conn,
"payback_insert",
params);
@ -5689,7 +5687,7 @@ postgres_insert_payback_request (void *cls,
GNUNET_break (0);
return GNUNET_SYSERR;
}
expiry = GNUNET_TIME_absolute_add (now,
expiry = GNUNET_TIME_absolute_add (timestamp,
TALER_IDLE_RESERVE_EXPIRATION_TIME);
reserve.expiry = GNUNET_TIME_absolute_max (expiry,
reserve.expiry);
@ -5700,7 +5698,6 @@ postgres_insert_payback_request (void *cls,
GNUNET_break (0);
return GNUNET_SYSERR;
}
*deadline = reserve.expiry;
return GNUNET_OK;
}

View File

@ -1511,6 +1511,7 @@ run (void *cls)
RND_BLK (&coin_sig);
RND_BLK (&coin_blind);
deadline = GNUNET_TIME_absolute_get ();
FAILIF (GNUNET_OK !=
plugin->insert_payback_request (plugin->cls,
session,
@ -1520,7 +1521,7 @@ run (void *cls)
&coin_blind,
&value,
&cbc.h_coin_envelope,
&deadline));
deadline));
result = 7;
rh = plugin->get_reserve_history (plugin->cls,
@ -1719,7 +1720,7 @@ run (void *cls)
&coin_blind,
&value,
&cbc.h_coin_envelope,
&deadline));
deadline));
auditor_row_cnt = 0;
FAILIF (GNUNET_OK !=

View File

@ -1344,7 +1344,7 @@ struct TALER_EXCHANGE_PaybackHandle;
* 0 if the exchange's reply is bogus (fails to follow the protocol)
* @param ec taler-specific error code, #TALER_EC_NONE on success
* @param amount amount the exchange will wire back for this coin
* @param deadline by when will the exchange wire the funds?
* @param timestamp what time did the exchange receive the /payback request
* @param reserve_pub public key of the reserve receiving the payback
* @param full_response full response from the exchange (for logging, in case of errors)
*/
@ -1353,7 +1353,7 @@ typedef void
unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_Amount *amount,
struct GNUNET_TIME_Absolute deadline,
struct GNUNET_TIME_Absolute timestamp,
const struct TALER_ReservePublicKeyP *reserve_pub,
const json_t *full_response);

View File

@ -1956,7 +1956,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param amount total amount to be paid back
* @param receiver_account_details who should receive the funds
* @parma h_blind_ev hash of the blinded coin's envelope (must match reserves_out entry)
* @param[out] deadline set to absolute time by when the exchange plans to pay it back
* @param now timestamp to store
* @return #GNUNET_OK on success,
* #GNUNET_SYSERR on DB errors
*/
@ -1969,7 +1969,7 @@ struct TALER_EXCHANGEDB_Plugin
const struct TALER_DenominationBlindingKeyP *coin_blind,
const struct TALER_Amount *amount,
const struct GNUNET_HashCode *h_blind_ev,
struct GNUNET_TIME_Absolute *deadline);
struct GNUNET_TIME_Absolute timestamp);
/**

View File

@ -131,6 +131,11 @@
*/
#define TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK 1039
/**
* Signature where the Exchange confirms it closed a reserve.
*/
#define TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED 1040
/*********************/
/* Wallet signatures */
@ -1170,15 +1175,16 @@ struct TALER_PaybackConfirmationPS
{
/**
* Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK
* Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
* By what deadline does the exchange promise to initiate
* the wire transfer?
* When did the exchange receive the payback request?
* Indirectly determines when the wire transfer is (likely)
* to happen.
*/
struct GNUNET_TIME_AbsoluteNBO payback_deadline;
struct GNUNET_TIME_AbsoluteNBO timestamp;
/**
* How much of the coin's value will the exchange transfer?
@ -1198,6 +1204,40 @@ struct TALER_PaybackConfirmationPS
};
/**
* Response by which the exchange affirms that it has
* closed a reserve and send back the funds.
*/
struct TALER_ReserveCloseConfirmationPS
{
/**
* Purpose is #TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
* When did the exchange initiate the wire transfer.
*/
struct GNUNET_TIME_AbsoluteNBO timestamp;
/**
* How much did the exchange send?
*/
struct TALER_AmountNBO closing_amount;
/**
* Public key of the reserve that received the payback.
*/
struct TALER_ReservePublicKeyP reserve_pub;
/**
* Hash of the receiver's bank account.
*/
struct GNUNET_HashCode h_wire;
};
GNUNET_NETWORK_STRUCT_END
#endif