diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mint/key_io.h | 1 | ||||
| -rw-r--r-- | src/mint/mint_db.c | 228 | ||||
| -rw-r--r-- | src/mint/mint_db.h | 182 | ||||
| -rw-r--r-- | src/mint/taler-mint-httpd_db.c | 227 | ||||
| -rw-r--r-- | src/mint/taler-mint-httpd_responses.c | 119 | ||||
| -rw-r--r-- | src/mint/taler-mint-httpd_responses.h | 21 | ||||
| -rw-r--r-- | src/util/amount.c | 42 | 
7 files changed, 495 insertions, 325 deletions
diff --git a/src/mint/key_io.h b/src/mint/key_io.h index 44665e37..a14866f4 100644 --- a/src/mint/key_io.h +++ b/src/mint/key_io.h @@ -42,6 +42,7 @@  struct TALER_MINT_SignKeyIssuePriv  {    struct GNUNET_CRYPTO_EddsaPrivateKey signkey_priv; +    struct TALER_MINT_SignKeyIssue issue;  }; diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 5da2a5d4..0e448bf0 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -103,128 +103,6 @@ TALER_TALER_DB_extract_amount (PGresult *result,  } - -int -TALER_MINT_DB_get_reserve (PGconn *db_conn, -                           const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub, -                           struct Reserve *reserve) -{ -  PGresult *result; -  int res; -  struct TALER_DB_QueryParam params[] = { -    TALER_DB_QUERY_PARAM_PTR (reserve_pub), -    TALER_DB_QUERY_PARAM_END -  }; - -  result = TALER_DB_exec_prepared (db_conn, "get_reserve", params); - -  if (PGRES_TUPLES_OK != PQresultStatus (result)) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed: %s\n", PQresultErrorMessage (result)); -    PQclear (result); -    return GNUNET_SYSERR; -  } - -  if (0 == PQntuples (result)) -  { -    PQclear (result); -    return GNUNET_NO; -  } - -  reserve->reserve_pub = *reserve_pub; - -  struct TALER_DB_ResultSpec rs[] = { -    TALER_DB_RESULT_SPEC("status_sig", &reserve->status_sig), -    TALER_DB_RESULT_SPEC("status_sign_pub", &reserve->status_sign_pub), -    TALER_DB_RESULT_SPEC_END -  }; - -  res = TALER_DB_extract_result (result, rs, 0); -  if (GNUNET_SYSERR == res) -  { -    GNUNET_break (0); -    PQclear (result); -    return GNUNET_SYSERR; -  } - -  { -    int fnums[] = { -      PQfnumber (result, "balance_value"), -      PQfnumber (result, "balance_fraction"), -      PQfnumber (result, "balance_currency"), -    }; -    if (GNUNET_OK != TALER_TALER_DB_extract_amount_nbo (result, 0, fnums, &reserve->balance)) -    { -      GNUNET_break (0); -      PQclear (result); -      return GNUNET_SYSERR; -    } -  } - -  /* FIXME: Add expiration?? */ - -  PQclear (result); -  return GNUNET_OK; -} - - -/* If fresh is GNUNET_YES, set some fields to NULL as they are not actually valid */ -int -TALER_MINT_DB_update_reserve (PGconn *db_conn, -                              const struct Reserve *reserve, -                              int fresh) -{ -  PGresult *result; -  uint64_t stamp_sec; - -  stamp_sec = GNUNET_ntohll (GNUNET_TIME_absolute_ntoh (reserve->expiration).abs_value_us / 1000000); - -  struct TALER_DB_QueryParam params[] = { -    TALER_DB_QUERY_PARAM_PTR (&reserve->reserve_pub), -    TALER_DB_QUERY_PARAM_PTR (&reserve->balance.value), -    TALER_DB_QUERY_PARAM_PTR (&reserve->balance.fraction), -    TALER_DB_QUERY_PARAM_PTR_SIZED (&reserve->balance.currency, -                           strlen (reserve->balance.currency)), -    TALER_DB_QUERY_PARAM_PTR (&reserve->status_sig), -    TALER_DB_QUERY_PARAM_PTR (&reserve->status_sign_pub), -    TALER_DB_QUERY_PARAM_PTR (&stamp_sec), -    TALER_DB_QUERY_PARAM_END -  }; - -  /* set some fields to NULL if they are not actually valid */ - -  if (GNUNET_YES == fresh) -  { -    unsigned i; -    for (i = 4; i <= 7; i += 1) -    { -     params[i].data = NULL; -     params[i].size = 0; -    } -  } - -  result = TALER_DB_exec_prepared (db_conn, "update_reserve", params); - -  if (PGRES_COMMAND_OK != PQresultStatus (result)) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed: %s\n", PQresultErrorMessage (result)); -    PQclear (result); -    return GNUNET_SYSERR; -  } - -  if (0 != strcmp ("1", PQcmdTuples (result))) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Update failed (updated '%s' tupes instead of '1')\n", -             PQcmdTuples (result)); -    return GNUNET_SYSERR; -  } - -  PQclear (result); -  return GNUNET_OK; -} - - -  int  TALER_MINT_DB_prepare (PGconn *db_conn)  { @@ -1560,9 +1438,6 @@ TALER_db_get_transfer (PGconn *db_conn, - - -  /**   * Close thread-local database connection when a thread is destroyed.   * @@ -1712,6 +1587,10 @@ TALER_MINT_DB_commit (PGconn *db_conn)  } + + + +  /**   * Locate the response for a /withdraw request under the   * key of the hash of the blinded message. @@ -1729,6 +1608,7 @@ TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,                                           const struct GNUNET_HashCode *h_blind,                                           struct CollectableBlindcoin *collectable)  { +  // FIXME: check logic!    PGresult *result;    struct TALER_DB_QueryParam params[] = {      TALER_DB_QUERY_PARAM_PTR (h_blind), @@ -1792,6 +1672,7 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,                                              const struct GNUNET_HashCode *h_blind,                                              const struct CollectableBlindcoin *collectable)  { +  // FIXME: check logic!    PGresult *result;    char *sig_buf;    size_t sig_buf_size; @@ -1835,6 +1716,95 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,  /** + * Get all of the transaction history associated with the specified + * reserve. + * + * @param db_conn connection to use + * @param reserve_pub public key of the reserve + * @return known transaction history (NULL if reserve is unknown) + */ +struct ReserveHistory * +TALER_MINT_DB_get_reserve_history (PGconn *db_conn, +                                   const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub) +{ +  // FIXME: implement logic! +  PGresult *result; +  // int res; +  struct TALER_DB_QueryParam params[] = { +    TALER_DB_QUERY_PARAM_PTR (reserve_pub), +    TALER_DB_QUERY_PARAM_END +  }; + +  result = TALER_DB_exec_prepared (db_conn, "get_reserve", params); + +  if (PGRES_TUPLES_OK != PQresultStatus (result)) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "Query failed: %s\n", +                PQresultErrorMessage (result)); +    PQclear (result); +    return NULL; +  } + +  if (0 == PQntuples (result)) +  { +    PQclear (result); +    return NULL; +  } +#if 0 +  reserve->reserve_pub = *reserve_pub; + +  struct TALER_DB_ResultSpec rs[] = { +    TALER_DB_RESULT_SPEC("status_sig", &reserve->status_sig), +    TALER_DB_RESULT_SPEC("status_sign_pub", &reserve->status_sign_pub), +    TALER_DB_RESULT_SPEC_END +  }; + +  res = TALER_DB_extract_result (result, rs, 0); +  if (GNUNET_SYSERR == res) +  { +    GNUNET_break (0); +    PQclear (result); +    return GNUNET_SYSERR; +  } + +  { +    int fnums[] = { +      PQfnumber (result, "balance_value"), +      PQfnumber (result, "balance_fraction"), +      PQfnumber (result, "balance_currency"), +    }; +    if (GNUNET_OK != TALER_TALER_DB_extract_amount_nbo (result, 0, fnums, &reserve->balance)) +    { +      GNUNET_break (0); +      PQclear (result); +      return GNUNET_SYSERR; +    } +  } + +  /* FIXME: Add expiration?? */ + +  PQclear (result); +  return GNUNET_OK; +#endif +  return NULL; +} + + +/** + * Free memory associated with the given reserve history. + * + * @param rh history to free. + */ +void +TALER_MINT_DB_free_reserve_history (struct ReserveHistory *rh) +{ +  // FIXME: implement +  GNUNET_assert (0); +} + + +/**   * Check if we have the specified deposit already in the database.   *   * @param db_conn database connection @@ -1846,6 +1816,7 @@ int  TALER_MINT_DB_have_deposit (PGconn *db_conn,                              const struct Deposit *deposit)  { +  // FIXME: check logic!    struct TALER_DB_QueryParam params[] = {      TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub), // FIXME      TALER_DB_QUERY_PARAM_END @@ -1884,6 +1855,7 @@ int  TALER_MINT_DB_insert_deposit (PGconn *db_conn,                                const struct Deposit *deposit)  { +  // FIXME: check logic!    struct TALER_DB_QueryParam params[]= {      TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub),      TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_pub), // FIXME! @@ -1928,6 +1900,7 @@ int  TALER_MINT_DB_have_refresh_melt (PGconn *db_conn,                                   const struct RefreshMelt *melt)  { +  // FIXME: check logic!    uint16_t oldcoin_index_nbo = htons (melt->oldcoin_index);    struct TALER_DB_QueryParam params[] = {      TALER_DB_QUERY_PARAM_PTR(&melt->session_pub), @@ -1956,7 +1929,6 @@ TALER_MINT_DB_have_refresh_melt (PGconn *db_conn,  } -  /**   * Store the given /refresh/melt request in the database.   * @@ -1969,6 +1941,7 @@ int  TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,                                     const struct RefreshMelt *melt)  { +  // FIXME: check logic!    uint16_t oldcoin_index_nbo = htons (melt->oldcoin_index);    char *buf;    size_t buf_size; @@ -2014,6 +1987,7 @@ TALER_MINT_DB_get_refresh_melt (PGconn *db_conn,                                  uint16_t oldcoin_index,                                  struct RefreshMelt *melt)  { +  // FIXME: check logic!    GNUNET_break (0);    return GNUNET_SYSERR;  } @@ -2031,6 +2005,7 @@ struct TALER_MINT_DB_TransactionList *  TALER_MINT_DB_get_coin_transactions (PGconn *db_conn,                                       const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub)  { +  // FIXME: check logic!    GNUNET_break (0); // FIXME: implement!    return NULL;  } @@ -2044,6 +2019,7 @@ TALER_MINT_DB_get_coin_transactions (PGconn *db_conn,  void  TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list)  { +  // FIXME: check logic!    GNUNET_break (0);  } diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h index ff14ba1e..4cb2a5f1 100644 --- a/src/mint/mint_db.h +++ b/src/mint/mint_db.h @@ -38,77 +38,6 @@ int  TALER_MINT_DB_prepare (PGconn *db_conn); -/** - * Reserve row.  Corresponds to table 'reserves' in the mint's - * database.  FIXME: not sure this is how we want to store this - * information.  Also, may currently used in different ways in the - * code, so we might need to separate the struct into different ones - * depending on the context it is used in. - */ -struct Reserve -{ -  /** -   * Signature over the purse. -   * Only valid if (blind_session_missing==GNUNET_YES). -   */ -  struct GNUNET_CRYPTO_EddsaSignature status_sig; - -  /** -   * Signature with purpose TALER_SIGNATURE_PURSE. -   * Only valid if (blind_session_missing==GNUNET_YES). -   */ -  struct GNUNET_CRYPTO_EccSignaturePurpose status_sig_purpose; - -  /** -   * Signing key used to sign the purse. -   * Only valid if (blind_session_missing==GNUNET_YES). -   */ -  struct GNUNET_CRYPTO_EddsaPublicKey status_sign_pub; - -  /** -   * Withdraw public key, identifies the purse. -   * Only the customer knows the corresponding private key. -   */ -  struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub; - -  /** -   * Remaining balance in the purse. // FIXME: do not use NBO here! -   */ -  struct TALER_AmountNBO balance; - -  /** -   * Expiration date for the purse. -   */ -  struct GNUNET_TIME_AbsoluteNBO expiration; -}; - - -int -TALER_MINT_DB_get_reserve (PGconn *db_conn, -                           const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub, -                           struct Reserve *reserve_res); - - -/** - * Update information about a reserve. - * - * @param db_conn - * @param reserve current reserve status - * @param fresh FIXME - * @return #GNUNET_OK on success - */ -int -TALER_MINT_DB_update_reserve (PGconn *db_conn, -                              const struct Reserve *reserve, -                              int fresh); - - - - - - - -  int  TALER_MINT_DB_insert_refresh_order (PGconn *db_conn,                                      uint16_t newcoin_index, @@ -328,6 +257,34 @@ void  TALER_MINT_DB_rollback (PGconn *db_conn); +/** + * Information we keep on a bank transfer that + * established a reserve. + */ +struct BankTransfer +{ + +  /** +   * Public key of the reserve that was filled. +   */ +  struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub; + +  /** +   * Amount that was transferred to the mint. +   */ +  struct TALER_Amount amount; + +  /** +   * Detailed wire information about the transaction. +   */ +  const json_t *wire; + +}; + + +/* FIXME: add functions to add bank transfers to our DB +   (and to test if we already did add one) */ +  /**   * Information we keep for a withdrawn coin to reproduce @@ -360,6 +317,9 @@ struct CollectableBlindcoin  }; +/* FIXME: need call to convert CollectableBlindcoin to JSON (#3527) */ + +  /**   * Locate the response for a /withdraw request under the   * key of the hash of the blinded message. @@ -396,6 +356,86 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,                                              const struct CollectableBlindcoin *collectable); + +/** + * Types of operations on a reserved. + */ +enum TALER_MINT_DB_ReserveOperation +{ +  /** +   * Money was deposited into the reserve via a bank transfer. +   */ +  TALER_MINT_DB_RO_BANK_TO_MINT = 0, + +  /** +   * A Coin was withdrawn from the reserve using /withdraw. +   */ +  TALER_MINT_DB_RO_WITHDRAW_COIN = 1 +}; + + +/** + * Reserve history as a linked list.  Lists all of the transactions + * associated with this reserve (such as the bank transfers that + * established the reserve and all /withdraw operations we have done + * since). + */ +struct ReserveHistory +{ + +  /** +   * Next entry in the reserve history. +   */ +  struct ReserveHistory *next; + +  /** +   * Type of the event, determins @e details. +   */ +  enum TALER_MINT_DB_ReserveOperation type; + +  /** +   * Details of the operation, depending on @e type. +   */ +  union +  { + +    /** +     * Details about a bank transfer to the mint. +     */ +    struct BankTransfer *bank; + +    /** +     * Details about a /withdraw operation. +     */ +    struct CollectableBlindcoin *withdraw; + +  } details; + +}; + + +/** + * Get all of the transaction history associated with the specified + * reserve. + * + * @param db_conn connection to use + * @param reserve_pub public key of the reserve + * @return known transaction history (NULL if reserve is unknown) + */ +struct ReserveHistory * +TALER_MINT_DB_get_reserve_history (PGconn *db_conn, +                                   const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub); + + +/** + * Free memory associated with the given reserve history. + * + * @param rh history to free. + */ +void +TALER_MINT_DB_free_reserve_history (struct ReserveHistory *rh); + +  /**   * Specification for a /deposit operation.   */ diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index c6f0fe2c..bf10cd29 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c @@ -22,12 +22,31 @@   * - actually abstract DB implementation (i.e. via plugin logic)   *   (this file should remain largely unchanged with the exception   *    of the PQ-specific DB handle types) - * - /deposit: properly check existing deposits - * - /deposit: properly perform commit (check return value) - * - /deposit: check for leaks - * - ALL: check API: given structs are usually not perfect, as they - *        often contain too many fields for the context - * - ALL: check transactional behavior + * - /withdraw/sign: all + *   + properly check all conditions and handle errors + *   + properly check transaction logic + *   + check for leaks + *   + check low-level API + * - /refresh/melt: all + *   + properly check all conditions and handle errors + *   + properly check transaction logic + *   + check for leaks + *   + check low-level API + * - /refresh/commit: all + *   + properly check all conditions and handle errors + *   + properly check transaction logic + *   + check for leaks + *   + check low-level API + * - /refresh/reveal: all + *   + properly check all conditions and handle errors + *   + properly check transaction logic + *   + check for leaks + *   + check low-level API + * - /refresh/link: all + *   + properly check all conditions and handle errors + *   + properly check transaction logic + *   + check for leaks + *   + check low-level API   */  #include "platform.h"  #include <pthread.h> @@ -43,6 +62,26 @@  /** + * Get an amount in the mint's currency that is zero. + * + * @return zero amount in the mint's currency + */ +static struct TALER_Amount +mint_amount_native_zero () +{ +  struct TALER_Amount amount; + +  memset (&amount, +          0, +          sizeof (amount)); +  memcpy (amount.currency, +          MINT_CURRENCY, +          strlen (MINT_CURRENCY) + 1); +  return amount; +} + + +/**   * 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 @@ -58,6 +97,15 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,  {    PGconn *db_conn;    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_withdraw; +  struct TALER_Amount fee_refresh; +  struct MintKeyState *mks; +  struct TALER_MINT_DenomKeyIssuePriv *dki; +  int ret;    if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))    { @@ -76,6 +124,14 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,                                               &deposit->merchant_pub,                                               &deposit->amount);    } +  mks = TALER_MINT_key_state_acquire (); +  dki = TALER_MINT_get_denom_key (mks, +                                  deposit->coin.denom_pub); +  value = TALER_amount_ntoh (dki->issue.value); +  fee_deposit = TALER_amount_ntoh (dki->issue.fee_deposit); +  fee_refresh = TALER_amount_ntoh (dki->issue.fee_refresh); +  TALER_MINT_key_state_release (mks); +    if (GNUNET_OK !=        TALER_MINT_DB_transaction (db_conn))    { @@ -84,19 +140,48 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,    }    tl = TALER_MINT_DB_get_coin_transactions (db_conn,                                              &deposit->coin.coin_pub); -  if (NULL != tl) +  spent = fee_withdraw; /* fee for THIS transaction */ +  /* FIXME: need to deal better with integer overflows +     in the logic that follows! (change amount.c API!) */ +  spent = TALER_amount_add (spent, +                            deposit->amount); + +  for (pos = tl; NULL != pos; pos = pos->next)    { -    // FIXME: in the future, check if there's enough credits -    // left on the coin. For now: refuse -    // FIXME: return more information here -    TALER_MINT_DB_rollback (db_conn); -    return TALER_MINT_reply_json_pack (connection, -                                       MHD_HTTP_FORBIDDEN, -                                       "{s:s}", -                                       "error", "insufficient funds"); +    switch (pos->type) +    { +    case TALER_MINT_DB_TT_DEPOSIT: +      spent = TALER_amount_add (spent, +                                pos->details.deposit->amount); +      spent = TALER_amount_add (spent, +                                fee_deposit); +      break; +    case TALER_MINT_DB_TT_REFRESH_MELT: +      spent = TALER_amount_add (spent, +                                pos->details.melt->amount); +      spent = TALER_amount_add (spent, +                                fee_refresh); +      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! +      break; +    }    } - +  if (0 < TALER_amount_cmp (spent, value)) +  { +    TALER_MINT_DB_rollback (db_conn); +    ret = TALER_MINT_reply_insufficient_funds (connection, +                                               tl); +    TALER_MINT_DB_free_coin_transaction_list (tl); +    return ret; +  }    TALER_MINT_DB_free_coin_transaction_list (tl);    if (GNUNET_OK != @@ -124,37 +209,6 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,  } - - - - - - - - -/** - * Sign a reserve's status with the current signing key. - * FIXME: not sure why we do this.  Should just return - * existing list of operations on the reserve. - * - * @param reserve the reserve to sign - * @param key_state the key state containing the current - *                  signing private key - */ -static void -sign_reserve (struct Reserve *reserve, -              struct MintKeyState *key_state) -{ -  reserve->status_sign_pub = key_state->current_sign_key_issue.issue.signkey_pub; -  reserve->status_sig_purpose.purpose = htonl (TALER_SIGNATURE_RESERVE_STATUS); -  reserve->status_sig_purpose.size = htonl (sizeof (struct Reserve) - -                                          offsetof (struct Reserve, status_sig_purpose)); -  GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv, -                            &reserve->status_sig_purpose, -                            &reserve->status_sig); -} - -  /**   * Execute a /withdraw/status.   * @@ -167,50 +221,25 @@ TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection,                                         const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub)  {    PGconn *db_conn; +  struct ReserveHistory *rh;    int res; -  struct Reserve reserve; -  struct MintKeyState *key_state; -  int must_update = GNUNET_NO;    if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))    {      GNUNET_break (0);      return TALER_MINT_reply_internal_db_error (connection);    } -  res = TALER_MINT_DB_get_reserve (db_conn, -                                   reserve_pub, -                                   &reserve); -  /* check if these are really the matching error codes, -     seems odd... */ -  if (GNUNET_SYSERR == res) +  rh = TALER_MINT_DB_get_reserve_history (db_conn, +                                          reserve_pub); +  if (NULL == rh)      return TALER_MINT_reply_json_pack (connection,                                         MHD_HTTP_NOT_FOUND,                                         "{s:s}", -                                       "error", -                                       "Reserve not found"); -  if (GNUNET_OK != res) -  { -    GNUNET_break (0); -    return TALER_MINT_reply_internal_error (connection, -                                            "Internal error"); -  } -  key_state = TALER_MINT_key_state_acquire (); -  if (0 != memcmp (&key_state->current_sign_key_issue.issue.signkey_pub, -                   &reserve.status_sign_pub, -                   sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))) -  { -    sign_reserve (&reserve, key_state); -    must_update = GNUNET_YES; -  } -  if ((GNUNET_YES == must_update) && -      (GNUNET_OK != TALER_MINT_DB_update_reserve (db_conn, &reserve, !must_update))) -  { -    GNUNET_break (0); -    return MHD_YES; -  } -  return TALER_MINT_reply_withdraw_status_success (connection, -                                                   TALER_amount_ntoh (reserve.balance), -                                                   GNUNET_TIME_absolute_ntoh (reserve.expiration)); +                                       "error", "Reserve not found"); +  res = TALER_MINT_reply_withdraw_status_success (connection, +                                                  rh); +  TALER_MINT_DB_free_reserve_history (rh); +  return res;  } @@ -234,7 +263,7 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,                                       const struct GNUNET_CRYPTO_EddsaSignature *signature)  {    PGconn *db_conn; -  struct Reserve db_reserve; +  struct ReserveHistory *rh;    struct MintKeyState *key_state;    struct CollectableBlindcoin collectable;    struct TALER_MINT_DenomKeyIssuePriv *dki; @@ -270,15 +299,9 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,      return res;    }    GNUNET_assert (GNUNET_NO == res); -  res = TALER_MINT_DB_get_reserve (db_conn, -                                   reserve, -                                   &db_reserve); -  if (GNUNET_SYSERR == res) -  { -    GNUNET_break (0); -    return TALER_MINT_reply_internal_db_error (connection); -  } -  if (GNUNET_NO == res) +  rh = TALER_MINT_DB_get_reserve_history (db_conn, +                                          reserve); +  if (NULL == rh)      return TALER_MINT_reply_json_pack (connection,                                         MHD_HTTP_NOT_FOUND,                                         "{s:s}", @@ -298,6 +321,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,    amount_required = TALER_amount_add (TALER_amount_ntoh (dki->issue.value),                                        TALER_amount_ntoh (dki->issue.fee_withdraw)); +  // FIX LOGIC! +#if 0    if (0 < TALER_amount_cmp (amount_required,                              TALER_amount_ntoh (db_reserve.balance)))      return TALER_MINT_reply_json_pack (connection, @@ -329,6 +354,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,      GNUNET_break (0);      return TALER_MINT_reply_internal_db_error (connection);    } +#endif +    collectable.denom_pub = (struct GNUNET_CRYPTO_rsa_PublicKey *) denomination_pub;    collectable.sig = sig;    collectable.reserve_pub = *reserve; @@ -401,21 +428,6 @@ refresh_accept_denoms (struct MHD_Connection *connection,  } -/** - * Get an amount in the mint's currency that is zero. - * - * @return zero amount in the mint's currency - */ -static struct TALER_Amount -mint_amount_native_zero () -{ -  struct TALER_Amount amount; - -  memset (&amount, 0, sizeof (amount)); -  memcpy (amount.currency, MINT_CURRENCY, strlen (MINT_CURRENCY) + 1); - -  return amount; -}  /** @@ -1290,3 +1302,6 @@ TALER_MINT_db_execute_refresh_link (struct MHD_Connection *connection,    json_decref (root);    return res;  } + + +/* end of taler-mint-httpd_db.c */ diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c index 307e6ec1..bad87429 100644 --- a/src/mint/taler-mint-httpd_responses.c +++ b/src/mint/taler-mint-httpd_responses.c @@ -309,31 +309,132 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,  /** + * Send proof that a /deposit, /refresh/melt or /lock request is + * invalid to client.  This function will create a message with all of + * the operations affecting the coin that demonstrate that the coin + * has insufficient value. + * + * @param connection connection to the client + * @param tl transaction list to use to build reply + * @return MHD result code + */ +int +TALER_MINT_reply_insufficient_funds (struct MHD_Connection *connection, +                                     const struct TALER_MINT_DB_TransactionList *tl) +{ +  const struct TALER_MINT_DB_TransactionList *pos; +  int ret; + +  // FIXME: implement properly! +  for (pos = tl; NULL != pos; pos = pos->next) +  { +    switch (pos->type) +    { +    case TALER_MINT_DB_TT_DEPOSIT: +      /* FIXME: add operation details to json reply */ +      break; +    case TALER_MINT_DB_TT_REFRESH_MELT: +      /* FIXME: add operation details to json reply */ +      break; +    case TALER_MINT_DB_TT_LOCK: +      /* FIXME: add operation details to json reply */ +      break; +    } +  } + +  ret = TALER_MINT_reply_json_pack (connection, +                                    MHD_HTTP_FORBIDDEN, +                                    "{s:s}", +                                    "error", "insufficient funds"); +  return ret; +} + + +/**   * Send reserve status information to client.   *   * @param connection connection to the client - * @param balance current reserve balance - * @param expiration when will the reserve expire + * @param rh reserve history to return   * @return MHD result code   */  int  TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection, -                                          const struct TALER_Amount balance, -                                          struct GNUNET_TIME_Absolute expiration) +                                          const struct ReserveHistory *rh)  { +  struct TALER_Amount deposit_total; +  struct TALER_Amount withdraw_total; +  struct TALER_Amount balance; +  struct TALER_Amount value;    json_t *json_balance; -  json_t *json_expiration; +  json_t *json_history;    int ret; +  struct MintKeyState *key_state; +  const struct ReserveHistory *pos; +  struct TALER_MINT_DenomKeyIssuePriv *dki; + +  json_history = json_array (); +  ret = 0; +  for (pos = rh; NULL != pos; pos = pos->next) +  { +    switch (pos->type) +    { +    case TALER_MINT_DB_RO_BANK_TO_MINT: +      if (0 == ret) +        deposit_total = pos->details.bank->amount; +      else +        deposit_total = TALER_amount_add (deposit_total, +                                          pos->details.bank->amount); +      ret = 1; +      json_array_append_new (json_history, +                             json_pack ("{s:s, s:o, s:o}", +                                        "type", "DEPOSIT", +                                        "wire", pos->details.bank->wire, +                                        "amount", TALER_JSON_from_amount (pos->details.bank->amount))); +      break; +    case TALER_MINT_DB_RO_WITHDRAW_COIN: +      break; +    } +  } + +  key_state = TALER_MINT_key_state_acquire (); +  ret = 0; +  for (pos = rh; NULL != pos; pos = pos->next) +  { +    switch (pos->type) +    { +    case TALER_MINT_DB_RO_BANK_TO_MINT: +      break; +    case TALER_MINT_DB_RO_WITHDRAW_COIN: +      dki = TALER_MINT_get_denom_key (key_state, +                                      pos->details.withdraw->denom_pub); +      value = TALER_amount_ntoh (dki->issue.value); +      if (0 == ret) +        withdraw_total = value; +      else +        withdraw_total = TALER_amount_add (withdraw_total, +                                           value); +      ret = 1; +      /* FIXME: add `struct CollectableBlindcoin` as JSON here as well! (#3527) */ +      json_array_append_new (json_history, +                             json_pack ("{s:s, s:o, s:o}", +                                        "type", "WITHDRAW", +                                        "amount", TALER_JSON_from_amount (value))); + +      break; +    } +  } +  TALER_MINT_key_state_release (key_state); +  balance = TALER_amount_subtract (deposit_total, +                                   withdraw_total);    json_balance = TALER_JSON_from_amount (balance); -  json_expiration = TALER_JSON_from_abs (expiration);    ret = TALER_MINT_reply_json_pack (connection,                                      MHD_HTTP_OK,                                      "{s:o, s:o}",                                      "balance", json_balance, -                                    "expiration", json_expiration); +                                    "history", json_history); +  json_decref (json_history);    json_decref (json_balance); -  json_decref (json_expiration);    return ret;  } @@ -354,7 +455,7 @@ TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection,    char *sig_buf;    int ret; -  /* FIXME: use TALER_JSON_from_sig here instead! */ +  /* FIXME: use TALER_JSON_from_sig here instead!? */    sig_buf_size = GNUNET_CRYPTO_rsa_signature_encode (collectable->sig,                                                       &sig_buf);    sig_json = TALER_JSON_from_data (sig_buf, diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h index f8a671e1..5e2f9863 100644 --- a/src/mint/taler-mint-httpd_responses.h +++ b/src/mint/taler-mint-httpd_responses.h @@ -182,17 +182,30 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,  /** + * Send proof that a /deposit, /refresh/melt or /lock request is + * invalid to client.  This function will create a message with all of + * the operations affecting the coin that demonstrate that the coin + * has insufficient value. + * + * @param connection connection to the client + * @param tl transaction list to use to build reply + * @return MHD result code + */ +int +TALER_MINT_reply_insufficient_funds (struct MHD_Connection *connection, +                                     const struct TALER_MINT_DB_TransactionList *tl); + + +/**   * Send reserve status information to client.   *   * @param connection connection to the client - * @param balance current reserve balance - * @param expiration when will the reserve expire + * @param rh reserve history to return   * @return MHD result code   */  int  TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection, -                                          struct TALER_Amount balance, -                                          struct GNUNET_TIME_Absolute expiration); +                                          const struct ReserveHistory *rh);  /** diff --git a/src/util/amount.c b/src/util/amount.c index bb5bf0d5..65fac78e 100644 --- a/src/util/amount.c +++ b/src/util/amount.c @@ -19,6 +19,12 @@   * @author Sree Harsha Totakura <sreeharsha@totakura.in>   * @author Florian Dold   * @author Benedikt Mueller + * + * TODO: + * - the way this library currently deals with underflow/overflow + *   is insufficient; just going for UINT32_MAX on overflow + *   will not do; similar issues for incompatible currencies; + *   we need some more explicit logic to say 'bogus value',   */  #include "platform.h"  #include "taler_util.h" @@ -169,7 +175,8 @@ TALER_amount_ntoh (struct TALER_AmountNBO dn)   * @return result of the comparison   */  int -TALER_amount_cmp (struct TALER_Amount a1, struct TALER_Amount a2) +TALER_amount_cmp (struct TALER_Amount a1, +                  struct TALER_Amount a2)  {    a1 = TALER_amount_normalize (a1);    a2 = TALER_amount_normalize (a2); @@ -195,7 +202,8 @@ TALER_amount_cmp (struct TALER_Amount a1, struct TALER_Amount a2)   * @return (a1-a2) or 0 if a2>=a1   */  struct TALER_Amount -TALER_amount_subtract (struct TALER_Amount a1, struct TALER_Amount a2) +TALER_amount_subtract (struct TALER_Amount a1, +                       struct TALER_Amount a2)  {    a1 = TALER_amount_normalize (a1);    a2 = TALER_amount_normalize (a2); @@ -233,7 +241,8 @@ TALER_amount_subtract (struct TALER_Amount a1, struct TALER_Amount a2)   * @return sum of a1 and a2   */  struct TALER_Amount -TALER_amount_add (struct TALER_Amount a1, struct TALER_Amount a2) +TALER_amount_add (struct TALER_Amount a1, +                  struct TALER_Amount a2)  {    a1 = TALER_amount_normalize (a1);    a2 = TALER_amount_normalize (a2); @@ -243,17 +252,25 @@ TALER_amount_add (struct TALER_Amount a1, struct TALER_Amount a2)    if (0 == a1.currency[0])    { -    memcpy (a2.currency, a1.currency, TALER_CURRENCY_LEN); +    memcpy (a2.currency, +            a1.currency, +            TALER_CURRENCY_LEN);    }    if (0 == a2.currency[0])    { -    memcpy (a1.currency, a2.currency, TALER_CURRENCY_LEN); +    memcpy (a1.currency, +            a2.currency, +            TALER_CURRENCY_LEN);    } -  if (0 != a1.currency[0] && 0 != memcmp (a1.currency, a2.currency, TALER_CURRENCY_LEN)) +  if ( (0 != a1.currency[0]) && +       (0 != memcmp (a1.currency, +                     a2.currency, +                     TALER_CURRENCY_LEN)) )    { -    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "adding mismatching currencies\n"); +    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                "adding mismatching currencies\n");    }    if (a1.value < a2.value) @@ -312,11 +329,18 @@ TALER_amount_to_string (struct TALER_Amount amount)        n = (n * 10) % (AMOUNT_FRAC_BASE);      }      tail[i] = 0; -    len = GNUNET_asprintf (&result, "%s:%lu.%s", curr, (unsigned long) amount.value, tail); +    len = GNUNET_asprintf (&result, +                           "%s:%lu.%s", +                           curr, +                           (unsigned long) amount.value, +                           tail);    }    else    { -    len = GNUNET_asprintf (&result, "%s:%lu", curr, (unsigned long) amount.value); +    len = GNUNET_asprintf (&result, +                           "%s:%lu", +                           curr, +                           (unsigned long) amount.value);    }    GNUNET_assert (len > 0);    return result;  | 
