diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/include/taler_mintdb_plugin.h | 3 | ||||
| -rw-r--r-- | src/mint/taler-mint-httpd_db.c | 466 | ||||
| -rwxr-xr-x | src/mint/test_taler_mint_httpd_afl.sh | 33 | ||||
| -rw-r--r-- | src/mintdb/plugin_mintdb_postgres.c | 26 | 
4 files changed, 332 insertions, 196 deletions
| diff --git a/src/include/taler_mintdb_plugin.h b/src/include/taler_mintdb_plugin.h index 851ed526..c8013acc 100644 --- a/src/include/taler_mintdb_plugin.h +++ b/src/include/taler_mintdb_plugin.h @@ -629,7 +629,8 @@ struct TALER_MINTDB_Plugin     *     * @param cls the @e cls of this struct with the plugin-specific state     * @param session connection to use -   * @return #GNUNET_OK on success +   * @return #GNUNET_OK on success, #GNUNET_NO if the transaction +   *         can be retried, #GNUNET_SYSERR on hard failures     */    int    (*commit) (void *cls, diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index 021a3155..da656abc 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c @@ -24,6 +24,67 @@  #include "taler-mint-httpd_responses.h"  #include "taler-mint-httpd_keystate.h" +/** + * How often should we retry a transaction before giving up + * (for transactions resulting in serialization/dead locks only). + */ +#define MAX_TRANSACTION_COMMIT_RETRIES 3 + +/** + * Code to begin a transaction, must be inline as we define a block + * that ends with #COMMIT_TRANSACTION() within which we perform a number + * of retries.  Note that this code may call "return" internally, so + * it must be called within a function where any cleanup will be done + * by the caller. Furthermore, the function's return value must + * match that of a #TMH_RESPONSE_reply_internal_db_error() status code. + * + * @param session session handle + * @param connection connection handle + */ +#define START_TRANSACTION(session,connection)                 \ +{ /* start new scope, will be ended by COMMIT_TRANSACTION() */\ +  unsigned int transaction_retries = 0;                       \ +  int transaction_commit_result;                              \ +transaction_start_label: /* we will use goto for retries */   \ +  if (GNUNET_OK !=                                            \ +      TMH_plugin->start (TMH_plugin->cls,                     \ +                         session))                            \ +  {                                                           \ +    GNUNET_break (0);                                         \ +    return TMH_RESPONSE_reply_internal_db_error (connection); \ +  } + +/** + * Code to conclude a transaction, dual to #START_TRANSACTION().  Note + * that this code may call "return" internally, so it must be called + * within a function where any cleanup will be done by the caller. + * Furthermore, the function's return value must match that of a + * #TMH_RESPONSE_reply_internal_db_error() status code. + * + * @param session session handle + * @param connection connection handle + */ +#define COMMIT_TRANSACTION(session,connection)                             \ +  transaction_commit_result =                                              \ +    TMH_plugin->commit (TMH_plugin->cls,                                   \ +                        session);                                          \ +  if (GNUNET_SYSERR == transaction_commit_result)                          \ +  {                                                                        \ +    TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ +    return TMH_RESPONSE_reply_commit_error (connection);                   \ +  }                                                                        \ +  if (GNUNET_NO == transaction_commit_result)                              \ +  {                                                                        \ +    TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ +    if (transaction_retries++ <= MAX_TRANSACTION_COMMIT_RETRIES)           \ +      goto transaction_start_label;                                        \ +    TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n",       \ +                       transaction_retries,                                \ +                       __FUNCTION__);                                      \ +    return TMH_RESPONSE_reply_commit_error (connection);                   \ +  }                                                                        \ +} /* end of scope opened by BEGIN_TRANSACTION */ +  /**   * Calculate the total value of all transactions performed. @@ -130,13 +191,8 @@ TMH_DB_execute_deposit (struct MHD_Connection *connection,                       &dki->issue.properties.value);    TMH_KS_release (mks); -  if (GNUNET_OK != -      TMH_plugin->start (TMH_plugin->cls, -                         session)) -  { -    GNUNET_break (0); -    return TMH_RESPONSE_reply_internal_db_error (connection); -  } +  START_TRANSACTION (session, connection); +    /* fee for THIS transaction */    spent = deposit->amount_with_fee;    /* add cost of all previous transactions */ @@ -179,13 +235,7 @@ TMH_DB_execute_deposit (struct MHD_Connection *connection,      return TMH_RESPONSE_reply_internal_db_error (connection);    } -  if (GNUNET_OK != -      TMH_plugin->commit (TMH_plugin->cls, -                          session)) -  { -    TALER_LOG_WARNING ("/deposit transaction commit failed\n"); -    return TMH_RESPONSE_reply_commit_error (connection); -  } +  COMMIT_TRANSACTION(session, connection);    GNUNET_assert (GNUNET_OK ==                   TALER_amount_subtract (&amount_without_fee,                                          &deposit->amount_with_fee, @@ -242,35 +292,36 @@ TMH_DB_execute_reserve_status (struct MHD_Connection *connection,  /** - * Execute a "/reserve/withdraw". Given a reserve and a properly signed - * request to withdraw a coin, check the balance of the reserve and - * if it is sufficient, store the request and return the signed - * blinded envelope. + * Try to execute /reserve/withdraw transaction.   * - * @param connection the MHD connection to handle - * @param reserve public key of the reserve + * @param connection request we are handling + * @param session database session we are using + * @param reserve reserve to withdraw from   * @param denomination_pub public key of the denomination requested + * @param dki denomination to withdraw   * @param blinded_msg blinded message to be signed   * @param blinded_msg_len number of bytes in @a blinded_msg   * @param signature signature over the withdraw request, to be stored in DB + * @param denom_sig[out] where to write the resulting signature + *        (used to release memory in case of transaction failure   * @return MHD result code   */ -int -TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection, -                                 const struct TALER_ReservePublicKeyP *reserve, -                                 const struct TALER_DenominationPublicKey *denomination_pub, -                                 const char *blinded_msg, -                                 size_t blinded_msg_len, -                                 const struct TALER_ReserveSignatureP *signature) +static int +execute_reserve_withdraw_transaction (struct MHD_Connection *connection, +                                      struct TALER_MINTDB_Session *session, +                                      struct TMH_KS_StateHandle *key_state, +                                      const struct TALER_ReservePublicKeyP *reserve, +                                      const struct TALER_DenominationPublicKey *denomination_pub, +                                      const struct TALER_MINTDB_DenominationKeyIssueInformation *dki, +                                      const char *blinded_msg, +                                      size_t blinded_msg_len, +                                      const struct TALER_ReserveSignatureP *signature, +                                      struct TALER_DenominationSignature *denom_sig)  { -  struct TALER_MINTDB_Session *session;    struct TALER_MINTDB_ReserveHistory *rh;    const struct TALER_MINTDB_ReserveHistory *pos; -  struct TMH_KS_StateHandle *key_state; -  struct TALER_MINTDB_CollectableBlindcoin collectable; -  struct TALER_MINTDB_DenominationKeyIssueInformation *dki;    struct TALER_MINTDB_DenominationKeyIssueInformation *tdki; -  struct GNUNET_CRYPTO_rsa_Signature *sig; +  struct TALER_MINTDB_CollectableBlindcoin collectable;    struct TALER_Amount amount_required;    struct TALER_Amount deposit_total;    struct TALER_Amount withdraw_total; @@ -280,60 +331,8 @@ TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,    struct GNUNET_HashCode h_blind;    int res; -  GNUNET_CRYPTO_hash (blinded_msg, -                      blinded_msg_len, -                      &h_blind); - -  if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, -                                                  TMH_test_mode))) -  { -    GNUNET_break (0); -    return TMH_RESPONSE_reply_internal_db_error (connection); -  } -  res = TMH_plugin->get_withdraw_info (TMH_plugin->cls, -                                       session, -                                       &h_blind, -                                       &collectable); -  if (GNUNET_SYSERR == res) -  { -    GNUNET_break (0); -    return TMH_RESPONSE_reply_internal_db_error (connection); -  } - -  /* Don't sign again if we have already signed the coin */ -  if (GNUNET_YES == res) -  { -    res = TMH_RESPONSE_reply_reserve_withdraw_success (connection, -                                                    &collectable); -    GNUNET_CRYPTO_rsa_signature_free (collectable.sig.rsa_signature); -    GNUNET_CRYPTO_rsa_public_key_free (collectable.denom_pub.rsa_public_key); -    return res; -  } -  GNUNET_assert (GNUNET_NO == res); -    /* Check if balance is sufficient */ -  key_state = TMH_KS_acquire (); -  dki = TMH_KS_denomination_key_lookup (key_state, -                                        denomination_pub, -					TMH_KS_DKU_WITHDRAW); -  if (NULL == dki) -  { -    TMH_KS_release (key_state); -    return TMH_RESPONSE_reply_json_pack (connection, -                                         MHD_HTTP_NOT_FOUND, -                                         "{s:s}", -                                         "error", -                                         "Denomination not found"); -  } -  if (GNUNET_OK != -      TMH_plugin->start (TMH_plugin->cls, -                         session)) -  { -    GNUNET_break (0); -    TMH_KS_release (key_state); -    return TMH_RESPONSE_reply_internal_db_error (connection); -  } - +  START_TRANSACTION (session, connection);    rh = TMH_plugin->get_reserve_history (TMH_plugin->cls,                                          session,                                          reserve); @@ -341,7 +340,6 @@ TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,    {      TMH_plugin->rollback (TMH_plugin->cls,                            session); -    TMH_KS_release (key_state);      return TMH_RESPONSE_reply_arg_unknown (connection,                                             "reserve_pub");    } @@ -359,7 +357,6 @@ TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,    {      TMH_plugin->rollback (TMH_plugin->cls,                            session); -    TMH_KS_release (key_state);      return TMH_RESPONSE_reply_internal_db_error (connection);    } @@ -380,7 +377,6 @@ TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,          {            TMH_plugin->rollback (TMH_plugin->cls,                                  session); -          TMH_KS_release (key_state);            return TMH_RESPONSE_reply_internal_db_error (connection);          }        res |= 1; @@ -401,7 +397,6 @@ TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,          {            TMH_plugin->rollback (TMH_plugin->cls,                                  session); -          TMH_KS_release (key_state);            return TMH_RESPONSE_reply_internal_db_error (connection);          }        res |= 2; @@ -428,11 +423,10 @@ TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,    if (0 < TALER_amount_cmp (&amount_required,                              &balance))    { -    TMH_KS_release (key_state);      TMH_plugin->rollback (TMH_plugin->cls,                            session);      res = TMH_RESPONSE_reply_reserve_withdraw_insufficient_funds (connection, -                                                               rh); +                                                                  rh);      TMH_plugin->free_reserve_history (TMH_plugin->cls,                                        rh);      return res; @@ -441,11 +435,11 @@ TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,                                      rh);    /* Balance is good, sign the coin! */ -  sig = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key, -                                blinded_msg, -                                blinded_msg_len); -  TMH_KS_release (key_state); -  if (NULL == sig) +  denom_sig->rsa_signature +    = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key, +                              blinded_msg, +                              blinded_msg_len); +  if (NULL == denom_sig->rsa_signature)    {      GNUNET_break (0);      TMH_plugin->rollback (TMH_plugin->cls, @@ -453,7 +447,7 @@ TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,      return TMH_RESPONSE_reply_internal_error (connection,                                                "Internal error");    } -  collectable.sig.rsa_signature = sig; +  collectable.sig = *denom_sig;    collectable.denom_pub = *denomination_pub;    collectable.amount_with_fee = amount_required;    collectable.withdraw_fee = fee_withdraw; @@ -466,21 +460,105 @@ TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection,                                          &collectable))    {      GNUNET_break (0); -    GNUNET_CRYPTO_rsa_signature_free (sig);      TMH_plugin->rollback (TMH_plugin->cls,                            session);      return TMH_RESPONSE_reply_internal_db_error (connection);    } -  if (GNUNET_OK != -      TMH_plugin->commit (TMH_plugin->cls, -                          session)) +  COMMIT_TRANSACTION (session, connection); + +  return TMH_RESPONSE_reply_reserve_withdraw_success (connection, +                                                      &collectable); +} + + + +/** + * Execute a "/reserve/withdraw". Given a reserve and a properly signed + * request to withdraw a coin, check the balance of the reserve and + * if it is sufficient, store the request and return the signed + * blinded envelope. + * + * @param connection the MHD connection to handle + * @param reserve public key of the reserve + * @param denomination_pub public key of the denomination requested + * @param blinded_msg blinded message to be signed + * @param blinded_msg_len number of bytes in @a blinded_msg + * @param signature signature over the withdraw request, to be stored in DB + * @return MHD result code + */ +int +TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection, +                                 const struct TALER_ReservePublicKeyP *reserve, +                                 const struct TALER_DenominationPublicKey *denomination_pub, +                                 const char *blinded_msg, +                                 size_t blinded_msg_len, +                                 const struct TALER_ReserveSignatureP *signature) +{ +  struct TALER_MINTDB_Session *session; +  struct TMH_KS_StateHandle *key_state; +  struct TALER_MINTDB_DenominationKeyIssueInformation *dki; +  struct TALER_MINTDB_CollectableBlindcoin collectable; +  struct TALER_DenominationSignature denom_sig; +  struct GNUNET_HashCode h_blind; +  int res; + +  GNUNET_CRYPTO_hash (blinded_msg, +                      blinded_msg_len, +                      &h_blind); + +  if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, +                                                  TMH_test_mode))) +  { +    GNUNET_break (0); +    return TMH_RESPONSE_reply_internal_db_error (connection); +  } +  res = TMH_plugin->get_withdraw_info (TMH_plugin->cls, +                                       session, +                                       &h_blind, +                                       &collectable); +  if (GNUNET_SYSERR == res) +  { +    GNUNET_break (0); +    return TMH_RESPONSE_reply_internal_db_error (connection); +  } + +  /* Don't sign again if we have already signed the coin */ +  if (GNUNET_YES == res)    { -    TALER_LOG_WARNING ("/reserve/withdraw transaction commit failed\n"); -    return TMH_RESPONSE_reply_commit_error (connection); +    res = TMH_RESPONSE_reply_reserve_withdraw_success (connection, +                                                       &collectable); +    GNUNET_CRYPTO_rsa_signature_free (collectable.sig.rsa_signature); +    GNUNET_CRYPTO_rsa_public_key_free (collectable.denom_pub.rsa_public_key); +    return res;    } -  res = TMH_RESPONSE_reply_reserve_withdraw_success (connection, -                                                  &collectable); -  GNUNET_CRYPTO_rsa_signature_free (sig); +  GNUNET_assert (GNUNET_NO == res); + +  key_state = TMH_KS_acquire (); +  dki = TMH_KS_denomination_key_lookup (key_state, +                                        denomination_pub, +					TMH_KS_DKU_WITHDRAW); +  if (NULL == dki) +  { +    TMH_KS_release (key_state); +    return TMH_RESPONSE_reply_json_pack (connection, +                                         MHD_HTTP_NOT_FOUND, +                                         "{s:s}", +                                         "error", +                                         "Denomination not found"); +  } +  denom_sig.rsa_signature = NULL; +  res = execute_reserve_withdraw_transaction (connection, +                                              session, +                                              key_state, +                                              reserve, +                                              denomination_pub, +                                              dki, +                                              blinded_msg, +                                              blinded_msg_len, +                                              signature, +                                              &denom_sig); +  GNUNET_CRYPTO_rsa_signature_free (denom_sig.rsa_signature); +  TMH_KS_release (key_state);    return res;  } @@ -633,13 +711,7 @@ TMH_DB_execute_refresh_melt (struct MHD_Connection *connection,      GNUNET_break (0);      return TMH_RESPONSE_reply_internal_db_error (connection);    } -  if (GNUNET_OK != -      TMH_plugin->start (TMH_plugin->cls, -                         session)) -  { -    GNUNET_break (0); -    return TMH_RESPONSE_reply_internal_db_error (connection); -  } +  START_TRANSACTION (session, connection);    res = TMH_plugin->get_refresh_session (TMH_plugin->cls,                                           session,                                           session_hash, @@ -741,13 +813,7 @@ TMH_DB_execute_refresh_melt (struct MHD_Connection *connection,      }    } -  if (GNUNET_OK != -      TMH_plugin->commit (TMH_plugin->cls, -                          session)) -  { -    TALER_LOG_WARNING ("/refresh/melt transaction commit failed\n"); -    return TMH_RESPONSE_reply_commit_error (connection); -  } +  COMMIT_TRANSACTION (session, connection);    return TMH_RESPONSE_reply_refresh_melt_success (connection,                                                    session_hash,                                                    refresh_session.noreveal_index); @@ -1038,10 +1104,10 @@ refresh_mint_coin (struct MHD_Connection *connection,    }    if (GNUNET_OK !=        TMH_plugin->insert_refresh_out (TMH_plugin->cls, -                                              session, -                                              session_hash, -                                              coin_off, -                                              &ev_sig)) +                                      session, +                                      session_hash, +                                      coin_off, +                                      &ev_sig))    {      GNUNET_break (0);      GNUNET_CRYPTO_rsa_signature_free (ev_sig.rsa_signature); @@ -1052,6 +1118,74 @@ refresh_mint_coin (struct MHD_Connection *connection,  /** + * The client request was well-formed, now execute the DB transaction + * of a "/refresh/reveal" operation.  We use the @a ev_sigs and + * @a commit_coins to clean up resources after this function returns + * as we might experience retries of the database transaction. + * + * @param connection the MHD connection to handle + * @param session database session + * @param session_hash hash identifying the refresh session + * @param refresh_session information about the refresh operation we are doing + * @param denom_pubs array of "num_newcoins" denomination keys for the new coins + * @param ev_sigs[out] where to store generated signatures for the new coins, + *                     array of length "num_newcoins", memory released by the + *                     caller + * @param commit_coins[out] array of length "num_newcoins" to be used for + *                     information about the new coins from the commitment. + * @return MHD result code + */ +static int +execute_refresh_reveal_transaction (struct MHD_Connection *connection, +                                    struct TALER_MINTDB_Session *session, +                                    const struct GNUNET_HashCode *session_hash, +                                    struct TALER_MINTDB_RefreshSession *refresh_session, +                                    struct TALER_MINTDB_RefreshMelt *melts, +                                    struct TALER_DenominationPublicKey *denom_pubs, +                                    struct TALER_DenominationSignature *ev_sigs, +                                    struct TALER_MINTDB_RefreshCommitCoin *commit_coins) +{ +  unsigned int j; +  struct TMH_KS_StateHandle *key_state; + +  START_TRANSACTION (session, connection); +  if (GNUNET_OK != +      TMH_plugin->get_refresh_commit_coins (TMH_plugin->cls, +                                            session, +                                            session_hash, +                                            refresh_session->noreveal_index, +                                            refresh_session->num_newcoins, +                                            commit_coins)) +  { +    GNUNET_break (0); +    return TMH_RESPONSE_reply_internal_db_error (connection); +  } +  key_state = TMH_KS_acquire (); +  for (j=0;j<refresh_session->num_newcoins;j++) +  { +    if (NULL == ev_sigs[j].rsa_signature) /* could be non-NULL during retries */ +      ev_sigs[j] = refresh_mint_coin (connection, +                                      session, +                                      session_hash, +                                      key_state, +                                      &denom_pubs[j], +                                      &commit_coins[j], +                                      j); +    if (NULL == ev_sigs[j].rsa_signature) +    { +      TMH_KS_release (key_state); +      return TMH_RESPONSE_reply_internal_db_error (connection); +    } +  } +  TMH_KS_release (key_state); +  COMMIT_TRANSACTION (session, connection); +  return TMH_RESPONSE_reply_refresh_reveal_success (connection, +                                                    refresh_session->num_newcoins, +                                                    ev_sigs); +} + + +/**   * Execute a "/refresh/reveal".  The client is revealing to us the   * transfer keys for @a #TALER_CNC_KAPPA-1 sets of coins.  Verify that the   * revealed transfer keys would allow linkage to the blinded coins, @@ -1074,7 +1208,6 @@ TMH_DB_execute_refresh_reveal (struct MHD_Connection *connection,    int res;    struct TALER_MINTDB_Session *session;    struct TALER_MINTDB_RefreshSession refresh_session; -  struct TMH_KS_StateHandle *key_state;    struct TALER_MINTDB_RefreshMelt *melts;    struct TALER_DenominationPublicKey *denom_pubs;    struct TALER_DenominationSignature *ev_sigs; @@ -1164,82 +1297,27 @@ TMH_DB_execute_refresh_reveal (struct MHD_Connection *connection,    GNUNET_free (melts);    /* Client request OK, start transaction */ -  if (GNUNET_OK != -      TMH_plugin->start (TMH_plugin->cls, -                         session)) -  { -    GNUNET_break (0); -    for (j=0;j<refresh_session.num_newcoins;j++) -      GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); -    GNUNET_free (denom_pubs); -    return TMH_RESPONSE_reply_internal_db_error (connection); -  } -    commit_coins = GNUNET_malloc (refresh_session.num_newcoins *                                  sizeof (struct TALER_MINTDB_RefreshCommitCoin)); -  if (GNUNET_OK != -      TMH_plugin->get_refresh_commit_coins (TMH_plugin->cls, -                                            session, -                                            session_hash, -                                            refresh_session.noreveal_index, -                                            refresh_session.num_newcoins, -                                            commit_coins)) -  { -    GNUNET_break (0); -    GNUNET_free (commit_coins); -    for (j=0;j<refresh_session.num_newcoins;j++) -      GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); -    GNUNET_free (denom_pubs); -    return TMH_RESPONSE_reply_internal_db_error (connection); -  }    ev_sigs = GNUNET_malloc (refresh_session.num_newcoins *                             sizeof (struct TALER_DenominationSignature)); -  key_state = TMH_KS_acquire (); -  for (j=0;j<refresh_session.num_newcoins;j++) -  { -    ev_sigs[j] = refresh_mint_coin (connection, -                                    session, -                                    session_hash, -                                    key_state, -                                    &denom_pubs[j], -                                    &commit_coins[j], -                                    j); -    if (NULL == ev_sigs[j].rsa_signature) -    { -      TMH_KS_release (key_state); -      for (i=0;i<j;i++) -        GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature); -      GNUNET_free (ev_sigs); -      for (j=0;j<refresh_session.num_newcoins;j++) -        GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); -      GNUNET_free (denom_pubs); -      GNUNET_free (commit_coins); -      return TMH_RESPONSE_reply_internal_db_error (connection); -    } -  } -  TMH_KS_release (key_state); -  for (j=0;j<refresh_session.num_newcoins;j++) -    GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); -  GNUNET_free (denom_pubs); -  GNUNET_free (commit_coins); - -  if (GNUNET_OK != -      TMH_plugin->commit (TMH_plugin->cls, -                          session)) -  { -    TALER_LOG_WARNING ("/refresh/reveal transaction commit failed\n"); -    for (i=0;i<refresh_session.num_newcoins;i++) -      GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature); -    GNUNET_free (ev_sigs); -    return TMH_RESPONSE_reply_commit_error (connection); -  } - -  res = TMH_RESPONSE_reply_refresh_reveal_success (connection, -                                                   refresh_session.num_newcoins, -                                                   ev_sigs); +  res = execute_refresh_reveal_transaction (connection, +                                            session, +                                            session_hash, +                                            &refresh_session, +                                            melts, +                                            denom_pubs, +                                            ev_sigs, +                                            commit_coins);    for (i=0;i<refresh_session.num_newcoins;i++) +    if (NULL != ev_sigs[i].rsa_signature)      GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature); +  for (j=0;j<refresh_session.num_newcoins;j++) +    if (NULL != denom_pubs[j].rsa_public_key) +      GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);    GNUNET_free (ev_sigs); +  GNUNET_free (denom_pubs); +  GNUNET_free (commit_coins);    return res;  } diff --git a/src/mint/test_taler_mint_httpd_afl.sh b/src/mint/test_taler_mint_httpd_afl.sh new file mode 100755 index 00000000..62ad4361 --- /dev/null +++ b/src/mint/test_taler_mint_httpd_afl.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# +# This file is part of TALER +# Copyright (C) 2015 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 +#  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 Affero General Public License for more details. +# +#  You should have received a copy of the GNU Affero General Public License along with +#  TALER; see the file COPYING.  If not, If not, see <http://www.gnu.org/licenses/> +# +# +# This script uses 'curl' to POST various ill-formed requests to the +# taler-mint-httpd.  Basically, the goal is to make sure that the +# HTTP server survives (and produces the 'correct' error code). +# +# We read the JSON snippets from afl-tests/ +# +# Setup keys. +taler-mint-keyup -d test-mint-home -m test-mint-home/master.priv +# Run test... +for n in afl-tests/*.req +do +  echo -n "Test $n" +  taler-mint-httpd -d test-mint-home/ -t 1 -f $n -C > /dev/null || { echo "FAIL!"; exit 1; } +  echo "OK" +done +exit 0 diff --git a/src/mintdb/plugin_mintdb_postgres.c b/src/mintdb/plugin_mintdb_postgres.c index 42aac19f..62110802 100644 --- a/src/mintdb/plugin_mintdb_postgres.c +++ b/src/mintdb/plugin_mintdb_postgres.c @@ -1095,7 +1095,31 @@ postgres_commit (void *cls,    if (PGRES_COMMAND_OK !=        PQresultStatus (result))    { -    GNUNET_break (0); +    const char *sqlstate; + +    sqlstate = PQresultErrorField (result, +                                   PG_DIAG_SQLSTATE); +    if (NULL == sqlstate) +    { +      /* very unexpected... */ +      GNUNET_break (0); +      PQclear (result); +      return GNUNET_SYSERR; +    } +    /* 40P01: deadlock, 40001: serialization failure */ +    if ( (0 == strcmp (sqlstate, +                       "40P01")) || +         (0 == strcmp (sqlstate, +                       "40001")) ) +    { +      /* These two can be retried and have a fair chance of working +         the next time */ +      PQclear (result); +      return GNUNET_NO; +    } +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "Database commit failure: %s\n", +                sqlstate);      PQclear (result);      return GNUNET_SYSERR;    } | 
