exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit ea4ddbc744baf281649db57bb4441d40ca609088
parent 79f095f2c3f125276664ddfe9d92d54996a2a182
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sat, 29 Mar 2025 15:24:13 +0100

fix tops rules

Diffstat:
Asrc/exchangedb/0009-batch_deposits.sql | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/exchangedb/exchange-0009.sql.in | 1+
Msrc/exchangedb/exchange_do_deposit.sql | 5++++-
Msrc/exchangedb/exchange_statistics_helpers.sql | 32++++++++++++++++----------------
Msrc/exchangedb/pg_do_deposit.c | 17++++++++++++++++-
Msrc/exchangedb/tops-0001.sql | 31+------------------------------
Msrc/testing/taler-unified-setup.sh | 1-
7 files changed, 92 insertions(+), 49 deletions(-)

diff --git a/src/exchangedb/0009-batch_deposits.sql b/src/exchangedb/0009-batch_deposits.sql @@ -0,0 +1,54 @@ +-- +-- This file is part of TALER +-- Copyright (C) 2025 Taler Systems SA +-- +-- TALER is free software; you can redistribute it and/or modify it under the +-- terms of the GNU General Public License as published by the Free Software +-- Foundation; either version 3, or (at your option) any later version. +-- +-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY +-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +-- A PARTICULAR PURPOSE. See the GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along with +-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +-- + +CREATE FUNCTION alter_table_batch_deposits9( + IN partition_suffix TEXT DEFAULT NULL +) +RETURNS VOID +LANGUAGE plpgsql +AS $$ +BEGIN + PERFORM create_partitioned_table( + 'ALTER TABLE %I' + ' ADD COLUMN total_amount taler_amount' + ' DEFAULT NULL' + ';', + 'batch_deposits' + ,'' + ,partition_suffix + ); + + PERFORM comment_partitioned_column( + 'total amount, NULL allowed for legacy entries (pre-1.0)' + ,'total_amount' + ,'batch_deposits' + ,partition_suffix + ); +END $$; + + +INSERT INTO exchange_tables + (name + ,version + ,action + ,partitioned + ,by_range) + VALUES + ('batch_deposits9' + ,'exchange-0009' + ,'alter' + ,TRUE + ,FALSE); diff --git a/src/exchangedb/exchange-0009.sql.in b/src/exchangedb/exchange-0009.sql.in @@ -26,6 +26,7 @@ COMMENT ON INDEX exchange_tables_by_pending #include "0009-age_withdraw.sql" +#include "0009-batch_deposits.sql" #include "0009-withdraw.sql" #include "0009-recoup.sql" #include "0009-statistics.sql" diff --git a/src/exchangedb/exchange_do_deposit.sql b/src/exchangedb/exchange_do_deposit.sql @@ -37,6 +37,7 @@ CREATE FUNCTION exchange_do_deposit( IN ina_coin_pub BYTEA[], IN ina_coin_sig BYTEA[], IN ina_amount_with_fee taler_amount[], + IN in_total_amount taler_amount, OUT out_exchange_timestamp INT8, OUT out_insufficient_balance_coin_index INT4, -- index of coin with bad balance, NULL if none OUT out_conflict BOOL @@ -100,6 +101,7 @@ INSERT INTO batch_deposits ,wire_target_h_payto ,policy_details_serial_id ,policy_blocked + ,total_amount ) VALUES (in_shard @@ -114,7 +116,8 @@ INSERT INTO batch_deposits ,in_wire_salt ,in_wire_target_h_payto ,in_policy_details_serial_id - ,in_policy_blocked) + ,in_policy_blocked + ,in_total_amount) ON CONFLICT DO NOTHING -- for CONFLICT ON (merchant_pub, h_contract_terms) RETURNING batch_deposit_serial_id diff --git a/src/exchangedb/exchange_statistics_helpers.sql b/src/exchangedb/exchange_statistics_helpers.sql @@ -795,7 +795,7 @@ BEGIN min_slot = my_ranges[my_i - 1]; END IF; end_slot = my_ranges[my_i]; - RAISE NOTICE 'Coarsening from [%,%) at %', my_time - end_slot, my_time - min_slot, my_precision; +-- RAISE NOTICE 'Coarsening from [%,%) at %', my_time - end_slot, my_time - min_slot, my_precision; LOOP EXIT WHEN min_slot >= end_slot; @@ -805,22 +805,22 @@ BEGIN MIN(nevent_serial_id) AS rep_serial_id INTO my_sum FROM exchange_statistic_counter_event - WHERE h_payto=my_instance + WHERE h_payto=my_h_payto AND imeta_serial_id=my_meta AND slot >= my_time - max_slot AND slot < my_time - min_slot; - RAISE NOTICE 'Found % entries between [%,%)', my_sum.matches, my_time - max_slot, my_time - min_slot; +-- RAISE NOTICE 'Found % entries between [%,%)', my_sum.matches, my_time - max_slot, my_time - min_slot; -- we only proceed if we had more then one match (optimization) IF FOUND AND my_sum.matches > 1 THEN my_total = my_sum.total; - RAISE NOTICE 'combining % entries to representative % for slots [%-%)', my_sum.matches, my_sum.rep_serial_id, my_time - max_slot, my_time - min_slot; +-- RAISE NOTICE 'combining % entries to representative % for slots [%-%)', my_sum.matches, my_sum.rep_serial_id, my_time - max_slot, my_time - min_slot; -- combine entries DELETE FROM exchange_statistic_counter_event - WHERE h_payto=my_instance + WHERE h_payto=my_h_payto AND imeta_serial_id=my_meta AND slot >= my_time - max_slot AND slot < my_time - min_slot @@ -829,7 +829,7 @@ BEGIN UPDATE exchange_statistic_counter_event SET delta = my_total WHERE imeta_serial_id = my_meta - AND h_payto = my_instance + AND h_payto = my_h_payto AND nevent_serial_id = my_sum.rep_serial_id; END IF; min_slot = min_slot + my_precision; @@ -837,13 +837,13 @@ BEGIN END LOOP; -- my_i loop -- Finally, delete all events beyond the range we care about - RAISE NOTICE 'deleting entries of %/% before % - % = %', my_instance, my_meta, my_time, my_ranges[array_length(my_ranges,1)], my_time - my_ranges[array_length(my_ranges,1)]; +-- RAISE NOTICE 'deleting entries of %/% before % - % = %', my_h_payto, my_meta, my_time, my_ranges[array_length(my_ranges,1)], my_time - my_ranges[array_length(my_ranges,1)]; DELETE FROM exchange_statistic_counter_event - WHERE h_payto=my_instance + WHERE h_payto=my_h_payto AND imeta_serial_id=my_meta AND slot < my_time - my_ranges[array_length(my_ranges,1)]; END LOOP; -- my_rec loop - END LOOP; -- my_instance loop + END LOOP; -- my_h_payto loop END $$; COMMENT ON PROCEDURE exchange_statistic_counter_gc IS 'Performs garbage collection and compaction of the exchange_statistic_counter_event table'; @@ -908,13 +908,13 @@ BEGIN END IF; end_slot = my_ranges[my_i]; - RAISE NOTICE 'Coarsening from [%,%) at %', my_time - end_slot, my_time - min_slot, my_precision; +-- RAISE NOTICE 'Coarsening from [%,%) at %', my_time - end_slot, my_time - min_slot, my_precision; LOOP EXIT WHEN min_slot >= end_slot; max_slot = min_slot + my_precision; - SELECT SUM(delta_value) AS total_val, - SUM(delta_frac) AS total_frac, - COUNT(*) AS matches, + SELECT SUM((delta).val) AS total_val, + SUM((delta).frac) AS total_frac, + COUNT(*) AS matches, MIN(aevent_serial_id) AS rep_serial_id INTO my_sum FROM exchange_statistic_amount_event @@ -938,8 +938,8 @@ BEGIN AND aevent_serial_id > my_sum.rep_serial_id; -- Now update the representative to the sum UPDATE exchange_statistic_amount_event SET - delta_value = my_total_value - ,delta_frac = my_total_frac + delta.val = my_total_value + ,delta.frac = my_total_frac WHERE imeta_serial_id = my_meta AND h_payto = my_h_payto AND aevent_serial_id = my_sum.rep_serial_id; @@ -949,7 +949,7 @@ BEGIN END LOOP; -- my_i loop -- Finally, delete all events beyond the range we care about - RAISE NOTICE 'deleting entries of %/% before % - % = %', my_h_payto, my_meta, my_time, my_ranges[array_length(my_ranges,1)], my_time - my_ranges[array_length(my_ranges,1)]; +-- RAISE NOTICE 'deleting entries of %/% before % - % = %', my_h_payto, my_meta, my_time, my_ranges[array_length(my_ranges,1)], my_time - my_ranges[array_length(my_ranges,1)]; DELETE FROM exchange_statistic_amount_event WHERE h_payto=my_h_payto AND imeta_serial_id=my_meta diff --git a/src/exchangedb/pg_do_deposit.c b/src/exchangedb/pg_do_deposit.c @@ -41,6 +41,7 @@ TEH_PG_do_deposit ( const struct TALER_CoinSpendPublicKeyP *coin_pubs[GNUNET_NZL (bd->num_cdis)]; const struct TALER_CoinSpendSignatureP *coin_sigs[GNUNET_NZL (bd->num_cdis)]; struct TALER_Amount amounts_with_fee[GNUNET_NZL (bd->num_cdis)]; + struct TALER_Amount total_amount; struct TALER_NormalizedPaytoHashP h_normalized_payto; struct GNUNET_PQ_QueryParam params[] = { /* data for batch_deposits */ @@ -76,6 +77,8 @@ TEH_PG_do_deposit ( TALER_PQ_query_param_array_amount (bd->num_cdis, amounts_with_fee, pg->conn), + TALER_PQ_query_param_amount (pg->conn, + &total_amount), GNUNET_PQ_query_param_end }; bool no_time; @@ -94,6 +97,7 @@ TEH_PG_do_deposit ( }; enum GNUNET_DB_QueryStatus qs; + GNUNET_assert (0 < bd->num_cdis); TALER_full_payto_normalize_and_hash (bd->receiver_wire_account, &h_normalized_payto); for (unsigned int i = 0; i < bd->num_cdis; i++) @@ -101,6 +105,17 @@ TEH_PG_do_deposit ( const struct TALER_EXCHANGEDB_CoinDepositInformation *cdi = &bd->cdis[i]; + if (0 == i) + { + total_amount = cdi->amount_with_fee; + } + else + { + GNUNET_assert (0 <= + TALER_amount_add (&total_amount, + &total_amount, + &cdi->amount_with_fee)); + } amounts_with_fee[i] = cdi->amount_with_fee; coin_pubs[i] = &cdi->coin.coin_pub; coin_sigs[i] = &cdi->csig; @@ -116,7 +131,7 @@ TEH_PG_do_deposit ( ",out_insufficient_balance_coin_index AS insufficient_balance_coin_index" ",out_conflict AS conflicted" " FROM exchange_do_deposit" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18);") + " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19);") ; qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "call_deposit", diff --git a/src/exchangedb/tops-0001.sql b/src/exchangedb/tops-0001.sql @@ -88,9 +88,6 @@ AS $$ DECLARE my_h_payto BYTEA; -- normalized h_payto of target account my_rec RECORD; - my_vsum INT8; - my_fsum INT8; - my_batch_amount taler_amount; -- sum of all coins (incl. fees) my_last_year taler_amount; -- sum of deposits this year my_last_month taler_amount; -- sum of deposits this month my_old_rules RECORD; @@ -103,37 +100,11 @@ BEGIN FROM wire_targets wt WHERE wire_target_h_payto = NEW.wire_target_h_payto; - -- FIXME: this does not work, coin_deposits is only initialized LATER - -- in exchange_do_deposit.sql; - -- Solution: add a new column with the sum? - FOR my_rec IN - SELECT amount_with_fee - FROM coin_deposits cdeps - WHERE batch_deposit_serial_id = NEW.batch_deposit_serial_id - LOOP - RAISE NOTICE 'XXXX has %', my_rec; - END LOOP; - SELECT SUM((cdeps.amount_with_fee).val) AS vsum, - SUM((cdeps.amount_with_fee).frac) AS fsum - INTO my_rec - FROM coin_deposits cdeps - WHERE batch_deposit_serial_id = NEW.batch_deposit_serial_id; - IF NOT FOUND - THEN - RAISE NOTICE 'Invariant failed, no coin deposits for batch deposit'; - RETURN NEW; - END IF; - RAISE NOTICE 'XXXZ SELECT yielded % - %',FOUND,my_rec; - my_vsum = my_rec.vsum; - my_fsum = my_rec.fsum; - RAISE NOTICE 'XXXY Batch deposit of %.%',my_vsum,my_fsum; - my_batch_amount.val = my_vsum + my_fsum / 100000000; - my_batch_amount.frac = my_fsum % 100000000; CALL exchange_do_bump_amount_stat ('deposit-volume' ,my_h_payto ,CURRENT_TIMESTAMP(0)::TIMESTAMP - ,my_batch_amount); + ,NEW.total_amount); -- FIXME: this is just for testing, I want to also check -- the 'counter'-based functions. diff --git a/src/testing/taler-unified-setup.sh b/src/testing/taler-unified-setup.sh @@ -512,7 +512,6 @@ then taler-exchange-dbinit \ -c "$CONF" \ --reset -# -e tops $USE_VALGRIND taler-exchange-secmod-eddsa \ -c "$CONF" \ -L "$LOGLEVEL" \