get_pending_aggregation.c (6302B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2026 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file src/exchangedb/get_pending_aggregation.c 18 * @brief Implementation of the get_pending_aggregation function for Postgres 19 * @author Christian Grothoff 20 */ 21 #include "taler/taler_pq_lib.h" 22 #include "helper.h" 23 #include "exchange-database/get_pending_aggregation.h" 24 25 26 enum GNUNET_DB_QueryStatus 27 TALER_EXCHANGEDB_get_pending_aggregation ( 28 struct TALER_EXCHANGEDB_PostgresContext *pg, 29 const struct TALER_WireTransferIdentifierRawP *wtid, 30 struct TALER_FullPaytoHashP *wire_target_h_payto, 31 struct TALER_FullPayto *payto_uri, 32 struct TALER_Amount *total_deposited, 33 struct TALER_Amount *total_refunded, 34 struct TALER_Amount *total_deposit_fee) 35 { 36 struct GNUNET_PQ_QueryParam params[] = { 37 GNUNET_PQ_query_param_auto_from_type (wtid), 38 GNUNET_PQ_query_param_end 39 }; 40 struct GNUNET_PQ_ResultSpec rs[] = { 41 GNUNET_PQ_result_spec_auto_from_type ("wire_target_h_payto", 42 wire_target_h_payto), 43 GNUNET_PQ_result_spec_string ("payto_uri", 44 &payto_uri->full_payto), 45 TALER_PQ_RESULT_SPEC_AMOUNT ("total_deposited", 46 total_deposited), 47 TALER_PQ_RESULT_SPEC_AMOUNT ("total_refunded", 48 total_refunded), 49 TALER_PQ_RESULT_SPEC_AMOUNT ("total_deposit_fee", 50 total_deposit_fee), 51 GNUNET_PQ_result_spec_end 52 }; 53 54 /* This mirrors the arithmetic of `exchange_do_aggregate' (see 55 do_aggregate.c) so that the result can be compared with what the exchange 56 itself computed. The one subtlety worth preserving is 57 `fully_refunded_coins': the exchange does not keep the deposit fee of a 58 coin whose deposit was refunded in full, so neither may we. 59 60 The `NOT EXISTS' on wire_out is what makes this a *pending* aggregation; 61 once the transfer is executed the query returns no rows and the caller 62 drops the hold. */ 63 PREPARE (pg, 64 "get_pending_aggregation", 65 "WITH bd AS (" 66 " SELECT bdep.batch_deposit_serial_id" 67 " ,bdep.wire_target_h_payto" 68 " FROM aggregation_tracking atr" 69 " JOIN batch_deposits bdep" 70 " USING (batch_deposit_serial_id)" 71 " WHERE atr.wtid_raw=$1)" 72 " ,cd AS (" 73 " SELECT cdep.coin_pub" 74 " ,cdep.batch_deposit_serial_id" 75 " ,cdep.amount_with_fee AS amount" 76 " FROM coin_deposits cdep" 77 " WHERE cdep.batch_deposit_serial_id IN" 78 " (SELECT batch_deposit_serial_id FROM bd))" 79 " ,ref AS (" 80 " SELECT r.amount_with_fee AS refund" 81 " ,r.coin_pub" 82 " ,r.batch_deposit_serial_id" 83 " FROM refunds r" 84 " WHERE r.batch_deposit_serial_id IN" 85 " (SELECT batch_deposit_serial_id FROM bd))" 86 " ,ref_by_coin AS (" 87 " SELECT SUM((ref.refund).val) AS sum_val" 88 " ,SUM((ref.refund).frac) AS sum_frac" 89 " ,coin_pub" 90 " ,batch_deposit_serial_id" 91 " FROM ref" 92 " GROUP BY coin_pub, batch_deposit_serial_id)" 93 " ,fully_refunded_coins AS (" 94 " SELECT cd.coin_pub" 95 " ,cd.batch_deposit_serial_id" 96 " FROM ref_by_coin n" 97 " JOIN cd" 98 " ON (n.coin_pub = cd.coin_pub" 99 " AND n.batch_deposit_serial_id = cd.batch_deposit_serial_id" 100 " AND n.sum_val + n.sum_frac / 100000000 = (cd.amount).val" 101 " AND n.sum_frac % 100000000 = (cd.amount).frac))" 102 " ,fees AS (" 103 " SELECT denom.fee_deposit AS fee" 104 " FROM cd" 105 " JOIN known_coins kc" 106 " USING (coin_pub)" 107 " JOIN denominations denom" 108 " USING (denominations_serial)" 109 " WHERE (cd.coin_pub, cd.batch_deposit_serial_id) NOT IN" 110 " (SELECT coin_pub, batch_deposit_serial_id" 111 " FROM fully_refunded_coins))" 112 "SELECT" 113 " (SELECT wire_target_h_payto FROM bd LIMIT 1)" 114 " AS wire_target_h_payto" 115 " ,(SELECT wt.payto_uri" 116 " FROM wire_targets wt" 117 " WHERE wt.wire_target_h_payto=" 118 " (SELECT wire_target_h_payto FROM bd LIMIT 1))" 119 " AS payto_uri" 120 " ,ROW(COALESCE(SUM((cd.amount).val),0)" 121 " + COALESCE(SUM((cd.amount).frac),0) / 100000000" 122 " ,COALESCE(SUM((cd.amount).frac),0) % 100000000)::taler_amount" 123 " AS total_deposited" 124 " ,(SELECT ROW(COALESCE(SUM((ref.refund).val),0)" 125 " + COALESCE(SUM((ref.refund).frac),0) / 100000000" 126 " ,COALESCE(SUM((ref.refund).frac),0)" 127 " % 100000000)::taler_amount" 128 " FROM ref)" 129 " AS total_refunded" 130 " ,(SELECT ROW(COALESCE(SUM((fees.fee).val),0)" 131 " + COALESCE(SUM((fees.fee).frac),0) / 100000000" 132 " ,COALESCE(SUM((fees.fee).frac),0)" 133 " % 100000000)::taler_amount" 134 " FROM fees)" 135 " AS total_deposit_fee" 136 " FROM cd" 137 " WHERE NOT EXISTS (" 138 " SELECT 1 FROM wire_out wo WHERE wo.wtid_raw=$1)" 139 " HAVING COUNT(*) > 0;"); 140 return GNUNET_PQ_eval_prepared_singleton_select ( 141 pg->conn, 142 "get_pending_aggregation", 143 params, 144 rs); 145 }