commit 61cf08e25e4f4505d1784bb7fe2fb942a2d24a91
parent 13ed1892fead3ea284f2033b2df9917be698d3d7
Author: Antoine A <>
Date: Tue, 10 Sep 2024 17:38:31 +0200
nexus: warn on data inconsistency
Diffstat:
2 files changed, 106 insertions(+), 31 deletions(-)
diff --git a/common/src/main/kotlin/db/transaction.kt b/common/src/main/kotlin/db/transaction.kt
@@ -45,7 +45,18 @@ suspend fun <R> retrySerializationError(lambda: suspend () -> R): R {
/** Run a postgres query using a prepared statement */
inline fun <R> PgConnection.withStatement(query: String, lambda: PreparedStatement.() -> R): R {
- return prepareStatement(query).use(lambda)
+ val stmt = prepareStatement(query)
+ return stmt.use {
+ val res = stmt.lambda()
+ // Log warnings
+ var warning = stmt.getWarnings()
+ while (warning != null) {
+ logger.warning(warning.message)
+ warning = warning.getNextWarning()
+ }
+ stmt.clearWarnings()
+ res
+ }
}
/** Run a postgres [transaction] */
diff --git a/database-versioning/libeufin-nexus-procedures.sql b/database-versioning/libeufin-nexus-procedures.sql
@@ -73,19 +73,69 @@ CREATE FUNCTION register_outgoing(
LANGUAGE plpgsql AS $$
DECLARE
init_id INT8;
+local_amount taler_amount;
+local_subject TEXT;
+local_credit_payto TEXT;
+local_wtid BYTEA;
+local_exchange_base_url TEXT;
BEGIN
-- Check if already registered
-SELECT outgoing_transaction_id INTO out_tx_id
- FROM outgoing_transactions
+SELECT outgoing_transaction_id, subject, credit_payto, (amount).val, (amount).frac,
+ wtid, exchange_base_url
+ INTO out_tx_id, local_subject, local_credit_payto, local_amount.val, local_amount.frac,
+ local_wtid, local_exchange_base_url
+ FROM outgoing_transactions LEFT JOIN talerable_outgoing_transactions USING (outgoing_transaction_id)
WHERE end_to_end_id = in_end_to_end_id;
-IF FOUND THEN
- out_found = true;
- -- TODO Should we update the subject and credit payto if it's finally found
- -- TODO Should we check that amount and other info match ?
- SELECT true INTO out_initiated
- FROM initiated_outgoing_transactions
- WHERE outgoing_transaction_id = out_tx_id;
-ELSE
+out_found=FOUND;
+IF out_found THEN
+ -- Check metadata
+ -- TODO take subject if missing and more detailed credit payto
+ IF local_subject IS DISTINCT FROM in_subject THEN
+ RAISE NOTICE 'outgoing tx %: stored subjet is ''%'' got ''%''', in_end_to_end_id, local_subject, in_subject;
+ END IF;
+ IF local_credit_payto IS DISTINCT FROM in_credit_payto THEN
+ RAISE NOTICE 'outgoing tx %: stored subjet credit payto is % got %', in_end_to_end_id, local_credit_payto, in_credit_payto;
+ END IF;
+ IF local_amount IS DISTINCT FROM in_amount THEN
+ RAISE NOTICE 'outgoing tx %: stored amount is % got %', in_end_to_end_id, local_amount, in_amount;
+ END IF;
+ IF local_wtid IS DISTINCT FROM in_wtid THEN
+ RAISE NOTICE 'outgoing tx %: stored wtid is % got %', in_end_to_end_id, local_wtid, in_wtid;
+ END IF;
+ IF local_exchange_base_url IS DISTINCT FROM in_exchange_url THEN
+ RAISE NOTICE 'outgoing tx %: stored exchange base url is % got %', in_end_to_end_id, local_exchange_base_url, in_exchange_url;
+ END IF;
+END IF;
+
+-- Check if initiated
+SELECT initiated_outgoing_transaction_id, subject, credit_payto, (amount).val, (amount).frac,
+ wtid, exchange_base_url
+ INTO init_id, local_subject, local_credit_payto, local_amount.val, local_amount.frac,
+ local_wtid, local_exchange_base_url
+ FROM initiated_outgoing_transactions LEFT JOIN transfer_operations USING (initiated_outgoing_transaction_id)
+ WHERE end_to_end_id = in_end_to_end_id;
+out_initiated=FOUND;
+IF out_initiated AND NOT out_found THEN
+ -- Check metadata
+ -- TODO take subject if missing and more detailed credit payto
+ IF local_subject IS DISTINCT FROM in_subject THEN
+ RAISE NOTICE 'outgoing tx %: initiated subjet is ''%'' got ''%''', in_end_to_end_id, local_subject, in_subject;
+ END IF;
+ IF local_credit_payto IS DISTINCT FROM in_credit_payto THEN
+ RAISE NOTICE 'outgoing tx %: initiated subjet credit payto is % got %', in_end_to_end_id, local_credit_payto, in_credit_payto;
+ END IF;
+ IF local_amount IS DISTINCT FROM in_amount THEN
+ RAISE NOTICE 'outgoing tx %: initiated amount is % got %', in_end_to_end_id, local_amount, in_amount;
+ END IF;
+ IF local_wtid IS DISTINCT FROM in_wtid THEN
+ RAISE NOTICE 'outgoing tx %: initiated wtid is % got %', in_end_to_end_id, local_wtid, in_wtid;
+ END IF;
+ IF local_exchange_base_url IS DISTINCT FROM in_exchange_url THEN
+ RAISE NOTICE 'outgoing tx %: initiated exchange base url is % got %', in_end_to_end_id, local_exchange_base_url, in_exchange_url;
+ END IF;
+END IF;
+
+IF NOT out_found THEN
-- Store the transaction in the database
INSERT INTO outgoing_transactions (
amount
@@ -103,33 +153,34 @@ ELSE
RETURNING outgoing_transaction_id
INTO out_tx_id;
+ -- Register as talerable if contains wtid and exchange URL
+ IF in_wtid IS NOT NULL OR in_exchange_url IS NOT NULL THEN
+ INSERT INTO talerable_outgoing_transactions (
+ outgoing_transaction_id,
+ wtid,
+ exchange_base_url
+ ) VALUES (out_tx_id, in_wtid, in_exchange_url)
+ ON CONFLICT (wtid) DO NOTHING;
+ IF FOUND THEN
+ PERFORM pg_notify('outgoing_tx', out_tx_id::text);
+ END IF;
+ END IF;
+END IF;
+
+IF NOT out_found AND out_initiated THEN
-- Reconciles the related initiated transaction
UPDATE initiated_outgoing_transactions
SET
outgoing_transaction_id = out_tx_id
,status = 'success'
,status_msg = null
- WHERE end_to_end_id = in_end_to_end_id
- RETURNING true INTO out_initiated;
+ WHERE initiated_outgoing_transaction_id = init_id;
-- Reconciles the related initiated batch
UPDATE initiated_outgoing_batches
- SET status = 'success'
+ SET status = 'success', status_msg = null
WHERE message_id = in_msg_id;
END IF;
-
--- Register as talerable if contains wtid and exchange URL
-IF in_wtid IS NOT NULL OR in_exchange_url IS NOT NULL THEN
- INSERT INTO talerable_outgoing_transactions (
- outgoing_transaction_id,
- wtid,
- exchange_base_url
- ) VALUES (out_tx_id, in_wtid, in_exchange_url)
- ON CONFLICT (wtid) DO NOTHING;
- IF FOUND THEN
- PERFORM pg_notify('outgoing_tx', out_tx_id::text);
- END IF;
-END IF;
END $$;
COMMENT ON FUNCTION register_outgoing
IS 'Register an outgoing transaction and optionally reconciles the related initiated transaction with it';
@@ -144,14 +195,27 @@ CREATE FUNCTION register_incoming(
,OUT out_tx_id INT8
)
LANGUAGE plpgsql AS $$
+DECLARE
+local_amount taler_amount;
+local_subject TEXT;
+local_debit_payto TEXT;
BEGIN
-- Check if already registered
-SELECT incoming_transaction_id INTO out_tx_id
+SELECT incoming_transaction_id, subject, debit_payto, (amount).val, (amount).frac
+ INTO out_tx_id, local_subject, local_debit_payto, local_amount.val, local_amount.frac
FROM incoming_transactions
WHERE bank_id = in_bank_id;
-IF FOUND THEN
- out_found = true;
- -- TODO Should we check that amount and other info match ?
+out_found=FOUND;
+IF out_found THEN
+ IF local_subject != in_subject THEN
+ RAISE NOTICE 'incoming tx %: stored subjet is ''%'' got ''%''', in_bank_id, local_subject, in_subject;
+ END IF;
+ IF local_debit_payto != in_debit_payto THEN
+ RAISE NOTICE 'incoming tx %: stored subjet debit payto is % got %', in_bank_id, local_debit_payto, in_debit_payto;
+ END IF;
+ IF local_amount != in_amount THEN
+ RAISE NOTICE 'incoming tx %: stored amount is % got %', in_bank_id, local_amount, in_amount;
+ END IF;
ELSE
-- Store the transaction in the database
INSERT INTO incoming_transactions (