complete taler-exchange-httpd_reserves_open.c logic (first pass, still without DB logic or tests)

This commit is contained in:
Christian Grothoff 2022-10-02 22:47:28 +02:00
parent de657800a8
commit 4a36ed7fbf
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
5 changed files with 152 additions and 41 deletions

View File

@ -83,6 +83,11 @@ struct ReserveOpenContext
*/ */
struct TALER_Amount open_cost; struct TALER_Amount open_cost;
/**
* Total amount that was deposited.
*/
struct TALER_Amount total;
/** /**
* Information about payments by coin. * Information about payments by coin.
*/ */
@ -111,9 +116,16 @@ static MHD_RESULT
reply_reserve_open_success (struct MHD_Connection *connection, reply_reserve_open_success (struct MHD_Connection *connection,
const struct ReserveOpenContext *rsc) const struct ReserveOpenContext *rsc)
{ {
unsigned int status;
status = MHD_HTTP_OK;
if (GNUNET_TIME_timestamp_cmp (rsc->reserve_expiration,
<,
rsc->desired_expiration))
status = MHD_HTTP_PAYMENT_REQUIRED;
return TALER_MHD_REPLY_JSON_PACK ( return TALER_MHD_REPLY_JSON_PACK (
connection, connection,
MHD_HTTP_OK, status,
GNUNET_JSON_pack_timestamp ("reserve_expiration", GNUNET_JSON_pack_timestamp ("reserve_expiration",
rsc->reserve_expiration), rsc->reserve_expiration),
TALER_JSON_pack_amount ("open_cost", TALER_JSON_pack_amount ("open_cost",
@ -150,7 +162,7 @@ cleanup_rsc (struct ReserveOpenContext *rsc)
* @param cls a `struct ReserveOpenContext *` * @param cls a `struct ReserveOpenContext *`
* @param connection MHD request which triggered the transaction * @param connection MHD request which triggered the transaction
* @param[out] mhd_ret set to MHD response status for @a connection, * @param[out] mhd_ret set to MHD response status for @a connection,
* if transaction failed (!); unused * if transaction failed (!)
* @return transaction status * @return transaction status
*/ */
static enum GNUNET_DB_QueryStatus static enum GNUNET_DB_QueryStatus
@ -161,15 +173,63 @@ reserve_open_transaction (void *cls,
struct ReserveOpenContext *rsc = cls; struct ReserveOpenContext *rsc = cls;
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
(void) rsc; for (unsigned int i = 0; i<rsc->payments_len; i++)
#if 0 {
// FIXME: implement! struct TEH_PurseDepositedCoin *coin = &rsc->payments[i];
bool insufficient_funds = true;
qs = TEH_make_coin_known (&coin->cpi,
connection,
&coin->known_coin_id,
mhd_ret);
if (qs < 0)
return qs;
qs = TEH_plugin->insert_reserve_open_deposit (
TEH_plugin->cls,
&coin->cpi,
&coin->coin_sig,
coin->known_coin_id,
&coin->amount,
&rsc->reserve_sig,
&insufficient_funds);
/* 0 == qs is fine, then the coin was already
spent for this very operation as identified
by reserve_sig! */
if (qs < 0)
{
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
return qs;
GNUNET_break (0);
*mhd_ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_STORE_FAILED,
"insert_reserve_open_deposit");
return qs;
}
if (insufficient_funds)
{
*mhd_ret
= TEH_RESPONSE_reply_coin_insufficient_funds (
connection,
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
&coin->cpi.denom_pub_hash,
&coin->cpi.coin_pub);
return GNUNET_DB_STATUS_HARD_ERROR;
}
}
qs = TEH_plugin->do_reserve_open (TEH_plugin->cls, qs = TEH_plugin->do_reserve_open (TEH_plugin->cls,
/* inputs */
rsc->reserve_pub, rsc->reserve_pub,
...); &rsc->total,
#else rsc->purse_limit,
qs = GNUNET_DB_STATUS_HARD_ERROR; &rsc->reserve_sig,
#endif rsc->desired_expiration,
rsc->timestamp,
&rsc->gf->fees.account,
/* outputs */
&rsc->open_cost,
&rsc->reserve_expiration);
switch (qs) switch (qs)
{ {
case GNUNET_DB_STATUS_HARD_ERROR: case GNUNET_DB_STATUS_HARD_ERROR:
@ -178,7 +238,7 @@ reserve_open_transaction (void *cls,
= TALER_MHD_reply_with_error (connection, = TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED, TALER_EC_GENERIC_DB_FETCH_FAILED,
"get_reserve_open"); "do_reserve_open");
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
case GNUNET_DB_STATUS_SOFT_ERROR: case GNUNET_DB_STATUS_SOFT_ERROR:
return qs; return qs;
@ -258,6 +318,7 @@ TEH_handler_reserves_open (struct TEH_RequestContext *rc,
rsc.payments_len = json_array_size (payments); rsc.payments_len = json_array_size (payments);
rsc.payments = GNUNET_new_array (rsc.payments_len, rsc.payments = GNUNET_new_array (rsc.payments_len,
struct TEH_PurseDepositedCoin); struct TEH_PurseDepositedCoin);
rsc.total = rsc.reserve_payment;
for (unsigned int i = 0; i<rsc.payments_len; i++) for (unsigned int i = 0; i<rsc.payments_len; i++)
{ {
struct TEH_PurseDepositedCoin *coin = &rsc.payments[i]; struct TEH_PurseDepositedCoin *coin = &rsc.payments[i];
@ -280,6 +341,21 @@ TEH_handler_reserves_open (struct TEH_RequestContext *rc,
cleanup_rsc (&rsc); cleanup_rsc (&rsc);
return MHD_YES; /* failure */ return MHD_YES; /* failure */
} }
/* FIXME-DOLD: Alternatively, we could here add coin->amount_minus_fee and
thereby charge the deposit fee even when paying the reserve-open fee.
To be decided... */
if (0 >
TALER_amount_add (&rsc.total,
&rsc.total,
&coin->amount))
{
GNUNET_break (0);
cleanup_rsc (&rsc);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_FAILED_COMPUTE_AMOUNT,
NULL);
}
} }
{ {

View File

@ -3107,16 +3107,14 @@ TALER_wallet_reserve_open_verify (
* Sign to deposit coin to pay for keeping a reserve open. * Sign to deposit coin to pay for keeping a reserve open.
* *
* @param coin_contribution how much the coin should contribute * @param coin_contribution how much the coin should contribute
* @param reserve_pub public key of the reserve * @param reserve_sig signature over the reserve open operation
* @param request_timestamp time of the open request
* @param coin_priv private key of the coin * @param coin_priv private key of the coin
* @param[out] coin_sig signature by the coin * @param[out] coin_sig signature by the coin
*/ */
void void
TALER_wallet_reserve_open_deposit_sign ( TALER_wallet_reserve_open_deposit_sign (
const struct TALER_Amount *coin_contribution, const struct TALER_Amount *coin_contribution,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReserveSignatureP *reserve_sig,
struct GNUNET_TIME_Timestamp request_timestamp,
const struct TALER_CoinSpendPrivateKeyP *coin_priv, const struct TALER_CoinSpendPrivateKeyP *coin_priv,
struct TALER_CoinSpendSignatureP *coin_sig); struct TALER_CoinSpendSignatureP *coin_sig);
@ -3125,8 +3123,7 @@ TALER_wallet_reserve_open_deposit_sign (
* Verify signature that deposits coin to pay for keeping a reserve open. * Verify signature that deposits coin to pay for keeping a reserve open.
* *
* @param coin_contribution how much the coin should contribute * @param coin_contribution how much the coin should contribute
* @param reserve_pub public key of the reserve * @param reserve_sig signature over the reserve open operation
* @param request_timestamp time of the open request
* @param coin_pub public key of the coin * @param coin_pub public key of the coin
* @param coin_sig signature by the coin * @param coin_sig signature by the coin
* @return #GNUNET_OK if the signature is valid * @return #GNUNET_OK if the signature is valid
@ -3134,8 +3131,7 @@ TALER_wallet_reserve_open_deposit_sign (
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_wallet_reserve_open_deposit_verify ( TALER_wallet_reserve_open_deposit_verify (
const struct TALER_Amount *coin_contribution, const struct TALER_Amount *coin_contribution,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReserveSignatureP *reserve_sig,
struct GNUNET_TIME_Timestamp request_timestamp,
const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_CoinSpendSignatureP *coin_sig); const struct TALER_CoinSpendSignatureP *coin_sig);

View File

@ -4043,6 +4043,55 @@ struct TALER_EXCHANGEDB_Plugin
void *rec_cls); void *rec_cls);
/**
* Insert reserve open coin deposit data into database.
* Subtracts the @a coin_total from the coin's balance.
*
* @param cls closure
* @param cpi public information about the coin
* @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT
* @param known_coin_id ID of the coin in the known_coins table
* @param coin_total amount to be spent of the coin (including deposit fee)
* @param reserve_sig signature by the reserve affirming the open operation
* @param[out] insufficient_funds set to true if the coin's balance is insufficient, otherwise to false
* @return transaction status code, 0 if operation is already in the DB
*/
enum GNUNET_DB_QueryStatus
(*insert_reserve_open_deposit)(
void *cls,
const struct TALER_CoinPublicInfo *cpi,
const struct TALER_CoinSpendSignatureP *coin_sig,
uint64_t known_coin_id,
const struct TALER_Amount *coin_total,
const struct TALER_ReserveSignatureP *reserve_sig,
bool *insufficient_funds);
/**
* Insert reserve close operation into database.
*
* @param cls closure
* @param reserve_pub which reserve is this about?
* @param execution_date when did we perform the transfer?
* @param receiver_account to which account do we transfer, in payto://-format
* @param wtid identifier for the wire transfer
* @param amount_with_fee amount we charged to the reserve
* @param closing_fee how high is the closing fee
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
(*do_reserve_open)(void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *total_paid,
uint32_t min_purse_limit,
const struct TALER_ReserveSignatureP *reserve_sig,
struct GNUNET_TIME_Timestamp desired_expiration,
struct GNUNET_TIME_Timestamp now,
const struct TALER_Amount *open_fee,
struct TALER_Amount *open_cost,
const struct GNUNET_TIME_Timestamp *final_expiration);
/** /**
* Insert reserve close operation into database. * Insert reserve close operation into database.
* *

View File

@ -393,6 +393,12 @@ TALER_EXCHANGE_reserves_open (
GNUNET_free (roh); GNUNET_free (roh);
return NULL; return NULL;
} }
TALER_wallet_reserve_open_sign (reserve_contribution,
roh->ts,
expiration_time,
min_purses,
reserve_priv,
&roh->reserve_sig);
cpa = json_array (); cpa = json_array ();
GNUNET_assert (NULL != cpa); GNUNET_assert (NULL != cpa);
for (unsigned int i = 0; i<coin_payments_length; i++) for (unsigned int i = 0; i<coin_payments_length; i++)
@ -412,8 +418,7 @@ TALER_EXCHANGE_reserves_open (
achp = &ahac; achp = &ahac;
} }
TALER_wallet_reserve_open_deposit_sign (&pd->amount, TALER_wallet_reserve_open_deposit_sign (&pd->amount,
&roh->reserve_pub, &roh->reserve_sig,
roh->ts,
&pd->coin_priv, &pd->coin_priv,
&coin_sig); &coin_sig);
GNUNET_CRYPTO_eddsa_key_get_public (&pd->coin_priv.eddsa_priv, GNUNET_CRYPTO_eddsa_key_get_public (&pd->coin_priv.eddsa_priv,
@ -437,12 +442,6 @@ TALER_EXCHANGE_reserves_open (
json_array_append_new (cpa, json_array_append_new (cpa,
cp)); cp));
} }
TALER_wallet_reserve_open_sign (reserve_contribution,
roh->ts,
expiration_time,
min_purses,
reserve_priv,
&roh->reserve_sig);
{ {
json_t *open_obj = GNUNET_JSON_PACK ( json_t *open_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_timestamp ("request_timestamp", GNUNET_JSON_pack_timestamp ("request_timestamp",

View File

@ -1342,14 +1342,9 @@ struct TALER_ReserveOpenDepositPS
struct GNUNET_CRYPTO_EccSignaturePurpose purpose; struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/** /**
* When was the request created. * Which reserve's opening signature should be paid for?
*/ */
struct GNUNET_TIME_TimestampNBO request_timestamp; struct TALER_ReserveSignatureP reserve_sig;
/**
* Which reserve's opening should be paid for?
*/
struct TALER_ReservePublicKeyP reserve_pub;
/** /**
* Specifies how much of the coin's value should be spent on opening this * Specifies how much of the coin's value should be spent on opening this
@ -1364,16 +1359,14 @@ GNUNET_NETWORK_STRUCT_END
void void
TALER_wallet_reserve_open_deposit_sign ( TALER_wallet_reserve_open_deposit_sign (
const struct TALER_Amount *coin_contribution, const struct TALER_Amount *coin_contribution,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReserveSignatureP *reserve_sig,
struct GNUNET_TIME_Timestamp request_timestamp,
const struct TALER_CoinSpendPrivateKeyP *coin_priv, const struct TALER_CoinSpendPrivateKeyP *coin_priv,
struct TALER_CoinSpendSignatureP *coin_sig) struct TALER_CoinSpendSignatureP *coin_sig)
{ {
struct TALER_ReserveOpenDepositPS rod = { struct TALER_ReserveOpenDepositPS rod = {
.purpose.size = htonl (sizeof (rod)), .purpose.size = htonl (sizeof (rod)),
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT), .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT),
.request_timestamp = GNUNET_TIME_timestamp_hton (request_timestamp), .reserve_sig = *reserve_sig
.reserve_pub = *reserve_pub
}; };
TALER_amount_hton (&rod.coin_contribution, TALER_amount_hton (&rod.coin_contribution,
@ -1388,16 +1381,14 @@ TALER_wallet_reserve_open_deposit_sign (
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_wallet_reserve_open_deposit_verify ( TALER_wallet_reserve_open_deposit_verify (
const struct TALER_Amount *coin_contribution, const struct TALER_Amount *coin_contribution,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReserveSignatureP *reserve_sig,
struct GNUNET_TIME_Timestamp request_timestamp,
const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_CoinSpendSignatureP *coin_sig) const struct TALER_CoinSpendSignatureP *coin_sig)
{ {
struct TALER_ReserveOpenDepositPS rod = { struct TALER_ReserveOpenDepositPS rod = {
.purpose.size = htonl (sizeof (rod)), .purpose.size = htonl (sizeof (rod)),
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT), .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT),
.request_timestamp = GNUNET_TIME_timestamp_hton (request_timestamp), .reserve_sig = *reserve_sig
.reserve_pub = *reserve_pub
}; };
TALER_amount_hton (&rod.coin_contribution, TALER_amount_hton (&rod.coin_contribution,