commit 78de19c38700070ab3fa965f573f180997c749ff
parent 9361da39e566a5054398bbd853da762f20bfc473
Author: Antoine A <>
Date: Tue, 21 Jul 2026 18:26:43 +0200
bitcoin: test and fix prepared transfers
Diffstat:
2 files changed, 79 insertions(+), 7 deletions(-)
diff --git a/depolymerizer-bitcoin/db/depolymerizer-bitcoin-procedures.sql b/depolymerizer-bitcoin/db/depolymerizer-bitcoin-procedures.sql
@@ -175,7 +175,7 @@ IF out_pending THEN
ELSIF in_type IS NOT NULL THEN
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;
+ WHERE (tx_in_id IS NULL AND account_pub = in_metadata AND type='reserve') OR authorization_pub = local_authorization_pub;
-- Insert new incoming talerable tranreceived_atsaction
INSERT INTO taler_in (
tx_in_id,
@@ -389,11 +389,11 @@ IF in_recurrent THEN
WITH moved_tx AS (
DELETE FROM pending_recurrent_in
WHERE tx_in_id = (
- SELECT txid
- FROM tx_in
+ 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
+ ORDER BY received_at ASC
LIMIT 1
)
RETURNING tx_in_id
diff --git a/depolymerizer-bitcoin/src/api.rs b/depolymerizer-bitcoin/src/api.rs
@@ -362,15 +362,21 @@ pub mod test {
use axum::Router;
use jiff::Timestamp;
- use sqlx::PgPool;
- use taler_api::{api::TalerRouter as _, auth::AuthMethod, subject::OutgoingSubject};
+ use sqlx::{PgPool, Row, postgres::PgRow};
+ use taler_api::{
+ api::TalerRouter as _, auth::AuthMethod, db::TypeHelper, subject::OutgoingSubject,
+ };
use taler_common::{
api::wire::{TransferState, WireConfig},
+ db::IncomingType,
types::amount::{Currency, amount},
};
use taler_test_utils::{
db::db_test_setup,
- routine::{admin_add_incoming_routine, out_history_routine, transfer_routine},
+ routine::{
+ Status, admin_add_incoming_routine, out_history_routine, registration_routine,
+ revenue_routine, transfer_routine,
+ },
server::TestServer,
tasks,
};
@@ -396,6 +402,13 @@ pub mod test {
.unwrap()
});
+ pub static UNKNOWN: LazyLock<FullBtcPayto> = LazyLock::new(|| {
+ FullBtcPayto::from_str(
+ "payto://bitcoin/1Q2TWHE3GMdB6BZKafqwxXtWAWgFt5Jvm3?receiver-name=Unknown",
+ )
+ .unwrap()
+ });
+
async fn setup() -> (Router, PgPool) {
let (_, pool) = db_test_setup(CONFIG_SOURCE).await;
let api = ServerState::start(
@@ -475,4 +488,63 @@ pub mod test {
)
.await;
}
+
+ #[tokio::test]
+ async fn revenue() {
+ let (server, _) = &setup().await;
+ revenue_routine(
+ &server.prefix("/taler-wire-gateway"),
+ &server.prefix("/taler-revenue"),
+ &EXCHANGE.as_uri(),
+ tasks!(),
+ tasks!(),
+ )
+ .await;
+ }
+
+ async fn check_in(pool: &PgPool) -> Vec<Status> {
+ sqlx::query(
+ "
+ SELECT pending_recurrent_in.authorization_pub IS NOT NULL, bounced.reason IS NOT NULL, type, metadata
+ FROM tx_in
+ LEFT JOIN taler_in USING (tx_in_id)
+ LEFT JOIN pending_recurrent_in USING (tx_in_id)
+ LEFT JOIN bounced USING (tx_in_id)
+ ORDER BY tx_in.tx_in_id
+ ",
+ )
+ .try_map(|r: PgRow| {
+ Ok(
+ if r.try_get_flag(0)? {
+ Status::Pending
+ } else if r.try_get_flag(1)? {
+ Status::Bounced
+ } else {
+ match r.try_get(2)? {
+ None => Status::Simple,
+ Some(IncomingType::reserve) => Status::Reserve(r.try_get(3)?),
+ Some(IncomingType::kyc) => Status::Kyc(r.try_get(3)?),
+ Some(e) => unreachable!("{e:?}")
+ }
+ }
+ )
+ })
+ .fetch_all(pool)
+ .await
+ .unwrap()
+ }
+
+ #[tokio::test]
+ async fn registration() {
+ let (server, pool) = setup().await;
+ registration_routine(
+ &server.prefix("/taler-wire-gateway"),
+ &server.prefix("/taler-prepared-transfer"),
+ &CLIENT.as_uri(),
+ &EXCHANGE.as_uri(),
+ &UNKNOWN.as_uri(),
+ || check_in(&pool),
+ )
+ .await;
+ }
}