diff options
| author | Christian Grothoff <christian@grothoff.org> | 2015-03-22 16:09:01 +0100 | 
|---|---|---|
| committer | Christian Grothoff <christian@grothoff.org> | 2015-03-22 16:09:01 +0100 | 
| commit | 1277f8445d0497107c5bd41b35007480d6a4472a (patch) | |
| tree | d6144643860085ba45f66e06748912acc83e6aa9 /src/mint | |
| parent | c2a42d5475daf23889c720734edbafc8c2ce4e4f (diff) | |
include fees in amounts being signed, check available balance on refresh
Diffstat (limited to 'src/mint')
| -rw-r--r-- | src/mint/plugin_mintdb_postgres.c | 2 | ||||
| -rw-r--r-- | src/mint/taler-mint-httpd_db.c | 178 | ||||
| -rw-r--r-- | src/mint/taler-mint-httpd_db.h | 2 | ||||
| -rw-r--r-- | src/mint/taler-mint-httpd_deposit.c | 6 | ||||
| -rw-r--r-- | src/mint/taler-mint-httpd_refresh.c | 10 | ||||
| -rw-r--r-- | src/mint/taler-mint-httpd_responses.c | 14 | ||||
| -rw-r--r-- | src/mint/taler_mintdb_plugin.h | 28 | ||||
| -rw-r--r-- | src/mint/test_mint_db.c | 2 | ||||
| -rw-r--r-- | src/mint/test_mint_deposits.c | 8 | 
9 files changed, 149 insertions, 101 deletions
| diff --git a/src/mint/plugin_mintdb_postgres.c b/src/mint/plugin_mintdb_postgres.c index 16b13435..1d7a965c 100644 --- a/src/mint/plugin_mintdb_postgres.c +++ b/src/mint/plugin_mintdb_postgres.c @@ -1401,7 +1401,7 @@ postgres_insert_deposit (void *cls,                                            &denom_sig_enc);    json_wire_enc = json_dumps (deposit->wire, JSON_COMPACT);    TALER_amount_hton (&amount_nbo, -                     &deposit->amount); +                     &deposit->amount_with_fee);    struct TALER_DB_QueryParam params[]= {      TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub),      TALER_DB_QUERY_PARAM_PTR_SIZED (denom_pub_enc, denom_pub_enc_size), diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index d347126d..b3e239c8 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c @@ -35,6 +35,64 @@  /** + * Calculate the total value of all transactions performed. + * Stores @a off plus the cost of all transactions in @a tl + * in @a ret. + * + * @param pos transaction list to process + * @param off offset to use as the starting value + * @param ret where the resulting total is to be stored + * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors + */ +static int +calculate_transaction_list_totals (struct TALER_MINT_DB_TransactionList *tl, +                                   const struct TALER_Amount *off, +                                   struct TALER_Amount *ret) +{ +  struct TALER_Amount spent = *off; +  struct TALER_MINT_DB_TransactionList *pos; + +  for (pos = tl; NULL != pos; pos = pos->next) +  { +    switch (pos->type) +    { +    case TALER_MINT_DB_TT_DEPOSIT: +      if (GNUNET_OK != +          TALER_amount_add (&spent, +                            &spent, +                            &pos->details.deposit->amount_with_fee)) +      { +        GNUNET_break (0); +        return GNUNET_SYSERR; +      } +      break; +    case TALER_MINT_DB_TT_REFRESH_MELT: +      if (GNUNET_OK != +          TALER_amount_add (&spent, +                            &spent, +                            &pos->details.melt->amount_with_fee)) +      { +        GNUNET_break (0); +        return GNUNET_SYSERR; +      } +      break; +    case TALER_MINT_DB_TT_LOCK: +      /* should check if lock is still active, +         and if it is for THIS operation; if +         lock is inactive, delete it; if lock +         is for THIS operation, ignore it; +         if lock is for another operation, +         count it! */ +      GNUNET_assert (0);  // FIXME: not implemented! (#3625) +      return GNUNET_SYSERR; +    } +  } +  *ret = spent; +  return GNUNET_OK; +} + + +/**   * Execute a deposit.  The validity of the coin and signature   * have already been checked.  The database must now check that   * the coin is not (double or over) spent, and execute the @@ -50,11 +108,9 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,  {    struct TALER_MINTDB_Session *session;    struct TALER_MINT_DB_TransactionList *tl; -  struct TALER_MINT_DB_TransactionList *pos;    struct TALER_Amount spent;    struct TALER_Amount value;    struct TALER_Amount fee_deposit; -  struct TALER_Amount fee_refresh;    struct MintKeyState *mks;    struct TALER_MINT_DenomKeyIssuePriv *dki;    int ret; @@ -76,7 +132,7 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,                                               &deposit->h_contract,                                               deposit->transaction_id,                                               &deposit->merchant_pub, -                                             &deposit->amount); +                                             &deposit->amount_with_fee);    }    mks = TALER_MINT_key_state_acquire ();    dki = TALER_MINT_get_denom_key (mks, @@ -85,8 +141,6 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,                       &dki->issue.value);    TALER_amount_ntoh (&fee_deposit,                       &dki->issue.fee_deposit); -  TALER_amount_ntoh (&fee_refresh, -                     &dki->issue.fee_refresh);    TALER_MINT_key_state_release (mks);    if (GNUNET_OK != @@ -96,69 +150,29 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,      GNUNET_break (0);      return TALER_MINT_reply_internal_db_error (connection);    } +  /* fee for THIS transaction */ +  spent = deposit->amount_with_fee; +  if (TALER_amount_cmp (&fee_deposit, +                        &spent) < 0) +  { +    return (MHD_YES == +            TALER_MINT_reply_external_error (connection, +                                             "deposited amount smaller than depositing fee")) +      ? GNUNET_NO : GNUNET_SYSERR; +  } +  /* add cost of all previous transactions */    tl = plugin->get_coin_transactions (plugin->cls,                                        session,                                        &deposit->coin.coin_pub); -  spent = fee_deposit; /* fee for THIS transaction */    if (GNUNET_OK != -      TALER_amount_add (&spent, -                        &spent, -                        &deposit->amount)) +      calculate_transaction_list_totals (tl, +                                         &spent, +                                         &spent))    { -    GNUNET_break (0);      plugin->free_coin_transaction_list (plugin->cls,                                          tl);      return TALER_MINT_reply_internal_db_error (connection);    } - -  for (pos = tl; NULL != pos; pos = pos->next) -  { -    switch (pos->type) -    { -    case TALER_MINT_DB_TT_DEPOSIT: -      if ( (GNUNET_OK != -            TALER_amount_add (&spent, -                              &spent, -                              &pos->details.deposit->amount)) || -           (GNUNET_OK != -            TALER_amount_add (&spent, -                              &spent, -                              &fee_deposit)) ) -      { -        GNUNET_break (0); -        plugin->free_coin_transaction_list (plugin->cls, -                                            tl); -        return TALER_MINT_reply_internal_db_error (connection); -      } -      break; -    case TALER_MINT_DB_TT_REFRESH_MELT: -      if ( (GNUNET_OK != -            TALER_amount_add (&spent, -                              &spent, -                              &pos->details.melt->amount)) || -           (GNUNET_OK != -            TALER_amount_add (&spent, -                              &spent, -                              &fee_refresh)) ) -      { -        GNUNET_break (0); -        plugin->free_coin_transaction_list (plugin->cls, -                                            tl); -        return TALER_MINT_reply_internal_db_error (connection); -      } -      break; -    case TALER_MINT_DB_TT_LOCK: -      /* should check if lock is still active, -         and if it is for THIS operation; if -         lock is inactive, delete it; if lock -         is for THIS operation, ignore it; -         if lock is for another operation, -         count it! */ -      GNUNET_assert (0);  // FIXME: not implemented! (#3625) -      break; -    } -  } -    if (0 < TALER_amount_cmp (&spent,                              &value))    { @@ -197,7 +211,7 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,                                             &deposit->h_contract,                                             deposit->transaction_id,                                             &deposit->merchant_pub, -                                           &deposit->amount); +                                           &deposit->amount_with_fee);  } @@ -501,8 +515,11 @@ refresh_accept_melts (struct MHD_Connection *connection,  {    struct TALER_MINT_DenomKeyIssue *dki;    struct TALER_MINT_DB_TransactionList *tl; +  struct TALER_Amount fee_deposit; +  struct TALER_Amount fee_refresh;    struct TALER_Amount coin_value;    struct TALER_Amount coin_residual; +  struct TALER_Amount spent;    struct RefreshMelt melt;    int res; @@ -518,26 +535,51 @@ refresh_accept_melts (struct MHD_Connection *connection,                                          "denom not found"))        ? GNUNET_NO : GNUNET_SYSERR; +  TALER_amount_ntoh (&fee_deposit, +                     &dki->fee_deposit); +  TALER_amount_ntoh (&fee_refresh, +                     &dki->fee_refresh);    TALER_amount_ntoh (&coin_value,                       &dki->value); +  /* fee for THIS transaction; the melt amount includes the fee! */ +  spent = coin_details->melt_amount_with_fee; +  if (TALER_amount_cmp (&fee_refresh, +                        &spent) < 0) +  { +    return (MHD_YES == +            TALER_MINT_reply_external_error (connection, +                                             "melt amount smaller than melting fee")) +      ? GNUNET_NO : GNUNET_SYSERR; +  } +  /* add historic transaction costs of this coin */    tl = plugin->get_coin_transactions (plugin->cls,                                        session,                                        &coin_public_info->coin_pub); -  /* FIXME: #3636: compute how much value is left with this coin and -     compare to `expected_value`! (subtract from "coin_value") */ -  coin_residual = coin_value; +  if (GNUNET_OK != +      calculate_transaction_list_totals (tl, +                                         &spent, +                                         &spent)) +  { +    GNUNET_break (0); +    plugin->free_coin_transaction_list (plugin->cls, +                                        tl); +    return TALER_MINT_reply_internal_db_error (connection); +  }    /* Refuse to refresh when the coin does not have enough money left to     * pay the refreshing fees of the coin. */ - -  if (TALER_amount_cmp (&coin_residual, -                        &coin_details->melt_amount) < 0) +  if (TALER_amount_cmp (&coin_value, +                        &spent) < 0)    { +    GNUNET_assert (GNUNET_OK == +                   TALER_amount_subtract (&coin_residual, +                                          &spent, +                                          &coin_details->melt_amount_with_fee));      res = (MHD_YES ==             TALER_MINT_reply_refresh_melt_insufficient_funds (connection,                                                               &coin_public_info->coin_pub,                                                               coin_value,                                                               tl, -                                                             coin_details->melt_amount, +                                                             coin_details->melt_amount_with_fee,                                                               coin_residual))        ? GNUNET_NO : GNUNET_SYSERR;      plugin->free_coin_transaction_list (plugin->cls, @@ -550,7 +592,7 @@ refresh_accept_melts (struct MHD_Connection *connection,    melt.coin = *coin_public_info;    melt.coin_sig = coin_details->melt_sig;    melt.melt_hash = *melt_hash; -  melt.amount = coin_details->melt_amount; +  melt.amount_with_fee = coin_details->melt_amount_with_fee;    if (GNUNET_OK !=        plugin->insert_refresh_melt (plugin->cls,                                     session, diff --git a/src/mint/taler-mint-httpd_db.h b/src/mint/taler-mint-httpd_db.h index aefbfc42..52e86f89 100644 --- a/src/mint/taler-mint-httpd_db.h +++ b/src/mint/taler-mint-httpd_db.h @@ -95,7 +95,7 @@ struct MeltDetails     * This amount includes the fees, so the final amount contributed     * to the melt is this value minus the fee for melting the coin.     */ -  struct TALER_Amount melt_amount; +  struct TALER_Amount melt_amount_with_fee;  }; diff --git a/src/mint/taler-mint-httpd_deposit.c b/src/mint/taler-mint-httpd_deposit.c index e411e0d8..647cd824 100644 --- a/src/mint/taler-mint-httpd_deposit.c +++ b/src/mint/taler-mint-httpd_deposit.c @@ -65,8 +65,8 @@ verify_and_execute_deposit (struct MHD_Connection *connection,    dr.h_contract = deposit->h_contract;    dr.h_wire = deposit->h_wire;    dr.transaction_id = GNUNET_htonll (deposit->transaction_id); -  TALER_amount_hton (&dr.amount, -                     &deposit->amount); +  TALER_amount_hton (&dr.amount_with_fee, +                     &deposit->amount_with_fee);    dr.coin_pub = deposit->coin.coin_pub;    if (GNUNET_OK !=        GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_WALLET_DEPOSIT, @@ -167,7 +167,7 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,    GNUNET_free (wire_enc);    deposit.wire = wire; -  deposit.amount = *amount; +  deposit.amount_with_fee = *amount;    res = verify_and_execute_deposit (connection,                                      &deposit);    TALER_MINT_release_parsed_data (spec); diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c index d4979288..602fc67f 100644 --- a/src/mint/taler-mint-httpd_refresh.c +++ b/src/mint/taler-mint-httpd_refresh.c @@ -109,8 +109,8 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,    body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_SESSION);    body.purpose.size = htonl (sizeof (struct RefreshMeltSessionSignature));    body.melt_hash = melt_hash; -  TALER_amount_hton (&body.amount, -                     &coin_melt_details->melt_amount); +  TALER_amount_hton (&body.amount_with_fee, +                     &coin_melt_details->melt_amount_with_fee);    if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_REFRESH_MELT_SESSION,                                                 &body.purpose, @@ -252,7 +252,7 @@ get_coin_public_info (struct MHD_Connection *connection,        ? GNUNET_NO : GNUNET_SYSERR;    }    r_melt_detail->melt_sig = melt_sig; -  r_melt_detail->melt_amount = amount; +  r_melt_detail->melt_amount_with_fee = amount;    TALER_MINT_release_parsed_data (spec);    return GNUNET_OK;  } @@ -288,8 +288,8 @@ verify_coin_public_info (struct MHD_Connection *connection,    body.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature));    body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN);    body.melt_hash = *melt_hash; -  TALER_amount_hton (&body.amount, -                     &r_melt_detail->melt_amount); +  TALER_amount_hton (&body.amount_with_fee, +                     &r_melt_detail->melt_amount_with_fee);    body.coin_pub = r_public_info->coin_pub;    if (GNUNET_OK !=        GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_REFRESH_MELT_COIN, diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c index a4b44215..681b2b92 100644 --- a/src/mint/taler-mint-httpd_responses.c +++ b/src/mint/taler-mint-httpd_responses.c @@ -299,7 +299,7 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,    dc.h_contract = *h_contract;    dc.h_wire = *h_wire;    dc.transaction_id = GNUNET_htonll (transaction_id); -  TALER_amount_hton (&dc.amount, +  TALER_amount_hton (&dc.amount_with_fee,                       amount);    dc.coin_pub = *coin_pub;    dc.merchant = *merchant; @@ -341,14 +341,14 @@ compile_transaction_history (const struct TALER_MINT_DB_TransactionList *tl)          const struct Deposit *deposit = pos->details.deposit;          type = "deposit"; -        value = deposit->amount; +        value = deposit->amount_with_fee;          dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_DEPOSIT);          dr.purpose.size = htonl (sizeof (struct TALER_DepositRequest));          dr.h_contract = deposit->h_contract;          dr.h_wire = deposit->h_wire;          dr.transaction_id = GNUNET_htonll (deposit->transaction_id); -        TALER_amount_hton (&dr.amount, -                           &deposit->amount); +        TALER_amount_hton (&dr.amount_with_fee, +                           &deposit->amount_with_fee);          dr.coin_pub = deposit->coin.coin_pub;          transaction = TALER_JSON_from_ecdsa_sig (&dr.purpose,                                                   &deposit->csig); @@ -360,12 +360,12 @@ compile_transaction_history (const struct TALER_MINT_DB_TransactionList *tl)          const struct RefreshMelt *melt = pos->details.melt;          type = "melt"; -        value = melt->amount; +        value = melt->amount_with_fee;          ms.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN);          ms.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature));          ms.melt_hash = melt->melt_hash; -        TALER_amount_hton (&ms.amount, -                           &melt->amount); +        TALER_amount_hton (&ms.amount_with_fee, +                           &melt->amount_with_fee);          ms.coin_pub = melt->coin.coin_pub;          transaction = TALER_JSON_from_ecdsa_sig (&ms.purpose,                                                   &melt->coin_sig); diff --git a/src/mint/taler_mintdb_plugin.h b/src/mint/taler_mintdb_plugin.h index bc5cd69a..83e37334 100644 --- a/src/mint/taler_mintdb_plugin.h +++ b/src/mint/taler_mintdb_plugin.h @@ -14,13 +14,13 @@    TALER; see the file COPYING.  If not, If not, see <http://www.gnu.org/licenses/>  */  /** - * @file mint/mint_db.h + * @file mint/taler_mintdb_plugin.h   * @brief Low-level (statement-level) database access for the mint   * @author Florian Dold   * @author Christian Grothoff   */ -#ifndef MINT_DB_H -#define MINT_DB_H +#ifndef TALER_MINTDB_PLUGIN_H +#define TALER_MINTDB_PLUGIN_H  #include <gnunet/gnunet_util_lib.h>  #include "taler_util.h" @@ -87,6 +87,9 @@ struct CollectableBlindcoin    /**     * Denomination key (which coin was generated). +   * FIXME: we should probably instead have the +   * AMOUNT *including* fee in what is being signed +   * as well!     */    struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub; @@ -217,10 +220,10 @@ struct Deposit    uint64_t transaction_id;    /** -   * Fraction of the coin's remaining value to be deposited. -   * The coin is identified by @e coin_pub. +   * Fraction of the coin's remaining value to be deposited, including +   * depositing fee (if any).  The coin is identified by @e coin_pub.     */ -  struct TALER_Amount amount; +  struct TALER_Amount amount_with_fee;  }; @@ -296,11 +299,14 @@ struct RefreshMelt    struct GNUNET_HashCode melt_hash;    /** -   * How much value is being melted? -   * This amount includes the fees, so the final amount contributed -   * to the melt is this value minus the fee for melting the coin. +   * How much value is being melted?  This amount includes the fees, +   * so the final amount contributed to the melt is this value minus +   * the fee for melting the coin.  We include the fee in what is +   * being signed so that we can verify a reserve's remaining total +   * balance without needing to access the respective denomination key +   * information each time.     */ -  struct TALER_Amount amount; +  struct TALER_Amount amount_with_fee;  }; @@ -397,7 +403,7 @@ struct Lock    const struct GNUNET_CRYPTO_EcdsaSignature coin_sig;    /** -   * How much value is being melted? +   * How much value is being locked?     */    struct TALER_Amount amount; diff --git a/src/mint/test_mint_db.c b/src/mint/test_mint_db.c index e4d31292..c80be70c 100644 --- a/src/mint/test_mint_db.c +++ b/src/mint/test_mint_db.c @@ -286,7 +286,7 @@ run (void *cls,    deposit.wire = wire;    deposit.transaction_id =        GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); -  deposit.amount = amount; +  deposit.amount_with_fee = amount;    FAILIF (GNUNET_OK !=            plugin->insert_deposit (plugin->cls,                                    session, &deposit)); diff --git a/src/mint/test_mint_deposits.c b/src/mint/test_mint_deposits.c index c829e6e1..4107c1ae 100644 --- a/src/mint/test_mint_deposits.c +++ b/src/mint/test_mint_deposits.c @@ -94,12 +94,12 @@ run (void *cls,                                               UINT64_MAX);    deposit->transaction_id = GNUNET_htonll (transaction_id);    /* Random amount */ -  deposit->amount.value = +  deposit->amount_with_fee.value =        htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX)); -  deposit->amount.fraction = +  deposit->amount_with_fee.fraction =        htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX)); -  GNUNET_assert (strlen (MINT_CURRENCY) < sizeof (deposit->amount.currency)); -  strcpy (deposit->amount.currency, MINT_CURRENCY); +  GNUNET_assert (strlen (MINT_CURRENCY) < sizeof (deposit->amount_with_fee.currency)); +  strcpy (deposit->amount_with_fee.currency, MINT_CURRENCY);    /* Copy wireformat */    deposit->wire = json_loads (wire, 0, NULL);    EXITIF (GNUNET_OK != | 
