exchange

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

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 $$;