taler-rust

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

commit 8d324855c5196858bfab1d1109be96df88f372d7
parent 7d17036797515db23661d670b40acd0ea792216f
Author: Antoine A <>
Date:   Fri, 28 Nov 2025 21:51:07 +0100

common: stop using taler weird timestamp everywhere

Diffstat:
Mcommon/taler-api/src/db.rs | 11+++++++----
Mcommon/taler-api/tests/common/db.rs | 18+++++++++---------
Mcommon/taler-api/tests/common/mod.rs | 7++++---
Mcommon/taler-build/build.rs | 2+-
Mcommon/taler-common/src/api_revenue.rs | 4++--
Mcommon/taler-common/src/api_wire.rs | 18+++++++++---------
Mcommon/taler-common/src/types/timestamp.rs | 102++++++++++++++++++++-----------------------------------------------------------
Mcommon/taler-common/src/types/utils.rs | 12+++++++-----
Mtaler-magnet-bank/src/api.rs | 9+++++----
Mtaler-magnet-bank/src/bin/magnet-bank-harness.rs | 4++--
Mtaler-magnet-bank/src/db.rs | 42+++++++++++++++++++++---------------------
Mtaler-magnet-bank/src/worker.rs | 3+--
Mtaler-magnet-bank/tests/api.rs | 5++---
13 files changed, 96 insertions(+), 141 deletions(-)

diff --git a/common/taler-api/src/db.rs b/common/taler-api/src/db.rs @@ -17,6 +17,7 @@ use std::{str::FromStr, time::Duration}; use jiff::{ + Timestamp, civil::{Date, Time}, tz::TimeZone, }; @@ -33,7 +34,6 @@ use taler_common::{ base32::Base32, iban::IBAN, payto::PaytoURI, - timestamp::Timestamp, utils::date_to_utc_timestamp, }, }; @@ -140,7 +140,7 @@ impl<'q> BindHelper for Query<'q, Postgres, <Postgres as sqlx::Database>::Argume } fn bind_timestamp(self, timestamp: &Timestamp) -> Self { - self.bind(timestamp.as_sql_micros()) + self.bind(timestamp.as_microsecond()) } fn bind_date(self, date: &Date) -> Self { @@ -168,11 +168,14 @@ pub trait TypeHelper { index: I, ) -> sqlx::Result<T>; fn try_get_timestamp<I: sqlx::ColumnIndex<Self>>(&self, index: I) -> sqlx::Result<Timestamp> { - self.try_get_map(index, Timestamp::from_sql_micros) + self.try_get_map(index, |micros| { + jiff::Timestamp::from_microsecond(micros) + .map_err(|e| format!("expected timestamp micros got overflowing {micros}: {e}")) + }) } fn try_get_date<I: sqlx::ColumnIndex<Self>>(&self, index: I) -> sqlx::Result<Date> { let timestamp = self.try_get_timestamp(index)?; - let zoned = timestamp.0.to_zoned(TimeZone::UTC); + let zoned = timestamp.to_zoned(TimeZone::UTC); assert_eq!(zoned.time(), Time::midnight()); Ok(zoned.date()) } diff --git a/common/taler-api/tests/common/db.rs b/common/taler-api/tests/common/db.rs @@ -14,6 +14,7 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ +use jiff::Timestamp; use sqlx::{PgPool, QueryBuilder, Row, postgres::PgRow}; use taler_api::db::{BindHelper, IncomingType, TypeHelper, history, page}; use taler_common::{ @@ -27,7 +28,6 @@ use taler_common::{ types::{ amount::{Amount, Currency}, payto::PaytoURI, - timestamp::Timestamp, }, }; use tokio::sync::watch::{Receiver, Sender}; @@ -75,7 +75,7 @@ pub async fn transfer(db: &PgPool, transfer: TransferRequest) -> sqlx::Result<Tr } else { TransferResult::Success(TransferResponse { row_id: r.try_get_safeu64("out_transfer_row_id")?, - timestamp: r.try_get_timestamp("out_created_at")?, + timestamp: r.try_get_timestamp("out_created_at")?.into(), }) }) }) @@ -117,7 +117,7 @@ pub async fn transfer_page( status: r.try_get("status")?, amount: r.try_get_amount("amount", currency)?, credit_account: r.try_get_payto("credit_payto")?, - timestamp: r.try_get_timestamp("created_at")?, + timestamp: r.try_get_timestamp("created_at")?.into(), }) }, ) @@ -152,7 +152,7 @@ pub async fn transfer_by_id( origin_exchange_url: r.try_get("exchange_base_url")?, wtid: r.try_get_base32("wtid")?, credit_account: r.try_get_payto("credit_payto")?, - timestamp: r.try_get_timestamp("created_at")?, + timestamp: r.try_get_timestamp("created_at")?.into(), }) }) .fetch_optional(db) @@ -191,7 +191,7 @@ pub async fn outgoing_revenue( wtid: r.try_get_base32("wtid")?, credit_account: r.try_get_payto("credit_payto")?, row_id: r.try_get_safeu64("transfer_id")?, - date: r.try_get_timestamp("created_at")?, + date: r.try_get_timestamp("created_at")?.into(), exchange_base_url: r.try_get_url("exchange_base_url")?, }) }, @@ -271,21 +271,21 @@ pub async fn incoming_history( Ok(match kind { IncomingType::reserve => IncomingBankTransaction::Reserve { row_id: r.try_get_safeu64("tx_in_id")?, - date: r.try_get_timestamp("created_at")?, + date: r.try_get_timestamp("created_at")?.into(), amount: r.try_get_amount("amount", currency)?, debit_account: r.try_get_payto("debit_payto")?, reserve_pub: r.try_get_base32("metadata")?, }, IncomingType::kyc => IncomingBankTransaction::Kyc { row_id: r.try_get_safeu64("tx_in_id")?, - date: r.try_get_timestamp("created_at")?, + date: r.try_get_timestamp("created_at")?.into(), amount: r.try_get_amount("amount", currency)?, debit_account: r.try_get_payto("debit_payto")?, account_pub: r.try_get_base32("metadata")?, }, IncomingType::wad => IncomingBankTransaction::Wad { row_id: r.try_get_safeu64("tx_in_id")?, - date: r.try_get_timestamp("created_at")?, + date: r.try_get_timestamp("created_at")?.into(), amount: r.try_get_amount("amount", currency)?, debit_account: r.try_get_payto("debit_payto")?, origin_exchange_url: r.try_get_url("origin_exchange_url")?, @@ -325,7 +325,7 @@ pub async fn revenue_history( |r: PgRow| { Ok(RevenueIncomingBankTransaction { row_id: r.try_get_safeu64("tx_in_id")?, - date: r.try_get_timestamp("created_at")?, + date: r.try_get_timestamp("created_at")?.into(), amount: r.try_get_amount("amount", currency)?, credit_fee: None, debit_account: r.try_get_payto("debit_payto")?, diff --git a/common/taler-api/tests/common/mod.rs b/common/taler-api/tests/common/mod.rs @@ -17,6 +17,7 @@ use std::sync::Arc; use db::notification_listener; +use jiff::Timestamp; use sqlx::PgPool; use taler_api::{ api::{Router, TalerApi, TalerRouter as _, revenue::Revenue, wire::WireGateway}, @@ -33,7 +34,7 @@ use taler_common::{ TransferState, TransferStatus, }, error_code::ErrorCode, - types::{amount::Currency, payto::payto, timestamp::Timestamp}, + types::{amount::Currency, payto::payto}, }; use taler_test_utils::db_test_setup_manual; use tokio::sync::watch::Sender; @@ -127,7 +128,7 @@ impl WireGateway for TestApi { .await?; match res { db::AddIncomingResult::Success { id, created_at } => Ok(AddIncomingResponse { - timestamp: created_at, + timestamp: created_at.into(), row_id: id, }), db::AddIncomingResult::ReservePubReuse => Err(failure( @@ -150,7 +151,7 @@ impl WireGateway for TestApi { .await?; match res { db::AddIncomingResult::Success { id, created_at } => Ok(AddKycauthResponse { - timestamp: created_at, + timestamp: created_at.into(), row_id: id, }), db::AddIncomingResult::ReservePubReuse => Err(failure( diff --git a/common/taler-build/build.rs b/common/taler-build/build.rs @@ -42,7 +42,7 @@ fn main() -> Result<(), String> { // Get the short commit hash let commit_hash = run_command("git", &["rev-parse", "--short", "HEAD"])?; - + // Set the environment variable VERSION println!("cargo:rustc-env=GIT_HASH={}", commit_hash); diff --git a/common/taler-common/src/api_revenue.rs b/common/taler-common/src/api_revenue.rs @@ -16,7 +16,7 @@ //! Type for the Taler Wire Gateway HTTP API <https://docs.taler.net/core/api-bank-wire.html#taler-wire-gateway-http-api> -use crate::types::{amount::Amount, payto::PaytoURI, timestamp::Timestamp}; +use crate::types::{amount::Amount, payto::PaytoURI, timestamp::TalerTimestamp}; use super::api_common::SafeU64; use serde::{Deserialize, Serialize}; @@ -41,7 +41,7 @@ pub struct RevenueIncomingHistory { #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct RevenueIncomingBankTransaction { pub row_id: SafeU64, - pub date: Timestamp, + pub date: TalerTimestamp, pub amount: Amount, pub credit_fee: Option<Amount>, pub debit_account: PaytoURI, diff --git a/common/taler-common/src/api_wire.rs b/common/taler-common/src/api_wire.rs @@ -18,7 +18,7 @@ use url::Url; -use crate::types::{amount::Amount, payto::PaytoURI, timestamp::Timestamp}; +use crate::types::{amount::Amount, payto::PaytoURI, timestamp::TalerTimestamp}; use super::api_common::{EddsaPublicKey, HashCode, SafeU64, ShortHashCode, WadId}; use serde::{Deserialize, Serialize}; @@ -36,7 +36,7 @@ pub struct WireConfig<'a> { /// <https://docs.taler.net/core/api-bank-wire.html#tsref-type-TransferResponse> #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TransferResponse { - pub timestamp: Timestamp, + pub timestamp: TalerTimestamp, pub row_id: SafeU64, } @@ -64,7 +64,7 @@ pub struct TransferListStatus { pub status: TransferState, pub amount: Amount, pub credit_account: PaytoURI, - pub timestamp: Timestamp, + pub timestamp: TalerTimestamp, } /// <https://docs.taler.net/core/api-bank-wire.html#tsref-type-TransfertSatus> @@ -76,7 +76,7 @@ pub struct TransferStatus { pub origin_exchange_url: String, pub wtid: ShortHashCode, pub credit_account: PaytoURI, - pub timestamp: Timestamp, + pub timestamp: TalerTimestamp, } /// <https://docs.taler.net/core/api-bank-wire.html#tsref-type-OutgoingHistory> @@ -90,7 +90,7 @@ pub struct OutgoingHistory { #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct OutgoingBankTransaction { pub row_id: SafeU64, - pub date: Timestamp, + pub date: TalerTimestamp, pub amount: Amount, pub credit_account: PaytoURI, pub wtid: ShortHashCode, @@ -111,7 +111,7 @@ pub enum IncomingBankTransaction { #[serde(rename = "RESERVE")] Reserve { row_id: SafeU64, - date: Timestamp, + date: TalerTimestamp, amount: Amount, debit_account: PaytoURI, reserve_pub: EddsaPublicKey, @@ -119,7 +119,7 @@ pub enum IncomingBankTransaction { #[serde(rename = "WAD")] Wad { row_id: SafeU64, - date: Timestamp, + date: TalerTimestamp, amount: Amount, debit_account: PaytoURI, origin_exchange_url: Url, @@ -128,7 +128,7 @@ pub enum IncomingBankTransaction { #[serde(rename = "KYCAUTH")] Kyc { row_id: SafeU64, - date: Timestamp, + date: TalerTimestamp, amount: Amount, debit_account: PaytoURI, account_pub: EddsaPublicKey, @@ -147,7 +147,7 @@ pub struct AddIncomingRequest { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AddIncomingResponse { pub row_id: SafeU64, - pub timestamp: Timestamp, + pub timestamp: TalerTimestamp, } /// <https://docs.taler.net/core/api-bank-wire.html#tsref-type-AddKycauthRequest> diff --git a/common/taler-common/src/types/timestamp.rs b/common/taler-common/src/types/timestamp.rs @@ -16,63 +16,23 @@ use std::{fmt::Display, ops::Add}; -use jiff::{civil::Time, tz::TimeZone}; +use jiff::{Timestamp, civil::Time, tz::TimeZone}; use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error, ser::SerializeStruct}; // codespell:ignore use serde_json::Value; /// <https://docs.taler.net/core/api-common.html#tsref-type-Timestamp> #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct Timestamp(pub jiff::Timestamp); +pub enum TalerTimestamp { + Never, + Timestamp(Timestamp), +} #[derive(Serialize, Deserialize)] struct TimestampImpl { t_s: Value, } -impl Timestamp { - /** Timestamp corresponding to "now" */ - pub fn now() -> Self { - Self(jiff::Timestamp::now()) - } - - /** Timestamp corresponding to now as it would be stored in db */ - pub fn now_stable() -> Self { - Self::from_sql_micros(Self::now().as_sql_micros()) - .expect("timestamp sql roundtrip must always succeed") - } - - /** Timestamp corresponding to "never" */ - pub const fn never() -> Self { - Self(jiff::Timestamp::MAX) - } - - /** Whether timestamp correspond to "never" */ - pub fn is_never(&self) -> bool { - self.0 == jiff::Timestamp::MAX - } - - /** I64 equivalent of this timestamp for db storage */ - pub fn as_sql_micros(&self) -> i64 { - if self.is_never() { - i64::MAX - } else { - self.0.as_microsecond() - } - } - - /** Timestamp equivalent of as i64 as stored in db */ - pub fn from_sql_micros(micros: i64) -> Result<Self, String> { - if micros == i64::MAX { - Ok(Self::never()) - } else { - let timestamp = jiff::Timestamp::from_microsecond(micros) - .map_err(|e| format!("expected timestamp micros got overflowing {micros}: {e}"))?; - Ok(Self(timestamp)) - } - } -} - -impl<'de> Deserialize<'de> for Timestamp { +impl<'de> Deserialize<'de> for TalerTimestamp { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, @@ -82,51 +42,50 @@ impl<'de> Deserialize<'de> for Timestamp { Value::Number(s) => { if let Some(since_epoch_s) = s.as_i64() { jiff::Timestamp::from_second(since_epoch_s) - .map(Self) + .map(Self::Timestamp) .map_err(Error::custom) } else { Err(Error::custom("Expected epoch time")) } } - Value::String(str) if str == "never" => Ok(Self::never()), + Value::String(str) if str == "never" => Ok(Self::Never), _ => Err(Error::custom("Expected epoch time or 'never'")), } } } -impl Serialize for Timestamp { +impl Serialize for TalerTimestamp { fn serialize<S>(&self, se: S) -> Result<S::Ok, S::Error> where S: Serializer, { let mut se_struct = se.serialize_struct("Timestamp", 1)?; - if self.is_never() { - se_struct.serialize_field("t_s", "never")? - } else { - se_struct.serialize_field("t_s", &self.0.as_second())? + match self { + TalerTimestamp::Never => se_struct.serialize_field("t_s", "never")?, + TalerTimestamp::Timestamp(timestamp) => { + se_struct.serialize_field("t_s", &timestamp.as_second())? + } } - se_struct.end() } } -impl Display for Timestamp { +impl Display for TalerTimestamp { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.is_never() { - f.write_str("never") - } else { - self.0.fmt(f) + match self { + TalerTimestamp::Never => f.write_str("never"), + TalerTimestamp::Timestamp(timestamp) => timestamp.fmt(f), } } } -impl From<jiff::Timestamp> for Timestamp { +impl From<jiff::Timestamp> for TalerTimestamp { fn from(time: jiff::Timestamp) -> Self { - Self(time) + Self::Timestamp(time) } } -impl From<jiff::civil::Date> for Timestamp { +impl From<jiff::civil::Date> for TalerTimestamp { fn from(date: jiff::civil::Date) -> Self { date.to_datetime(Time::midnight()) .to_zoned(TimeZone::UTC) @@ -136,22 +95,13 @@ impl From<jiff::civil::Date> for Timestamp { } } -impl Add<jiff::Span> for Timestamp { +impl Add<jiff::Span> for TalerTimestamp { type Output = Self; fn add(self, rhs: jiff::Span) -> Self::Output { - Self(self.0 + rhs) - } -} - -impl PartialEq<jiff::Timestamp> for Timestamp { - fn eq(&self, other: &jiff::Timestamp) -> bool { - self.0.eq(other) - } -} - -impl PartialOrd<jiff::Timestamp> for Timestamp { - fn partial_cmp(&self, other: &jiff::Timestamp) -> Option<std::cmp::Ordering> { - self.0.partial_cmp(other) + match self { + TalerTimestamp::Never => TalerTimestamp::Never, + TalerTimestamp::Timestamp(timestamp) => TalerTimestamp::Timestamp(timestamp + rhs), + } } } diff --git a/common/taler-common/src/types/utils.rs b/common/taler-common/src/types/utils.rs @@ -16,9 +16,7 @@ use std::{fmt::Debug, ops::Deref}; -use jiff::{civil::Date, tz::TimeZone}; - -use crate::types::timestamp::Timestamp; +use jiff::{Timestamp, civil::Date, tz::TimeZone}; #[derive(Clone, PartialEq, Eq)] pub struct InlineStr<const LEN: usize> { @@ -95,6 +93,10 @@ impl<const LEN: usize> Deref for InlineStr<LEN> { /** Convert a date to a UTC timestamp */ pub fn date_to_utc_timestamp(date: &Date) -> Timestamp { - let zoned = date.to_zoned(TimeZone::UTC).unwrap(); - Timestamp(zoned.timestamp()) + date.to_zoned(TimeZone::UTC).unwrap().timestamp() +} + +/** Get current timestamp truncated to micros precision */ +pub fn now_sql_stable_timestamp() -> Timestamp { + Timestamp::from_microsecond(Timestamp::now().as_microsecond()).unwrap() } diff --git a/taler-magnet-bank/src/api.rs b/taler-magnet-bank/src/api.rs @@ -14,6 +14,7 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ +use jiff::Timestamp; use taler_api::{ api::{TalerApi, revenue::Revenue, wire::WireGateway}, error::{ApiResult, failure}, @@ -29,7 +30,7 @@ use taler_common::{ TransferState, TransferStatus, }, error_code::ErrorCode, - types::{payto::PaytoURI, timestamp::Timestamp, utils::date_to_utc_timestamp}, + types::{payto::PaytoURI, utils::date_to_utc_timestamp}, }; use tokio::sync::watch::Sender; @@ -89,7 +90,7 @@ impl WireGateway for MagnetApi { let result = db::make_transfer(&self.pool, &req, &creditor, &Timestamp::now()).await?; match result { db::TransferResult::Success { id, initiated_at } => Ok(TransferResponse { - timestamp: initiated_at, + timestamp: initiated_at.into(), row_id: SafeU64::try_from(id).unwrap(), }), db::TransferResult::RequestUidReuse => Err(failure( @@ -159,7 +160,7 @@ impl WireGateway for MagnetApi { row_id, valued_at, .. } => Ok(AddIncomingResponse { row_id: safe_u64(row_id), - timestamp: date_to_utc_timestamp(&valued_at), + timestamp: date_to_utc_timestamp(&valued_at).into(), }), AddIncomingResult::ReservePubReuse => Err(failure( ErrorCode::BANK_DUPLICATE_RESERVE_PUB_SUBJECT, @@ -186,7 +187,7 @@ impl WireGateway for MagnetApi { row_id, valued_at, .. } => Ok(AddKycauthResponse { row_id: safe_u64(row_id), - timestamp: date_to_utc_timestamp(&valued_at), + timestamp: date_to_utc_timestamp(&valued_at).into(), }), AddIncomingResult::ReservePubReuse => Err(failure( ErrorCode::BANK_DUPLICATE_RESERVE_PUB_SUBJECT, diff --git a/taler-magnet-bank/src/bin/magnet-bank-harness.rs b/taler-magnet-bank/src/bin/magnet-bank-harness.rs @@ -30,7 +30,7 @@ use taler_common::{ config::Config, db::{dbinit, pool}, taler_main, - types::{self, amount::amount, url}, + types::{amount::amount, url}, }; use taler_magnet_bank::{ FullHuPayto, HuIban, @@ -147,7 +147,7 @@ impl<'a> Harness<'a> { credit_account: creditor.as_payto(), }, creditor, - &types::timestamp::Timestamp::now(), + &Timestamp::now(), ) .await .unwrap(); diff --git a/taler-magnet-bank/src/db.rs b/taler-magnet-bank/src/db.rs @@ -16,7 +16,7 @@ use std::fmt::Display; -use jiff::{civil::Date, tz::TimeZone}; +use jiff::{Timestamp, civil::Date, tz::TimeZone}; use serde::{Serialize, de::DeserializeOwned}; use sqlx::{PgConnection, PgExecutor, PgPool, QueryBuilder, Row, postgres::PgRow}; use taler_api::{ @@ -30,7 +30,7 @@ use taler_common::{ IncomingBankTransaction, OutgoingBankTransaction, TransferListStatus, TransferRequest, TransferState, TransferStatus, }, - types::{amount::Amount, payto::PaytoImpl as _, timestamp::Timestamp}, + types::{amount::Amount, payto::PaytoImpl as _}, }; use tokio::sync::watch::{Receiver, Sender}; @@ -175,7 +175,7 @@ pub async fn register_tx_in_admin( .bind(&tx.subject) .bind(tx.debtor.iban()) .bind(&tx.debtor.name) - .bind_date(&now.0.to_zoned(TimeZone::UTC).date()) + .bind_date(&now.to_zoned(TimeZone::UTC).date()) .bind(tx.metadata.ty()) .bind(tx.metadata.key()) .try_map(|r: PgRow| { @@ -451,7 +451,7 @@ pub async fn transfer_page<'a>( status: r.try_get(1)?, amount: r.try_get_amount_i(2, &CURRENCY)?, credit_account: r.try_get_iban(4)?.as_full_payto(r.try_get(5)?), - timestamp: r.try_get_timestamp(6)?, + timestamp: r.try_get_timestamp(6)?.into(), }) }, ) @@ -491,7 +491,7 @@ pub async fn outgoing_history( row_id: r.try_get_safeu64(0)?, amount: r.try_get_amount_i(1, &CURRENCY)?, credit_account: r.try_get_iban(3)?.as_full_payto(r.try_get(4)?), - date: r.try_get_timestamp(5)?, + date: r.try_get_timestamp(5)?.into(), exchange_base_url: r.try_get_url(6)?, wtid: r.try_get_base32(7)?, }) @@ -534,14 +534,14 @@ pub async fn incoming_history( row_id: r.try_get_safeu64(1)?, amount: r.try_get_amount_i(2, &CURRENCY)?, debit_account: r.try_get_iban(4)?.as_full_payto(r.try_get(5)?), - date: r.try_get_timestamp(6)?, + date: r.try_get_timestamp(6)?.into(), reserve_pub: r.try_get_base32(7)?, }, IncomingType::kyc => IncomingBankTransaction::Kyc { row_id: r.try_get_safeu64(1)?, amount: r.try_get_amount_i(2, &CURRENCY)?, debit_account: r.try_get_iban(4)?.as_full_payto(r.try_get(5)?), - date: r.try_get_timestamp(6)?, + date: r.try_get_timestamp(6)?.into(), account_pub: r.try_get_base32(7)?, }, IncomingType::wad => { @@ -582,7 +582,7 @@ pub async fn revenue_history( |r: PgRow| { Ok(RevenueIncomingBankTransaction { row_id: r.try_get_safeu64(0)?, - date: r.try_get_timestamp(1)?, + date: r.try_get_timestamp(1)?.into(), amount: r.try_get_amount_i(2, &CURRENCY)?, credit_fee: None, debit_account: r.try_get_iban(4)?.as_full_payto(r.try_get(5)?), @@ -623,7 +623,7 @@ pub async fn transfer_by_id<'a>( origin_exchange_url: r.try_get(4)?, wtid: r.try_get_base32(5)?, credit_account: r.try_get_iban(6)?.as_full_payto(r.try_get(7)?), - timestamp: r.try_get_timestamp(8)?, + timestamp: r.try_get_timestamp(8)?.into(), }) }) .fetch_optional(db) @@ -765,7 +765,7 @@ pub async fn kv_set<'a, T: Serialize>( #[cfg(test)] mod test { - use jiff::{Span, Zoned}; + use jiff::{Span, Timestamp, Zoned}; use serde_json::json; use sqlx::{PgConnection, PgPool, postgres::PgRow}; use taler_api::{ @@ -776,7 +776,7 @@ mod test { api_common::{EddsaPublicKey, HashCode, ShortHashCode}, api_params::{History, Page}, api_wire::TransferRequest, - types::{amount::amount, payto::payto, timestamp::Timestamp, url}, + types::{amount::amount, payto::payto, url, utils::now_sql_stable_timestamp}, }; use tokio::sync::watch::Receiver; @@ -839,7 +839,7 @@ mod test { .fetch_one(&mut *db) .await .unwrap(); - let now = Timestamp::now_stable(); + let now = now_sql_stable_timestamp(); let date = Zoned::now().date(); let later = date.tomorrow().unwrap(); let tx = TxIn { @@ -966,7 +966,7 @@ mod test { Vec::new() ); - let now = Timestamp::now_stable(); + let now = now_sql_stable_timestamp(); let later = now + Span::new().hours(2); let date = Zoned::now().date(); let tx = TxInAdmin { @@ -1038,7 +1038,7 @@ mod test { .fetch_one(&mut *db) .await .unwrap(); - let now = Timestamp::now_stable(); + let now = now_sql_stable_timestamp(); let date = Zoned::now().date(); let later = date.tomorrow().unwrap(); let tx = TxOut { @@ -1165,7 +1165,7 @@ mod test { async fn tx_out_failure() { let (mut db, _) = setup().await; - let now = Timestamp::now_stable(); + let now = now_sql_stable_timestamp(); // Unknown assert_eq!( @@ -1286,7 +1286,7 @@ mod test { credit_account: payto("payto://iban/HU02162000031000164800000000?receiver-name=name"), }; let payto = magnet_payto("payto://iban/HU30162000031000163100000000?receiver-name=name"); - let now = Timestamp::now_stable(); + let now = now_sql_stable_timestamp(); let later = now + Span::new().hours(2); // Insert assert_eq!( @@ -1295,7 +1295,7 @@ mod test { .expect("transfer"), TransferResult::Success { id: 1, - initiated_at: now + initiated_at: now.into() } ); // Idempotent @@ -1305,7 +1305,7 @@ mod test { .expect("transfer"), TransferResult::Success { id: 1, - initiated_at: now + initiated_at: now.into() } ); // Request UID reuse @@ -1354,7 +1354,7 @@ mod test { .expect("transfer"), TransferResult::Success { id: 2, - initiated_at: later + initiated_at: later.into() } ); @@ -1377,7 +1377,7 @@ mod test { let amount = amount("HUF:10"); let payto = magnet_payto("payto://iban/HU30162000031000163100000000?receiver-name=name"); - let now = Timestamp::now_stable(); + let now = now_sql_stable_timestamp(); let date = Zoned::now().date(); // Empty db @@ -1569,7 +1569,7 @@ mod test { ), }, &magnet_payto, - &&Timestamp::now(), + &Timestamp::now(), ) .await .expect("transfer"); diff --git a/taler-magnet-bank/src/worker.rs b/taler-magnet-bank/src/worker.rs @@ -16,14 +16,13 @@ use std::num::ParseIntError; -use jiff::{Zoned, civil::Date}; +use jiff::{Timestamp, Zoned, civil::Date}; use p256::ecdsa::SigningKey; use sqlx::PgConnection; use taler_api::subject::{self, parse_incoming_unstructured}; use taler_common::types::{ amount::{self}, iban::IBAN, - timestamp::Timestamp, }; use tracing::{debug, error, info, trace, warn}; diff --git a/taler-magnet-bank/tests/api.rs b/taler-magnet-bank/tests/api.rs @@ -16,14 +16,14 @@ use std::sync::Arc; -use jiff::Zoned; +use jiff::{Timestamp, Zoned}; use sqlx::PgPool; use taler_api::{api::TalerRouter as _, auth::AuthMethod, subject::OutgoingSubject}; use taler_common::{ api_common::ShortHashCode, api_revenue::RevenueConfig, api_wire::{OutgoingHistory, TransferState, WireConfig}, - types::{amount::amount, payto::payto, timestamp::Timestamp, url}, + types::{amount::amount, payto::payto, url}, }; use taler_magnet_bank::{ api::MagnetApi, @@ -93,7 +93,6 @@ async fn outgoing_history() { }, |_, i| { let acquire = pool.acquire(); - Timestamp::now().to_string(); async move { let mut conn = acquire.await.unwrap(); let now = Zoned::now().date();