diff --git a/src/exchangedb/exchangedb.conf b/src/exchangedb/exchangedb.conf index 1c22301ad..2bfcb2ca0 100644 --- a/src/exchangedb/exchangedb.conf +++ b/src/exchangedb/exchangedb.conf @@ -30,3 +30,7 @@ LEGAL_RESERVE_EXPIRATION_TIME = 7 years # What is the desired delay between a transaction being ready and the # aggregator triggering on it? AGGREGATOR_SHIFT = 1 s + +# How many concurrent purses may be opened by a reserve +# if the reserve is paid for a year? +DEFAULT_PURSE_LIMIT = 1 \ No newline at end of file diff --git a/src/exchangedb/pg_do_reserve_open.c b/src/exchangedb/pg_do_reserve_open.c index f7a3a5f7b..ad18cb936 100644 --- a/src/exchangedb/pg_do_reserve_open.c +++ b/src/exchangedb/pg_do_reserve_open.c @@ -47,8 +47,10 @@ TEH_PG_do_reserve_open ( TALER_PQ_query_param_amount (total_paid), TALER_PQ_query_param_amount (reserve_payment), GNUNET_PQ_query_param_uint32 (&min_purse_limit), + GNUNET_PQ_query_param_uint32 (&pg->def_purse_limit), GNUNET_PQ_query_param_auto_from_type (reserve_sig), GNUNET_PQ_query_param_timestamp (&desired_expiration), + GNUNET_PQ_query_param_relative_time (&pg->legal_reserve_expiration_time), GNUNET_PQ_query_param_timestamp (&now), TALER_PQ_query_param_amount (open_fee), GNUNET_PQ_query_param_end diff --git a/src/exchangedb/pg_helper.h b/src/exchangedb/pg_helper.h index e0a4be49d..84d4c22b7 100644 --- a/src/exchangedb/pg_helper.h +++ b/src/exchangedb/pg_helper.h @@ -82,6 +82,12 @@ struct PostgresClosure */ unsigned long long prep_gen; + /** + * Number of purses we allow to be opened concurrently + * for one year per annual fee payment. + */ + uint32_t def_purse_limit; + /** * Did we initialize the prepared statements * for this session? (To be replaced with @e prep_gen.) diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 1bb835877..a369b7107 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -15567,6 +15567,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) const struct GNUNET_CONFIGURATION_Handle *cfg = cls; struct PostgresClosure *pg; struct TALER_EXCHANGEDB_Plugin *plugin; + unsigned long long dpl; pg = GNUNET_new (struct PostgresClosure); pg->cfg = cfg; @@ -15625,6 +15626,21 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) "exchangedb", "AGGREGATOR_SHIFT"); } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + "exchangedb", + "DEFAULT_PURSE_LIMIT", + &dpl)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + "exchangedb", + "DEFAULT_PURSE_LIMIT"); + pg->def_purse_limit = 1; + } + else + { + pg->def_purse_limit = (uint32_t) dpl; + } if (GNUNET_OK != TALER_config_get_currency (cfg, diff --git a/src/exchangedb/procedures.sql b/src/exchangedb/procedures.sql index 1e9b6b166..90fb7d321 100644 --- a/src/exchangedb/procedures.sql +++ b/src/exchangedb/procedures.sql @@ -2183,8 +2183,10 @@ CREATE OR REPLACE FUNCTION exchange_do_reserve_open( IN in_reserve_payment_val INT8, IN in_reserve_payment_frac INT4, IN in_min_purse_limit INT4, + IN in_default_purse_limit INT4, IN in_reserve_sig BYTEA, IN in_desired_expiration INT8, + IN in_reserve_gc_delay INT8, IN in_now INT8, IN in_open_fee_val INT8, IN in_open_fee_frac INT4, @@ -2194,9 +2196,161 @@ CREATE OR REPLACE FUNCTION exchange_do_reserve_open( OUT out_no_funds BOOLEAN) LANGUAGE plpgsql AS $$ +DECLARE + my_balance_val INT8; +DECLARE + my_balance_frac INT4; +DECLARE + my_cost_val INT8; +DECLARE + my_cost_tmp INT8; +DECLARE + my_cost_frac INT4; +DECLARE + my_years_tmp INT4; +DECLARE + my_years INT4; +DECLARE + my_needs_update BOOL; +DECLARE + my_purses_allowed INT8; +DECLARE + my_expiration_date INT8; +DECLARE + my_reserve_expiration INT8; BEGIN --- FIXME: implement! +-- FIXME: use SELECT FOR UPDATE? +SELECT + purses_allowed + ,expiration_date + ,current_balance_val + ,current_balance_frac +INTO + my_purses_allowed + ,my_reserve_expiration + ,my_balance_val + ,my_balance_frac +FROM reserves +WHERE + reserve_pub=in_reserve_pub; + +IF NOT FOUND +THEN + -- FIXME: do we need to set a 'not found'? + RETURN; +END IF; + +-- Do not allow expiration time to start in the past already +IF (my_reserve_expiration < in_now) +THEN + my_expiration_date = in_now; +ELSE + my_expiration_date = my_reserve_expiration; +END IF; + +my_cost_val = 0; +my_cost_frac = 0; +my_needs_update = FALSE; +my_years = 0; + +-- Compute years based on desired expiration time +IF (my_expiration_date < in_desired_expiration) +THEN + my_years = (31535999999999 + in_desired_expiration - my_expiration_date) / 31536000000000; + my_purses_allowed = in_default_purse_limit; + my_expiration_date = my_expiration_date + 31536000000000 * my_years; +END IF; + +-- Increase years based on purses requested +IF (my_purses_allowed < in_min_purse_limit) +THEN + my_years = (31535999999999 + in_desired_expiration - in_now) / 31536000000000; + my_expiration_date = in_now + 31536000000000 * my_years; + my_years_tmp = (in_min_purse_limit + in_default_purse_limit - my_purses_allowed - 1) / in_default_purse_limit; + my_years = my_years + my_years_tmp; + my_purses_allowed = my_purses_allowed + (in_default_purse_limit * my_years_tmp); +END IF; + +-- Compute cost based on annual fees +IF (my_years > 0) +THEN + my_cost_val = my_years * in_open_fee_val; + my_cost_tmp = my_years * in_open_fee_frac / 100000000; + IF (CAST (my_cost_val + my_cost_tmp AS INT8) < my_cost_val) + THEN + out_open_cost_val=9223372036854775807; + out_open_cost_frac=2147483647; + out_final_expiration=my_expiration_date; + out_no_funds=true; + RETURN; + END IF; + my_cost_val = CAST (my_cost_val + my_cost_tmp AS INT8); + my_cost_frac = my_years * in_open_fee_frac % 100000000; + my_needs_update = TRUE; +END IF; + +-- check if we actually have something to do +IF NOT my_needs_update +THEN + out_final_expiration = my_reserve_expiration; + out_open_cost_val = 0; + out_open_cost_frac = 0; + out_no_funds=FALSE; + RETURN; +END IF; + +-- Check payment (coins and reserve) would be sufficient. +IF ( (in_total_paid_val < my_cost_val) OR + ( (in_total_paid_val = my_cost_val) AND + (in_total_paid_frac < my_cost_frac) ) ) +THEN + out_final_expiration=my_reserve_expiration; + out_open_cost_val = my_cost_val; + out_open_cost_frac = my_cost_frac; + out_no_funds=TRUE; + RETURN; +END IF; + +-- Check reserve balance is sufficient. +IF (my_balance_val > in_reserve_payment_val) +THEN + IF (my_balance_frac >= in_reserve_payment_frac) + THEN + my_balance_val=my_balance_val - in_reserve_payment_val; + my_balance_frac=my_balance_frac - in_reserve_payment_frac; + ELSE + my_balance_val=my_balance_val - in_reserve_payment_val - 1; + my_balance_frac=my_balance_frac + 100000000 - in_reserve_payment_frac; + END IF; +ELSE + IF (my_balance_val = in_reserve_payment_val) AND (my_balance_frac >= in_reserve_payment_frac) + THEN + my_balance_val=0; + my_balance_frac=my_balance_frac - in_reserve_payment_frac; + ELSE + out_final_expiration=my_reserve_expiration; + out_open_cost_val = my_cost_val; + out_open_cost_frac = my_cost_frac; + out_no_funds=TRUE; + RETURN; + END IF; +END IF; + +UPDATE reserves SET + current_balance_val=my_balance_val + ,current_balance_frac=my_balance_frac + ,gc_date=my_reserve_expiration + in_reserve_gc_delay + ,expiration_date=my_reserve_expiration + ,purses_allowed=my_purses_allowed +WHERE + reserve_pub=in_reserve_pub; + +out_final_expiration=my_reserve_expiration; +out_open_cost_val = my_cost_val; +out_open_cost_frac = my_cost_frac; +out_no_funds=FALSE; +RETURN; END $$;