diff options
Diffstat (limited to 'src')
38 files changed, 4986 insertions, 349 deletions
diff --git a/src/auditordb/Makefile.am b/src/auditordb/Makefile.am index e8ec40272..640f95f25 100644 --- a/src/auditordb/Makefile.am +++ b/src/auditordb/Makefile.am @@ -12,7 +12,8 @@ pkgcfg_DATA = \ auditordb-postgres.conf EXTRA_DIST = \ - auditordb-postgres.conf + auditordb-postgres.conf \ + test-auditor-db-postgres.conf plugindir = $(libdir)/taler @@ -49,5 +50,21 @@ libtalerauditordb_la_LDFLAGS = \ -no-undefined -EXTRA_test_auditordb_postgres_DEPENDENCIES = \ - libtaler_plugin_auditordb_postgres.la +#EXTRA_test_auditordb_postgres_DEPENDENCIES = \ +# libtaler_plugin_auditordb_postgres.la + + +check_PROGRAMS = \ + test-auditordb-postgres + +AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH; +TESTS = \ + test-auditordb-postgres + +test_auditordb_postgres_SOURCES = \ + test_auditordb.c +test_auditordb_postgres_LDADD = \ + libtalerauditordb.la \ + $(top_srcdir)/src/pq/libtalerpq.la \ + $(top_srcdir)/src/util/libtalerutil.la \ + -lgnunetutil diff --git a/src/auditordb/plugin_auditordb_postgres.c b/src/auditordb/plugin_auditordb_postgres.c index 3205d489c..81c1b4369 100644 --- a/src/auditordb/plugin_auditordb_postgres.c +++ b/src/auditordb/plugin_auditordb_postgres.c @@ -17,9 +17,8 @@ /** * @file plugin_auditordb_postgres.c * @brief Low-level (statement-level) Postgres database access for the auditor - * @author Florian Dold * @author Christian Grothoff - * @author Sree Harsha Totakura + * @author Gabor X Toth */ #include "platform.h" #include "taler_pq_lib.h" @@ -326,7 +325,7 @@ postgres_create_tables (void *cls) of; "refund_serial_id" tells us the last entry in "refunds" for this denom_pub that the auditor is aware of. */ SQLEXEC ("CREATE TABLE IF NOT EXISTS denomination_pending" - "(denom_pub_hash BYTEA PRIMARY KEY REFERENCES denominations (denom_pub_hash) ON DELETE CASCADE" + "(denom_pub_hash BYTEA PRIMARY KEY REFERENCES auditor_denominations (denom_pub_hash) ON DELETE CASCADE" ",denom_balance_val INT8 NOT NULL" ",denom_balance_frac INT4 NOT NULL" ",denom_balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" @@ -435,8 +434,8 @@ postgres_create_tables (void *cls) ",reserve_profits_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" ")"); - SQLEXEC_INDEX("CREATE INDEX historic_reserve_summary_by_master_pub_start_date" - " ON historic_ledger(master_pub,start_date)"); + SQLEXEC_INDEX("CREATE INDEX historic_reserve_summary_by_master_pub_start_date " + "ON historic_reserve_summary(master_pub,start_date)"); /* Table with historic business ledger; basically, when the exchange @@ -510,13 +509,457 @@ postgres_prepare (PGconn *db_conn) PQclear (result); result = NULL; \ } while (0); - /* Used in #postgres_XXX() */ - PREPARE ("test_insert", - "INSERT INTO test " - "(test_pub" - ") VALUES " - "($1);", + /* Used in #postgres_insert_denomination_info() */ + PREPARE ("auditor_denominations_insert", + "INSERT INTO auditor_denominations " + "(denom_pub_hash" + ",master_pub" + ",valid_from" + ",expire_withdraw" + ",expire_deposit" + ",expire_legal" + ",coin_val" + ",coin_frac" + ",coin_curr" + ",fee_withdraw_val" + ",fee_withdraw_frac" + ",fee_withdraw_curr" + ",fee_deposit_val" + ",fee_deposit_frac" + ",fee_deposit_curr" + ",fee_refresh_val" + ",fee_refresh_frac" + ",fee_refresh_curr" + ",fee_refund_val" + ",fee_refund_frac" + ",fee_refund_curr" + ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21);", + 21, NULL); + + /* Used in #postgres_insert_denomination_info() */ + PREPARE ("auditor_denominations_select", + "SELECT" + " denom_pub_hash" + ",valid_from" + ",expire_withdraw" + ",expire_deposit" + ",expire_legal" + ",coin_val" + ",coin_frac" + ",coin_curr" + ",fee_withdraw_val" + ",fee_withdraw_frac" + ",fee_withdraw_curr" + ",fee_deposit_val" + ",fee_deposit_frac" + ",fee_deposit_curr" + ",fee_refresh_val" + ",fee_refresh_frac" + ",fee_refresh_curr" + ",fee_refund_val" + ",fee_refund_frac" + ",fee_refund_curr" + " FROM auditor_denominations" + " WHERE master_pub=$1;", 1, NULL); + + /* Used in #postgres_insert_auditor_progress() */ + PREPARE ("auditor_progress_insert", + "INSERT INTO auditor_progress " + "(master_pub" + ",last_reserve_in_serial_id" + ",last_reserve_out_serial_id" + ",last_deposit_serial_id" + ",last_melt_serial_id" + ",last_refund_serial_id" + ",last_prewire_serial_id" + ") VALUES ($1,$2,$3,$4,$5,$6,$7);", + 7, NULL); + + /* Used in #postgres_update_auditor_progress() */ + PREPARE ("auditor_progress_update", + "UPDATE auditor_progress SET " + " last_reserve_in_serial_id=$1" + ",last_reserve_out_serial_id=$2" + ",last_deposit_serial_id=$3" + ",last_melt_serial_id=$4" + ",last_refund_serial_id=$5" + ",last_prewire_serial_id=$6" + " WHERE master_pub=$7", + 7, NULL); + + /* Used in #postgres_get_auditor_progress() */ + PREPARE ("auditor_progress_select", + "SELECT" + " last_reserve_in_serial_id" + ",last_reserve_out_serial_id" + ",last_deposit_serial_id" + ",last_melt_serial_id" + ",last_refund_serial_id" + ",last_prewire_serial_id" + " FROM auditor_progress" + " WHERE master_pub=$1;", + 1, NULL); + + /* Used in #postgres_insert_reserve_info() */ + PREPARE ("auditor_reserves_insert", + "INSERT INTO auditor_reserves " + "(reserve_pub" + ",master_pub" + ",reserve_balance_val" + ",reserve_balance_frac" + ",reserve_balance_curr" + ",withdraw_fee_balance_val" + ",withdraw_fee_balance_frac" + ",withdraw_fee_balance_curr" + ",expiration_date" + ",last_reserve_in_serial_id" + ",last_reserve_out_serial_id" + ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);", + 11, NULL); + + /* Used in #postgres_update_reserve_info() */ + PREPARE ("auditor_reserves_update", + "UPDATE auditor_reserves SET" + " reserve_balance_val=$1" + ",reserve_balance_frac=$2" + ",reserve_balance_curr=$3" + ",withdraw_fee_balance_val=$4" + ",withdraw_fee_balance_frac=$5" + ",withdraw_fee_balance_curr=$6" + ",expiration_date=$7" + ",last_reserve_in_serial_id=$8" + ",last_reserve_out_serial_id=$9" + " WHERE reserve_pub=$10 AND master_pub=$11;", + 11, NULL); + + /* Used in #postgres_get_reserve_info() */ + PREPARE ("auditor_reserves_select", + "SELECT" + " reserve_balance_val" + ",reserve_balance_frac" + ",reserve_balance_curr" + ",withdraw_fee_balance_val" + ",withdraw_fee_balance_frac" + ",withdraw_fee_balance_curr" + ",expiration_date" + ",last_reserve_in_serial_id" + ",last_reserve_out_serial_id" + " FROM auditor_reserves" + " WHERE reserve_pub=$1 AND master_pub=$2;", + 2, NULL); + + /* Used in #postgres_insert_reserve_summary() */ + PREPARE ("auditor_reserve_balance_insert", + "INSERT INTO auditor_reserve_balance" + "(master_pub" + ",reserve_balance_val" + ",reserve_balance_frac" + ",reserve_balance_curr" + ",withdraw_fee_balance_val" + ",withdraw_fee_balance_frac" + ",withdraw_fee_balance_curr" + ") VALUES ($1,$2,$3,$4,$5,$6,$7)", + 7, NULL); + + /* Used in #postgres_update_reserve_summary() */ + PREPARE ("auditor_reserve_balance_update", + "UPDATE auditor_reserve_balance SET" + " reserve_balance_val=$1" + ",reserve_balance_frac=$2" + ",reserve_balance_curr=$3" + ",withdraw_fee_balance_val=$4" + ",withdraw_fee_balance_frac=$5" + ",withdraw_fee_balance_curr=$6" + " WHERE master_pub=$7;", + 7, NULL); + + /* Used in #postgres_get_reserve_summary() */ + PREPARE ("auditor_reserve_balance_select", + "SELECT" + " reserve_balance_val" + ",reserve_balance_frac" + ",reserve_balance_curr" + ",withdraw_fee_balance_val" + ",withdraw_fee_balance_frac" + ",withdraw_fee_balance_curr" + " FROM auditor_reserve_balance" + " WHERE master_pub=$1;", + 1, NULL); + + /* Used in #postgres_insert_denomination_balance() */ + PREPARE ("denomination_pending_insert", + "INSERT INTO denomination_pending " + "(denom_pub_hash" + ",denom_balance_val" + ",denom_balance_frac" + ",denom_balance_curr" + ",deposit_fee_balance_val" + ",deposit_fee_balance_frac" + ",deposit_fee_balance_curr" + ",melt_fee_balance_val" + ",melt_fee_balance_frac" + ",melt_fee_balance_curr" + ",refund_fee_balance_val" + ",refund_fee_balance_frac" + ",refund_fee_balance_curr" + ",last_reserve_out_serial_id" + ",last_deposit_serial_id" + ",last_melt_serial_id" + ",last_refund_serial_id" + ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17);", + 17, NULL); + + /* Used in #postgres_update_denomination_balance() */ + PREPARE ("denomination_pending_update", + "UPDATE denomination_pending SET" + " denom_balance_val=$1" + ",denom_balance_frac=$2" + ",denom_balance_curr=$3" + ",deposit_fee_balance_val=$4" + ",deposit_fee_balance_frac=$5" + ",deposit_fee_balance_curr=$6" + ",melt_fee_balance_val=$7" + ",melt_fee_balance_frac=$8" + ",melt_fee_balance_curr=$9" + ",refund_fee_balance_val=$10" + ",refund_fee_balance_frac=$11" + ",refund_fee_balance_curr=$12" + ",last_reserve_out_serial_id=$13" + ",last_deposit_serial_id=$14" + ",last_melt_serial_id=$15" + ",last_refund_serial_id=$16" + " WHERE denom_pub_hash=$17", + 18, NULL); + + /* Used in #postgres_get_denomination_balance() */ + PREPARE ("denomination_pending_select", + "SELECT" + " denom_balance_val" + ",denom_balance_frac" + ",denom_balance_curr" + ",deposit_fee_balance_val" + ",deposit_fee_balance_frac" + ",deposit_fee_balance_curr" + ",melt_fee_balance_val" + ",melt_fee_balance_frac" + ",melt_fee_balance_curr" + ",refund_fee_balance_val" + ",refund_fee_balance_frac" + ",refund_fee_balance_curr" + ",last_reserve_out_serial_id" + ",last_deposit_serial_id" + ",last_melt_serial_id" + ",last_refund_serial_id" + " FROM denomination_pending" + " WHERE denom_pub_hash=$1", + 1, NULL); + + /* Used in #postgres_insert_denomination_summary() */ + PREPARE ("total_liabilities_insert", + "INSERT INTO total_liabilities " + "(master_pub" + ",denom_balance_val" + ",denom_balance_frac" + ",denom_balance_curr" + ",deposit_fee_balance_val" + ",deposit_fee_balance_frac" + ",deposit_fee_balance_curr" + ",melt_fee_balance_val" + ",melt_fee_balance_frac" + ",melt_fee_balance_curr" + ",refund_fee_balance_val" + ",refund_fee_balance_frac" + ",refund_fee_balance_curr" + ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13);", + 13, NULL); + + /* Used in #postgres_update_denomination_summary() */ + PREPARE ("total_liabilities_update", + "UPDATE total_liabilities SET" + " denom_balance_val=$1" + ",denom_balance_frac=$2" + ",denom_balance_curr=$3" + ",deposit_fee_balance_val=$4" + ",deposit_fee_balance_frac=$5" + ",deposit_fee_balance_curr=$6" + ",melt_fee_balance_val=$7" + ",melt_fee_balance_frac=$8" + ",melt_fee_balance_curr=$9" + ",refund_fee_balance_val=$10" + ",refund_fee_balance_frac=$11" + ",refund_fee_balance_curr=$12" + " WHERE master_pub=$13;", + 13, NULL); + + /* Used in #postgres_get_denomination_summary() */ + PREPARE ("total_liabilities_select", + "SELECT" + " denom_balance_val" + ",denom_balance_frac" + ",denom_balance_curr" + ",deposit_fee_balance_val" + ",deposit_fee_balance_frac" + ",deposit_fee_balance_curr" + ",melt_fee_balance_val" + ",melt_fee_balance_frac" + ",melt_fee_balance_curr" + ",refund_fee_balance_val" + ",refund_fee_balance_frac" + ",refund_fee_balance_curr" + " FROM total_liabilities" + " WHERE master_pub=$1;", + 1, NULL); + + /* Used in #postgres_insert_risk_summary() */ + PREPARE ("total_risk_insert", + "INSERT INTO total_risk" + "(master_pub" + ",risk_val" + ",risk_frac" + ",risk_curr" + ") VALUES ($1,$2,$3,$4);", + 4, NULL); + + /* Used in #postgres_update_risk_summary() */ + PREPARE ("total_risk_update", + "UPDATE total_risk SET " + " risk_val=$1" + ",risk_frac=$2" + ",risk_curr=$3" + " WHERE master_pub=$4;", + 4, NULL); + + /* Used in #postgres_get_risk_summary() */ + PREPARE ("total_risk_select", + "SELECT" + " risk_val" + ",risk_frac" + ",risk_curr" + " FROM total_risk" + " WHERE master_pub=$1;", + 1, NULL); + + + /* Used in #postgres_insert_historic_denom_revenue() */ + PREPARE ("historic_denomination_revenue_insert", + "INSERT INTO historic_denomination_revenue" + "(master_pub" + ",denom_pub_hash" + ",revenue_timestamp" + ",revenue_balance_val" + ",revenue_balance_frac" + ",revenue_balance_curr" + ",deposit_fee_balance_val" + ",deposit_fee_balance_frac" + ",deposit_fee_balance_curr" + ",melt_fee_balance_val" + ",melt_fee_balance_frac" + ",melt_fee_balance_curr" + ",refund_fee_balance_val" + ",refund_fee_balance_frac" + ",refund_fee_balance_curr" + ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15);", + 15, NULL); + + /* Used in #postgres_select_historic_denom_revenue() */ + PREPARE ("historic_denomination_revenue_select", + "SELECT" + " denom_pub_hash" + ",revenue_timestamp" + ",revenue_balance_val" + ",revenue_balance_frac" + ",revenue_balance_curr" + ",deposit_fee_balance_val" + ",deposit_fee_balance_frac" + ",deposit_fee_balance_curr" + ",melt_fee_balance_val" + ",melt_fee_balance_frac" + ",melt_fee_balance_curr" + ",refund_fee_balance_val" + ",refund_fee_balance_frac" + ",refund_fee_balance_curr" + " FROM historic_denomination_revenue" + " WHERE master_pub=$1;", + 1, NULL); + + /* Used in #postgres_insert_historic_losses() */ + PREPARE ("historic_losses_insert", + "INSERT INTO historic_losses" + "(master_pub" + ",denom_pub_hash" + ",loss_timestamp" + ",loss_balance_val" + ",loss_balance_frac" + ",loss_balance_curr" + ") VALUES ($1,$2,$3,$4,$5,$6);", + 6, NULL); + + /* Used in #postgres_select_historic_losses() */ + PREPARE ("historic_losses_select", + "SELECT" + " denom_pub_hash" + ",loss_timestamp" + ",loss_balance_val" + ",loss_balance_frac" + ",loss_balance_curr" + " FROM historic_losses" + " WHERE master_pub=$1;", + 1, NULL); + + /* Used in #postgres_insert_historic_reserve_revenue() */ + PREPARE ("historic_reserve_summary_insert", + "INSERT INTO historic_reserve_summary" + "(master_pub" + ",start_date" + ",end_date" + ",reserve_profits_val" + ",reserve_profits_frac" + ",reserve_profits_curr" + ") VALUES ($1,$2,$3,$4,$5,$6);", + 6, NULL); + + /* Used in #postgres_select_historic_reserve_revenue() */ + PREPARE ("historic_reserve_summary_select", + "SELECT" + " start_date" + ",end_date" + ",reserve_profits_val" + ",reserve_profits_frac" + ",reserve_profits_curr" + " FROM historic_reserve_summary" + " WHERE master_pub=$1;", + 1, NULL); + + /* Used in #postgres_insert_predicted_result() */ + PREPARE ("predicted_result_insert", + "INSERT INTO predicted_result" + "(master_pub" + ",balance_val" + ",balance_frac" + ",balance_curr" + ") VALUES ($1,$2,$3,$4);", + 4, NULL); + + /* Used in #postgres_update_predicted_result() */ + PREPARE ("predicted_result_update", + "UPDATE predicted_result SET" + " balance_val=$1" + ",balance_frac=$2" + ",balance_curr=$3" + " WHERE master_pub=$4;", + 4, NULL); + + /* Used in #postgres_get_predicted_balance() */ + PREPARE ("predicted_result_select", + "SELECT" + " balance_val" + ",balance_frac" + ",balance_curr" + " FROM predicted_result" + " WHERE master_pub=$1;", + 1, NULL); + return GNUNET_OK; #undef PREPARE } @@ -743,8 +1186,55 @@ postgres_insert_denomination_info (void *cls, struct TALER_AUDITORDB_Session *session, const struct TALER_DenominationKeyValidityPS *issue) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (&issue->denom_hash), + GNUNET_PQ_query_param_auto_from_type (&issue->master), + + GNUNET_PQ_query_param_auto_from_type (&issue->start), + GNUNET_PQ_query_param_auto_from_type (&issue->expire_withdraw), + GNUNET_PQ_query_param_auto_from_type (&issue->expire_deposit), + GNUNET_PQ_query_param_auto_from_type (&issue->expire_legal), + + TALER_PQ_query_param_amount_nbo (&issue->value), + TALER_PQ_query_param_amount_nbo (&issue->fee_withdraw), + TALER_PQ_query_param_amount_nbo (&issue->fee_deposit), + TALER_PQ_query_param_amount_nbo (&issue->fee_refresh), + TALER_PQ_query_param_amount_nbo (&issue->fee_refund), + + GNUNET_PQ_query_param_end + }; + + /* check fees match coin currency */ + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency_nbo (&issue->value, + &issue->fee_withdraw)); + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency_nbo (&issue->value, + &issue->fee_deposit)); + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency_nbo (&issue->value, + &issue->fee_refresh)); + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency_nbo (&issue->value, + &issue->fee_refund)); + + result = GNUNET_PQ_exec_prepared (session->conn, + "auditor_denominations_insert", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -762,11 +1252,265 @@ static int postgres_select_denomination_info (void *cls, struct TALER_AUDITORDB_Session *session, const struct TALER_MasterPublicKeyP *master_pub, - void *cb, /* FIXME: type! */ + TALER_AUDITORDB_DenominationInfoDataCallback cb, void *cb_cls) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "auditor_denominations_select", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + + int ret = GNUNET_OK; + int nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "postgres_select_denomination_info() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + for (int i = 0; i < nrows; i++) + { + struct TALER_DenominationKeyValidityPS issue = { .master = *master_pub }; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", &issue.denom_hash), + + GNUNET_PQ_result_spec_auto_from_type ("valid_from", &issue.start), + GNUNET_PQ_result_spec_auto_from_type ("expire_withdraw", &issue.expire_withdraw), + GNUNET_PQ_result_spec_auto_from_type ("expire_deposit", &issue.expire_deposit), + GNUNET_PQ_result_spec_auto_from_type ("expire_legal", &issue.expire_legal), + + TALER_PQ_result_spec_amount_nbo ("coin", &issue.value), + TALER_PQ_result_spec_amount_nbo ("fee_withdraw", &issue.fee_withdraw), + TALER_PQ_result_spec_amount_nbo ("fee_deposit", &issue.fee_deposit), + TALER_PQ_result_spec_amount_nbo ("fee_refresh", &issue.fee_refresh), + TALER_PQ_result_spec_amount_nbo ("fee_refund", &issue.fee_refund), + + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + ret = cb (cb_cls, + &issue); + switch (ret) + { + case GNUNET_OK: + break; + + default: + i = nrows; + } + } + PQclear (result); + return ret; +} + + +/** + * Insert information about the auditor's progress with an exchange's + * data. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @param master_pub master key of the exchange + * @param last_reserve_in_serial_id serial ID of the last reserve_in transfer the auditor processed + * @param last_reserve_out_serial_id serial ID of the last withdraw the auditor processed + * @param last_deposit_serial_id serial ID of the last deposit the auditor processed + * @param last_melt_serial_id serial ID of the last refresh the auditor processed + * @param last_prewire_serial_id serial ID of the last prewire transfer the auditor processed + * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure + */ +int +postgres_insert_auditor_progress (void *cls, + struct TALER_AUDITORDB_Session *session, + const struct TALER_MasterPublicKeyP *master_pub, + uint64_t last_reserve_in_serial_id, + uint64_t last_reserve_out_serial_id, + uint64_t last_deposit_serial_id, + uint64_t last_melt_serial_id, + uint64_t last_refund_serial_id, + uint64_t last_prewire_serial_id) +{ + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_uint64 (&last_reserve_in_serial_id), + GNUNET_PQ_query_param_uint64 (&last_reserve_out_serial_id), + GNUNET_PQ_query_param_uint64 (&last_deposit_serial_id), + GNUNET_PQ_query_param_uint64 (&last_melt_serial_id), + GNUNET_PQ_query_param_uint64 (&last_refund_serial_id), + GNUNET_PQ_query_param_uint64 (&last_prewire_serial_id), + + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "auditor_progress_insert", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; +} + + +/** + * Update information about the progress of the auditor. There + * must be an existing record for the exchange. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @param master_pub master key of the exchange + * @param last_reserve_in_serial_id serial ID of the last reserve_in transfer the auditor processed + * @param last_reserve_out_serial_id serial ID of the last withdraw the auditor processed + * @param last_deposit_serial_id serial ID of the last deposit the auditor processed + * @param last_melt_serial_id serial ID of the last refresh the auditor processed + * @param last_prewire_serial_id serial ID of the last prewire transfer the auditor processed + * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure + */ +int +postgres_update_auditor_progress (void *cls, + struct TALER_AUDITORDB_Session *session, + const struct TALER_MasterPublicKeyP *master_pub, + uint64_t last_reserve_in_serial_id, + uint64_t last_reserve_out_serial_id, + uint64_t last_deposit_serial_id, + uint64_t last_melt_serial_id, + uint64_t last_refund_serial_id, + uint64_t last_prewire_serial_id) +{ + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&last_reserve_in_serial_id), + GNUNET_PQ_query_param_uint64 (&last_reserve_out_serial_id), + GNUNET_PQ_query_param_uint64 (&last_deposit_serial_id), + GNUNET_PQ_query_param_uint64 (&last_melt_serial_id), + GNUNET_PQ_query_param_uint64 (&last_refund_serial_id), + GNUNET_PQ_query_param_uint64 (&last_prewire_serial_id), + + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "auditor_progress_update", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; +} + + +/** + * Get information about the progress of the auditor. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @param master_pub master key of the exchange + * @param[out] last_reserve_in_serial_id serial ID of the last reserve_in transfer the auditor processed + * @param[out] last_reserve_out_serial_id serial ID of the last withdraw the auditor processed + * @param[out] last_deposit_serial_id serial ID of the last deposit the auditor processed + * @param[out] last_melt_serial_id serial ID of the last refresh the auditor processed + * @param[out] last_prewire_serial_id serial ID of the last prewire transfer the auditor processed + * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure; + * #GNUNET_NO if we have no records for the @a master_pub + */ +int +postgres_get_auditor_progress (void *cls, + struct TALER_AUDITORDB_Session *session, + const struct TALER_MasterPublicKeyP *master_pub, + uint64_t *last_reserve_in_serial_id, + uint64_t *last_reserve_out_serial_id, + uint64_t *last_deposit_serial_id, + uint64_t *last_melt_serial_id, + uint64_t *last_refund_serial_id, + uint64_t *last_prewire_serial_id) +{ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "auditor_progress_select", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + + int nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "postgres_get_auditor_progress() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + GNUNET_assert (1 == nrows); + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint64 ("last_reserve_in_serial_id", last_reserve_in_serial_id), + GNUNET_PQ_result_spec_uint64 ("last_reserve_out_serial_id", last_reserve_out_serial_id), + GNUNET_PQ_result_spec_uint64 ("last_deposit_serial_id", last_deposit_serial_id), + GNUNET_PQ_result_spec_uint64 ("last_melt_serial_id", last_melt_serial_id), + GNUNET_PQ_result_spec_uint64 ("last_refund_serial_id", last_refund_serial_id), + GNUNET_PQ_result_spec_uint64 ("last_prewire_serial_id", last_prewire_serial_id), + + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; } @@ -799,8 +1543,42 @@ postgres_insert_reserve_info (void *cls, uint64_t last_reserve_in_serial_id, uint64_t last_reserve_out_serial_id) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + GNUNET_PQ_query_param_auto_from_type (master_pub), + + TALER_PQ_query_param_amount (reserve_balance), + TALER_PQ_query_param_amount (withdraw_fee_balance), + + GNUNET_PQ_query_param_auto_from_type (&expiration_date), + + GNUNET_PQ_query_param_uint64 (&last_reserve_in_serial_id), + GNUNET_PQ_query_param_uint64 (&last_reserve_out_serial_id), + + GNUNET_PQ_query_param_end + }; + + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency (reserve_balance, + withdraw_fee_balance)); + + result = GNUNET_PQ_exec_prepared (session->conn, + "auditor_reserves_insert", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -833,8 +1611,42 @@ postgres_update_reserve_info (void *cls, uint64_t last_reserve_in_serial_id, uint64_t last_reserve_out_serial_id) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + TALER_PQ_query_param_amount (reserve_balance), + TALER_PQ_query_param_amount (withdraw_fee_balance), + + GNUNET_PQ_query_param_auto_from_type (&expiration_date), + + GNUNET_PQ_query_param_uint64 (&last_reserve_in_serial_id), + GNUNET_PQ_query_param_uint64 (&last_reserve_out_serial_id), + + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency (reserve_balance, + withdraw_fee_balance)); + + result = GNUNET_PQ_exec_prepared (session->conn, + "auditor_reserves_update", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -867,8 +1679,54 @@ postgres_get_reserve_info (void *cls, uint64_t *last_reserve_in_serial_id, uint64_t *last_reserve_out_serial_id) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "auditor_reserves_select", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + + int nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "postgres_get_reserve_info() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + GNUNET_assert (1 == nrows); + + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_amount ("reserve_balance", reserve_balance), + TALER_PQ_result_spec_amount ("withdraw_fee_balance", withdraw_fee_balance), + + GNUNET_PQ_result_spec_auto_from_type ("expiration_date", expiration_date), + + GNUNET_PQ_result_spec_uint64 ("last_reserve_in_serial_id", last_reserve_in_serial_id), + GNUNET_PQ_result_spec_uint64 ("last_reserve_out_serial_id", last_reserve_out_serial_id), + + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; } @@ -891,8 +1749,36 @@ postgres_insert_reserve_summary (void *cls, const struct TALER_Amount *reserve_balance, const struct TALER_Amount *withdraw_fee_balance) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + TALER_PQ_query_param_amount (reserve_balance), + TALER_PQ_query_param_amount (withdraw_fee_balance), + + GNUNET_PQ_query_param_end + }; + + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency (reserve_balance, + withdraw_fee_balance)); + + result = GNUNET_PQ_exec_prepared (session->conn, + "auditor_reserve_balance_insert", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -915,8 +1801,32 @@ postgres_update_reserve_summary (void *cls, const struct TALER_Amount *reserve_balance, const struct TALER_Amount *withdraw_fee_balance) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + TALER_PQ_query_param_amount (reserve_balance), + TALER_PQ_query_param_amount (withdraw_fee_balance), + + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "auditor_reserve_balance_update", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -939,8 +1849,48 @@ postgres_get_reserve_summary (void *cls, struct TALER_Amount *reserve_balance, struct TALER_Amount *withdraw_fee_balance) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "auditor_reserve_balance_select", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + + int nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "postgres_get_reserve_summary() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + GNUNET_assert (1 == nrows); + + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_amount ("reserve_balance", reserve_balance), + TALER_PQ_result_spec_amount ("withdraw_fee_balance", withdraw_fee_balance), + + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; } @@ -978,8 +1928,51 @@ postgres_insert_denomination_balance (void *cls, uint64_t last_melt_serial_id, uint64_t last_refund_serial_id) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (denom_pub_hash), + + TALER_PQ_query_param_amount (denom_balance), + TALER_PQ_query_param_amount (deposit_fee_balance), + TALER_PQ_query_param_amount (melt_fee_balance), + TALER_PQ_query_param_amount (refund_fee_balance), + + GNUNET_PQ_query_param_uint64 (&last_reserve_out_serial_id), + GNUNET_PQ_query_param_uint64 (&last_deposit_serial_id), + GNUNET_PQ_query_param_uint64 (&last_melt_serial_id), + GNUNET_PQ_query_param_uint64 (&last_refund_serial_id), + + GNUNET_PQ_query_param_end + }; + + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency (denom_balance, + deposit_fee_balance)); + + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency (denom_balance, + melt_fee_balance)); + + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency (denom_balance, + refund_fee_balance)); + + result = GNUNET_PQ_exec_prepared (session->conn, + "denomination_pending_insert", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -1017,8 +2010,39 @@ postgres_update_denomination_balance (void *cls, uint64_t last_melt_serial_id, uint64_t last_refund_serial_id) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + TALER_PQ_query_param_amount (denom_balance), + TALER_PQ_query_param_amount (deposit_fee_balance), + TALER_PQ_query_param_amount (melt_fee_balance), + TALER_PQ_query_param_amount (refund_fee_balance), + + GNUNET_PQ_query_param_uint64 (&last_reserve_out_serial_id), + GNUNET_PQ_query_param_uint64 (&last_deposit_serial_id), + GNUNET_PQ_query_param_uint64 (&last_melt_serial_id), + GNUNET_PQ_query_param_uint64 (&last_refund_serial_id), + + GNUNET_PQ_query_param_auto_from_type (denom_pub_hash), + + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "denomination_pending_update", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -1055,8 +2079,55 @@ postgres_get_denomination_balance (void *cls, uint64_t *last_melt_serial_id, uint64_t *last_refund_serial_id) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (denom_pub_hash), + + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "denomination_pending_select", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + + int nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "postgres_get_denomination_balance() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + GNUNET_assert (1 == nrows); + + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_amount ("denom_balance", denom_balance), + TALER_PQ_result_spec_amount ("deposit_fee_balance", deposit_fee_balance), + TALER_PQ_result_spec_amount ("melt_fee_balance", melt_fee_balance), + TALER_PQ_result_spec_amount ("refund_fee_balance", refund_fee_balance), + + GNUNET_PQ_result_spec_uint64 ("last_reserve_out_serial_id", last_reserve_out_serial_id), + GNUNET_PQ_result_spec_uint64 ("last_deposit_serial_id", last_deposit_serial_id), + GNUNET_PQ_result_spec_uint64 ("last_melt_serial_id", last_melt_serial_id), + GNUNET_PQ_result_spec_uint64 ("last_refund_serial_id", last_refund_serial_id), + + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; } @@ -1082,8 +2153,46 @@ postgres_insert_denomination_summary (void *cls, const struct TALER_Amount *melt_fee_balance, const struct TALER_Amount *refund_fee_balance) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + TALER_PQ_query_param_amount (denom_balance), + TALER_PQ_query_param_amount (deposit_fee_balance), + TALER_PQ_query_param_amount (melt_fee_balance), + TALER_PQ_query_param_amount (refund_fee_balance), + + GNUNET_PQ_query_param_end + }; + + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency (denom_balance, + deposit_fee_balance)); + + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency (denom_balance, + melt_fee_balance)); + + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency (denom_balance, + refund_fee_balance)); + + result = GNUNET_PQ_exec_prepared (session->conn, + "total_liabilities_insert", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -1109,8 +2218,34 @@ postgres_update_denomination_summary (void *cls, const struct TALER_Amount *melt_fee_balance, const struct TALER_Amount *refund_fee_balance) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + TALER_PQ_query_param_amount (denom_balance), + TALER_PQ_query_param_amount (deposit_fee_balance), + TALER_PQ_query_param_amount (melt_fee_balance), + TALER_PQ_query_param_amount (refund_fee_balance), + + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "total_liabilities_update", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -1136,8 +2271,50 @@ postgres_get_denomination_summary (void *cls, struct TALER_Amount *melt_fee_balance, struct TALER_Amount *refund_fee_balance) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "total_liabilities_select", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + + int nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "postgres_get_denomination_summary() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + GNUNET_assert (1 == nrows); + + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_amount ("denom_balance", denom_balance), + TALER_PQ_result_spec_amount ("deposit_fee_balance", deposit_fee_balance), + TALER_PQ_result_spec_amount ("melt_fee_balance", melt_fee_balance), + TALER_PQ_result_spec_amount ("refund_fee_balance", refund_fee_balance), + + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; } @@ -1157,8 +2334,31 @@ postgres_insert_risk_summary (void *cls, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_Amount *risk) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + TALER_PQ_query_param_amount (risk), + + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "total_risk_insert", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -1178,8 +2378,31 @@ postgres_update_risk_summary (void *cls, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_Amount *risk) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + TALER_PQ_query_param_amount (risk), + + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "total_risk_update", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -1199,8 +2422,47 @@ postgres_get_risk_summary (void *cls, const struct TALER_MasterPublicKeyP *master_pub, struct TALER_Amount *risk) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "total_risk_select", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + + int nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "postgres_get_risk_summary() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + GNUNET_assert (1 == nrows); + + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_amount ("risk", risk), + + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; } @@ -1232,8 +2494,49 @@ postgres_insert_historic_denom_revenue (void *cls, const struct TALER_Amount *melt_fee_balance, const struct TALER_Amount *refund_fee_balance) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + GNUNET_PQ_query_param_auto_from_type (denom_pub_hash), + + GNUNET_PQ_query_param_auto_from_type (&revenue_timestamp), + + TALER_PQ_query_param_amount (revenue_balance), + TALER_PQ_query_param_amount (deposit_fee_balance), + TALER_PQ_query_param_amount (melt_fee_balance), + TALER_PQ_query_param_amount (refund_fee_balance), + + GNUNET_PQ_query_param_end + }; + + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency (revenue_balance, + deposit_fee_balance)); + + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency (revenue_balance, + melt_fee_balance)); + + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency (revenue_balance, + refund_fee_balance)); + + result = GNUNET_PQ_exec_prepared (session->conn, + "historic_denomination_revenue_insert", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -1252,11 +2555,82 @@ static int postgres_select_historic_denom_revenue (void *cls, struct TALER_AUDITORDB_Session *session, const struct TALER_MasterPublicKeyP *master_pub, - void *cb, /* FIXME: fix type */ + TALER_AUDITORDB_HistoricDenominationRevenueDataCallback cb, void *cb_cls) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "historic_denomination_revenue_select", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + + int ret = GNUNET_OK; + int nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "postgres_select_historic_denom_revenue() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + for (int i = 0; i < nrows; i++) + { + struct GNUNET_HashCode denom_pub_hash; + struct GNUNET_TIME_Absolute revenue_timestamp; + struct TALER_Amount revenue_balance; + struct TALER_Amount deposit_fee_balance; + struct TALER_Amount melt_fee_balance; + struct TALER_Amount refund_fee_balance; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", &denom_pub_hash), + + GNUNET_PQ_result_spec_auto_from_type ("revenue_timestamp", &revenue_timestamp), + + TALER_PQ_result_spec_amount ("revenue_balance", &revenue_balance), + TALER_PQ_result_spec_amount ("deposit_fee_balance", &deposit_fee_balance), + TALER_PQ_result_spec_amount ("melt_fee_balance", &melt_fee_balance), + TALER_PQ_result_spec_amount ("refund_fee_balance", &refund_fee_balance), + + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + + ret = cb (cb_cls, + &denom_pub_hash, + revenue_timestamp, + &revenue_balance, + &deposit_fee_balance, + &melt_fee_balance, + &refund_fee_balance); + switch (ret) + { + case GNUNET_OK: + break; + + default: + i = nrows; + } + } + PQclear (result); + return ret; } @@ -1283,8 +2657,34 @@ postgres_insert_historic_losses (void *cls, struct GNUNET_TIME_Absolute loss_timestamp, const struct TALER_Amount *loss_balance) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + GNUNET_PQ_query_param_auto_from_type (denom_pub_hash), + + GNUNET_PQ_query_param_auto_from_type (&loss_timestamp), + + TALER_PQ_query_param_amount (loss_balance), + + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "historic_losses_insert", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -1303,11 +2703,72 @@ static int postgres_select_historic_losses (void *cls, struct TALER_AUDITORDB_Session *session, const struct TALER_MasterPublicKeyP *master_pub, - void *cb, /* FIXME: fix type */ + TALER_AUDITORDB_HistoricLossesDataCallback cb, void *cb_cls) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "historic_losses_select", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + + int ret = GNUNET_OK; + int nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "postgres_select_historic_losses() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + for (int i = 0; i < nrows; i++) + { + struct GNUNET_HashCode denom_pub_hash; + struct GNUNET_TIME_Absolute loss_timestamp; + struct TALER_Amount loss_balance; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", &denom_pub_hash), + + GNUNET_PQ_result_spec_auto_from_type ("loss_timestamp", &loss_timestamp), + + TALER_PQ_result_spec_amount ("loss_balance", &loss_balance), + + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + ret = cb (cb_cls, + &denom_pub_hash, + loss_timestamp, + &loss_balance); + switch (ret) + { + case GNUNET_OK: + break; + + default: + i = nrows; + } + } + PQclear (result); + return ret; } @@ -1330,8 +2791,34 @@ postgres_insert_historic_reserve_revenue (void *cls, struct GNUNET_TIME_Absolute end_time, const struct TALER_Amount *reserve_profits) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_auto_from_type (&start_time), + GNUNET_PQ_query_param_auto_from_type (&end_time), + + TALER_PQ_query_param_amount (reserve_profits), + + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "historic_reserve_summary_insert", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -1349,11 +2836,71 @@ static int postgres_select_historic_reserve_revenue (void *cls, struct TALER_AUDITORDB_Session *session, const struct TALER_MasterPublicKeyP *master_pub, - void *cb, /* FIXME: type */ + TALER_AUDITORDB_HistoricReserveRevenueDataCallback cb, void *cb_cls) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "historic_reserve_summary_select", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + + int ret = GNUNET_OK; + int nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "postgres_select_historic_reserve_revenue() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + for (int i = 0; i < nrows; i++) + { + struct GNUNET_TIME_Absolute start_date; + struct GNUNET_TIME_Absolute end_date; + struct TALER_Amount reserve_profits; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("start_date", &start_date), + GNUNET_PQ_result_spec_auto_from_type ("end_date", &end_date), + + TALER_PQ_result_spec_amount ("reserve_profits", &reserve_profits), + + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + ret = cb (cb_cls, + start_date, + end_date, + &reserve_profits); + switch (ret) + { + case GNUNET_OK: + break; + + default: + i = nrows; + } + } + PQclear (result); + return ret; } @@ -1373,8 +2920,30 @@ postgres_insert_predicted_result (void *cls, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_Amount *balance) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + TALER_PQ_query_param_amount (balance), + + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "predicted_result_insert", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -1394,8 +2963,30 @@ postgres_update_predicted_result (void *cls, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_Amount *balance) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + TALER_PQ_query_param_amount (balance), + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "predicted_result_update", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; } @@ -1415,8 +3006,47 @@ postgres_get_predicted_balance (void *cls, const struct TALER_MasterPublicKeyP *master_pub, struct TALER_Amount *balance) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (master_pub), + + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "predicted_result_select", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + + int nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "postgres_get_predicted_balance() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + GNUNET_assert (1 == nrows); + + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_amount ("balance", balance), + + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; } @@ -1472,32 +3102,46 @@ libtaler_plugin_auditordb_postgres_init (void *cls) plugin->commit = &postgres_commit; plugin->rollback = &postgres_rollback; plugin->gc = &postgres_gc; - plugin->get_predicted_balance = &postgres_get_predicted_balance; - plugin->update_predicted_result = &postgres_update_predicted_result; - plugin->insert_predicted_result = &postgres_insert_predicted_result; - plugin->select_historic_reserve_revenue = &postgres_select_historic_reserve_revenue; - plugin->insert_historic_reserve_revenue = &postgres_insert_historic_reserve_revenue; - plugin->select_historic_losses = &postgres_select_historic_losses; - plugin->insert_historic_losses = &postgres_insert_historic_losses; - plugin->select_historic_denom_revenue = &postgres_select_historic_denom_revenue; - plugin->insert_historic_denom_revenue = &postgres_insert_historic_denom_revenue; - plugin->get_risk_summary = &postgres_get_risk_summary; - plugin->update_risk_summary = &postgres_update_risk_summary; - plugin->insert_risk_summary = &postgres_insert_risk_summary; - plugin->get_denomination_summary = &postgres_get_denomination_summary; - plugin->update_denomination_summary = &postgres_update_denomination_summary; - plugin->insert_denomination_summary = &postgres_insert_denomination_summary; - plugin->get_denomination_balance = &postgres_get_denomination_balance; - plugin->update_denomination_balance = &postgres_update_denomination_balance; - plugin->insert_denomination_balance = &postgres_insert_denomination_balance; - plugin->get_reserve_summary = &postgres_get_reserve_summary; - plugin->update_reserve_summary = &postgres_update_reserve_summary; - plugin->insert_reserve_summary = &postgres_insert_reserve_summary; + + plugin->select_denomination_info = &postgres_select_denomination_info; + plugin->insert_denomination_info = &postgres_insert_denomination_info; + + plugin->get_auditor_progress = &postgres_get_auditor_progress; + plugin->update_auditor_progress = &postgres_update_auditor_progress; + plugin->insert_auditor_progress = &postgres_insert_auditor_progress; + plugin->get_reserve_info = &postgres_get_reserve_info; plugin->update_reserve_info = &postgres_update_reserve_info; plugin->insert_reserve_info = &postgres_insert_reserve_info; - plugin->select_denomination_info = &postgres_select_denomination_info; - plugin->insert_denomination_info = &postgres_insert_denomination_info; + + plugin->get_reserve_summary = &postgres_get_reserve_summary; + plugin->update_reserve_summary = &postgres_update_reserve_summary; + plugin->insert_reserve_summary = &postgres_insert_reserve_summary; + + plugin->get_denomination_balance = &postgres_get_denomination_balance; + plugin->update_denomination_balance = &postgres_update_denomination_balance; + plugin->insert_denomination_balance = &postgres_insert_denomination_balance; + + plugin->get_denomination_summary = &postgres_get_denomination_summary; + plugin->update_denomination_summary = &postgres_update_denomination_summary; + plugin->insert_denomination_summary = &postgres_insert_denomination_summary; + + plugin->get_risk_summary = &postgres_get_risk_summary; + plugin->update_risk_summary = &postgres_update_risk_summary; + plugin->insert_risk_summary = &postgres_insert_risk_summary; + + plugin->select_historic_denom_revenue = &postgres_select_historic_denom_revenue; + plugin->insert_historic_denom_revenue = &postgres_insert_historic_denom_revenue; + + plugin->select_historic_losses = &postgres_select_historic_losses; + plugin->insert_historic_losses = &postgres_insert_historic_losses; + + plugin->select_historic_reserve_revenue = &postgres_select_historic_reserve_revenue; + plugin->insert_historic_reserve_revenue = &postgres_insert_historic_reserve_revenue; + + plugin->get_predicted_balance = &postgres_get_predicted_balance; + plugin->update_predicted_result = &postgres_update_predicted_result; + plugin->insert_predicted_result = &postgres_insert_predicted_result; return plugin; } diff --git a/src/auditordb/test-auditor-db-postgres.conf b/src/auditordb/test-auditor-db-postgres.conf new file mode 100644 index 000000000..5c1e7fbc1 --- /dev/null +++ b/src/auditordb/test-auditor-db-postgres.conf @@ -0,0 +1,7 @@ +[auditor] +# Which database backend do we use for the auditor? +DB = postgres + +[auditordb-postgres] +# Argument for Postgres for how to connect to the database. +DB_CONN_STR = "postgres:///talercheck" diff --git a/src/auditordb/test_auditordb.c b/src/auditordb/test_auditordb.c new file mode 100644 index 000000000..93c279384 --- /dev/null +++ b/src/auditordb/test_auditordb.c @@ -0,0 +1,798 @@ +/* + This file is part of TALER + Copyright (C) 2016 GNUnet e.V. and INRIA + + 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, see <http://www.gnu.org/licenses/> +*/ +/** + * @file auditordb/test_auditordb.c + * @brief test cases for DB interaction functions + * @author Gabor X Toth + */ +#include "platform.h" +#include "taler_auditordb_lib.h" +#include "taler_auditordb_plugin.h" + + +/** + * Global result from the testcase. + */ +static int result = -1; + +/** + * Report line of error if @a cond is true, and jump to label "drop". + */ +#define FAILIF(cond) \ + do { \ + if (!(cond)){ break;} \ + GNUNET_break (0); \ + goto drop; \ + } while (0) + + +/** + * Initializes @a ptr with random data. + */ +#define RND_BLK(ptr) \ + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr)) + +/** + * Initializes @a ptr with zeros. + */ +#define ZR_BLK(ptr) \ + memset (ptr, 0, sizeof (*ptr)) + + +/** + * Currency we use. + */ +#define CURRENCY "EUR" + +/** + * Database plugin under test. + */ +static struct TALER_AUDITORDB_Plugin *plugin; + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure with config + */ +static void +run (void *cls) +{ + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + struct TALER_AUDITORDB_Session *session; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "loading database plugin\n"); + + if (NULL == + (plugin = TALER_AUDITORDB_plugin_load (cfg))) + { + result = 77; + return; + } + + (void) plugin->drop_tables (plugin->cls); + if (GNUNET_OK != + plugin->create_tables (plugin->cls)) + { + result = 77; + goto drop; + } + if (NULL == + (session = plugin->get_session (plugin->cls))) + { + result = 77; + goto drop; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "initializing\n"); + + struct TALER_Amount value, fee_withdraw, fee_deposit, fee_refresh, fee_refund; + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":1.000010", + &value)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000011", + &fee_withdraw)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000012", + &fee_deposit)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000013", + &fee_refresh)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000014", + &fee_refund)); + + struct TALER_MasterPublicKeyP master_pub; + struct TALER_ReservePublicKeyP reserve_pub; + struct GNUNET_HashCode rnd_hash; + RND_BLK (&master_pub); + RND_BLK (&reserve_pub); + RND_BLK (&rnd_hash); + + struct TALER_DenominationPrivateKey denom_priv; + struct TALER_DenominationPublicKey denom_pub; + struct GNUNET_HashCode denom_pub_hash; + denom_priv.rsa_private_key = GNUNET_CRYPTO_rsa_private_key_create (1024); + denom_pub.rsa_public_key = GNUNET_CRYPTO_rsa_private_key_get_public (denom_priv.rsa_private_key); + GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key, &denom_pub_hash); + + struct GNUNET_TIME_Absolute now, past, future, date; + now = GNUNET_TIME_absolute_get (); + past = GNUNET_TIME_absolute_subtract (now, + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, + 4)); + future = GNUNET_TIME_absolute_add (now, + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, + 4)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: insert_denomination_info\n"); + + struct TALER_DenominationKeyValidityPS issue = { 0 }; + issue.master = master_pub; + issue.denom_hash = denom_pub_hash; + + issue.start = GNUNET_TIME_absolute_hton (now); + issue.expire_withdraw = GNUNET_TIME_absolute_hton + (GNUNET_TIME_absolute_add (now, + GNUNET_TIME_UNIT_HOURS)); + issue.expire_deposit = GNUNET_TIME_absolute_hton + (GNUNET_TIME_absolute_add + (now, + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 2))); + issue.expire_legal = GNUNET_TIME_absolute_hton + (GNUNET_TIME_absolute_add + (now, + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 3))); + TALER_amount_hton (&issue.value, &value); + TALER_amount_hton (&issue.fee_withdraw, &fee_withdraw); + TALER_amount_hton (&issue.fee_deposit, &fee_deposit); + TALER_amount_hton (&issue.fee_refresh, &fee_refresh); + TALER_amount_hton (&issue.fee_refund, &fee_refund); + + FAILIF (GNUNET_OK != + plugin->insert_denomination_info (plugin->cls, + session, + &issue)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: select_denomination_info\n"); + + int + select_denomination_info_result (void *cls, + const struct TALER_DenominationKeyValidityPS *issue2) + { + const struct TALER_DenominationKeyValidityPS *issue1 = cls; + + if (0 != memcmp (issue1, issue2, sizeof (*issue2))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "select_denomination_info_result: issue does not match\n"); + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; + } + + FAILIF (GNUNET_OK != + plugin->select_denomination_info (plugin->cls, + session, + &master_pub, + select_denomination_info_result, + &issue)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: insert_auditor_progress\n"); + + uint64_t + last_reserve_in_serial_id = 1234, + last_reserve_out_serial_id = 5678, + last_deposit_serial_id = 123, + last_melt_serial_id = 456, + last_refund_serial_id = 789, + last_prewire_serial_id = 555, + + last_reserve_in_serial_id2 = 0, + last_reserve_out_serial_id2 = 0, + last_deposit_serial_id2 = 0, + last_melt_serial_id2 = 0, + last_refund_serial_id2 = 0, + last_prewire_serial_id2 = 0; + + FAILIF (GNUNET_OK != + plugin->insert_auditor_progress (plugin->cls, + session, + &master_pub, + last_reserve_in_serial_id, + last_reserve_out_serial_id, + last_deposit_serial_id, + last_melt_serial_id, + last_refund_serial_id, + last_prewire_serial_id)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: update_auditor_progress\n"); + + last_reserve_in_serial_id++; + last_reserve_out_serial_id++; + last_deposit_serial_id2++; + last_melt_serial_id2++; + last_refund_serial_id2++; + last_prewire_serial_id2++; + + FAILIF (GNUNET_OK != + plugin->update_auditor_progress (plugin->cls, + session, + &master_pub, + last_reserve_in_serial_id, + last_reserve_out_serial_id, + last_deposit_serial_id, + last_melt_serial_id, + last_refund_serial_id, + last_prewire_serial_id)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: get_auditor_progress\n"); + + FAILIF (GNUNET_OK != + plugin->get_auditor_progress (plugin->cls, + session, + &master_pub, + &last_reserve_in_serial_id2, + &last_reserve_out_serial_id2, + &last_deposit_serial_id2, + &last_melt_serial_id2, + &last_refund_serial_id2, + &last_prewire_serial_id2)); + + FAILIF (last_reserve_in_serial_id2 != last_reserve_in_serial_id + || last_reserve_out_serial_id2 != last_reserve_out_serial_id + || last_deposit_serial_id2 != last_deposit_serial_id + || last_melt_serial_id2 != last_melt_serial_id + || last_refund_serial_id2 != last_refund_serial_id + || last_prewire_serial_id2 != last_prewire_serial_id); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: insert_reserve_info\n"); + + struct TALER_Amount reserve_balance, withdraw_fee_balance; + struct TALER_Amount reserve_balance2 = {}, withdraw_fee_balance2 = {}; + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":12.345678", + &reserve_balance)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":23.456789", + &withdraw_fee_balance)); + + FAILIF (GNUNET_OK != + plugin->insert_reserve_info (plugin->cls, + session, + &reserve_pub, + &master_pub, + &reserve_balance, + &withdraw_fee_balance, + past, + last_reserve_in_serial_id, + last_reserve_out_serial_id)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: update_reserve_info\n"); + + last_reserve_in_serial_id++; + last_reserve_out_serial_id++; + + FAILIF (GNUNET_OK != + plugin->update_reserve_info (plugin->cls, + session, + &reserve_pub, + &master_pub, + &reserve_balance, + &withdraw_fee_balance, + future, + last_reserve_in_serial_id, + last_reserve_out_serial_id)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: get_reserve_info\n"); + + FAILIF (GNUNET_OK != + plugin->get_reserve_info (plugin->cls, + session, + &reserve_pub, + &master_pub, + &reserve_balance2, + &withdraw_fee_balance2, + &date, + &last_reserve_in_serial_id2, + &last_reserve_out_serial_id2)); + + FAILIF (0 != memcmp (&date, &future, sizeof (future)) + || 0 != memcmp (&reserve_balance2, &reserve_balance, sizeof (reserve_balance)) + || 0 != memcmp (&withdraw_fee_balance2, &withdraw_fee_balance, sizeof (withdraw_fee_balance)) + || last_reserve_in_serial_id2 != last_reserve_in_serial_id + || last_reserve_out_serial_id2 != last_reserve_out_serial_id); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: insert_reserve_summary\n"); + + FAILIF (GNUNET_OK != + plugin->insert_reserve_summary (plugin->cls, + session, + &master_pub, + &withdraw_fee_balance, + &reserve_balance)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: update_reserve_summary\n"); + + FAILIF (GNUNET_OK != + plugin->update_reserve_summary (plugin->cls, + session, + &master_pub, + &reserve_balance, + &withdraw_fee_balance)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: get_reserve_summary\n"); + + ZR_BLK (&reserve_balance2); + ZR_BLK (&withdraw_fee_balance2); + + FAILIF (GNUNET_OK != + plugin->get_reserve_summary (plugin->cls, + session, + &master_pub, + &reserve_balance2, + &withdraw_fee_balance2)); + + FAILIF (0 != memcmp (&reserve_balance2, &reserve_balance, sizeof (reserve_balance)) + || 0 != memcmp (&withdraw_fee_balance2, &withdraw_fee_balance, sizeof (withdraw_fee_balance))); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: insert_denomination_balance\n"); + + struct TALER_Amount denom_balance, deposit_fee_balance, melt_fee_balance, refund_fee_balance; + struct TALER_Amount denom_balance2, deposit_fee_balance2, melt_fee_balance2, refund_fee_balance2; + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":12.345678", + &denom_balance)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":23.456789", + &deposit_fee_balance)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":34.567890", + &melt_fee_balance)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":45.678901", + &refund_fee_balance)); + + FAILIF (GNUNET_OK != + plugin->insert_denomination_balance (plugin->cls, + session, + &denom_pub_hash, + &refund_fee_balance, + &melt_fee_balance, + &deposit_fee_balance, + &denom_balance, + last_reserve_out_serial_id, + last_deposit_serial_id, + last_melt_serial_id, + last_refund_serial_id)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: update_denomination_balance\n"); + + last_reserve_out_serial_id++; + last_deposit_serial_id++; + last_melt_serial_id++; + last_refund_serial_id++; + + FAILIF (GNUNET_OK != + plugin->update_denomination_balance (plugin->cls, + session, + &denom_pub_hash, + &denom_balance, + &deposit_fee_balance, + &melt_fee_balance, + &refund_fee_balance, + last_reserve_out_serial_id, + last_deposit_serial_id, + last_melt_serial_id, + last_refund_serial_id)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: get_denomination_balance\n"); + + FAILIF (GNUNET_OK != + plugin->get_denomination_balance (plugin->cls, + session, + &denom_pub_hash, + &denom_balance2, + &deposit_fee_balance2, + &melt_fee_balance2, + &refund_fee_balance2, + &last_reserve_out_serial_id2, + &last_deposit_serial_id2, + &last_melt_serial_id2, + &last_refund_serial_id2)); + + FAILIF (0 != memcmp (&denom_balance2, &denom_balance, sizeof (denom_balance)) + || 0 != memcmp (&deposit_fee_balance2, &deposit_fee_balance, sizeof (deposit_fee_balance)) + || 0 != memcmp (&melt_fee_balance2, &melt_fee_balance, sizeof (melt_fee_balance)) + || 0 != memcmp (&refund_fee_balance2, &refund_fee_balance, sizeof (refund_fee_balance)) + || last_reserve_out_serial_id2 != last_reserve_out_serial_id + || last_deposit_serial_id2 != last_deposit_serial_id + || last_melt_serial_id2 != last_melt_serial_id + || last_refund_serial_id2 != last_refund_serial_id); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: insert_denomination_summary\n"); + + FAILIF (GNUNET_OK != + plugin->insert_denomination_summary (plugin->cls, + session, + &master_pub, + &refund_fee_balance, + &melt_fee_balance, + &deposit_fee_balance, + &denom_balance)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: update_denomination_summary\n"); + + FAILIF (GNUNET_OK != + plugin->update_denomination_summary (plugin->cls, + session, + &master_pub, + &denom_balance, + &deposit_fee_balance, + &melt_fee_balance, + &refund_fee_balance)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: get_denomination_summary\n"); + + ZR_BLK (&denom_balance2); + ZR_BLK (&deposit_fee_balance2); + ZR_BLK (&melt_fee_balance2); + ZR_BLK (&refund_fee_balance2); + + FAILIF (GNUNET_OK != + plugin->get_denomination_summary (plugin->cls, + session, + &master_pub, + &denom_balance2, + &deposit_fee_balance2, + &melt_fee_balance2, + &refund_fee_balance2)); + + FAILIF (0 != memcmp (&denom_balance2, &denom_balance, sizeof (denom_balance)) + || 0 != memcmp (&deposit_fee_balance2, &deposit_fee_balance, sizeof (deposit_fee_balance)) + || 0 != memcmp (&melt_fee_balance2, &melt_fee_balance, sizeof (melt_fee_balance)) + || 0 != memcmp (&refund_fee_balance2, &refund_fee_balance, sizeof (refund_fee_balance))); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: insert_risk_summary\n"); + + struct TALER_Amount balance, balance2; + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":13.57986", + &balance)); + + FAILIF (GNUNET_OK != + plugin->insert_risk_summary (plugin->cls, + session, + &master_pub, + &balance)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: update_risk_summary\n"); + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":57.310986", + &balance)); + + FAILIF (GNUNET_OK != + plugin->update_risk_summary (plugin->cls, + session, + &master_pub, + &balance)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: get_risk_summary\n"); + + FAILIF (GNUNET_OK != + plugin->get_risk_summary (plugin->cls, + session, + &master_pub, + &balance2)); + + FAILIF (0 != memcmp (&balance2, &balance, sizeof (balance))); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: insert_historic_denom_revenue\n"); + + FAILIF (GNUNET_OK != + plugin->insert_historic_denom_revenue (plugin->cls, + session, + &master_pub, + &denom_pub_hash, + past, + &balance, + &deposit_fee_balance, + &melt_fee_balance, + &refund_fee_balance)); + + FAILIF (GNUNET_OK != + plugin->insert_historic_denom_revenue (plugin->cls, + session, + &master_pub, + &rnd_hash, + now, + &balance, + &deposit_fee_balance, + &melt_fee_balance, + &refund_fee_balance)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: select_historic_denom_revenue\n"); + + int + select_historic_denom_revenue_result (void *cls, + const struct GNUNET_HashCode *denom_pub_hash2, + struct GNUNET_TIME_Absolute revenue_timestamp2, + const struct TALER_Amount *revenue_balance2, + const struct TALER_Amount *deposit_fee_balance2, + const struct TALER_Amount *melt_fee_balance2, + const struct TALER_Amount *refund_fee_balance2) + { + static int n = 0; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "select_historic_denom_revenue_result: row %u\n", n); + + if (2 <= n++ + || cls != NULL + || (0 != memcmp (&revenue_timestamp2, &past, sizeof (past)) + && 0 != memcmp (&revenue_timestamp2, &now, sizeof (now))) + || (0 != memcmp (denom_pub_hash2, &denom_pub_hash, sizeof (denom_pub_hash)) + && 0 != memcmp (denom_pub_hash2, &rnd_hash, sizeof (rnd_hash))) + || 0 != memcmp (revenue_balance2, &balance, sizeof (balance)) + || 0 != memcmp (deposit_fee_balance2, &deposit_fee_balance, sizeof (deposit_fee_balance)) + || 0 != memcmp (melt_fee_balance2, &melt_fee_balance, sizeof (melt_fee_balance)) + || 0 != memcmp (refund_fee_balance2, &refund_fee_balance, sizeof (refund_fee_balance))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "select_historic_denom_revenue_result: result does not match\n"); + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; + } + + FAILIF (GNUNET_OK != + plugin->select_historic_denom_revenue (plugin->cls, + session, + &master_pub, + select_historic_denom_revenue_result, + NULL)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: insert_historic_losses\n"); + + FAILIF (GNUNET_OK != + plugin->insert_historic_losses (plugin->cls, + session, + &master_pub, + &denom_pub_hash, + past, + &balance)); + + FAILIF (GNUNET_OK != + plugin->insert_historic_losses (plugin->cls, + session, + &master_pub, + &rnd_hash, + past, + &balance)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: select_historic_losses\n"); + + int + select_historic_losses_result (void *cls, + const struct GNUNET_HashCode *denom_pub_hash2, + struct GNUNET_TIME_Absolute loss_timestamp2, + const struct TALER_Amount *loss_balance2) + { + static int n = 0; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "select_historic_losses_result: row %u\n", n); + + if (2 <= n++ + || cls != NULL + || (0 != memcmp (&loss_timestamp2, &past, sizeof (past)) + && 0 != memcmp (&loss_timestamp2, &now, sizeof (now))) + || (0 != memcmp (denom_pub_hash2, &denom_pub_hash, sizeof (denom_pub_hash)) + && 0 != memcmp (denom_pub_hash2, &rnd_hash, sizeof (rnd_hash))) + || 0 != memcmp (loss_balance2, &balance, sizeof (balance))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "select_historic_denom_revenue_result: result does not match\n"); + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; + } + + FAILIF (GNUNET_OK != + plugin->select_historic_losses (plugin->cls, + session, + &master_pub, + select_historic_losses_result, + NULL)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: insert_historic_reserve_revenue\n"); + + struct TALER_Amount reserve_profits; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":56.789012", + &reserve_profits)); + + FAILIF (GNUNET_OK != + plugin->insert_historic_reserve_revenue (plugin->cls, + session, + &master_pub, + past, + future, + &reserve_profits)); + + FAILIF (GNUNET_OK != + plugin->insert_historic_reserve_revenue (plugin->cls, + session, + &master_pub, + now, + future, + &reserve_profits)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: select_historic_reserve_revenue\n"); + + int + select_historic_reserve_revenue_result (void *cls, + struct GNUNET_TIME_Absolute start_time2, + struct GNUNET_TIME_Absolute end_time2, + const struct TALER_Amount *reserve_profits2) + { + static int n = 0; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "select_historic_reserve_revenue_result: row %u\n", n); + + if (2 <= n++ + || cls != NULL + || (0 != memcmp (&start_time2, &past, sizeof (past)) + && 0 != memcmp (&start_time2, &now, sizeof (now))) + || 0 != memcmp (&end_time2, &future, sizeof (future)) + || 0 != memcmp (reserve_profits2, &reserve_profits, sizeof (reserve_profits))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "select_historic_reserve_revenue_result: result does not match\n"); + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; + } + + FAILIF (GNUNET_OK != + plugin->select_historic_reserve_revenue (plugin->cls, + session, + &master_pub, + select_historic_reserve_revenue_result, + NULL)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: insert_predicted_result\n"); + + FAILIF (GNUNET_OK != + plugin->insert_predicted_result (plugin->cls, + session, + &master_pub, + &balance)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: update_predicted_result\n"); + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":78.901234", + &balance)); + + FAILIF (GNUNET_OK != + plugin->update_predicted_result (plugin->cls, + session, + &master_pub, + &balance)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test: get_predicted_balance\n"); + + FAILIF (GNUNET_OK != + plugin->get_predicted_balance (plugin->cls, + session, + &master_pub, + &balance2)); + + FAILIF (0 != memcmp (&balance2, &balance, sizeof (balance))); + + result = 0; + +drop: + + GNUNET_break (GNUNET_OK == + plugin->drop_tables (plugin->cls)); + TALER_AUDITORDB_plugin_unload (plugin); + plugin = NULL; +} + + +int +main (int argc, + char *const argv[]) +{ + const char *plugin_name; + char *config_filename; + char *testname; + struct GNUNET_CONFIGURATION_Handle *cfg; + + result = -1; + if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) + { + GNUNET_break (0); + return -1; + } + GNUNET_log_setup (argv[0], + "WARNING", + NULL); + plugin_name++; + (void) GNUNET_asprintf (&testname, + "test-auditor-db-%s", plugin_name); + (void) GNUNET_asprintf (&config_filename, + "%s.conf", testname); + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_parse (cfg, + config_filename)) + { + GNUNET_break (0); + GNUNET_free (config_filename); + GNUNET_free (testname); + return 2; + } + GNUNET_SCHEDULER_run (&run, cfg); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free (config_filename); + GNUNET_free (testname); + return result; +} diff --git a/src/bank-lib/test_bank_api.c b/src/bank-lib/test_bank_api.c index 88fe82451..88ca2fd24 100644 --- a/src/bank-lib/test_bank_api.c +++ b/src/bank-lib/test_bank_api.c @@ -67,22 +67,35 @@ main (int argc, char * const *argv) { struct GNUNET_OS_Process *bankd; + struct GNUNET_OS_Process *bankd_admin; unsigned int cnt; int result; GNUNET_log_setup ("test-bank-api", "WARNING", NULL); + bankd_admin = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-bank-manage", + "taler-bank-manage", + "--admin", + "serve-http", + "--port", "8081", + NULL); bankd = GNUNET_OS_start_process (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL, NULL, NULL, NULL, "taler-bank-manage", "taler-bank-manage", "serve-http", - "--port", "8081", + "--port", "8080", NULL); - if (NULL == bankd) + + + if ((NULL == bankd_admin) || (NULL == bankd)) { + /*FIXME: More accurate error message?*/ fprintf (stderr, "taler-bank-manage not found, skipping test\n"); return 77; /* report 'skip' */ @@ -99,13 +112,26 @@ main (int argc, if (cnt > 30) break; } - while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/ -o /dev/null -O /dev/null")); + while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8080/ -o /dev/null -O /dev/null")); + + do + { + fprintf (stderr, "."); + sleep (1); + cnt++; + if (cnt > 30) + break; + } + while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/admin/add/incoming -o /dev/null -O /dev/null")); + fprintf (stderr, "\n"); result = GNUNET_SYSERR; if (cnt <= 30) GNUNET_SCHEDULER_run (&run, &result); GNUNET_OS_process_kill (bankd, SIGTERM); + GNUNET_OS_process_kill (bankd_admin, + SIGTERM); GNUNET_OS_process_wait (bankd); GNUNET_OS_process_destroy (bankd); if (cnt > 30) diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 40e5818bf..7b143a189 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -541,6 +541,7 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys, * @param cls closure with the `struct Coin *` * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error * @param sigs array of signature over @a num_coins coins, NULL on error @@ -549,6 +550,7 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys, static void reveal_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, unsigned int num_coins, const struct TALER_CoinSpendPrivateKeyP *coin_privs, const struct TALER_DenominationSignature *sigs, @@ -617,6 +619,7 @@ reveal_cb (void *cls, * @param cls closure with the `struct Coin *` * @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped. * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param noreveal_index choice by the exchange in the cut-and-choose protocol, * UINT16_MAX on error * @param exchange_pub public key the exchange used for signing @@ -625,6 +628,7 @@ reveal_cb (void *cls, static void melt_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, uint16_t noreveal_index, const struct TALER_ExchangePublicKeyP *exchange_pub, const json_t *full_response) @@ -776,6 +780,7 @@ refresh_coin (struct Coin *coin) * @param cls closure with the `struct Coin` that we are processing * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param exchange_pub public key used by the exchange for signing * @param obj the received JSON reply, should be kept as proof (and, in case of errors, * be forwarded to the customer) @@ -783,6 +788,7 @@ refresh_coin (struct Coin *coin) static void deposit_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const struct TALER_ExchangePublicKeyP *exchange_pub, const json_t *obj) { @@ -935,12 +941,14 @@ spend_coin (struct Coin *coin, * @param cls closure with our `struct Coin` * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param sig signature over the coin, NULL on error * @param full_response full response from the exchange (for logging, in case of errors) */ static void reserve_withdraw_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const struct TALER_DenominationSignature *sig, const json_t *full_response) { @@ -1027,11 +1035,13 @@ withdraw_coin (struct Coin *coin) * @param cls closure with the `struct Reserve *` * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param full_response full response from the exchange (for logging, in case of errors) */ static void add_incoming_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const json_t *full_response) { struct Reserve *r = cls; diff --git a/src/exchange-lib/Makefile.am b/src/exchange-lib/Makefile.am index 83fcf1475..19c36744d 100644 --- a/src/exchange-lib/Makefile.am +++ b/src/exchange-lib/Makefile.am @@ -14,7 +14,7 @@ libtalerexchange_la_LDFLAGS = \ -no-undefined libtalerexchange_la_SOURCES = \ - exchange_api_common.c exchange_api_common.h \ + exchange_api_common.c \ exchange_api_handle.c exchange_api_handle.h \ exchange_api_admin.c \ exchange_api_deposit.c \ diff --git a/src/exchange-lib/exchange_api_admin.c b/src/exchange-lib/exchange_api_admin.c index 524916e68..e6cb8101c 100644 --- a/src/exchange-lib/exchange_api_admin.c +++ b/src/exchange-lib/exchange_api_admin.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. + Copyright (C) 2014, 2015, 2016 GNUnet e.V. 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 @@ -129,6 +129,7 @@ handle_admin_add_incoming_finished (void *cls, } aai->cb (aai->cb_cls, response_code, + TALER_JSON_get_error_code (json), json); TALER_EXCHANGE_admin_add_incoming_cancel (aai); } diff --git a/src/exchange-lib/exchange_api_common.c b/src/exchange-lib/exchange_api_common.c index acf90fce6..a531b1c39 100644 --- a/src/exchange-lib/exchange_api_common.c +++ b/src/exchange-lib/exchange_api_common.c @@ -20,7 +20,6 @@ * @author Christian Grothoff */ #include "platform.h" -#include "exchange_api_common.h" #include "taler_json_lib.h" #include <gnunet/gnunet_curl_lib.h> #include "exchange_api_handle.h" @@ -38,8 +37,8 @@ */ int TALER_EXCHANGE_verify_coin_history (const char *currency, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - json_t *history, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + json_t *history, struct TALER_Amount *total) { size_t len; diff --git a/src/exchange-lib/exchange_api_common.h b/src/exchange-lib/exchange_api_common.h deleted file mode 100644 index 5655f5d3b..000000000 --- a/src/exchange-lib/exchange_api_common.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - 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 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, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file exchange-lib/exchange_api_common.h - * @brief common functions for the exchange API - * @author Christian Grothoff - */ -#include <jansson.h> -#include <gnunet/gnunet_util_lib.h> -#include "taler_exchange_service.h" - -/** - * Verify a coins transaction history as returned by the exchange. - * - * @param currency expected currency for the coin - * @param coin_pub public key of the coin - * @param history history of the coin in json encoding - * @param[out] total how much of the coin has been spent according to @a history - * @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not - */ -int -TALER_EXCHANGE_verify_coin_history (const char *currency, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - json_t *history, - struct TALER_Amount *total); - -/* end of exchange_api_common.h */ diff --git a/src/exchange-lib/exchange_api_deposit.c b/src/exchange-lib/exchange_api_deposit.c index aa7e07ed8..9282bbfd1 100644 --- a/src/exchange-lib/exchange_api_deposit.c +++ b/src/exchange-lib/exchange_api_deposit.c @@ -29,7 +29,6 @@ #include <gnunet/gnunet_curl_lib.h> #include "taler_json_lib.h" #include "taler_exchange_service.h" -#include "exchange_api_common.h" #include "exchange_api_handle.h" #include "taler_signatures.h" @@ -262,6 +261,7 @@ handle_deposit_finished (void *cls, } dh->cb (dh->cb_cls, response_code, + TALER_JSON_get_error_code (json), ep, json); TALER_EXCHANGE_deposit_cancel (dh); diff --git a/src/exchange-lib/exchange_api_refresh.c b/src/exchange-lib/exchange_api_refresh.c index 6d12a718c..c3216a6e6 100644 --- a/src/exchange-lib/exchange_api_refresh.c +++ b/src/exchange-lib/exchange_api_refresh.c @@ -28,7 +28,6 @@ #include <gnunet/gnunet_curl_lib.h> #include "taler_json_lib.h" #include "taler_exchange_service.h" -#include "exchange_api_common.h" #include "exchange_api_handle.h" #include "taler_signatures.h" @@ -1115,6 +1114,7 @@ handle_refresh_melt_finished (void *cls, { rmh->melt_cb (rmh->melt_cb_cls, response_code, + TALER_JSON_get_error_code (json), noreveal_index, (0 == response_code) ? NULL : &exchange_pub, json); @@ -1160,6 +1160,7 @@ handle_refresh_melt_finished (void *cls, if (NULL != rmh->melt_cb) rmh->melt_cb (rmh->melt_cb_cls, response_code, + TALER_JSON_get_error_code (json), UINT16_MAX, NULL, json); @@ -1598,6 +1599,7 @@ handle_refresh_reveal_finished (void *cls, { rrh->reveal_cb (rrh->reveal_cb_cls, MHD_HTTP_OK, + TALER_EC_NONE, rrh->md->num_fresh_coins, coin_privs, sigs, @@ -1634,7 +1636,10 @@ handle_refresh_reveal_finished (void *cls, if (NULL != rrh->reveal_cb) rrh->reveal_cb (rrh->reveal_cb_cls, response_code, - 0, NULL, NULL, + TALER_JSON_get_error_code (json), + 0, + NULL, + NULL, json); TALER_EXCHANGE_refresh_reveal_cancel (rrh); } diff --git a/src/exchange-lib/exchange_api_refresh_link.c b/src/exchange-lib/exchange_api_refresh_link.c index a1dba9938..9b825138e 100644 --- a/src/exchange-lib/exchange_api_refresh_link.c +++ b/src/exchange-lib/exchange_api_refresh_link.c @@ -265,6 +265,7 @@ parse_refresh_link_ok (struct TALER_EXCHANGE_RefreshLinkHandle *rlh, { rlh->link_cb (rlh->link_cb_cls, MHD_HTTP_OK, + TALER_EC_NONE, num_coins, coin_privs, sigs, @@ -345,7 +346,11 @@ handle_refresh_link_finished (void *cls, if (NULL != rlh->link_cb) rlh->link_cb (rlh->link_cb_cls, response_code, - 0, NULL, NULL, NULL, + TALER_JSON_get_error_code (json), + 0, + NULL, + NULL, + NULL, json); TALER_EXCHANGE_refresh_link_cancel (rlh); } diff --git a/src/exchange-lib/exchange_api_refund.c b/src/exchange-lib/exchange_api_refund.c index f712f126a..be080c57b 100644 --- a/src/exchange-lib/exchange_api_refund.c +++ b/src/exchange-lib/exchange_api_refund.c @@ -28,7 +28,6 @@ #include <gnunet/gnunet_curl_lib.h> #include "taler_json_lib.h" #include "taler_exchange_service.h" -#include "exchange_api_common.h" #include "exchange_api_handle.h" #include "taler_signatures.h" @@ -196,6 +195,7 @@ handle_refund_finished (void *cls, } rh->cb (rh->cb_cls, response_code, + TALER_JSON_get_error_code (json), ep, json); TALER_EXCHANGE_refund_cancel (rh); diff --git a/src/exchange-lib/exchange_api_reserve.c b/src/exchange-lib/exchange_api_reserve.c index 0bff767e6..28f329c42 100644 --- a/src/exchange-lib/exchange_api_reserve.c +++ b/src/exchange-lib/exchange_api_reserve.c @@ -314,7 +314,8 @@ handle_reserve_status_finished (void *cls, if (GNUNET_OK != GNUNET_JSON_parse (json, spec, - NULL, NULL)) + NULL, + NULL)) { GNUNET_break_op (0); response_code = 0; @@ -355,6 +356,7 @@ handle_reserve_status_finished (void *cls, } wsh->cb (wsh->cb_cls, response_code, + TALER_EC_NONE, json, &balance, len, @@ -387,6 +389,7 @@ handle_reserve_status_finished (void *cls, if (NULL != wsh->cb) wsh->cb (wsh->cb_cls, response_code, + TALER_JSON_get_error_code (json), json, NULL, 0, NULL); @@ -589,6 +592,7 @@ reserve_withdraw_ok (struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh, dsig.rsa_signature = sig; wsh->cb (wsh->cb_cls, MHD_HTTP_OK, + TALER_EC_NONE, &dsig, json); /* make sure callback isn't called again after return */ @@ -599,7 +603,7 @@ reserve_withdraw_ok (struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh, /** - * We got a 402 PAYMENT REQUIRED response for the /reserve/withdraw operation. + * We got a 403 FORBIDDEN response for the /reserve/withdraw operation. * Check the signatures on the withdraw transactions in the provided * history and that the balances add up. We don't do anything directly * with the information, as the JSON will be returned to the application. @@ -723,7 +727,7 @@ handle_reserve_withdraw_finished (void *cls, /* This should never happen, either us or the exchange is buggy (or API version conflict); just pass JSON reply to the application */ break; - case MHD_HTTP_PAYMENT_REQUIRED: + case MHD_HTTP_FORBIDDEN: /* The exchange says that the reserve has insufficient funds; check the signatures in the history... */ if (GNUNET_OK != @@ -762,6 +766,7 @@ handle_reserve_withdraw_finished (void *cls, if (NULL != wsh->cb) wsh->cb (wsh->cb_cls, response_code, + TALER_JSON_get_error_code (json), NULL, json); TALER_EXCHANGE_reserve_withdraw_cancel (wsh); diff --git a/src/exchange-lib/exchange_api_track_transaction.c b/src/exchange-lib/exchange_api_track_transaction.c index c05115d57..7fd2efb21 100644 --- a/src/exchange-lib/exchange_api_track_transaction.c +++ b/src/exchange-lib/exchange_api_track_transaction.c @@ -28,7 +28,6 @@ #include <gnunet/gnunet_curl_lib.h> #include "taler_json_lib.h" #include "taler_exchange_service.h" -#include "exchange_api_common.h" #include "exchange_api_handle.h" #include "taler_signatures.h" @@ -239,6 +238,7 @@ handle_deposit_wtid_finished (void *cls, } dwh->cb (dwh->cb_cls, response_code, + TALER_JSON_get_error_code (json), ep, json, wtid, diff --git a/src/exchange-lib/exchange_api_track_transfer.c b/src/exchange-lib/exchange_api_track_transfer.c index ffcb19b59..8ed5865d7 100644 --- a/src/exchange-lib/exchange_api_track_transfer.c +++ b/src/exchange-lib/exchange_api_track_transfer.c @@ -26,7 +26,6 @@ #include <gnunet/gnunet_util_lib.h> #include <gnunet/gnunet_curl_lib.h> #include "taler_exchange_service.h" -#include "exchange_api_common.h" #include "taler_json_lib.h" #include "exchange_api_handle.h" #include "taler_signatures.h" @@ -183,6 +182,7 @@ check_track_transfer_response_ok (struct TALER_EXCHANGE_TrackTransferHandle *wdh } wdh->cb (wdh->cb_cls, MHD_HTTP_OK, + TALER_EC_NONE, &exchange_pub, json, &h_wire, @@ -253,6 +253,7 @@ handle_track_transfer_finished (void *cls, } wdh->cb (wdh->cb_cls, response_code, + TALER_JSON_get_error_code (json), NULL, json, NULL, diff --git a/src/exchange-lib/exchange_api_wire.c b/src/exchange-lib/exchange_api_wire.c index cb8df4944..7401e66d4 100644 --- a/src/exchange-lib/exchange_api_wire.c +++ b/src/exchange-lib/exchange_api_wire.c @@ -28,7 +28,6 @@ #include "taler_exchange_service.h" #include "taler_json_lib.h" #include "taler_wire_plugin.h" -#include "exchange_api_common.h" #include "exchange_api_handle.h" @@ -210,6 +209,7 @@ handle_wire_finished (void *cls, } wh->cb (wh->cb_cls, response_code, + TALER_JSON_get_error_code (json), (NULL != keep) ? keep : json); if (NULL != keep) json_decref (keep); diff --git a/src/exchange-lib/test_exchange_api.c b/src/exchange-lib/test_exchange_api.c index 541a621d2..e25fa66cd 100644 --- a/src/exchange-lib/test_exchange_api.c +++ b/src/exchange-lib/test_exchange_api.c @@ -761,11 +761,13 @@ next_command (struct InterpreterState *is) * @param cls closure with the interpreter state * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param full_response full response from the exchange (for logging, in case of errors) */ static void add_incoming_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const json_t *full_response) { struct InterpreterState *is = cls; @@ -857,6 +859,7 @@ compare_reserve_withdraw_history (const struct TALER_EXCHANGE_ReserveHistory *h, * @param cls closure with the interpreter state * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param[in] json original response in JSON format (useful only for diagnostics) * @param balance current balance in the reserve, NULL on error * @param history_length number of entries in the transaction history, 0 on error @@ -865,6 +868,7 @@ compare_reserve_withdraw_history (const struct TALER_EXCHANGE_ReserveHistory *h, static void reserve_status_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const json_t *json, const struct TALER_Amount *balance, unsigned int history_length, @@ -924,7 +928,7 @@ reserve_status_cb (void *cls, { if (GNUNET_OK != compare_reserve_withdraw_history (&history[j], - rel)) + rel)) { GNUNET_break (0); fail (is); @@ -973,12 +977,14 @@ reserve_status_cb (void *cls, * @param cls closure with the interpreter state * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param sig signature over the coin, NULL on error * @param full_response full response from the exchange (for logging, in case of errors) */ static void reserve_withdraw_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const struct TALER_DenominationSignature *sig, const json_t *full_response) { @@ -1009,7 +1015,7 @@ reserve_withdraw_cb (void *cls, cmd->details.reserve_withdraw.sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature); break; - case MHD_HTTP_PAYMENT_REQUIRED: + case MHD_HTTP_FORBIDDEN: /* nothing to check */ break; default: @@ -1027,6 +1033,7 @@ reserve_withdraw_cb (void *cls, * @param cls closure with the interpreter state * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param exchange_pub public key the exchange used for signing * @param obj the received JSON reply, should be kept as proof (and, in case of errors, * be forwarded to the customer) @@ -1034,6 +1041,7 @@ reserve_withdraw_cb (void *cls, static void deposit_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const struct TALER_ExchangePublicKeyP *exchange_pub, const json_t *obj) { @@ -1061,6 +1069,7 @@ deposit_cb (void *cls, * @param cls closure with the interpreter state * @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped. * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param noreveal_index choice by the exchange in the cut-and-choose protocol, * UINT16_MAX on error * @param exchange_pub public key the exchange used for signing @@ -1069,6 +1078,7 @@ deposit_cb (void *cls, static void melt_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, uint16_t noreveal_index, const struct TALER_ExchangePublicKeyP *exchange_pub, const json_t *full_response) @@ -1098,6 +1108,7 @@ melt_cb (void *cls, * @param cls closure with the interpreter state * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error * @param sigs array of signature over @a num_coins coins, NULL on error @@ -1106,6 +1117,7 @@ melt_cb (void *cls, static void reveal_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, unsigned int num_coins, const struct TALER_CoinSpendPrivateKeyP *coin_privs, const struct TALER_DenominationSignature *sigs, @@ -1160,6 +1172,7 @@ reveal_cb (void *cls, * @param cls closure with the interpreter state * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error * @param sigs array of signature over @a num_coins coins, NULL on error @@ -1169,6 +1182,7 @@ reveal_cb (void *cls, static void link_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, unsigned int num_coins, const struct TALER_CoinSpendPrivateKeyP *coin_privs, const struct TALER_DenominationSignature *sigs, @@ -1336,12 +1350,14 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys, * @param cls closure with the interpreter state * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request; * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param obj the received JSON reply, if successful this should be the wire * format details as provided by /wire. */ static void wire_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const json_t *obj) { struct InterpreterState *is = cls; @@ -1391,6 +1407,7 @@ wire_cb (void *cls, * * @param cls closure * @param http_status HTTP status code we got, 0 on exchange protocol violation + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param exchange_pub public key the exchange used for signing * @param json original json reply (may include signatures, those have then been * validated already) @@ -1404,6 +1421,7 @@ wire_cb (void *cls, static void wire_deposits_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const struct TALER_ExchangePublicKeyP *exchange_pub, const json_t *json, const struct GNUNET_HashCode *h_wire, @@ -1521,6 +1539,7 @@ wire_deposits_cb (void *cls, * * @param cls closure * @param http_status HTTP status code we got, 0 on exchange protocol violation + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param exchange_pub public key the exchange used for signing * @param json original json reply (may include signatures, those have then been * validated already) @@ -1534,6 +1553,7 @@ wire_deposits_cb (void *cls, static void deposit_wtid_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const struct TALER_ExchangePublicKeyP *exchange_pub, const json_t *json, const struct TALER_WireTransferIdentifierRawP *wtid, @@ -1588,6 +1608,7 @@ deposit_wtid_cb (void *cls, * @param cls closure * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param exchange_pub public key the exchange used for signing @a obj * @param obj the received JSON reply, should be kept as proof (and, in particular, * be forwarded to the customer) @@ -1595,6 +1616,7 @@ deposit_wtid_cb (void *cls, static void refund_cb (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const struct TALER_ExchangePublicKeyP *exchange_pub, const json_t *obj) { @@ -1782,9 +1804,9 @@ interpreter_run (void *cls) &reserve_pub.eddsa_pub); cmd->details.reserve_status.wsh = TALER_EXCHANGE_reserve_status (exchange, - &reserve_pub, - &reserve_status_cb, - is); + &reserve_pub, + &reserve_status_cb, + is); return; case OC_WITHDRAW_SIGN: GNUNET_assert (NULL != @@ -2737,7 +2759,7 @@ run (void *cls) /* Try to overdraw funds ... */ { .oc = OC_WITHDRAW_SIGN, .label = "withdraw-coin-2", - .expected_response_code = MHD_HTTP_PAYMENT_REQUIRED, + .expected_response_code = MHD_HTTP_FORBIDDEN, .details.reserve_withdraw.reserve_reference = "create-reserve-1", .details.reserve_withdraw.amount = "EUR:5" }, @@ -3051,8 +3073,11 @@ main (int argc, unsigned long code; GNUNET_log_setup ("test-exchange-api", - "WARNING", - NULL); + "DEBUG", + "/tmp/logs"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test log\n"); + return 0; + /* These might get in the way... */ unsetenv ("XDG_DATA_HOME"); unsetenv ("XDG_CONFIG_HOME"); diff --git a/src/exchange/taler-exchange-httpd_admin.c b/src/exchange/taler-exchange-httpd_admin.c index e99448f87..72cdcb7d6 100644 --- a/src/exchange/taler-exchange-httpd_admin.c +++ b/src/exchange/taler-exchange-httpd_admin.c @@ -89,6 +89,7 @@ TEH_ADMIN_handler_admin_add_incoming (struct TEH_RequestHandler *rh, GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); return TEH_RESPONSE_reply_arg_unknown (connection, + TALER_EC_ADMIN_ADD_INCOMING_WIREFORMAT_UNSUPPORTED, "sender_account_details"); } if (0 != strcasecmp (amount.currency, @@ -100,6 +101,7 @@ TEH_ADMIN_handler_admin_add_incoming (struct TEH_RequestHandler *rh, amount.currency); GNUNET_JSON_parse_free (spec); return TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_ADMIN_ADD_INCOMING_CURRENCY_UNSUPPORTED, "amount:currency"); } res = TEH_DB_execute_admin_add_incoming (connection, diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c index 6b27a22a6..870f7a251 100644 --- a/src/exchange/taler-exchange-httpd_db.c +++ b/src/exchange/taler-exchange-httpd_db.c @@ -53,7 +53,8 @@ transaction_start_label: /* we will use goto for retries */ \ session)) \ { \ GNUNET_break (0); \ - return TEH_RESPONSE_reply_internal_db_error (connection); \ + return TEH_RESPONSE_reply_internal_db_error (connection, \ + TALER_EC_DB_START_FAILED); \ } /** @@ -73,8 +74,9 @@ transaction_start_label: /* we will use goto for retries */ \ if (GNUNET_SYSERR == transaction_commit_result) \ { \ TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ - return TEH_RESPONSE_reply_commit_error (connection); \ - } \ + return TEH_RESPONSE_reply_commit_error (connection, \ + TALER_EC_DB_COMMIT_FAILED_HARD); \ + } \ if (GNUNET_NO == transaction_commit_result) \ { \ TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ @@ -83,7 +85,8 @@ transaction_start_label: /* we will use goto for retries */ \ TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n", \ transaction_retries, \ __FUNCTION__); \ - return TEH_RESPONSE_reply_commit_error (connection); \ + return TEH_RESPONSE_reply_commit_error (connection, \ + TALER_EC_DB_COMMIT_FAILED_ON_RETRY); \ } \ } /* end of scope opened by BEGIN_TRANSACTION */ @@ -197,7 +200,8 @@ TEH_DB_execute_deposit (struct MHD_Connection *connection, if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DB_SETUP_FAILED); } if (GNUNET_YES == TEH_plugin->have_deposit (TEH_plugin->cls, @@ -225,8 +229,8 @@ TEH_DB_execute_deposit (struct MHD_Connection *connection, if (NULL == dki) { TEH_KS_release (mks); - return TEH_RESPONSE_reply_arg_invalid (connection, - "denom_pub"); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DEPOSIT_DB_DENOMINATION_KEY_UNKNOWN); } TALER_amount_ntoh (&value, &dki->issue.properties.value); @@ -249,7 +253,8 @@ TEH_DB_execute_deposit (struct MHD_Connection *connection, session); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DEPOSIT_HISTORY_DB_ERROR); } /* Check that cost of all transactions is smaller than the value of the coin. */ @@ -274,7 +279,8 @@ TEH_DB_execute_deposit (struct MHD_Connection *connection, TALER_LOG_WARNING ("Failed to store /deposit information in database\n"); TEH_plugin->rollback (TEH_plugin->cls, session); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DEPOSIT_STORE_DB_ERROR); } COMMIT_TRANSACTION(session, connection); @@ -324,7 +330,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection, if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DB_SETUP_FAILED); } dep = NULL; ref = NULL; @@ -337,7 +344,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection, TEH_plugin->rollback (TEH_plugin->cls, session); return TEH_RESPONSE_reply_refund_failure (connection, - MHD_HTTP_NOT_FOUND); + MHD_HTTP_NOT_FOUND, + TALER_EC_REFUND_COIN_NOT_FOUND); } deposit_found = GNUNET_NO; refund_found = GNUNET_NO; @@ -411,7 +419,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection, session); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); - return TEH_RESPONSE_reply_transaction_unknown (connection); + return TEH_RESPONSE_reply_transaction_unknown (connection, + TALER_EC_REFUND_DEPOSIT_NOT_FOUND); } /* handle if conflicting refund found */ if (GNUNET_SYSERR == refund_found) @@ -449,7 +458,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection, TEH_plugin->rollback (TEH_plugin->cls, session); return TEH_RESPONSE_reply_refund_failure (connection, - MHD_HTTP_PRECONDITION_FAILED); + MHD_HTTP_PRECONDITION_FAILED, + TALER_EC_REFUND_CURRENCY_MISSMATCH); } /* check if we already send the money for the /deposit */ @@ -466,6 +476,7 @@ TEH_DB_execute_refund (struct MHD_Connection *connection, TEH_plugin->rollback (TEH_plugin->cls, session); return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_REFUND_DB_INCONSISTENT, "database inconsistent"); } if (GNUNET_YES == done) @@ -476,7 +487,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection, TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); return TEH_RESPONSE_reply_refund_failure (connection, - MHD_HTTP_GONE); + MHD_HTTP_GONE, + TALER_EC_REFUND_MERCHANT_ALREADY_PAID); } /* check refund amount is sufficiently low */ @@ -487,7 +499,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection, TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); return TEH_RESPONSE_reply_refund_failure (connection, - MHD_HTTP_PRECONDITION_FAILED); + MHD_HTTP_PRECONDITION_FAILED, + TALER_EC_REFUND_INSUFFICIENT_FUNDS); } /* Check refund fee matches fee of denomination key! */ @@ -504,6 +517,7 @@ TEH_DB_execute_refund (struct MHD_Connection *connection, TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_REFUND_DENOMINATION_KEY_NOT_FOUND, "denomination key not found"); } TALER_amount_ntoh (&expect_fee, @@ -519,6 +533,7 @@ TEH_DB_execute_refund (struct MHD_Connection *connection, TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); return TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_REFUND_FEE_TOO_LOW, "refund_fee"); } if (1 == fee_cmp) @@ -538,7 +553,8 @@ TEH_DB_execute_refund (struct MHD_Connection *connection, TALER_LOG_WARNING ("Failed to store /refund information in database\n"); TEH_plugin->rollback (TEH_plugin->cls, session); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFUND_STORE_DB_ERROR); } COMMIT_TRANSACTION(session, connection); @@ -566,7 +582,8 @@ TEH_DB_execute_reserve_status (struct MHD_Connection *connection, if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DB_SETUP_FAILED); } rh = TEH_plugin->get_reserve_history (TEH_plugin->cls, session, @@ -637,6 +654,7 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection, TEH_plugin->rollback (TEH_plugin->cls, session); return TEH_RESPONSE_reply_arg_unknown (connection, + TALER_EC_WITHDRAW_RESERVE_UNKNOWN, "reserve_pub"); } @@ -653,7 +671,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection, { TEH_plugin->rollback (TEH_plugin->cls, session); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_AMOUNT_FEE_OVERFLOW); } /* calculate balance of the reserve */ @@ -673,7 +692,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection, { TEH_plugin->rollback (TEH_plugin->cls, session); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_AMOUNT_DEPOSITS_OVERFLOW); } res |= 1; break; @@ -686,7 +706,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection, GNUNET_break (0); TEH_plugin->rollback (TEH_plugin->cls, session); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_HISTORIC_DENOMINATION_KEY_NOT_FOUND); } TALER_amount_ntoh (&value, &tdki->issue.properties.value); @@ -700,7 +721,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection, { TEH_plugin->rollback (TEH_plugin->cls, session); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_AMOUNT_WITHDRAWALS_OVERFLOW); } res |= 2; break; @@ -708,9 +730,10 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection, } if (0 == (res & 1)) { - /* did not encounter any deposit operations, how can we have a reserve? */ + /* did not encounter any wire transfer operations, how can we have a reserve? */ GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_RESERVE_WITHOUT_WIRE_TRANSFER); } if (0 == (res & 2)) { @@ -748,6 +771,7 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection, TEH_plugin->rollback (TEH_plugin->cls, session); return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_WITHDRAW_SIGNATURE_FAILED, "Internal error"); } collectable.sig = *denom_sig; @@ -765,7 +789,8 @@ execute_reserve_withdraw_transaction (struct MHD_Connection *connection, GNUNET_break (0); TEH_plugin->rollback (TEH_plugin->cls, session); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_DB_STORE_ERROR); } COMMIT_TRANSACTION (session, connection); @@ -811,7 +836,8 @@ TEH_DB_execute_reserve_withdraw (struct MHD_Connection *connection, if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DB_SETUP_FAILED); } res = TEH_plugin->get_withdraw_info (TEH_plugin->cls, session, @@ -820,7 +846,8 @@ TEH_DB_execute_reserve_withdraw (struct MHD_Connection *connection, if (GNUNET_SYSERR == res) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_WITHDRAW_DB_FETCH_ERROR); } /* Don't sign again if we have already signed the coin */ @@ -834,6 +861,7 @@ TEH_DB_execute_reserve_withdraw (struct MHD_Connection *connection, } GNUNET_assert (GNUNET_NO == res); + /* FIXME: do we have to do this a second time here? */ key_state = TEH_KS_acquire (); dki = TEH_KS_denomination_key_lookup (key_state, denomination_pub, @@ -843,9 +871,11 @@ TEH_DB_execute_reserve_withdraw (struct MHD_Connection *connection, TEH_KS_release (key_state); return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_NOT_FOUND, - "{s:s}", + "{s:s, s:I}", "error", - "Denomination not found"); + "Denomination not found", + "code", + (json_int_t) TALER_EC_WITHDRAW_DENOMINATION_KEY_NOT_FOUND); } denom_sig.rsa_signature = NULL; res = execute_reserve_withdraw_transaction (connection, @@ -901,8 +931,9 @@ refresh_check_melt (struct MHD_Connection *connection, TEH_KS_DKU_DEPOSIT); if (NULL == dk) return (MHD_YES == - TEH_RESPONSE_reply_arg_unknown (connection, - "denom_pub")) + TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_REFRESH_MELT_DB_DENOMINATION_KEY_NOT_FOUND, + "denomination key no longer available while executing transaction")) ? GNUNET_NO : GNUNET_SYSERR; dki = &dk->issue; TALER_amount_ntoh (&coin_value, @@ -922,7 +953,8 @@ refresh_check_melt (struct MHD_Connection *connection, TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); return (MHD_YES == - TEH_RESPONSE_reply_internal_db_error (connection)) + TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_MELT_COIN_HISTORY_COMPUTATION_FAILED)) ? GNUNET_NO : GNUNET_SYSERR; } /* Refuse to refresh when the coin's value is insufficient @@ -995,7 +1027,8 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection, if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DB_SETUP_FAILED); } START_TRANSACTION (session, connection); res = TEH_plugin->get_refresh_session (TEH_plugin->cls, @@ -1015,14 +1048,15 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection, { TEH_plugin->rollback (TEH_plugin->cls, session); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_MELT_DB_FETCH_ERROR); } /* store 'global' session data */ refresh_session.num_newcoins = num_new_denoms; refresh_session.noreveal_index - = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, - TALER_CNC_KAPPA); + = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, + TALER_CNC_KAPPA); key_state = TEH_KS_acquire (); if (GNUNET_OK != (res = refresh_check_melt (connection, @@ -1047,7 +1081,8 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection, { TEH_plugin->rollback (TEH_plugin->cls, session); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_MELT_DB_STORE_SESSION_ERROR); } /* store requested new denominations */ @@ -1060,7 +1095,8 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection, { TEH_plugin->rollback (TEH_plugin->cls, session); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_MELT_DB_STORE_ORDER_ERROR); } if (GNUNET_OK != @@ -1072,7 +1108,8 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection, { TEH_plugin->rollback (TEH_plugin->cls, session); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_MELT_DB_STORE_ORDER_ERROR); } if (GNUNET_OK != TEH_plugin->insert_refresh_transfer_public_key (TEH_plugin->cls, @@ -1082,7 +1119,8 @@ TEH_DB_execute_refresh_melt (struct MHD_Connection *connection, { TEH_plugin->rollback (TEH_plugin->cls, session); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_MELT_DB_STORE_TRANSFER_ERROR); } COMMIT_TRANSACTION (session, connection); @@ -1126,8 +1164,6 @@ check_commitment (struct MHD_Connection *connection, struct TALER_TransferSecretP transfer_secret; unsigned int j; - /* FIXME: instead of consulting DB, reconstruct everything - from transfer_priv here! */ TALER_link_reveal_transfer_secret (transfer_priv, &melt->coin.coin_pub, &transfer_secret); @@ -1158,8 +1194,10 @@ check_commitment (struct MHD_Connection *connection, { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Blind failed (bad denomination key!?)\n"); - return (MHD_YES == TEH_RESPONSE_reply_internal_error (connection, - "Blinding error")) + return (MHD_YES == + TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_REFRESH_REVEAL_BLINDING_ERROR, + "Blinding error")) ? GNUNET_NO : GNUNET_SYSERR; } GNUNET_CRYPTO_hash_context_read (hash_context, @@ -1274,7 +1312,8 @@ execute_refresh_reveal_transaction (struct MHD_Connection *connection, j); if (NULL == ev_sigs[j].rsa_signature) { - ret = TEH_RESPONSE_reply_internal_db_error (connection); + ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_REVEAL_SIGNING_ERROR); goto cleanup; } } @@ -1323,7 +1362,8 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection, if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DB_SETUP_FAILED); } res = TEH_plugin->get_refresh_session (TEH_plugin->cls, @@ -1332,10 +1372,12 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection, &refresh_session); if (GNUNET_NO == res) return TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN, "session_hash"); if ( (GNUNET_SYSERR == res) || (refresh_session.noreveal_index >= TALER_CNC_KAPPA) ) - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR); denom_pubs = GNUNET_new_array (refresh_session.num_newcoins, struct TALER_DenominationPublicKey); if (GNUNET_OK != @@ -1349,7 +1391,8 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection, GNUNET_free (denom_pubs); GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature); GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key); - return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection)) + return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR)) ? GNUNET_NO : GNUNET_SYSERR; } @@ -1373,7 +1416,8 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection, GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature); GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key); GNUNET_CRYPTO_hash_context_abort (hash_context); - return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection)) + return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_REVEAL_DB_FETCH_TRANSFER_ERROR)) ? GNUNET_NO : GNUNET_SYSERR; } GNUNET_CRYPTO_hash_context_read (hash_context, @@ -1410,7 +1454,8 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection, GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature); GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key); GNUNET_CRYPTO_hash_context_abort (hash_context); - return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection)) + return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR)) ? GNUNET_NO : GNUNET_SYSERR; } for (i=0;i<refresh_session.num_newcoins;i++) @@ -1463,7 +1508,8 @@ TEH_DB_execute_refresh_reveal (struct MHD_Connection *connection, GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature); GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key); GNUNET_CRYPTO_hash_context_abort (hash_context); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_REVEAL_DB_FETCH_COMMIT_ERROR); } /* add envelopes to hash_context */ for (j=0;j<refresh_session.num_newcoins;j++) @@ -1656,7 +1702,8 @@ TEH_DB_execute_refresh_link (struct MHD_Connection *connection, if (NULL == (ctx.session = TEH_plugin->get_session (TEH_plugin->cls))) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DB_SETUP_FAILED); } ctx.connection = connection; ctx.num_sessions = 0; @@ -1680,6 +1727,7 @@ TEH_DB_execute_refresh_link (struct MHD_Connection *connection, GNUNET_assert (GNUNET_OK == ctx.status); if (0 == ctx.num_sessions) return TEH_RESPONSE_reply_arg_unknown (connection, + TALER_EC_REFRESH_LINK_COIN_UNKNOWN, "coin_pub"); res = TEH_RESPONSE_reply_refresh_link_success (connection, ctx.num_sessions, @@ -1720,7 +1768,8 @@ TEH_DB_execute_admin_add_incoming (struct MHD_Connection *connection, if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DB_SETUP_FAILED); } ret = TEH_plugin->reserves_in_insert (TEH_plugin->cls, session, @@ -1732,7 +1781,8 @@ TEH_DB_execute_admin_add_incoming (struct MHD_Connection *connection, if (GNUNET_SYSERR == ret) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_ADMIN_ADD_INCOMING_DB_STORE); } return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_OK, @@ -1913,7 +1963,8 @@ TEH_DB_execute_track_transfer (struct MHD_Connection *connection, if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DB_SETUP_FAILED); } ctx.is_valid = GNUNET_NO; ctx.wdd_head = NULL; @@ -1926,18 +1977,21 @@ TEH_DB_execute_track_transfer (struct MHD_Connection *connection, if (GNUNET_SYSERR == ret) { GNUNET_break (0); - ret = TEH_RESPONSE_reply_internal_db_error (connection); + ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_TRACK_TRANSFER_DB_FETCH_FAILED); goto cleanup; } if (GNUNET_SYSERR == ctx.is_valid) { GNUNET_break (0); - ret = TEH_RESPONSE_reply_internal_db_error (connection); + ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_TRACK_TRANSFER_DB_INCONSISTENT); goto cleanup; } if (GNUNET_NO == ctx.is_valid) { ret = TEH_RESPONSE_reply_arg_unknown (connection, + TALER_EC_TRACK_TRANSFER_WTID_NOT_FOUND, "wtid"); goto cleanup; } @@ -2035,7 +2089,8 @@ handle_wtid_data (void *cls, coin_fee)) { GNUNET_break (0); - ctx->res = TEH_RESPONSE_reply_internal_db_error (ctx->connection); + ctx->res = TEH_RESPONSE_reply_internal_db_error (ctx->connection, + TALER_EC_TRACK_TRANSACTION_DB_FEE_INCONSISTENT); } else { @@ -2079,7 +2134,8 @@ TEH_DB_execute_track_transaction (struct MHD_Connection *connection, if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DB_SETUP_FAILED); } ctx.connection = connection; ctx.h_contract = *h_contract; @@ -2100,17 +2156,20 @@ TEH_DB_execute_track_transaction (struct MHD_Connection *connection, { GNUNET_break (0); GNUNET_break (GNUNET_SYSERR == ctx.res); - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_TRACK_TRANSACTION_DB_FETCH_FAILED); } if (GNUNET_NO == ret) { GNUNET_break (GNUNET_SYSERR == ctx.res); - return TEH_RESPONSE_reply_transaction_unknown (connection); + return TEH_RESPONSE_reply_transaction_unknown (connection, + TALER_EC_TRACK_TRANSACTION_NOT_FOUND); } if (GNUNET_SYSERR == ctx.res) { GNUNET_break (0); return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_TRACK_TRANSACTION_WTID_RESOLUTION_ERROR, "bug resolving deposit wtid"); } return ctx.res; diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c index a97dd0514..b0ab42e7f 100644 --- a/src/exchange/taler-exchange-httpd_deposit.c +++ b/src/exchange/taler-exchange-httpd_deposit.c @@ -48,12 +48,9 @@ */ static int verify_and_execute_deposit (struct MHD_Connection *connection, - const struct TALER_EXCHANGEDB_Deposit *deposit) + const struct TALER_EXCHANGEDB_Deposit *deposit) { - struct TEH_KS_StateHandle *key_state; struct TALER_DepositRequestPS dr; - struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; - struct TALER_Amount fee_deposit; dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); @@ -76,39 +73,9 @@ verify_and_execute_deposit (struct MHD_Connection *connection, { TALER_LOG_WARNING ("Invalid signature on /deposit request\n"); return TEH_RESPONSE_reply_signature_invalid (connection, + TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID, "coin_sig"); } - /* check denomination exists and is valid */ - key_state = TEH_KS_acquire (); - dki = TEH_KS_denomination_key_lookup (key_state, - &deposit->coin.denom_pub, - TEH_KS_DKU_DEPOSIT); - if (NULL == dki) - { - TEH_KS_release (key_state); - TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n"); - return TEH_RESPONSE_reply_arg_unknown (connection, - "denom_pub"); - } - /* check coin signature */ - if (GNUNET_YES != - TALER_test_coin_valid (&deposit->coin)) - { - TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); - TEH_KS_release (key_state); - return TEH_RESPONSE_reply_signature_invalid (connection, - "ub_sig"); - } - TALER_amount_ntoh (&fee_deposit, - &dki->issue.properties.fee_deposit); - if (0 < TALER_amount_cmp (&fee_deposit, - &deposit->amount_with_fee)) - { - TEH_KS_release (key_state); - return TEH_RESPONSE_reply_external_error (connection, - "deposited amount smaller than depositing fee"); - } - TEH_KS_release (key_state); return TEH_DB_execute_deposit (connection, deposit); @@ -141,12 +108,11 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, json_t *wire; struct TALER_EXCHANGEDB_Deposit deposit; struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; - struct TEH_KS_StateHandle *ks; + struct TEH_KS_StateHandle *key_state; struct GNUNET_HashCode my_h_wire; - struct TALER_Amount amount; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_json ("wire", &wire), - TALER_JSON_spec_amount ("f", &amount), + TALER_JSON_spec_amount ("f", &deposit.amount_with_fee), TALER_JSON_spec_denomination_public_key ("denom_pub", &deposit.coin.denom_pub), TALER_JSON_spec_denomination_signature ("ub_sig", &deposit.coin.denom_sig), GNUNET_JSON_spec_fixed_auto ("coin_pub", &deposit.coin.coin_pub), @@ -180,11 +146,13 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, if (GNUNET_NO == res) return MHD_YES; /* failure */ + deposit.receiver_wire_account = wire; if (deposit.refund_deadline.abs_value_us > deposit.wire_deadline.abs_value_us) { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); return TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE, "refund_deadline"); } @@ -194,6 +162,7 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, { GNUNET_JSON_parse_free (spec); return TEH_RESPONSE_reply_arg_unknown (connection, + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT, "wire"); } if (GNUNET_OK != @@ -203,6 +172,7 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, TALER_LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n"); GNUNET_JSON_parse_free (spec); return TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON, "wire"); } if (0 != memcmp (&deposit.h_wire, @@ -212,32 +182,48 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, /* Client hashed contract differently than we did, reject */ GNUNET_JSON_parse_free (spec); return TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT, "H_wire"); } - ks = TEH_KS_acquire (); - dki = TEH_KS_denomination_key_lookup (ks, + + /* check denomination exists and is valid */ + key_state = TEH_KS_acquire (); + dki = TEH_KS_denomination_key_lookup (key_state, &deposit.coin.denom_pub, TEH_KS_DKU_DEPOSIT); if (NULL == dki) { - TEH_KS_release (ks); - GNUNET_JSON_parse_free (spec); + TEH_KS_release (key_state); + TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n"); return TEH_RESPONSE_reply_arg_unknown (connection, + TALER_EC_DEPOSIT_DENOMINATION_KEY_UNKNOWN, "denom_pub"); } TALER_amount_ntoh (&deposit.deposit_fee, &dki->issue.properties.fee_deposit); - TEH_KS_release (ks); - deposit.receiver_wire_account = wire; - deposit.amount_with_fee = amount; - if (-1 == TALER_amount_cmp (&deposit.amount_with_fee, - &deposit.deposit_fee)) + /* check coin signature */ + if (GNUNET_YES != + TALER_test_coin_valid (&deposit.coin)) { - /* Total amount smaller than fee, invalid */ - GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_arg_invalid (connection, - "f"); + TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); + TEH_KS_release (key_state); + return TEH_RESPONSE_reply_signature_invalid (connection, + TALER_EC_DEPOSIT_DENOMINATION_SIGNATURE_INVALID, + "ub_sig"); + } + TALER_amount_ntoh (&deposit.deposit_fee, + &dki->issue.properties.fee_deposit); + TEH_KS_release (key_state); + + if (0 < TALER_amount_cmp (&deposit.deposit_fee, + &deposit.amount_with_fee)) + { + GNUNET_break_op (0); + return TEH_RESPONSE_reply_external_error (connection, + TALER_EC_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE, + "deposited amount smaller than depositing fee"); } + res = verify_and_execute_deposit (connection, &deposit); GNUNET_JSON_parse_free (spec); diff --git a/src/exchange/taler-exchange-httpd_parsing.c b/src/exchange/taler-exchange-httpd_parsing.c index c7118c462..e9c38eb82 100644 --- a/src/exchange/taler-exchange-httpd_parsing.c +++ b/src/exchange/taler-exchange-httpd_parsing.c @@ -79,6 +79,7 @@ TEH_PARSE_post_json (struct MHD_Connection *connection, case GNUNET_JSON_PR_OUT_OF_MEMORY: return (MHD_NO == TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_PARSER_OUT_OF_MEMORY, "out of memory")) ? GNUNET_SYSERR : GNUNET_NO; case GNUNET_JSON_PR_CONTINUE: @@ -144,7 +145,9 @@ TEH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, if (NULL == str) { return (MHD_NO == - TEH_RESPONSE_reply_arg_missing (connection, param_name)) + TEH_RESPONSE_reply_arg_missing (connection, + TALER_EC_PARAMETER_MISSING, + param_name)) ? GNUNET_SYSERR : GNUNET_NO; } if (GNUNET_OK != @@ -153,7 +156,9 @@ TEH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, out_data, out_size)) return (MHD_NO == - TEH_RESPONSE_reply_arg_invalid (connection, param_name)) + TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_PARAMETER_MALFORMED, + param_name)) ? GNUNET_SYSERR : GNUNET_NO; return GNUNET_OK; } @@ -193,8 +198,9 @@ TEH_PARSE_json_data (struct MHD_Connection *connection, ret = (MHD_YES == TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{s:s, s:s, s:I}", + "{s:s, s:I, s:s, s:I}", "error", "parse error", + "code", (json_int_t) TALER_EC_JSON_INVALID_WITH_DETAILS, "field", error_json_name, "line", (json_int_t) error_line)) ? GNUNET_NO : GNUNET_SYSERR; diff --git a/src/exchange/taler-exchange-httpd_refresh.c b/src/exchange/taler-exchange-httpd_refresh.c index 0c500920d..3a8875f44 100644 --- a/src/exchange/taler-exchange-httpd_refresh.c +++ b/src/exchange/taler-exchange-httpd_refresh.c @@ -69,7 +69,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection, struct TALER_Amount total_melt; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "melt request for session %s\n", + "/refresh/melt request for session %s\n", GNUNET_h2s (session_hash)); GNUNET_assert (GNUNET_OK == @@ -86,6 +86,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection, GNUNET_break_op (0); TEH_KS_release (key_state); return TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_REFRESH_MELT_FRESH_DENOMINATION_KEY_NOT_FOUND, "new_denoms"); } dki = &dk->issue; @@ -105,6 +106,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection, GNUNET_break_op (0); TEH_KS_release (key_state); return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_REFRESH_MELT_COST_CALCULATION_OVERFLOW, "cost calculation failure"); } } @@ -115,8 +117,9 @@ handle_refresh_melt_binary (struct MHD_Connection *connection, if (NULL == dk) { GNUNET_break (0); - return TEH_RESPONSE_reply_arg_invalid (connection, - "denom_pub"); + return TEH_RESPONSE_reply_arg_unknown (connection, + TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND, + "denom_pub"); } dki = &dk->issue; TALER_amount_ntoh (&fee_melt, @@ -129,6 +132,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection, GNUNET_break_op (0); TEH_KS_release (key_state); return TEH_RESPONSE_reply_external_error (connection, + TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION, "Melt contribution below melting fee"); } TEH_KS_release (key_state); @@ -141,8 +145,9 @@ handle_refresh_melt_binary (struct MHD_Connection *connection, total value of coins being generated to match! */ return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", "value mismatch"); + "{s:s, s:I}", + "error", "value mismatch", + "code", (json_int_t) TALER_EC_REFRESH_MELT_FEES_MISSMATCH); } return TEH_DB_execute_refresh_melt (connection, session_hash, @@ -203,6 +208,7 @@ get_coin_public_info (struct MHD_Connection *connection, r_melt_detail->coin_info.denom_pub.rsa_public_key = NULL; return (MHD_YES == TEH_RESPONSE_reply_signature_invalid (connection, + TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID, "denom_sig")) ? GNUNET_NO : GNUNET_SYSERR; } @@ -237,6 +243,8 @@ verify_coin_public_info (struct MHD_Connection *connection, struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; struct TALER_Amount fee_refresh; + /* FIXME: we lookup the dki twice during /refresh/melt. + This should be avoided. */ key_state = TEH_KS_acquire (); dki = TEH_KS_denomination_key_lookup (key_state, &melt_detail->coin_info.denom_pub, @@ -246,6 +254,7 @@ verify_coin_public_info (struct MHD_Connection *connection, TEH_KS_release (key_state); TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n"); return TEH_RESPONSE_reply_arg_unknown (connection, + TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND, "denom_pub"); } TALER_amount_ntoh (&fee_refresh, @@ -266,6 +275,7 @@ verify_coin_public_info (struct MHD_Connection *connection, TEH_KS_release (key_state); return (MHD_YES == TEH_RESPONSE_reply_external_error (connection, + TALER_EC_REFRESH_MELT_AMOUNT_INSUFFICIENT, "melt amount smaller than melting fee")) ? GNUNET_NO : GNUNET_SYSERR; } @@ -280,6 +290,7 @@ verify_coin_public_info (struct MHD_Connection *connection, GNUNET_break_op (0); if (MHD_YES != TEH_RESPONSE_reply_signature_invalid (connection, + TALER_EC_REFRESH_MELT_COIN_SIGNATURE_INVALID, "confirm_sig")) return GNUNET_SYSERR; return GNUNET_NO; @@ -565,6 +576,7 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh, GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); return TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_REFRESH_MELT_CNC_COIN_ARRAY_SIZE_INVALID, "coin_evs"); } if (TALER_CNC_KAPPA != json_array_size (transfer_pubs)) @@ -572,6 +584,7 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh, GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); return TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_REFRESH_MELT_CNC_TRANSFER_ARRAY_SIZE_INVALID, "transfer_pubs"); } res = handle_refresh_melt_json (connection, @@ -694,6 +707,7 @@ TEH_REFRESH_handler_refresh_reveal (struct TEH_RequestHandler *rh, GNUNET_JSON_parse_free (spec); GNUNET_break_op (0); return TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_REFRESH_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID, "transfer_privs"); } res = handle_refresh_reveal_json (connection, diff --git a/src/exchange/taler-exchange-httpd_refund.c b/src/exchange/taler-exchange-httpd_refund.c index fdb6f8b76..591bb188d 100644 --- a/src/exchange/taler-exchange-httpd_refund.c +++ b/src/exchange/taler-exchange-httpd_refund.c @@ -69,14 +69,16 @@ verify_and_execute_refund (struct MHD_Connection *connection, { GNUNET_break_op (0); return TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH, "refund_fee"); } if (-1 == TALER_amount_cmp (&refund->refund_amount, &refund->refund_fee) ) { GNUNET_break_op (0); - return TEH_RESPONSE_reply_signature_invalid (connection, - "refund_amount"); + return TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_REFUND_FEE_ABOVE_AMOUNT, + "refund_amount"); } if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND, @@ -86,6 +88,7 @@ verify_and_execute_refund (struct MHD_Connection *connection, { TALER_LOG_WARNING ("Invalid signature on /refund request\n"); return TEH_RESPONSE_reply_signature_invalid (connection, + TALER_EC_REFUND_MERCHANT_SIGNATURE_INVALID, "merchant_sig"); } return TEH_DB_execute_refund (connection, diff --git a/src/exchange/taler-exchange-httpd_reserve.c b/src/exchange/taler-exchange-httpd_reserve.c index 7098e99a2..0abe37c5a 100644 --- a/src/exchange/taler-exchange-httpd_reserve.c +++ b/src/exchange/taler-exchange-httpd_reserve.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014,2015 GNUnet e.V. + Copyright (C) 2014, 2015, 2016 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 @@ -138,6 +138,7 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh, GNUNET_JSON_parse_free (spec); TEH_KS_release (ks); return TEH_RESPONSE_reply_arg_unknown (connection, + TALER_EC_WITHDRAW_DENOMINATION_KEY_NOT_FOUND, "denom_pub"); } TALER_amount_ntoh (&amount, @@ -171,6 +172,7 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh, TALER_LOG_WARNING ("Client supplied invalid signature for /reserve/withdraw request\n"); GNUNET_JSON_parse_free (spec); return TEH_RESPONSE_reply_signature_invalid (connection, + TALER_EC_WITHDRAW_RESERVE_SIGNATURE_INVALID, "reserve_sig"); } res = TEH_DB_execute_reserve_withdraw (connection, diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c index cacd933f1..b31f22e10 100644 --- a/src/exchange/taler-exchange-httpd_responses.c +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -132,17 +132,20 @@ TEH_RESPONSE_reply_json_pack (struct MHD_Connection *connection, * Send a response indicating an invalid argument. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param param_name the parameter that is invalid * @return a MHD result code */ int TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *param_name) { return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{s:s, s:s}", + "{s:s, s:I, s:s}", "error", "invalid parameter", + "code", (json_int_t) ec, "parameter", param_name); } @@ -153,17 +156,20 @@ TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, * denomination key). * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param param_name the parameter that is invalid * @return a MHD result code */ int TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *param_name) { return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_NOT_FOUND, - "{s:s, s:s}", + "{s:s, s:I, s:s}", "error", "unknown entity referenced", + "code", (json_int_t) ec, "parameter", param_name); } @@ -172,17 +178,20 @@ TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, * Send a response indicating an invalid signature. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param param_name the parameter that is invalid * @return a MHD result code */ int TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *param_name) { return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_UNAUTHORIZED, - "{s:s, s:s}", + "{s:s, s:I, s:s}", "error", "invalid signature", + "code", (json_int_t) ec, "parameter", param_name); } @@ -191,17 +200,20 @@ TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, * Send a response indicating a missing argument. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param param_name the parameter that is missing * @return a MHD result code */ int TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *param_name) { return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{ s:s, s:s}", + "{ s:s, s:I, s:s}", "error", "missing parameter", + "code", (json_int_t) ec, "parameter", param_name); } @@ -210,17 +222,20 @@ TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, * Send a response indicating permission denied. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param hint hint about why access was denied * @return a MHD result code */ int TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *hint) { return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_FORBIDDEN, - "{s:s, s:s}", + "{s:s, s:I, s:s}", "error", "permission denied", + "code", (json_int_t) ec, "hint", hint); } @@ -229,17 +244,20 @@ TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection, * Send a response indicating an internal error. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param hint hint about the internal error's nature * @return a MHD result code */ int TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *hint) { return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, - "{s:s, s:s}", + "{s:s, s:I, s:s}", "error", "internal error", + "code", (json_int_t) ec, "hint", hint); } @@ -248,17 +266,20 @@ TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, * Send a response indicating an external error. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param hint hint about the error's nature * @return a MHD result code */ int TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *hint) { return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{s:s, s:s}", + "{s:s, s:I, s:s}", "error", "client error", + "code", (json_int_t) ec, "hint", hint); } @@ -268,15 +289,18 @@ TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection, * transaction (concurrent interference). * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @return a MHD result code */ int -TEH_RESPONSE_reply_commit_error (struct MHD_Connection *connection) +TEH_RESPONSE_reply_commit_error (struct MHD_Connection *connection, + enum TALER_ErrorCode ec) { return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", "commit failure"); + "{s:s, s:I}", + "error", "commit failure", + "code", (json_int_t) ec); } @@ -285,12 +309,15 @@ TEH_RESPONSE_reply_commit_error (struct MHD_Connection *connection) * database. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @return a MHD result code */ int -TEH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection) +TEH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection, + enum TALER_ErrorCode ec) { return TEH_RESPONSE_reply_internal_error (connection, + ec, "Failed to connect to database"); } @@ -332,9 +359,9 @@ TEH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection) { return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", - "invalid json"); + "{s:s, s:I}", + "error", "invalid json", + "code", (json_int_t) TALER_EC_JSON_INVALID); } @@ -556,11 +583,13 @@ TEH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection history = compile_transaction_history (tl); if (NULL == history) - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_DEPOSIT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS); return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_FORBIDDEN, - "{s:s, s:o}", + "{s:s, s:I, s:o}", "error", "insufficient funds", + "code", (json_int_t) TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS, "history", history); } @@ -696,8 +725,9 @@ TEH_RESPONSE_reply_refund_conflict (struct MHD_Connection *connection, { return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_CONFLICT, - "{s:s, s:o}", + "{s:s, s:I, s:o}", "status", "conflicting refund", + "code", (json_int_t) TALER_EC_REFUND_CONFLICT, "history", compile_transaction_history (tl)); } @@ -708,17 +738,19 @@ TEH_RESPONSE_reply_refund_conflict (struct MHD_Connection *connection, * * @param connection connection to the client * @param response_code response code to generate + * @param ec taler error code to include * @return MHD result code */ int TEH_RESPONSE_reply_refund_failure (struct MHD_Connection *connection, - unsigned int response_code) + unsigned int response_code, + enum TALER_ErrorCode ec) { return TEH_RESPONSE_reply_json_pack (connection, response_code, - "{s:s}", - "error", - "no details"); + "{s:s, s:I}", + "status", "refund failure", + "code", (json_int_t) ec); } @@ -779,6 +811,7 @@ TEH_RESPONSE_reply_reserve_status_success (struct MHD_Connection *connection, &balance); if (NULL == json_history) return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_RESERVE_STATUS_DB_ERROR, "balance calculation failure"); json_balance = TALER_JSON_from_amount (&balance); return TEH_RESPONSE_reply_json_pack (connection, @@ -810,12 +843,14 @@ TEH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *c &balance); if (NULL == json_history) return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS, "balance calculation failure"); json_balance = TALER_JSON_from_amount (&balance); return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_PAYMENT_REQUIRED, - "{s:s, s:o, s:o}", + MHD_HTTP_FORBIDDEN, + "{s:s, s:I, s:o, s:o}", "error", "Insufficient funds", + "code", (json_int_t) TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS, "balance", json_balance, "history", json_history); } @@ -830,7 +865,7 @@ TEH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *c */ int TEH_RESPONSE_reply_reserve_withdraw_success (struct MHD_Connection *connection, - const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable) + const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable) { json_t *sig_json; @@ -869,12 +904,15 @@ TEH_RESPONSE_reply_refresh_melt_insufficient_funds (struct MHD_Connection *conne history = compile_transaction_history (tl); if (NULL == history) - return TEH_RESPONSE_reply_internal_db_error (connection); + return TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_MELT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS); return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_FORBIDDEN, - "{s:s, s:o, s:o, s:o, s:o, s:o}", + "{s:s, s:I, s:o, s:o, s:o, s:o, s:o}", "error", - "insufficient funds", + "insufficient funds", + "code", + (json_int_t) TALER_EC_REFRESH_MELT_INSUFFICIENT_FUNDS, "coin_pub", GNUNET_JSON_from_data_auto (coin_pub), "original_value", @@ -1011,8 +1049,9 @@ TEH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection, } return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_CONFLICT, - "{s:s, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:i}", + "{s:s, s:I, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:i}", "error", "commitment violation", + "code", (json_int_t) TALER_EC_REFRESH_REVEAL_COMMITMENT_VIOLATION, "coin_sig", GNUNET_JSON_from_data_auto (&session->melt.coin_sig), "coin_pub", GNUNET_JSON_from_data_auto (&session->melt.coin.coin_pub), "melt_amount_with_fee", TALER_JSON_from_amount (&session->melt.amount_with_fee), @@ -1089,15 +1128,18 @@ TEH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection, * 404 reply. * * @param connection connection to the client + * @param ec Taler error code * @return MHD result code */ int -TEH_RESPONSE_reply_transaction_unknown (struct MHD_Connection *connection) +TEH_RESPONSE_reply_transaction_unknown (struct MHD_Connection *connection, + enum TALER_ErrorCode ec) { return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", "Deposit unknown"); + "{s:s, s:I}", + "error", "Deposit unknown", + "code", (json_int_t) ec); } diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h index 742a95b91..70d384fe4 100644 --- a/src/exchange/taler-exchange-httpd_responses.h +++ b/src/exchange/taler-exchange-httpd_responses.h @@ -29,6 +29,7 @@ #include <jansson.h> #include <microhttpd.h> #include <pthread.h> +#include "taler_error_codes.h" #include "taler-exchange-httpd.h" #include "taler-exchange-httpd_db.h" @@ -78,11 +79,13 @@ TEH_RESPONSE_reply_json_pack (struct MHD_Connection *connection, * Send a response indicating an invalid signature. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param param_name the parameter that is invalid * @return a MHD result code */ int TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *param_name); @@ -90,11 +93,13 @@ TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, * Send a response indicating an invalid argument. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param param_name the parameter that is invalid * @return MHD result code */ int TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *param_name); @@ -104,11 +109,13 @@ TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, * denomination key). * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param param_name the parameter that is invalid * @return a MHD result code */ int TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *param_name); @@ -116,11 +123,13 @@ TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, * Send a response indicating a missing argument. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param param_name the parameter that is missing * @return a MHD result code */ int TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *param_name); @@ -128,11 +137,13 @@ TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, * Send a response indicating permission denied. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param hint hint about why access was denied * @return a MHD result code */ int TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *hint); @@ -140,11 +151,13 @@ TEH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection, * Send a response indicating an internal error. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param hint hint about the internal error's nature * @return a MHD result code */ int TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *hint); @@ -152,11 +165,13 @@ TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, * Send a response indicating an external error. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @param hint hint about the error's nature * @return a MHD result code */ int TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *hint); @@ -165,21 +180,24 @@ TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection, * transaction (concurrent interference). * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @return a MHD result code */ int -TEH_RESPONSE_reply_commit_error (struct MHD_Connection *connection); - +TEH_RESPONSE_reply_commit_error (struct MHD_Connection *connection, + enum TALER_ErrorCode ec); /** * Send a response indicating a failure to talk to the Exchange's * database. * * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error * @return a MHD result code */ int -TEH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection); +TEH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection, + enum TALER_ErrorCode ec); /** @@ -199,7 +217,7 @@ TEH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection); * @return a MHD result code */ int -TEH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection); +TEH_RESPONSE_reply_invalid_json (struct MHD_Connection *connectionx); /** @@ -266,11 +284,13 @@ TEH_RESPONSE_reply_refund_conflict (struct MHD_Connection *connection, * * @param connection connection to the client * @param response_code response code to generate + * @param ec error code uniquely identifying the error * @return MHD result code */ int TEH_RESPONSE_reply_refund_failure (struct MHD_Connection *connection, - unsigned int response_code); + unsigned int response_code, + enum TALER_ErrorCode ec); /** @@ -291,10 +311,12 @@ TEH_RESPONSE_reply_refund_success (struct MHD_Connection *connection, * 404 reply. * * @param connection connection to the client + * @param ec Taler error code * @return MHD result code */ int -TEH_RESPONSE_reply_transaction_unknown (struct MHD_Connection *connection); +TEH_RESPONSE_reply_transaction_unknown (struct MHD_Connection *connection, + enum TALER_ErrorCode ec); /** @@ -307,7 +329,7 @@ TEH_RESPONSE_reply_transaction_unknown (struct MHD_Connection *connection); */ int TEH_RESPONSE_reply_transfer_pending (struct MHD_Connection *connection, - struct GNUNET_TIME_Absolute planned_exec_time); + struct GNUNET_TIME_Absolute planned_exec_time); /** diff --git a/src/exchange/taler-exchange-httpd_test.c b/src/exchange/taler-exchange-httpd_test.c index 7c3252b10..731da36ce 100644 --- a/src/exchange/taler-exchange-httpd_test.c +++ b/src/exchange/taler-exchange-httpd_test.c @@ -295,6 +295,7 @@ TEH_TEST_handler_test_ecdhe (struct TEH_RequestHandler *rh, { GNUNET_JSON_parse_free (spec); return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_TEST_ECDH_ERROR, "Failed to perform ECDH"); } GNUNET_JSON_parse_free (spec); @@ -365,6 +366,7 @@ TEH_TEST_handler_test_eddsa (struct TEH_RequestHandler *rh, { GNUNET_JSON_parse_free (spec); return TEH_RESPONSE_reply_signature_invalid (connection, + TALER_EC_TEST_EDDSA_INVALID, "eddsa_sig"); } GNUNET_JSON_parse_free (spec); @@ -377,6 +379,7 @@ TEH_TEST_handler_test_eddsa (struct TEH_RequestHandler *rh, { GNUNET_free (pk); return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_TEST_EDDSA_ERROR, "Failed to EdDSA-sign"); } GNUNET_CRYPTO_eddsa_key_get_public (pk, @@ -419,6 +422,7 @@ TEH_TEST_handler_test_rsa_get (struct TEH_RequestHandler *rh, { GNUNET_break (0); return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_TEST_RSA_GEN_ERROR, "Failed to create RSA key"); } pub = GNUNET_CRYPTO_rsa_private_key_get_public (rsa_pk); @@ -426,6 +430,7 @@ TEH_TEST_handler_test_rsa_get (struct TEH_RequestHandler *rh, { GNUNET_break (0); return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_TEST_RSA_PUB_ERROR, "Failed to get public RSA key"); } res = TEH_RESPONSE_reply_json_pack (connection, @@ -489,6 +494,7 @@ TEH_TEST_handler_test_rsa_sign (struct TEH_RequestHandler *rh, GNUNET_break (0); GNUNET_JSON_parse_free (spec); return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_TEST_RSA_GEN_ERROR, "Failed to create RSA key"); } sig = GNUNET_CRYPTO_rsa_sign_blinded (rsa_pk, @@ -499,6 +505,7 @@ TEH_TEST_handler_test_rsa_sign (struct TEH_RequestHandler *rh, GNUNET_break (0); GNUNET_JSON_parse_free (spec); return TEH_RESPONSE_reply_internal_error (connection, + TALER_EC_TEST_RSA_SIGN_ERROR, "Failed to RSA-sign"); } GNUNET_JSON_parse_free (spec); diff --git a/src/exchange/taler-exchange-httpd_tracking.c b/src/exchange/taler-exchange-httpd_tracking.c index 1c7c24557..04b50132c 100644 --- a/src/exchange/taler-exchange-httpd_tracking.c +++ b/src/exchange/taler-exchange-httpd_tracking.c @@ -88,6 +88,7 @@ check_and_handle_track_transaction_request (struct MHD_Connection *connection, { GNUNET_break_op (0); return TEH_RESPONSE_reply_signature_invalid (connection, + TALER_EC_TRACK_TRANSACTION_MERCHANT_SIGNATURE_INVALID, "merchant_sig"); } return TEH_DB_execute_track_transaction (connection, diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 972d70808..461184c7e 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -20,6 +20,7 @@ * @author Florian Dold * @author Christian Grothoff * @author Sree Harsha Totakura + * @author Marcello Stanisci */ #include "platform.h" #include "taler_pq_lib.h" @@ -627,6 +628,23 @@ postgres_prepare (PGconn *db_conn) "($1, $2, $3, $4, $5, $6, $7);", 7, NULL); + + /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound + transactions for reserves with serial id '\geq' the given parameter */ + PREPARE ("audit_reserves_in_get_transactions_incr", + "SELECT" + " reserve_pub" + ",credit_val" + ",credit_frac" + ",credit_curr" + ",execution_date" + ",sender_account_details" + ",transfer_details" + " FROM reserves_in" + " WHERE reserve_in_serial_id>=$1" + " ORDER BY reserve_in_serial_id", + 1, NULL); + /* Used in #postgres_get_reserve_history() to obtain inbound transactions for a reserve */ PREPARE ("reserves_in_get_transactions", @@ -707,6 +725,23 @@ postgres_prepare (PGconn *db_conn) " WHERE reserve_pub=$1;", 1, NULL); + /* Used in #postgres_select_reserves_out_above_serial_id() */ + PREPARE ("audit_get_reserves_out_incr", + "SELECT" + " h_blind_ev" + ",denom_pub" + ",denom_sig" + ",reserve_sig" + ",reserve_pub" + ",execution_date" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + " FROM reserves_out" + " WHERE reserve_out_serial_id>=$1" + " ORDER BY reserve_out_serial_id ASC", + 1, NULL); + /* Used in #postgres_get_refresh_session() to fetch high-level information about a refresh session */ PREPARE ("get_refresh_session", @@ -727,6 +762,22 @@ postgres_prepare (PGconn *db_conn) " WHERE session_hash=$1 ", 1, NULL); + /* Used in #postgres_select_refreshs_above_serial_id() to fetch + refresh session with id '\geq' the given parameter */ + PREPARE ("audit_get_refresh_sessions_incr", + "SELECT" + " old_coin_pub" + ",old_coin_sig" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",num_newcoins" + ",noreveal_index" + " FROM refresh_sessions" + " WHERE melt_serial_id>=$1" + " ORDER BY melt_serial_id ASC", + 1, NULL); + /* Used in #postgres_create_refresh_session() to store high-level information about a refresh session */ PREPARE ("insert_refresh_session", @@ -802,6 +853,23 @@ postgres_prepare (PGconn *db_conn) " WHERE old_coin_pub=$1", 1, NULL); + /* Fetch refunds with rowid '\geq' the given parameter */ + PREPARE ("audit_get_refunds_incr", + "SELECT" + " merchant_pub" + ",merchant_sig" + ",h_contract" + ",transaction_id" + ",rtransaction_id" + ",coin_pub" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + " FROM refunds" + " WHERE refund_serial_id>=$1" + " ORDER BY refund_serial_id ASC", + 1, NULL); + /* Query the 'refunds' by coin public key */ PREPARE ("get_refunds_by_coin", "SELECT" @@ -823,6 +891,7 @@ postgres_prepare (PGconn *db_conn) 1, NULL); + /* Used in #postgres_insert_transfer_public_key() to store commitments */ PREPARE ("insert_transfer_public_key", @@ -921,8 +990,7 @@ postgres_prepare (PGconn *db_conn) " )", 3, NULL); - /* Fetch an existing deposit request, used to ensure idempotency - during /deposit processing. Used in #postgres_have_deposit(). */ + /* Fetch deposits with rowid '\geq' the given parameter */ PREPARE ("audit_get_deposits_incr", "SELECT" " amount_with_fee_val" @@ -937,11 +1005,12 @@ postgres_prepare (PGconn *db_conn) ",wire_deadline" ",h_contract" ",wire" + ",done" " FROM deposits" " WHERE (" " (deposit_serial_id>=$1)" " )" - " ORDER BY deposit_serial_id", + " ORDER BY deposit_serial_id ASC", 1, NULL); /* Fetch an existing deposit request. @@ -1207,6 +1276,18 @@ postgres_prepare (PGconn *db_conn) " FROM prewire" " WHERE finished=true", 0, NULL); + + /* Used in #postgres_select_prepare_above_serial_id() */ + PREPARE ("audit_get_wire_incr", + "SELECT" + " type" + ",buf" + ",finished" + " FROM prewire" + " WHERE prewire_uuid>=$1" + " ORDER BY prewire_uuid ASC", + 1, NULL); + PREPARE ("gc_denominations", "DELETE" " FROM denominations" @@ -4291,9 +4372,9 @@ postgres_select_deposits_above_serial_id (void *cls, }; PGresult *result; result = GNUNET_PQ_exec_prepared (session->conn, - "audit_get_deposits_incr", - params); - if (PGRES_COMMAND_OK != + "audit_get_deposits_incr", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) { BREAK_DB_ERR (result); @@ -4307,20 +4388,62 @@ postgres_select_deposits_above_serial_id (void *cls, if (0 == nrows) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "audit_get_deposit_incr() returned 0 matching rows\n"); + "select_deposits_above_serial_id() returned 0 matching rows\n"); PQclear (result); return GNUNET_NO; } for (i=0;i<nrows;i++) { + struct TALER_EXCHANGEDB_Deposit deposit; + uint8_t done = 0; + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_amount ("amount_with_fee", + &deposit.amount_with_fee), + GNUNET_PQ_result_spec_absolute_time ("timestamp", + &deposit.timestamp), + GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", + &deposit.merchant_pub), + GNUNET_PQ_result_spec_auto_from_type ("coin_pub", + &deposit.coin.coin_pub), + GNUNET_PQ_result_spec_auto_from_type ("coin_sig", + &deposit.csig), + GNUNET_PQ_result_spec_uint64 ("transaction_id", + &deposit.transaction_id), + GNUNET_PQ_result_spec_absolute_time ("refund_deadline", + &deposit.refund_deadline), + GNUNET_PQ_result_spec_absolute_time ("wire_deadline", + &deposit.wire_deadline), + GNUNET_PQ_result_spec_auto_from_type ("h_contract", + &deposit.h_contract), + TALER_PQ_result_spec_json ("wire", + &deposit.receiver_wire_account), + GNUNET_PQ_result_spec_auto_from_type ("done", + &done), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + cb (cb_cls, + serial_id, + &deposit.merchant_pub, + &deposit.coin.coin_pub, + &deposit.csig, + &deposit.amount_with_fee, + deposit.transaction_id, + &deposit.h_contract, + deposit.refund_deadline, + deposit.wire_deadline, + deposit.receiver_wire_account, + done); } - PQclear (result); return GNUNET_OK; - - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; } @@ -4343,8 +4466,72 @@ postgres_select_refreshs_above_serial_id (void *cls, TALER_EXCHANGEDB_RefreshSessionCallback cb, void *cb_cls) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&serial_id), + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "audit_get_refresh_sessions_incr", + params); + + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + int nrows; + int i; + + nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "select_refreshs_above_serial_id() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + + for (i=0;i<nrows;i++) + { + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_CoinSpendSignatureP coin_sig; + struct TALER_Amount amount_with_fee; + uint16_t num_newcoins; + uint16_t noreveal_index; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub", + &coin_pub), + GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig", + &coin_sig), + TALER_PQ_result_spec_amount ("amount_with_fee", + &amount_with_fee), + GNUNET_PQ_result_spec_uint16 ("num_newcoins", + &num_newcoins), + GNUNET_PQ_result_spec_uint16 ("noreveal_index", + &noreveal_index), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + cb (cb_cls, + serial_id, + &coin_pub, + &coin_sig, + &amount_with_fee, + num_newcoins, + noreveal_index); + } + PQclear (result); + return GNUNET_OK; } @@ -4367,8 +4554,72 @@ postgres_select_refunds_above_serial_id (void *cls, TALER_EXCHANGEDB_RefundCallback cb, void *cb_cls) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&serial_id), + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "audit_get_refunds_incr", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + int nrows; + int i; + + nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "select_refunds_above_serial_id() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + for (i=0;i<nrows;i++) + { + struct TALER_EXCHANGEDB_Refund refund; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", + &refund.merchant_pub), + GNUNET_PQ_result_spec_auto_from_type ("merchant_sig", + &refund.merchant_sig), + GNUNET_PQ_result_spec_auto_from_type ("h_contract", + &refund.h_contract), + GNUNET_PQ_result_spec_uint64 ("transaction_id", + &refund.transaction_id), + GNUNET_PQ_result_spec_uint64 ("rtransaction_id", + &refund.rtransaction_id), + GNUNET_PQ_result_spec_auto_from_type ("coin_pub", + &refund.coin.coin_pub), + TALER_PQ_result_spec_amount ("amount_with_fee", + &refund.refund_amount), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + cb (cb_cls, + serial_id, + &refund.coin.coin_pub, + &refund.merchant_pub, + &refund.merchant_sig, + &refund.h_contract, + refund.transaction_id, + refund.rtransaction_id, + &refund.refund_amount); + } + PQclear (result); + return GNUNET_OK; } @@ -4391,8 +4642,73 @@ postgres_select_reserves_in_above_serial_id (void *cls, TALER_EXCHANGEDB_ReserveInCallback cb, void *cb_cls) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&serial_id), + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "audit_reserves_in_get_transactions_incr", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + int nrows; + int i; + + nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "select_reserves_in_above_serial_id() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + + for (i=0;i<nrows;i++) + { + struct TALER_ReservePublicKeyP reserve_pub; + struct TALER_Amount credit; + json_t *sender_account_details; + json_t *transfer_details; + struct GNUNET_TIME_Absolute execution_date; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", + &reserve_pub), + TALER_PQ_result_spec_amount ("credit", + &credit), + GNUNET_PQ_result_spec_absolute_time("execution_date", + &execution_date), + TALER_PQ_result_spec_json ("sender_account_details", + &sender_account_details), + TALER_PQ_result_spec_json ("transfer_details", + &transfer_details), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + cb (cb_cls, + serial_id, + &reserve_pub, + &credit, + sender_account_details, + transfer_details, + execution_date); + } + + PQclear (result); + return GNUNET_OK; } @@ -4415,8 +4731,79 @@ postgres_select_reserves_out_above_serial_id (void *cls, TALER_EXCHANGEDB_WithdrawCallback cb, void *cb_cls) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&serial_id), + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "audit_get_reserves_out_incr", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + int nrows; + int i; + + nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "select_reserves_out_above_serial_id() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + for (i=0;i<nrows;i++) + { + struct GNUNET_HashCode h_blind_ev; + struct TALER_DenominationPublicKey denom_pub; + struct TALER_DenominationSignature denom_sig; + struct TALER_ReservePublicKeyP reserve_pub; + struct TALER_ReserveSignatureP reserve_sig; + struct GNUNET_TIME_Absolute execution_date; + struct TALER_Amount amount_with_fee; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev", + &h_blind_ev), + GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", + &denom_pub.rsa_public_key), + GNUNET_PQ_result_spec_rsa_signature ("denom_sig", + &denom_sig.rsa_signature), + GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", + &reserve_pub), + GNUNET_PQ_result_spec_auto_from_type ("reserve_sig", + &reserve_sig), + GNUNET_PQ_result_spec_absolute_time ("execution_date", + &execution_date), + TALER_PQ_result_spec_amount ("amount_with_fee", + &amount_with_fee), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + cb (cb_cls, + serial_id, + &h_blind_ev, + &denom_pub, + &denom_sig, + &reserve_pub, + &reserve_sig, + execution_date, + &amount_with_fee); + } + + PQclear (result); + return GNUNET_OK; } @@ -4440,8 +4827,69 @@ postgres_select_prepare_above_serial_id (void *cls, TALER_EXCHANGEDB_WirePreparationCallback cb, void *cb_cls) { - GNUNET_break (0); // FIXME: not implemented - return GNUNET_SYSERR; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&serial_id), + GNUNET_PQ_query_param_end + }; + PGresult *result; + result = GNUNET_PQ_exec_prepared (session->conn, + "audit_get_wire_incr", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + int nrows; + int i; + + nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "select_prepare_above_serial_id() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + for (i=0;i<nrows;i++) + { + char *wire_method; + void *buf; + size_t buf_size; + uint8_t finished; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_string ("type", + &wire_method), + GNUNET_PQ_result_spec_variable_size ("buf", + &buf, + &buf_size), + GNUNET_PQ_result_spec_auto_from_type ("finished", + &finished), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + + cb (cb_cls, + serial_id, + wire_method, + buf, + buf_size, + finished); + } + + PQclear (result); + return GNUNET_OK; } diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index 00c7a9ef6..d0ec63f46 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -18,6 +18,7 @@ * @brief test cases for DB interaction functions * @author Sree Harsha Totakura * @author Christian Grothoff + * @author Marcello Stanisci */ #include "platform.h" #include "taler_exchangedb_lib.h" @@ -77,6 +78,12 @@ dead_prepare_cb (void *cls, GNUNET_assert (0); } +/** + * Counter used in auditor-related db functions. Used to count + * expected rows. + */ +unsigned int auditor_row_cnt; + /** * Callback that is called with wire prepare data @@ -103,6 +110,27 @@ mark_prepare_cb (void *cls, rowid)); } +/** + * Callback with data about a prepared wire transfer. + * + * @param cls closure + * @param rowid row identifier used to mark prepared transaction as done + * @param wire_method which wire method is this preparation data for + * @param buf transaction data that was persisted, NULL on error + * @param buf_size number of bytes in @a buf, 0 on error + * @param finished did we complete the transfer yet? + */ +void +audit_wire_cb (void *cls, + unsigned long long rowid, + const char *wire_method, + const char *buf, + size_t buf_size, + int finished) +{ + auditor_row_cnt++; + return; +} /** * Test API relating to persisting the wire plugins preparation data. @@ -134,6 +162,14 @@ test_wire_prepare (struct TALER_EXCHANGEDB_Session *session) session, &dead_prepare_cb, NULL)); + auditor_row_cnt = 0; + FAILIF (GNUNET_OK != + plugin->select_prepare_above_serial_id (plugin->cls, + session, + 0, + &audit_wire_cb, + NULL)); + FAILIF (1 != auditor_row_cnt); return GNUNET_OK; drop: return GNUNET_SYSERR; @@ -465,6 +501,38 @@ check_transfer_data (void *cls, *ok = GNUNET_SYSERR; } +/** + * Function called with details about coins that were melted, + * with the goal of auditing the refresh's execution. + * + * @param cls closure + * @param rowid unique serial ID for the refresh session in our DB + * @param merchant_pub public key of the merchant + * @param coin_pub public key of the coin + * @param coin_sig signature from the coin + * @param amount_with_fee amount that was deposited including fee + * @param transaction_id unique transaction ID chosen by the merchant + * @param h_contract hash of the contract between merchant and customer + * @param refund_deadline by which the merchant adviced that he might want + * to get a refund + * @param wire_deadline by which the merchant adviced that he would like the + * wire transfer to be executed + * @param receiver_wire_account wire details for the merchant, NULL from iterate_matching_deposits() + * @param done flag set if the deposit was already executed (or not) + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop + */ +int +audit_refresh_session_cb (void *cls, + unsigned long long rowid, /* FIXME: decide data type for serial_id! */ + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig, + const struct TALER_Amount *amount_with_fee, + uint16_t num_newcoins, + uint16_t noreveal_index) +{ + auditor_row_cnt++; + return GNUNET_OK; +} /** * Function to test melting of coins as part of a refresh session @@ -538,6 +606,14 @@ test_melting (struct TALER_EXCHANGEDB_Session *session) session, &session_hash, &ret_refresh_session)); + + auditor_row_cnt = 0; + FAILIF (GNUNET_OK != plugin->select_refreshs_above_serial_id (plugin->cls, + session, + 0, + &audit_refresh_session_cb, + NULL)); + FAILIF (1 != auditor_row_cnt); FAILIF (ret_refresh_session.num_newcoins != refresh_session.num_newcoins); FAILIF (ret_refresh_session.noreveal_index != refresh_session.noreveal_index); @@ -874,6 +950,128 @@ deposit_cb (void *cls, return GNUNET_OK; } +/** + * Callback for #select_deposits_above_serial_id () + * + * @param cls closure + * @param rowid unique serial ID for the deposit in our DB + * @param merchant_pub public key of the merchant + * @param coin_pub public key of the coin + * @param coin_sig signature from the coin + * @param amount_with_fee amount that was deposited including fee + * @param transaction_id unique transaction ID chosen by the merchant + * @param h_contract hash of the contract between merchant and customer + * @param refund_deadline by which the merchant adviced that he might want + * to get a refund + * @param wire_deadline by which the merchant adviced that he would like the + * wire transfer to be executed + * @param receiver_wire_account wire details for the merchant, NULL from iterate_matching_deposits() + * @param done flag set if the deposit was already executed (or not) + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop + */ +int +audit_deposit_cb (void *cls, + unsigned long long rowid, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig, + const struct TALER_Amount *amount_with_fee, + uint64_t transaction_id, + const struct GNUNET_HashCode *h_contract, + struct GNUNET_TIME_Absolute refund_deadline, + struct GNUNET_TIME_Absolute wire_deadline, + const json_t *receiver_wire_account, + int done) +{ + auditor_row_cnt++; + return GNUNET_OK; +} + + +/** + * Function called with details about coins that were refunding, + * with the goal of auditing the refund's execution. + * + * @param cls closure + * @param rowid unique serial ID for the refund in our DB + * @param coin_pub public key of the coin + * @param merchant_pub public key of the merchant + * @param merchant_sig signature of the merchant + * @param h_contract hash of the contract between merchant and customer + * @param transaction_id original transaction ID chosen by the merchant + * @param rtransaction_id refund transaction ID chosen by the merchant + * @param amount_with_fee amount that was deposited including fee + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop + */ +int +audit_refund_cb (void *cls, + unsigned long long rowid, /* FIXME: decide data type for serial_id! */ + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_MerchantSignatureP *merchant_sig, + const struct GNUNET_HashCode *h_contract, + uint64_t transaction_id, + uint64_t rtransaction_id, + const struct TALER_Amount *amount_with_fee) +{ + auditor_row_cnt++; + return GNUNET_OK; +} + + +/** + * Function called with details about incoming wire transfers. + * + * @param cls closure + * @param rowid unique serial ID for the refresh session in our DB + * @param reserve_pub public key of the reserve (also the WTID) + * @param credit amount that was received + * @param sender_account_details information about the sender's bank account + * @param transfer_details information that uniquely identifies the wire transfer + * @param execution_date when did we receive the funds + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop + */ +int +audit_reserve_in_cb (void *cls, + unsigned long long rowid, /* FIXME: decide data type for serial_id! */ + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_Amount *credit, + const json_t *sender_account_details, + const json_t *transfer_details, + struct GNUNET_TIME_Absolute execution_date) +{ + auditor_row_cnt++; + return GNUNET_OK; +} + +/** + * Function called with details about withdraw operations. + * + * @param cls closure + * @param rowid unique serial ID for the refresh session in our DB + * @param h_blind_ev blinded hash of the coin's public key + * @param denom_pub public denomination key of the deposited coin + * @param denom_sig signature over the deposited coin + * @param reserve_pub public key of the reserve + * @param reserve_sig signature over the withdraw operation + * @param execution_date when did the wallet withdraw the coin + * @param amount_with_fee amount that was withdrawn + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop + */ +int +audit_reserve_out_cb (void *cls, + unsigned long long rowid, /* FIXME: decide data type for serial_id! */ + const struct GNUNET_HashCode *h_blind_ev, + const struct TALER_DenominationPublicKey *denom_pub, + const struct TALER_DenominationSignature *denom_sig, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ReserveSignatureP *reserve_sig, + struct GNUNET_TIME_Absolute execution_date, + const struct TALER_Amount *amount_with_fee) +{ + auditor_row_cnt++; + return GNUNET_OK; +} /** * Test garbage collection. @@ -1121,6 +1319,21 @@ run (void *cls) } } FAILIF (3 != cnt); + + auditor_row_cnt = 0; + FAILIF (GNUNET_OK != + plugin->select_reserves_in_above_serial_id (plugin->cls, + session, + 0, + &audit_reserve_in_cb, + NULL)); + FAILIF (GNUNET_OK != + plugin->select_reserves_out_above_serial_id (plugin->cls, + session, + 0, + &audit_reserve_out_cb, + NULL)); + FAILIF (3 != auditor_row_cnt); /* Tests for deposits */ memset (&deposit, 0, sizeof (deposit)); RND_BLK (&deposit.coin.coin_pub); @@ -1145,6 +1358,14 @@ run (void *cls) plugin->have_deposit (plugin->cls, session, &deposit)); + auditor_row_cnt = 0; + FAILIF (GNUNET_OK != + plugin->select_deposits_above_serial_id (plugin->cls, + session, + 0, + &audit_deposit_cb, + NULL)); + FAILIF (1 != auditor_row_cnt); result = 9; FAILIF (1 != plugin->iterate_matching_deposits (plugin->cls, @@ -1232,7 +1453,15 @@ run (void *cls) plugin->insert_refund (plugin->cls, session, &refund)); + auditor_row_cnt = 0; + FAILIF (GNUNET_OK != + plugin->select_refunds_above_serial_id (plugin->cls, + session, + 0, + &audit_refund_cb, + NULL)); + FAILIF (1 != auditor_row_cnt); tl = plugin->get_coin_transactions (plugin->cls, session, &refund.coin.coin_pub); diff --git a/src/include/taler_auditordb_plugin.h b/src/include/taler_auditordb_plugin.h index cc75fb014..c27295a08 100644 --- a/src/include/taler_auditordb_plugin.h +++ b/src/include/taler_auditordb_plugin.h @@ -29,6 +29,90 @@ /** + * Function called with the results of select_denomination_info() + * + * @param cls closure + * @param issue issuing information with value, fees and other info about the denomination. + * + * @return sets the return value of select_denomination_info(), + * #GNUNET_OK to continue, + * #GNUNET_NO to stop processing further rows + * #GNUNET_SYSERR or other values on error. + */ +typedef int +(*TALER_AUDITORDB_DenominationInfoDataCallback)(void *cls, + const struct TALER_DenominationKeyValidityPS *issue); + + +/** + * Function called with the results of select_historic_denom_revenue() + * + * @param cls closure + * @param denom_pub_hash hash of the denomination key + * @param revenue_timestamp when did this profit get realized + * @param revenue_balance what was the total profit made from + * deposit fees, melting fees, refresh fees + * and coins that were never returned? + * @param deposit_fee_balance total profits from deposit fees + * @param melt_fee_balance total profits from melting fees + * @param refund_fee_balance total profits from refund fees + * + * @return sets the return value of select_denomination_info(), + * #GNUNET_OK to continue, + * #GNUNET_NO to stop processing further rows + * #GNUNET_SYSERR or other values on error. + */ +typedef int +(*TALER_AUDITORDB_HistoricDenominationRevenueDataCallback)(void *cls, + const struct GNUNET_HashCode *denom_pub_hash, + struct GNUNET_TIME_Absolute revenue_timestamp, + const struct TALER_Amount *revenue_balance, + const struct TALER_Amount *deposit_fee_balance, + const struct TALER_Amount *melt_fee_balance, + const struct TALER_Amount *refund_fee_balance); + + +/** + * Function called with the results of select_historic_losses() + * + * @param cls closure + * @param denom_pub_hash hash of the denomination key + * @param loss_timestamp when did this profit get realized + * @param loss_balance what was the total loss + * + * @return sets the return value of select_denomination_info(), + * #GNUNET_OK to continue, + * #GNUNET_NO to stop processing further rows + * #GNUNET_SYSERR or other values on error. + */ +typedef int +(*TALER_AUDITORDB_HistoricLossesDataCallback)(void *cls, + const struct GNUNET_HashCode *denom_pub_hash, + struct GNUNET_TIME_Absolute loss_timestamp, + const struct TALER_Amount *loss_balance); + + +/** + * Function called with the results of select_historic_reserve_revenue() + * + * @param cls closure + * @param start_time beginning of aggregated time interval + * @param end_time end of aggregated time interval + * @param reserve_profits total profits made + * + * @return sets the return value of select_denomination_info(), + * #GNUNET_OK to continue, + * #GNUNET_NO to stop processing further rows + * #GNUNET_SYSERR or other values on error. + */ +typedef int +(*TALER_AUDITORDB_HistoricReserveRevenueDataCallback)(void *cls, + struct GNUNET_TIME_Absolute start_time, + struct GNUNET_TIME_Absolute end_time, + const struct TALER_Amount *reserve_profits); + + +/** * Handle for one session with the database. */ struct TALER_AUDITORDB_Session; @@ -164,11 +248,89 @@ struct TALER_AUDITORDB_Plugin (*select_denomination_info)(void *cls, struct TALER_AUDITORDB_Session *session, const struct TALER_MasterPublicKeyP *master_pub, - void *cb, /* FIXME: type! */ + TALER_AUDITORDB_DenominationInfoDataCallback cb, void *cb_cls); /** + * Insert information about the auditor's progress with an exchange's + * data. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @param master_pub master key of the exchange + * @param last_reserve_in_serial_id serial ID of the last reserve_in transfer the auditor processed + * @param last_reserve_out_serial_id serial ID of the last withdraw the auditor processed + * @param last_deposit_serial_id serial ID of the last deposit the auditor processed + * @param last_melt_serial_id serial ID of the last refresh the auditor processed + * @param last_prewire_serial_id serial ID of the last prewire transfer the auditor processed + * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure + */ + int + (*insert_auditor_progress)(void *cls, + struct TALER_AUDITORDB_Session *session, + const struct TALER_MasterPublicKeyP *master_pub, + uint64_t last_reserve_in_serial_id, + uint64_t last_reserve_out_serial_id, + uint64_t last_deposit_serial_id, + uint64_t last_melt_serial_id, + uint64_t last_refund_serial_id, + uint64_t last_prewire_serial_id); + + + /** + * Update information about the progress of the auditor. There + * must be an existing record for the exchange. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @param master_pub master key of the exchange + * @param last_reserve_in_serial_id serial ID of the last reserve_in transfer the auditor processed + * @param last_reserve_out_serial_id serial ID of the last withdraw the auditor processed + * @param last_deposit_serial_id serial ID of the last deposit the auditor processed + * @param last_melt_serial_id serial ID of the last refresh the auditor processed + * @param last_prewire_serial_id serial ID of the last prewire transfer the auditor processed + * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure + */ + int + (*update_auditor_progress)(void *cls, + struct TALER_AUDITORDB_Session *session, + const struct TALER_MasterPublicKeyP *master_pub, + uint64_t last_reserve_in_serial_id, + uint64_t last_reserve_out_serial_id, + uint64_t last_deposit_serial_id, + uint64_t last_melt_serial_id, + uint64_t last_refund_serial_id, + uint64_t last_prewire_serial_id); + + + /** + * Get information about the progress of the auditor. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @param master_pub master key of the exchange + * @param[out] last_reserve_in_serial_id serial ID of the last reserve_in transfer the auditor processed + * @param[out] last_reserve_out_serial_id serial ID of the last withdraw the auditor processed + * @param[out] last_deposit_serial_id serial ID of the last deposit the auditor processed + * @param[out] last_melt_serial_id serial ID of the last refresh the auditor processed + * @param[out] last_prewire_serial_id serial ID of the last prewire transfer the auditor processed + * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure; + * #GNUNET_NO if we have no records for the @a master_pub + */ + int + (*get_auditor_progress)(void *cls, + struct TALER_AUDITORDB_Session *session, + const struct TALER_MasterPublicKeyP *master_pub, + uint64_t *last_reserve_in_serial_id, + uint64_t *last_reserve_out_serial_id, + uint64_t *last_deposit_serial_id, + uint64_t *last_melt_serial_id, + uint64_t *last_refund_serial_id, + uint64_t *last_prewire_serial_id); + + + /** * Insert information about a reserve. There must not be an * existing record for the reserve. * @@ -586,7 +748,7 @@ struct TALER_AUDITORDB_Plugin (*select_historic_denom_revenue)(void *cls, struct TALER_AUDITORDB_Session *session, const struct TALER_MasterPublicKeyP *master_pub, - void *cb, /* FIXME: fix type */ + TALER_AUDITORDB_HistoricDenominationRevenueDataCallback cb, void *cb_cls); @@ -628,7 +790,7 @@ struct TALER_AUDITORDB_Plugin (*select_historic_losses)(void *cls, struct TALER_AUDITORDB_Session *session, const struct TALER_MasterPublicKeyP *master_pub, - void *cb, /* FIXME: fix type */ + TALER_AUDITORDB_HistoricLossesDataCallback cb, void *cb_cls); @@ -666,7 +828,7 @@ struct TALER_AUDITORDB_Plugin (*select_historic_reserve_revenue)(void *cls, struct TALER_AUDITORDB_Session *session, const struct TALER_MasterPublicKeyP *master_pub, - void *cb, /* FIXME: type */ + TALER_AUDITORDB_HistoricReserveRevenueDataCallback cb, void *cb_cls); @@ -721,6 +883,7 @@ struct TALER_AUDITORDB_Plugin const struct TALER_MasterPublicKeyP *master_pub, struct TALER_Amount *balance); + }; diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h index bbb300440..6da76a122 100644 --- a/src/include/taler_error_codes.h +++ b/src/include/taler_error_codes.h @@ -33,12 +33,1097 @@ enum TALER_ErrorCode { /** - * Special code to indicate no error. + * Special code to indicate no error (or no "code" present). */ - TALER_EC_NONE = 0 + TALER_EC_NONE = 0, + /** + * Special code to indicate that a non-integer error code was + * returned in the JSON response. + */ + TALER_EC_INVALID = 1, + + /** + * The response we got from the server was not even in JSON format. + */ + TALER_EC_INVALID_RESPONSE = 2, + + + /* ********** generic error codes ************* */ + + /** + * The exchange failed to even just initialize its connection to the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DB_SETUP_FAILED = 1001, + + /** + * The exchange encountered an error event to just start + * the database transaction. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DB_START_FAILED = 1002, + + /** + * The exchange encountered an error event to commit + * the database transaction (hard, unrecoverable error). + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DB_COMMIT_FAILED_HARD = 1003, + + /** + * The exchange encountered an error event to commit + * the database transaction, even after repeatedly + * retrying it there was always a conflicting transaction. + * (This indicates a repeated serialization error; should + * only happen if some client maliciously tries to create + * conflicting concurrent transactions.) + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DB_COMMIT_FAILED_ON_RETRY = 1004, + /** + * The exchange had insufficient memory to parse the request. This + * response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_PARSER_OUT_OF_MEMORY = 1005, + + /** + * The JSON in the client's request to the exchange was malformed. + * (Generic parse error). + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_JSON_INVALID = 1006, + + /** + * The JSON in the client's request to the exchange was malformed. + * Details about the location of the parse error are provided. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_JSON_INVALID_WITH_DETAILS = 1007, + + /** + * A required parameter in the request to the exchange was missing. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PARAMETER_MISSING = 1008, + + /** + * A parameter in the request to the exchange was malformed. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PARAMETER_MALFORMED = 1009, + + /* ********** request-specific error codes ************* */ + + /** + * The given reserve does not have sufficient funds to admit the + * requested withdraw operation at this time. The response includes + * the current "balance" of the reserve as well as the transaction + * "history" that lead to this balance. This response is provided + * with HTTP status code MHD_HTTP_FORBIDDEN. + */ + TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS = 1100, + + /** + * The exchange has no information about the "reserve_pub" that + * was given. + * This response is provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_WITHDRAW_RESERVE_UNKNOWN = 1101, + + /** + * The amount to withdraw together with the fee exceeds the + * numeric range for Taler amounts. This is not a client + * failure, as the coin value and fees come from the exchange's + * configuration. + * This response is provided with HTTP status code MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_AMOUNT_FEE_OVERFLOW = 1102, + + /** + * All of the deposited amounts into this reserve total up to a + * value that is too big for the numeric range for Taler amounts. + * This is not a client failure, as the transaction history comes + * from the exchange's configuration. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_AMOUNT_DEPOSITS_OVERFLOW = 1103, + + /** + * For one of the historic withdrawals from this reserve, the + * exchange could not find the denomination key. + * This is not a client failure, as the transaction history comes + * from the exchange's configuration. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_HISTORIC_DENOMINATION_KEY_NOT_FOUND = 1104, + + /** + * All of the withdrawals from reserve total up to a + * value that is too big for the numeric range for Taler amounts. + * This is not a client failure, as the transaction history comes + * from the exchange's configuration. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_AMOUNT_WITHDRAWALS_OVERFLOW = 1105, + + /** + * The exchange somehow knows about this reserve, but there seem to + * have been no wire transfers made. This is not a client failure, + * as this is a database consistency issue of the exchange. This + * response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_RESERVE_WITHOUT_WIRE_TRANSFER = 1106, + + /** + * The exchange failed to create the signature using the + * denomination key. This response is provided with HTTP status + * code MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_SIGNATURE_FAILED = 1107, + + /** + * The exchange failed to store the withdraw operation in its + * database. This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_DB_STORE_ERROR = 1108, + + /** + * The exchange failed to check against historic withdraw data from + * database (as part of ensuring the idempotency of the operation). + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_DB_FETCH_ERROR = 1109, + + /** + * The exchange is not aware of the denomination key + * the wallet requested for the withdrawal. + * This response is provided + * with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_WITHDRAW_DENOMINATION_KEY_NOT_FOUND = 1110, + + /** + * The signature of the reserve is not valid. This response is + * provided with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_WITHDRAW_RESERVE_SIGNATURE_INVALID = 1111, + + /** + * The exchange failed to obtain the transaction history of the + * given reserve from the database while generating an insufficient + * funds errors. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1112, + + /** + * The exchange failed to obtain the transaction history of the + * given reserve from the database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_RESERVE_STATUS_DB_ERROR = 1150, + + + /** + * The respective coin did not have sufficient residual value + * for the /deposit operation (i.e. due to double spending). + * The "history" in the respose provides the transaction history + * of the coin proving this fact. This response is provided + * with HTTP status code MHD_HTTP_FORBIDDEN. + */ + TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS = 1200, + + /** + * The exchange failed to obtain the transaction history of the + * given coin from the database (this does not happen merely because + * the coin is seen by the exchange for the first time). + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DEPOSIT_HISTORY_DB_ERROR = 1201, + + /** + * The exchange failed to store the /depost information in the + * database. This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DEPOSIT_STORE_DB_ERROR = 1202, + + /** + * The exchange database is unaware of the denomination key that + * signed the coin (however, the exchange process is; this is not + * supposed to happen; it can happen if someone decides to purge the + * DB behind the back of the exchange process). Hence the deposit + * is being refused. This response is provided with HTTP status + * code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DEPOSIT_DB_DENOMINATION_KEY_UNKNOWN = 1203, + + /** + * The exchange database is unaware of the denomination key that + * signed the coin (however, the exchange process is; this is not + * supposed to happen; it can happen if someone decides to purge the + * DB behind the back of the exchange process). Hence the deposit + * is being refused. This response is provided with HTTP status + * code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_DEPOSIT_DENOMINATION_KEY_UNKNOWN = 1204, + + /** + * The signature of the coin is not valid. This response is + * provided with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID = 1205, + + /** + * The signature of the denomination key over the coin is not valid. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_DENOMINATION_SIGNATURE_INVALID = 1206, + + /** + * The stated value of the coin after the deposit fee is subtracted + * would be negative. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE = 1207, + + /** + * The stated refund deadline is after the wire deadline. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE = 1208, + + /** + * The exchange does not recognize the validity of or support the + * given wire (bank account) address. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT = 1209, + + /** + * The exchange failed to canonicalize and hash the given wire format. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON = 1210, + + /** + * The hash of the given wire address does not match the hash + * specified in the contract. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT = 1211, + + /** + * The exchange failed to obtain the transaction history of the + * given coin from the database while generating an insufficient + * funds errors. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DEPOSIT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1212, + + /** + * The respective coin did not have sufficient residual value + * for the /refresh/melt operation. The "history" in this + * response provdes the "residual_value" of the coin, which may + * be less than its "original_value". This response is provided + * with HTTP status code MHD_HTTP_FORBIDDEN. + */ + TALER_EC_REFRESH_MELT_INSUFFICIENT_FUNDS = 1300, + + /** + * The exchange is unaware of the denomination key that was + * used to sign the melted coin. This response is provided + * with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND = 1301, + + /** + * The exchange had an internal error reconstructing the + * transaction history of the coin that was being melted. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFRESH_MELT_COIN_HISTORY_COMPUTATION_FAILED = 1302, + + /** + * The exchange failed to check against historic melt data from + * database (as part of ensuring the idempotency of the operation). + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_MELT_DB_FETCH_ERROR = 1303, + + /** + * The exchange failed to store session data in the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_MELT_DB_STORE_SESSION_ERROR = 1304, + + /** + * The exchange failed to store refresh order data in the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_MELT_DB_STORE_ORDER_ERROR = 1305, + + /** + * The exchange failed to store commit data in the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_MELT_DB_STORE_COMMIT_ERROR = 1306, + + /** + * The exchange failed to store transfer keys in the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_MELT_DB_STORE_TRANSFER_ERROR = 1307, + + /** + * The exchange is unaware of the denomination key that was + * requested for one of the fresh coins. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_FRESH_DENOMINATION_KEY_NOT_FOUND = 1308, + + /** + * The exchange encountered a numeric overflow totaling up + * the cost for the refresh operation. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFRESH_MELT_COST_CALCULATION_OVERFLOW = 1309, + + /** + * During the transaction phase, the exchange could suddenly + * no longer find the denomination key that was + * used to sign the melted coin. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFRESH_MELT_DB_DENOMINATION_KEY_NOT_FOUND = 1310, + + /** + * The exchange encountered melt fees exceeding the melted + * coin's contribution. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION = 1311, + + /** + * The exchange's cost calculation does not add up to the + * melt fees specified in the request. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_FEES_MISSMATCH = 1312, + + /** + * The denomination key signature on the melted coin is invalid. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID = 1313, + + /** + * The exchange's cost calculation shows that the melt amount + * is below the costs of the transaction. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_AMOUNT_INSUFFICIENT = 1314, + + /** + * The signature made with the coin to be melted is invalid. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_COIN_SIGNATURE_INVALID = 1315, + + /** + * The size of the cut-and-choose dimension of the + * blinded coins request does not match #TALER_CNC_KAPPA. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_CNC_COIN_ARRAY_SIZE_INVALID = 1316, + + /** + * The size of the cut-and-choose dimension of the + * transfer keys request does not match #TALER_CNC_KAPPA. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_CNC_TRANSFER_ARRAY_SIZE_INVALID = 1317, + + /** + * The exchange failed to obtain the transaction history of the + * given coin from the database while generating an insufficient + * funds errors. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFRESH_MELT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1318, + + /** + * The provided transfer keys do not match up with the + * original commitment. Information about the original + * commitment is included in the response. This response is + * provided with HTTP status code MHD_HTTP_CONFLICT. + */ + TALER_EC_REFRESH_REVEAL_COMMITMENT_VIOLATION = 1350, + + /** + * Failed to blind the envelope to reconstruct the blinded + * coins for revealation checks. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_REVEAL_BLINDING_ERROR = 1351, + + /** + * Failed to produce the blinded signatures over the coins + * to be returned. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_REVEAL_SIGNING_ERROR = 1352, + + /** + * The exchange is unaware of the refresh sessino specified in + * the request. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN = 1353, + + /** + * The exchange failed to retrieve valid session data from the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR = 1354, + + /** + * The exchange failed to retrieve order data from the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR = 1355, + + /** + * The exchange failed to retrieve transfer keys from the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_REVEAL_DB_FETCH_TRANSFER_ERROR = 1356, + + /** + * The exchange failed to retrieve commitment data from the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_REVEAL_DB_FETCH_COMMIT_ERROR = 1357, + + /** + * The size of the cut-and-choose dimension of the + * private transfer keys request does not match #TALER_CNC_KAPPA - 1. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID = 1358, + + + /** + * The coin specified in the link request is unknown to the exchange. + * This response is provided with HTTP status code + * MHD_HTTP_NOT_FOUND. + */ + TALER_EC_REFRESH_LINK_COIN_UNKNOWN = 1400, + + + /** + * The exchange knows literally nothing about the coin we were asked + * to refund. But without a transaction history, we cannot issue a + * refund. This is kind-of OK, the owner should just refresh it + * directly without executing the refund. This response is provided + * with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_REFUND_COIN_NOT_FOUND = 1500, + + /** + * We could not process the refund request as the coin's transaction + * history does not permit the requested refund at this time. The + * "history" in the response proves this. This response is provided + * with HTTP status code MHD_HTTP_CONFLICT. + */ + TALER_EC_REFUND_CONFLICT = 1501, + + /** + * The exchange knows about the coin we were asked to refund, but + * not about the specific /deposit operation. Hence, we cannot + * issue a refund (as we do not know if this merchant public key is + * authorized to do a refund). This response is provided with HTTP + * status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_REFUND_DEPOSIT_NOT_FOUND = 1503, + + /** + * The currency specified for the refund is different from + * the currency of the coin. This response is provided with HTTP + * status code MHD_HTTP_PRECONDITION_FAILED. + */ + TALER_EC_REFUND_CURRENCY_MISSMATCH = 1504, + + /** + * When we tried to check if we already paid out the coin, the + * exchange's database suddenly disagreed with data it previously + * provided (internal inconsistency). + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFUND_DB_INCONSISTENT = 1505, + /** + * The exchange can no longer refund the customer/coin as the + * money was already transferred (paid out) to the merchant. + * (It should be past the refund deadline.) + * This response is provided with HTTP status code + * MHD_HTTP_GONE. + */ + TALER_EC_REFUND_MERCHANT_ALREADY_PAID = 1506, + + /** + * The amount the exchange was asked to refund exceeds + * (with fees) the total amount of the deposit (including fees). + * This response is provided with HTTP status code + * MHD_HTTP_PRECONDITION_FAILED. + */ + TALER_EC_REFUND_INSUFFICIENT_FUNDS = 1507, + + /** + * The exchange failed to recover information about the + * denomination key of the refunded coin (even though it + * recognizes the key). Hence it could not check the fee + * strucutre. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFUND_DENOMINATION_KEY_NOT_FOUND = 1508, + + /** + * The refund fee specified for the request is lower than + * the refund fee charged by the exchange for the given + * denomination key of the refunded coin. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFUND_FEE_TOO_LOW = 1509, + + /** + * The exchange failed to store the refund information to + * its database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFUND_STORE_DB_ERROR = 1510, + + /** + * The refund fee is specified in a different currency + * than the refund amount. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH = 1511, + + /** + * The refunded amount is smaller than the refund fee, + * which would result in a negative refund. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFUND_FEE_ABOVE_AMOUNT = 1512, + + /** + * The signature of the merchant is invalid. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFUND_MERCHANT_SIGNATURE_INVALID = 1513, + + + /** + * The wire format specified in the "sender_account_details" + * is not understood or not supported by this exchange. + * Returned with an HTTP status code of MHD_HTTP_NOT_FOUND. + * (As we did not find an interpretation of the wire format.) + */ + TALER_EC_ADMIN_ADD_INCOMING_WIREFORMAT_UNSUPPORTED = 1600, + + /** + * The currency specified in the "amount" parameter is not + * supported by this exhange. Returned with an HTTP status + * code of MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_ADMIN_ADD_INCOMING_CURRENCY_UNSUPPORTED = 1601, + + /** + * The exchange failed to store information about the incoming + * transfer in its database. This response is provided with HTTP + * status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_ADMIN_ADD_INCOMING_DB_STORE = 1602, + + /** + * The exchange encountered an error (that is not about not finding + * the wire transfer) trying to lookup a wire transfer identifier + * in the database. This response is provided with HTTP + * status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_DB_FETCH_FAILED = 1700, + + /** + * The exchange found internally inconsistent data when resolving a + * wire transfer identifier in the database. This response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_DB_INCONSISTENT = 1701, + + /** + * The exchange did not find information about the specified + * wire transfer identifier in the database. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_TRACK_TRANSFER_WTID_NOT_FOUND = 1702, + + + /** + * The exchange found internally inconsistent fee data when + * resolving a transaction in the database. This + * response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSACTION_DB_FEE_INCONSISTENT = 1800, + + /** + * The exchange encountered an error (that is not about not finding + * the transaction) trying to lookup a transaction + * in the database. This response is provided with HTTP + * status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSACTION_DB_FETCH_FAILED = 1801, + + /** + * The exchange did not find information about the specified + * transaction in the database. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_TRACK_TRANSACTION_NOT_FOUND = 1802, + + /** + * The exchange failed to identify the wire transfer of the + * transaction (or information about the plan that it was supposed + * to still happen in the future). This response is provided with + * HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSACTION_WTID_RESOLUTION_ERROR = 1803, + + /** + * The signature of the merchant is invalid. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_TRACK_TRANSACTION_MERCHANT_SIGNATURE_INVALID = 1804, + + + /* *********** Merchant backend error codes ********* */ + + /** + * The backend could not find the merchant instance specified + * in the request. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_CONTRACT_INSTANCE_UNKNOWN = 2000, + + /** + * The exchange failed to provide a meaningful response + * to a /deposit request. This response is provided + * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE. + */ + TALER_EC_PAY_EXCHANGE_FAILED = 2101, + + /** + * The merchant failed to commit the exchanges' response to + * a /deposit request to its database. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_PAY_DB_STORE_PAY_ERROR = 2102, + + /** + * The specified exchange is not supported/trusted by + * this merchant. This response is provided + * with HTTP status code MHD_HTTP_PRECONDITION_FAILED. + */ + TALER_EC_PAY_EXCHANGE_REJECTED = 2103, + + /** + * The denomination key used for payment is not listed among the + * denomination keys of the exchange. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_DENOMINATION_KEY_NOT_FOUND = 2104, + + /** + * The denomination key used for payment is not audited by an + * auditor approved by the merchant. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_DENOMINATION_KEY_AUDITOR_FAILURE = 2105, + + /** + * There was an integer overflow totaling up the amounts or + * deposit fees in the payment. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_AMOUNT_OVERFLOW = 2106, + + /** + * The deposit fees exceed the total value of the payment. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_FEES_EXCEED_PAYMENT = 2107, + + /** + * After considering deposit fees, the payment is insufficient + * to satisfy the required amount for the contract. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_PAYMENT_INSUFFICIENT_DUE_TO_FEES = 2108, + + /** + * While the merchant is happy to cover all applicable deposit fees, + * the payment is insufficient to satisfy the required amount for + * the contract. This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_PAYMENT_INSUFFICIENT = 2109, + + /** + * The signature over the contract of one of the coins + * was invalid. This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_COIN_SIGNATURE_INVALID = 2110, + + /** + * We failed to contact the exchange for the /pay request. + * This response is provided + * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE. + */ + TALER_EC_PAY_EXCHANGE_TIMEOUT = 2111, + + /** + * The backend could not find the merchant instance specified + * in the request. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_PAY_INSTANCE_UNKNOWN = 2112, + + /** + * The signature over the contract of the merchant + * was invalid. This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_MERCHANT_SIGNATURE_INVALID = 2113, + + /** + * The refund deadline was after the transfer deadline. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE = 2114, + + /** + * The request fails to provide coins for the payment. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_COINS_ARRAY_EMPTY = 2115, + + /** + * The merchant failed to fetch the merchant's previous state with + * respect to a /pay request from its database. This response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_PAY_DB_FETCH_PAY_ERROR = 2116, + + /** + * The merchant failed to fetch the merchant's previous state with + * respect to transactions from its database. This response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR = 2117, + + /** + * The transaction ID was used for a conflicing transaction before. + * This response is + * provided with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_DB_TRANSACTION_ID_CONFLICT = 2118, + + /** + * The merchant failed to store the merchant's state with + * respect to the transaction in its database. This response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_PAY_DB_STORE_TRANSACTION_ERROR = 2119, + + /** + * The exchange failed to provide a valid response to + * the merchant's /keys request. + * This response is provided + * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE. + */ + TALER_EC_PAY_EXCHANGE_KEYS_FAILURE = 2120, + + /** + * The payment is too late, the offer has expired. + * This response is + * provided with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_OFFER_EXPIRED = 2121, + + + /** + * Integer overflow with sepcified timestamp argument detected. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_HISTORY_TIMESTAMP_OVERFLOW = 2200, + + /** + * Failed to retrieve history from merchant database. + * This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_HISTORY_DB_FETCH_ERROR = 2201, + + + /** + * We failed to contact the exchange for the /track/transaction + * request. This response is provided with HTTP status code + * MHD_HTTP_SERVICE_UNAVAILABLE. + */ + TALER_EC_TRACK_TRANSACTION_EXCHANGE_TIMEOUT = 2300, + + /** + * The backend could not find the merchant instance specified + * in the request. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_TRACK_TRANSACTION_INSTANCE_UNKNOWN = 2301, + + /** + * The backend could not find the transaction specified + * in the request. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_TRACK_TRANSACTION_TRANSACTION_UNKNOWN = 2302, + + /** + * The backend had a database access error trying to + * retrieve transaction data from its database. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSACTION_DB_FETCH_TRANSACTION_ERROR = 2303, + + /** + * The backend had a database access error trying to + * retrieve payment data from its database. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSACTION_DB_FETCH_PAYMENT_ERROR = 2304, + + /** + * The backend found no applicable deposits in the database. + * This is odd, as we know about the transaction, but not + * about deposits we made for the transaction. The response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_TRACK_TRANSACTION_DB_NO_DEPOSITS_ERROR = 2305, + + /** + * We failed to obtain a wire transfer identifier for one + * of the coins in the transaction. The response is + * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY if + * the exchange had a hard error, or MHD_HTTP_ACCEPTED if the + * exchange signaled that the transfer was in progress. + */ + TALER_EC_TRACK_TRANSACTION_COIN_TRACE_ERROR = 2306, + + /** + * We failed to obtain the full wire transfer identifier for the + * transfer one of the coins was aggregated into. + * The response is + * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY. + */ + TALER_EC_TRACK_TRANSACTION_WIRE_TRANSFER_TRACE_ERROR = 2307, + + /** + * We got conflicting reports from the exhange with + * respect to which transfers are included in which + * aggregate. + * The response is + * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY. + */ + TALER_EC_TRACK_TRANSACTION_CONFLICTING_REPORTS = 2308, + + + /** + * We failed to contact the exchange for the /track/transfer + * request. This response is provided with HTTP status code + * MHD_HTTP_SERVICE_UNAVAILABLE. + */ + TALER_EC_TRACK_TRANSFER_EXCHANGE_TIMEOUT = 2400, + + /** + * The backend could not find the merchant instance specified + * in the request. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_TRACK_TRANSFER_INSTANCE_UNKNOWN = 2401, + + /** + * We failed to persist coin wire transfer information in + * our merchant database. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_DB_STORE_COIN_ERROR = 2402, + + /** + * We internally failed to execute the /track/transfer request. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_REQUEST_ERROR = 2403, + + /** + * We failed to persist wire transfer information in + * our merchant database. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_DB_STORE_TRANSFER_ERROR = 2404, + + /** + * The exchange returned an error from /track/transfer. + * The response is + * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY. + */ + TALER_EC_TRACK_TRANSFER_EXCHANGE_ERROR = 2405, + + /** + * We failed to fetch deposit information from + * our merchant database. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_DB_FETCH_DEPOSIT_ERROR = 2406, + + /** + * We encountered an internal logic error. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_DB_INTERNAL_LOGIC_ERROR = 2407, + + /** + * The exchange gave conflicting information about a coin which has + * been wire transferred. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_CONFLICTING_REPORTS = 2408, + + /* ********** /test API error codes ************* */ + + /** + * The exchange failed to compute ECDH. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TEST_ECDH_ERROR = 4000, + + /** + * The EdDSA test signature is invalid. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_TEST_EDDSA_INVALID = 4001, + + /** + * The exchange failed to compute the EdDSA test signature. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TEST_EDDSA_ERROR = 4002, + + /** + * The exchange failed to generate an RSA key. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TEST_RSA_GEN_ERROR = 4003, + + /** + * The exchange failed to compute the public RSA key. This response + * is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TEST_RSA_PUB_ERROR = 4004, + + /** + * The exchange failed to compute the RSA signature. This response + * is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TEST_RSA_SIGN_ERROR = 4005, + + + /** + * End of error code range. + */ + TALER_EC_END = 9999 + }; diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 9e3c48c4c..e368f954c 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -24,6 +24,7 @@ #include <jansson.h> #include "taler_util.h" +#include "taler_error_codes.h" #include <gnunet/gnunet_curl_lib.h> @@ -355,6 +356,7 @@ struct TALER_EXCHANGE_WireHandle; * @param cls closure * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request; * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param obj the received JSON reply, if successful this should be the wire * format details as provided by /wire, or NULL if the * reply was not in JSON format. @@ -362,6 +364,7 @@ struct TALER_EXCHANGE_WireHandle; typedef void (*TALER_EXCHANGE_WireResultCallback) (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const json_t *obj); @@ -423,6 +426,7 @@ struct TALER_EXCHANGE_DepositHandle; typedef void (*TALER_EXCHANGE_DepositResultCallback) (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const struct TALER_ExchangePublicKeyP *sign_key, const json_t *obj); @@ -504,6 +508,7 @@ struct TALER_EXCHANGE_RefundHandle; * @param cls closure * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param sign_key exchange key used to sign @a obj, or NULL * @param obj the received JSON reply, should be kept as proof (and, in particular, * be forwarded to the customer) @@ -511,6 +516,7 @@ struct TALER_EXCHANGE_RefundHandle; typedef void (*TALER_EXCHANGE_RefundResultCallback) (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const struct TALER_ExchangePublicKeyP *sign_key, const json_t *obj); @@ -650,6 +656,7 @@ struct TALER_EXCHANGE_ReserveHistory * @param cls closure * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param[in] json original response in JSON format (useful only for diagnostics) * @param balance current balance in the reserve, NULL on error * @param history_length number of entries in the transaction history, 0 on error @@ -658,6 +665,7 @@ struct TALER_EXCHANGE_ReserveHistory typedef void (*TALER_EXCHANGE_ReserveStatusResultCallback) (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const json_t *json, const struct TALER_Amount *balance, unsigned int history_length, @@ -713,12 +721,14 @@ struct TALER_EXCHANGE_ReserveWithdrawHandle; * @param cls closure * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param sig signature over the coin, NULL on error * @param full_response full response from the exchange (for logging, in case of errors) */ typedef void (*TALER_EXCHANGE_ReserveWithdrawResultCallback) (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const struct TALER_DenominationSignature *sig, const json_t *full_response); @@ -835,6 +845,7 @@ struct TALER_EXCHANGE_RefreshMeltHandle; * @param cls closure * @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped. * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param noreveal_index choice by the exchange in the cut-and-choose protocol, * UINT16_MAX on error * @param sign_key exchange key used to sign @a full_response, or NULL @@ -843,7 +854,8 @@ struct TALER_EXCHANGE_RefreshMeltHandle; typedef void (*TALER_EXCHANGE_RefreshMeltCallback) (void *cls, unsigned int http_status, - uint16_t noreveal_index, + enum TALER_ErrorCode ec, + uint16_t noreveal_index, const struct TALER_ExchangePublicKeyP *sign_key, const json_t *full_response); @@ -900,6 +912,7 @@ TALER_EXCHANGE_refresh_melt_cancel (struct TALER_EXCHANGE_RefreshMeltHandle *rmh * @param cls closure * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error * @param sigs array of signature over @a num_coins coins, NULL on error @@ -908,6 +921,7 @@ TALER_EXCHANGE_refresh_melt_cancel (struct TALER_EXCHANGE_RefreshMeltHandle *rmh typedef void (*TALER_EXCHANGE_RefreshRevealCallback) (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, unsigned int num_coins, const struct TALER_CoinSpendPrivateKeyP *coin_privs, const struct TALER_DenominationSignature *sigs, @@ -979,6 +993,7 @@ struct TALER_EXCHANGE_RefreshLinkHandle; * @param cls closure * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error * @param sigs array of signature over @a num_coins coins, NULL on error @@ -988,6 +1003,7 @@ struct TALER_EXCHANGE_RefreshLinkHandle; typedef void (*TALER_EXCHANGE_RefreshLinkCallback) (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, unsigned int num_coins, const struct TALER_CoinSpendPrivateKeyP *coin_privs, const struct TALER_DenominationSignature *sigs, @@ -1043,11 +1059,13 @@ struct TALER_EXCHANGE_AdminAddIncomingHandle; * @param cls closure * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param full_response full response from the exchange (for logging, in case of errors) */ typedef void (*TALER_EXCHANGE_AdminAddIncomingResultCallback) (void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const json_t *full_response); @@ -1108,6 +1126,7 @@ struct TALER_EXCHANGE_TrackTransferHandle; * * @param cls closure * @param http_status HTTP status code we got, 0 on exchange protocol violation + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param sign_key exchange key used to sign @a json, or NULL * @param json original json reply (may include signatures, those have then been * validated already) @@ -1121,6 +1140,7 @@ struct TALER_EXCHANGE_TrackTransferHandle; typedef void (*TALER_EXCHANGE_TrackTransferCallback)(void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const struct TALER_ExchangePublicKeyP *sign_key, const json_t *json, const struct GNUNET_HashCode *h_wire, @@ -1171,6 +1191,7 @@ struct TALER_EXCHANGE_TrackTransactionHandle; * * @param cls closure * @param http_status HTTP status code we got, 0 on exchange protocol violation + * @param ec taler-specific error code, #TALER_EC_NONE on success * @param sign_key exchange key used to sign @a json, or NULL * @param json original json reply (may include signatures, those have then been * validated already) @@ -1182,6 +1203,7 @@ struct TALER_EXCHANGE_TrackTransactionHandle; typedef void (*TALER_EXCHANGE_TrackTransactionCallback)(void *cls, unsigned int http_status, + enum TALER_ErrorCode ec, const struct TALER_ExchangePublicKeyP *sign_key, const json_t *json, const struct TALER_WireTransferIdentifierRawP *wtid, @@ -1240,4 +1262,5 @@ TALER_EXCHANGE_verify_coin_history (const char *currency, json_t *history, struct TALER_Amount *total); + #endif /* _TALER_EXCHANGE_SERVICE_H */ diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h index b47aea5b6..b247ba1f5 100644 --- a/src/include/taler_json_lib.h +++ b/src/include/taler_json_lib.h @@ -25,6 +25,7 @@ #include <jansson.h> #include <gnunet/gnunet_json_lib.h> #include "taler_util.h" +#include "taler_error_codes.h" /** * Print JSON parsing related error information @@ -92,6 +93,17 @@ int TALER_JSON_hash (const json_t *json, struct GNUNET_HashCode *hc); +/** + * Extract the Taler error code from the given @a json object. + * Note that #TALER_EC_NONE is returned if no "code" is present. + * + * @param json response to extract the error code from + * @return the "code" value from @a json + */ +enum TALER_ErrorCode +TALER_JSON_get_error_code (const json_t *json); + + #endif /* TALER_JSON_LIB_H_ */ /* End of taler_json_lib.h */ diff --git a/src/include/taler_util.h b/src/include/taler_util.h index 613f860cd..c115594f5 100644 --- a/src/include/taler_util.h +++ b/src/include/taler_util.h @@ -117,4 +117,6 @@ const struct GNUNET_OS_ProjectData * TALER_project_data_default (void); + + #endif diff --git a/src/json/json.c b/src/json/json.c index 8f21447ec..74559e6c5 100644 --- a/src/json/json.c +++ b/src/json/json.c @@ -50,4 +50,33 @@ TALER_JSON_hash (const json_t *json, } + +/** + * Extract the Taler error code from the given @a json object. + * Note that #TALER_EC_NONE is returned if no "code" is present. + * + * @param json response to extract the error code from + * @return the "code" value from @a json + */ +enum TALER_ErrorCode +TALER_JSON_get_error_code (const json_t *json) +{ + const json_t *jc; + + if (NULL == json) + { + GNUNET_break_op (0); + return TALER_EC_INVALID_RESPONSE; + } + jc = json_object_get (json, "code"); + if (NULL == jc) + return TALER_EC_NONE; + if (json_is_integer (jc)) + return (enum TALER_ErrorCode) json_integer_value (jc); + GNUNET_break_op (0); + return TALER_EC_INVALID; +} + + + /* End of json/json.c */ |