-- -- 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 -- CREATE OR REPLACE FUNCTION exchange_do_reserve_purse( IN in_purse_pub BYTEA, IN in_merge_sig BYTEA, IN in_merge_timestamp INT8, IN in_reserve_expiration INT8, IN in_reserve_gc INT8, IN in_reserve_sig BYTEA, IN in_reserve_quota BOOLEAN, IN in_purse_fee taler_amount, IN in_reserve_pub BYTEA, IN in_wallet_h_payto BYTEA, OUT out_no_funds BOOLEAN, OUT out_no_reserve BOOLEAN, OUT out_conflict BOOLEAN) LANGUAGE plpgsql AS $$ BEGIN -- Store purse merge signature, checks for purse_pub uniqueness INSERT INTO purse_merges (partner_serial_id ,reserve_pub ,purse_pub ,merge_sig ,merge_timestamp) VALUES (NULL ,in_reserve_pub ,in_purse_pub ,in_merge_sig ,in_merge_timestamp) ON CONFLICT DO NOTHING; IF NOT FOUND THEN -- Idempotency check: see if an identical record exists. -- Note that by checking 'merge_sig', we implicitly check -- identity over everything that the signature covers. PERFORM FROM purse_merges WHERE purse_pub=in_purse_pub AND merge_sig=in_merge_sig; IF NOT FOUND THEN -- Purse was merged, but to some other reserve. Not allowed. out_conflict=TRUE; out_no_reserve=FALSE; out_no_funds=FALSE; RETURN; END IF; -- "success" out_conflict=FALSE; out_no_funds=FALSE; out_no_reserve=FALSE; RETURN; END IF; out_conflict=FALSE; PERFORM FROM exchange.reserves WHERE reserve_pub=in_reserve_pub; out_no_reserve = NOT FOUND; IF (in_reserve_quota) THEN -- Increment active purses per reserve (and check this is allowed) IF (out_no_reserve) THEN out_no_funds=TRUE; RETURN; END IF; UPDATE exchange.reserves SET purses_active=purses_active+1 WHERE reserve_pub=in_reserve_pub AND purses_active < purses_allowed; IF NOT FOUND THEN out_no_funds=TRUE; RETURN; END IF; ELSE -- UPDATE reserves balance (and check if balance is enough to pay the fee) IF (out_no_reserve) THEN IF ( (0 != in_purse_fee.val) OR (0 != in_purse_fee.frac) ) THEN out_no_funds=TRUE; RETURN; END IF; INSERT INTO exchange.reserves (reserve_pub ,expiration_date ,gc_date) VALUES (in_reserve_pub ,in_reserve_expiration ,in_reserve_gc); ELSE UPDATE exchange.reserves SET current_balance.frac=(current_balance).frac-in_purse_fee.frac + CASE WHEN (current_balance).frac < in_purse_fee.frac THEN 100000000 ELSE 0 END, current_balance.val=(current_balance).val-in_purse_fee.val - CASE WHEN (current_balance).frac < in_purse_fee.frac THEN 1 ELSE 0 END WHERE reserve_pub=in_reserve_pub AND ( ((current_balance).val > in_purse_fee.val) OR ( ((current_balance).frac >= in_purse_fee.frac) AND ((current_balance).val >= in_purse_fee.val) ) ); IF NOT FOUND THEN out_no_funds=TRUE; RETURN; END IF; END IF; END IF; out_no_funds=FALSE; -- Store account merge signature. INSERT INTO account_merges (reserve_pub ,reserve_sig ,purse_pub ,wallet_h_payto) VALUES (in_reserve_pub ,in_reserve_sig ,in_purse_pub ,in_wallet_h_payto); END $$; COMMENT ON FUNCTION exchange_do_reserve_purse(BYTEA, BYTEA, INT8, INT8, INT8, BYTEA, BOOLEAN, taler_amount, BYTEA, BYTEA) IS 'Create a purse for a reserve.';