diff options
| -rw-r--r-- | src/exchange/taler-exchange-httpd_reserves_status.c | 33 | ||||
| -rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 224 | ||||
| -rw-r--r-- | src/include/taler_exchangedb_plugin.h | 8 | 
3 files changed, 247 insertions, 18 deletions
| diff --git a/src/exchange/taler-exchange-httpd_reserves_status.c b/src/exchange/taler-exchange-httpd_reserves_status.c index 5b7becb9..ff8a65c2 100644 --- a/src/exchange/taler-exchange-httpd_reserves_status.c +++ b/src/exchange/taler-exchange-httpd_reserves_status.c @@ -59,6 +59,18 @@ struct ReserveStatusContext    struct TALER_EXCHANGEDB_KycStatus kyc;    /** +   * Sum of incoming transactions within the returned history. +   * (currently not used). +   */ +  struct TALER_Amount balance_in; + +  /** +   * Sum of outgoing transactions within the returned history. +   * (currently not used). +   */ +  struct TALER_Amount balance_out; + +  /**     * Current reserve balance.     */    struct TALER_Amount balance; @@ -135,10 +147,11 @@ reserve_status_transaction (void *cls,                                             "inselect_wallet_status");      return qs;    } -  qs = TEH_plugin->get_reserve_history (TEH_plugin->cls, -                                        rsc->reserve_pub, -                                        &rsc->balance, -                                        &rsc->rh); +  qs = TEH_plugin->get_reserve_status (TEH_plugin->cls, +                                       rsc->reserve_pub, +                                       &rsc->balance_in, +                                       &rsc->balance_out, +                                       &rsc->rh);    if (GNUNET_DB_STATUS_HARD_ERROR == qs)    {      GNUNET_break (0); @@ -148,6 +161,18 @@ reserve_status_transaction (void *cls,                                      TALER_EC_GENERIC_DB_FETCH_FAILED,                                      "get_reserve_status");    } +  qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls, +                                        rsc->reserve_pub, +                                        &rsc->balance); +  if (GNUNET_DB_STATUS_HARD_ERROR == qs) +  { +    GNUNET_break (0); +    *mhd_ret +      = TALER_MHD_reply_with_error (connection, +                                    MHD_HTTP_INTERNAL_SERVER_ERROR, +                                    TALER_EC_GENERIC_DB_FETCH_FAILED, +                                    "get_reserve_balance"); +  }    return qs;  } diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 63f07521..b9debfa4 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -815,6 +815,42 @@ prepare_statements (struct PostgresClosure *pg)        "  SELECT wire_source_h_payto FROM ri "        "); ",        1), +    /* Used in #postgres_get_reserve_status() to obtain inbound transactions +       for a reserve */ +    GNUNET_PQ_make_prepare ( +      "reserves_in_get_transactions_truncated", +      /* +      "SELECT" +      " wire_reference" +      ",credit_val" +      ",credit_frac" +      ",execution_date" +      ",payto_uri AS sender_account_details" +      " FROM reserves_in" +      " JOIN wire_targets" +      "   ON (wire_source_h_payto = wire_target_h_payto)" +      " WHERE reserve_pub=$1" +      "   AND execution_date>=$2;", +      */ +      "WITH ri AS MATERIALIZED ( " +      "  SELECT * " +      "  FROM reserves_in " +      "  WHERE reserve_pub = $1 " +      ") " +      "SELECT  " +      "  wire_reference " +      "  ,credit_val " +      "  ,credit_frac " +      "  ,execution_date " +      "  ,payto_uri AS sender_account_details " +      "FROM wire_targets " +      "JOIN ri  " +      "  ON (wire_target_h_payto = wire_source_h_payto) " +      "WHERE execution_date >= $2" +      "  AND wire_target_h_payto = ( " +      "  SELECT wire_source_h_payto FROM ri " +      "); ", +      2),      /* Used in #postgres_do_withdraw() to store         the signature of a blinded coin with the blinded coin's         details before returning it during /reserve/withdraw. We store @@ -1020,6 +1056,58 @@ prepare_statements (struct PostgresClosure *pg)        "JOIN denominations denom "        "  ON (ro.denominations_serial = denom.denominations_serial); ",        1), +    /* Used during #postgres_get_reserve_status() to +       obtain all of the /reserve/withdraw operations that +       have been performed on a given reserve. (i.e. to +       demonstrate double-spending) */ +    GNUNET_PQ_make_prepare ( +      "get_reserves_out_truncated", +      /* +      "SELECT" +      " ro.h_blind_ev" +      ",denom.denom_pub_hash" +      ",ro.denom_sig" +      ",ro.reserve_sig" +      ",ro.execution_date" +      ",ro.amount_with_fee_val" +      ",ro.amount_with_fee_frac" +      ",denom.fee_withdraw_val" +      ",denom.fee_withdraw_frac" +      " FROM reserves res" +      " JOIN reserves_out_by_reserve ror" +      "   ON (res.reserve_uuid = ror.reserve_uuid)" +      " JOIN reserves_out ro" +      "   ON (ro.h_blind_ev = ror.h_blind_ev)" +      " JOIN denominations denom" +      "   ON (ro.denominations_serial = denom.denominations_serial)" +      " WHERE res.reserve_pub=$1" +      "   AND execution_date>=$2;", +      */ +      "WITH robr AS MATERIALIZED ( " +      "  SELECT h_blind_ev " +      "  FROM reserves_out_by_reserve " +      "  WHERE reserve_uuid= ( " +      "    SELECT reserve_uuid " +      "    FROM reserves " +      "    WHERE reserve_pub = $1 " +      "  ) " +      ") SELECT " +      "  ro.h_blind_ev " +      "  ,denom.denom_pub_hash " +      "  ,ro.denom_sig " +      "  ,ro.reserve_sig " +      "  ,ro.execution_date " +      "  ,ro.amount_with_fee_val " +      "  ,ro.amount_with_fee_frac " +      "  ,denom.fee_withdraw_val " +      "  ,denom.fee_withdraw_frac " +      "FROM robr " +      "JOIN reserves_out ro " +      "  ON (ro.h_blind_ev = robr.h_blind_ev) " +      "JOIN denominations denom " +      "  ON (ro.denominations_serial = denom.denominations_serial)" +      " WHERE ro.execution_date>=$2;", +      2),      /* Used in #postgres_select_withdrawals_above_serial_id() */      GNUNET_PQ_make_prepare ( @@ -2240,6 +2328,51 @@ prepare_statements (struct PostgresClosure *pg)        "  JOIN exchange_do_recoup_by_reserve($1) robr"        " USING (denominations_serial);",        1), +    /* Used in #postgres_get_reserve_status() to obtain recoup transactions +       for a reserve - query optimization should be disabled i.e. +       BEGIN; SET LOCAL join_collapse_limit=1; query; COMMIT; */ +    GNUNET_PQ_make_prepare ( +      "recoup_by_reserve_truncated", +      /* +      "SELECT" +      " recoup.coin_pub" +      ",recoup.coin_sig" +      ",recoup.coin_blind" +      ",recoup.amount_val" +      ",recoup.amount_frac" +      ",recoup.recoup_timestamp" +      ",denominations.denom_pub_hash" +      ",known_coins.denom_sig" +      " FROM denominations" +      " JOIN (known_coins" +      "   JOIN recoup " +      "   ON (recoup.coin_pub = known_coins.coin_pub))" +      "  ON (known_coins.denominations_serial = denominations.denominations_serial)" +      " WHERE recoup_timestamp>=$2" +      " AND recoup.coin_pub" +      "  IN (SELECT coin_pub" +      "     FROM recoup_by_reserve" +      "     JOIN (reserves_out" +      "       JOIN (reserves_out_by_reserve" +      "         JOIN reserves" +      "           ON (reserves.reserve_uuid = reserves_out_by_reserve.reserve_uuid))" +      "       ON (reserves_out_by_reserve.h_blind_ev = reserves_out.h_blind_ev))" +      "     ON (recoup_by_reserve.reserve_out_serial_id = reserves_out.reserve_out_serial_id)" +      "     WHERE reserves.reserve_pub=$1);", +      */ +      "SELECT robr.coin_pub " +      "  ,robr.coin_sig " +      "  ,robr.coin_blind " +      "  ,robr.amount_val " +      "  ,robr.amount_frac " +      "  ,robr.recoup_timestamp " +      "  ,denominations.denom_pub_hash " +      "  ,robr.denom_sig " +      "FROM denominations " +      "  JOIN exchange_do_recoup_by_reserve($1) robr" +      "    USING (denominations_serial)" +      " WHERE recoup_timestamp>=$2;", +      2),      /* Used in #postgres_get_coin_transactions() to obtain recoup transactions         affecting old coins of refreshed coins */      GNUNET_PQ_make_prepare ( @@ -2282,6 +2415,23 @@ prepare_statements (struct PostgresClosure *pg)        "     USING (wire_target_h_payto)"        " WHERE reserve_pub=$1;",        1), +    /* Used in #postgres_get_reserve_status() */ +    GNUNET_PQ_make_prepare ( +      "close_by_reserve_truncated", +      "SELECT" +      " amount_val" +      ",amount_frac" +      ",closing_fee_val" +      ",closing_fee_frac" +      ",execution_date" +      ",payto_uri AS receiver_account" +      ",wtid" +      " FROM reserves_close" +      "   JOIN wire_targets" +      "     USING (wire_target_h_payto)" +      " WHERE reserve_pub=$1" +      "   AND execution_date>=$2;", +      2),      /* Used in #postgres_get_reserve_history() */      GNUNET_PQ_make_prepare (        "merge_by_reserve", @@ -2311,6 +2461,36 @@ prepare_statements (struct PostgresClosure *pg)        "  AND pr.finished"        "  AND NOT pr.refunded;",        1), +    /* Used in #postgres_get_reserve_status() */ +    GNUNET_PQ_make_prepare ( +      "merge_by_reserve_truncated", +      "SELECT" +      " pr.amount_with_fee_val" +      ",pr.amount_with_fee_frac" +      ",pr.balance_val" +      ",pr.balance_frac" +      ",pr.purse_fee_val" +      ",pr.purse_fee_frac" +      ",pr.h_contract_terms" +      ",pr.merge_pub" +      ",am.reserve_sig" +      ",pm.purse_pub" +      ",pm.merge_timestamp" +      ",pr.purse_expiration" +      ",pr.age_limit" +      ",pr.flags" +      " FROM purse_merges pm" +      "   JOIN purse_requests pr" +      "     USING (purse_pub)" +      "   JOIN account_merges am" +      "     ON (am.purse_pub = pm.purse_pub AND" +      "         am.reserve_pub = pm.reserve_pub)" +      " WHERE pm.reserve_pub=$1" +      "  AND pm.merge_timestamp >= $2" +      "  AND pm.partner_serial_id=0" /* must be local! */ +      "  AND pr.finished" +      "  AND NOT pr.refunded;", +      2),      /* Used in #postgres_get_reserve_history() */      GNUNET_PQ_make_prepare (        "history_by_reserve", @@ -2322,6 +2502,18 @@ prepare_statements (struct PostgresClosure *pg)        " FROM history_requests"        " WHERE reserve_pub=$1;",        1), +    /* Used in #postgres_get_reserve_status() */ +    GNUNET_PQ_make_prepare ( +      "history_by_reserve_truncated", +      "SELECT" +      " history_fee_val" +      ",history_fee_frac" +      ",request_timestamp" +      ",reserve_sig" +      " FROM history_requests" +      " WHERE reserve_pub=$1" +      "  AND request_timestamp>=$2;", +      2),      /* Used in #postgres_get_expired_reserves() */      GNUNET_PQ_make_prepare (        "get_expired_reserves", @@ -7031,14 +7223,18 @@ postgres_get_reserve_history (void *cls,   *   * @param cls the `struct PostgresClosure` with the plugin-specific state   * @param reserve_pub public key of the reserve - * @param[out] balance set to the reserve balance + * @param[out] balance_in set to the total of inbound + *             transactions in the returned history + * @param[out] balance_out set to the total of outbound + *             transactions in the returned history   * @param[out] rhp set to known transaction history (NULL if reserve is unknown)   * @return transaction status   */  static enum GNUNET_DB_QueryStatus  postgres_get_reserve_status (void *cls,                               const struct TALER_ReservePublicKeyP *reserve_pub, -                             struct TALER_Amount *balance, +                             struct TALER_Amount *balance_in, +                             struct TALER_Amount *balance_out,                               struct TALER_EXCHANGEDB_ReserveHistory **rhp)  {    struct PostgresClosure *pg = cls; @@ -7055,33 +7251,39 @@ postgres_get_reserve_status (void *cls,      GNUNET_PQ_PostgresResultHandler cb;    } work[] = {      /** #TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE */ -    { "reserves_in_get_transactions", +    { "reserves_in_get_transactions_truncated",        add_bank_to_exchange },      /** #TALER_EXCHANGEDB_RO_WITHDRAW_COIN */ -    { "get_reserves_out", +    { "get_reserves_out_truncated",        &add_withdraw_coin },      /** #TALER_EXCHANGEDB_RO_RECOUP_COIN */ -    { "recoup_by_reserve", +    { "recoup_by_reserve_truncated",        &add_recoup },      /** #TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK */ -    { "close_by_reserve", +    { "close_by_reserve_truncated",        &add_exchange_to_bank },      /** #TALER_EXCHANGEDB_RO_PURSE_MERGE */ -    { "merge_by_reserve", +    { "merge_by_reserve_truncated",        &add_p2p_merge },      /** #TALER_EXCHANGEDB_RO_HISTORY_REQUEST */ -    { "history_by_reserve", +    { "history_by_reserve_truncated",        &add_history_requests },      /* List terminator */      { NULL,        NULL }    };    enum GNUNET_DB_QueryStatus qs; +  struct GNUNET_TIME_Absolute timelimit;    struct GNUNET_PQ_QueryParam params[] = {      GNUNET_PQ_query_param_auto_from_type (reserve_pub), +    GNUNET_PQ_query_param_absolute_time (&timelimit),      GNUNET_PQ_query_param_end    }; +  timelimit = GNUNET_TIME_absolute_subtract ( +    GNUNET_TIME_absolute_get (), +    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_WEEKS, +                                   5));    /* FIXME: actually implement reserve history truncation logic! */    rhc.reserve_pub = reserve_pub;    rhc.rh = NULL; @@ -7119,10 +7321,8 @@ postgres_get_reserve_status (void *cls,      }    }    *rhp = rhc.rh; -  GNUNET_assert (0 <= -                 TALER_amount_subtract (balance, -                                        &rhc.balance_in, -                                        &rhc.balance_out)); +  *balance_in = rhc.balance_in; +  *balance_out = rhc.balance_out;    return qs;  } diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 4a871786..82c46cdc 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -3442,14 +3442,18 @@ struct TALER_EXCHANGEDB_Plugin     *     * @param cls the @e cls of this struct with the plugin-specific state     * @param reserve_pub public key of the reserve -   * @param[out] balance set to the reserve balance +   * @param[out] balance_in set to the total of inbound +   *             transactions in the returned history +   * @param[out] balance_out set to the total of outbound +   *             transactions in the returned history     * @param[out] rhp set to known transaction history (NULL if reserve is unknown)     * @return transaction status     */    enum GNUNET_DB_QueryStatus    (*get_reserve_status)(void *cls,                          const struct TALER_ReservePublicKeyP *reserve_pub, -                        struct TALER_Amount *balance, +                        struct TALER_Amount *balance_in, +                        struct TALER_Amount *balance_out,                          struct TALER_EXCHANGEDB_ReserveHistory **rhp); | 
