mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-10-01 01:45:40 -04:00
Add Tor to main
This commit is contained in:
parent
cf8accf30d
commit
8811a0a205
@ -28,20 +28,38 @@ use xmr_btc::{alice::State0, bob, monero};
|
||||
|
||||
pub type Swarm = libp2p::Swarm<Alice>;
|
||||
|
||||
// TODO: After we have done some testing replace all the 'panic's with log
|
||||
// statements or error returns.
|
||||
|
||||
// FIXME: This whole function is horrible, needs total re-write.
|
||||
#[cfg(not(feature = "tor"))]
|
||||
pub async fn swap(
|
||||
listen: Multiaddr,
|
||||
redeem_address: ::bitcoin::Address,
|
||||
punish_address: ::bitcoin::Address,
|
||||
) -> Result<()> {
|
||||
let swarm = new_swarm(listen)?;
|
||||
_swap(redeem_address, punish_address, swarm).await
|
||||
}
|
||||
#[cfg(feature = "tor")]
|
||||
pub async fn swap(
|
||||
listen: Multiaddr,
|
||||
local_port: u16,
|
||||
redeem_address: ::bitcoin::Address,
|
||||
punish_address: ::bitcoin::Address,
|
||||
) -> Result<()> {
|
||||
let swarm = new_swarm(listen, local_port)?;
|
||||
_swap(redeem_address, punish_address, swarm).await
|
||||
}
|
||||
|
||||
// TODO: After we have done some testing replace all the 'panic's with log
|
||||
// statements or error returns.
|
||||
|
||||
// FIXME: This whole function is horrible, needs total re-write.
|
||||
async fn _swap(
|
||||
redeem_address: ::bitcoin::Address,
|
||||
punish_address: ::bitcoin::Address,
|
||||
mut swarm: Swarm,
|
||||
) -> Result<()> {
|
||||
let message0: bob::Message0;
|
||||
let mut last_amounts: Option<SwapAmounts> = None;
|
||||
|
||||
let mut swarm = new_swarm(listen)?;
|
||||
|
||||
loop {
|
||||
match swarm.next().await {
|
||||
OutEvent::ConnectionEstablished(id) => {
|
||||
@ -111,6 +129,32 @@ pub async fn swap(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "tor")]
|
||||
fn new_swarm(listen: Multiaddr, port: u16) -> Result<Swarm> {
|
||||
use anyhow::Context as _;
|
||||
|
||||
let behaviour = Alice::default();
|
||||
|
||||
let local_key_pair = behaviour.identity();
|
||||
let local_peer_id = behaviour.peer_id();
|
||||
|
||||
let transport = transport::build(local_key_pair, Some((listen.clone(), port)))?;
|
||||
|
||||
let mut swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, local_peer_id.clone())
|
||||
.executor(Box::new(TokioExecutor {
|
||||
handle: tokio::runtime::Handle::current(),
|
||||
}))
|
||||
.build();
|
||||
|
||||
Swarm::listen_on(&mut swarm, listen.clone())
|
||||
.with_context(|| format!("Address is not supported: {:#}", listen))?;
|
||||
|
||||
tracing::info!("Initialized swarm: {}", local_peer_id);
|
||||
|
||||
Ok(swarm)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "tor"))]
|
||||
fn new_swarm(listen: Multiaddr) -> Result<Swarm> {
|
||||
use anyhow::Context as _;
|
||||
|
||||
|
@ -114,7 +114,16 @@ fn new_swarm() -> Result<Swarm> {
|
||||
let local_key_pair = behaviour.identity();
|
||||
let local_peer_id = behaviour.peer_id();
|
||||
|
||||
let transport = transport::build(local_key_pair)?;
|
||||
let transport = {
|
||||
#[cfg(feature = "tor")]
|
||||
{
|
||||
transport::build(local_key_pair, None)?
|
||||
}
|
||||
#[cfg(not(feature = "tor"))]
|
||||
{
|
||||
transport::build(local_key_pair)?
|
||||
}
|
||||
};
|
||||
|
||||
let swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, local_peer_id.clone())
|
||||
.executor(Box::new(TokioExecutor {
|
||||
|
@ -11,4 +11,9 @@ pub struct Options {
|
||||
/// Run the swap as Bob and try to swap this many BTC (in satoshi).
|
||||
#[structopt(long = "sats")]
|
||||
pub satoshis: Option<u64>,
|
||||
|
||||
/// Alice's onion multitaddr (only required for Bob, Alice will autogenerate
|
||||
/// one)
|
||||
#[structopt(long)]
|
||||
pub alice_address: Option<String>,
|
||||
}
|
||||
|
@ -12,22 +12,21 @@
|
||||
)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use cli::Options;
|
||||
use futures::{channel::mpsc, StreamExt};
|
||||
use libp2p::Multiaddr;
|
||||
use log::LevelFilter;
|
||||
use std::{io, io::Write, process};
|
||||
use structopt::StructOpt;
|
||||
use swap::{alice, bitcoin::Wallet, bob, Cmd, Rsp, SwapAmounts};
|
||||
use tracing::info;
|
||||
use url::Url;
|
||||
use xmr_btc::bitcoin::{BroadcastSignedTransaction, BuildTxLockPsbt, SignTxLock};
|
||||
|
||||
mod cli;
|
||||
mod trace;
|
||||
|
||||
use cli::Options;
|
||||
use swap::{alice, bitcoin::Wallet, bob, Cmd, Rsp, SwapAmounts};
|
||||
use xmr_btc::bitcoin::{BroadcastSignedTransaction, BuildTxLockPsbt, SignTxLock};
|
||||
|
||||
// TODO: Add root seed file instead of generating new seed each run.
|
||||
// TODO: Remove all instances of the todo! macro
|
||||
|
||||
@ -35,7 +34,14 @@ use xmr_btc::bitcoin::{BroadcastSignedTransaction, BuildTxLockPsbt, SignTxLock};
|
||||
// Alice's address and port until we have a config file.
|
||||
pub const PORT: u16 = 9876; // Arbitrarily chosen.
|
||||
pub const ADDR: &str = "127.0.0.1";
|
||||
pub const BITCOIND_JSON_RPC_URL: &str = "127.0.0.1:8332";
|
||||
pub const BITCOIND_JSON_RPC_URL: &str = "http://127.0.0.1:8332";
|
||||
|
||||
#[cfg(feature = "tor")]
|
||||
use swap::tor::{AuthenticatedConnection, UnauthenticatedConnection};
|
||||
#[cfg(feature = "tor")]
|
||||
use torut::onion::TorSecretKeyV3;
|
||||
#[cfg(feature = "tor")]
|
||||
pub const TOR_PORT: u16 = PORT + 1;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
@ -43,7 +49,21 @@ async fn main() -> Result<()> {
|
||||
|
||||
trace::init_tracing(LevelFilter::Debug)?;
|
||||
|
||||
#[cfg(feature = "tor")]
|
||||
let (addr, _ac) = {
|
||||
let tor_secret_key = TorSecretKeyV3::generate();
|
||||
let onion_address = tor_secret_key
|
||||
.public()
|
||||
.get_onion_address()
|
||||
.get_address_without_dot_onion();
|
||||
(
|
||||
format!("/onion3/{}:{}", onion_address, TOR_PORT),
|
||||
create_tor_service(tor_secret_key).await?,
|
||||
)
|
||||
};
|
||||
#[cfg(not(feature = "tor"))]
|
||||
let addr = format!("/ip4/{}/tcp/{}", ADDR, PORT);
|
||||
|
||||
let alice: Multiaddr = addr.parse().expect("failed to parse Alice's address");
|
||||
|
||||
if opt.as_alice {
|
||||
@ -71,6 +91,12 @@ async fn main() -> Result<()> {
|
||||
} else {
|
||||
info!("running swap node as Bob ...");
|
||||
|
||||
let alice_address = match opt.alice_address {
|
||||
Some(addr) => addr,
|
||||
None => bail!("Address required to dial"),
|
||||
};
|
||||
let alice_address = multiaddr(&alice_address)?;
|
||||
|
||||
let url = Url::parse(BITCOIND_JSON_RPC_URL).expect("failed to parse url");
|
||||
let bitcoin_wallet = Wallet::new("bob", &url)
|
||||
.await
|
||||
@ -86,7 +112,7 @@ async fn main() -> Result<()> {
|
||||
(None, None) => bail!("Please supply an amount to swap"),
|
||||
(Some(_picos), _) => todo!("support starting with picos"),
|
||||
(None, Some(sats)) => {
|
||||
swap_as_bob(sats, alice, refund, bitcoin_wallet).await?;
|
||||
swap_as_bob(sats, alice_address, refund, bitcoin_wallet).await?;
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -94,13 +120,36 @@ async fn main() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "tor")]
|
||||
async fn create_tor_service(tor_secret_key: TorSecretKeyV3) -> Result<AuthenticatedConnection> {
|
||||
// todo use configurable ports for tor connection
|
||||
let mut authenticated_connection = UnauthenticatedConnection::default()
|
||||
.init_authenticated_connection()
|
||||
.await?;
|
||||
tracing::info!("Tor authenticated.");
|
||||
|
||||
authenticated_connection
|
||||
.add_service(TOR_PORT, &tor_secret_key)
|
||||
.await?;
|
||||
tracing::info!("Tor service added.");
|
||||
|
||||
Ok(authenticated_connection)
|
||||
}
|
||||
|
||||
async fn swap_as_alice(
|
||||
addr: Multiaddr,
|
||||
redeem: bitcoin::Address,
|
||||
punish: bitcoin::Address,
|
||||
) -> Result<()> {
|
||||
#[cfg(not(feature = "tor"))]
|
||||
{
|
||||
alice::swap(addr, redeem, punish).await
|
||||
}
|
||||
#[cfg(feature = "tor")]
|
||||
{
|
||||
alice::swap(addr, PORT, redeem, punish).await
|
||||
}
|
||||
}
|
||||
|
||||
async fn swap_as_bob<W>(
|
||||
sats: u64,
|
||||
@ -164,3 +213,10 @@ fn verify(amounts: SwapAmounts) -> Rsp {
|
||||
fn is_yes(s: &str) -> bool {
|
||||
matches!(s, "y" | "Y" | "yes" | "YES" | "Yes")
|
||||
}
|
||||
|
||||
fn multiaddr(s: &str) -> Result<Multiaddr> {
|
||||
let addr = s
|
||||
.parse()
|
||||
.with_context(|| format!("failed to parse multiaddr: {}", s))?;
|
||||
Ok(addr)
|
||||
}
|
||||
|
@ -10,18 +10,18 @@ use libp2p::{
|
||||
dns::DnsConfig,
|
||||
mplex::MplexConfig,
|
||||
noise::{self, NoiseConfig, X25519Spec},
|
||||
tcp::TokioTcpConfig,
|
||||
yamux, PeerId,
|
||||
};
|
||||
|
||||
// TOOD: Add the tor transport builder.
|
||||
|
||||
/// Builds a libp2p transport with the following features:
|
||||
/// Builds a libp2p transport without Tor with the following features:
|
||||
/// - TcpConnection
|
||||
/// - DNS name resolution
|
||||
/// - authentication via noise
|
||||
/// - multiplexing via yamux or mplex
|
||||
#[cfg(not(feature = "tor"))]
|
||||
pub fn build(id_keys: identity::Keypair) -> Result<SwapTransport> {
|
||||
use libp2p::tcp::TokioTcpConfig;
|
||||
|
||||
let dh_keys = noise::Keypair::<X25519Spec>::new().into_authentic(&id_keys)?;
|
||||
let noise = NoiseConfig::xx(dh_keys).into_authenticated();
|
||||
|
||||
@ -41,4 +41,41 @@ pub fn build(id_keys: identity::Keypair) -> Result<SwapTransport> {
|
||||
Ok(transport)
|
||||
}
|
||||
|
||||
/// Builds a libp2p transport with Tor and with the following features:
|
||||
/// - TCP connection over the Tor network
|
||||
/// - DNS name resolution
|
||||
/// - authentication via noise
|
||||
/// - multiplexing via yamux or mplex
|
||||
#[cfg(feature = "tor")]
|
||||
pub fn build(
|
||||
id_keys: identity::Keypair,
|
||||
address_port_pair: Option<(libp2p::core::Multiaddr, u16)>,
|
||||
) -> Result<SwapTransport> {
|
||||
use libp2p_tokio_socks5::Socks5TokioTcpConfig;
|
||||
use std::collections::HashMap;
|
||||
|
||||
let mut map = HashMap::new();
|
||||
if let Some((addr, port)) = address_port_pair {
|
||||
map.insert(addr, port);
|
||||
}
|
||||
|
||||
let dh_keys = noise::Keypair::<X25519Spec>::new().into_authentic(&id_keys)?;
|
||||
let noise = NoiseConfig::xx(dh_keys).into_authenticated();
|
||||
|
||||
let socks = Socks5TokioTcpConfig::default().nodelay(true).onion_map(map);
|
||||
let dns = DnsConfig::new(socks)?;
|
||||
|
||||
let transport = dns
|
||||
.upgrade(Version::V1)
|
||||
.authenticate(noise)
|
||||
.multiplex(SelectUpgrade::new(
|
||||
yamux::Config::default(),
|
||||
MplexConfig::new(),
|
||||
))
|
||||
.map(|(peer, muxer), _| (peer, StreamMuxerBox::new(muxer)))
|
||||
.boxed();
|
||||
|
||||
Ok(transport)
|
||||
}
|
||||
|
||||
pub type SwapTransport = Boxed<(PeerId, StreamMuxerBox)>;
|
||||
|
Loading…
Reference in New Issue
Block a user