commit 5a4e56976d3fb7a88819aa7b9e290c0c8f3aaff9
parent 2ce7dab90e029a1c01d13e0730b220fd2bf5c7a3
Author: Antoine A <>
Date: Thu, 1 Oct 2026 14:21:02 +0200
common: sync taler-rust
Diffstat:
9 files changed, 108 insertions(+), 102 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -809,6 +809,7 @@ dependencies = [
"taler-api",
"taler-build",
"taler-common",
+ "taler-macros",
"taler-test-utils",
"thiserror",
"tokio",
@@ -993,7 +994,7 @@ dependencies = [
[[package]]
name = "failure-injection"
version = "1.5.0"
-source = "git+git://git.taler.net/taler-rust.git/#3f6a0fd79c5c9f294536810a2edb2f5419acf326"
+source = "git+git://git.taler.net/taler-rust.git/#7bfaf2c5e3f7ee89c29cc9175da77ee7cb582b18"
dependencies = [
"thiserror",
]
@@ -1595,9 +1596,9 @@ dependencies = [
[[package]]
name = "lazy_static"
-version = "1.5.0"
+version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+checksum = "20870f649af7073d53e38067b2a84312175d56ea15217e1b15bc83506ec50afb"
dependencies = [
"spin",
]
@@ -2921,7 +2922,7 @@ dependencies = [
[[package]]
name = "taler-api"
version = "1.5.0"
-source = "git+git://git.taler.net/taler-rust.git/#3f6a0fd79c5c9f294536810a2edb2f5419acf326"
+source = "git+git://git.taler.net/taler-rust.git/#7bfaf2c5e3f7ee89c29cc9175da77ee7cb582b18"
dependencies = [
"aws-lc-rs",
"axum",
@@ -2939,6 +2940,7 @@ dependencies = [
"serde_urlencoded",
"sqlx",
"taler-common",
+ "taler-macros",
"thiserror",
"tokio",
"tower-http",
@@ -2950,12 +2952,12 @@ dependencies = [
[[package]]
name = "taler-build"
version = "1.5.0"
-source = "git+git://git.taler.net/taler-rust.git/#3f6a0fd79c5c9f294536810a2edb2f5419acf326"
+source = "git+git://git.taler.net/taler-rust.git/#7bfaf2c5e3f7ee89c29cc9175da77ee7cb582b18"
[[package]]
name = "taler-common"
version = "1.5.0"
-source = "git+git://git.taler.net/taler-rust.git/#3f6a0fd79c5c9f294536810a2edb2f5419acf326"
+source = "git+git://git.taler.net/taler-rust.git/#7bfaf2c5e3f7ee89c29cc9175da77ee7cb582b18"
dependencies = [
"anyhow",
"aws-lc-rs",
@@ -2985,7 +2987,7 @@ dependencies = [
[[package]]
name = "taler-macros"
version = "1.5.0"
-source = "git+git://git.taler.net/taler-rust.git/#3f6a0fd79c5c9f294536810a2edb2f5419acf326"
+source = "git+git://git.taler.net/taler-rust.git/#7bfaf2c5e3f7ee89c29cc9175da77ee7cb582b18"
dependencies = [
"proc-macro2",
"quote",
@@ -2995,7 +2997,7 @@ dependencies = [
[[package]]
name = "taler-test-utils"
version = "1.5.0"
-source = "git+git://git.taler.net/taler-rust.git/#3f6a0fd79c5c9f294536810a2edb2f5419acf326"
+source = "git+git://git.taler.net/taler-rust.git/#7bfaf2c5e3f7ee89c29cc9175da77ee7cb582b18"
dependencies = [
"aws-lc-rs",
"axum",
@@ -3793,9 +3795,9 @@ dependencies = [
[[package]]
name = "yoke-derive"
-version = "0.8.3"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78"
+checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71"
dependencies = [
"proc-macro2",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
@@ -29,6 +29,7 @@ url = { version = "2.2", features = ["serde"] }
taler-common = { git = "git://git.taler.net/taler-rust.git/" }
taler-api = { git = "git://git.taler.net/taler-rust.git/" }
taler-build = { git = "git://git.taler.net/taler-rust.git/" }
+taler-macros = { git = "git://git.taler.net/taler-rust.git/" }
taler-test-utils = { git = "git://git.taler.net/taler-rust.git/" }
failure-injection = { git = "git://git.taler.net/taler-rust.git/" }
depolymerizer-common = { path = "depolymerizer-common" }
diff --git a/depolymerizer-bitcoin/Cargo.toml b/depolymerizer-bitcoin/Cargo.toml
@@ -22,6 +22,7 @@ anyhow.workspace = true
taler-api.workspace = true
taler-build.workspace = true
taler-common.workspace = true
+taler-macros.workspace = true
failure-injection.workspace = true
sqlx.workspace = true
tokio.workspace = true
diff --git a/depolymerizer-bitcoin/src/api.rs b/depolymerizer-bitcoin/src/api.rs
@@ -415,8 +415,8 @@ pub mod test {
db::IncomingType,
types::amount::{Currency, amount},
};
+ use taler_macros::db_test;
use taler_test_utils::{
- db::db_test_setup,
routine::{
Status, admin_add_incoming_routine, out_history_routine, registration_routine,
revenue_routine, transfer_routine,
@@ -426,7 +426,6 @@ pub mod test {
};
use crate::{
- CONFIG_SOURCE,
api::ServerState,
db::{TxOut, TxOutKind, sync_out, test::rand_tx_id},
payto::FullBtcPayto,
@@ -453,27 +452,24 @@ pub mod test {
.unwrap()
});
- async fn setup() -> (Router, PgPool) {
- let (_, pool) = db_test_setup(CONFIG_SOURCE).await;
+ async fn setup(db: &PgPool) -> Router {
let api = ServerState::start(
- pool.clone(),
+ db.clone(),
EXCHANGE.clone(),
Currency::from_str("BTC").unwrap(),
)
.await;
- let server = Router::new()
+ Router::new()
.wire_gateway(api.clone(), AuthMethod::None)
.prepared_transfer(api.clone())
.revenue(api.clone(), AuthMethod::None)
.observability(api, AuthMethod::None)
- .finalize();
-
- (server, pool)
+ .finalize()
}
- #[tokio::test]
- async fn config() {
- let (server, _) = setup().await;
+ #[db_test]
+ async fn config(db: PgPool) {
+ let server = setup(&db).await;
server
.get("/taler-wire-gateway/config")
.await
@@ -493,9 +489,9 @@ pub mod test {
server.get("/taler-observability/metrics").await.assert_ok();
}
- #[tokio::test]
- async fn transfer() {
- let (server, _) = setup().await;
+ #[db_test]
+ async fn transfer(db: PgPool) {
+ let server = setup(&db).await;
transfer_routine(
&server.prefix("/taler-wire-gateway"),
TransferState::pending,
@@ -504,9 +500,9 @@ pub mod test {
.await;
}
- #[tokio::test]
- async fn outgoing_history() {
- let (server, db) = setup().await;
+ #[db_test]
+ async fn outgoing_history(db: PgPool) {
+ let server = setup(&db).await;
out_history_routine(
&server.prefix("/taler-wire-gateway"),
tasks!({
@@ -535,9 +531,9 @@ pub mod test {
.await;
}
- #[tokio::test]
- async fn admin_add_incoming() {
- let (server, _) = setup().await;
+ #[db_test]
+ async fn admin_add_incoming(db: PgPool) {
+ let server = setup(&db).await;
admin_add_incoming_routine(
&server.prefix("/taler-wire-gateway"),
&server.prefix("/taler-prepared-transfer"),
@@ -547,9 +543,9 @@ pub mod test {
.await;
}
- #[tokio::test]
- async fn revenue() {
- let (server, _) = &setup().await;
+ #[db_test]
+ async fn revenue(db: PgPool) {
+ let server = setup(&db).await;
revenue_routine(
&server.prefix("/taler-wire-gateway"),
&server.prefix("/taler-revenue"),
@@ -592,16 +588,16 @@ pub mod test {
.unwrap()
}
- #[tokio::test]
- async fn registration() {
- let (server, pool) = setup().await;
+ #[db_test]
+ async fn registration(db: PgPool) {
+ let server = setup(&db).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),
+ || check_in(&db),
)
.await;
}
diff --git a/depolymerizer-bitcoin/src/bin/btc-harness.rs b/depolymerizer-bitcoin/src/bin/btc-harness.rs
@@ -26,8 +26,9 @@ use std::{
use bitcoin::{Address, Amount, Txid, address::NetworkUnchecked, hashes::Hash};
use clap::Parser as _;
use depolymerizer_bitcoin::{
- CONFIG_SOURCE, RpcApiExtended as _,
+ RpcApiExtended as _,
config::{RpcAuth, RpcCfg, WorkerCfg},
+ constants::CONFIG_SOURCE,
db::{self, dbinit, incoming_history, pool},
loops::{LoopError, LoopResult, analysis::analysis, worker::worker_step},
payto::{BtcWallet, FullBtcPayto},
diff --git a/depolymerizer-bitcoin/src/constants.rs b/depolymerizer-bitcoin/src/constants.rs
@@ -0,0 +1,19 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022-2025, 2026 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+
+use taler_common::config::parser::ConfigSource;
+
+pub const CONFIG_SOURCE: ConfigSource = ConfigSource::simple("depolymerizer-bitcoin");
diff --git a/depolymerizer-bitcoin/src/db.rs b/depolymerizer-bitcoin/src/db.rs
@@ -883,7 +883,7 @@ pub mod test {
hashes::{Hash as _, sha256d::Hash},
};
use jiff::Span;
- use sqlx::{PgPool, Postgres, pool::PoolConnection, postgres::PgRow};
+ use sqlx::{PgConnection, PgPool, postgres::PgRow};
use taler_api::{db::TypeHelper as _, notification::dummy_listen, subject::IncomingKey};
use taler_common::{
api::{EddsaPublicKey, HashCode, ShortHashCode, params::History, wire::TransferRequest},
@@ -893,9 +893,9 @@ pub mod test {
utils::now_sql_stable_ts,
},
};
+ use taler_macros::db_test;
use crate::{
- CONFIG_SOURCE,
api::test::CLIENT,
db::{
AddIncomingResult, ProblematicTx, SyncOutResult, SyncOutState, TransferResult, TxOut,
@@ -908,14 +908,8 @@ pub mod test {
pub const CURR: Currency = Currency::TEST;
- async fn setup() -> (PoolConnection<Postgres>, PgPool) {
- taler_test_utils::db::db_test_setup(CONFIG_SOURCE).await
- }
-
- #[tokio::test]
- async fn kv() {
- let (mut db, pool) = setup().await;
-
+ #[db_test]
+ async fn kv(mut db: PgConnection, pool: PgPool) {
// Empty status
update_status(&mut db, false).await.unwrap();
update_status(&mut db, true).await.unwrap();
@@ -953,15 +947,14 @@ pub mod test {
.assume_checked()
});
- #[tokio::test]
- async fn tx_in() {
- let (mut db, pool) = setup().await;
+ #[db_test]
+ async fn tx_in(mut db: PgConnection, pool: PgPool) {
let amount = amount("KUDOS:10");
let mut routine = async |first: &Option<IncomingKey>, second: &Option<IncomingKey>| {
let id = sqlx::query("SELECT count(*) + 1 FROM tx_in")
.try_map(|r: PgRow| r.try_get_u64(0))
- .fetch_one(&mut *db)
+ .fetch_one(&mut db)
.await
.unwrap();
let now = now_sql_stable_ts();
@@ -1056,10 +1049,8 @@ pub mod test {
);
}
- #[tokio::test]
- async fn tx_in_admin() {
- let (_, pool) = setup().await;
-
+ #[db_test]
+ async fn tx_in_admin(pool: PgPool) {
let amount = amount("KUDOS:10");
// Empty db
@@ -1119,9 +1110,8 @@ pub mod test {
);
}
- #[tokio::test]
- async fn sync_out_simple() {
- let (_, pool) = setup().await;
+ #[db_test]
+ async fn sync_out_simple(pool: PgPool) {
let amount = amount("KUDOS:10");
let now = now_sql_stable_ts();
@@ -1199,9 +1189,8 @@ pub mod test {
);
}
- #[tokio::test]
- async fn sync_out_talerable() {
- let (mut db, poll) = setup().await;
+ #[db_test]
+ async fn sync_out_talerable(mut db: PgConnection, pool: PgPool) {
let amount = amount("KUDOS:10");
let now = now_sql_stable_ts();
@@ -1214,7 +1203,7 @@ pub mod test {
metadata: None,
credit_account: CLIENT.as_uri(),
};
- let id = match transfer(&poll, &CLIENT, &t).await.unwrap() {
+ let id = match transfer(&pool, &CLIENT, &t).await.unwrap() {
TransferResult::Success(res) => res.row_id,
_ => unreachable!(),
};
@@ -1235,23 +1224,23 @@ pub mod test {
url,
metadata: None,
};
- transfer_sent(&mut *db, *id, &out.id).await.unwrap();
+ transfer_sent(&mut db, *id, &out.id).await.unwrap();
assert_eq!(
- sync_out(&poll, &out, &kind, false).await.unwrap(),
+ sync_out(&pool, &out, &kind, false).await.unwrap(),
SyncOutResult {
id: None,
state: SyncOutState::None
}
);
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::New
}
);
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::None
@@ -1274,24 +1263,24 @@ pub mod test {
url,
metadata: None,
};
- transfer_sent(&mut *db, *id, &tx_id).await.unwrap();
- transfer_conflict(&mut *db, &conflict_id).await.unwrap();
+ transfer_sent(&mut db, *id, &tx_id).await.unwrap();
+ transfer_conflict(&mut db, &conflict_id).await.unwrap();
assert_eq!(
- sync_out(&poll, &out, &kind, false).await.unwrap(),
+ sync_out(&pool, &out, &kind, false).await.unwrap(),
SyncOutResult {
id: None,
state: SyncOutState::None
}
);
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::New
}
);
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::None
@@ -1314,24 +1303,24 @@ pub mod test {
url,
metadata: None,
};
- transfer_sent(&mut *db, *id, &tx_id).await.unwrap();
+ transfer_sent(&mut db, *id, &tx_id).await.unwrap();
transfer_bumpfee(&mut db, &bump_id, wtid).await.unwrap();
assert_eq!(
- sync_out(&poll, &out, &kind, false).await.unwrap(),
+ sync_out(&pool, &out, &kind, false).await.unwrap(),
SyncOutResult {
id: None,
state: SyncOutState::None
}
);
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::New
}
);
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::None
@@ -1353,14 +1342,14 @@ pub mod test {
metadata: None,
};
assert_eq!(
- sync_out(&poll, &out, &kind, false).await.unwrap(),
+ sync_out(&pool, &out, &kind, false).await.unwrap(),
SyncOutResult {
id: None,
state: SyncOutState::Recovered
}
);
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::New
@@ -1382,14 +1371,14 @@ pub mod test {
metadata: None,
};
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::Recovered
}
);
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::None
@@ -1411,14 +1400,14 @@ pub mod test {
metadata: None,
};
assert_eq!(
- sync_out(&poll, &out, &kind, false).await.unwrap(),
+ sync_out(&pool, &out, &kind, false).await.unwrap(),
SyncOutResult {
id: None,
state: SyncOutState::Recovered
}
);
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::New
@@ -1440,14 +1429,14 @@ pub mod test {
metadata: None,
};
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::Recovered
}
);
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::None
@@ -1469,16 +1458,16 @@ pub mod test {
url,
metadata: None,
};
- transfer_sent(&mut *db, *id, &txid).await.unwrap();
+ transfer_sent(&mut db, *id, &txid).await.unwrap();
assert_eq!(
- sync_out(&poll, &out, &kind, false).await.unwrap(),
+ sync_out(&pool, &out, &kind, false).await.unwrap(),
SyncOutResult {
id: None,
state: SyncOutState::Replaced
}
);
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::New
@@ -1500,16 +1489,16 @@ pub mod test {
url,
metadata: None,
};
- transfer_sent(&mut *db, *id, &txid).await.unwrap();
+ transfer_sent(&mut db, *id, &txid).await.unwrap();
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::Replaced
}
);
assert_eq!(
- sync_out(&poll, &out, &kind, true).await.unwrap(),
+ sync_out(&pool, &out, &kind, true).await.unwrap(),
SyncOutResult {
id: Some(*id),
state: SyncOutState::None
@@ -1518,12 +1507,11 @@ pub mod test {
// Failure
let (id, _, _) = &prepare_transfer().await;
- transfer_ignored(&mut *db, *id, "Oh nooooo").await.unwrap();
+ transfer_ignored(&mut db, *id, "Oh nooooo").await.unwrap();
}
- #[tokio::test]
- async fn bounces() {
- let (_, db) = setup().await;
+ #[db_test]
+ async fn bounces(db: PgPool) {
let amount = amount("KUDOS:10");
let now = now_sql_stable_ts();
@@ -1609,9 +1597,8 @@ pub mod test {
assert_eq!(pending_bounce(&db).await.unwrap(), None);
}
- #[tokio::test]
- async fn reorgs() {
- let (_, pool) = setup().await;
+ #[db_test]
+ async fn reorgs(pool: PgPool) {
let amount = amount("KUDOS:10");
let now = now_sql_stable_ts();
diff --git a/depolymerizer-bitcoin/src/lib.rs b/depolymerizer-bitcoin/src/lib.rs
@@ -19,13 +19,14 @@ use bitcoin::{Address, Amount, Network, Txid, hashes::hex::FromHex};
use rpc::{Category, Transaction};
use rpc_utils::segwit_min_amount;
use segwit::{decode_segwit_msg, encode_segwit_key};
-use taler_common::{api::EddsaPublicKey, config::parser::ConfigSource};
+use taler_common::api::EddsaPublicKey;
use crate::{rpc::RpcApi, segwit::DecodeSegWitErr};
pub mod api;
pub mod cli;
pub mod config;
+pub mod constants;
pub mod db;
pub mod loops;
pub mod payto;
@@ -36,8 +37,6 @@ pub mod setup;
pub mod sql;
pub mod taler_utils;
-pub const CONFIG_SOURCE: ConfigSource = ConfigSource::simple("depolymerizer-bitcoin");
-
#[derive(Debug, thiserror::Error)]
pub enum GetOpReturnErr {
#[error("Missing opreturn")]
diff --git a/depolymerizer-bitcoin/src/main.rs b/depolymerizer-bitcoin/src/main.rs
@@ -16,8 +16,8 @@
use clap::Parser as _;
use depolymerizer_bitcoin::{
- CONFIG_SOURCE,
cli::{Args, run},
+ constants::CONFIG_SOURCE,
};
use taler_common::taler_main;