summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2022-07-05 14:25:30 +0200
committerChristian Grothoff <christian@grothoff.org>2022-07-05 14:25:30 +0200
commit36a8ecd4c47eaaab767d679564aa4e87166fa361 (patch)
tree7d59767c322edc96ece6e996a1a5d5659010e196
parentbf9b7e168bfccb7a92793b50936ac404bdfb72d9 (diff)
downloadexchange-36a8ecd4c47eaaab767d679564aa4e87166fa361.tar.gz
exchange-36a8ecd4c47eaaab767d679564aa4e87166fa361.tar.bz2
exchange-36a8ecd4c47eaaab767d679564aa4e87166fa361.zip
-implemented bounded history for reserve status requests
-rw-r--r--src/exchange/taler-exchange-httpd_reserves_status.c33
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c224
-rw-r--r--src/include/taler_exchangedb_plugin.h8
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 5b7becb94..ff8a65c23 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 63f075210..b9debfa44 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 4a871786f..82c46cdcb 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);