summaryrefslogtreecommitdiff
path: root/src/exchangedb/exchange_do_deposit.sql
diff options
context:
space:
mode:
Diffstat (limited to 'src/exchangedb/exchange_do_deposit.sql')
-rw-r--r--src/exchangedb/exchange_do_deposit.sql229
1 files changed, 132 insertions, 97 deletions
diff --git a/src/exchangedb/exchange_do_deposit.sql b/src/exchangedb/exchange_do_deposit.sql
index a2f5ba53a..c89e9e470 100644
--- a/src/exchangedb/exchange_do_deposit.sql
+++ b/src/exchangedb/exchange_do_deposit.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 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
@@ -14,158 +14,193 @@
-- 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,
+ -- For batch_deposits
+ IN in_shard INT8,
+ IN in_merchant_pub 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_h_contract_terms BYTEA,
+ IN in_wallet_data_hash BYTEA, -- can be NULL
+ IN in_wire_salt BYTEA,
+ IN in_wire_target_h_payto BYTEA,
+ IN in_policy_details_serial_id INT8, -- can be NULL
IN in_policy_blocked BOOLEAN,
- IN in_policy_details_serial_id INT8,
+ -- For wire_targets
+ IN in_receiver_wire_account TEXT,
+ -- For coin_deposits
+ IN ina_coin_pub BYTEA[],
+ IN ina_coin_sig BYTEA[],
+ IN ina_amount_with_fee taler_amount[],
OUT out_exchange_timestamp INT8,
- OUT out_balance_ok BOOLEAN,
- OUT out_conflict BOOLEAN)
+ OUT out_insufficient_balance_coin_index INT4, -- index of coin with bad balance, NULL if none
+ OUT out_conflict BOOL
+ )
LANGUAGE plpgsql
AS $$
DECLARE
wtsi INT8; -- wire target serial id
+ bdsi INT8; -- batch_deposits serial id
+ i INT4;
+ ini_amount_with_fee taler_amount;
+ ini_coin_pub BYTEA;
+ ini_coin_sig BYTEA;
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)
+-- Shards:
+-- INSERT wire_targets (by h_payto), ON CONFLICT DO NOTHING;
+-- INSERT batch_deposits (by shard, merchant_pub), ON CONFLICT idempotency check;
+-- INSERT[] coin_deposits (by coin_pub), ON CONFLICT idempotency check;
+-- UPDATE[] known_coins (by coin_pub)
+
-INSERT INTO exchange.wire_targets
- (wire_target_h_payto
- ,payto_uri)
+-- First, get or create the 'wtsi'
+INSERT INTO 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;
+ (in_wire_target_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;
+ SELECT
+ wire_target_serial_id
+ INTO
+ wtsi
+ FROM wire_targets
+ WHERE
+ wire_target_h_payto=in_wire_target_h_payto;
END IF;
-INSERT INTO exchange.deposits
+-- Second, create the batch_deposits entry
+INSERT INTO batch_deposits
(shard
- ,coin_pub
- ,known_coin_id
- ,amount_with_fee_val
- ,amount_with_fee_frac
+ ,merchant_pub
,wallet_timestamp
,exchange_timestamp
,refund_deadline
,wire_deadline
- ,merchant_pub
,h_contract_terms
- ,coin_sig
+ ,wallet_data_hash
,wire_salt
,wire_target_h_payto
- ,policy_blocked
,policy_details_serial_id
+ ,policy_blocked
)
VALUES
(in_shard
- ,in_coin_pub
- ,in_known_coin_id
- ,in_amount_with_fee_val
- ,in_amount_with_fee_frac
+ ,in_merchant_pub
,in_wallet_timestamp
,in_exchange_timestamp
,in_refund_deadline
,in_wire_deadline
- ,in_merchant_pub
,in_h_contract_terms
- ,in_coin_sig
+ ,in_wallet_data_hash
,in_wire_salt
- ,in_h_payto
- ,in_policy_blocked
- ,in_policy_details_serial_id)
- ON CONFLICT DO NOTHING;
+ ,in_wire_target_h_payto
+ ,in_policy_details_serial_id
+ ,in_policy_blocked)
+ ON CONFLICT DO NOTHING -- for CONFLICT ON (merchant_pub, h_contract_terms)
+ RETURNING
+ batch_deposit_serial_id
+ INTO
+ bdsi;
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.
+ -- We do select over merchant_pub, h_contract_terms and wire_target_h_payto
+ -- first to maximally increase the chance of using the existing index.
SELECT
- exchange_timestamp
+ exchange_timestamp
+ ,batch_deposit_serial_id
INTO
- out_exchange_timestamp
- FROM exchange.deposits
+ out_exchange_timestamp
+ ,bdsi
+ FROM batch_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?
-
+ AND h_contract_terms=in_h_contract_terms
+ AND wire_target_h_payto=in_wire_target_h_payto
+ -- now check the rest, too
+ AND ( (wallet_data_hash=in_wallet_data_hash) OR
+ (wallet_data_hash IS NULL AND in_wallet_data_hash IS NULL) )
+ AND wire_salt=in_wire_salt
+ AND wallet_timestamp=in_wallet_timestamp
+ AND refund_deadline=in_refund_deadline
+ AND wire_deadline=in_wire_deadline
+ AND ( (policy_details_serial_id=in_policy_details_serial_id) OR
+ (policy_details_serial_id IS NULL AND in_policy_details_serial_id IS NULL) );
IF NOT FOUND
THEN
- -- Deposit exists, but with differences. Not allowed.
- out_balance_ok=FALSE;
+ -- Deposit exists, but with *strange* differences. Not allowed.
out_conflict=TRUE;
RETURN;
END IF;
+END IF;
- -- Idempotent request known, return success.
- out_balance_ok=TRUE;
- out_conflict=FALSE;
+out_conflict=FALSE;
- RETURN;
-END IF;
+-- Deposit each coin
+FOR i IN 1..array_length(ina_coin_pub,1)
+LOOP
+ ini_coin_pub = ina_coin_pub[i];
+ ini_coin_sig = ina_coin_sig[i];
+ ini_amount_with_fee = ina_amount_with_fee[i];
-out_exchange_timestamp=in_exchange_timestamp;
+ INSERT INTO coin_deposits
+ (batch_deposit_serial_id
+ ,coin_pub
+ ,coin_sig
+ ,amount_with_fee
+ )
+ VALUES
+ (bdsi
+ ,ini_coin_pub
+ ,ini_coin_sig
+ ,ini_amount_with_fee
+ )
+ ON CONFLICT DO NOTHING;
--- 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 FOUND
+ THEN
+ -- Insert did happen, update balance in known_coins!
-IF NOT FOUND
-THEN
- -- Insufficient balance.
- out_balance_ok=FALSE;
- out_conflict=FALSE;
- RETURN;
-END IF;
+ UPDATE known_coins kc
+ SET
+ remaining.frac=(kc.remaining).frac-ini_amount_with_fee.frac
+ + CASE
+ WHEN (kc.remaining).frac < ini_amount_with_fee.frac
+ THEN 100000000
+ ELSE 0
+ END,
+ remaining.val=(kc.remaining).val-ini_amount_with_fee.val
+ - CASE
+ WHEN (kc.remaining).frac < ini_amount_with_fee.frac
+ THEN 1
+ ELSE 0
+ END
+ WHERE coin_pub=ini_coin_pub
+ AND ( ((kc.remaining).val > ini_amount_with_fee.val) OR
+ ( ((kc.remaining).frac >= ini_amount_with_fee.frac) AND
+ ((kc.remaining).val >= ini_amount_with_fee.val) ) );
--- Everything fine, return success!
-out_balance_ok=TRUE;
-out_conflict=FALSE;
+ IF NOT FOUND
+ THEN
+ -- Insufficient balance.
+ -- Note: C arrays are 0 indexed, but i started at 1
+ out_insufficient_balance_coin_index=i-1;
+ RETURN;
+ END IF;
+ END IF;
+END LOOP; -- end FOR all coins
END $$;