exchange_do_reserve_open.sql (5946B)
1 -- 2 -- This file is part of TALER 3 -- Copyright (C) 2014--2022 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 CREATE OR REPLACE FUNCTION exchange_do_reserve_open( 18 IN in_reserve_pub BYTEA, 19 IN in_total_paid taler_amount, 20 IN in_reserve_payment taler_amount, 21 IN in_min_purse_limit INT4, 22 IN in_default_purse_limit INT4, 23 IN in_reserve_sig BYTEA, 24 IN in_desired_expiration INT8, 25 IN in_reserve_gc_delay INT8, 26 IN in_now INT8, 27 IN in_open_fee taler_amount, 28 OUT out_open_cost taler_amount, 29 OUT out_final_expiration INT8, 30 OUT out_no_reserve BOOLEAN, 31 OUT out_no_funds BOOLEAN, 32 OUT out_reserve_balance taler_amount) 33 LANGUAGE plpgsql 34 AS $$ 35 DECLARE 36 my_balance taler_amount; 37 my_cost taler_amount; 38 my_cost_tmp INT8; 39 my_years_tmp INT4; 40 my_years INT4; 41 my_needs_update BOOL; 42 my_expiration_date INT8; 43 reserve RECORD; 44 BEGIN 45 46 SELECT current_balance 47 ,expiration_date 48 ,purses_allowed 49 INTO reserve 50 FROM reserves 51 WHERE reserve_pub=in_reserve_pub; 52 53 IF NOT FOUND 54 THEN 55 RAISE NOTICE 'reserve not found'; 56 out_no_reserve = TRUE; 57 out_no_funds = TRUE; 58 out_reserve_balance.val = 0; 59 out_reserve_balance.frac = 0; 60 out_open_cost.val = 0; 61 out_open_cost.frac = 0; 62 out_final_expiration = 0; 63 RETURN; 64 END IF; 65 66 out_no_reserve = FALSE; 67 out_reserve_balance = reserve.current_balance; 68 69 -- Do not allow expiration time to start in the past already 70 IF (reserve.expiration_date < in_now) 71 THEN 72 my_expiration_date = in_now; 73 ELSE 74 my_expiration_date = reserve.expiration_date; 75 END IF; 76 77 my_cost.val = 0; 78 my_cost.frac = 0; 79 my_needs_update = FALSE; 80 my_years = 0; 81 82 -- Compute years based on desired expiration time 83 IF (my_expiration_date < in_desired_expiration) 84 THEN 85 my_years = (31535999999999 + in_desired_expiration - my_expiration_date) / 31536000000000; 86 reserve.purses_allowed = in_default_purse_limit; 87 my_expiration_date = my_expiration_date + 31536000000000 * my_years; 88 END IF; 89 90 -- Increase years based on purses requested 91 IF (reserve.purses_allowed < in_min_purse_limit) 92 THEN 93 my_years = (31535999999999 + in_desired_expiration - in_now) / 31536000000000; 94 my_expiration_date = in_now + 31536000000000 * my_years; 95 my_years_tmp = (in_min_purse_limit + in_default_purse_limit - reserve.purses_allowed - 1) / in_default_purse_limit; 96 my_years = my_years + my_years_tmp; 97 reserve.purses_allowed = reserve.purses_allowed + (in_default_purse_limit * my_years_tmp); 98 END IF; 99 100 101 -- Compute cost based on annual fees 102 IF (my_years > 0) 103 THEN 104 my_cost.val = my_years * in_open_fee.val; 105 my_cost_tmp = my_years * in_open_fee.frac / 100000000; 106 IF (CAST (my_cost.val + my_cost_tmp AS INT8) < my_cost.val) 107 THEN 108 out_open_cost.val=9223372036854775807; 109 out_open_cost.frac=2147483647; 110 out_final_expiration=my_expiration_date; 111 out_no_funds=FALSE; 112 RAISE NOTICE 'arithmetic issue computing amount'; 113 RETURN; 114 END IF; 115 my_cost.val = CAST (my_cost.val + my_cost_tmp AS INT8); 116 my_cost.frac = my_years * in_open_fee.frac % 100000000; 117 my_needs_update = TRUE; 118 END IF; 119 120 -- check if we actually have something to do 121 IF NOT my_needs_update 122 THEN 123 out_final_expiration = reserve.expiration_date; 124 out_open_cost.val = 0; 125 out_open_cost.frac = 0; 126 out_no_funds=FALSE; 127 RAISE NOTICE 'no change required'; 128 RETURN; 129 END IF; 130 131 -- Check payment (coins and reserve) would be sufficient. 132 IF ( (in_total_paid.val < my_cost.val) OR 133 ( (in_total_paid.val = my_cost.val) AND 134 (in_total_paid.frac < my_cost.frac) ) ) 135 THEN 136 out_open_cost.val = my_cost.val; 137 out_open_cost.frac = my_cost.frac; 138 out_no_funds=FALSE; 139 -- We must return a failure, which is indicated by 140 -- the expiration being below the desired expiration. 141 IF (reserve.expiration_date >= in_desired_expiration) 142 THEN 143 -- This case is relevant especially if the purse 144 -- count was to be increased and the payment was 145 -- insufficient to cover this for the full period. 146 RAISE NOTICE 'forcing low expiration time'; 147 out_final_expiration = 0; 148 ELSE 149 out_final_expiration = reserve.expiration_date; 150 END IF; 151 RAISE NOTICE 'amount paid too low'; 152 RETURN; 153 END IF; 154 155 -- Check reserve balance is sufficient. 156 IF (out_reserve_balance.val > in_reserve_payment.val) 157 THEN 158 IF (out_reserve_balance.frac >= in_reserve_payment.frac) 159 THEN 160 my_balance.val=out_reserve_balance.val - in_reserve_payment.val; 161 my_balance.frac=out_reserve_balance.frac - in_reserve_payment.frac; 162 ELSE 163 my_balance.val=out_reserve_balance.val - in_reserve_payment.val - 1; 164 my_balance.frac=out_reserve_balance.frac + 100000000 - in_reserve_payment.frac; 165 END IF; 166 ELSE 167 IF (out_reserve_balance.val = in_reserve_payment.val) AND (out_reserve_balance.frac >= in_reserve_payment.frac) 168 THEN 169 my_balance.val=0; 170 my_balance.frac=out_reserve_balance.frac - in_reserve_payment.frac; 171 ELSE 172 out_final_expiration = reserve.expiration_date; 173 out_open_cost.val = my_cost.val; 174 out_open_cost.frac = my_cost.frac; 175 out_no_funds=TRUE; 176 RAISE NOTICE 'reserve balance too low'; 177 RETURN; 178 END IF; 179 END IF; 180 181 UPDATE reserves SET 182 current_balance=my_balance 183 ,gc_date=reserve.expiration_date + in_reserve_gc_delay 184 ,expiration_date=my_expiration_date 185 ,purses_allowed=reserve.purses_allowed 186 WHERE 187 reserve_pub=in_reserve_pub; 188 189 out_final_expiration=my_expiration_date; 190 out_open_cost = my_cost; 191 out_no_funds=FALSE; 192 RETURN; 193 194 END $$;