exchange/src/exchangedb/exchange_do_deposit.sql
2022-12-06 13:29:23 +01:00

172 lines
4.4 KiB
PL/PgSQL

--
-- 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 <http://www.gnu.org/licenses/>
--
CREATE OR REPLACE FUNCTION exchange_do_deposit(
IN in_amount_with_fee_val INT8,
IN in_amount_with_fee_frac INT4,
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 VARCHAR,
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_val
,amount_with_fee_frac
,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_val
,in_amount_with_fee_frac
,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;
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
SET
remaining_frac=remaining_frac-in_amount_with_fee_frac
+ CASE
WHEN remaining_frac < in_amount_with_fee_frac
THEN 100000000
ELSE 0
END,
remaining_val=remaining_val-in_amount_with_fee_val
- CASE
WHEN remaining_frac < in_amount_with_fee_frac
THEN 1
ELSE 0
END
WHERE coin_pub=in_coin_pub
AND ( (remaining_val > in_amount_with_fee_val) OR
( (remaining_frac >= in_amount_with_fee_frac) AND
(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 $$;