commit 502ed283fd45af1f430e94a90f9a57e5d7621ade
parent e9c7a7907d5588da15b0faebfaeddb667872e639
Author: Antoine A <>
Date: Wed, 11 Dec 2024 19:47:05 +0100
update utils
Diffstat:
12 files changed, 95 insertions(+), 75 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -166,7 +166,7 @@ dependencies = [
"serde_json",
"serde_path_to_error",
"serde_urlencoded",
- "sync_wrapper 1.0.2",
+ "sync_wrapper",
"tokio",
"tower",
"tower-layer",
@@ -189,7 +189,7 @@ dependencies = [
"mime",
"pin-project-lite",
"rustversion",
- "sync_wrapper 1.0.2",
+ "sync_wrapper",
"tower-layer",
"tower-service",
"tracing",
@@ -945,13 +945,13 @@ dependencies = [
[[package]]
name = "flexi_logger"
-version = "0.29.6"
+version = "0.29.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d26948e37cfcb1f2c2cd38e0602d3a8ab6b9472c0c6eff4516fc8def9a3124d7"
+checksum = "4613c3fa90ebf91dff72ff383a9324329c017819711bda86142be81368ac6fad"
dependencies = [
"chrono",
"log",
- "thiserror 1.0.69",
+ "thiserror 2.0.6",
]
[[package]]
@@ -2149,9 +2149,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.5.7"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
+checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
dependencies = [
"bitflags",
]
@@ -2279,9 +2279,9 @@ dependencies = [
[[package]]
name = "rustls"
-version = "0.23.19"
+version = "0.23.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1"
+checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b"
dependencies = [
"log",
"once_cell",
@@ -2367,18 +2367,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.215"
+version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
+checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.215"
+version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
+checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
dependencies = [
"proc-macro2",
"quote",
@@ -2845,12 +2845,6 @@ dependencies = [
[[package]]
name = "sync_wrapper"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
-
-[[package]]
-name = "sync_wrapper"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
@@ -2869,7 +2863,7 @@ dependencies = [
[[package]]
name = "taler-api"
version = "0.1.0"
-source = "git+https://git.taler.net/taler-rust.git/#90d4608cf2f4a73cf13cb252e8892a27fa090e62"
+source = "git+https://git.taler.net/taler-rust.git/#fcc09117ad3a761486922279845b3abec0efd024"
dependencies = [
"axum",
"dashmap",
@@ -2890,13 +2884,14 @@ dependencies = [
[[package]]
name = "taler-common"
version = "0.1.0"
-source = "git+https://git.taler.net/taler-rust.git/#90d4608cf2f4a73cf13cb252e8892a27fa090e62"
+source = "git+https://git.taler.net/taler-rust.git/#fcc09117ad3a761486922279845b3abec0efd024"
dependencies = [
"base32",
"fastrand",
"rand",
"serde",
"serde_json",
+ "serde_urlencoded",
"serde_with",
"sqlx",
"thiserror 2.0.6",
@@ -3136,14 +3131,14 @@ dependencies = [
[[package]]
name = "tower"
-version = "0.5.1"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
+checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
- "sync_wrapper 0.1.2",
+ "sync_wrapper",
"tokio",
"tower-layer",
"tower-service",
diff --git a/btc-wire/src/loops/worker.rs b/btc-wire/src/loops/worker.rs
@@ -335,7 +335,7 @@ fn sync_chain_incoming_confirmed(
let credit_addr = full.details[0].address.clone().unwrap().assume_checked();
let amount = btc_to_taler(&full.amount, state.currency);
let nb = db.execute("INSERT INTO tx_in (received, amount, reserve_pub, debit_acc, credit_acc) VALUES ($1, ($2, $3)::taler_amount, $4, $5, $6) ON CONFLICT (reserve_pub) DO NOTHING ", &[
- &((full.time * 1000000) as i64), &(amount.decimal.val as i64), &(amount.decimal.frac as i32), &reserve_pub.as_slice(), &btc_payto_url(&debit_addr).as_ref(), &btc_payto_url(&credit_addr).as_ref()
+ &((full.time * 1000000) as i64), &(amount.decimal.val as i64), &(amount.decimal.frac as i32), &reserve_pub.as_slice(), &btc_payto_url(&debit_addr).raw(), &btc_payto_url(&credit_addr).raw()
])?;
if nb > 0 {
info!(
@@ -439,7 +439,7 @@ fn sync_chain_debit(
let debit_addr = sender_address(rpc, full)?;
let nb = db.execute(
"INSERT INTO tx_out (created, amount, wtid, debit_acc, credit_acc, exchange_url, status, txid, request_uid) VALUES ($1, ($2, $3)::taler_amount, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (wtid) DO NOTHING",
- &[&((full.time*1000000) as i64), &(amount.decimal.val as i64), &(amount.decimal.frac as i32), &wtid.as_slice(), &btc_payto_url(&debit_addr).as_ref(), &btc_payto_url(&credit_addr).as_ref(), &state.base_url.as_ref(), &(DebitStatus::Sent as i16), &id.as_byte_array().as_slice(), &None::<&[u8]>],
+ &[&((full.time*1000000) as i64), &(amount.decimal.val as i64), &(amount.decimal.frac as i32), &wtid.as_slice(), &btc_payto_url(&debit_addr).raw(), &btc_payto_url(&credit_addr).raw(), &state.base_url.as_ref(), &(DebitStatus::Sent as i16), &id.as_byte_array().as_slice(), &None::<&[u8]>],
)?;
if nb > 0 {
warn!(
diff --git a/btc-wire/src/taler_utils.rs b/btc-wire/src/taler_utils.rs
@@ -16,14 +16,14 @@
//! Utils function to convert taler API types to bitcoin API types
use bitcoin::{Address, Amount as BtcAmount, SignedAmount};
-use common::taler_common::amount::Amount;
+use common::taler_common::{amount::Amount, payto::Payto};
use common::url::Url;
use common::{currency::CurrencyBtc, taler_common::amount::FRAC_BASE};
use std::str::FromStr;
/// Generate a payto uri from a btc address
-pub fn btc_payto_url(addr: &Address) -> Url {
- Url::from_str(&format!("payto://bitcoin/{}", addr)).unwrap()
+pub fn btc_payto_url(addr: &Address) -> Payto {
+ Payto::from_str(&format!("payto://bitcoin/{}", addr)).unwrap()
}
/// Extract a btc address from a payto uri
diff --git a/common/src/config.rs b/common/src/config.rs
@@ -20,6 +20,7 @@ use std::{
process::Command,
str::FromStr,
};
+use taler_common::payto::Payto;
use url::Url;
use crate::{
@@ -98,8 +99,8 @@ impl TalerConfig {
/* ----- Wire Gateway ----- */
- pub fn payto(&self) -> Url {
- required(self.section(), "PAYTO", url)
+ pub fn payto(&self) -> Payto {
+ required(self.section(), "PAYTO", payto)
}
pub fn port(&self) -> u16 {
@@ -200,6 +201,13 @@ pub fn url(properties: &Properties, name: &str) -> Option<Url> {
})
}
+pub fn payto(properties: &Properties, name: &str) -> Option<Payto> {
+ properties.get(name).map(|s| {
+ s.parse()
+ .or_fail(|e| format!("config {}={} is not a valid payto: {}", name, s, e))
+ })
+}
+
pub fn postgres(properties: &Properties, name: &str) -> Option<postgres::Config> {
properties.get(name).map(|s| {
postgres::Config::from_str(s)
diff --git a/common/src/sql.rs b/common/src/sql.rs
@@ -17,7 +17,7 @@
use std::str::FromStr;
use postgres::Row;
-use taler_common::{amount::Amount, api_common::SafeU64};
+use taler_common::{amount::Amount, api_common::SafeU64, payto::Payto};
use url::Url;
use crate::log::OrFail;
@@ -28,6 +28,12 @@ pub fn sql_url(row: &Row, idx: usize) -> Url {
Url::from_str(str).or_fail(|_| format!("Database invariant: expected an url got {}", str))
}
+/// Payto from sql
+pub fn sql_payto(row: &Row, idx: usize) -> Payto {
+ let str: &str = row.get(idx);
+ Payto::from_str(str).or_fail(|_| format!("Database invariant: expected a payto got {}", str))
+}
+
/// Ethereum amount from sql
pub fn sql_amount(row: &Row, idx: usize, currency: &str) -> Amount {
let val: i64 = row.get(idx);
diff --git a/eth-wire/src/lib.rs b/eth-wire/src/lib.rs
@@ -26,7 +26,7 @@ use common::{
log::{fail, OrFail},
metadata::{InMetadata, OutMetadata},
postgres,
- taler_common::amount::Amount,
+ taler_common::{amount::Amount, payto::Payto},
url::Url,
};
use ethereum_types::{Address, H160, H256, U256, U64};
@@ -232,7 +232,7 @@ pub struct WireState {
pub lifetime: Option<u32>,
pub bump_delay: Option<u32>,
pub base_url: Url,
- pub payto: Url,
+ pub payto: Payto,
pub db_config: postgres::Config,
pub currency: CurrencyEth,
}
diff --git a/eth-wire/src/loops/worker.rs b/eth-wire/src/loops/worker.rs
@@ -279,7 +279,7 @@ fn sync_chain_incoming_confirmed(
let amount = eth_to_taler(&tx.value, state.currency);
let credit_addr = tx.from.expect("Not coinbase");
let nb = db.execute("INSERT INTO tx_in (received, amount, reserve_pub, debit_acc, credit_acc) VALUES ($1, ($2, $3)::taler_amount, $4, $5, $6) ON CONFLICT (reserve_pub) DO NOTHING ", &[
- &Timestamp::now().as_sql_micros(), &(amount.decimal.val as i64), &(amount.decimal.frac as i32), &reserve_pub.as_ref(), ð_payto_url(&credit_addr).as_ref(), &state.payto.as_ref()
+ &Timestamp::now().as_sql_micros(), &(amount.decimal.val as i64), &(amount.decimal.frac as i32), &reserve_pub.as_ref(), ð_payto_url(&credit_addr).raw(), &state.payto.raw()
])?;
if nb > 0 {
info!(
@@ -353,7 +353,7 @@ fn sync_chain_outgoing(tx: &SyncTransaction, db: &mut Client, state: &WireState)
// Else add to database
let nb = db.execute(
"INSERT INTO tx_out (created, amount, wtid, debit_acc, credit_acc, exchange_url, status, txid, request_uid) VALUES ($1, ($2, $3)::taler_amount, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (wtid) DO NOTHING",
- &[&Timestamp::now().as_sql_micros(), &(amount.decimal.val as i64), &(amount.decimal.frac as i32), &wtid.as_ref(), ð_payto_url(&state.address).as_ref(), ð_payto_url(&credit_addr).as_ref(), &state.base_url.as_ref(), &(DebitStatus::Sent as i16), &tx.hash.as_ref(), &None::<&[u8]>],
+ &[&Timestamp::now().as_sql_micros(), &(amount.decimal.val as i64), &(amount.decimal.frac as i32), &wtid.as_ref(), ð_payto_url(&state.address).raw(), ð_payto_url(&credit_addr).raw(), &state.base_url.as_ref(), &(DebitStatus::Sent as i16), &tx.hash.as_ref(), &None::<&[u8]>],
)?;
if nb > 0 {
warn!(
diff --git a/eth-wire/src/sql.rs b/eth-wire/src/sql.rs
@@ -17,7 +17,7 @@ use common::{
currency::CurrencyEth,
log::OrFail,
postgres::Row,
- sql::{sql_amount, sql_array, sql_url},
+ sql::{sql_amount, sql_array, sql_payto},
};
use eth_wire::taler_util::{eth_payto_addr, taler_to_eth};
use ethereum_types::{H160, H256, U256};
@@ -35,7 +35,7 @@ pub fn sql_eth_amount(row: &Row, idx: usize, currency: CurrencyEth) -> U256 {
/// Ethereum address from sql
pub fn sql_addr(row: &Row, idx: usize) -> H160 {
- let url = sql_url(row, idx);
+ let url = sql_payto(row, idx);
eth_payto_addr(&url).or_fail(|_| {
format!(
"Database invariant: expected an ethereum payto url got {}",
diff --git a/eth-wire/src/taler_util.rs b/eth-wire/src/taler_util.rs
@@ -17,8 +17,10 @@ use std::str::FromStr;
use common::{
currency::CurrencyEth,
- taler_common::amount::{Amount, FRAC_BASE},
- url::Url,
+ taler_common::{
+ amount::{Amount, FRAC_BASE},
+ payto::Payto,
+ },
};
use ethereum_types::{Address, U256};
@@ -26,8 +28,8 @@ pub const WEI: u64 = 1_000_000_000_000_000_000;
pub const TRUNC: u64 = WEI / FRAC_BASE as u64;
/// Generate a payto uri from an eth address
-pub fn eth_payto_url(addr: &Address) -> Url {
- Url::from_str(&format!(
+pub fn eth_payto_url(addr: &Address) -> Payto {
+ Payto::from_str(&format!(
"payto://ethereum/{}",
hex::encode(addr.as_bytes())
))
@@ -35,7 +37,8 @@ pub fn eth_payto_url(addr: &Address) -> Url {
}
/// Extract an eth address from a payto uri
-pub fn eth_payto_addr(url: &Url) -> Result<Address, String> {
+pub fn eth_payto_addr(payto: &Payto) -> Result<Address, String> {
+ let url = payto.as_ref();
if url.domain() != Some("ethereum") {
return Err(format!(
"Expected domain 'ethereum' got '{}'",
diff --git a/instrumentation/src/gateway.rs b/instrumentation/src/gateway.rs
@@ -18,8 +18,13 @@ use std::str::FromStr;
use btc_wire::taler_utils::btc_payto_url;
use common::{
- rand_slice, taler_common::amount::Amount as TalerAmount, taler_common::api_common::Base32,
- taler_common::api_wire::TransferRequest, url::Url,
+ rand_slice,
+ taler_common::{
+ amount::Amount as TalerAmount,
+ api_common::Base32,
+ api_wire::TransferRequest,
+ payto::{payto, Payto},
+ },
};
use libdeflater::{CompressionLvl, Compressor};
use ureq::Response;
@@ -29,10 +34,10 @@ use crate::{
utils::{cmd_out, cmd_redirect_ok, gateway_error, TestCtx},
};
-fn client_transfer(gateway_url: &str, payto_url: &str, amount: &str) -> String {
+fn client_transfer(gateway_url: &str, payto_url: &Payto, amount: &str) -> String {
cmd_out(
"taler-exchange-wire-gateway-client",
- &["-b", gateway_url, "-C", payto_url, "-a", amount],
+ &["-b", gateway_url, "-C", payto_url.raw(), "-a", amount],
)
}
@@ -63,7 +68,7 @@ pub fn api(ctx: TestCtx) {
"-b",
&ctx.gateway_url,
"-D",
- btc_payto_url(&ctx.client_addr).as_ref(),
+ btc_payto_url(&ctx.client_addr).raw(),
"-a",
&amount,
],
@@ -84,11 +89,7 @@ pub fn api(ctx: TestCtx) {
let mut amounts = Vec::new();
for n in 1..10 {
let amount = format!("{}:0.0000{}", ctx.taler_conf.currency.to_str(), n);
- client_transfer(
- &ctx.gateway_url,
- btc_payto_url(&ctx.client_addr).as_ref(),
- &amount,
- );
+ client_transfer(&ctx.gateway_url, &btc_payto_url(&ctx.client_addr), &amount);
amounts.push(amount);
}
@@ -111,7 +112,7 @@ pub fn api(ctx: TestCtx) {
}
let amount = &format!("{}:0.00042", ctx.taler_conf.currency.to_str());
- let payto = btc_payto_url(&ctx.client_addr).to_string();
+ let btc_payto = btc_payto_url(&ctx.client_addr);
ctx.step("Request format");
{
@@ -124,12 +125,12 @@ pub fn api(ctx: TestCtx) {
"payto://bitcoin/42$CLIENT",
] {
let url = url.replace("$CLIENT", &ctx.client_addr.to_string());
- let result = client_transfer(&ctx.gateway_url, &url, amount);
+ let result = client_transfer(&ctx.gateway_url, &payto(url), amount);
assert!(result.contains("(400/24)"));
}
// Bad transaction amount
- let result = client_transfer(&ctx.gateway_url, &payto, "ATC:0.00042");
+ let result = client_transfer(&ctx.gateway_url, &btc_payto, "ATC:0.00042");
assert!(result.contains("(400/30)"));
// Bad history delta
@@ -152,7 +153,7 @@ pub fn api(ctx: TestCtx) {
amount: TalerAmount::from_str(amount).unwrap(),
exchange_base_url: ctx.taler_conf.base_url(),
wtid: Base32::from(rand_slice()),
- credit_account: Url::from_str(&payto).unwrap(),
+ credit_account: btc_payto,
};
// Same
assert_eq!(
@@ -230,7 +231,7 @@ pub fn auth(ctx: TestCtx) {
"-s",
"exchange-accountcredentials-admin",
"-C",
- btc_payto_url(&ctx.client_addr).as_ref(),
+ btc_payto_url(&ctx.client_addr).raw(),
"-a",
&format!("{}:0.00042", ctx.taler_conf.currency.to_str()),
],
diff --git a/instrumentation/src/utils.rs b/instrumentation/src/utils.rs
@@ -34,6 +34,7 @@ use common::{
amount::Amount,
api_common::Base32,
api_wire::{IncomingBankTransaction, IncomingHistory, OutgoingHistory, TransferRequest},
+ payto::Payto,
},
url::Url,
};
@@ -108,7 +109,13 @@ pub fn check_gateway_up(base_url: &str) -> bool {
ureq::get(&format!("{}config", base_url)).call().is_ok()
}
-pub fn transfer(base_url: &str, wtid: &[u8; 32], url: &Url, credit_account: Url, amount: &Amount) {
+pub fn transfer(
+ base_url: &str,
+ wtid: &[u8; 32],
+ url: &Url,
+ credit_account: Payto,
+ amount: &Amount,
+) {
ureq::post(&format!("{}transfer", base_url))
.send_json(TransferRequest {
request_uid: Base32::from(rand_slice()),
diff --git a/wire-gateway/src/main.rs b/wire-gateway/src/main.rs
@@ -27,7 +27,6 @@ use common::{
fail,
log::{error, info},
},
- url::Url,
};
use listenfd::ListenFd;
use sqlx::Row;
@@ -56,12 +55,13 @@ use taler_common::{
TransferList, TransferRequest, TransferResponse, TransferState, TransferStatus,
},
error_code::ErrorCode,
+ payto::Payto,
};
use tokio::time::sleep;
struct ServerState {
pool: PgPool,
- payto: Url,
+ payto: Payto,
currency: Currency,
status: AtomicBool,
}
@@ -90,7 +90,7 @@ impl WireGatewayImpl for ServerState {
amount: r.try_get_amount_i(0, self.currency())?,
exchange_base_url: r.try_get_url(2)?,
wtid: r.try_get_base32(3)?,
- credit_account: r.try_get_url(4)?,
+ credit_account: r.try_get_payto(4)?,
};
if prev == req {
// Idempotence
@@ -114,8 +114,8 @@ impl WireGatewayImpl for ServerState {
.bind_timestamp(&Timestamp::now())
.bind_amount(&req.amount)
.bind(req.wtid.as_slice())
- .bind(self.payto.as_str())
- .bind(req.credit_account.as_str())
+ .bind((&self.payto).raw())
+ .bind(req.credit_account.raw())
.bind(req.exchange_base_url.as_str())
.bind(req.request_uid.as_slice())
.fetch_one(&mut *tx).await?;
@@ -149,7 +149,7 @@ impl WireGatewayImpl for ServerState {
date: r.try_get_timestamp(1)?,
amount: r.try_get_amount_i(2, self.currency())?,
wtid: r.try_get_base32(4)?,
- credit_account: r.try_get_url(5)?,
+ credit_account: r.try_get_payto(5)?,
exchange_base_url: r.try_get_url(6)?,
})
}).await?;
@@ -175,7 +175,7 @@ impl WireGatewayImpl for ServerState {
date: r.try_get_timestamp(1)?,
amount: r.try_get_amount_i(2, self.currency())?,
reserve_pub: r.try_get_base32(4)?,
- debit_account: r.try_get_url(5)?,
+ debit_account: r.try_get_payto(5)?,
})
},
)
@@ -195,7 +195,7 @@ impl WireGatewayImpl for ServerState {
.bind_timestamp(&Timestamp::now())
.bind_amount(&req.amount)
.bind(req.reserve_pub.as_slice())
- .bind(req.debit_account.as_str())
+ .bind(req.debit_account.raw())
.bind("payto://bitcoin/bcrt1qgkgxkjj27g3f7s87mcvjjsghay7gh34cx39prj")
.fetch_one(&self.pool).await?;
Ok(AddIncomingResponse {
@@ -296,18 +296,18 @@ async fn main() {
info!("wire-gateway stopped");
}
-/// Check if an url if a valid payto url for the configured currency
-fn check_payto(url: &Url, currency: Currency) -> bool {
+/// Check if a payto is valid the configured currency
+fn check_payto(payto: &Payto, currency: Currency) -> bool {
match currency {
- Currency::ETH(_) => check_pay_to_eth(url),
- Currency::BTC(_) => check_pay_to_btc(url),
+ Currency::ETH(_) => check_pay_to_eth(payto),
+ Currency::BTC(_) => check_pay_to_btc(payto),
}
}
/// Check if an url is a valid bitcoin payto url
-fn check_pay_to_btc(url: &Url) -> bool {
+fn check_pay_to_btc(payto: &Payto) -> bool {
+ let url = payto.as_ref();
url.domain() == Some("bitcoin")
- && url.scheme() == "payto"
&& url.username() == ""
&& url.password().is_none()
&& url.query().is_none()
@@ -316,9 +316,9 @@ fn check_pay_to_btc(url: &Url) -> bool {
}
/// Check if an url is a valid ethereum payto url
-fn check_pay_to_eth(url: &Url) -> bool {
+fn check_pay_to_eth(payto: &Payto) -> bool {
+ let url = payto.as_ref();
url.domain() == Some("ethereum")
- && url.scheme() == "payto"
&& url.username() == ""
&& url.password().is_none()
&& url.query().is_none()