exchange_do_melt.sql (4709B)
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 18 19 20 CREATE OR REPLACE FUNCTION exchange_do_melt( 21 IN in_cs_rms BYTEA, 22 IN in_amount_with_fee taler_amount, 23 IN in_rc BYTEA, 24 IN in_old_coin_pub BYTEA, 25 IN in_old_coin_sig BYTEA, 26 IN in_known_coin_id INT8, -- not used, but that's OK 27 IN in_noreveal_index INT4, 28 IN in_zombie_required BOOLEAN, 29 OUT out_balance_ok BOOLEAN, 30 OUT out_zombie_bad BOOLEAN, 31 OUT out_noreveal_index INT4) 32 LANGUAGE plpgsql 33 AS $$ 34 DECLARE 35 denom_max INT8; 36 BEGIN 37 -- Shards: INSERT refresh_commitments (by rc) 38 -- (rare:) SELECT refresh_commitments (by old_coin_pub) -- crosses shards! 39 -- (rare:) SEELCT refresh_revealed_coins (by melt_serial_id) 40 -- (rare:) PERFORM recoup_refresh (by rrc_serial) -- crosses shards! 41 -- UPDATE known_coins (by coin_pub) 42 43 INSERT INTO exchange.refresh_commitments 44 (rc 45 ,old_coin_pub 46 ,old_coin_sig 47 ,amount_with_fee 48 ,noreveal_index 49 ) 50 VALUES 51 (in_rc 52 ,in_old_coin_pub 53 ,in_old_coin_sig 54 ,in_amount_with_fee 55 ,in_noreveal_index) 56 ON CONFLICT DO NOTHING; 57 58 IF NOT FOUND 59 THEN 60 -- Idempotency check: see if an identical record exists. 61 out_noreveal_index=-1; 62 SELECT 63 noreveal_index 64 INTO 65 out_noreveal_index 66 FROM exchange.refresh_commitments 67 WHERE rc=in_rc; 68 out_balance_ok=FOUND; 69 out_zombie_bad=FALSE; -- zombie is OK 70 RETURN; 71 END IF; 72 73 74 IF in_zombie_required 75 THEN 76 -- Check if this coin was part of a refresh 77 -- operation that was subsequently involved 78 -- in a recoup operation. We begin by all 79 -- refresh operations our coin was involved 80 -- with, then find all associated reveal 81 -- operations, and then see if any of these 82 -- reveal operations was involved in a recoup. 83 PERFORM 84 FROM recoup_refresh 85 WHERE rrc_serial IN 86 (SELECT rrc_serial 87 FROM refresh_revealed_coins 88 WHERE melt_serial_id IN 89 (SELECT melt_serial_id 90 FROM refresh_commitments 91 WHERE old_coin_pub=in_old_coin_pub)); 92 IF NOT FOUND 93 THEN 94 out_zombie_bad=TRUE; 95 out_balance_ok=FALSE; 96 RETURN; 97 END IF; 98 END IF; 99 100 out_zombie_bad=FALSE; -- zombie is OK 101 102 103 -- Check and update balance of the coin. 104 UPDATE known_coins kc 105 SET 106 remaining.frac=(kc.remaining).frac-in_amount_with_fee.frac 107 + CASE 108 WHEN (kc.remaining).frac < in_amount_with_fee.frac 109 THEN 100000000 110 ELSE 0 111 END, 112 remaining.val=(kc.remaining).val-in_amount_with_fee.val 113 - CASE 114 WHEN (kc.remaining).frac < in_amount_with_fee.frac 115 THEN 1 116 ELSE 0 117 END 118 WHERE coin_pub=in_old_coin_pub 119 AND ( ((kc.remaining).val > in_amount_with_fee.val) OR 120 ( ((kc.remaining).frac >= in_amount_with_fee.frac) AND 121 ((kc.remaining).val >= in_amount_with_fee.val) ) ); 122 123 IF NOT FOUND 124 THEN 125 -- Insufficient balance. 126 out_noreveal_index=-1; 127 out_balance_ok=FALSE; 128 RETURN; 129 END IF; 130 131 132 133 -- Special actions needed for a CS melt? 134 IF in_cs_rms IS NOT NULL 135 THEN 136 -- Get maximum denominations serial value in 137 -- existence, this will determine how long the 138 -- nonce will be locked. 139 SELECT 140 denominations_serial 141 INTO 142 denom_max 143 FROM exchange.denominations 144 ORDER BY denominations_serial DESC 145 LIMIT 1; 146 147 -- Cache CS signature to prevent replays in the future 148 -- (and check if cached signature exists at the same time). 149 INSERT INTO exchange.cs_nonce_locks 150 (nonce 151 ,max_denomination_serial 152 ,op_hash) 153 VALUES 154 (in_cs_rms 155 ,denom_max 156 ,in_rc) 157 ON CONFLICT DO NOTHING; 158 159 IF NOT FOUND 160 THEN 161 -- Record exists, make sure it is the same 162 SELECT 1 163 FROM exchange.cs_nonce_locks 164 WHERE nonce=in_cs_rms 165 AND op_hash=in_rc; 166 167 IF NOT FOUND 168 THEN 169 -- Nonce reuse detected 170 out_balance_ok=FALSE; 171 out_zombie_bad=FALSE; 172 out_noreveal_index=42; -- FIXME: return error message more nicely! 173 ASSERT false, 'nonce reuse attempted by client'; 174 END IF; 175 END IF; 176 END IF; 177 178 -- Everything fine, return success! 179 out_balance_ok=TRUE; 180 out_noreveal_index=in_noreveal_index; 181 182 END $$;