diff options
Diffstat (limited to 'src/mint-tools/taler-mint-reservemod.c')
| -rw-r--r-- | src/mint-tools/taler-mint-reservemod.c | 305 | 
1 files changed, 305 insertions, 0 deletions
diff --git a/src/mint-tools/taler-mint-reservemod.c b/src/mint-tools/taler-mint-reservemod.c new file mode 100644 index 00000000..3261f47c --- /dev/null +++ b/src/mint-tools/taler-mint-reservemod.c @@ -0,0 +1,305 @@ +/* +  This file is part of TALER +  Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors) + +  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 +  Foundation; either version 3, or (at your option) any later version. + +  TALER is distributed in the hope that it will be useful, but WITHOUT ANY +  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +  A PARTICULAR PURPOSE.  See the GNU General Public License for more details. + +  You should have received a copy of the GNU General Public License along with +  TALER; see the file COPYING.  If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-mint-reservemod.c + * @brief Modify reserves.  Allows manipulation of reserve balances. + * @author Florian Dold + * @author Benedikt Mueller + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <libpq-fe.h> +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_mintdb_plugin.h" +#include "taler_mintdb_lib.h" + + +/** + * Director of the mint, containing the keys. + */ +static char *mint_directory; + +/** + * Public key of the reserve to manipulate. + */ +static struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub; + +/** + * Handle to the mint's configuration + */ +static struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Database connection handle. + */ +static PGconn *db_conn; + + +/** + * Create a new or add to existing reserve.  Fails if currencies do + * not match. + * + * @param denom denomination to add + * @return #GNUNET_OK on success, + *         #GNUNET_SYSERR on error + */ +// FIXME: this should use the DB abstraction layer. (#3717) +// FIXME: this should be done by adding an inbound transaction +//        to the table with the transactions for this reserve, +//        not by modifying some 'total' value for the reserve! +//        (we should in fact probably never modify, always just append!) (#3633) +static int +reservemod_add (struct TALER_Amount denom) +{ +  PGresult *result; +  const void *param_values[] = { +    reserve_pub +  }; +  int param_lengths[] = { +    sizeof(struct GNUNET_CRYPTO_EddsaPublicKey) +  }; +  int param_formats[] = { +    1 +  }; +  struct TALER_Amount old_denom; +  struct TALER_Amount new_denom; +  struct TALER_AmountNBO new_denom_nbo; + +  result = PQexecParams (db_conn, +                         "SELECT balance_value, balance_fraction, balance_currency" +                         " FROM reserves" +                         " WHERE reserve_pub=$1" +                         " LIMIT 1;", +                         1, +                         NULL, +                         (const char * const *) param_values, +                         param_lengths, +                         param_formats, +                         1); +  if (PGRES_TUPLES_OK != PQresultStatus (result)) +  { +    fprintf (stderr, +             "Select failed: %s\n", +             PQresultErrorMessage (result)); +    return GNUNET_SYSERR; +  } +  if (0 == PQntuples (result)) +  { +    struct GNUNET_TIME_AbsoluteNBO exnbo; +    uint32_t value = htonl (denom.value); +    uint32_t fraction = htonl (denom.fraction); +    const void *param_values[] = { +      reserve_pub, +      &value, +      &fraction, +      denom.currency, +      &exnbo +    }; +    int param_lengths[] = { +      sizeof (struct GNUNET_CRYPTO_EddsaPublicKey), +      sizeof (uint32_t), +      sizeof (uint32_t), +      strlen (denom.currency), +      sizeof (struct GNUNET_TIME_AbsoluteNBO) +    }; +    int param_formats[] = { +      1, 1, 1, 1, 1 +    }; + +    exnbo = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS)); +    result = PQexecParams (db_conn, +                           "INSERT INTO reserves (reserve_pub, balance_value, balance_fraction, balance_currency, expiration_date)" +                           " VALUES ($1,$2,$3,$4,$5);", +                           5, +                           NULL, +                           (const char **) param_values, +                           param_lengths, +                           param_formats, +                           1); + +    if (PGRES_COMMAND_OK != PQresultStatus (result)) +    { +      fprintf (stderr, +               "Insert failed: %s\n", +               PQresultErrorMessage (result)); +      return GNUNET_SYSERR; +    } +  } +  else +  { +    const void *param_values[] = { +      &new_denom_nbo.value, +      &new_denom_nbo.fraction, +      reserve_pub +    }; +    int param_lengths[] = { +      sizeof (new_denom_nbo.value), +      sizeof (new_denom_nbo.fraction), +      sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +    }; +    int param_formats[] = { +      1, 1, 1 +    }; + +    GNUNET_assert (GNUNET_OK == +                   TALER_PQ_extract_amount (result, 0, +                                            "balance_value", +                                            "balance_fraction", +                                            "balance_currency", +                                            &old_denom)); +    TALER_amount_add (&new_denom, +                      &old_denom, +                      &denom); +    TALER_amount_hton (&new_denom_nbo, +                       &new_denom); +    result = PQexecParams (db_conn, +                           "UPDATE reserves" +                           " SET balance_value = $1, balance_fraction = $2, status_sig = NULL, status_sign_pub = NULL" +                           " WHERE reserve_pub = $3;", +                           3, +                           NULL, +                           (const char **) param_values, +                           param_lengths, +                           param_formats, +                           1); + +    if (PGRES_COMMAND_OK != PQresultStatus (result)) +    { +      fprintf (stderr, +               "Update failed: %s\n", +               PQresultErrorMessage (result)); +      return GNUNET_SYSERR; +    } +    /* Yes, for historic reasons libpq returns a 'const char *'... */ +    if (0 != strcmp ("1", +                     PQcmdTuples (result))) +    { +      fprintf (stderr, +               "Update failed (updated `%s' tupes instead of '1')\n", +               PQcmdTuples (result)); +      return GNUNET_SYSERR; +    } +  } +  return GNUNET_OK; +} + + +/** + * The main function of the reservemod tool + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ +  static char *reserve_pub_str; +  static char *add_str; +  static const struct GNUNET_GETOPT_CommandLineOption options[] = { +    GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-reservemod OPTIONS"), +    {'d', "mint-dir", "DIR", +     "mint directory with keys to update", 1, +     &GNUNET_GETOPT_set_filename, &mint_directory}, +    {'R', "reserve", "KEY", +     "reserve (public key) to modify", 1, +     &GNUNET_GETOPT_set_string, &reserve_pub_str}, +    {'a', "add", "DENOM", +     "value to add", 1, +     &GNUNET_GETOPT_set_string, &add_str}, +    GNUNET_GETOPT_OPTION_END +  }; +  char *connection_cfg_str; + +  GNUNET_assert (GNUNET_OK == +                 GNUNET_log_setup ("taler-mint-reservemod", +                                   "WARNING", +                                   NULL)); + +  if (GNUNET_GETOPT_run ("taler-mint-reservemod", +                         options, +                         argc, argv) < 0) +    return 1; +  if (NULL == mint_directory) +  { +    fprintf (stderr, +             "Mint directory not given\n"); +    return 1; +  } + +  reserve_pub = GNUNET_new (struct GNUNET_CRYPTO_EddsaPublicKey); +  if ((NULL == reserve_pub_str) || +      (GNUNET_OK != +       GNUNET_STRINGS_string_to_data (reserve_pub_str, +                                      strlen (reserve_pub_str), +                                      reserve_pub, +                                      sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))) +  { +    fprintf (stderr, +             "Parsing reserve key invalid\n"); +    return 1; +  } +  cfg = TALER_config_load (mint_directory); +  if (NULL == cfg) +  { +    fprintf (stderr, +             "Failed to load mint configuration\n"); +    return 1; +  } +  if (GNUNET_OK != +      GNUNET_CONFIGURATION_get_value_string (cfg, +                                             "mint", +                                             "db", +                                             &connection_cfg_str)) +  { +    fprintf (stderr, +             "Database configuration string not found\n"); +    return 1; +  } +  db_conn = PQconnectdb (connection_cfg_str); +  if (CONNECTION_OK != PQstatus (db_conn)) +  { +    fprintf (stderr, +             "Database connection failed: %s\n", +             PQerrorMessage (db_conn)); +    return 1; +  } +  if (NULL != add_str) +  { +    struct TALER_Amount add_value; + +    if (GNUNET_OK != +        TALER_string_to_amount (add_str, +                                &add_value)) +    { +      fprintf (stderr, +               "Failed to parse currency amount `%s'\n", +               add_str); +      return 1; +    } +    if (GNUNET_OK != +        reservemod_add (add_value)) +    { +      fprintf (stderr, +               "Failed to update reserve.\n"); +      return 1; +    } +  } +  return 0; +} + +/* end taler-mint-reservemod.c */  | 
