make sure reserves are not gc'ed before legal expiration

This commit is contained in:
Christian Grothoff 2019-07-24 12:19:36 +02:00
parent 9e3f4bdd79
commit a654ceafba
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
5 changed files with 100 additions and 54 deletions

View File

@ -21,3 +21,8 @@ WIREFEE_BASE_DIR = ${TALER_DATA_HOME}/exchange/wirefees/
# it is only configurable for testing, and should be treated
# as constant in production.
IDLE_RESERVE_EXPIRATION_TIME = 4 weeks
# After how long do we forget about reserves? Should be above
# the legal expiration timeframe of withdrawn coins.
LEGAL_RESERVE_EXPIRATION_TIME = 7 years

View File

@ -97,6 +97,12 @@ struct PostgresClosure
* After how long should idle reserves be closed?
*/
struct GNUNET_TIME_Relative idle_reserve_expiration_time;
/**
* After how long should reserves that have seen withdraw operations
* be garbage collected?
*/
struct GNUNET_TIME_Relative legal_reserve_expiration_time;
};
@ -210,6 +216,7 @@ postgres_create_tables (void *cls)
",current_balance_frac INT4 NOT NULL"
",current_balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
",expiration_date INT8 NOT NULL"
",gc_date INT8 NOT NULL"
");"),
/* index on reserves table (TODO: useless due to primary key!?) */
GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_reserve_pub_index ON "
@ -217,6 +224,9 @@ postgres_create_tables (void *cls)
/* index for get_expired_reserves */
GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_expiration_index"
" ON reserves (expiration_date,current_balance_val,current_balance_frac);"),
/* index for reserve GC operations */
GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_gc_index"
" ON reserves (gc_date);"),
/* reserves_in table collects the transactions which transfer funds
into the reserve. The rows of this table correspond to each
incoming transaction. */
@ -649,6 +659,7 @@ postgres_prepare (PGconn *db_conn)
",current_balance_frac"
",current_balance_curr"
",expiration_date"
",gc_date"
" FROM reserves"
" WHERE reserve_pub=$1"
" LIMIT 1"
@ -663,9 +674,10 @@ postgres_prepare (PGconn *db_conn)
",current_balance_frac"
",current_balance_curr"
",expiration_date"
",gc_date"
") VALUES "
"($1, $2, $3, $4, $5, $6);",
6),
"($1, $2, $3, $4, $5, $6, $7);",
7),
/* Used in #postgres_insert_reserve_closed() */
GNUNET_PQ_make_prepare ("reserves_close_insert",
"INSERT INTO reserves_close "
@ -687,12 +699,13 @@ postgres_prepare (PGconn *db_conn)
"UPDATE reserves"
" SET"
" expiration_date=$1"
",current_balance_val=$2"
",current_balance_frac=$3"
",current_balance_curr=$4"
",gc_date=$2"
",current_balance_val=$3"
",current_balance_frac=$4"
",current_balance_curr=$5"
" WHERE"
" reserve_pub=$5;",
5),
" reserve_pub=$6;",
6),
/* Used in #postgres_reserves_in_insert() to store transaction details */
GNUNET_PQ_make_prepare ("reserves_in_add_transaction",
"INSERT INTO reserves_in "
@ -1788,7 +1801,7 @@ postgres_prepare (PGconn *db_conn)
GNUNET_PQ_make_prepare ("gc_reserves",
"DELETE"
" FROM reserves"
" WHERE expiration_date < $1"
" WHERE gc_date < $1"
" AND current_balance_val = 0"
" AND current_balance_frac = 0;",
1),
@ -2277,6 +2290,7 @@ postgres_reserve_get (void *cls,
struct GNUNET_PQ_ResultSpec rs[] = {
TALER_PQ_result_spec_amount("current_balance", &reserve->balance),
TALER_PQ_result_spec_absolute_time("expiration_date", &reserve->expiry),
TALER_PQ_result_spec_absolute_time("gc_date", &reserve->gc),
GNUNET_PQ_result_spec_end
};
@ -2303,6 +2317,7 @@ reserves_update (void *cls,
{
struct GNUNET_PQ_QueryParam params[] = {
TALER_PQ_query_param_absolute_time (&reserve->expiry),
TALER_PQ_query_param_absolute_time (&reserve->gc),
TALER_PQ_query_param_amount (&reserve->balance),
GNUNET_PQ_query_param_auto_from_type (&reserve->pub),
GNUNET_PQ_query_param_end
@ -2382,6 +2397,7 @@ postgres_reserves_in_insert (void *cls,
GNUNET_NO));
expiry = GNUNET_TIME_absolute_add (execution_time,
pg->idle_reserve_expiration_time);
(void) GNUNET_TIME_round_abs (&expiry);
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == reserve_exists)
{
/* New reserve, create balance for the first time; we do this
@ -2394,6 +2410,7 @@ postgres_reserves_in_insert (void *cls,
GNUNET_PQ_query_param_string (sender_account_details),
TALER_PQ_query_param_amount (balance),
TALER_PQ_query_param_absolute_time (&expiry),
TALER_PQ_query_param_absolute_time (&expiry),
GNUNET_PQ_query_param_end
};
@ -2461,6 +2478,10 @@ postgres_reserves_in_insert (void *cls,
}
updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry,
reserve.expiry);
(void) GNUNET_TIME_round_abs (&updated_reserve.expiry);
updated_reserve.gc = GNUNET_TIME_absolute_max (updated_reserve.expiry,
reserve.gc);
(void) GNUNET_TIME_round_abs (&updated_reserve.gc);
return reserves_update (cls,
session,
&updated_reserve);
@ -2627,13 +2648,11 @@ postgres_insert_withdraw_info (void *cls,
TALER_B2S (&collectable->reserve_pub));
return GNUNET_DB_STATUS_SOFT_ERROR;
}
/* FIXME: idle_reserve_expiration_time is not a good value here,
we should base this on the LEGAL expiration time of coins
as we need reserve data for payback! */
expiry = GNUNET_TIME_absolute_add (now,
pg->idle_reserve_expiration_time);
reserve.expiry = GNUNET_TIME_absolute_max (expiry,
reserve.expiry);
pg->legal_reserve_expiration_time);
reserve.gc = GNUNET_TIME_absolute_max (expiry,
reserve.gc);
(void) GNUNET_TIME_round_abs (&reserve.gc);
qs = reserves_update (cls,
session,
&reserve);
@ -7081,10 +7100,16 @@ postgres_insert_payback_request (void *cls,
GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR;
}
expiry = GNUNET_TIME_absolute_add (timestamp,
pg->legal_reserve_expiration_time);
reserve.gc = GNUNET_TIME_absolute_max (expiry,
reserve.gc);
(void) GNUNET_TIME_round_abs (&reserve.gc);
expiry = GNUNET_TIME_absolute_add (timestamp,
pg->idle_reserve_expiration_time);
reserve.expiry = GNUNET_TIME_absolute_max (expiry,
reserve.expiry);
(void) GNUNET_TIME_round_abs (&reserve.expiry);
qs = reserves_update (cls,
session,
&reserve);
@ -7725,15 +7750,20 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
}
}
if (GNUNET_OK !=
if ( (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (cfg,
"exchangedb",
"IDLE_RESERVE_EXPIRATION_TIME",
&pg->idle_reserve_expiration_time))
&pg->idle_reserve_expiration_time)) ||
(GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (cfg,
"exchangedb",
"LEGAL_RESERVE_EXPIRATION_TIME",
&pg->legal_reserve_expiration_time)) )
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"exchangedb",
"IDLE_RESERVE_EXPIRATION_TIME");
"LEGAL/IDLE_RESERVE_EXPIRATION_TIME");
GNUNET_free (pg);
return NULL;
}

View File

@ -17,3 +17,7 @@ CONFIG = postgres:///talercheck
# it is only configurable for testing, and should be treated
# as constant in production.
IDLE_RESERVE_EXPIRATION_TIME = 4 weeks
# After how long do we forget about reserves? Should be above
# the legal expiration timeframe of withdrawn coins.
LEGAL_RESERVE_EXPIRATION_TIME = 7 years

View File

@ -127,9 +127,16 @@ struct TALER_EXCHANGEDB_Reserve
struct TALER_Amount balance;
/**
* The expiration date of this reserve
* The expiration date of this reserve; funds will be wired back
* at this time.
*/
struct GNUNET_TIME_Absolute expiry;
/**
* The legal expiration date of this reserve; we will forget about
* it at this time.
*/
struct GNUNET_TIME_Absolute gc;
};