diff --git a/Cargo.lock b/Cargo.lock index 2f536e1b27..2ad70c5ff9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1295,6 +1295,27 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +[[package]] +name = "dynosaur" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47baef31f408cc1a54eadcb0160ffe2b935b5963bd2b519719f3a101749af524" +dependencies = [ + "dynosaur_derive", + "trait-variant", +] + +[[package]] +name = "dynosaur_derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320c6861ca45ea23faee2bd86a6c7f20ec4b7a64a2773971cd4f52ae61615463" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.63", +] + [[package]] name = "ecdsa" version = "0.16.9" @@ -5373,6 +5394,17 @@ dependencies = [ "syn 2.0.63", ] +[[package]] +name = "trait-variant" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.63", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -5993,6 +6025,7 @@ dependencies = [ "byteorder", "crossbeam-channel", "document-features", + "dynosaur", "futures-util", "group", "gumdrop", @@ -6029,6 +6062,7 @@ dependencies = [ "tor-rtcompat", "tower", "tracing", + "trait-variant", "webpki-roots 0.25.4", "which", "zcash_address", diff --git a/Cargo.toml b/Cargo.toml index b1ce8ecca6..78468956fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -146,9 +146,11 @@ incrementalmerkletree-testing = "0.2" # - `arti-client` depends on `rusqlite`, and a version mismatch there causes a compilation # failure due to incompatible `libsqlite3-sys` versions. arti-client = { version = "0.23", default-features = false, features = ["compression", "rustls", "tokio"] } +dynosaur = "0.1.1" tokio = "1" tor-rtcompat = "0.23" tower = "0.4" +trait-variant = "0.1" # ZIP 32 aes = "0.8" diff --git a/supply-chain/config.toml b/supply-chain/config.toml index 37b0ff94b9..da79faef09 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -414,6 +414,14 @@ criteria = "safe-to-deploy" version = "1.0.17" criteria = "safe-to-deploy" +[[exemptions.dynosaur]] +version = "0.1.1" +criteria = "safe-to-deploy" + +[[exemptions.dynosaur_derive]] +version = "0.1.1" +criteria = "safe-to-deploy" + [[exemptions.ecdsa]] version = "0.16.9" criteria = "safe-to-deploy" @@ -1406,6 +1414,10 @@ criteria = "safe-to-deploy" version = "0.2.5" criteria = "safe-to-deploy" +[[exemptions.trait-variant]] +version = "0.1.2" +criteria = "safe-to-deploy" + [[exemptions.typed-index-collections]] version = "3.1.0" criteria = "safe-to-deploy" diff --git a/zcash_client_backend/CHANGELOG.md b/zcash_client_backend/CHANGELOG.md index b08cd2e498..aebf460767 100644 --- a/zcash_client_backend/CHANGELOG.md +++ b/zcash_client_backend/CHANGELOG.md @@ -23,6 +23,10 @@ and this library adheres to Rust's notion of - A new feature flag, `non-standard-fees`, has been added. This flag is now required in order to make use of any types or methods that enable non-standard fee calculation. +- `zcash_client_backend::tor::http::cryptex`: + - `LocalExchange`, a variant of the `Exchange` trait without `Send` bounds. + - `DynExchange` + - `DynLocalExchange` ### Changed - MSRV is now 1.77.0. @@ -76,6 +80,9 @@ and this library adheres to Rust's notion of `ProposalDecodingError::FeeRuleNotSupported` has been added to replace it. - `zcash_client_backend::data_api::fees::fixed` is now available only via the use of the `non-standard-fees` feature flag. +- `zcash_client_backend::tor::http::cryptex`: + - The `Exchange` trait is no longer object-safe. Replace any existing uses of + `dyn Exchange` with `DynExchange`. ### Removed - `zcash_client_backend::data_api`: diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index ef01a76658..3bf10880ad 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -95,8 +95,10 @@ nom = "7" # `hyper::Error`, `hyper::http::Error`, `serde_json::Error`. We could avoid this with # changes to error handling. arti-client = { workspace = true, optional = true } +dynosaur = { workspace = true, optional = true } hyper = { workspace = true, optional = true, features = ["client", "http1"] } serde_json = { workspace = true, optional = true } +trait-variant = { workspace = true, optional = true } # - Currency conversion rust_decimal = { workspace = true, optional = true } @@ -179,7 +181,7 @@ sync = [ ## operations. tor = [ "dep:arti-client", - "dep:async-trait", + "dep:dynosaur", "dep:futures-util", "dep:http-body-util", "dep:hyper", @@ -191,6 +193,7 @@ tor = [ "dep:tokio", "dep:tokio-rustls", "dep:tor-rtcompat", + "dep:trait-variant", "dep:tower", "dep:webpki-roots", ] diff --git a/zcash_client_backend/src/tor/http/cryptex.rs b/zcash_client_backend/src/tor/http/cryptex.rs index 933a713571..f2662418ea 100644 --- a/zcash_client_backend/src/tor/http/cryptex.rs +++ b/zcash_client_backend/src/tor/http/cryptex.rs @@ -1,6 +1,5 @@ //! Cryptocurrency exchange rate APIs. -use async_trait::async_trait; use futures_util::{future::join_all, join}; use rand::{seq::IteratorRandom, thread_rng}; use rust_decimal::Decimal; @@ -26,8 +25,10 @@ pub mod exchanges { } /// An exchange that can be queried for ZEC data. -#[async_trait] -pub trait Exchange: 'static { +#[trait_variant::make(Exchange: Send)] +#[dynosaur::dynosaur(DynExchange = dyn Exchange)] +#[dynosaur::dynosaur(DynLocalExchange = dyn LocalExchange)] +pub trait LocalExchange { /// Queries data about the USD/ZEC pair. /// /// The returned bid and ask data must be denominated in USD, i.e. the latest bid and @@ -55,8 +56,8 @@ impl ExchangeData { /// A set of [`Exchange`]s that can be queried for ZEC data. pub struct Exchanges { - trusted: Box, - others: Vec>, + trusted: Box>, + others: Vec>>, } impl Exchanges { @@ -78,7 +79,7 @@ impl Exchanges { /// /// The `trusted` exchange will always have its data used, _if_ data is successfully /// obtained via Tor (i.e. no transient failures). - pub fn builder(trusted: impl Exchange) -> ExchangesBuilder { + pub fn builder(trusted: impl Exchange + 'static) -> ExchangesBuilder { ExchangesBuilder::new(trusted) } } @@ -105,16 +106,16 @@ impl ExchangesBuilder { /// /// The `trusted` exchange will always have its data used, _if_ data is successfully /// obtained via Tor (i.e. no transient failures). - pub fn new(trusted: impl Exchange) -> Self { + pub fn new(trusted: impl Exchange + 'static) -> Self { Self(Exchanges { - trusted: Box::new(trusted), + trusted: DynExchange::boxed(trusted), others: vec![], }) } /// Adds another [`Exchange`] as a data source. - pub fn with(mut self, other: impl Exchange) -> Self { - self.0.others.push(Box::new(other)); + pub fn with(mut self, other: impl Exchange + 'static) -> Self { + self.0.others.push(DynExchange::boxed(other)); self } diff --git a/zcash_client_backend/src/tor/http/cryptex/binance.rs b/zcash_client_backend/src/tor/http/cryptex/binance.rs index 49f3001d6b..aa1645e82a 100644 --- a/zcash_client_backend/src/tor/http/cryptex/binance.rs +++ b/zcash_client_backend/src/tor/http/cryptex/binance.rs @@ -1,4 +1,3 @@ -use async_trait::async_trait; use rust_decimal::Decimal; use serde::Deserialize; @@ -44,7 +43,6 @@ struct BinanceData { count: u32, } -#[async_trait] impl Exchange for Binance { async fn query_zec_to_usd(&self, client: &Client) -> Result { // API documentation: diff --git a/zcash_client_backend/src/tor/http/cryptex/coinbase.rs b/zcash_client_backend/src/tor/http/cryptex/coinbase.rs index 61a355f269..190d3650eb 100644 --- a/zcash_client_backend/src/tor/http/cryptex/coinbase.rs +++ b/zcash_client_backend/src/tor/http/cryptex/coinbase.rs @@ -1,4 +1,3 @@ -use async_trait::async_trait; use rust_decimal::Decimal; use serde::Deserialize; @@ -31,7 +30,6 @@ struct CoinbaseData { conversions_volume: Option, } -#[async_trait] impl Exchange for Coinbase { #[allow(dead_code)] async fn query_zec_to_usd(&self, client: &Client) -> Result { diff --git a/zcash_client_backend/src/tor/http/cryptex/gate_io.rs b/zcash_client_backend/src/tor/http/cryptex/gate_io.rs index 80a81b7dce..382517de12 100644 --- a/zcash_client_backend/src/tor/http/cryptex/gate_io.rs +++ b/zcash_client_backend/src/tor/http/cryptex/gate_io.rs @@ -1,4 +1,3 @@ -use async_trait::async_trait; use hyper::StatusCode; use rust_decimal::Decimal; use serde::Deserialize; @@ -32,7 +31,6 @@ struct GateIoData { low_24h: Decimal, } -#[async_trait] impl Exchange for GateIo { async fn query_zec_to_usd(&self, client: &Client) -> Result { // API documentation: diff --git a/zcash_client_backend/src/tor/http/cryptex/gemini.rs b/zcash_client_backend/src/tor/http/cryptex/gemini.rs index dbb596e245..856634b21e 100644 --- a/zcash_client_backend/src/tor/http/cryptex/gemini.rs +++ b/zcash_client_backend/src/tor/http/cryptex/gemini.rs @@ -1,4 +1,3 @@ -use async_trait::async_trait; use rust_decimal::Decimal; use serde::Deserialize; @@ -30,7 +29,6 @@ struct GeminiData { ask: Decimal, } -#[async_trait] impl Exchange for Gemini { async fn query_zec_to_usd(&self, client: &Client) -> Result { // API documentation: diff --git a/zcash_client_backend/src/tor/http/cryptex/ku_coin.rs b/zcash_client_backend/src/tor/http/cryptex/ku_coin.rs index 30b4ac629c..3301367050 100644 --- a/zcash_client_backend/src/tor/http/cryptex/ku_coin.rs +++ b/zcash_client_backend/src/tor/http/cryptex/ku_coin.rs @@ -1,4 +1,3 @@ -use async_trait::async_trait; use rust_decimal::Decimal; use serde::Deserialize; @@ -46,7 +45,6 @@ struct KuCoinResponse { data: KuCoinData, } -#[async_trait] impl Exchange for KuCoin { async fn query_zec_to_usd(&self, client: &Client) -> Result { // API documentation: diff --git a/zcash_client_backend/src/tor/http/cryptex/mexc.rs b/zcash_client_backend/src/tor/http/cryptex/mexc.rs index 7dcb46d7b6..278fec6939 100644 --- a/zcash_client_backend/src/tor/http/cryptex/mexc.rs +++ b/zcash_client_backend/src/tor/http/cryptex/mexc.rs @@ -1,4 +1,3 @@ -use async_trait::async_trait; use rust_decimal::Decimal; use serde::Deserialize; @@ -39,7 +38,6 @@ struct MexcData { closeTime: u64, } -#[async_trait] impl Exchange for Mexc { async fn query_zec_to_usd(&self, client: &Client) -> Result { // API documentation: