commit 8e33065eacbe23ec3dff71e630bb765cab7a7a3a
parent 77f35d8fc62fb899aa7faf9e0f884d695365631f
Author: Antoine A <>
Date: Wed, 18 Mar 2026 12:15:01 +0100
common: add regex config, replace fastrand by rand and improve utils
Diffstat:
19 files changed, 119 insertions(+), 76 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -40,7 +40,6 @@ sqlx = { version = "0.8", default-features = false, features = [
] }
url = { version = "2.2", features = ["serde"] }
criterion = { version = "0.8", default-features = false }
-fastrand = { version = "2.2", default-features = false }
tracing = "0.1"
tracing-subscriber = "0.3"
clap = { version = "4.5", features = ["derive"] }
@@ -58,4 +57,6 @@ http-body-util = "0.1.2"
base64 = "0.22"
owo-colors = "4.2.3"
aws-lc-rs = "1.15"
-compact_str = { version = "0.9.0", features = ["serde", "sqlx-postgres"] }
-\ No newline at end of file
+compact_str = { version = "0.9.0", features = ["serde", "sqlx-postgres"] }
+rand = { version = "0.10" }
+regex = { version = "1" }
diff --git a/common/taler-api/Cargo.toml b/common/taler-api/Cargo.toml
@@ -30,7 +30,7 @@ compact_str.workspace = true
[dev-dependencies]
taler-test-utils.workspace = true
criterion.workspace = true
-fastrand.workspace = true
+rand.workspace = true
[[bench]]
name = "subject"
diff --git a/common/taler-api/benches/subject.rs b/common/taler-api/benches/subject.rs
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2024-2025 Taler Systems SA
+ Copyright (C) 2024, 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
@@ -17,11 +17,12 @@
use std::hint::black_box;
use criterion::{Criterion, criterion_group, criterion_main};
+use rand::{SeedableRng, seq::IndexedRandom};
use taler_api::subject::parse_incoming_unstructured;
fn parser(c: &mut Criterion) {
const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789::: \t\t\t\t\n\n\n\n----++++";
- let mut rng = fastrand::Rng::with_seed(42);
+ let mut rng = rand::rngs::SmallRng::seed_from_u64(42);
let real_simple = [
"Taler TEGY6d9mh9pgwvwpgs0z0095z854xegfy7jj202yd0esp8p0za60",
"00Q979QSMJ29S7BJT3DDAVC5A0DR5Z05B7N0QT1RCBQ8FXJPZ6RG",
@@ -40,9 +41,12 @@ fn parser(c: &mut Criterion) {
];
let randoms: Vec<String> = (0..30)
.map(|_| {
- (0..256)
- .map(|_| *rng.choice(CHARS).unwrap() as char)
- .collect()
+ CHARS
+ .choose_iter(&mut rng)
+ .unwrap()
+ .take(256)
+ .map(|c| *c as char)
+ .collect::<String>()
})
.collect();
let chunks: Vec<String> = [
diff --git a/common/taler-api/src/db.rs b/common/taler-api/src/db.rs
@@ -33,7 +33,7 @@ use taler_common::{
amount::{Amount, Currency, Decimal},
iban::IBAN,
payto::PaytoURI,
- utils::date_to_utc_timestamp,
+ utils::date_to_utc_ts,
},
};
use tokio::sync::watch::Receiver;
@@ -133,7 +133,7 @@ impl<'q> BindHelper for Query<'q, Postgres, <Postgres as sqlx::Database>::Argume
}
fn bind_date(self, date: &Date) -> Self {
- self.bind_timestamp(&date_to_utc_timestamp(date))
+ self.bind_timestamp(&date_to_utc_ts(date))
}
}
diff --git a/common/taler-api/src/subject.rs b/common/taler-api/src/subject.rs
@@ -45,7 +45,7 @@ impl IncomingSubject {
pub fn key(&self) -> &[u8] {
match self {
- IncomingSubject::Kyc(key) | IncomingSubject::Reserve(key) => key.as_ref().as_ref(),
+ IncomingSubject::Kyc(key) | IncomingSubject::Reserve(key) => key.as_ref(),
}
}
}
diff --git a/common/taler-api/tests/common/db.rs b/common/taler-api/tests/common/db.rs
@@ -64,8 +64,8 @@ pub async fn transfer(db: &PgPool, transfer: TransferRequest) -> sqlx::Result<Tr
.bind(transfer.exchange_base_url.as_str())
.bind(format!("{} {}", transfer.wtid, transfer.exchange_base_url))
.bind(transfer.credit_account.raw())
- .bind(transfer.request_uid.as_slice())
- .bind(transfer.wtid.as_slice())
+ .bind(transfer.request_uid)
+ .bind(transfer.wtid)
.bind_timestamp(&Timestamp::now())
.try_map(|r: PgRow| {
Ok(if r.try_get_flag("out_request_uid_reuse")? {
@@ -221,7 +221,7 @@ pub async fn add_incoming(
.bind(subject)
.bind(debit_account.raw())
.bind(kind)
- .bind(key.as_ref().as_slice())
+ .bind(key)
.bind_timestamp(timestamp)
.try_map(|r: PgRow| {
Ok(if r.try_get_flag("out_reserve_pub_reuse")? {
diff --git a/common/taler-common/Cargo.toml b/common/taler-common/Cargo.toml
@@ -19,7 +19,7 @@ serde_with.workspace = true
serde_urlencoded.workspace = true
url.workspace = true
thiserror.workspace = true
-fastrand.workspace = true
+rand.workspace = true
tracing.workspace = true
clap.workspace = true
anyhow.workspace = true
@@ -28,6 +28,7 @@ tokio = { workspace = true, features = ["rt-multi-thread"] }
sqlx = { workspace = true, features = ["macros"] }
compact_str.workspace = true
aws-lc-rs.workspace = true
+regex.workspace = true
[dev-dependencies]
criterion.workspace = true
diff --git a/common/taler-common/benches/base32.rs b/common/taler-common/benches/base32.rs
@@ -15,17 +15,14 @@
*/
use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
+use rand::RngExt as _;
use taler_common::types::base32::{Base32, decode_static, encode_static};
fn parser(c: &mut Criterion) {
let mut buf = [0u8; 255];
c.bench_function("base32_encode_random", |b| {
b.iter_batched(
- || {
- let mut bytes = [0; 64];
- fastrand::fill(&mut bytes);
- bytes
- },
+ rand::random::<[u8; 64]>,
|case| {
encode_static(&case, &mut buf);
},
@@ -41,7 +38,12 @@ fn parser(c: &mut Criterion) {
});
c.bench_function("base32_decode_random", |b| {
b.iter_batched(
- || (0..56).map(|_| fastrand::char(..)).collect::<String>(),
+ || {
+ rand::rng()
+ .sample_iter::<char, _>(&rand::distr::StandardUniform)
+ .take(56)
+ .collect::<String>()
+ },
|case| decode_static::<64>(case.as_bytes()).ok(),
BatchSize::SmallInput,
)
diff --git a/common/taler-common/benches/iban.rs b/common/taler-common/benches/iban.rs
@@ -17,6 +17,7 @@
use std::str::FromStr;
use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
+use rand::{RngExt, distr::Alphanumeric, seq::IndexedRandom};
use taler_common::types::iban::{
Country::{self, *},
IBAN,
@@ -33,8 +34,9 @@ fn parser(c: &mut Criterion) {
c.bench_function("iban_random_all", |b| {
b.iter_batched(
|| {
- (0..fastrand::usize(0..40))
- .map(|_| fastrand::char(..))
+ rand::rng()
+ .sample_iter::<char, _>(rand::distr::StandardUniform)
+ .take(40)
.collect::<String>()
},
|case| IBAN::from_str(&case),
@@ -44,8 +46,10 @@ fn parser(c: &mut Criterion) {
c.bench_function("iban_random_alphanumeric", |b| {
b.iter_batched(
|| {
- (0..fastrand::usize(0..40))
- .map(|_| fastrand::alphanumeric())
+ rand::rng()
+ .sample_iter(&Alphanumeric)
+ .take(40)
+ .map(char::from)
.collect::<String>()
},
|case| IBAN::from_str(&case),
@@ -55,7 +59,7 @@ fn parser(c: &mut Criterion) {
c.bench_function("iban_valid", |b| {
b.iter_batched(
- || IBAN::random(fastrand::choice(COUNTRIES).unwrap()).to_string(),
+ || IBAN::random(*COUNTRIES.choose(&mut rand::rng()).unwrap()).to_string(),
|case| IBAN::from_str(&case).unwrap(),
BatchSize::SmallInput,
)
diff --git a/common/taler-common/src/api_common.rs b/common/taler-common/src/api_common.rs
@@ -126,8 +126,10 @@ pub type EddsaSignature = Base32<64>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EddsaPublicKey(Base32<32>);
-impl AsRef<Base32<32>> for EddsaPublicKey {
- fn as_ref(&self) -> &Base32<32> {
+impl Deref for EddsaPublicKey {
+ type Target = Base32<32>;
+
+ fn deref(&self) -> &Self::Target {
&self.0
}
}
@@ -183,6 +185,15 @@ impl TryFrom<&[u8]> for EddsaPublicKey {
}
}
+impl TryFrom<[u8; 32]> for EddsaPublicKey {
+ type Error = EddsaPublicKeyError;
+
+ fn try_from(value: [u8; 32]) -> Result<Self, Self::Error> {
+ let encoded = Base32::from(value);
+ Self::try_from(encoded)
+ }
+}
+
impl TryFrom<Base32<32>> for EddsaPublicKey {
type Error = EddsaPublicKeyError;
@@ -193,10 +204,6 @@ impl TryFrom<Base32<32>> for EddsaPublicKey {
}
impl EddsaPublicKey {
- pub fn slice(&self) -> &[u8; 32] {
- self.0.deref()
- }
-
pub fn rand() -> EddsaPublicKey {
let signing_key = Ed25519KeyPair::generate().unwrap();
let bytes: [u8; 32] = signing_key.public_key().as_ref().try_into().unwrap();
diff --git a/common/taler-common/src/config.rs b/common/taler-common/src/config.rs
@@ -829,12 +829,16 @@ impl<'cfg, 'arg> Section<'cfg, 'arg> {
})
}
- /** Access [option] as Amount */
- pub fn amount(&self, option: &'arg str, currency: &str) -> Value<'arg, Amount> {
- let currency: Currency = currency.parse().unwrap();
+ /** Access [option] as a Currency */
+ pub fn currency(&self, option: &'arg str) -> Value<'arg, Currency> {
+ self.parse("currency", option)
+ }
+
+ /** Access [option] as an Amount */
+ pub fn amount(&self, option: &'arg str, currency: &Currency) -> Value<'arg, Amount> {
self.value("amount", option, |it| {
let amount = it.parse::<Amount>().map_err(|e| e.to_string())?;
- if amount.currency != currency {
+ if amount.currency != *currency {
return Err(format!(
"expected currency {currency} got {}",
amount.currency
@@ -893,7 +897,12 @@ impl<'cfg, 'arg> Section<'cfg, 'arg> {
self.parse("Timestamp", option)
}
- /** Access [option] as a date time */
+ /** Access [option] as a time */
+ pub fn time(&self, option: &'arg str) -> Value<'arg, jiff::civil::Time> {
+ self.parse("Time", option)
+ }
+
+ /** Access [option] as a date */
pub fn date(&self, option: &'arg str) -> Value<'arg, jiff::civil::Date> {
self.parse("Date", option)
}
@@ -905,6 +914,11 @@ impl<'cfg, 'arg> Section<'cfg, 'arg> {
Ok::<_, String>(Duration::from_millis(tmp.as_millis() as u64))
})
}
+
+ /** Access [option] as a regex */
+ pub fn regex(&self, option: &'arg str) -> Value<'arg, regex::Regex> {
+ self.parse("Pattern", option)
+ }
}
pub struct Value<'arg, T> {
@@ -940,11 +954,15 @@ mod test {
fmt::{Debug, Display},
fs::{File, Permissions},
os::unix::fs::PermissionsExt,
+ str::FromStr,
};
use tracing::error;
- use crate::{config::parser::ConfigSource, types::amount};
+ use crate::{
+ config::parser::ConfigSource,
+ types::amount::{self, Currency},
+ };
use super::{Config, Section, Value};
@@ -1075,7 +1093,7 @@ mod test {
fn routine<T: Debug + Eq>(
ty: &str,
- lambda: for<'cfg, 'arg> fn(&Section<'cfg, 'arg>, &'arg str) -> Value<'arg, T>,
+ mut lambda: impl for<'cfg, 'arg> FnMut(&Section<'cfg, 'arg>, &'arg str) -> Value<'arg, T>,
wellformed: &[(&[&str], T)],
malformed: &[(&[&str], fn(&str) -> String)],
) {
@@ -1209,9 +1227,10 @@ mod test {
#[test]
fn amount() {
+ let currency = Currency::from_str("KUDOS").unwrap();
routine(
"amount",
- |sect, value| sect.amount(value, "KUDOS"),
+ |sect, value| sect.amount(value, ¤cy),
&[(
&["KUDOS:12", "KUDOS:12.0", "KUDOS:012.0"],
amount::amount("KUDOS:12"),
diff --git a/common/taler-common/src/lib.rs b/common/taler-common/src/lib.rs
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2024-2025 Taler Systems SA
+ Copyright (C) 2024, 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
@@ -96,7 +96,7 @@ impl ExpoBackoffDecorr {
pub fn backoff(&mut self) -> Duration {
self.sleep =
- fastrand::u32(self.base..(self.sleep as f32 * self.factor) as u32).min(self.max);
+ rand::random_range(self.base..(self.sleep as f32 * self.factor) as u32).min(self.max);
Duration::from_millis(self.sleep as u64)
}
diff --git a/common/taler-common/src/types/amount.rs b/common/taler-common/src/types/amount.rs
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2024-2025 Taler Systems SA
+ Copyright (C) 2024, 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
@@ -308,6 +308,12 @@ impl Amount {
let decimal = self.decimal().try_add(&rhs.decimal())?.normalize()?;
Some((self.currency, decimal).into())
}
+
+ pub fn try_sub(self, rhs: &Self) -> Option<Self> {
+ assert_eq!(self.currency, rhs.currency);
+ let decimal = self.decimal().try_sub(&rhs.decimal())?.normalize()?;
+ Some((self.currency, decimal).into())
+ }
}
impl From<(Currency, Decimal)> for Amount {
diff --git a/common/taler-common/src/types/base32.rs b/common/taler-common/src/types/base32.rs
@@ -188,9 +188,7 @@ pub struct Base32<const L: usize>([u8; L]);
impl<const L: usize> Base32<L> {
pub fn rand() -> Self {
- let mut bytes = [0; L];
- fastrand::fill(&mut bytes);
- Self(bytes)
+ Self(rand::random())
}
}
diff --git a/common/taler-common/src/types/iban/registry.rs b/common/taler-common/src/types/iban/registry.rs
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2025 Taler Systems SA
+ Copyright (C) 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
@@ -18,6 +18,7 @@ use std::fmt::Display;
use Country::*;
use IbanC::*;
+use rand::seq::IndexedRandom;
/// IBAN ASCII characters rules
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -1016,6 +1017,7 @@ impl Display for Country {
/// Generate random ASCII string following an IBAN pattern rules
pub fn rng_pattern(out: &mut [u8], pattern: Pattern) {
let mut cursor = 0;
+ let mut rng = rand::rng();
for (len, rule) in pattern {
let alphabet = match rule {
IbanC::C => "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
@@ -1023,7 +1025,7 @@ pub fn rng_pattern(out: &mut [u8], pattern: Pattern) {
IbanC::A => "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
};
for b in &mut out[cursor..cursor + *len as usize] {
- *b = *fastrand::choice(alphabet.as_bytes()).unwrap();
+ *b = *alphabet.as_bytes().choose(&mut rng).unwrap();
}
cursor += *len as usize
}
diff --git a/common/taler-common/src/types/utils.rs b/common/taler-common/src/types/utils.rs
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2025 Taler Systems SA
+ Copyright (C) 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
@@ -92,11 +92,11 @@ impl<const LEN: usize> Deref for InlineStr<LEN> {
}
/** Convert a date to a UTC timestamp */
-pub fn date_to_utc_timestamp(date: &Date) -> Timestamp {
+pub fn date_to_utc_ts(date: &Date) -> Timestamp {
date.to_zoned(TimeZone::UTC).unwrap().timestamp()
}
/** Get current timestamp truncated to micros precision */
-pub fn now_sql_stable_timestamp() -> Timestamp {
+pub fn now_sql_stable_ts() -> Timestamp {
Timestamp::from_microsecond(Timestamp::now().as_microsecond()).unwrap()
}
diff --git a/taler-cyclos/src/db.rs b/taler-cyclos/src/db.rs
@@ -324,8 +324,8 @@ pub async fn register_tx_out(
.bind(None::<i64>),
TxOutKind::Bounce(bounced) => query.bind(None::<&[u8]>).bind(None::<&str>).bind(*bounced),
TxOutKind::Talerable(subject) => query
- .bind(subject.wtid.as_ref())
- .bind(subject.exchange_base_url.as_ref())
+ .bind(&subject.wtid)
+ .bind(subject.exchange_base_url.as_str())
.bind(None::<i64>),
};
query
@@ -369,8 +369,8 @@ pub async fn make_transfer<'a>(
FROM taler_transfer($1, $2, $3, $4, $5, $6, $7, $8)
",
)
- .bind(tx.request_uid.as_ref())
- .bind(tx.wtid.as_ref())
+ .bind(&tx.request_uid)
+ .bind(&tx.wtid)
.bind(&subject)
.bind(tx.amount)
.bind(tx.exchange_base_url.as_str())
@@ -853,7 +853,7 @@ mod test {
types::{
amount::{Currency, decimal},
url,
- utils::now_sql_stable_timestamp,
+ utils::now_sql_stable_ts,
},
};
@@ -913,7 +913,7 @@ mod test {
.fetch_one(&mut *db)
.await
.unwrap();
- let now = now_sql_stable_timestamp();
+ let now = now_sql_stable_ts();
let later = now + Span::new().hours(2);
let tx = TxIn {
transfer_id: now.as_microsecond() as i64,
@@ -1038,7 +1038,7 @@ mod test {
Vec::new()
);
- let now = now_sql_stable_timestamp();
+ let now = now_sql_stable_ts();
let later = now + Span::new().hours(2);
let tx = TxInAdmin {
amount: decimal("10"),
@@ -1109,7 +1109,7 @@ mod test {
.fetch_one(&mut *db)
.await
.unwrap();
- let now = now_sql_stable_timestamp();
+ let now = now_sql_stable_ts();
let later = now + Span::new().hours(2);
let tx = TxOut {
transfer_id,
@@ -1251,7 +1251,7 @@ mod test {
creditor_id: 31000163100000000,
creditor_name: "Name".into(),
};
- let now = now_sql_stable_timestamp();
+ let now = now_sql_stable_ts();
let later = now + Span::new().hours(2);
// Insert
assert_eq!(
@@ -1353,7 +1353,7 @@ mod test {
let (mut db, _) = setup().await;
let amount = decimal("10");
- let now = now_sql_stable_timestamp();
+ let now = now_sql_stable_ts();
// Bounce
assert_eq!(
diff --git a/taler-magnet-bank/src/api.rs b/taler-magnet-bank/src/api.rs
@@ -30,7 +30,7 @@ use taler_common::{
TransferState, TransferStatus,
},
error_code::ErrorCode,
- types::{payto::PaytoURI, utils::date_to_utc_timestamp},
+ types::{payto::PaytoURI, utils::date_to_utc_ts},
};
use tokio::sync::watch::Sender;
@@ -171,7 +171,7 @@ impl WireGateway for MagnetApi {
row_id, valued_at, ..
} => Ok(AddIncomingResponse {
row_id: safe_u64(row_id),
- timestamp: date_to_utc_timestamp(&valued_at).into(),
+ timestamp: date_to_utc_ts(&valued_at).into(),
}),
AddIncomingResult::ReservePubReuse => Err(failure(
ErrorCode::BANK_DUPLICATE_RESERVE_PUB_SUBJECT,
@@ -198,7 +198,7 @@ impl WireGateway for MagnetApi {
row_id, valued_at, ..
} => Ok(AddKycauthResponse {
row_id: safe_u64(row_id),
- timestamp: date_to_utc_timestamp(&valued_at).into(),
+ timestamp: date_to_utc_ts(&valued_at).into(),
}),
AddIncomingResult::ReservePubReuse => Err(failure(
ErrorCode::BANK_DUPLICATE_RESERVE_PUB_SUBJECT,
diff --git a/taler-magnet-bank/src/db.rs b/taler-magnet-bank/src/db.rs
@@ -312,8 +312,8 @@ pub async fn register_tx_out(
.bind(None::<&str>)
.bind(*bounced as i64),
TxOutKind::Talerable(subject) => query
- .bind(subject.wtid.as_ref())
- .bind(subject.exchange_base_url.as_ref())
+ .bind(&subject.wtid)
+ .bind(subject.exchange_base_url.as_str())
.bind(None::<i64>),
};
query
@@ -387,8 +387,8 @@ pub async fn make_transfer<'a>(
FROM taler_transfer($1, $2, $3, $4, $5, $6, $7, $8)
",
)
- .bind(tx.request_uid.as_ref())
- .bind(tx.wtid.as_ref())
+ .bind(&tx.request_uid)
+ .bind(&tx.wtid)
.bind(&subject)
.bind(tx.amount)
.bind(tx.exchange_base_url.as_str())
@@ -819,7 +819,7 @@ mod test {
types::{
amount::{amount, decimal},
url,
- utils::now_sql_stable_timestamp,
+ utils::now_sql_stable_ts,
},
};
@@ -878,7 +878,7 @@ mod test {
.fetch_one(&mut *db)
.await
.unwrap();
- let now = now_sql_stable_timestamp();
+ let now = now_sql_stable_ts();
let date = Zoned::now().date();
let later = date.tomorrow().unwrap();
let tx = TxIn {
@@ -1005,7 +1005,7 @@ mod test {
Vec::new()
);
- let now = now_sql_stable_timestamp();
+ let now = now_sql_stable_ts();
let later = now + Span::new().hours(2);
let date = Zoned::now().date();
let tx = TxInAdmin {
@@ -1077,7 +1077,7 @@ mod test {
.fetch_one(&mut *db)
.await
.unwrap();
- let now = now_sql_stable_timestamp();
+ let now = now_sql_stable_ts();
let date = Zoned::now().date();
let later = date.tomorrow().unwrap();
let tx = TxOut {
@@ -1195,7 +1195,7 @@ mod test {
async fn tx_out_failure() {
let (mut db, _) = setup().await;
- let now = now_sql_stable_timestamp();
+ let now = now_sql_stable_ts();
// Unknown
assert_eq!(
@@ -1315,7 +1315,7 @@ mod test {
wtid: ShortHashCode::rand(),
creditor: magnet_payto("payto://iban/HU02162000031000164800000000?receiver-name=name"),
};
- let now = now_sql_stable_timestamp();
+ let now = now_sql_stable_ts();
let later = now + Span::new().hours(2);
// Insert
assert_eq!(
@@ -1401,7 +1401,7 @@ mod test {
let amount = amount("HUF:10");
let payto = magnet_payto("payto://iban/HU30162000031000163100000000?receiver-name=name");
- let now = now_sql_stable_timestamp();
+ let now = now_sql_stable_ts();
let date = Zoned::now().date();
// Empty db