exchange

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

commit 280eeebcd3e80c1bcaa22e347367c67f6c0ee61f
parent 030de55b4925e6f71e47f9c5962bfbbf4138d577
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue, 26 May 2026 23:51:48 +0200

more SQL bugfixes, DCE

Diffstat:
Msrc/auditor/taler-auditor-sync.c | 1-
Dsrc/exchangedb/batch_ensure_coin_known.c | 457-------------------------------------------------------------------------------
Dsrc/exchangedb/batch_ensure_coin_known.sql | 469-------------------------------------------------------------------------------
Msrc/exchangedb/do_refresh.sql | 11++++++-----
Msrc/exchangedb/gc.sql | 6+++---
Msrc/exchangedb/meson.build | 1-
Msrc/exchangedb/persist_policy_details.sql | 2+-
Msrc/exchangedb/select_aggregations_above_serial.sql | 5+++++
Msrc/exchangedb/sql-schema/exchange_statistics_helpers.sql | 10+++++-----
Msrc/exchangedb/sql-schema/meson.build | 2--
10 files changed, 20 insertions(+), 944 deletions(-)

diff --git a/src/auditor/taler-auditor-sync.c b/src/auditor/taler-auditor-sync.c @@ -27,7 +27,6 @@ #include "exchange-database/add_denomination_key.h" #include "exchange-database/add_policy_fulfillment_proof.h" #include "exchange-database/aggregate.h" -#include "exchange-database/batch_ensure_coin_known.h" #include "exchange-database/begin_revolving_shard.h" #include "exchange-database/begin_shard.h" #include "exchange-database/clear_aml_lock.h" diff --git a/src/exchangedb/batch_ensure_coin_known.c b/src/exchangedb/batch_ensure_coin_known.c @@ -1,457 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 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/> - */ -/** - * @file exchangedb/batch_ensure_coin_known.c - * @brief Implementation of the batch_ensure_coin_known function for Postgres - * @author Christian Grothoff - * - * FIXME-#9373: use the array support for postgres to simplify this code! - * - */ -#include "exchangedb_lib.h" -#include "taler/taler_pq_lib.h" -#include "exchange-database/batch_ensure_coin_known.h" -#include "helper.h" - - -static enum GNUNET_DB_QueryStatus -insert1 (struct TALER_EXCHANGEDB_PostgresContext *pg, - const struct TALER_CoinPublicInfo coin[1], - struct TALER_EXCHANGEDB_CoinInfo result[1]) -{ - enum GNUNET_DB_QueryStatus qs; - bool is_denom_pub_hash_null = false; - bool is_age_hash_null = false; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&coin[0].coin_pub), - GNUNET_PQ_query_param_auto_from_type (&coin[0].denom_pub_hash), - GNUNET_PQ_query_param_auto_from_type (&coin[0].h_age_commitment), - TALER_PQ_query_param_denom_sig (&coin[0].denom_sig), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("existed", - &result[0].existed), - GNUNET_PQ_result_spec_uint64 ("known_coin_id", - &result[0].known_coin_id), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", - &result[0].denom_hash), - &is_denom_pub_hash_null), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash", - &result[0].h_age_commitment), - &is_age_hash_null), - GNUNET_PQ_result_spec_end - }; - - PREPARE (pg, - "batch1_known_coin", - "SELECT" - " existed1 AS existed" - ",known_coin_id1 AS known_coin_id" - ",denom_pub_hash1 AS denom_hash" - ",age_commitment_hash1 AS h_age_commitment" - " FROM exchange_do_batch1_known_coin" - " ($1, $2, $3, $4);" - ); - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch1_known_coin", - params, - rs); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - return qs; - case GNUNET_DB_STATUS_SOFT_ERROR: - return qs; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - GNUNET_break (0); /* should be impossible */ - return GNUNET_DB_STATUS_HARD_ERROR; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; /* continued below */ - } - - if ( (! is_denom_pub_hash_null) && - (0 != GNUNET_memcmp (&result[0].denom_hash, - &coin->denom_pub_hash)) ) - { - GNUNET_break_op (0); - result[0].denom_conflict = true; - } - - if ( (! is_denom_pub_hash_null) && - (0 != GNUNET_memcmp (&result[0].denom_hash, - &coin[0].denom_pub_hash)) ) - { - GNUNET_break_op (0); - result[0].denom_conflict = true; - } - - result[0].age_conflict = TALER_AgeCommitmentHashP_NoConflict; - - if (is_age_hash_null != coin[0].no_age_commitment) - { - if (is_age_hash_null) - { - GNUNET_break_op (0); - result[0].age_conflict = TALER_AgeCommitmentHashP_NullExpected; - } - else - { - GNUNET_break_op (0); - result[0].age_conflict = TALER_AgeCommitmentHashP_ValueExpected; - } - } - else if ( (! is_age_hash_null) && - (0 != GNUNET_memcmp (&result[0].h_age_commitment, - &coin[0].h_age_commitment)) ) - { - GNUNET_break_op (0); - result[0].age_conflict = TALER_AgeCommitmentHashP_ValueDiffers; - } - - return qs; -} - - -static enum GNUNET_DB_QueryStatus -insert2 (struct TALER_EXCHANGEDB_PostgresContext *pg, - const struct TALER_CoinPublicInfo coin[2], - struct TALER_EXCHANGEDB_CoinInfo result[2]) -{ - enum GNUNET_DB_QueryStatus qs; - bool is_denom_pub_hash_null[2] = {false, false}; - bool is_age_hash_null[2] = {false, false}; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&coin[0].coin_pub), - GNUNET_PQ_query_param_auto_from_type (&coin[0].denom_pub_hash), - GNUNET_PQ_query_param_auto_from_type (&coin[0].h_age_commitment), - TALER_PQ_query_param_denom_sig (&coin[0].denom_sig), - - GNUNET_PQ_query_param_auto_from_type (&coin[1].coin_pub), - GNUNET_PQ_query_param_auto_from_type (&coin[1].denom_pub_hash), - GNUNET_PQ_query_param_auto_from_type (&coin[1].h_age_commitment), - TALER_PQ_query_param_denom_sig (&coin[0].denom_sig), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("existed", - &result[0].existed), - GNUNET_PQ_result_spec_uint64 ("known_coin_id", - &result[0].known_coin_id), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", - &result[0].denom_hash), - &is_denom_pub_hash_null[0]), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash", - &result[0].h_age_commitment), - &is_age_hash_null[0]), - GNUNET_PQ_result_spec_bool ("existed2", - &result[1].existed), - GNUNET_PQ_result_spec_uint64 ("known_coin_id2", - &result[1].known_coin_id), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash2", - &result[1].denom_hash), - &is_denom_pub_hash_null[1]), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash2", - &result[1].h_age_commitment), - &is_age_hash_null[1]), - GNUNET_PQ_result_spec_end - }; - - PREPARE (pg, - "batch2_known_coin", - "SELECT" - " existed1 AS existed" - ",known_coin_id1 AS known_coin_id" - ",denom_pub_hash1 AS denom_hash" - ",age_commitment_hash1 AS h_age_commitment" - ",existed2 AS existed2" - ",known_coin_id2 AS known_coin_id2" - ",denom_pub_hash2 AS denom_hash2" - ",age_commitment_hash2 AS h_age_commitment2" - " FROM exchange_do_batch2_known_coin" - " ($1, $2, $3, $4, $5, $6, $7, $8);" - ); - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch2_known_coin", - params, - rs); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - return qs; - case GNUNET_DB_STATUS_SOFT_ERROR: - return qs; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - GNUNET_break (0); /* should be impossible */ - return GNUNET_DB_STATUS_HARD_ERROR; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; /* continued below */ - } - - for (int i = 0; i < 2; i++) - { - if ( (! is_denom_pub_hash_null[i]) && - (0 != GNUNET_memcmp (&result[i].denom_hash, - &coin[i].denom_pub_hash)) ) - { - GNUNET_break_op (0); - result[i].denom_conflict = true; - } - - result[i].age_conflict = TALER_AgeCommitmentHashP_NoConflict; - - if (is_age_hash_null[i] != coin[i].no_age_commitment) - { - if (is_age_hash_null[i]) - { - GNUNET_break_op (0); - result[i].age_conflict = TALER_AgeCommitmentHashP_NullExpected; - } - else - { - GNUNET_break_op (0); - result[i].age_conflict = TALER_AgeCommitmentHashP_ValueExpected; - } - } - else if ( (! is_age_hash_null[i]) && - (0 != GNUNET_memcmp (&result[i].h_age_commitment, - &coin[i].h_age_commitment)) ) - { - GNUNET_break_op (0); - result[i].age_conflict = TALER_AgeCommitmentHashP_ValueDiffers; - } - } - - return qs; -} - - -static enum GNUNET_DB_QueryStatus -insert4 (struct TALER_EXCHANGEDB_PostgresContext *pg, - const struct TALER_CoinPublicInfo coin[4], - struct TALER_EXCHANGEDB_CoinInfo result[4]) -{ - enum GNUNET_DB_QueryStatus qs; - bool is_denom_pub_hash_null[4] = {false, false, false, false}; - bool is_age_hash_null[4] = {false, false, false, false}; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&coin[0].coin_pub), - GNUNET_PQ_query_param_auto_from_type (&coin[0].denom_pub_hash), - GNUNET_PQ_query_param_auto_from_type (&coin[0].h_age_commitment), - TALER_PQ_query_param_denom_sig (&coin[0].denom_sig), - - GNUNET_PQ_query_param_auto_from_type (&coin[1].coin_pub), - GNUNET_PQ_query_param_auto_from_type (&coin[1].denom_pub_hash), - GNUNET_PQ_query_param_auto_from_type (&coin[1].h_age_commitment), - TALER_PQ_query_param_denom_sig (&coin[0].denom_sig), - - GNUNET_PQ_query_param_auto_from_type (&coin[2].coin_pub), - GNUNET_PQ_query_param_auto_from_type (&coin[2].denom_pub_hash), - GNUNET_PQ_query_param_auto_from_type (&coin[2].h_age_commitment), - TALER_PQ_query_param_denom_sig (&coin[2].denom_sig), - - GNUNET_PQ_query_param_auto_from_type (&coin[3].coin_pub), - GNUNET_PQ_query_param_auto_from_type (&coin[3].denom_pub_hash), - GNUNET_PQ_query_param_auto_from_type (&coin[3].h_age_commitment), - TALER_PQ_query_param_denom_sig (&coin[3].denom_sig), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("existed", - &result[0].existed), - GNUNET_PQ_result_spec_uint64 ("known_coin_id", - &result[0].known_coin_id), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", - &result[0].denom_hash), - &is_denom_pub_hash_null[0]), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash", - &result[0].h_age_commitment), - &is_age_hash_null[0]), - GNUNET_PQ_result_spec_bool ("existed2", - &result[1].existed), - GNUNET_PQ_result_spec_uint64 ("known_coin_id2", - &result[1].known_coin_id), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash2", - &result[1].denom_hash), - &is_denom_pub_hash_null[1]), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash2", - &result[1].h_age_commitment), - &is_age_hash_null[1]), - GNUNET_PQ_result_spec_bool ("existed3", - &result[2].existed), - GNUNET_PQ_result_spec_uint64 ("known_coin_id3", - &result[2].known_coin_id), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash3", - &result[2].denom_hash), - &is_denom_pub_hash_null[2]), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash3", - &result[2].h_age_commitment), - &is_age_hash_null[2]), - GNUNET_PQ_result_spec_bool ("existed4", - &result[3].existed), - GNUNET_PQ_result_spec_uint64 ("known_coin_id4", - &result[3].known_coin_id), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash4", - &result[3].denom_hash), - &is_denom_pub_hash_null[3]), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash4", - &result[3].h_age_commitment), - &is_age_hash_null[3]), - GNUNET_PQ_result_spec_end - }; - - PREPARE (pg, - "batch4_known_coin", - "SELECT" - " existed1 AS existed" - ",known_coin_id1 AS known_coin_id" - ",denom_pub_hash1 AS denom_hash" - ",age_commitment_hash1 AS h_age_commitment" - ",existed2 AS existed2" - ",known_coin_id2 AS known_coin_id2" - ",denom_pub_hash2 AS denom_hash2" - ",age_commitment_hash2 AS h_age_commitment2" - ",existed3 AS existed3" - ",known_coin_id3 AS known_coin_id3" - ",denom_pub_hash3 AS denom_hash3" - ",age_commitment_hash3 AS h_age_commitment3" - ",existed4 AS existed4" - ",known_coin_id4 AS known_coin_id4" - ",denom_pub_hash4 AS denom_hash4" - ",age_commitment_hash4 AS h_age_commitment4" - " FROM exchange_do_batch2_known_coin" - " ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16);" - ); - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch4_known_coin", - params, - rs); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - return qs; - case GNUNET_DB_STATUS_SOFT_ERROR: - return qs; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - GNUNET_break (0); /* should be impossible */ - return GNUNET_DB_STATUS_HARD_ERROR; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; /* continued below */ - } - - for (int i = 0; i < 4; i++) - { - if ( (! is_denom_pub_hash_null[i]) && - (0 != GNUNET_memcmp (&result[i].denom_hash, - &coin[i].denom_pub_hash)) ) - { - GNUNET_break_op (0); - result[i].denom_conflict = true; - } - - result[i].age_conflict = TALER_AgeCommitmentHashP_NoConflict; - - if (is_age_hash_null[i] != coin[i].no_age_commitment) - { - if (is_age_hash_null[i]) - { - GNUNET_break_op (0); - result[i].age_conflict = TALER_AgeCommitmentHashP_NullExpected; - } - else - { - GNUNET_break_op (0); - result[i].age_conflict = TALER_AgeCommitmentHashP_ValueExpected; - } - } - else if ( (! is_age_hash_null[i]) && - (0 != GNUNET_memcmp (&result[i].h_age_commitment, - &coin[i].h_age_commitment)) ) - { - GNUNET_break_op (0); - result[i].age_conflict = TALER_AgeCommitmentHashP_ValueDiffers; - } - } - - return qs; -} - - -enum GNUNET_DB_QueryStatus -TALER_EXCHANGEDB_batch_ensure_coin_known ( - struct TALER_EXCHANGEDB_PostgresContext *pg, - const struct TALER_CoinPublicInfo *coin, - struct TALER_EXCHANGEDB_CoinInfo *result, - unsigned int coin_length, - unsigned int batch_size) -{ - enum GNUNET_DB_QueryStatus qs = 0; - unsigned int i = 0; - - while ( (qs >= 0) && - (i < coin_length) ) - { - unsigned int bs = GNUNET_MIN (batch_size, - coin_length - i); - if (bs >= 4) - { - qs = insert4 (pg, - &coin[i], - &result[i]); - i += 4; - continue; - } - switch (bs) - { - case 3: - case 2: - qs = insert2 (pg, - &coin[i], - &result[i]); - i += 2; - break; - case 1: - qs = insert1 (pg, - &coin[i], - &result[i]); - i += 1; - break; - case 0: - GNUNET_assert (0); - break; - } - } /* end while */ - if (qs < 0) - return qs; - return i; -} diff --git a/src/exchangedb/batch_ensure_coin_known.sql b/src/exchangedb/batch_ensure_coin_known.sql @@ -1,469 +0,0 @@ --- --- This file is part of TALER --- Copyright (C) 2014--2022 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 OR REPLACE FUNCTION exchange_do_batch4_known_coin( - IN in_coin_pub1 BYTEA, - IN in_denom_pub_hash1 BYTEA, - IN in_h_age_commitment1 BYTEA, - IN in_denom_sig1 BYTEA, - IN in_coin_pub2 BYTEA, - IN in_denom_pub_hash2 BYTEA, - IN in_h_age_commitment2 BYTEA, - IN in_denom_sig2 BYTEA, - IN in_coin_pub3 BYTEA, - IN in_denom_pub_hash3 BYTEA, - IN in_h_age_commitment3 BYTEA, - IN in_denom_sig3 BYTEA, - IN in_coin_pub4 BYTEA, - IN in_denom_pub_hash4 BYTEA, - IN in_h_age_commitment4 BYTEA, - IN in_denom_sig4 BYTEA, - OUT existed1 BOOLEAN, - OUT existed2 BOOLEAN, - OUT existed3 BOOLEAN, - OUT existed4 BOOLEAN, - OUT known_coin_id1 INT8, - OUT known_coin_id2 INT8, - OUT known_coin_id3 INT8, - OUT known_coin_id4 INT8, - OUT denom_pub_hash1 BYTEA, - OUT denom_pub_hash2 BYTEA, - OUT denom_pub_hash3 BYTEA, - OUT denom_pub_hash4 BYTEA, - OUT age_commitment_hash1 BYTEA, - OUT age_commitment_hash2 BYTEA, - OUT age_commitment_hash3 BYTEA, - OUT age_commitment_hash4 BYTEA) -LANGUAGE plpgsql -AS $$ -BEGIN -WITH dd AS ( -SELECT - denominations_serial, - coin - FROM denominations - WHERE denom_pub_hash - IN - (in_denom_pub_hash1, - in_denom_pub_hash2, - in_denom_pub_hash3, - in_denom_pub_hash4) - ),--dd - input_rows AS ( - VALUES - (in_coin_pub1, - in_denom_pub_hash1, - in_h_age_commitment1, - in_denom_sig1), - (in_coin_pub2, - in_denom_pub_hash2, - in_h_age_commitment2, - in_denom_sig2), - (in_coin_pub3, - in_denom_pub_hash3, - in_h_age_commitment3, - in_denom_sig3), - (in_coin_pub4, - in_denom_pub_hash4, - in_h_age_commitment4, - in_denom_sig4) - ),--ir - ins AS ( - INSERT INTO known_coins ( - coin_pub, - denominations_serial, - age_commitment_hash, - denom_sig, - remaining - ) - SELECT - ir.coin_pub, - dd.denominations_serial, - ir.age_commitment_hash, - ir.denom_sig, - dd.coin - FROM input_rows ir - JOIN dd - ON dd.denom_pub_hash = ir.denom_pub_hash - ON CONFLICT DO NOTHING - RETURNING known_coin_id - ),--kc - exists AS ( - SELECT - CASE - WHEN - ins.known_coin_id IS NOT NULL - THEN - FALSE - ELSE - TRUE - END AS existed, - ins.known_coin_id, - dd.denom_pub_hash, - kc.age_commitment_hash - FROM input_rows ir - LEFT JOIN ins - ON ins.coin_pub = ir.coin_pub - LEFT JOIN known_coins kc - ON kc.coin_pub = ir.coin_pub - LEFT JOIN dd - ON dd.denom_pub_hash = ir.denom_pub_hash - )--exists -SELECT - exists.existed AS existed1, - exists.known_coin_id AS known_coin_id1, - exists.denom_pub_hash AS denom_pub_hash1, - exists.age_commitment_hash AS age_commitment_hash1, - ( - SELECT exists.existed - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash2 - ) AS existed2, - ( - SELECT exists.known_coin_id - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash2 - ) AS known_coin_id2, - ( - SELECT exists.denom_pub_hash - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash2 - ) AS denom_pub_hash2, - ( - SELECT exists.age_commitment_hash - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash2 - )AS age_commitment_hash2, - ( - SELECT exists.existed - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash3 - ) AS existed3, - ( - SELECT exists.known_coin_id - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash3 - ) AS known_coin_id3, - ( - SELECT exists.denom_pub_hash - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash3 - ) AS denom_pub_hash3, - ( - SELECT exists.age_commitment_hash - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash3 - )AS age_commitment_hash3, - ( - SELECT exists.existed - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash4 - ) AS existed4, - ( - SELECT exists.known_coin_id - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash4 - ) AS known_coin_id4, - ( - SELECT exists.denom_pub_hash - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash4 - ) AS denom_pub_hash4, - ( - SELECT exists.age_commitment_hash - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash4 - )AS age_commitment_hash4 -FROM exists; - -RETURN; -END $$; - - -CREATE OR REPLACE FUNCTION exchange_do_batch2_known_coin( - IN in_coin_pub1 BYTEA, - IN in_denom_pub_hash1 BYTEA, - IN in_h_age_commitment1 BYTEA, - IN in_denom_sig1 BYTEA, - IN in_coin_pub2 BYTEA, - IN in_denom_pub_hash2 BYTEA, - IN in_h_age_commitment2 BYTEA, - IN in_denom_sig2 BYTEA, - OUT existed1 BOOLEAN, - OUT existed2 BOOLEAN, - OUT known_coin_id1 INT8, - OUT known_coin_id2 INT8, - OUT denom_pub_hash1 BYTEA, - OUT denom_pub_hash2 BYTEA, - OUT age_commitment_hash1 BYTEA, - OUT age_commitment_hash2 BYTEA) -LANGUAGE plpgsql -AS $$ -BEGIN -WITH dd AS ( -SELECT - denominations_serial, - coin - FROM denominations - WHERE denom_pub_hash - IN - (in_denom_pub_hash1, - in_denom_pub_hash2) - ),--dd - input_rows AS ( - VALUES - (in_coin_pub1, - in_denom_pub_hash1, - in_h_age_commitment1, - in_denom_sig1), - (in_coin_pub2, - in_denom_pub_hash2, - in_h_age_commitment2, - in_denom_sig2) - ),--ir - ins AS ( - INSERT INTO known_coins ( - coin_pub, - denominations_serial, - age_commitment_hash, - denom_sig, - remaining - ) - SELECT - ir.coin_pub, - dd.denominations_serial, - ir.age_commitment_hash, - ir.denom_sig, - dd.coin - FROM input_rows ir - JOIN dd - ON dd.denom_pub_hash = ir.denom_pub_hash - ON CONFLICT DO NOTHING - RETURNING known_coin_id - ),--kc - exists AS ( - SELECT - CASE - WHEN ins.known_coin_id IS NOT NULL - THEN - FALSE - ELSE - TRUE - END AS existed, - ins.known_coin_id, - dd.denom_pub_hash, - kc.age_commitment_hash - FROM input_rows ir - LEFT JOIN ins - ON ins.coin_pub = ir.coin_pub - LEFT JOIN known_coins kc - ON kc.coin_pub = ir.coin_pub - LEFT JOIN dd - ON dd.denom_pub_hash = ir.denom_pub_hash - )--exists -SELECT - exists.existed AS existed1, - exists.known_coin_id AS known_coin_id1, - exists.denom_pub_hash AS denom_pub_hash1, - exists.age_commitment_hash AS age_commitment_hash1, - ( - SELECT exists.existed - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash2 - ) AS existed2, - ( - SELECT exists.known_coin_id - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash2 - ) AS known_coin_id2, - ( - SELECT exists.denom_pub_hash - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash2 - ) AS denom_pub_hash2, - ( - SELECT exists.age_commitment_hash - FROM exists - WHERE exists.denom_pub_hash = in_denom_pub_hash2 - )AS age_commitment_hash2 -FROM exists; - -RETURN; -END $$; - - -CREATE OR REPLACE FUNCTION exchange_do_batch1_known_coin( - IN in_coin_pub1 BYTEA, - IN in_denom_pub_hash1 BYTEA, - IN in_h_age_commitment1 BYTEA, - IN in_denom_sig1 BYTEA, - OUT existed1 BOOLEAN, - OUT known_coin_id1 INT8, - OUT denom_pub_hash1 BYTEA, - OUT age_commitment_hash1 BYTEA) -LANGUAGE plpgsql -AS $$ -BEGIN -WITH dd AS ( -SELECT - denominations_serial, - coin - FROM denominations - WHERE denom_pub_hash - IN - (in_denom_pub_hash1, - in_denom_pub_hash2) - ),--dd - input_rows AS ( - VALUES - (in_coin_pub1, - in_denom_pub_hash1, - in_h_age_commitment1, - in_denom_sig1) - ),--ir - ins AS ( - INSERT INTO known_coins ( - coin_pub, - denominations_serial, - age_commitment_hash, - denom_sig, - remaining - ) - SELECT - ir.coin_pub, - dd.denominations_serial, - ir.age_commitment_hash, - ir.denom_sig, - dd.coin - FROM input_rows ir - JOIN dd - ON dd.denom_pub_hash = ir.denom_pub_hash - ON CONFLICT DO NOTHING - RETURNING known_coin_id - ),--kc - exists AS ( - SELECT - CASE - WHEN ins.known_coin_id IS NOT NULL - THEN - FALSE - ELSE - TRUE - END AS existed, - ins.known_coin_id, - dd.denom_pub_hash, - kc.age_commitment_hash - FROM input_rows ir - LEFT JOIN ins - ON ins.coin_pub = ir.coin_pub - LEFT JOIN known_coins kc - ON kc.coin_pub = ir.coin_pub - LEFT JOIN dd - ON dd.denom_pub_hash = ir.denom_pub_hash - )--exists -SELECT - exists.existed AS existed1, - exists.known_coin_id AS known_coin_id1, - exists.denom_pub_hash AS denom_pub_hash1, - exists.age_commitment_hash AS age_commitment_hash1 -FROM exists; - -RETURN; -END $$; - -/*** Experiment using a loop ***/ -/* -CREATE OR REPLACE FUNCTION exchange_do_batch2_known_coin( - IN in_coin_pub1 BYTEA, - IN in_denom_pub_hash1 TEXT, - IN in_h_age_commitment1 TEXT, - IN in_denom_sig1 TEXT, - IN in_coin_pub2 BYTEA, - IN in_denom_pub_hash2 TEXT, - IN in_h_age_commitment2 TEXT, - IN in_denom_sig2 TEXT, - OUT existed1 BOOLEAN, - OUT existed2 BOOLEAN, - OUT known_coin_id1 INT8, - OUT known_coin_id2 INT8, - OUT denom_pub_hash1 TEXT, - OUT denom_pub_hash2 TEXT, - OUT age_commitment_hash1 TEXT, - OUT age_commitment_hash2 TEXT) -LANGUAGE plpgsql -AS $$ -DECLARE - ins_values RECORD; -BEGIN - FOR i IN 1..2 LOOP - ins_values := ( - SELECT - in_coin_pub1 AS coin_pub, - in_denom_pub_hash1 AS denom_pub_hash, - in_h_age_commitment1 AS age_commitment_hash, - in_denom_sig1 AS denom_sig - WHERE i = 1 - UNION - SELECT - in_coin_pub2 AS coin_pub, - in_denom_pub_hash2 AS denom_pub_hash, - in_h_age_commitment2 AS age_commitment_hash, - in_denom_sig2 AS denom_sig - WHERE i = 2 - ); - WITH dd (denominations_serial, coin) AS ( - SELECT denominations_serial, coin - FROM denominations - WHERE denom_pub_hash = ins_values.denom_pub_hash - ), - input_rows(coin_pub) AS ( - VALUES (ins_values.coin_pub) - ), - ins AS ( - INSERT INTO known_coins ( - coin_pub, - denominations_serial, - age_commitment_hash, - denom_sig, - remaining - ) SELECT - input_rows.coin_pub, - dd.denominations_serial, - ins_values.age_commitment_hash, - ins_values.denom_sig, - coin - FROM dd - CROSS JOIN input_rows - ON CONFLICT DO NOTHING - RETURNING known_coin_id, denom_pub_hash - ) - SELECT - CASE i - WHEN 1 THEN - COALESCE(ins.known_coin_id, 0) <> 0 AS existed1, - ins.known_coin_id AS known_coin_id1, - ins.denom_pub_hash AS denom_pub_hash1, - ins.age_commitment_hash AS age_commitment_hash1 - WHEN 2 THEN - COALESCE(ins.known_coin_id, 0) <> 0 AS existed2, - ins.known_coin_id AS known_coin_id2, - ins.denom_pub_hash AS denom_pub_hash2, - ins.age_commitment_hash AS age_commitment_hash2 - END - FROM ins; - END LOOP; -END; -$$;*/ diff --git a/src/exchangedb/do_refresh.sql b/src/exchangedb/do_refresh.sql @@ -77,10 +77,11 @@ out_coin_found = TRUE; out_coin_balance = known_coin.remaining; -- Next, check for idempotency -SELECT TRUE, noreveal_index -INTO out_idempotent, out_noreveal_index -FROM exchange.refresh -WHERE rc=in_rc; +SELECT noreveal_index + INTO out_noreveal_index + FROM exchange.refresh + WHERE rc=in_rc; +out_idempotent = FOUND; IF out_idempotent THEN @@ -91,7 +92,7 @@ THEN out_balance_ok = TRUE; out_zombie_bad = FALSE; -- zombie is OK out_nonce_reuse = FALSE; -RETURN; + RETURN; END IF; out_idempotent = FALSE; diff --git a/src/exchangedb/gc.sql b/src/exchangedb/gc.sql @@ -92,15 +92,15 @@ DELETE FROM denominations (SELECT DISTINCT coin_pub FROM recoup_refresh)); -DELETE FROM recoup_refresh - WHERE known_coin_id < coin_min; - SELECT known_coin_id INTO coin_min FROM known_coins ORDER BY known_coin_id ASC LIMIT 1; +DELETE FROM recoup_refresh + WHERE known_coin_id < coin_min; + SELECT batch_deposit_serial_id INTO batch_deposit_min FROM coin_deposits diff --git a/src/exchangedb/meson.build b/src/exchangedb/meson.build @@ -55,7 +55,6 @@ libtalerexchangedb = library( 'add_denomination_key.c', 'add_policy_fulfillment_proof.c', 'aggregate.c', - 'batch_ensure_coin_known.c', 'begin_revolving_shard.c', 'begin_shard.c', 'pg.c', diff --git a/src/exchangedb/persist_policy_details.sql b/src/exchangedb/persist_policy_details.sql @@ -94,7 +94,7 @@ BEGIN -- Set the fulfillment_state according to the values. -- For now, we only update the state when it was INSUFFICIENT. -- FIXME[oec] #7999: What to do in case of Failure or other state? - IF (out_fullfillment_state = 2) -- INSUFFICIENT + IF (out_fulfillment_state = 2) -- INSUFFICIENT THEN IF (out_accumulated_total.val >= cur_commitment.val OR (out_accumulated_total.val = cur_commitment.val AND diff --git a/src/exchangedb/select_aggregations_above_serial.sql b/src/exchangedb/select_aggregations_above_serial.sql @@ -53,6 +53,11 @@ LOOP my_batch_record FROM coin_deposits cdep WHERE cdep.batch_deposit_serial_id = i.batch_deposit_serial_id; + IF NOT FOUND + THEN + -- No matching deposit found, how can this be!? + RETURN; + END IF; my_total_val=my_batch_record.total_val; my_total_frac=my_batch_record.total_frac; diff --git a/src/exchangedb/sql-schema/exchange_statistics_helpers.sql b/src/exchangedb/sql-schema/exchange_statistics_helpers.sql @@ -921,7 +921,7 @@ BEGIN WHERE imeta_serial_id=my_meta AND h_payto=my_h_payto AND slot >= my_time - max_slot - AND slot < my_time - max_slot; + AND slot < my_time - min_slot; -- we only proceed if we had more then one match (optimization) IF FOUND AND my_sum.matches > 1 THEN @@ -934,11 +934,11 @@ BEGIN WHERE imeta_serial_id=my_meta AND h_payto=my_h_payto AND slot >= my_time - max_slot - AND slot < my_time - max_slot + AND slot < my_time - min_slot AND aevent_serial_id > my_sum.rep_serial_id; -- Now update the representative to the sum UPDATE exchange_statistic_amount_event SET - delta.val = my_total_value + delta.val = my_total_val ,delta.frac = my_total_frac WHERE imeta_serial_id = my_meta AND h_payto = my_h_payto @@ -987,12 +987,12 @@ BEGIN DELETE FROM exchange_statistic_bucket_amount WHERE bmeta_serial_id = my_rec.bmeta_serial_id - AND bucket_start >= my_end; + AND bucket_start < my_end; ELSE DELETE FROM exchange_statistic_bucket_counter WHERE bmeta_serial_id = my_rec.bmeta_serial_id - AND bucket_start >= my_end; + AND bucket_start < my_end; END IF; END LOOP; END $$; diff --git a/src/exchangedb/sql-schema/meson.build b/src/exchangedb/sql-schema/meson.build @@ -36,7 +36,6 @@ procedures_sql = [ '../reserves_in_insert.sql', # semi-dead... 'exchange_do_get_link_data.sql', - '../batch_ensure_coin_known.sql', '../kycauth_in_insert.sql', '../trigger_kyc_rule_for_account.sql', '../lookup_kyc_requirement_by_row.sql', @@ -191,4 +190,3 @@ foreach g : generated_sql install_dir: sqldir, ) endforeach -