taler-rust

GNU Taler code in Rust. Largely core banking integrations.
Log | Files | Refs | Submodules | README | LICENSE

commit 16b9ff784bda6409ded13a8cfb3d0ce1b0c759b0
parent 7edc32c25b781cab5937bfa7fe97ca6665c0eb49
Author: Antoine A <>
Date:   Tue, 13 Oct 2026 11:17:13 +0200

common: lock for commit ordered ids

Diffstat:
Madapters/taler-cyclos/db/cyclos-procedures.sql | 37+++++++++++++++++++++----------------
Madapters/taler-magnet-bank/db/magnet-bank-procedures.sql | 37+++++++++++++++++++++----------------
Madapters/taler-wise/db/wise-procedures.sql | 47+++++++++++++++++++++++------------------------
Mcommon/taler-api/db/taler-api-procedures.sql | 36++++++++++++++++++++----------------
4 files changed, 85 insertions(+), 72 deletions(-)

diff --git a/adapters/taler-cyclos/db/cyclos-procedures.sql b/adapters/taler-cyclos/db/cyclos-procedures.sql @@ -99,6 +99,8 @@ END IF; -- Insert new incoming transaction out_valued_at = in_valued_at; +-- Lock for revenue id commit ordering +LOCK TABLE tx_in IN SHARE ROW EXCLUSIVE MODE; INSERT INTO tx_in ( transfer_id, tx_id, @@ -132,6 +134,8 @@ ELSIF in_type IS NOT NULL THEN WHERE ( tx_in_id IS NULL AND account_pub = in_metadata AND in_type=type AND type='reserve' ) OR authorization_pub = local_authorization_pub; + -- Lock for incoming history id commit ordering + LOCK TABLE taler_in IN SHARE ROW EXCLUSIVE MODE; -- Insert new incoming talerable transaction INSERT INTO taler_in ( tx_in_id, @@ -180,6 +184,8 @@ IF FOUND THEN RETURN; END IF; +-- Lock for revenue and incoming history id commit ordering +LOCK TABLE tx_out IN SHARE ROW EXCLUSIVE MODE; -- Insert new outgoing transaction INSERT INTO tx_out ( transfer_id, @@ -320,6 +326,7 @@ IF out_wtid_reuse THEN END IF; -- Insert an initiated outgoing transaction out_initiated_at = in_now; +LOCK TABLE transfer IN SHARE ROW EXCLUSIVE MODE; INSERT INTO initiated ( amount, subject, @@ -456,24 +463,22 @@ IF out_reserve_pub_reuse THEN END IF; IF in_recurrent THEN - -- Finalize one pending right now - WITH moved_tx AS ( - DELETE FROM pending_recurrent_in - WHERE tx_in_id = ( - SELECT tx_in_id - FROM pending_recurrent_in - JOIN tx_in USING (tx_in_id) - WHERE authorization_pub = in_authorization_pub - ORDER BY registered_at ASC - LIMIT 1 - ) - RETURNING tx_in_id + -- Finalize one pending right now. Lock history only if there is a row to publish. + DELETE FROM pending_recurrent_in + WHERE tx_in_id = ( + SELECT tx_in_id + FROM pending_recurrent_in + JOIN tx_in USING (tx_in_id) + WHERE authorization_pub = in_authorization_pub + ORDER BY registered_at ASC + LIMIT 1 ) - INSERT INTO taler_in (tx_in_id, type, metadata, authorization_pub, authorization_sig) - SELECT moved_tx.tx_in_id, in_type, in_account_pub, in_authorization_pub, in_authorization_sig - FROM moved_tx - RETURNING tx_in_id, taler_in_id INTO talerable_tx, local_taler_in_id; + RETURNING tx_in_id INTO talerable_tx; IF talerable_tx IS NOT NULL THEN + LOCK TABLE taler_in IN SHARE ROW EXCLUSIVE MODE; + INSERT INTO taler_in (tx_in_id, type, metadata, authorization_pub, authorization_sig) + VALUES (talerable_tx, in_type, in_account_pub, in_authorization_pub, in_authorization_sig) + RETURNING taler_in_id INTO local_taler_in_id; PERFORM pg_notify('taler_in', local_taler_in_id::text); END IF; ELSE diff --git a/adapters/taler-magnet-bank/db/magnet-bank-procedures.sql b/adapters/taler-magnet-bank/db/magnet-bank-procedures.sql @@ -97,6 +97,8 @@ END IF; -- Insert new incoming transaction out_valued_at = in_valued_at; +-- Lock for revenue id commit ordering +LOCK TABLE tx_in IN SHARE ROW EXCLUSIVE MODE; INSERT INTO tx_in ( magnet_code, amount, @@ -128,6 +130,8 @@ ELSIF in_type IS NOT NULL THEN WHERE ( tx_in_id IS NULL AND account_pub = in_metadata AND in_type=type AND type='reserve' ) OR authorization_pub = local_authorization_pub; + -- Lock for incoming history id commit ordering + LOCK TABLE taler_in IN SHARE ROW EXCLUSIVE MODE; -- Insert new incoming talerable transaction INSERT INTO taler_in ( tx_in_id, @@ -175,6 +179,8 @@ IF FOUND THEN RETURN; END IF; +-- Lock for revenue and incoming history id commit ordering +LOCK TABLE tx_out IN SHARE ROW EXCLUSIVE MODE; -- Insert new outgoing transaction INSERT INTO tx_out ( magnet_code, @@ -508,24 +514,23 @@ IF out_reserve_pub_reuse THEN END IF; IF in_recurrent THEN - -- Finalize one pending right now - WITH moved_tx AS ( - DELETE FROM pending_recurrent_in - WHERE tx_in_id = ( - SELECT tx_in_id - FROM pending_recurrent_in - JOIN tx_in USING (tx_in_id) - WHERE authorization_pub = in_authorization_pub - ORDER BY registered_at ASC - LIMIT 1 - ) - RETURNING tx_in_id + -- Finalize one pending right now. Lock history only if there is a row to publish. + DELETE FROM pending_recurrent_in + WHERE tx_in_id = ( + SELECT tx_in_id + FROM pending_recurrent_in + JOIN tx_in USING (tx_in_id) + WHERE authorization_pub = in_authorization_pub + ORDER BY registered_at ASC + LIMIT 1 ) - INSERT INTO taler_in (tx_in_id, type, metadata, authorization_pub, authorization_sig) - SELECT moved_tx.tx_in_id, in_type, in_account_pub, in_authorization_pub, in_authorization_sig - FROM moved_tx - RETURNING tx_in_id, taler_in_id INTO talerable_tx, local_taler_in_id; + RETURNING tx_in_id INTO talerable_tx; IF talerable_tx IS NOT NULL THEN + -- Lock for incoming history id commit ordering + LOCK TABLE taler_in IN SHARE ROW EXCLUSIVE MODE; + INSERT INTO taler_in (tx_in_id, type, metadata, authorization_pub, authorization_sig) + VALUES (talerable_tx, in_type, in_account_pub, in_authorization_pub, in_authorization_sig) + RETURNING taler_in_id INTO local_taler_in_id; PERFORM pg_notify('taler_in', local_taler_in_id::text); END IF; ELSE diff --git a/adapters/taler-wise/db/wise-procedures.sql b/adapters/taler-wise/db/wise-procedures.sql @@ -100,6 +100,8 @@ END IF; -- Insert new incoming transaction out_valued_at = in_valued_at; +-- Lock for revenue id commit ordering +LOCK TABLE tx_in IN SHARE ROW EXCLUSIVE MODE; INSERT INTO tx_in ( balance_id, wise_ref, @@ -133,6 +135,8 @@ ELSIF in_type IS NOT NULL AND in_debit_payto IS NOT NULL THEN WHERE ( tx_in_id IS NULL AND account_pub = in_metadata AND in_type=type AND type='reserve' ) OR authorization_pub = local_authorization_pub; + -- Lock for incoming history id commit ordering + LOCK TABLE taler_in IN SHARE ROW EXCLUSIVE MODE; -- Insert new incoming talerable transaction INSERT INTO taler_in ( tx_in_id, @@ -198,31 +202,26 @@ IF out_reserve_pub_reuse THEN END IF; IF in_recurrent THEN - -- Finalize one pending right now - WITH pending AS ( - SELECT tx_in_id - FROM pending_recurrent_in - JOIN tx_in USING (tx_in_id) - WHERE authorization_pub = in_authorization_pub - ORDER BY valued_at ASC - LIMIT 1 - ), moved_tx AS ( - DELETE FROM pending_recurrent_in - USING tx_in, pending - WHERE pending_recurrent_in.tx_in_id = tx_in.tx_in_id - AND pending_recurrent_in.tx_in_id = pending.tx_in_id - RETURNING pending_recurrent_in.tx_in_id, tx_in.balance_id - ), inserted AS ( - INSERT INTO taler_in (tx_in_id, type, metadata, authorization_pub, authorization_sig) - SELECT tx_in_id, in_type, in_account_pub, in_authorization_pub, in_authorization_sig - FROM moved_tx - RETURNING tx_in_id, taler_in_id - ) - SELECT inserted.tx_in_id, inserted.taler_in_id, moved_tx.balance_id - INTO talerable_tx, local_taler_in_id, local_balance_id - FROM inserted - JOIN moved_tx USING (tx_in_id); + -- Finalize one pending right now. Lock history only if there is a row to publish. + DELETE FROM pending_recurrent_in + USING tx_in + WHERE pending_recurrent_in.tx_in_id = tx_in.tx_in_id + AND pending_recurrent_in.tx_in_id = ( + SELECT pending.tx_in_id + FROM pending_recurrent_in AS pending + JOIN tx_in USING (tx_in_id) + WHERE authorization_pub = in_authorization_pub + ORDER BY valued_at ASC + LIMIT 1 + ) + RETURNING pending_recurrent_in.tx_in_id, tx_in.balance_id + INTO talerable_tx, local_balance_id; IF talerable_tx IS NOT NULL THEN + -- Lock for incoming history id commit ordering + LOCK TABLE taler_in IN SHARE ROW EXCLUSIVE MODE; + INSERT INTO taler_in (tx_in_id, type, metadata, authorization_pub, authorization_sig) + VALUES (talerable_tx, in_type, in_account_pub, in_authorization_pub, in_authorization_sig) + RETURNING taler_in_id INTO local_taler_in_id; PERFORM pg_notify('taler_in', local_balance_id || ' ' || local_taler_in_id); END IF; END IF; diff --git a/common/taler-api/db/taler-api-procedures.sql b/common/taler-api/db/taler-api-procedures.sql @@ -90,6 +90,8 @@ INSERT INTO tx_out ( in_credit_payto, in_now ) RETURNING tx_out_id INTO local_tx_id; +-- Lock for transfer id commit ordering +LOCK TABLE transfer IN SHARE ROW EXCLUSIVE MODE; INSERT INTO transfer ( tx_out_id, exchange_base_url, @@ -158,6 +160,8 @@ END IF; -- Register incoming transaction out_created_at=in_now; +-- Lock for revenue id commit ordering +LOCK TABLE tx_in IN SHARE ROW EXCLUSIVE MODE; INSERT INTO tx_in ( amount, debit_payto, @@ -179,6 +183,7 @@ ELSE WHERE ( tx_in_id IS NULL AND account_pub = in_account_pub AND in_type=type AND type='reserve' ) OR authorization_pub = local_authorization_pub; + LOCK TABLE taler_in IN SHARE ROW EXCLUSIVE MODE; INSERT INTO taler_in ( tx_in_id, type, @@ -242,24 +247,23 @@ IF out_reserve_pub_reuse THEN END IF; IF in_recurrent THEN - -- Finalize one pending right now - WITH moved_tx AS ( - DELETE FROM pending_recurrent_in - WHERE tx_in_id = ( - SELECT tx_in_id - FROM pending_recurrent_in - JOIN tx_in USING (tx_in_id) - WHERE authorization_pub = in_authorization_pub - ORDER BY created_at ASC - LIMIT 1 - ) - RETURNING tx_in_id + -- Finalize one pending right now. + DELETE FROM pending_recurrent_in + WHERE tx_in_id = ( + SELECT tx_in_id + FROM pending_recurrent_in + JOIN tx_in USING (tx_in_id) + WHERE authorization_pub = in_authorization_pub + ORDER BY created_at ASC + LIMIT 1 ) - INSERT INTO taler_in (tx_in_id, type, account_pub, authorization_pub, authorization_sig) - SELECT moved_tx.tx_in_id, in_type, in_account_pub, in_authorization_pub, in_authorization_sig - FROM moved_tx - RETURNING tx_in_id, taler_in_id INTO talerable_tx, local_taler_in_id; + RETURNING tx_in_id INTO talerable_tx; IF talerable_tx IS NOT NULL THEN + -- Lock for incoming history id commit ordering + LOCK TABLE taler_in IN SHARE ROW EXCLUSIVE MODE; + INSERT INTO taler_in (tx_in_id, type, account_pub, authorization_pub, authorization_sig) + VALUES (talerable_tx, in_type, in_account_pub, in_authorization_pub, in_authorization_sig) + RETURNING taler_in_id INTO local_taler_in_id; PERFORM pg_notify('incoming_tx', local_taler_in_id::text); END IF; ELSE