Skip to content

Commit

Permalink
feat(tor): add new AsyncTorClient
Browse files Browse the repository at this point in the history
- feat(tor): add new async client, `AsyncTorClient`, which uses
  `arti-client` to establish Tor connections, and `hyper` as HTTP client
  over custom Tor anonymized data stream.
- feat(tor): implements the common methods: `get_response`,
  `get_response_json`, `get_response_hex` and their `opt` versions too.
  • Loading branch information
oleonardolima committed Sep 6, 2024
1 parent ac64e04 commit 8f7fff7
Show file tree
Hide file tree
Showing 5 changed files with 1,117 additions and 6 deletions.
42 changes: 40 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,59 @@ log = "^0.4"
minreq = { version = "2.11.0", features = ["json-using-serde"], optional = true }
reqwest = { version = "0.11", features = ["json"], default-features = false, optional = true }

arti-client = { version = "0.21.0", default-features = false, optional = true }
tor-rtcompat = { version = "0.21.0", default-features = false, optional = true }
hyper = { version = "1.4.1", features = ["client", "http1"], default-features = false, optional = true }
hyper-util = { version = "0.1.7", features = ["tokio"], default-features = false, optional = true }
tokio = { version = "1.38.1", optional = true }
http-body-util = { version = "0.1.2", optional = true}
http = { version = "1.1.0", optional = true }
serde_json = { version = "1.0.127", optional = true }
tokio-rustls = { version = "0.26.0", default-features = false, features = [
"logging",
"tls12",
"ring",
], optional = true }
webpki-roots = { version = "0.26.3", optional = true }
rustls-pki-types = { version = "1.8.0", optional = true }

[dev-dependencies]
serde_json = "1.0"
tokio = { version = "1.20.1", features = ["full"] }
electrsd = { version = "0.28.0", features = ["legacy", "esplora_a33e97e1", "bitcoind_25_0"] }
lazy_static = "1.4.0"

[features]
default = ["blocking", "async", "async-https"]
default = ["blocking", "async", "async-https", "async-tor"]
blocking = ["minreq", "minreq/proxy"]
blocking-https = ["blocking", "minreq/https"]
blocking-https-rustls = ["blocking", "minreq/https-rustls"]
blocking-https-native = ["blocking", "minreq/https-native"]
blocking-https-bundled = ["blocking", "minreq/https-bundled"]

async = ["reqwest", "reqwest/socks"]
async-https = ["async", "reqwest/default-tls"]
async-https-native = ["async", "reqwest/native-tls"]
async-https-rustls = ["async", "reqwest/rustls-tls"]
async-https-rustls-manual-roots = ["async", "reqwest/rustls-tls-manual-roots"]

async-tor = [
"dep:arti-client",
"arti-client/tokio",
"arti-client/onion-service-client",
"arti-client/native-tls",

"dep:tor-rtcompat",
"tor-rtcompat/tokio",

"dep:hyper",
"dep:hyper-util",
"dep:tokio",
"dep:http-body-util",
"dep:http",
"dep:serde_json",
"dep:tokio-rustls",
"dep:webpki-roots",
"dep:rustls-pki-types"
]
async-tor-https-native = ["async-tor", "arti-client/native-tls"]
async-tor-https-rustls = ["async-tor", "arti-client/rustls"]
28 changes: 28 additions & 0 deletions examples/tor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use bitcoin::{consensus::encode::deserialize_hex, Transaction};
use esplora_client::{r#async_tor::AsyncTorClient, Builder};

extern crate esplora_client;

// const MEMPOOL_SPACE_API: &str = "https://mempool.space/api";
const MEMPOOL_SPACE_API: &str = "https://blockstream.info/api";

#[tokio::main]
async fn main() {
let builder = Builder::new(MEMPOOL_SPACE_API);
let esplora_client = AsyncTorClient::from_builder(builder).await.unwrap();

let raw_tx = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000";
let tx: Transaction = deserialize_hex(raw_tx).unwrap();
esplora_client.broadcast(&tx).await.unwrap();

print!(
"successfully broadcasted transaction, with txid: {:?}",
tx.compute_txid()
);

// let tx_id =
// Txid::from_str("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b").unwrap();
// let tx = esplora_client.get_tx(&tx_id).await.unwrap().unwrap();

// println!("successfully fetched the transaction {:?}", tx);
}
6 changes: 5 additions & 1 deletion src/async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

//! Esplora by way of `reqwest` HTTP client.
use core::str;
use std::collections::HashMap;
use std::str::FromStr;

Expand All @@ -28,6 +29,7 @@ use reqwest::{header, Client};

use crate::{BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputStatus, Tx, TxStatus};

#[cfg(feature = "async")]
#[derive(Debug, Clone)]
pub struct AsyncClient {
/// The URL of the Esplora Server.
Expand All @@ -36,6 +38,7 @@ pub struct AsyncClient {
client: Client,
}

#[cfg(feature = "async")]
impl AsyncClient {
/// Build an async client from a builder
pub fn from_builder(builder: Builder) -> Result<Self, Error> {
Expand Down Expand Up @@ -84,7 +87,8 @@ impl AsyncClient {
/// [`bitcoin::consensus::Decodable`] deserialization.
async fn get_response<T: Decodable>(&self, path: &str) -> Result<T, Error> {
let url = format!("{}{}", self.url, path);
let response = self.client.get(url).send().await?;
let request = self.client.get(url);
let response = request.send().await?;

match response.status().is_success() {
true => Ok(deserialize::<T>(&response.bytes().await?)?),
Expand Down
Loading

0 comments on commit 8f7fff7

Please sign in to comment.