-- -- 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_deposit( IN in_amount_with_fee taler_amount, IN in_h_contract_terms BYTEA, IN in_wire_salt BYTEA, IN in_wallet_timestamp INT8, IN in_exchange_timestamp INT8, IN in_refund_deadline INT8, IN in_wire_deadline INT8, IN in_merchant_pub BYTEA, IN in_receiver_wire_account TEXT, IN in_h_payto BYTEA, IN in_known_coin_id INT8, IN in_coin_pub BYTEA, IN in_coin_sig BYTEA, IN in_shard INT8, IN in_policy_blocked BOOLEAN, IN in_policy_details_serial_id INT8, OUT out_exchange_timestamp INT8, OUT out_balance_ok BOOLEAN, OUT out_conflict BOOLEAN) LANGUAGE plpgsql AS $$ DECLARE wtsi INT8; -- wire target serial id BEGIN -- Shards: INSERT policy_details (by policy_details_serial_id) -- INSERT wire_targets (by h_payto), on CONFLICT DO NOTHING; -- INSERT deposits (by coin_pub, shard), ON CONFLICT DO NOTHING; -- UPDATE known_coins (by coin_pub) INSERT INTO exchange.wire_targets (wire_target_h_payto ,payto_uri) VALUES (in_h_payto ,in_receiver_wire_account) ON CONFLICT DO NOTHING -- for CONFLICT ON (wire_target_h_payto) RETURNING wire_target_serial_id INTO wtsi; IF NOT FOUND THEN SELECT wire_target_serial_id INTO wtsi FROM exchange.wire_targets WHERE wire_target_h_payto=in_h_payto; END IF; INSERT INTO exchange.deposits (shard ,coin_pub ,known_coin_id ,amount_with_fee ,wallet_timestamp ,exchange_timestamp ,refund_deadline ,wire_deadline ,merchant_pub ,h_contract_terms ,coin_sig ,wire_salt ,wire_target_h_payto ,policy_blocked ,policy_details_serial_id ) VALUES (in_shard ,in_coin_pub ,in_known_coin_id ,in_amount_with_fee ,in_wallet_timestamp ,in_exchange_timestamp ,in_refund_deadline ,in_wire_deadline ,in_merchant_pub ,in_h_contract_terms ,in_coin_sig ,in_wire_salt ,in_h_payto ,in_policy_blocked ,in_policy_details_serial_id) ON CONFLICT DO NOTHING; IF NOT FOUND THEN -- Idempotency check: see if an identical record exists. -- Note that by checking 'coin_sig', we implicitly check -- identity over everything that the signature covers. -- We do select over merchant_pub and wire_target_h_payto -- primarily here to maximally use the existing index. SELECT exchange_timestamp INTO out_exchange_timestamp FROM exchange.deposits WHERE shard=in_shard AND merchant_pub=in_merchant_pub AND wire_target_h_payto=in_h_payto AND coin_pub=in_coin_pub AND coin_sig=in_coin_sig; -- AND policy_details_serial_id=in_policy_details_serial_id; -- FIXME: is this required for idempotency? IF NOT FOUND THEN -- Deposit exists, but with differences. Not allowed. out_balance_ok=FALSE; out_conflict=TRUE; out_exchange_timestamp=0; RETURN; END IF; -- Idempotent request known, return success. out_balance_ok=TRUE; out_conflict=FALSE; RETURN; END IF; out_exchange_timestamp=in_exchange_timestamp; -- Check and update balance of the coin. UPDATE known_coins kc SET remaining.frac=(kc.remaining).frac-in_amount_with_fee.frac + CASE WHEN (kc.remaining).frac < in_amount_with_fee.frac THEN 100000000 ELSE 0 END, remaining.val=(kc.remaining).val-in_amount_with_fee.val - CASE WHEN (kc.remaining).frac < in_amount_with_fee.frac THEN 1 ELSE 0 END WHERE coin_pub=in_coin_pub AND ( ((kc.remaining).val > in_amount_with_fee.val) OR ( ((kc.remaining).frac >= in_amount_with_fee.frac) AND ((kc.remaining).val >= in_amount_with_fee.val) ) ); IF NOT FOUND THEN -- Insufficient balance. out_balance_ok=FALSE; out_conflict=FALSE; RETURN; END IF; -- Everything fine, return success! out_balance_ok=TRUE; out_conflict=FALSE; END $$;