zcash_client_backend: Add a Tor client using the Arti library
This commit is contained in:
parent
4cefa92c28
commit
1e5b62bfce
File diff suppressed because it is too large
Load Diff
|
@ -125,6 +125,13 @@ proptest = "1"
|
|||
rand_chacha = "0.3"
|
||||
rand_xorshift = "0.3"
|
||||
|
||||
# Tor
|
||||
# - `arti-client` depends on `rusqlite`, and a version mismatch there causes a compilation
|
||||
# failure due to incompatible `libsqlite3-sys` versions.
|
||||
arti-client = { version = "0.11", default-features = false, features = ["compression", "rustls", "tokio"] }
|
||||
tokio = "1"
|
||||
tor-rtcompat = "0.9"
|
||||
|
||||
# ZIP 32
|
||||
aes = "0.8"
|
||||
fpe = "0.6"
|
||||
|
|
11
deny.toml
11
deny.toml
|
@ -31,16 +31,27 @@ allow = [
|
|||
]
|
||||
exceptions = [
|
||||
{ name = "arrayref", allow = ["BSD-2-Clause"] },
|
||||
{ name = "async_executors", allow = ["Unlicense"] },
|
||||
{ name = "bounded-vec-deque", allow = ["BSD-3-Clause"] },
|
||||
{ name = "coarsetime", allow = ["ISC"] },
|
||||
{ name = "curve25519-dalek", allow = ["BSD-3-Clause"] },
|
||||
{ name = "ed25519-dalek", allow = ["BSD-3-Clause"] },
|
||||
{ name = "matchit", allow = ["BSD-3-Clause"] },
|
||||
{ name = "minreq", allow = ["ISC"] },
|
||||
{ name = "option-ext", allow = ["MPL-2.0"] },
|
||||
{ name = "priority-queue", allow = ["MPL-2.0"] },
|
||||
{ name = "ring", allow = ["LicenseRef-ring"] },
|
||||
{ name = "rustls-webpki", allow = ["ISC"] },
|
||||
{ name = "secp256k1", allow = ["CC0-1.0"] },
|
||||
{ name = "secp256k1-sys", allow = ["CC0-1.0"] },
|
||||
{ name = "simple_asn1", allow = ["ISC"] },
|
||||
{ name = "slotmap", allow = ["Zlib"] },
|
||||
{ name = "subtle", allow = ["BSD-3-Clause"] },
|
||||
{ name = "tinystr", allow = ["Unicode-3.0"] },
|
||||
{ name = "unicode-ident", allow = ["Unicode-DFS-2016"] },
|
||||
{ name = "untrusted", allow = ["ISC"] },
|
||||
{ name = "webpki-roots", allow = ["MPL-2.0"] },
|
||||
{ name = "x25519-dalek", allow = ["BSD-3-Clause"] },
|
||||
]
|
||||
|
||||
[[licenses.clarify]]
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -38,6 +38,7 @@ funds to those addresses. See [ZIP 320](https://zips.z.cash/zip-0320) for detail
|
|||
- `zcash_client_backend::scanning`:
|
||||
- `testing` module
|
||||
- `zcash_client_backend::sync` module, behind the `sync` feature flag.
|
||||
- `zcash_client_backend::tor` module, behind the `tor` feature flag.
|
||||
- `zcash_client_backend::wallet::Recipient::map_ephemeral_transparent_outpoint`
|
||||
|
||||
### Changed
|
||||
|
|
|
@ -27,6 +27,7 @@ features = [
|
|||
"lightwalletd-tonic",
|
||||
"transparent-inputs",
|
||||
"test-dependencies",
|
||||
"tor",
|
||||
"unstable",
|
||||
"unstable-serialization",
|
||||
"unstable-spanning-tree",
|
||||
|
@ -94,6 +95,12 @@ jubjub = { workspace = true, optional = true }
|
|||
# - ZIP 321
|
||||
nom = "7"
|
||||
|
||||
# - Tor
|
||||
# -- Exposed error types: `arti_client::Error`, `arti_client::config::ConfigBuildError`,
|
||||
# `hyper::Error`, `hyper::http::Error`, `serde_json::Error`. We could avoid this with
|
||||
# changes to error handling.
|
||||
arti-client = { workspace = true, optional = true }
|
||||
|
||||
# Dependencies used internally:
|
||||
# (Breaking upgrades to these are usually backwards-compatible, but check MSRVs.)
|
||||
# - Documentation
|
||||
|
@ -107,6 +114,10 @@ percent-encoding.workspace = true
|
|||
crossbeam-channel.workspace = true
|
||||
rayon.workspace = true
|
||||
|
||||
# - Tor
|
||||
tokio = { workspace = true, optional = true, features = ["fs"] }
|
||||
tor-rtcompat = { workspace = true, optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = { workspace = true, features = ["prost"] }
|
||||
which = "4"
|
||||
|
@ -148,6 +159,14 @@ sync = [
|
|||
"dep:futures-util",
|
||||
]
|
||||
|
||||
## Exposes a Tor client for hiding a wallet's IP address while performing certain wallet
|
||||
## operations.
|
||||
tor = [
|
||||
"dep:arti-client",
|
||||
"dep:tokio",
|
||||
"dep:tor-rtcompat",
|
||||
]
|
||||
|
||||
## Exposes APIs that are useful for testing, such as `proptest` strategies.
|
||||
test-dependencies = [
|
||||
"dep:proptest",
|
||||
|
|
|
@ -80,6 +80,9 @@ pub mod sync;
|
|||
#[cfg(feature = "unstable-serialization")]
|
||||
pub mod serialization;
|
||||
|
||||
#[cfg(feature = "tor")]
|
||||
pub mod tor;
|
||||
|
||||
pub use decrypt::{decrypt_transaction, DecryptedOutput, TransferType};
|
||||
pub use zcash_protocol::{PoolType, ShieldedProtocol};
|
||||
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
//! Tor support for Zcash wallets.
|
||||
|
||||
use std::{fmt, io, path::Path};
|
||||
|
||||
use arti_client::{config::TorClientConfigBuilder, TorClient};
|
||||
use tor_rtcompat::PreferredRuntime;
|
||||
use tracing::debug;
|
||||
|
||||
/// A Tor client that exposes capabilities designed for Zcash wallets.
|
||||
pub struct Client {
|
||||
inner: TorClient<PreferredRuntime>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
/// Creates and bootstraps a Tor client.
|
||||
///
|
||||
/// The client's persistent data and cache are both stored in the given directory.
|
||||
/// Preserving the contents of this directory will speed up subsequent calls to
|
||||
/// `Client::create`.
|
||||
///
|
||||
/// Returns an error if `tor_dir` does not exist, or if bootstrapping fails.
|
||||
pub async fn create(tor_dir: &Path) -> Result<Self, Error> {
|
||||
let runtime = PreferredRuntime::current()?;
|
||||
|
||||
if !tokio::fs::try_exists(tor_dir).await? {
|
||||
return Err(Error::MissingTorDirectory);
|
||||
}
|
||||
|
||||
let config = TorClientConfigBuilder::from_directories(
|
||||
tor_dir.join("arti-data"),
|
||||
tor_dir.join("arti-cache"),
|
||||
)
|
||||
.build()
|
||||
.expect("all required fields initialized");
|
||||
|
||||
let client_builder = TorClient::with_runtime(runtime).config(config);
|
||||
|
||||
debug!("Bootstrapping Tor");
|
||||
let inner = client_builder.create_bootstrapped().await?;
|
||||
debug!("Tor bootstrapped");
|
||||
|
||||
Ok(Self { inner })
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors that can occur while creating or using a Tor [`Client`].
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// The directory passed to [`Client::create`] does not exist.
|
||||
MissingTorDirectory,
|
||||
/// An IO error occurred while interacting with the filesystem.
|
||||
Io(io::Error),
|
||||
/// A Tor-specific error.
|
||||
Tor(arti_client::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Error::MissingTorDirectory => write!(f, "Tor directory is missing"),
|
||||
Error::Io(e) => write!(f, "IO error: {}", e),
|
||||
Error::Tor(e) => write!(f, "Tor error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Error::MissingTorDirectory => None,
|
||||
Error::Io(e) => Some(e),
|
||||
Error::Tor(e) => Some(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(e: io::Error) -> Self {
|
||||
Error::Io(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<arti_client::Error> for Error {
|
||||
fn from(e: arti_client::Error) -> Self {
|
||||
Error::Tor(e)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue