-implemented bounded history for reserve status requests

This commit is contained in:
Christian Grothoff 2022-07-05 14:25:30 +02:00
parent bf9b7e168b
commit 36a8ecd4c4
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
3 changed files with 247 additions and 18 deletions

View File

@ -58,6 +58,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.
*/
@ -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;
}

View File

@ -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;
}

View File

@ -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);