taler-rust

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

commit dc223fd8aa6b1c27be78484ceb7a8efbb1c42cef
parent 3322693545f8648b7e8dd9b881d0827b737680a5
Author: Antoine A <>
Date:   Thu, 26 Mar 2026 17:36:39 +0100

common: improve prepared transfer tests, fix bugs and bump API version

Diffstat:
Mcommon/taler-api/db/taler-api-procedures.sql | 16+++++++++-------
Mcommon/taler-api/src/constants.rs | 2+-
Mcommon/taler-test-utils/src/routine.rs | 434+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mtaler-cyclos/db/cyclos-procedures.sql | 16+++++++++-------
Mtaler-cyclos/src/db.rs | 12+++++++-----
Mtaler-magnet-bank/db/magnet-bank-procedures.sql | 16+++++++++-------
Mtaler-magnet-bank/src/db.rs | 12+++++++-----
7 files changed, 325 insertions(+), 183 deletions(-)

diff --git a/common/taler-api/db/taler-api-procedures.sql b/common/taler-api/db/taler-api-procedures.sql @@ -174,19 +174,21 @@ IF local_pending THEN INSERT INTO pending_recurrent_in (tx_in_id, authorization_pub) VALUES (out_tx_row_id, local_authorization_pub); ELSE - IF local_authorization_pub IS NOT NULL THEN - UPDATE prepared_in - SET tx_in_id = out_tx_row_id - WHERE authorization_pub = local_authorization_pub; - END IF; + UPDATE prepared_in + SET tx_in_id = out_tx_row_id + WHERE (tx_in_id IS NULL AND account_pub = in_account_pub) OR authorization_pub = local_authorization_pub; INSERT INTO taler_in ( tx_in_id, type, - account_pub + account_pub, + authorization_pub, + authorization_sig ) VALUES ( out_tx_row_id, in_type, - in_account_pub + in_account_pub, + local_authorization_pub, + local_authorization_sig ); -- Notify new incoming transaction PERFORM pg_notify('incoming_tx', out_tx_row_id || ''); diff --git a/common/taler-api/src/constants.rs b/common/taler-api/src/constants.rs @@ -14,7 +14,7 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -pub const WIRE_GATEWAY_API_VERSION: &str = "4:0:0"; +pub const WIRE_GATEWAY_API_VERSION: &str = "5:0:0"; pub const WIRE_GATEWAY_TRANSFER_API_VERSION: &str = "1:0:0"; pub const REVENUE_API_VERSION: &str = "1:0:0"; pub const MAX_PAGE_SIZE: i64 = 1024; diff --git a/common/taler-test-utils/src/routine.rs b/common/taler-test-utils/src/routine.rs @@ -24,7 +24,10 @@ use aws_lc_rs::signature::{Ed25519KeyPair, KeyPair as _}; use axum::Router; use jiff::{SignedDuration, Timestamp}; use serde::{Deserialize, de::DeserializeOwned}; -use taler_api::{crypto::eddsa_sign, subject::fmt_in_subject}; +use taler_api::{ + crypto::{check_eddsa_signature, eddsa_sign}, + subject::fmt_in_subject, +}; use taler_common::{ api_common::{EddsaPublicKey, HashCode, ShortHashCode}, api_params::PageParams, @@ -683,28 +686,28 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>, F2: Future<O let currency = &get_transfer_currency(server).await; let amount = amount(format!("{currency}:42")); - let key_pair = Ed25519KeyPair::generate().unwrap(); - let auth_pub = EddsaPublicKey::try_from(key_pair.public_key().as_ref()).unwrap(); + let key_pair1 = Ed25519KeyPair::generate().unwrap(); + let auth_pub1 = EddsaPublicKey::try_from(key_pair1.public_key().as_ref()).unwrap(); let req = json!({ "credit_amount": amount, "type": "reserve", "alg": "EdDSA", - "account_pub": auth_pub, - "authorization_pub": auth_pub, - "authorization_sig": eddsa_sign(&key_pair, auth_pub.as_ref()), + "account_pub": auth_pub1, + "authorization_pub": auth_pub1, + "authorization_sig": eddsa_sign(&key_pair1, auth_pub1.as_ref()), "recurrent": false }); + /* ----- Registration ----- */ let routine = async |ty: TransferType, account_pub: &EddsaPublicKey, - auth_pub: &EddsaPublicKey, recurrent: bool, - expected: &str| { + fmt: IncomingType| { let req = json!(req + { "type": ty, "account_pub": account_pub, - "authorization_pub": auth_pub, - "authorization_sig": eddsa_sign(&key_pair, account_pub.as_ref()), + "authorization_pub": auth_pub1, + "authorization_sig": eddsa_sign(&key_pair1, account_pub.as_ref()), "recurrent": recurrent }); // Valid @@ -728,54 +731,26 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>, F2: Future<O for sub in res.subjects { if let TransferSubject::Simple { subject, .. } = sub { - assert_eq!(subject, expected); + assert_eq!(subject, fmt_in_subject(fmt, &auth_pub1)); }; } }; for ty in [TransferType::reserve, TransferType::kyc] { - routine( - ty, - &auth_pub, - &auth_pub, - false, - &fmt_in_subject(ty.into(), &auth_pub), - ) - .await; - routine( - ty, - &auth_pub, - &auth_pub, - true, - &fmt_in_subject(IncomingType::map, &auth_pub), - ) - .await; + routine(ty, &auth_pub1, false, ty.into()).await; + routine(ty, &auth_pub1, true, IncomingType::map).await; } - let account_pub = EddsaPublicKey::rand(); + let acc_pub1 = EddsaPublicKey::rand(); for ty in [TransferType::reserve, TransferType::kyc] { - routine( - ty, - &account_pub, - &auth_pub, - false, - &fmt_in_subject(IncomingType::map, &auth_pub), - ) - .await; - routine( - ty, - &account_pub, - &auth_pub, - true, - &fmt_in_subject(IncomingType::map, &auth_pub), - ) - .await; + routine(ty, &acc_pub1, false, IncomingType::map).await; + routine(ty, &acc_pub1, true, IncomingType::map).await; } // Bad signature server .post("/taler-wire-transfer-gateway/registration") .json(&json!(req + { - "authorization_sig": eddsa_sign(&key_pair, "lol".as_bytes()), + "authorization_sig": eddsa_sign(&key_pair1, "lol".as_bytes()), })) .await .assert_error(ErrorCode::BANK_BAD_SIGNATURE); @@ -784,8 +759,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>, F2: Future<O server .post("/taler-wire-transfer-gateway/registration") .json(&json!(req + { - "account_pub": account_pub, - "authorization_sig": eddsa_sign(&key_pair, account_pub.as_ref()), + "account_pub": acc_pub1, + "authorization_sig": eddsa_sign(&key_pair1, acc_pub1.as_ref()), })) .await .assert_ok_json::<RegistrationResponse>(); @@ -795,9 +770,9 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>, F2: Future<O server .post("/taler-wire-transfer-gateway/registration") .json(&json!(req + { - "account_pub": account_pub, + "account_pub": acc_pub1, "authorization_pub": auth_pub, - "authorization_sig": eddsa_sign(&key_pair, account_pub.as_ref()), + "authorization_sig": eddsa_sign(&key_pair, acc_pub1.as_ref()), })) .await .assert_error(ErrorCode::BANK_DUPLICATE_RESERVE_PUB_SUBJECT); @@ -807,34 +782,64 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>, F2: Future<O server .post("/taler-wire-transfer-gateway/registration") .json(&json!(req + { - "account_pub": account_pub, - "authorization_sig": eddsa_sign(&key_pair, account_pub.as_ref()), + "account_pub": acc_pub1, + "authorization_sig": eddsa_sign(&key_pair1, acc_pub1.as_ref()), })) .await .assert_ok_json::<RegistrationResponse>(); - register(&auth_pub).await; - check_in(&[Reserve(account_pub.clone())]).await; - register(&auth_pub).await; - check_in(&[Reserve(account_pub.clone()), Bounced]).await; + register(&auth_pub1).await; + check_in(&[Reserve(acc_pub1.clone())]).await; + register(&auth_pub1).await; + check_in(&[Reserve(acc_pub1.clone()), Bounced]).await; + + // Again without using mapping + let acc_pub2 = EddsaPublicKey::rand(); + server + .post("/taler-wire-transfer-gateway/registration") + .json(&json!(req + { + "account_pub": acc_pub2, + "authorization_sig": eddsa_sign(&key_pair1, acc_pub2.as_ref()), + })) + .await + .assert_ok_json::<RegistrationResponse>(); + server + .post("/taler-wire-gateway/admin/add-incoming") + .json(&json!({ + "amount": amount, + "reserve_pub": acc_pub2, + "debit_account": account, + })) + .await + .assert_ok(); + register(&auth_pub1).await; + check_in(&[ + Reserve(acc_pub1.clone()), + Bounced, + Reserve(acc_pub2.clone()), + Bounced, + ]) + .await; // Recurrent accept one and delay others - let new_key = EddsaPublicKey::rand(); + let acc_pub3 = EddsaPublicKey::rand(); server .post("/taler-wire-transfer-gateway/registration") .json(&json!(req + { - "account_pub": new_key, - "authorization_sig": eddsa_sign(&key_pair, new_key.as_ref()), + "account_pub": acc_pub3, + "authorization_sig": eddsa_sign(&key_pair1, acc_pub3.as_ref()), "recurrent": true })) .await .assert_ok_json::<RegistrationResponse>(); for _ in 0..5 { - register(&auth_pub).await; + register(&auth_pub1).await; } check_in(&[ - Reserve(account_pub.clone()), + Reserve(acc_pub1.clone()), + Bounced, + Reserve(acc_pub2.clone()), Bounced, - Reserve(new_key.clone()), + Reserve(acc_pub3.clone()), Pending, Pending, Pending, @@ -843,13 +848,13 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>, F2: Future<O .await; // Complete pending on recurrent update - let kyc_key = EddsaPublicKey::rand(); + let acc_pub4 = EddsaPublicKey::rand(); server .post("/taler-wire-transfer-gateway/registration") .json(&json!(req + { "type": "kyc", - "account_pub": kyc_key, - "authorization_sig": eddsa_sign(&key_pair, kyc_key.as_ref()), + "account_pub": acc_pub4, + "authorization_sig": eddsa_sign(&key_pair1, acc_pub4.as_ref()), "recurrent": true })) .await @@ -857,18 +862,20 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>, F2: Future<O server .post("/taler-wire-transfer-gateway/registration") .json(&json!(req + { - "account_pub": kyc_key, - "authorization_sig": eddsa_sign(&key_pair, kyc_key.as_ref()), + "account_pub": acc_pub4, + "authorization_sig": eddsa_sign(&key_pair1, acc_pub4.as_ref()), "recurrent": true })) .await .assert_ok_json::<RegistrationResponse>(); check_in(&[ - Reserve(account_pub.clone()), + Reserve(acc_pub1.clone()), + Bounced, + Reserve(acc_pub2.clone()), Bounced, - Reserve(new_key.clone()), - Kyc(kyc_key.clone()), - Reserve(kyc_key.clone()), + Reserve(acc_pub3.clone()), + Kyc(acc_pub4.clone()), + Reserve(acc_pub4.clone()), Pending, Pending, ]) @@ -879,49 +886,53 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>, F2: Future<O .post("/taler-wire-gateway/admin/add-kycauth") .json(&json!({ "amount": amount, - "account_pub": kyc_key, + "account_pub": acc_pub4, "debit_account": account, })) .await .assert_ok_json::<TransferResponse>(); check_in(&[ - Reserve(account_pub.clone()), + Reserve(acc_pub1.clone()), Bounced, - Reserve(new_key.clone()), - Kyc(kyc_key.clone()), - Reserve(kyc_key.clone()), + Reserve(acc_pub2.clone()), + Bounced, + Reserve(acc_pub3.clone()), + Kyc(acc_pub4.clone()), + Reserve(acc_pub4.clone()), Pending, Pending, - Kyc(kyc_key.clone()), + Kyc(acc_pub4.clone()), ]) .await; // Switching to non recurrent cancel pending let auth_pair = Ed25519KeyPair::generate().unwrap(); - let last_pub = EddsaPublicKey::try_from(auth_pair.public_key().as_ref()).unwrap(); + let auth_pub2 = EddsaPublicKey::try_from(auth_pair.public_key().as_ref()).unwrap(); server .post("/taler-wire-transfer-gateway/registration") .json(&json!(req + { - "account_pub": last_pub, - "authorization_pub": last_pub, - "authorization_sig": eddsa_sign(&auth_pair, last_pub.as_ref()), + "account_pub": auth_pub2, + "authorization_pub": auth_pub2, + "authorization_sig": eddsa_sign(&auth_pair, auth_pub2.as_ref()), "recurrent": true })) .await .assert_ok_json::<RegistrationResponse>(); for _ in 0..3 { - register(&last_pub).await; + register(&auth_pub2).await; } check_in(&[ - Reserve(account_pub.clone()), + Reserve(acc_pub1.clone()), + Bounced, + Reserve(acc_pub2.clone()), Bounced, - Reserve(new_key.clone()), - Kyc(kyc_key.clone()), - Reserve(kyc_key.clone()), + Reserve(acc_pub3.clone()), + Kyc(acc_pub4.clone()), + Reserve(acc_pub4.clone()), Pending, Pending, - Kyc(kyc_key.clone()), - Reserve(last_pub.clone()), + Kyc(acc_pub4.clone()), + Reserve(auth_pub2.clone()), Pending, Pending, ]) @@ -930,123 +941,244 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>, F2: Future<O .post("/taler-wire-transfer-gateway/registration") .json(&json!(req + { "type": "kyc", - "account_pub": last_pub, - "authorization_pub": last_pub, - "authorization_sig": eddsa_sign(&auth_pair, last_pub.as_ref()), + "account_pub": auth_pub2, + "authorization_pub": auth_pub2, + "authorization_sig": eddsa_sign(&auth_pair, auth_pub2.as_ref()), "recurrent": false })) .await .assert_ok_json::<RegistrationResponse>(); check_in(&[ - Reserve(account_pub.clone()), + Reserve(acc_pub1.clone()), Bounced, - Reserve(new_key.clone()), - Kyc(kyc_key.clone()), - Reserve(kyc_key.clone()), + Reserve(acc_pub2.clone()), + Bounced, + Reserve(acc_pub3.clone()), + Kyc(acc_pub4.clone()), + Reserve(acc_pub4.clone()), Pending, Pending, - Kyc(kyc_key.clone()), - Reserve(last_pub.clone()), + Kyc(acc_pub4.clone()), + Reserve(auth_pub2.clone()), Bounced, Bounced, ]) .await; - // Unregistration - let now = Timestamp::now().to_string(); - let un_req = json!({ - "timestamp": now, - "authorization_pub": last_pub, - "authorization_sig": eddsa_sign(&auth_pair, now.as_bytes()), - }); - - // Known - server - .delete("/taler-wire-transfer-gateway/registration") - .json(&un_req) - .await - .assert_no_content(); - - // Idempotent + // Recurrent reserve simple subject + let acc_pub5 = EddsaPublicKey::rand(); server - .delete("/taler-wire-transfer-gateway/registration") - .json(&un_req) + .post("/taler-wire-transfer-gateway/registration") + .json(&json!(req + { + "type": "reserve", + "account_pub": acc_pub5, + "authorization_pub": auth_pub2, + "authorization_sig": eddsa_sign(&auth_pair, acc_pub5.as_ref()), + "recurrent": true + })) .await - .assert_error(ErrorCode::BANK_TRANSACTION_NOT_FOUND); - - // Bad signature + .assert_ok_json::<RegistrationResponse>(); server - .delete("/taler-wire-transfer-gateway/registration") - .json(&json!(un_req + { - "authorization_sig": eddsa_sign(&auth_pair, "lol".as_bytes()), + .post("/taler-wire-gateway/admin/add-incoming") + .json(&json!({ + "amount": amount, + "reserve_pub": acc_pub5, + "debit_account": account, })) .await - .assert_error(ErrorCode::BANK_BAD_SIGNATURE); + .assert_ok(); + register(&auth_pub2).await; + check_in(&[ + Reserve(acc_pub1.clone()), + Bounced, + Reserve(acc_pub2.clone()), + Bounced, + Reserve(acc_pub3.clone()), + Kyc(acc_pub4.clone()), + Reserve(acc_pub4.clone()), + Pending, + Pending, + Kyc(acc_pub4.clone()), + Reserve(auth_pub2.clone()), + Bounced, + Bounced, + Reserve(acc_pub5.clone()), + Pending, + ]) + .await; - // Old timestamp - let now = (Timestamp::now() - SignedDuration::from_mins(10)).to_string(); + // Recurrent kyc simple subject server - .delete("/taler-wire-transfer-gateway/registration") - .json(&json!({ - "timestamp": now, - "authorization_pub": last_pub, - "authorization_sig": eddsa_sign(&auth_pair, now.as_bytes()), + .post("/taler-wire-transfer-gateway/registration") + .json(&json!(req + { + "type": "kyc", + "account_pub": acc_pub5, + "authorization_pub": auth_pub2, + "authorization_sig": eddsa_sign(&auth_pair, acc_pub5.as_ref()), + "recurrent": false })) .await - .assert_error(ErrorCode::BANK_OLD_TIMESTAMP); - - // Check bounce pending on deletion + .assert_ok_json::<RegistrationResponse>(); server .post("/taler-wire-transfer-gateway/registration") .json(&json!(req + { "type": "kyc", - "account_pub": last_pub, - "authorization_pub": last_pub, - "authorization_sig": eddsa_sign(&auth_pair, last_pub.as_ref()), + "account_pub": acc_pub5, + "authorization_pub": auth_pub2, + "authorization_sig": eddsa_sign(&auth_pair, acc_pub5.as_ref()), "recurrent": true })) .await .assert_ok_json::<RegistrationResponse>(); - for _ in 0..3 { - register(&last_pub).await; - } + server + .post("/taler-wire-gateway/admin/add-kycauth") + .json(&json!({ + "amount": amount, + "account_pub": acc_pub5, + "debit_account": account, + })) + .await + .assert_ok(); + register(&auth_pub2).await; + register(&auth_pub2).await; check_in(&[ - Reserve(account_pub.clone()), + Reserve(acc_pub1.clone()), + Bounced, + Reserve(acc_pub2.clone()), Bounced, - Reserve(new_key.clone()), - Kyc(kyc_key.clone()), - Reserve(kyc_key.clone()), + Reserve(acc_pub3.clone()), + Kyc(acc_pub4.clone()), + Reserve(acc_pub4.clone()), Pending, Pending, - Kyc(kyc_key.clone()), - Reserve(last_pub.clone()), + Kyc(acc_pub4.clone()), + Reserve(auth_pub2.clone()), Bounced, Bounced, - Kyc(last_pub.clone()), + Reserve(acc_pub5.clone()), + Bounced, + Kyc(acc_pub5.clone()), Pending, Pending, ]) .await; + + /* ----- Unregistration ----- */ + let now = Timestamp::now().to_string(); + let un_req = json!({ + "timestamp": now, + "authorization_pub": auth_pub2, + "authorization_sig": eddsa_sign(&auth_pair, now.as_bytes()), + }); + + // Delete server .delete("/taler-wire-transfer-gateway/registration") .json(&un_req) .await .assert_no_content(); + + // Check bounce pending on deletion + check_in(&[ - Reserve(account_pub.clone()), + Reserve(acc_pub1.clone()), Bounced, - Reserve(new_key.clone()), - Kyc(kyc_key.clone()), - Reserve(kyc_key.clone()), + Reserve(acc_pub2.clone()), + Bounced, + Reserve(acc_pub3.clone()), + Kyc(acc_pub4.clone()), + Reserve(acc_pub4.clone()), Pending, Pending, - Kyc(kyc_key.clone()), - Reserve(last_pub.clone()), + Kyc(acc_pub4.clone()), + Reserve(auth_pub2.clone()), + Bounced, Bounced, + Reserve(acc_pub5.clone()), Bounced, - Kyc(last_pub.clone()), + Kyc(acc_pub5.clone()), Bounced, Bounced, ]) .await; + + // Idempotent + server + .delete("/taler-wire-transfer-gateway/registration") + .json(&un_req) + .await + .assert_error(ErrorCode::BANK_TRANSACTION_NOT_FOUND); + + // Bad signature + server + .delete("/taler-wire-transfer-gateway/registration") + .json(&json!(un_req + { + "authorization_sig": eddsa_sign(&auth_pair, "lol".as_bytes()), + })) + .await + .assert_error(ErrorCode::BANK_BAD_SIGNATURE); + + // Old timestamp + let now = (Timestamp::now() - SignedDuration::from_mins(10)).to_string(); + server + .delete("/taler-wire-transfer-gateway/registration") + .json(&json!({ + "timestamp": now, + "authorization_pub": auth_pub2, + "authorization_sig": eddsa_sign(&auth_pair, now.as_bytes()), + })) + .await + .assert_error(ErrorCode::BANK_OLD_TIMESTAMP); + + /* ----- API ----- */ + + let history: Vec<_> = server + .get("/taler-wire-gateway/history/incoming?limit=20") + .await + .assert_ok_json::<IncomingHistory>() + .incoming_transactions + .into_iter() + .map(|tx| { + let (acc_pub, auth_pub, auth_sig) = match tx { + IncomingBankTransaction::Reserve { + reserve_pub, + authorization_pub, + authorization_sig, + .. + } => (reserve_pub, authorization_pub, authorization_sig), + IncomingBankTransaction::Wad { .. } => unreachable!(), + IncomingBankTransaction::Kyc { + account_pub, + authorization_pub, + authorization_sig, + .. + } => (account_pub, authorization_pub, authorization_sig), + }; + if let Some(auth_pub) = &auth_pub { + assert!(check_eddsa_signature( + auth_pub, + acc_pub.as_ref(), + &auth_sig.unwrap() + )); + } else { + assert!(auth_sig.is_none()) + } + (acc_pub, auth_pub) + }) + .collect(); + dbg!(&history); + assert_eq!( + history, + [ + (acc_pub1.clone(), Some(auth_pub1.clone())), + (acc_pub2.clone(), None), + (acc_pub3.clone(), Some(auth_pub1.clone())), + (acc_pub4.clone(), Some(auth_pub1.clone())), + (acc_pub4.clone(), Some(auth_pub1.clone())), + (acc_pub4.clone(), None), + (auth_pub2.clone(), Some(auth_pub2.clone())), + (acc_pub5.clone(), None), + (acc_pub5.clone(), None), + ] + ) } diff --git a/taler-cyclos/db/cyclos-procedures.sql b/taler-cyclos/db/cyclos-procedures.sql @@ -127,20 +127,22 @@ IF out_pending THEN INSERT INTO pending_recurrent_in (tx_in_id, authorization_pub) VALUES (out_tx_row_id, local_authorization_pub); ELSIF in_type IS NOT NULL THEN - IF local_authorization_pub IS NOT NULL THEN - UPDATE prepared_in - SET tx_in_id = out_tx_row_id - WHERE authorization_pub = local_authorization_pub; - END IF; + UPDATE prepared_in + SET tx_in_id = out_tx_row_id + WHERE (tx_in_id IS NULL AND account_pub = in_metadata) OR authorization_pub = local_authorization_pub; -- Insert new incoming talerable transaction INSERT INTO taler_in ( tx_in_id, type, - metadata + metadata, + authorization_pub, + authorization_sig ) VALUES ( out_tx_row_id, in_type, - in_metadata + in_metadata, + local_authorization_pub, + local_authorization_sig ); -- Notify new incoming talerable transaction registration PERFORM pg_notify('taler_in', out_tx_row_id || ''); diff --git a/taler-cyclos/src/db.rs b/taler-cyclos/src/db.rs @@ -573,7 +573,9 @@ pub async fn incoming_history( debit_account, debit_name, valued_at, - metadata + metadata, + authorization_pub, + authorization_sig FROM taler_in JOIN tx_in USING (tx_in_id) WHERE @@ -589,8 +591,8 @@ pub async fn incoming_history( debit_account: r.try_get_cyclos_fullpaytouri(3, 4, root)?, date: r.try_get_timestamp(5)?.into(), reserve_pub: r.try_get(6)?, - authorization_pub: None, - authorization_sig: None, + authorization_pub: r.try_get(7)?, + authorization_sig: r.try_get(8)?, }, IncomingType::kyc => IncomingBankTransaction::Kyc { row_id: r.try_get_safeu64(1)?, @@ -599,8 +601,8 @@ pub async fn incoming_history( debit_account: r.try_get_cyclos_fullpaytouri(3, 4, root)?, date: r.try_get_timestamp(5)?.into(), account_pub: r.try_get(6)?, - authorization_pub: None, - authorization_sig: None, + authorization_pub: r.try_get(7)?, + authorization_sig: r.try_get(8)?, }, IncomingType::map => unimplemented!("MAP are never listed in the history"), }) diff --git a/taler-magnet-bank/db/magnet-bank-procedures.sql b/taler-magnet-bank/db/magnet-bank-procedures.sql @@ -123,20 +123,22 @@ IF out_pending THEN INSERT INTO pending_recurrent_in (tx_in_id, authorization_pub) VALUES (out_tx_row_id, local_authorization_pub); ELSIF in_type IS NOT NULL THEN - IF local_authorization_pub IS NOT NULL THEN - UPDATE prepared_in - SET tx_in_id = out_tx_row_id - WHERE authorization_pub = local_authorization_pub; - END IF; + UPDATE prepared_in + SET tx_in_id = out_tx_row_id + WHERE (tx_in_id IS NULL AND account_pub = in_metadata) OR authorization_pub = local_authorization_pub; -- Insert new incoming talerable transaction INSERT INTO taler_in ( tx_in_id, type, - metadata + metadata, + authorization_pub, + authorization_sig ) VALUES ( out_tx_row_id, in_type, - in_metadata + in_metadata, + local_authorization_pub, + local_authorization_sig ); -- Notify new incoming talerable transaction registration PERFORM pg_notify('taler_in', out_tx_row_id || ''); diff --git a/taler-magnet-bank/src/db.rs b/taler-magnet-bank/src/db.rs @@ -585,7 +585,9 @@ pub async fn incoming_history( debit_account, debit_name, valued_at, - metadata + metadata, + authorization_pub, + authorization_sig FROM taler_in JOIN tx_in USING (tx_in_id) WHERE @@ -601,8 +603,8 @@ pub async fn incoming_history( debit_account: r.try_get_iban(3)?.as_full_payto(r.try_get(4)?), date: r.try_get_timestamp(5)?.into(), reserve_pub: r.try_get(6)?, - authorization_pub: None, - authorization_sig: None, + authorization_pub: r.try_get(7)?, + authorization_sig: r.try_get(8)?, }, IncomingType::kyc => IncomingBankTransaction::Kyc { row_id: r.try_get_safeu64(1)?, @@ -611,8 +613,8 @@ pub async fn incoming_history( debit_account: r.try_get_iban(3)?.as_full_payto(r.try_get(4)?), date: r.try_get_timestamp(5)?.into(), account_pub: r.try_get(6)?, - authorization_pub: None, - authorization_sig: None, + authorization_pub: r.try_get(7)?, + authorization_sig: r.try_get(8)?, }, IncomingType::map => unimplemented!("MAP are never listed in the history"), })